Skip to main content

MultiOptInstance

Struct MultiOptInstance 

Source
pub struct MultiOptInstance<VM: ManageVars = BasicVarManager> { /* private fields */ }
Available on crate feature multiopt only.
Expand description

Type representing a multi-objective optimization instance. The constraints are represented as a SatInstance struct.

Implementations§

Source§

impl<VM: ManageVars> MultiOptInstance<VM>

Source

pub fn new_with_manager(n_objs: usize, var_manager: VM) -> Self

Creates a new optimization instance with a specific var manager

Source

pub fn compose(constraints: SatInstance<VM>, objectives: Vec<Objective>) -> Self

Creates a new optimization instance from constraints and objectives

Examples found in repository?
examples/mcnf2opb.rs (line 44)
25fn main() -> anyhow::Result<()> {
26    let args = Args::parse();
27    let opb_opts = OpbOptions {
28        first_var_idx: args.first_var_idx,
29        no_negated_lits: args.avoid_negated_lits,
30    };
31
32    let inst: MultiOptInstance = if let Some(in_path) = args.in_path {
33        MultiOptInstance::from_dimacs_path(in_path).context("error parsing the input file")?
34    } else {
35        MultiOptInstance::from_dimacs(&mut io::BufReader::new(io::stdin()))
36            .context("error parsing input")?
37    };
38
39    let (mut constr, mut objs) = inst.decompose();
40    for obj in &mut objs {
41        let hardened = obj.convert_to_soft_lits(constr.var_manager_mut());
42        constr.extend(hardened.into());
43    }
44    let inst = MultiOptInstance::compose(constr, objs);
45
46    if let Some(out_path) = args.out_path {
47        inst.write_opb_path(out_path, opb_opts)
48            .context("error writing the output file")?;
49    } else {
50        inst.write_opb(&mut io::stdout(), opb_opts)
51            .context("error writing the output file")?;
52    }
53    Ok(())
54}
More examples
Hide additional examples
examples/opb2mcnf.rs (line 45)
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}
examples/gbmosplit.rs (line 332)
316fn split<VM: ManageVars>(
317    so_inst: OptInstance<VM>,
318    cli: &Cli,
319) -> (MultiOptInstance<VM>, SplitStats) {
320    let (constr, obj) = so_inst.decompose();
321
322    if !obj.weighted() {
323        cli.warning("objective is unweighted, can't split");
324        let obj_stats = ObjStats {
325            n_softs: obj.n_softs(),
326            weight_sum: obj.weight_sum(),
327            min_weight: obj.min_weight(),
328            max_weight: obj.max_weight(),
329            multiplier: 1,
330        };
331        return (
332            MultiOptInstance::compose(constr, vec![obj]),
333            SplitStats {
334                obj_stats: vec![obj_stats],
335            },
336        );
337    }
338
339    let (softs, offset) = obj.into_soft_cls();
340
341    if offset != 0 {
342        cli.warning(&format!(
343            "objective offset is not zero ({offset}), will be added to the lowest ranking objective"
344        ));
345    }
346
347    let mut sorted_clauses: Vec<_> = softs.into_iter().collect();
348    sorted_clauses.sort_by(|wc1, wc2| wc1.1.cmp(&wc2.1));
349
350    let (mut objs, split_stats) = match cli.split_alg {
351        SplitAlg::Bmo => split_bmo(sorted_clauses),
352        SplitAlg::Gcd => split_gbmo(sorted_clauses, cli),
353        SplitAlg::Gbmo => split_gbmo(sorted_clauses, cli),
354    };
355
356    // add offset of original objective to last objective
357    objs.last_mut().unwrap().set_offset(offset);
358
359    (MultiOptInstance::compose(constr, objs), split_stats)
360}
361
362fn perform_split(
363    sorted_clauses: Vec<(Clause, usize)>,
364    split_ends: Vec<usize>,
365) -> (Vec<Objective>, SplitStats) {
366    // split objectives and collect stats
367    let mut objs = vec![];
368    let mut split_start = 0;
369    let mut split_stats = SplitStats { obj_stats: vec![] };
370    for split_end in split_ends {
371        let softs = &sorted_clauses[split_start..split_end + 1];
372        let w_gcd = softs
373            .iter()
374            .fold(softs[0].1, |w_gcd, (_, w)| gcd(w_gcd, *w));
375        let obj = Objective::from_iter(softs.iter().cloned().map(|(c, w)| (c, w / w_gcd)));
376        split_stats.obj_stats.push(ObjStats {
377            n_softs: obj.n_softs(),
378            weight_sum: obj.weight_sum(),
379            min_weight: obj.min_weight(),
380            max_weight: obj.max_weight(),
381            multiplier: w_gcd,
382        });
383        objs.push(obj);
384        split_start = split_end + 1;
385    }
386    let softs = &sorted_clauses[split_start..];
387    let w_gcd = softs
388        .iter()
389        .fold(softs[0].1, |w_gcd, (_, w)| gcd(w_gcd, *w));
390    let obj = Objective::from_iter(softs.iter().cloned().map(|(c, w)| (c, w / w_gcd)));
391    split_stats.obj_stats.push(ObjStats {
392        n_softs: obj.n_softs(),
393        weight_sum: obj.weight_sum(),
394        min_weight: obj.min_weight(),
395        max_weight: obj.max_weight(),
396        multiplier: w_gcd,
397    });
398    objs.push(obj);
399    (objs, split_stats)
400}
401
402fn split_bmo(sorted_clauses: Vec<(Clause, usize)>) -> (Vec<Objective>, SplitStats) {
403    let mut multipliers = vec![sorted_clauses.first().unwrap().1];
404    let mut split_ends = vec![];
405    let mut sum = 0;
406    for (idx, (_, w)) in sorted_clauses.iter().enumerate() {
407        if w > multipliers.last().unwrap() {
408            if *w <= sum {
409                // instance not BMO, return original instance
410                split_ends.clear();
411                break;
412            } else {
413                multipliers.push(*w);
414                split_ends.push(idx - 1);
415            }
416        }
417        sum += *w;
418    }
419    perform_split(sorted_clauses, split_ends)
420}
421
422fn gcd(mut a: usize, mut b: usize) -> usize {
423    // Euclid's algorithm
424    while b != 0 {
425        a %= b;
426        std::mem::swap(&mut a, &mut b);
427    }
428    a
429}
430
431fn get_sums_pot_splits_gcds(
432    sorted_clauses: &[(Clause, usize)],
433) -> (Vec<usize>, Vec<usize>, Vec<usize>) {
434    let mut sums = vec![];
435    let mut pot_split_ends = vec![];
436    let mut sum = 0;
437    // find sums and potential splits
438    for idx in 0..sorted_clauses.len() {
439        sum += sorted_clauses[idx].1;
440        sums.push(sum);
441        if idx < sorted_clauses.len() - 1 && sorted_clauses[idx + 1].1 > sum {
442            pot_split_ends.push(idx);
443        }
444    }
445    // calculate gcds backwards
446    let mut gcds = vec![sorted_clauses.last().unwrap().1];
447    for (_, w) in sorted_clauses.iter().rev().skip(1) {
448        gcds.push(gcd(*gcds.last().unwrap(), *w));
449    }
450    (sums, pot_split_ends, gcds.into_iter().rev().collect())
451}
452
453fn check_split_thorough_gbmo(
454    right_partition: &[(Clause, usize)],
455    left_sum: usize,
456    cli: &Cli,
457) -> bool {
458    // first check immediate weight distances (fail fast)
459    for idx in 0..right_partition.len() - 1 {
460        let dist = right_partition[idx + 1].1 - right_partition[idx].1;
461        if dist != 0 && dist < left_sum {
462            return false;
463        }
464    }
465    // Check all weight combinations (disclaimer: exponential runtime).
466    let right_sum = right_partition.iter().fold(0, |s, (_, w)| s + w);
467    let mut all_weight_combs: BTreeSet<usize> = BTreeSet::new();
468    for (_, w) in right_partition {
469        let w = *w;
470        // add w to all previous weight combs and compare to adjacent weight combs.
471        // copy existing weight combs to iterate over while modifying set.
472        for weight_comb in all_weight_combs.iter().copied().collect::<Vec<_>>() {
473            let new_comb = weight_comb + w;
474            if !all_weight_combs.insert(new_comb) {
475                // weight combination already in set
476                continue;
477            }
478            let next_lower = all_weight_combs.range(0..new_comb).last().unwrap();
479            if new_comb - *next_lower <= left_sum {
480                // lower difference between new comb and next lower known comb
481                return false;
482            }
483            if let Some(next_higher) = all_weight_combs.range(new_comb + 1..right_sum + 1).next() {
484                if next_higher - new_comb <= left_sum {
485                    // lower difference between new comb and next higher known comb
486                    return false;
487                }
488            }
489            if all_weight_combs.len() > cli.max_combs {
490                cli.warning(&format!(
491                    "thorough GBMO check terminated after {} checked weight combinations",
492                    all_weight_combs.len()
493                ));
494                return false;
495            }
496        }
497        if !all_weight_combs.insert(w) {
498            // weight combination already in set
499            continue;
500        }
501        if let Some(next_lower) = all_weight_combs.range(0..w).last() {
502            if w - *next_lower <= left_sum {
503                // lower difference between w and next lower known comb
504                return false;
505            }
506        }
507        if let Some(next_higher) = all_weight_combs.range(w + 1..right_sum).next() {
508            if next_higher - w <= left_sum {
509                // lower difference between w and next higher known comb
510                return false;
511            }
512        }
513        if all_weight_combs.len() > cli.max_combs {
514            cli.warning(&format!(
515                "thorough GBMO check terminated after {} checked weight combinations",
516                all_weight_combs.len()
517            ));
518            return false;
519        }
520    }
521    true
522}
523
524fn split_gbmo(sorted_clauses: Vec<(Clause, usize)>, cli: &Cli) -> (Vec<Objective>, SplitStats) {
525    let (sums, pot_split_ends, gcds) = get_sums_pot_splits_gcds(&sorted_clauses);
526    let mut split_ends = vec![];
527    for split_end in pot_split_ends {
528        // checking strictly for truly separate objectives
529        if sums[split_end] < gcds[split_end + 1]
530            || (cli.split_alg == SplitAlg::Gbmo
531                && check_split_thorough_gbmo(
532                    &sorted_clauses[split_end + 1..],
533                    sums[split_end],
534                    cli,
535                ))
536        {
537            split_ends.push(split_end);
538        }
539    }
540    perform_split(sorted_clauses, split_ends)
541}
542
543macro_rules! is_one_of {
544    ($a:expr, $($b:expr),*) => {
545        $( $a == $b || )* false
546    }
547}
548
549fn parse_instance(
550    path: &Option<PathBuf>,
551    file_format: InputFormat,
552    opb_opts: fio::opb::Options,
553) -> anyhow::Result<(OptInstance, WriteFormat)> {
554    match file_format {
555        InputFormat::Infer => {
556            if let Some(path) = path {
557                if let Some(ext) = path.extension() {
558                    let path_without_compr = path.with_extension("");
559                    let ext = if is_one_of!(ext, "gz", "bz2", "xz") {
560                        // Strip compression extension
561                        match path_without_compr.extension() {
562                            Some(ext) => ext,
563                            None => anyhow::bail!("no file extension after compression extension"),
564                        }
565                    } else {
566                        ext
567                    };
568                    if is_one_of!(ext, "wcnf") {
569                        OptInstance::from_dimacs_path(path).map(|inst| (inst, WriteFormat::Mcnf))
570                    } else if is_one_of!(ext, "opb") {
571                        OptInstance::from_opb_path(path, opb_opts)
572                            .map(|inst| (inst, WriteFormat::Opb))
573                    } else {
574                        anyhow::bail!("unknown file extension")
575                    }
576                } else {
577                    anyhow::bail!("no file extension")
578                }
579            } else {
580                anyhow::bail!("cannot infer file format from stdin")
581            }
582        }
583        InputFormat::Wcnf => {
584            if let Some(path) = path {
585                OptInstance::from_dimacs_path(path).map(|inst| (inst, WriteFormat::Mcnf))
586            } else {
587                OptInstance::from_dimacs(&mut io::BufReader::new(io::stdin()))
588                    .map(|inst| (inst, WriteFormat::Mcnf))
589            }
590        }
591        InputFormat::Opb => {
592            if let Some(path) = path {
593                OptInstance::from_opb_path(path, opb_opts).map(|inst| (inst, WriteFormat::Opb))
594            } else {
595                OptInstance::from_opb(&mut io::BufReader::new(io::stdin()), opb_opts)
596                    .map(|inst| (inst, WriteFormat::Opb))
597            }
598        }
599    }
600}
601
602macro_rules! handle_error {
603    ($res:expr, $cli:expr) => {{
604        match $res {
605            Ok(val) => val,
606            Err(err) => {
607                $cli.error(&err);
608                anyhow::bail!(err)
609            }
610        }
611    }};
612}
613
614fn main() -> anyhow::Result<()> {
615    let cli = Cli::init();
616
617    if let Some(path) = &cli.in_path {
618        cli.info(&format!("finding splits in {}", path.display()));
619    }
620
621    let (so_inst, write_format) = handle_error!(
622        parse_instance(&cli.in_path, cli.input_format, cli.opb_opts),
623        cli
624    );
625
626    let (mut mo_inst, split_stats) = split(so_inst, &cli);
627
628    if cli.out_path.is_some() {
629        cli.print_split_stats(split_stats);
630    }
631
632    let found_split = mo_inst.n_objectives() > 1;
633
634    let write_format = cli.output_format.infer(write_format);
635
636    if found_split || cli.always_dump {
637        match write_format {
638            WriteFormat::Mcnf => {
639                mo_inst.constraints_mut().convert_to_cnf();
640                if let Some(path) = &cli.out_path {
641                    cli.info(&format!("writing mcnf to {}", path.display()));
642                    handle_error!(mo_inst.write_dimacs_path(path), cli);
643                } else {
644                    handle_error!(
645                        mo_inst.write_dimacs(&mut io::BufWriter::new(io::stdout())),
646                        cli
647                    );
648                }
649            }
650            WriteFormat::Opb => {
651                let (mut constrs, mut objs) = mo_inst.decompose();
652                for obj in &mut objs {
653                    obj.convert_to_soft_lits(constrs.var_manager_mut());
654                }
655                let mo_inst = MultiOptInstance::compose(constrs, objs);
656                if let Some(path) = &cli.out_path {
657                    cli.info(&format!("writing opb to {}", path.display()));
658                    handle_error!(mo_inst.write_opb_path(path, cli.opb_opts), cli);
659                } else {
660                    handle_error!(
661                        mo_inst.write_opb(&mut io::BufWriter::new(io::stdout()), cli.opb_opts),
662                        cli
663                    );
664                }
665            }
666        }
667    }
668
669    if found_split {
670        std::process::exit(0);
671    }
672    std::process::exit(1);
673}
examples/check-solution.rs (line 122)
102fn parse_instance(
103    inst_path: PathBuf,
104    file_format: FileFormat,
105    opb_opts: fio::opb::Options,
106) -> anyhow::Result<MultiOptInstance> {
107    match file_format {
108        FileFormat::Infer => {
109            if let Some(ext) = inst_path.extension() {
110                let path_without_compr = inst_path.with_extension("");
111                let ext = if is_one_of!(ext, "gz", "bz2", "xz") {
112                    // Strip compression extension
113                    match path_without_compr.extension() {
114                        Some(ext) => ext,
115                        None => anyhow::bail!("no file extension after compression extension"),
116                    }
117                } else {
118                    ext
119                };
120                let inst = if is_one_of!(ext, "cnf", "dimacs") {
121                    let inst = SatInstance::from_dimacs_path(inst_path)?;
122                    MultiOptInstance::compose(inst, vec![])
123                } else if is_one_of!(ext, "wcnf") {
124                    let (inst, obj) = OptInstance::from_dimacs_path(inst_path)?.decompose();
125                    MultiOptInstance::compose(inst, vec![obj])
126                } else if is_one_of!(ext, "mcnf") {
127                    MultiOptInstance::from_dimacs_path(inst_path)?
128                } else if is_one_of!(ext, "opb", "mopb", "pbmo") {
129                    MultiOptInstance::from_opb_path(inst_path, opb_opts)?
130                } else {
131                    anyhow::bail!("unknown file extension")
132                };
133                Ok(inst)
134            } else {
135                anyhow::bail!("no file extension")
136            }
137        }
138        FileFormat::Cnf => {
139            let inst = SatInstance::from_dimacs_path(inst_path)?;
140            Ok(MultiOptInstance::compose(inst, vec![]))
141        }
142        FileFormat::Wcnf => {
143            let (inst, obj) = OptInstance::from_dimacs_path(inst_path)?.decompose();
144            Ok(MultiOptInstance::compose(inst, vec![obj]))
145        }
146        FileFormat::Mcnf => MultiOptInstance::from_dimacs_path(inst_path),
147        FileFormat::Opb => MultiOptInstance::from_opb_path(inst_path, opb_opts),
148    }
149}
Source

pub fn decompose(self) -> (SatInstance<VM>, Vec<Objective>)

Decomposes the optimization instance to a SatInstance and Objectives

Examples found in repository?
examples/mcnf2opb.rs (line 39)
25fn main() -> anyhow::Result<()> {
26    let args = Args::parse();
27    let opb_opts = OpbOptions {
28        first_var_idx: args.first_var_idx,
29        no_negated_lits: args.avoid_negated_lits,
30    };
31
32    let inst: MultiOptInstance = if let Some(in_path) = args.in_path {
33        MultiOptInstance::from_dimacs_path(in_path).context("error parsing the input file")?
34    } else {
35        MultiOptInstance::from_dimacs(&mut io::BufReader::new(io::stdin()))
36            .context("error parsing input")?
37    };
38
39    let (mut constr, mut objs) = inst.decompose();
40    for obj in &mut objs {
41        let hardened = obj.convert_to_soft_lits(constr.var_manager_mut());
42        constr.extend(hardened.into());
43    }
44    let inst = MultiOptInstance::compose(constr, objs);
45
46    if let Some(out_path) = args.out_path {
47        inst.write_opb_path(out_path, opb_opts)
48            .context("error writing the output file")?;
49    } else {
50        inst.write_opb(&mut io::stdout(), opb_opts)
51            .context("error writing the output file")?;
52    }
53    Ok(())
54}
More examples
Hide additional examples
examples/opb2mcnf.rs (line 37)
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}
examples/check-solution.rs (line 60)
54fn main() -> anyhow::Result<()> {
55    let args = Args::parse();
56    let opb_opts = OpbOptions {
57        first_var_idx: args.opb_first_var_idx,
58        ..OpbOptions::default()
59    };
60    let (constrs, objs) = parse_instance(args.instance, args.file_format, opb_opts)?.decompose();
61
62    let mut reader = if let Some(solution) = args.solution {
63        fio::open_compressed_uncompressed_read(solution)?
64    } else {
65        Box::new(io::BufReader::new(io::stdin()))
66    };
67
68    let mut sol = Assignment::default();
69    loop {
70        let mut buf = String::new();
71        let read = reader.read_line(&mut buf)?;
72        if read == 0 {
73            break;
74        }
75        if buf.starts_with('v') {
76            sol.extend_from_vline(&buf)?;
77        }
78    }
79
80    if let Some(constr) = constrs.unsat_constraint(&sol) {
81        println!("unsatisfied constraint: {constr}");
82        std::process::exit(1);
83    }
84    print!("objective values: ");
85    for i in 0..objs.len() {
86        if i < objs.len() - 1 {
87            print!("{}, ", objs[i].evaluate(&sol))
88        } else {
89            print!("{}", objs[i].evaluate(&sol));
90        }
91    }
92    println!();
93    Ok(())
94}
examples/gbmosplit.rs (line 651)
614fn main() -> anyhow::Result<()> {
615    let cli = Cli::init();
616
617    if let Some(path) = &cli.in_path {
618        cli.info(&format!("finding splits in {}", path.display()));
619    }
620
621    let (so_inst, write_format) = handle_error!(
622        parse_instance(&cli.in_path, cli.input_format, cli.opb_opts),
623        cli
624    );
625
626    let (mut mo_inst, split_stats) = split(so_inst, &cli);
627
628    if cli.out_path.is_some() {
629        cli.print_split_stats(split_stats);
630    }
631
632    let found_split = mo_inst.n_objectives() > 1;
633
634    let write_format = cli.output_format.infer(write_format);
635
636    if found_split || cli.always_dump {
637        match write_format {
638            WriteFormat::Mcnf => {
639                mo_inst.constraints_mut().convert_to_cnf();
640                if let Some(path) = &cli.out_path {
641                    cli.info(&format!("writing mcnf to {}", path.display()));
642                    handle_error!(mo_inst.write_dimacs_path(path), cli);
643                } else {
644                    handle_error!(
645                        mo_inst.write_dimacs(&mut io::BufWriter::new(io::stdout())),
646                        cli
647                    );
648                }
649            }
650            WriteFormat::Opb => {
651                let (mut constrs, mut objs) = mo_inst.decompose();
652                for obj in &mut objs {
653                    obj.convert_to_soft_lits(constrs.var_manager_mut());
654                }
655                let mo_inst = MultiOptInstance::compose(constrs, objs);
656                if let Some(path) = &cli.out_path {
657                    cli.info(&format!("writing opb to {}", path.display()));
658                    handle_error!(mo_inst.write_opb_path(path, cli.opb_opts), cli);
659                } else {
660                    handle_error!(
661                        mo_inst.write_opb(&mut io::BufWriter::new(io::stdout()), cli.opb_opts),
662                        cli
663                    );
664                }
665            }
666        }
667    }
668
669    if found_split {
670        std::process::exit(0);
671    }
672    std::process::exit(1);
673}
Source

pub fn n_objectives(&self) -> usize

Returns the number of objectives in the instance

Examples found in repository?
examples/gbmosplit.rs (line 632)
614fn main() -> anyhow::Result<()> {
615    let cli = Cli::init();
616
617    if let Some(path) = &cli.in_path {
618        cli.info(&format!("finding splits in {}", path.display()));
619    }
620
621    let (so_inst, write_format) = handle_error!(
622        parse_instance(&cli.in_path, cli.input_format, cli.opb_opts),
623        cli
624    );
625
626    let (mut mo_inst, split_stats) = split(so_inst, &cli);
627
628    if cli.out_path.is_some() {
629        cli.print_split_stats(split_stats);
630    }
631
632    let found_split = mo_inst.n_objectives() > 1;
633
634    let write_format = cli.output_format.infer(write_format);
635
636    if found_split || cli.always_dump {
637        match write_format {
638            WriteFormat::Mcnf => {
639                mo_inst.constraints_mut().convert_to_cnf();
640                if let Some(path) = &cli.out_path {
641                    cli.info(&format!("writing mcnf to {}", path.display()));
642                    handle_error!(mo_inst.write_dimacs_path(path), cli);
643                } else {
644                    handle_error!(
645                        mo_inst.write_dimacs(&mut io::BufWriter::new(io::stdout())),
646                        cli
647                    );
648                }
649            }
650            WriteFormat::Opb => {
651                let (mut constrs, mut objs) = mo_inst.decompose();
652                for obj in &mut objs {
653                    obj.convert_to_soft_lits(constrs.var_manager_mut());
654                }
655                let mo_inst = MultiOptInstance::compose(constrs, objs);
656                if let Some(path) = &cli.out_path {
657                    cli.info(&format!("writing opb to {}", path.display()));
658                    handle_error!(mo_inst.write_opb_path(path, cli.opb_opts), cli);
659                } else {
660                    handle_error!(
661                        mo_inst.write_opb(&mut io::BufWriter::new(io::stdout()), cli.opb_opts),
662                        cli
663                    );
664                }
665            }
666        }
667    }
668
669    if found_split {
670        std::process::exit(0);
671    }
672    std::process::exit(1);
673}
Source

pub fn constraints_mut(&mut self) -> &mut SatInstance<VM>

Gets a mutable reference to the hard constraints for modifying them

Examples found in repository?
examples/opb2mcnf.rs (line 46)
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}
More examples
Hide additional examples
examples/gbmosplit.rs (line 639)
614fn main() -> anyhow::Result<()> {
615    let cli = Cli::init();
616
617    if let Some(path) = &cli.in_path {
618        cli.info(&format!("finding splits in {}", path.display()));
619    }
620
621    let (so_inst, write_format) = handle_error!(
622        parse_instance(&cli.in_path, cli.input_format, cli.opb_opts),
623        cli
624    );
625
626    let (mut mo_inst, split_stats) = split(so_inst, &cli);
627
628    if cli.out_path.is_some() {
629        cli.print_split_stats(split_stats);
630    }
631
632    let found_split = mo_inst.n_objectives() > 1;
633
634    let write_format = cli.output_format.infer(write_format);
635
636    if found_split || cli.always_dump {
637        match write_format {
638            WriteFormat::Mcnf => {
639                mo_inst.constraints_mut().convert_to_cnf();
640                if let Some(path) = &cli.out_path {
641                    cli.info(&format!("writing mcnf to {}", path.display()));
642                    handle_error!(mo_inst.write_dimacs_path(path), cli);
643                } else {
644                    handle_error!(
645                        mo_inst.write_dimacs(&mut io::BufWriter::new(io::stdout())),
646                        cli
647                    );
648                }
649            }
650            WriteFormat::Opb => {
651                let (mut constrs, mut objs) = mo_inst.decompose();
652                for obj in &mut objs {
653                    obj.convert_to_soft_lits(constrs.var_manager_mut());
654                }
655                let mo_inst = MultiOptInstance::compose(constrs, objs);
656                if let Some(path) = &cli.out_path {
657                    cli.info(&format!("writing opb to {}", path.display()));
658                    handle_error!(mo_inst.write_opb_path(path, cli.opb_opts), cli);
659                } else {
660                    handle_error!(
661                        mo_inst.write_opb(&mut io::BufWriter::new(io::stdout()), cli.opb_opts),
662                        cli
663                    );
664                }
665            }
666        }
667    }
668
669    if found_split {
670        std::process::exit(0);
671    }
672    std::process::exit(1);
673}
Source

pub fn constraints_ref(&self) -> &SatInstance<VM>

Gets a reference to the hard constraints

Examples found in repository?
examples/shuffledimacs.rs (line 54)
26fn main() -> anyhow::Result<()> {
27    let in_path = PathBuf::from(&std::env::args().nth(1).unwrap_or_else(|| print_usage!()));
28    let out_path = PathBuf::from(&std::env::args().nth(2).unwrap_or_else(|| print_usage!()));
29
30    match determine_file_type(&in_path) {
31        FileType::Cnf => {
32            let inst = instances::SatInstance::<BasicVarManager>::from_dimacs_path(in_path)
33                .context("Could not parse CNF")?;
34            let n_vars = inst.n_vars();
35            let rand_reindexer = RandReindVarManager::init(n_vars);
36            inst.reindex(rand_reindexer)
37                .shuffle()
38                .write_dimacs_path(out_path)
39                .context("Could not write CNF")?;
40        }
41        FileType::Wcnf => {
42            let inst = instances::OptInstance::<BasicVarManager>::from_dimacs_path(in_path)
43                .context("Could not parse WCNF")?;
44            let n_vars = inst.constraints_ref().n_vars();
45            let rand_reindexer = RandReindVarManager::init(n_vars);
46            inst.reindex(rand_reindexer)
47                .shuffle()
48                .write_dimacs_path(out_path)
49                .context("Could not write WCNF")?;
50        }
51        FileType::Mcnf => {
52            let inst = instances::MultiOptInstance::<BasicVarManager>::from_dimacs_path(in_path)
53                .context("Could not parse MCNF")?;
54            let n_vars = inst.constraints_ref().n_vars();
55            let rand_reindexer = RandReindVarManager::init(n_vars);
56            inst.reindex(rand_reindexer)
57                .shuffle()
58                .write_dimacs_path(out_path)
59                .context("Could not write MCNF")?;
60        }
61    }
62    Ok(())
63}
Source

pub fn new_var(&mut self) -> Var

Reserves a new variable in the internal variable manager. This is a shortcut for inst.get_constraints().var_manager().new_var().

Source

pub fn new_lit(&mut self) -> Lit

Reserves a new variable in the internal variable manager. This is a shortcut for inst.get_constraints().var_manager().new_lit().

Source

pub fn max_var(&self) -> Option<Var>

Gets the used variable with the highest index. This is a shortcut for inst.get_constraints().var_manager().max_var().

Source

pub fn objective_mut(&mut self, obj_idx: usize) -> &mut Objective

Gets a mutable reference to the objective with index obj_idx for modifying it. Make sure obj_idx does not exceed the number of objectives in the instance.

§Panics

If obj_idx exceeds the number of objectives in the instance.

Source

pub fn objective_ref(&self, obj_idx: usize) -> &Objective

Gets a reference to the objective with index obj_idx. Make sure obj_idx does not exceed the number of objectives in the instance.

§Panics

If obj_idx exceeds the number of objectives in the instance.

Source

pub fn iter_obj(&self) -> impl Iterator<Item = &Objective>

Returns an iterator over references to the objectives

Source

pub fn iter_obj_mut(&mut self) -> impl Iterator<Item = &mut Objective>

Returns an iterator over mutable references to the objectives

Source

pub fn into_hard_cls_soft_cls(self) -> (Cnf, Vec<(impl WClsIter, isize)>, VM)

Converts the instance to a set of hard and soft clauses

§Panic

This might panic if the conversion to Cnf runs out of memory.

Source

pub fn into_hard_cls_soft_lits(self) -> (Cnf, Vec<(impl WLitIter, isize)>, VM)

Converts the instance to a set of hard clauses and soft literals

§Panic

This might panic if the conversion to Cnf runs out of memory.

Source

pub fn change_var_manager<VM2, VMC>( self, vm_converter: VMC, ) -> (MultiOptInstance<VM2>, VM)
where VM2: ManageVars + Default, VMC: Fn(&VM) -> VM2,

Converts the included variable manager to a different type

Source

pub fn reindex<R: ReindexVars>(self, reindexer: R) -> MultiOptInstance<R>

Re-indexes all variables in the instance with a re-indexing variable manager

Examples found in repository?
examples/shuffledimacs.rs (line 56)
26fn main() -> anyhow::Result<()> {
27    let in_path = PathBuf::from(&std::env::args().nth(1).unwrap_or_else(|| print_usage!()));
28    let out_path = PathBuf::from(&std::env::args().nth(2).unwrap_or_else(|| print_usage!()));
29
30    match determine_file_type(&in_path) {
31        FileType::Cnf => {
32            let inst = instances::SatInstance::<BasicVarManager>::from_dimacs_path(in_path)
33                .context("Could not parse CNF")?;
34            let n_vars = inst.n_vars();
35            let rand_reindexer = RandReindVarManager::init(n_vars);
36            inst.reindex(rand_reindexer)
37                .shuffle()
38                .write_dimacs_path(out_path)
39                .context("Could not write CNF")?;
40        }
41        FileType::Wcnf => {
42            let inst = instances::OptInstance::<BasicVarManager>::from_dimacs_path(in_path)
43                .context("Could not parse WCNF")?;
44            let n_vars = inst.constraints_ref().n_vars();
45            let rand_reindexer = RandReindVarManager::init(n_vars);
46            inst.reindex(rand_reindexer)
47                .shuffle()
48                .write_dimacs_path(out_path)
49                .context("Could not write WCNF")?;
50        }
51        FileType::Mcnf => {
52            let inst = instances::MultiOptInstance::<BasicVarManager>::from_dimacs_path(in_path)
53                .context("Could not parse MCNF")?;
54            let n_vars = inst.constraints_ref().n_vars();
55            let rand_reindexer = RandReindVarManager::init(n_vars);
56            inst.reindex(rand_reindexer)
57                .shuffle()
58                .write_dimacs_path(out_path)
59                .context("Could not write MCNF")?;
60        }
61    }
62    Ok(())
63}
Source

pub fn var_set(&self) -> BTreeSet<Var>

Gets the set of variables in the instance

Source

pub fn reindex_ordered<R: ReindexVars>( self, reindexer: R, ) -> MultiOptInstance<R>

Re-index all variables in the instance in order

If the re-indexing variable manager produces new free variables in order, this results in the variable order being preserved with gaps in the variable space being closed

Source

pub fn shuffle(self) -> Self

Available on crate feature rand only.

Randomly shuffles the order of constraints and the objective

Examples found in repository?
examples/shuffledimacs.rs (line 57)
26fn main() -> anyhow::Result<()> {
27    let in_path = PathBuf::from(&std::env::args().nth(1).unwrap_or_else(|| print_usage!()));
28    let out_path = PathBuf::from(&std::env::args().nth(2).unwrap_or_else(|| print_usage!()));
29
30    match determine_file_type(&in_path) {
31        FileType::Cnf => {
32            let inst = instances::SatInstance::<BasicVarManager>::from_dimacs_path(in_path)
33                .context("Could not parse CNF")?;
34            let n_vars = inst.n_vars();
35            let rand_reindexer = RandReindVarManager::init(n_vars);
36            inst.reindex(rand_reindexer)
37                .shuffle()
38                .write_dimacs_path(out_path)
39                .context("Could not write CNF")?;
40        }
41        FileType::Wcnf => {
42            let inst = instances::OptInstance::<BasicVarManager>::from_dimacs_path(in_path)
43                .context("Could not parse WCNF")?;
44            let n_vars = inst.constraints_ref().n_vars();
45            let rand_reindexer = RandReindVarManager::init(n_vars);
46            inst.reindex(rand_reindexer)
47                .shuffle()
48                .write_dimacs_path(out_path)
49                .context("Could not write WCNF")?;
50        }
51        FileType::Mcnf => {
52            let inst = instances::MultiOptInstance::<BasicVarManager>::from_dimacs_path(in_path)
53                .context("Could not parse MCNF")?;
54            let n_vars = inst.constraints_ref().n_vars();
55            let rand_reindexer = RandReindVarManager::init(n_vars);
56            inst.reindex(rand_reindexer)
57                .shuffle()
58                .write_dimacs_path(out_path)
59                .context("Could not write MCNF")?;
60        }
61    }
62    Ok(())
63}
Source

pub fn write_dimacs_path<P: AsRef<Path>>(&self, path: P) -> Result<()>

Writes the instance to a DIMACS MCNF file at a path

This requires that the instance is clausal, i.e., does not contain any non-converted cardinality of pseudo-boolean constraints. If necessary, the instance can be converted by SatInstance::convert_to_cnf or SatInstance::convert_to_cnf_with_encoders first.

§Errors
Examples found in repository?
examples/opb2mcnf.rs (line 49)
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}
More examples
Hide additional examples
examples/shuffledimacs.rs (line 58)
26fn main() -> anyhow::Result<()> {
27    let in_path = PathBuf::from(&std::env::args().nth(1).unwrap_or_else(|| print_usage!()));
28    let out_path = PathBuf::from(&std::env::args().nth(2).unwrap_or_else(|| print_usage!()));
29
30    match determine_file_type(&in_path) {
31        FileType::Cnf => {
32            let inst = instances::SatInstance::<BasicVarManager>::from_dimacs_path(in_path)
33                .context("Could not parse CNF")?;
34            let n_vars = inst.n_vars();
35            let rand_reindexer = RandReindVarManager::init(n_vars);
36            inst.reindex(rand_reindexer)
37                .shuffle()
38                .write_dimacs_path(out_path)
39                .context("Could not write CNF")?;
40        }
41        FileType::Wcnf => {
42            let inst = instances::OptInstance::<BasicVarManager>::from_dimacs_path(in_path)
43                .context("Could not parse WCNF")?;
44            let n_vars = inst.constraints_ref().n_vars();
45            let rand_reindexer = RandReindVarManager::init(n_vars);
46            inst.reindex(rand_reindexer)
47                .shuffle()
48                .write_dimacs_path(out_path)
49                .context("Could not write WCNF")?;
50        }
51        FileType::Mcnf => {
52            let inst = instances::MultiOptInstance::<BasicVarManager>::from_dimacs_path(in_path)
53                .context("Could not parse MCNF")?;
54            let n_vars = inst.constraints_ref().n_vars();
55            let rand_reindexer = RandReindVarManager::init(n_vars);
56            inst.reindex(rand_reindexer)
57                .shuffle()
58                .write_dimacs_path(out_path)
59                .context("Could not write MCNF")?;
60        }
61    }
62    Ok(())
63}
examples/gbmosplit.rs (line 642)
614fn main() -> anyhow::Result<()> {
615    let cli = Cli::init();
616
617    if let Some(path) = &cli.in_path {
618        cli.info(&format!("finding splits in {}", path.display()));
619    }
620
621    let (so_inst, write_format) = handle_error!(
622        parse_instance(&cli.in_path, cli.input_format, cli.opb_opts),
623        cli
624    );
625
626    let (mut mo_inst, split_stats) = split(so_inst, &cli);
627
628    if cli.out_path.is_some() {
629        cli.print_split_stats(split_stats);
630    }
631
632    let found_split = mo_inst.n_objectives() > 1;
633
634    let write_format = cli.output_format.infer(write_format);
635
636    if found_split || cli.always_dump {
637        match write_format {
638            WriteFormat::Mcnf => {
639                mo_inst.constraints_mut().convert_to_cnf();
640                if let Some(path) = &cli.out_path {
641                    cli.info(&format!("writing mcnf to {}", path.display()));
642                    handle_error!(mo_inst.write_dimacs_path(path), cli);
643                } else {
644                    handle_error!(
645                        mo_inst.write_dimacs(&mut io::BufWriter::new(io::stdout())),
646                        cli
647                    );
648                }
649            }
650            WriteFormat::Opb => {
651                let (mut constrs, mut objs) = mo_inst.decompose();
652                for obj in &mut objs {
653                    obj.convert_to_soft_lits(constrs.var_manager_mut());
654                }
655                let mo_inst = MultiOptInstance::compose(constrs, objs);
656                if let Some(path) = &cli.out_path {
657                    cli.info(&format!("writing opb to {}", path.display()));
658                    handle_error!(mo_inst.write_opb_path(path, cli.opb_opts), cli);
659                } else {
660                    handle_error!(
661                        mo_inst.write_opb(&mut io::BufWriter::new(io::stdout()), cli.opb_opts),
662                        cli
663                    );
664                }
665            }
666        }
667    }
668
669    if found_split {
670        std::process::exit(0);
671    }
672    std::process::exit(1);
673}
Source

pub fn write_dimacs<W: Write>(&self, writer: &mut W) -> Result<()>

Write to DIMACS MCNF

This requires that the instance is clausal, i.e., does not contain any non-converted cardinality of pseudo-boolean constraints. If necessary, the instance can be converted by SatInstance::convert_to_cnf or SatInstance::convert_to_cnf_with_encoders first.

§Performance

For performance, consider using a std::io::BufWriter instance.

§Errors
Examples found in repository?
examples/opb2mcnf.rs (line 52)
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}
More examples
Hide additional examples
examples/gbmosplit.rs (line 645)
614fn main() -> anyhow::Result<()> {
615    let cli = Cli::init();
616
617    if let Some(path) = &cli.in_path {
618        cli.info(&format!("finding splits in {}", path.display()));
619    }
620
621    let (so_inst, write_format) = handle_error!(
622        parse_instance(&cli.in_path, cli.input_format, cli.opb_opts),
623        cli
624    );
625
626    let (mut mo_inst, split_stats) = split(so_inst, &cli);
627
628    if cli.out_path.is_some() {
629        cli.print_split_stats(split_stats);
630    }
631
632    let found_split = mo_inst.n_objectives() > 1;
633
634    let write_format = cli.output_format.infer(write_format);
635
636    if found_split || cli.always_dump {
637        match write_format {
638            WriteFormat::Mcnf => {
639                mo_inst.constraints_mut().convert_to_cnf();
640                if let Some(path) = &cli.out_path {
641                    cli.info(&format!("writing mcnf to {}", path.display()));
642                    handle_error!(mo_inst.write_dimacs_path(path), cli);
643                } else {
644                    handle_error!(
645                        mo_inst.write_dimacs(&mut io::BufWriter::new(io::stdout())),
646                        cli
647                    );
648                }
649            }
650            WriteFormat::Opb => {
651                let (mut constrs, mut objs) = mo_inst.decompose();
652                for obj in &mut objs {
653                    obj.convert_to_soft_lits(constrs.var_manager_mut());
654                }
655                let mo_inst = MultiOptInstance::compose(constrs, objs);
656                if let Some(path) = &cli.out_path {
657                    cli.info(&format!("writing opb to {}", path.display()));
658                    handle_error!(mo_inst.write_opb_path(path, cli.opb_opts), cli);
659                } else {
660                    handle_error!(
661                        mo_inst.write_opb(&mut io::BufWriter::new(io::stdout()), cli.opb_opts),
662                        cli
663                    );
664                }
665            }
666        }
667    }
668
669    if found_split {
670        std::process::exit(0);
671    }
672    std::process::exit(1);
673}
Source

pub fn write_opb_path<P: AsRef<Path>>( &self, path: P, opts: Options, ) -> Result<()>

Writes the instance to an OPB file at a path

This requires that the objective does not contain soft clauses. If it does, use Objective::convert_to_soft_lits first.

§Errors
Examples found in repository?
examples/mcnf2opb.rs (line 47)
25fn main() -> anyhow::Result<()> {
26    let args = Args::parse();
27    let opb_opts = OpbOptions {
28        first_var_idx: args.first_var_idx,
29        no_negated_lits: args.avoid_negated_lits,
30    };
31
32    let inst: MultiOptInstance = if let Some(in_path) = args.in_path {
33        MultiOptInstance::from_dimacs_path(in_path).context("error parsing the input file")?
34    } else {
35        MultiOptInstance::from_dimacs(&mut io::BufReader::new(io::stdin()))
36            .context("error parsing input")?
37    };
38
39    let (mut constr, mut objs) = inst.decompose();
40    for obj in &mut objs {
41        let hardened = obj.convert_to_soft_lits(constr.var_manager_mut());
42        constr.extend(hardened.into());
43    }
44    let inst = MultiOptInstance::compose(constr, objs);
45
46    if let Some(out_path) = args.out_path {
47        inst.write_opb_path(out_path, opb_opts)
48            .context("error writing the output file")?;
49    } else {
50        inst.write_opb(&mut io::stdout(), opb_opts)
51            .context("error writing the output file")?;
52    }
53    Ok(())
54}
More examples
Hide additional examples
examples/gbmosplit.rs (line 658)
614fn main() -> anyhow::Result<()> {
615    let cli = Cli::init();
616
617    if let Some(path) = &cli.in_path {
618        cli.info(&format!("finding splits in {}", path.display()));
619    }
620
621    let (so_inst, write_format) = handle_error!(
622        parse_instance(&cli.in_path, cli.input_format, cli.opb_opts),
623        cli
624    );
625
626    let (mut mo_inst, split_stats) = split(so_inst, &cli);
627
628    if cli.out_path.is_some() {
629        cli.print_split_stats(split_stats);
630    }
631
632    let found_split = mo_inst.n_objectives() > 1;
633
634    let write_format = cli.output_format.infer(write_format);
635
636    if found_split || cli.always_dump {
637        match write_format {
638            WriteFormat::Mcnf => {
639                mo_inst.constraints_mut().convert_to_cnf();
640                if let Some(path) = &cli.out_path {
641                    cli.info(&format!("writing mcnf to {}", path.display()));
642                    handle_error!(mo_inst.write_dimacs_path(path), cli);
643                } else {
644                    handle_error!(
645                        mo_inst.write_dimacs(&mut io::BufWriter::new(io::stdout())),
646                        cli
647                    );
648                }
649            }
650            WriteFormat::Opb => {
651                let (mut constrs, mut objs) = mo_inst.decompose();
652                for obj in &mut objs {
653                    obj.convert_to_soft_lits(constrs.var_manager_mut());
654                }
655                let mo_inst = MultiOptInstance::compose(constrs, objs);
656                if let Some(path) = &cli.out_path {
657                    cli.info(&format!("writing opb to {}", path.display()));
658                    handle_error!(mo_inst.write_opb_path(path, cli.opb_opts), cli);
659                } else {
660                    handle_error!(
661                        mo_inst.write_opb(&mut io::BufWriter::new(io::stdout()), cli.opb_opts),
662                        cli
663                    );
664                }
665            }
666        }
667    }
668
669    if found_split {
670        std::process::exit(0);
671    }
672    std::process::exit(1);
673}
Source

pub fn write_opb<W: Write>(&self, writer: &mut W, opts: Options) -> Result<()>

Writes the instance to an OPB file

This requires that the objective does not contain soft clauses. If it does, use Objective::convert_to_soft_lits first.

§Performance

For performance, consider using a std::io::BufWriter instance(crate).

§Errors
Examples found in repository?
examples/mcnf2opb.rs (line 50)
25fn main() -> anyhow::Result<()> {
26    let args = Args::parse();
27    let opb_opts = OpbOptions {
28        first_var_idx: args.first_var_idx,
29        no_negated_lits: args.avoid_negated_lits,
30    };
31
32    let inst: MultiOptInstance = if let Some(in_path) = args.in_path {
33        MultiOptInstance::from_dimacs_path(in_path).context("error parsing the input file")?
34    } else {
35        MultiOptInstance::from_dimacs(&mut io::BufReader::new(io::stdin()))
36            .context("error parsing input")?
37    };
38
39    let (mut constr, mut objs) = inst.decompose();
40    for obj in &mut objs {
41        let hardened = obj.convert_to_soft_lits(constr.var_manager_mut());
42        constr.extend(hardened.into());
43    }
44    let inst = MultiOptInstance::compose(constr, objs);
45
46    if let Some(out_path) = args.out_path {
47        inst.write_opb_path(out_path, opb_opts)
48            .context("error writing the output file")?;
49    } else {
50        inst.write_opb(&mut io::stdout(), opb_opts)
51            .context("error writing the output file")?;
52    }
53    Ok(())
54}
More examples
Hide additional examples
examples/gbmosplit.rs (line 661)
614fn main() -> anyhow::Result<()> {
615    let cli = Cli::init();
616
617    if let Some(path) = &cli.in_path {
618        cli.info(&format!("finding splits in {}", path.display()));
619    }
620
621    let (so_inst, write_format) = handle_error!(
622        parse_instance(&cli.in_path, cli.input_format, cli.opb_opts),
623        cli
624    );
625
626    let (mut mo_inst, split_stats) = split(so_inst, &cli);
627
628    if cli.out_path.is_some() {
629        cli.print_split_stats(split_stats);
630    }
631
632    let found_split = mo_inst.n_objectives() > 1;
633
634    let write_format = cli.output_format.infer(write_format);
635
636    if found_split || cli.always_dump {
637        match write_format {
638            WriteFormat::Mcnf => {
639                mo_inst.constraints_mut().convert_to_cnf();
640                if let Some(path) = &cli.out_path {
641                    cli.info(&format!("writing mcnf to {}", path.display()));
642                    handle_error!(mo_inst.write_dimacs_path(path), cli);
643                } else {
644                    handle_error!(
645                        mo_inst.write_dimacs(&mut io::BufWriter::new(io::stdout())),
646                        cli
647                    );
648                }
649            }
650            WriteFormat::Opb => {
651                let (mut constrs, mut objs) = mo_inst.decompose();
652                for obj in &mut objs {
653                    obj.convert_to_soft_lits(constrs.var_manager_mut());
654                }
655                let mo_inst = MultiOptInstance::compose(constrs, objs);
656                if let Some(path) = &cli.out_path {
657                    cli.info(&format!("writing opb to {}", path.display()));
658                    handle_error!(mo_inst.write_opb_path(path, cli.opb_opts), cli);
659                } else {
660                    handle_error!(
661                        mo_inst.write_opb(&mut io::BufWriter::new(io::stdout()), cli.opb_opts),
662                        cli
663                    );
664                }
665            }
666        }
667    }
668
669    if found_split {
670        std::process::exit(0);
671    }
672    std::process::exit(1);
673}
Source

pub fn cost(&self, assign: &Assignment) -> Option<Vec<isize>>

Calculates the objective values of an assignment. Returns None if the assignment is not a solution.

Source§

impl<VM: ManageVars + Default> MultiOptInstance<VM>

Source

pub fn new(n_objs: usize) -> Self

Creates a new optimization instance

Source

pub fn from_dimacs<R: BufRead>(reader: &mut R) -> Result<Self>

Parse a DIMACS instance from a reader object.

§File Format

The file format expected by this reader is an extension of the new DIMACS WCNF format to multiple objectives, which we call DIMACS MCNF. An example of this file format is the following:

c <comment>
h 1 2 3 0
o1 5 1 0
o2 7 2 3 0

Comments start with c, as in other DIMACS formats. Hard clauses start with an h, as in WCNF files. Soft clauses are of the following form o<obj idx> <weight> <lit 1> ... <lit n> 0. The first token must be a positive number preceded by an o, indicating what objective this soft clause belongs to. After that, the format is identical to a soft clause in a WCNF file.

§Errors

Parsing errors from nom or io::Error.

Examples found in repository?
examples/mcnf2opb.rs (line 35)
25fn main() -> anyhow::Result<()> {
26    let args = Args::parse();
27    let opb_opts = OpbOptions {
28        first_var_idx: args.first_var_idx,
29        no_negated_lits: args.avoid_negated_lits,
30    };
31
32    let inst: MultiOptInstance = if let Some(in_path) = args.in_path {
33        MultiOptInstance::from_dimacs_path(in_path).context("error parsing the input file")?
34    } else {
35        MultiOptInstance::from_dimacs(&mut io::BufReader::new(io::stdin()))
36            .context("error parsing input")?
37    };
38
39    let (mut constr, mut objs) = inst.decompose();
40    for obj in &mut objs {
41        let hardened = obj.convert_to_soft_lits(constr.var_manager_mut());
42        constr.extend(hardened.into());
43    }
44    let inst = MultiOptInstance::compose(constr, objs);
45
46    if let Some(out_path) = args.out_path {
47        inst.write_opb_path(out_path, opb_opts)
48            .context("error writing the output file")?;
49    } else {
50        inst.write_opb(&mut io::stdout(), opb_opts)
51            .context("error writing the output file")?;
52    }
53    Ok(())
54}
Source

pub fn from_dimacs_path<P: AsRef<Path>>(path: P) -> Result<Self>

Parses a DIMACS instance from a file path. For more details see OptInstance::from_dimacs.

§Errors

Parsing errors from nom or io::Error.

Examples found in repository?
examples/mcnf2opb.rs (line 33)
25fn main() -> anyhow::Result<()> {
26    let args = Args::parse();
27    let opb_opts = OpbOptions {
28        first_var_idx: args.first_var_idx,
29        no_negated_lits: args.avoid_negated_lits,
30    };
31
32    let inst: MultiOptInstance = if let Some(in_path) = args.in_path {
33        MultiOptInstance::from_dimacs_path(in_path).context("error parsing the input file")?
34    } else {
35        MultiOptInstance::from_dimacs(&mut io::BufReader::new(io::stdin()))
36            .context("error parsing input")?
37    };
38
39    let (mut constr, mut objs) = inst.decompose();
40    for obj in &mut objs {
41        let hardened = obj.convert_to_soft_lits(constr.var_manager_mut());
42        constr.extend(hardened.into());
43    }
44    let inst = MultiOptInstance::compose(constr, objs);
45
46    if let Some(out_path) = args.out_path {
47        inst.write_opb_path(out_path, opb_opts)
48            .context("error writing the output file")?;
49    } else {
50        inst.write_opb(&mut io::stdout(), opb_opts)
51            .context("error writing the output file")?;
52    }
53    Ok(())
54}
More examples
Hide additional examples
examples/shuffledimacs.rs (line 52)
26fn main() -> anyhow::Result<()> {
27    let in_path = PathBuf::from(&std::env::args().nth(1).unwrap_or_else(|| print_usage!()));
28    let out_path = PathBuf::from(&std::env::args().nth(2).unwrap_or_else(|| print_usage!()));
29
30    match determine_file_type(&in_path) {
31        FileType::Cnf => {
32            let inst = instances::SatInstance::<BasicVarManager>::from_dimacs_path(in_path)
33                .context("Could not parse CNF")?;
34            let n_vars = inst.n_vars();
35            let rand_reindexer = RandReindVarManager::init(n_vars);
36            inst.reindex(rand_reindexer)
37                .shuffle()
38                .write_dimacs_path(out_path)
39                .context("Could not write CNF")?;
40        }
41        FileType::Wcnf => {
42            let inst = instances::OptInstance::<BasicVarManager>::from_dimacs_path(in_path)
43                .context("Could not parse WCNF")?;
44            let n_vars = inst.constraints_ref().n_vars();
45            let rand_reindexer = RandReindVarManager::init(n_vars);
46            inst.reindex(rand_reindexer)
47                .shuffle()
48                .write_dimacs_path(out_path)
49                .context("Could not write WCNF")?;
50        }
51        FileType::Mcnf => {
52            let inst = instances::MultiOptInstance::<BasicVarManager>::from_dimacs_path(in_path)
53                .context("Could not parse MCNF")?;
54            let n_vars = inst.constraints_ref().n_vars();
55            let rand_reindexer = RandReindVarManager::init(n_vars);
56            inst.reindex(rand_reindexer)
57                .shuffle()
58                .write_dimacs_path(out_path)
59                .context("Could not write MCNF")?;
60        }
61    }
62    Ok(())
63}
examples/check-solution.rs (line 127)
102fn parse_instance(
103    inst_path: PathBuf,
104    file_format: FileFormat,
105    opb_opts: fio::opb::Options,
106) -> anyhow::Result<MultiOptInstance> {
107    match file_format {
108        FileFormat::Infer => {
109            if let Some(ext) = inst_path.extension() {
110                let path_without_compr = inst_path.with_extension("");
111                let ext = if is_one_of!(ext, "gz", "bz2", "xz") {
112                    // Strip compression extension
113                    match path_without_compr.extension() {
114                        Some(ext) => ext,
115                        None => anyhow::bail!("no file extension after compression extension"),
116                    }
117                } else {
118                    ext
119                };
120                let inst = if is_one_of!(ext, "cnf", "dimacs") {
121                    let inst = SatInstance::from_dimacs_path(inst_path)?;
122                    MultiOptInstance::compose(inst, vec![])
123                } else if is_one_of!(ext, "wcnf") {
124                    let (inst, obj) = OptInstance::from_dimacs_path(inst_path)?.decompose();
125                    MultiOptInstance::compose(inst, vec![obj])
126                } else if is_one_of!(ext, "mcnf") {
127                    MultiOptInstance::from_dimacs_path(inst_path)?
128                } else if is_one_of!(ext, "opb", "mopb", "pbmo") {
129                    MultiOptInstance::from_opb_path(inst_path, opb_opts)?
130                } else {
131                    anyhow::bail!("unknown file extension")
132                };
133                Ok(inst)
134            } else {
135                anyhow::bail!("no file extension")
136            }
137        }
138        FileFormat::Cnf => {
139            let inst = SatInstance::from_dimacs_path(inst_path)?;
140            Ok(MultiOptInstance::compose(inst, vec![]))
141        }
142        FileFormat::Wcnf => {
143            let (inst, obj) = OptInstance::from_dimacs_path(inst_path)?.decompose();
144            Ok(MultiOptInstance::compose(inst, vec![obj]))
145        }
146        FileFormat::Mcnf => MultiOptInstance::from_dimacs_path(inst_path),
147        FileFormat::Opb => MultiOptInstance::from_opb_path(inst_path, opb_opts),
148    }
149}
Source

pub fn from_opb<R: BufRead>(reader: &mut R, opts: Options) -> Result<Self>

Parses an OPB instance from a reader object.

§File Format

The file format expected by this parser is the OPB format for pseudo-boolean optimization instances with multiple objectives defined. For details on the file format see here.

§Errors

Parsing errors from nom or io::Error.

Examples found in repository?
examples/opb2mcnf.rs (line 33)
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}
Source

pub fn from_opb_path<P: AsRef<Path>>(path: P, opts: Options) -> Result<Self>

Parses an OPB instance from a file path. For more details see MultiOptInstance::from_opb. With feature compression supports bzip2 and gzip compression, detected by the file extension.

§Errors

Parsing errors from nom or io::Error.

Examples found in repository?
examples/opb2mcnf.rs (line 30)
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}
More examples
Hide additional examples
examples/check-solution.rs (line 129)
102fn parse_instance(
103    inst_path: PathBuf,
104    file_format: FileFormat,
105    opb_opts: fio::opb::Options,
106) -> anyhow::Result<MultiOptInstance> {
107    match file_format {
108        FileFormat::Infer => {
109            if let Some(ext) = inst_path.extension() {
110                let path_without_compr = inst_path.with_extension("");
111                let ext = if is_one_of!(ext, "gz", "bz2", "xz") {
112                    // Strip compression extension
113                    match path_without_compr.extension() {
114                        Some(ext) => ext,
115                        None => anyhow::bail!("no file extension after compression extension"),
116                    }
117                } else {
118                    ext
119                };
120                let inst = if is_one_of!(ext, "cnf", "dimacs") {
121                    let inst = SatInstance::from_dimacs_path(inst_path)?;
122                    MultiOptInstance::compose(inst, vec![])
123                } else if is_one_of!(ext, "wcnf") {
124                    let (inst, obj) = OptInstance::from_dimacs_path(inst_path)?.decompose();
125                    MultiOptInstance::compose(inst, vec![obj])
126                } else if is_one_of!(ext, "mcnf") {
127                    MultiOptInstance::from_dimacs_path(inst_path)?
128                } else if is_one_of!(ext, "opb", "mopb", "pbmo") {
129                    MultiOptInstance::from_opb_path(inst_path, opb_opts)?
130                } else {
131                    anyhow::bail!("unknown file extension")
132                };
133                Ok(inst)
134            } else {
135                anyhow::bail!("no file extension")
136            }
137        }
138        FileFormat::Cnf => {
139            let inst = SatInstance::from_dimacs_path(inst_path)?;
140            Ok(MultiOptInstance::compose(inst, vec![]))
141        }
142        FileFormat::Wcnf => {
143            let (inst, obj) = OptInstance::from_dimacs_path(inst_path)?.decompose();
144            Ok(MultiOptInstance::compose(inst, vec![obj]))
145        }
146        FileFormat::Mcnf => MultiOptInstance::from_dimacs_path(inst_path),
147        FileFormat::Opb => MultiOptInstance::from_opb_path(inst_path, opb_opts),
148    }
149}

Trait Implementations§

Source§

impl<VM: Clone + ManageVars> Clone for MultiOptInstance<VM>

Source§

fn clone(&self) -> MultiOptInstance<VM>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<VM: Debug + ManageVars> Debug for MultiOptInstance<VM>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<VM: Default + ManageVars> Default for MultiOptInstance<VM>

Source§

fn default() -> MultiOptInstance<VM>

Returns the “default value” for a type. Read more
Source§

impl<'de, VM> Deserialize<'de> for MultiOptInstance<VM>
where VM: Deserialize<'de> + ManageVars,

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl<VM: ManageVars + Default> FromIterator<McnfLine> for MultiOptInstance<VM>

Source§

fn from_iter<T: IntoIterator<Item = McnfLine>>(iter: T) -> Self

Creates a value from an iterator. Read more
Source§

impl<VM: PartialEq + ManageVars> PartialEq for MultiOptInstance<VM>

Source§

fn eq(&self, other: &MultiOptInstance<VM>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<VM> Serialize for MultiOptInstance<VM>
where VM: Serialize + ManageVars,

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl<VM: Eq + ManageVars> Eq for MultiOptInstance<VM>

Source§

impl<VM: ManageVars> StructuralPartialEq for MultiOptInstance<VM>

Auto Trait Implementations§

§

impl<VM> Freeze for MultiOptInstance<VM>
where VM: Freeze,

§

impl<VM> RefUnwindSafe for MultiOptInstance<VM>
where VM: RefUnwindSafe,

§

impl<VM> Send for MultiOptInstance<VM>
where VM: Send,

§

impl<VM> Sync for MultiOptInstance<VM>
where VM: Sync,

§

impl<VM> Unpin for MultiOptInstance<VM>
where VM: Unpin,

§

impl<VM> UnwindSafe for MultiOptInstance<VM>
where VM: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,