
impl<N, F> Problem<N, F>
where
    N: Display + Zero + Copy + PartialEq,
    F: Flag,
{
    /// Write the semi-definite program in the file `filename` in the sdpa format.
    pub fn write_sdpa_select(&self, filename: &str, select: &Selector, fixed_obj: Option<f64>) -> Result<()> {
        self.check();
        let mut filename = PathBuf::from(filename);
        let _ = filename.set_extension("sdpa");
        let mut file = BufWriter::new(File::create(&filename)?);
        let problem = self.view(&select); // Selected problem
        info!("Writing problem in {}", filename.display());
        problem.write_header(&mut file)?;
        debug!("Generating Cauchy-Schwarz inequalities");
        let cs_mat: Vec<_> = problem.cs.iter().map(|cs|{ cs.get() }).collect();
        // Line 1: Number of constraints = size of the basis
        //  * If the target objective is fixed: add 1 constraint for the objective
        if fixed_obj == None {
            writeln!(file, "{}", self.obj.data.len())?;
        } else {
            writeln!(file, "{}", self.obj.data.len() + 1)?;
        }
        // Line 2: Number of blocks (one for each constraint)
        writeln!(file, "{}", self.ineqs.len() + select.cs.len())?;
        // Line 3: Sizes of the blocks
        for ineq in problem.ineqs.iter() {
            write!(file, "-{} ", std::cmp::max(1, ineq.len()))?;
        }
        for split in &cs_mat {
            write!(file, "{} ", split[0].rows())?;
        }
        writeln!(file)?;
        // Line 4: vector ai
        // ai is the needed coefficient for the flag Fi
        for v in &self.obj.data {
            write!(file, "{} ", v)?;
        }
        // * The last coefficient is the target value, if there is one
        if let Some(obj_value) = fixed_obj {
            write!(file, "{} ", obj_value)?;
        }
        writeln!(file)?;
        // Lines 5+: body
        // Matrix 0: Objective
        let mat_obj = match fixed_obj {
            None => 0,
            Some(_) => self.obj.data.len() + 1,  // * Additional matrix, after the ones of the Fis
        };
        for (block_num, ineq) in problem.ineqs.iter().enumerate() {
            for (i, ineq_data) in ineq.iter().enumerate() {
                write_coeff(&mut file, mat_obj, block_num, i, i, ineq_data.bound)?;
            }
        }
        writeln!(file)?;
        // Matrices 1+:
        // Inequaltity blocks
        for (block_num, ineq) in problem.ineqs.iter().enumerate() {
            for (i, ineq_data) in ineq.iter().enumerate() {
                for (mat_num, &v) in ineq_data.flag.iter().enumerate() {
                    write_coeff(&mut file, mat_num + 1, block_num, i, i, v)?;
                }
            }
        }
        writeln!(file)?;
        // Cs blocks
        let offset = self.ineqs.len();
        for (block_num, line) in cs_mat.iter().enumerate() {
            for (mat_num, matrix) in line.iter().enumerate() {
                for (&v, (i, j)) in matrix.iter() {
                    if i <= j {
                        write_coeff(&mut file, mat_num + 1, block_num + offset, i, j, v)?;
                    }
                }
            }
        }
        // * If fixed objective, weight the certificate
        if let Some(_) = fixed_obj {
            // * Weight coeffs of inequalities     
            for (block_num, ineq) in problem.ineqs.iter().enumerate() {
                for i in 0..ineq.len() {
                    write_coeff(&mut file, 0, block_num, i, i, -10.)?;
                }
            }
            // * Weight thr trace of Cauchy-Schwarz matrices
            for (block_num, line) in cs_mat.iter().enumerate() {
                for i in 0..line[0].cols() {
                    write_coeff(&mut file, 0, block_num + offset, i, i, -1000_000.)?;
                }
            }
        }
        Ok(())
    }
}