Skip to main content

opb2mcnf/
opb2mcnf.rs

1//! # `opb2mcnf`
2//!
3//! A small tool for converting OPB files to DIMACS MCNF.
4
5use anyhow::Context;
6use clap::Parser;
7use rustsat::instances::{fio::opb::Options as OpbOptions, MultiOptInstance};
8use std::{io, path::PathBuf};
9
10#[derive(Parser)]
11#[command(author, version, about, long_about = None)]
12struct Args {
13    /// The OPB input file. Reads from `stdin` if not given.
14    in_path: Option<PathBuf>,
15    /// The DIMACS MCNF output path. Writes to `stdout` if not given.
16    out_path: Option<PathBuf>,
17    /// The index in the OPB file to treat as the lowest variable
18    #[arg(long, default_value_t = 1)]
19    first_var_idx: usize,
20}
21
22fn main() -> anyhow::Result<()> {
23    let args = Args::parse();
24    let opb_opts = OpbOptions {
25        first_var_idx: 0,
26        ..Default::default()
27    };
28
29    let inst: MultiOptInstance = if let Some(in_path) = args.in_path {
30        MultiOptInstance::from_opb_path(in_path, opb_opts)
31            .context("error parsing the input file")?
32    } else {
33        MultiOptInstance::from_opb(&mut io::BufReader::new(io::stdin()), opb_opts)
34            .context("error parsing input")?
35    };
36
37    let (constrs, objs) = inst.decompose();
38    let constrs = constrs.sanitize();
39
40    println!("c {} clauses", constrs.n_clauses());
41    println!("c {} cards", constrs.n_cards());
42    println!("c {} pbs", constrs.n_pbs());
43    println!("c {} objectives", objs.len());
44
45    let mut inst = MultiOptInstance::compose(constrs, objs);
46    inst.constraints_mut().convert_to_cnf();
47
48    if let Some(out_path) = args.out_path {
49        inst.write_dimacs_path(out_path)
50            .context("error writing the output file")?;
51    } else {
52        inst.write_dimacs(&mut io::stdout())
53            .context("error writing to stdout")?;
54    }
55    Ok(())
56}