pub struct MultiOptInstance<VM: ManageVars = BasicVarManager> { /* private fields */ }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>
impl<VM: ManageVars> MultiOptInstance<VM>
Sourcepub fn new_with_manager(n_objs: usize, var_manager: VM) -> Self
pub fn new_with_manager(n_objs: usize, var_manager: VM) -> Self
Creates a new optimization instance with a specific var manager
Sourcepub fn compose(constraints: SatInstance<VM>, objectives: Vec<Objective>) -> Self
pub fn compose(constraints: SatInstance<VM>, objectives: Vec<Objective>) -> Self
Creates a new optimization instance from constraints and objectives
Examples found in repository?
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
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}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}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}Sourcepub fn decompose(self) -> (SatInstance<VM>, Vec<Objective>)
pub fn decompose(self) -> (SatInstance<VM>, Vec<Objective>)
Decomposes the optimization instance to a SatInstance and Objectives
Examples found in repository?
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
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}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}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}Sourcepub fn n_objectives(&self) -> usize
pub fn n_objectives(&self) -> usize
Returns the number of objectives in the instance
Examples found in repository?
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}Sourcepub fn constraints_mut(&mut self) -> &mut SatInstance<VM>
pub fn constraints_mut(&mut self) -> &mut SatInstance<VM>
Gets a mutable reference to the hard constraints for modifying them
Examples found in repository?
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
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}Sourcepub fn constraints_ref(&self) -> &SatInstance<VM>
pub fn constraints_ref(&self) -> &SatInstance<VM>
Gets a reference to the hard constraints
Examples found in repository?
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}Sourcepub fn new_var(&mut self) -> Var
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().
Sourcepub fn new_lit(&mut self) -> Lit
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().
Sourcepub fn max_var(&self) -> Option<Var>
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().
Sourcepub fn objective_mut(&mut self, obj_idx: usize) -> &mut Objective
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.
Sourcepub fn objective_ref(&self, obj_idx: usize) -> &Objective
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.
Sourcepub fn iter_obj(&self) -> impl Iterator<Item = &Objective>
pub fn iter_obj(&self) -> impl Iterator<Item = &Objective>
Returns an iterator over references to the objectives
Sourcepub fn iter_obj_mut(&mut self) -> impl Iterator<Item = &mut Objective>
pub fn iter_obj_mut(&mut self) -> impl Iterator<Item = &mut Objective>
Returns an iterator over mutable references to the objectives
Sourcepub fn change_var_manager<VM2, VMC>(
self,
vm_converter: VMC,
) -> (MultiOptInstance<VM2>, VM)
pub fn change_var_manager<VM2, VMC>( self, vm_converter: VMC, ) -> (MultiOptInstance<VM2>, VM)
Converts the included variable manager to a different type
Sourcepub fn reindex<R: ReindexVars>(self, reindexer: R) -> MultiOptInstance<R>
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?
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}Sourcepub fn reindex_ordered<R: ReindexVars>(
self,
reindexer: R,
) -> MultiOptInstance<R>
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
Sourcepub fn shuffle(self) -> Self
Available on crate feature rand only.
pub fn shuffle(self) -> Self
rand only.Randomly shuffles the order of constraints and the objective
Examples found in repository?
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}Sourcepub fn write_dimacs_path<P: AsRef<Path>>(&self, path: P) -> Result<()>
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
- If the instance is not clausal, returns
RequiresClausal - Returns
io::Erroron errors during writing
Examples found in repository?
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
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}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}Sourcepub fn write_dimacs<W: Write>(&self, writer: &mut W) -> Result<()>
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
- If the instance is not clausal, returns
RequiresClausal - Returns
io::Erroron errors during writing
Examples found in repository?
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
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}Sourcepub fn write_opb_path<P: AsRef<Path>>(
&self,
path: P,
opts: Options,
) -> Result<()>
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
- If the objective contains soft literals, returns
RequiresSoftLits - Returns
io::Erroron errors during writing
Examples found in repository?
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
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}Sourcepub fn write_opb<W: Write>(&self, writer: &mut W, opts: Options) -> Result<()>
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
- If the objective contains soft literals, returns
RequiresSoftLits - Returns
io::Erroron errors during writing
Examples found in repository?
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
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§impl<VM: ManageVars + Default> MultiOptInstance<VM>
impl<VM: ManageVars + Default> MultiOptInstance<VM>
Sourcepub fn from_dimacs<R: BufRead>(reader: &mut R) -> Result<Self>
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 0Comments 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
Examples found in repository?
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}Sourcepub fn from_dimacs_path<P: AsRef<Path>>(path: P) -> Result<Self>
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
Examples found in repository?
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
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}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}Sourcepub fn from_opb<R: BufRead>(reader: &mut R, opts: Options) -> Result<Self>
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
Examples found in repository?
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}Sourcepub fn from_opb_path<P: AsRef<Path>>(path: P, opts: Options) -> Result<Self>
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
Examples found in repository?
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
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>
impl<VM: Clone + ManageVars> Clone for MultiOptInstance<VM>
Source§fn clone(&self) -> MultiOptInstance<VM>
fn clone(&self) -> MultiOptInstance<VM>
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl<VM: Debug + ManageVars> Debug for MultiOptInstance<VM>
impl<VM: Debug + ManageVars> Debug for MultiOptInstance<VM>
Source§impl<VM: Default + ManageVars> Default for MultiOptInstance<VM>
impl<VM: Default + ManageVars> Default for MultiOptInstance<VM>
Source§fn default() -> MultiOptInstance<VM>
fn default() -> MultiOptInstance<VM>
Source§impl<'de, VM> Deserialize<'de> for MultiOptInstance<VM>where
VM: Deserialize<'de> + ManageVars,
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>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl<VM: ManageVars + Default> FromIterator<McnfLine> for MultiOptInstance<VM>
impl<VM: ManageVars + Default> FromIterator<McnfLine> for MultiOptInstance<VM>
Source§impl<VM: PartialEq + ManageVars> PartialEq for MultiOptInstance<VM>
impl<VM: PartialEq + ManageVars> PartialEq for MultiOptInstance<VM>
Source§impl<VM> Serialize for MultiOptInstance<VM>where
VM: Serialize + ManageVars,
impl<VM> Serialize for MultiOptInstance<VM>where
VM: Serialize + ManageVars,
impl<VM: Eq + ManageVars> Eq for MultiOptInstance<VM>
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> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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