1pub mod bool_linear;
236pub mod cardinality;
237pub mod cardinality_one;
238pub(crate) mod helpers;
239mod integer;
240pub mod propositional_logic;
241pub mod solver;
242mod sorted;
243#[cfg(any(feature = "tracing", test))]
244pub mod trace;
245
246use std::{
247 clone::Clone,
248 cmp::{Eq, Ordering},
249 error::Error,
250 fmt::{self, Display},
251 fs::File,
252 hash::Hash,
253 io::{self, BufRead, BufReader, Write},
254 iter::{repeat_n, FusedIterator},
255 num::NonZeroI32,
256 ops::{Add, BitAnd, BitOr, BitXor, Bound, Mul, Not, RangeBounds, RangeInclusive},
257 path::Path,
258 slice,
259};
260
261use itertools::{traits::HomogeneousTuple, Itertools};
262
263pub use crate::helpers::AsDynClauseDatabase;
264use crate::{
265 bool_linear::BoolLinExp, helpers::subscript_number, propositional_logic::Formula,
266 solver::VarFactory,
267};
268
269#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
272#[expect(
273 variant_size_differences,
274 reason = "bool is 1 byte, but Lit will always require more"
275)]
276pub enum BoolVal {
277 Const(bool),
279 Lit(Lit),
281}
282
283pub trait Checker {
287 fn check<F: Valuation + ?Sized>(&self, value: &F) -> Result<(), Unsatisfiable>;
294}
295
296pub trait ClauseDatabase {
303 fn add_clause_from_slice(&mut self, clause: &[Lit]) -> Result;
308 fn new_var_range(&mut self, len: usize) -> VarRange;
311}
312
313pub trait ClauseDatabaseTools: ClauseDatabase {
317 fn add_clause<Iter>(&mut self, clause: Iter) -> Result
322 where
323 Iter: IntoIterator,
324 Iter::Item: Into<BoolVal>,
325 {
326 let result: Result<Vec<_>, ()> = clause
327 .into_iter()
328 .filter_map(|v| match v.into() {
329 BoolVal::Const(false) => None, BoolVal::Const(true) => Some(Err(())), BoolVal::Lit(lit) => Some(Ok(lit)), })
333 .collect();
334 match result {
335 Ok(clause) => {
336 let result = self.add_clause_from_slice(&clause);
337 #[cfg(any(feature = "tracing", test))]
338 {
339 tracing::info!(clause = ?&clause, fail = result.is_err(), "emit clause");
340 }
341 result
342 }
343 Err(()) => Ok(()),
345 }
346 }
347
348 fn encode<C, E>(&mut self, constraint: &C, encoder: &E) -> Result
350 where
351 C: ?Sized,
352 E: Encoder<Self, C> + ?Sized,
353 {
354 encoder.encode(self, constraint)
355 }
356
357 fn new_lit(&mut self) -> Lit {
359 self.new_var().into()
360 }
361
362 fn new_lits<T>(&mut self) -> T
371 where
372 T: HomogeneousTuple<Item = Lit>,
373 {
374 let range = self.new_var_range(T::num_items());
375 range.map(Lit::from).collect_tuple().unwrap()
376 }
377
378 #[cfg(any(feature = "tracing", test))]
379 #[inline]
380 fn new_named_lit(&mut self, name: &str) -> Lit {
383 self.new_named_var(name).into()
384 }
385
386 #[cfg(any(feature = "tracing", test))]
387 #[inline]
388 fn new_named_var(&mut self, name: &str) -> Var {
392 let var = self.new_var();
393 tracing::info!(var = ?i32::from(var), label = name, "new variable");
394 var
395 }
396
397 fn new_var(&mut self) -> Var {
400 let mut range = self.new_var_range(1);
401 debug_assert_eq!(range.len(), 1);
402 range.next().unwrap()
403 }
404
405 fn new_vars<T>(&mut self) -> T
414 where
415 T: HomogeneousTuple<Item = Var>,
416 {
417 let range = self.new_var_range(T::num_items());
418 range.collect_tuple().unwrap()
419 }
420
421 fn with_conditions(&mut self, conditions: Vec<Lit>) -> impl ClauseDatabase + '_
427 where
428 Self: AsDynClauseDatabase,
429 {
430 struct ConditionalDatabase<'a> {
431 db: &'a mut dyn ClauseDatabase,
432 conditions: Vec<Lit>,
433 }
434
435 impl ClauseDatabase for ConditionalDatabase<'_> {
436 fn add_clause_from_slice(&mut self, clause: &[Lit]) -> Result {
437 let chain = self
438 .conditions
439 .iter()
440 .copied()
441 .chain(clause.iter().copied())
442 .collect_vec();
443 self.db.add_clause_from_slice(&chain)
444 }
445
446 fn new_var_range(&mut self, len: usize) -> VarRange {
447 self.db.new_var_range(len)
448 }
449 }
450
451 ConditionalDatabase {
452 db: self.as_mut_dyn(),
453 conditions,
454 }
455 }
456}
457
458#[derive(Clone, Debug, Default)]
463pub struct Cnf {
464 nvar: VarFactory,
466 lits: Vec<Lit>,
468 size: Vec<usize>,
470}
471
472#[derive(Debug, Clone)]
473struct CnfIterator<'a> {
475 lits: &'a Vec<Lit>,
476 size: slice::Iter<'a, usize>,
477 index: usize,
478}
479
480pub(crate) type Coeff = i64;
483
484enum Dimacs {
485 Cnf(Cnf),
486 Wcnf(Wcnf),
487}
488
489pub trait Encoder<Db: ClauseDatabase + ?Sized, Constraint: ?Sized> {
491 fn encode(&self, db: &mut Db, con: &Constraint) -> Result;
493}
494
495#[derive(Debug, Clone, PartialEq, Eq, Hash)]
498pub enum IntEncoding<'a> {
499 Direct {
504 first: Coeff,
507 vals: &'a [Lit],
510 },
511 Order {
515 first: Coeff,
518 vals: &'a [Lit],
521 },
522 Log {
527 signed: bool,
529 bits: &'a [Lit],
532 },
533}
534
535#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
536pub struct Lit(NonZeroI32);
539
540type Result<T = (), E = Unsatisfiable> = std::result::Result<T, E>;
543
544#[derive(Clone, Debug, PartialEq, Eq, PartialOrd)]
545pub struct Unsatisfiable;
548
549pub trait Valuation {
551 fn value(&self, lit: Lit) -> bool;
557}
558
559#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
560pub struct Var(pub(crate) NonZeroI32);
563
564#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
565pub struct VarRange {
570 start: Var,
571 end: Var,
572}
573
574#[derive(Clone, Debug, Default)]
579pub struct Wcnf {
580 cnf: Cnf,
582 weights: Vec<Option<Coeff>>,
584 }
586
587fn parse_dimacs_file<const WEIGHTED: bool>(path: &Path) -> Result<Dimacs, io::Error> {
591 let file = File::open(path)?;
592 let mut had_header = false;
593
594 let mut wcnf = Wcnf::default();
595
596 let mut cl: Vec<Lit> = Vec::new();
597 let mut top: Option<Coeff> = None;
598
599 for line in BufReader::new(file).lines() {
600 match line {
601 Ok(line) if line.is_empty() || line.starts_with('c') => (),
602 Ok(line) if had_header => {
603 for seg in line.split(' ') {
604 if WEIGHTED {
605 if let Ok(weight) = seg.parse::<Coeff>() {
606 wcnf.weights.push(match weight.cmp(&top.unwrap()) {
607 Ordering::Less => Some(weight),
608 Ordering::Equal => None,
609 Ordering::Greater => panic!(
610 "Found weight weight {weight} greater than top {top:?} from header"
611 ),
612 });
613 } else {
614 panic!("Cannot parse line {line}");
615 }
616 }
617
618 if let Ok(lit) = seg.parse::<i32>() {
619 if lit == 0 {
620 wcnf.add_clause(cl.drain(..)).unwrap();
621 } else {
622 cl.push(Lit(NonZeroI32::new(lit).unwrap()));
623 }
624 }
625 }
626 }
627 Ok(line) => {
630 let vec: Vec<&str> = line.split_whitespace().collect();
631 if !WEIGHTED && (vec.len() != 4 || vec[0..2] != ["p", "cnf"]) {
633 return Err(io::Error::new(
634 io::ErrorKind::InvalidInput,
635 "expected DIMACS CNF header formatted \"p cnf {variables} {clauses}\"",
636 ));
637 } else if WEIGHTED && (vec.len() != 4 || vec[0..2] != ["p", "wcnf"]) {
638 return Err(io::Error::new(
639 io::ErrorKind::InvalidInput,
640 "expected DIMACS WCNF header formatted \"p wcnf {variables} {clauses} {top}\"",
641 ));
642 }
643 wcnf.cnf.nvar = VarFactory {
645 next_var: Some(Var(vec[2].parse::<NonZeroI32>().map_err(|_| {
646 io::Error::new(
647 io::ErrorKind::InvalidInput,
648 "unable to parse number of variables",
649 )
650 })?)),
651 };
652 let num_clauses: usize = vec[3].parse().map_err(|_| {
654 io::Error::new(
655 io::ErrorKind::InvalidInput,
656 "unable to parse number of clauses",
657 )
658 })?;
659
660 wcnf.cnf.lits.reserve(num_clauses);
661 wcnf.cnf.size.reserve(num_clauses);
662
663 if WEIGHTED {
664 top = Some(vec[4].parse().map_err(|_| {
665 io::Error::new(io::ErrorKind::InvalidInput, "unable to parse top weight")
666 })?);
667 }
668
669 had_header = true;
671 }
672 Err(e) => return Err(e),
673 }
674 }
675
676 if WEIGHTED {
677 Ok(Dimacs::Wcnf(wcnf))
678 } else {
679 Ok(Dimacs::Cnf(wcnf.cnf))
680 }
681}
682
683impl BitAnd<BoolVal> for BoolVal {
684 type Output = Formula<BoolVal>;
685
686 fn bitand(self, rhs: BoolVal) -> Self::Output {
687 match (self, rhs) {
688 (BoolVal::Const(a), BoolVal::Const(b)) => Formula::Atom((a & b).into()),
689 (BoolVal::Lit(a), BoolVal::Lit(b)) => (a & b).into(),
690 (BoolVal::Lit(a), BoolVal::Const(b)) | (BoolVal::Const(b), BoolVal::Lit(a)) => {
691 Formula::Atom(a & b)
692 }
693 }
694 }
695}
696
697impl BitAnd<Lit> for BoolVal {
698 type Output = Formula<BoolVal>;
699
700 fn bitand(self, rhs: Lit) -> Self::Output {
701 self & BoolVal::Lit(rhs)
702 }
703}
704
705impl BitAnd<bool> for BoolVal {
706 type Output = BoolVal;
707
708 fn bitand(self, rhs: bool) -> Self::Output {
709 match self {
710 BoolVal::Const(b) => (b & rhs).into(),
711 BoolVal::Lit(l) if rhs => (l).into(),
712 BoolVal::Lit(_) => false.into(),
713 }
714 }
715}
716
717impl BitOr<BoolVal> for BoolVal {
718 type Output = Formula<BoolVal>;
719
720 fn bitor(self, rhs: BoolVal) -> Self::Output {
721 match (self, rhs) {
722 (BoolVal::Const(a), BoolVal::Const(b)) => Formula::Atom((a | b).into()),
723 (BoolVal::Lit(a), BoolVal::Lit(b)) => (a | b).into(),
724 (BoolVal::Lit(a), BoolVal::Const(b)) | (BoolVal::Const(b), BoolVal::Lit(a)) => {
725 Formula::Atom(a | b)
726 }
727 }
728 }
729}
730
731impl BitOr<Lit> for BoolVal {
732 type Output = Formula<BoolVal>;
733
734 fn bitor(self, rhs: Lit) -> Self::Output {
735 self | BoolVal::Lit(rhs)
736 }
737}
738
739impl BitOr<bool> for BoolVal {
740 type Output = BoolVal;
741
742 fn bitor(self, rhs: bool) -> Self::Output {
743 match self {
744 BoolVal::Const(b) => (b | rhs).into(),
745 BoolVal::Lit(_) if rhs => true.into(),
746 BoolVal::Lit(_) => self,
747 }
748 }
749}
750
751impl BitXor<BoolVal> for BoolVal {
752 type Output = Formula<BoolVal>;
753
754 fn bitxor(self, rhs: BoolVal) -> Self::Output {
755 match (self, rhs) {
756 (BoolVal::Const(a), BoolVal::Const(b)) => Formula::Atom((a ^ b).into()),
757 (BoolVal::Lit(a), BoolVal::Lit(b)) => {
758 Formula::Xor(vec![Formula::Atom(a.into()), Formula::Atom(b.into())])
759 }
760 (BoolVal::Lit(a), BoolVal::Const(b)) | (BoolVal::Const(b), BoolVal::Lit(a)) => {
761 Formula::Atom((a ^ b).into())
762 }
763 }
764 }
765}
766
767impl BitXor<Lit> for BoolVal {
768 type Output = Formula<BoolVal>;
769
770 fn bitxor(self, rhs: Lit) -> Self::Output {
771 self ^ BoolVal::Lit(rhs)
772 }
773}
774
775impl BitXor<bool> for BoolVal {
776 type Output = BoolVal;
777
778 fn bitxor(self, rhs: bool) -> Self::Output {
779 if rhs {
780 !self
781 } else {
782 self
783 }
784 }
785}
786
787impl Display for BoolVal {
788 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
789 match self {
790 BoolVal::Const(b) => write!(f, "{b}"),
791 BoolVal::Lit(l) => write!(f, "{l}"),
792 }
793 }
794}
795
796impl From<Lit> for BoolVal {
797 fn from(value: Lit) -> Self {
798 BoolVal::Lit(value)
799 }
800}
801
802impl From<Var> for BoolVal {
803 fn from(value: Var) -> Self {
804 BoolVal::Lit(value.into())
805 }
806}
807
808impl From<bool> for BoolVal {
809 fn from(value: bool) -> Self {
810 BoolVal::Const(value)
811 }
812}
813
814impl Not for BoolVal {
815 type Output = BoolVal;
816
817 fn not(self) -> Self::Output {
818 match self {
819 BoolVal::Lit(l) => (!l).into(),
820 BoolVal::Const(b) => (!b).into(),
821 }
822 }
823}
824
825impl Cnf {
826 pub fn from_file(path: &Path) -> Result<Self, io::Error> {
828 match parse_dimacs_file::<false>(path)? {
829 Dimacs::Cnf(cnf) => Ok(cnf),
830 _ => unreachable!(),
831 }
832 }
833
834 #[cfg(test)]
835 pub(crate) fn get_variables(&self) -> VarRange {
838 VarRange::new(
839 Var(NonZeroI32::new(1).unwrap()),
840 self.nvar.next_var.unwrap().prev_var().unwrap(),
841 )
842 }
843
844 pub fn iter(&self) -> impl ExactSizeIterator<Item = &[Lit]> + '_ {
846 CnfIterator {
847 lits: &self.lits,
848 size: self.size.iter(),
849 index: 0,
850 }
851 }
852
853 pub fn literals(&self) -> usize {
855 self.size.iter().sum()
856 }
857 pub fn num_clauses(&self) -> usize {
859 self.size.len()
860 }
861
862 pub fn to_file(&self, path: &Path, comment: Option<&str>) -> Result<(), io::Error> {
866 let mut file = File::create(path)?;
867 if let Some(comment) = comment {
868 for line in comment.lines() {
869 writeln!(file, "c {line}")?;
870 }
871 }
872 write!(file, "{self}")
873 }
874
875 pub fn num_vars(&self) -> usize {
877 self.nvar.num_emitted_vars()
878 }
879
880 pub fn variables(&self) -> VarRange {
882 self.nvar.emitted_vars()
883 }
884}
885
886impl ClauseDatabase for Cnf {
887 fn add_clause_from_slice(&mut self, clause: &[Lit]) -> Result {
888 let size = self.lits.len();
889 self.lits.extend(clause);
890 let len = self.lits.len() - size;
891 self.size.push(len);
892 if len == 0 {
893 Err(Unsatisfiable)
894 } else {
895 Ok(())
896 }
897 }
898
899 fn new_var_range(&mut self, len: usize) -> VarRange {
900 self.nvar.next_var_range(len)
901 }
902}
903
904impl Display for Cnf {
905 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
906 let num_var = &self.num_vars();
907 let num_clauses = self.size.len();
908 writeln!(f, "p cnf {num_var} {num_clauses}")?;
909 let mut start = 0;
910 for size in self.size.iter() {
911 let cl = self.lits.iter().skip(start).take(*size);
912 for &lit in cl {
913 write!(f, "{} ", i32::from(lit))?;
914 }
915 writeln!(f, "0")?;
916 start += size;
917 }
918 Ok(())
919 }
920}
921
922impl ExactSizeIterator for CnfIterator<'_> {}
923
924impl<'a> Iterator for CnfIterator<'a> {
925 type Item = &'a [Lit];
926
927 fn count(self) -> usize {
928 self.size.count()
929 }
930
931 fn next(&mut self) -> Option<Self::Item> {
932 if let Some(size) = self.size.next() {
933 let start = self.index;
934 self.index += size;
935 Some(&self.lits[start..self.index])
936 } else {
937 None
938 }
939 }
940
941 fn size_hint(&self) -> (usize, Option<usize>) {
942 self.size.size_hint()
943 }
944}
945
946impl Add<Lit> for Coeff {
947 type Output = BoolLinExp;
948
949 fn add(self, rhs: Lit) -> Self::Output {
950 rhs + self
951 }
952}
953
954impl Mul<Lit> for Coeff {
955 type Output = BoolLinExp;
956
957 fn mul(self, rhs: Lit) -> Self::Output {
958 rhs * self
959 }
960}
961
962impl<Db: ClauseDatabase + ?Sized> ClauseDatabaseTools for Db {}
963
964impl<F: Fn(Lit) -> bool> Valuation for F {
965 fn value(&self, lit: Lit) -> bool {
966 self(lit)
967 }
968}
969
970impl Lit {
971 pub fn from_raw(value: NonZeroI32) -> Lit {
978 Lit(value)
979 }
980
981 pub fn is_negated(&self) -> bool {
983 self.0.is_negative()
984 }
985
986 pub fn var(&self) -> Var {
988 Var(self.0.abs())
989 }
990}
991
992impl Add for Lit {
993 type Output = BoolLinExp;
994
995 fn add(self, rhs: Self) -> Self::Output {
996 BoolLinExp::from_terms(&[(self, 1), (rhs, 1)])
997 }
998}
999
1000impl Add<Coeff> for Lit {
1001 type Output = BoolLinExp;
1002
1003 fn add(self, rhs: Coeff) -> Self::Output {
1004 BoolLinExp::from_terms(&[(self, 1)]) + rhs
1005 }
1006}
1007
1008impl BitAnd<BoolVal> for Lit {
1009 type Output = Formula<BoolVal>;
1010
1011 fn bitand(self, rhs: BoolVal) -> Self::Output {
1012 rhs & self
1013 }
1014}
1015
1016impl BitAnd<Lit> for Lit {
1017 type Output = Formula<Lit>;
1018
1019 fn bitand(self, rhs: Lit) -> Self::Output {
1020 Formula::And(vec![Formula::Atom(self), Formula::Atom(rhs)])
1021 }
1022}
1023
1024impl BitAnd<bool> for Lit {
1025 type Output = BoolVal;
1026
1027 fn bitand(self, rhs: bool) -> Self::Output {
1028 if rhs {
1029 self.into()
1030 } else {
1031 false.into()
1032 }
1033 }
1034}
1035
1036impl BitOr<BoolVal> for Lit {
1037 type Output = Formula<BoolVal>;
1038
1039 fn bitor(self, rhs: BoolVal) -> Self::Output {
1040 rhs | self
1041 }
1042}
1043
1044impl BitOr<Lit> for Lit {
1045 type Output = Formula<Lit>;
1046
1047 fn bitor(self, rhs: Lit) -> Self::Output {
1048 Formula::Or(vec![Formula::Atom(self), Formula::Atom(rhs)])
1049 }
1050}
1051
1052impl BitOr<bool> for Lit {
1053 type Output = BoolVal;
1054
1055 fn bitor(self, rhs: bool) -> Self::Output {
1056 if rhs {
1057 true.into()
1058 } else {
1059 self.into()
1060 }
1061 }
1062}
1063
1064impl BitXor<BoolVal> for Lit {
1065 type Output = Formula<BoolVal>;
1066
1067 fn bitxor(self, rhs: BoolVal) -> Self::Output {
1068 rhs ^ self
1069 }
1070}
1071
1072impl BitXor<Lit> for Lit {
1073 type Output = Formula<Lit>;
1074
1075 fn bitxor(self, rhs: Lit) -> Self::Output {
1076 Formula::Xor(vec![Formula::Atom(self), Formula::Atom(rhs)])
1077 }
1078}
1079
1080impl BitXor<bool> for Lit {
1081 type Output = Lit;
1082
1083 fn bitxor(self, rhs: bool) -> Self::Output {
1084 if rhs {
1085 !self
1086 } else {
1087 self
1088 }
1089 }
1090}
1091
1092impl Display for Lit {
1093 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1094 write!(
1095 f,
1096 "{}{}",
1097 if self.is_negated() { "¬" } else { "" },
1098 self.var()
1099 )
1100 }
1101}
1102
1103impl From<Var> for Lit {
1104 fn from(value: Var) -> Self {
1105 Lit(value.0)
1106 }
1107}
1108
1109impl Mul<Coeff> for Lit {
1110 type Output = BoolLinExp;
1111
1112 fn mul(self, rhs: Coeff) -> Self::Output {
1113 BoolLinExp::from_terms(&[(self, rhs)])
1114 }
1115}
1116
1117impl Not for Lit {
1118 type Output = Lit;
1119
1120 fn not(self) -> Self::Output {
1121 Lit(-self.0)
1122 }
1123}
1124
1125impl Ord for Lit {
1126 fn cmp(&self, other: &Self) -> Ordering {
1127 match self.var().cmp(&other.var()) {
1128 Ordering::Equal => (self.is_negated()).cmp(&other.is_negated()),
1129 r => r,
1130 }
1131 }
1132}
1133
1134impl PartialOrd for Lit {
1135 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1136 Some(self.cmp(other))
1137 }
1138}
1139
1140impl From<Lit> for NonZeroI32 {
1141 fn from(val: Lit) -> Self {
1142 val.0
1143 }
1144}
1145
1146impl From<Var> for NonZeroI32 {
1147 fn from(val: Var) -> Self {
1148 val.0
1149 }
1150}
1151
1152impl Display for Unsatisfiable {
1153 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1154 write!(f, "Problem inconsistency detected")
1155 }
1156}
1157
1158impl Error for Unsatisfiable {}
1159
1160impl Var {
1161 const MAX_VARS: usize = NonZeroI32::MAX.get() as usize;
1162
1163 fn checked_add(&self, b: NonZeroI32) -> Option<Var> {
1164 self.0
1165 .get()
1166 .checked_add(b.get())
1167 .map(|v| Var(NonZeroI32::new(v).unwrap()))
1168 }
1169
1170 fn next_var(&self) -> Option<Var> {
1171 const ONE: NonZeroI32 = NonZeroI32::new(1).unwrap();
1172 self.checked_add(ONE)
1173 }
1174
1175 fn prev_var(&self) -> Option<Var> {
1176 let prev = self.0.get() - 1;
1177 if prev > 0 {
1178 Some(Var(NonZeroI32::new(prev).unwrap()))
1179 } else {
1180 None
1181 }
1182 }
1183}
1184
1185impl Display for Var {
1186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1187 write!(f, "x{}", subscript_number(self.0.get() as usize).format(""))
1188 }
1189}
1190
1191impl Not for Var {
1192 type Output = Lit;
1193
1194 fn not(self) -> Self::Output {
1195 !Lit::from(self)
1196 }
1197}
1198
1199impl VarRange {
1200 pub fn empty() -> Self {
1202 Self {
1203 start: Var(NonZeroI32::new(2).unwrap()),
1204 end: Var(NonZeroI32::new(1).unwrap()),
1205 }
1206 }
1207
1208 pub fn end(&self) -> Var {
1213 self.end
1214 }
1215
1216 pub fn find(&self, var: Var) -> Option<usize> {
1218 if !self.contains(&var) {
1219 None
1220 } else {
1221 let offset = (var.0.get() - self.start.0.get()) as usize;
1222 debug_assert!(offset <= self.len());
1223 Some(offset)
1224 }
1225 }
1226
1227 pub fn index(&self, index: usize) -> Var {
1229 if index >= self.len() {
1230 panic!("out of bounds access");
1231 }
1232 if index == 0 {
1233 self.start
1234 } else {
1235 let index = NonZeroI32::new(index as i32).unwrap();
1236 self.start.checked_add(index).unwrap()
1237 }
1238 }
1239
1240 pub const fn is_empty(&self) -> bool {
1249 self.len() == 0
1250 }
1251
1252 pub fn iter_lits(&mut self) -> impl Iterator<Item = Lit> + '_ {
1255 self.map(Lit::from)
1256 }
1257
1258 pub const fn len(&self) -> usize {
1260 let len = self.end.0.get() - self.start.0.get() + 1;
1261 if len < 0 {
1262 return 0;
1263 }
1264 len as usize
1265 }
1266
1267 pub fn new(start: Var, end: Var) -> Self {
1269 Self { start, end }
1270 }
1271
1272 pub fn start(&self) -> Var {
1277 self.start
1278 }
1279}
1280
1281impl DoubleEndedIterator for VarRange {
1282 fn next_back(&mut self) -> Option<Self::Item> {
1283 if self.start <= self.end {
1284 let item = self.end;
1285 if let Some(prev) = self.end.prev_var() {
1286 self.end = prev;
1287 } else {
1288 *self = VarRange::empty();
1289 }
1290 Some(item)
1291 } else {
1292 None
1293 }
1294 }
1295}
1296
1297impl ExactSizeIterator for VarRange {
1298 fn len(&self) -> usize {
1299 self.len()
1300 }
1301}
1302
1303impl From<RangeInclusive<Var>> for VarRange {
1304 fn from(value: RangeInclusive<Var>) -> Self {
1305 VarRange::new(*value.start(), *value.end())
1306 }
1307}
1308
1309impl FusedIterator for VarRange {}
1310
1311impl Iterator for VarRange {
1312 type Item = Var;
1313
1314 fn count(self) -> usize {
1315 let (lower, upper) = self.size_hint();
1316 debug_assert_eq!(upper, Some(lower));
1317 lower
1318 }
1319
1320 fn next(&mut self) -> Option<Self::Item> {
1321 if self.start <= self.end {
1322 let item = self.start;
1323 self.start = self.start.next_var().unwrap();
1324 Some(item)
1325 } else {
1326 None
1327 }
1328 }
1329
1330 fn size_hint(&self) -> (usize, Option<usize>) {
1331 let len = self.len();
1332 (len, Some(len))
1333 }
1334}
1335
1336impl RangeBounds<Var> for VarRange {
1337 fn end_bound(&self) -> Bound<&Var> {
1338 Bound::Included(&self.end)
1339 }
1340 fn start_bound(&self) -> Bound<&Var> {
1341 Bound::Included(&self.start)
1342 }
1343}
1344
1345impl Wcnf {
1346 pub fn add_weighted_clause<I>(&mut self, clause: I, weight: Coeff) -> Result
1348 where
1349 I: IntoIterator,
1350 I::Item: Into<BoolVal>,
1351 {
1352 let clauses = self.cnf.num_clauses();
1353 self.cnf.add_clause(clause)?;
1354 if self.cnf.num_clauses() > clauses {
1355 self.weights.push(Some(weight));
1356 }
1357 Ok(())
1358 }
1359
1360 pub fn num_clauses(&self) -> usize {
1362 self.cnf.num_clauses()
1363 }
1364
1365 pub fn num_vars(&self) -> usize {
1367 self.cnf.num_vars()
1368 }
1369
1370 pub fn from_file(path: &Path) -> Result<Self, io::Error> {
1372 match parse_dimacs_file::<true>(path)? {
1373 Dimacs::Wcnf(wcnf) => Ok(wcnf),
1374 _ => unreachable!(),
1375 }
1376 }
1377
1378 pub fn iter(&self) -> impl ExactSizeIterator<Item = (&[Lit], &Option<Coeff>)> {
1380 self.cnf.iter().zip(self.weights.iter())
1381 }
1382
1383 pub fn literals(&self) -> usize {
1385 self.cnf.literals()
1386 }
1387
1388 pub fn to_file(&self, path: &Path, comment: Option<&str>) -> Result<(), io::Error> {
1392 let mut file = File::create(path)?;
1393 if let Some(comment) = comment {
1394 for line in comment.lines() {
1395 writeln!(file, "c {line}")?;
1396 }
1397 }
1398 write!(file, "{self}")
1399 }
1400
1401 pub fn variables(&self) -> VarRange {
1403 self.cnf.variables()
1404 }
1405}
1406
1407impl ClauseDatabase for Wcnf {
1408 fn add_clause_from_slice(&mut self, clause: &[Lit]) -> Result {
1409 let clauses = self.cnf.num_clauses();
1410 self.cnf.add_clause_from_slice(clause)?;
1411 if self.cnf.num_clauses() > clauses {
1412 self.weights.push(None);
1413 }
1414 Ok(())
1415 }
1416
1417 fn new_var_range(&mut self, len: usize) -> VarRange {
1418 self.cnf.new_var_range(len)
1419 }
1420}
1421
1422impl Display for Wcnf {
1423 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1424 let num_var = &self.cnf.nvar.num_emitted_vars();
1425 let num_clauses = self.cnf.size.len();
1426 let top = self.weights.iter().flatten().fold(1, |a, b| a + *b);
1427 writeln!(f, "p wcnf {num_var} {num_clauses} {top}")?;
1428 let mut start = 0;
1429 for (size, weight) in self.cnf.size.iter().zip(self.weights.iter()) {
1430 let cl = self.cnf.lits.iter().skip(start).take(*size);
1431 let weight = weight.unwrap_or(top);
1432 write!(f, "{weight} ")?;
1433 for lit in cl {
1434 write!(f, "{} ", lit.0)?;
1435 }
1436 writeln!(f, "0")?;
1437 start += size;
1438 }
1439 Ok(())
1440 }
1441}
1442
1443impl From<Cnf> for Wcnf {
1444 fn from(cnf: Cnf) -> Self {
1445 let weights = repeat_n(None, cnf.num_clauses()).collect();
1446 Wcnf { cnf, weights }
1447 }
1448}
1449
1450impl From<Lit> for i32 {
1451 fn from(val: Lit) -> Self {
1452 val.0.get()
1453 }
1454}
1455
1456impl From<Var> for i32 {
1457 fn from(val: Var) -> Self {
1458 val.0.get()
1459 }
1460}
1461
1462#[cfg(test)]
1463mod tests {
1464 use std::num::NonZeroI32;
1465
1466 use crate::{solver::VarFactory, Lit, Var};
1467
1468 #[test]
1469 fn var_range() {
1470 let mut factory = VarFactory::default();
1471
1472 let range = factory.next_var_range(0);
1473 assert_eq!(range.len(), 0);
1474 assert_eq!(factory.next_var, Some(Var(NonZeroI32::new(1).unwrap())));
1475
1476 let range = factory.next_var_range(1);
1477 assert_eq!(range.len(), 1);
1478 assert_eq!(factory.next_var, Some(Var(NonZeroI32::new(2).unwrap())));
1479
1480 let range = factory.next_var_range(2);
1481 assert_eq!(range.len(), 2);
1482 assert_eq!(factory.next_var, Some(Var(NonZeroI32::new(4).unwrap())));
1483
1484 let range = factory.next_var_range(100);
1485 assert_eq!(range.len(), 100);
1486 assert_eq!(factory.next_var, Some(Var(NonZeroI32::new(104).unwrap())));
1487 }
1488
1489 impl From<i32> for Lit {
1490 fn from(value: i32) -> Self {
1491 Lit(NonZeroI32::new(value).expect("cannot create literal with value zero"))
1492 }
1493 }
1494}