1use core::slice;
8use std::{
9 collections::TryReserveError,
10 fmt,
11 ops::{self, Not, RangeBounds},
12};
13
14use itertools::Itertools;
15use thiserror::Error;
16
17use super::{Assignment, IWLitIter, Lit, LitIter, RsHashSet, TernaryVal, WLitIter};
18
19use crate::RequiresClausal;
20
21#[derive(Clone, Copy, Debug, PartialEq, Eq)]
23pub enum ConstraintRef<'constr> {
24 Clause(&'constr Clause),
26 Card(&'constr CardConstraint),
28 Pb(&'constr PbConstraint),
30}
31
32impl fmt::Display for ConstraintRef<'_> {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 match self {
35 ConstraintRef::Clause(cl) => write!(f, "{cl}"),
36 ConstraintRef::Card(card) => write!(f, "{card}"),
37 ConstraintRef::Pb(pb) => write!(f, "{pb}"),
38 }
39 }
40}
41
42#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Default)]
46#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
47pub struct Clause {
48 lits: Vec<Lit>,
49}
50
51impl std::hash::Hash for Clause {
52 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
53 self.lits.hash(state);
54 }
55}
56
57impl Clause {
58 #[must_use]
60 pub fn new() -> Self {
61 Self::default()
62 }
63
64 #[must_use]
68 pub fn with_capacity(capacity: usize) -> Self {
69 Self {
70 lits: Vec::with_capacity(capacity),
71 }
72 }
73
74 pub fn reserve(&mut self, additional: usize) {
78 self.lits.reserve(additional);
79 }
80
81 pub fn reserve_exact(&mut self, additional: usize) {
85 self.lits.reserve_exact(additional);
86 }
87
88 pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
96 self.lits.try_reserve(additional)
97 }
98
99 pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
107 self.lits.try_reserve_exact(additional)
108 }
109
110 pub fn drain<R: RangeBounds<usize>>(&mut self, range: R) -> std::vec::Drain<'_, Lit> {
112 self.lits.drain(range)
113 }
114
115 #[must_use]
119 pub fn normalize(mut self) -> Option<Self> {
120 if self.len() <= 1 {
121 return Some(self);
122 }
123 self.lits.sort_unstable();
125 self.lits.dedup();
126 let mut neg_last = None;
128 if let Err(()) = self.iter().try_for_each(|l| {
129 if let Some(neg_last) = neg_last {
130 if l == &neg_last {
131 return Err(());
133 }
134 }
135 neg_last = Some(!*l);
136 Ok(())
137 }) {
138 return None;
139 }
140 Some(self)
141 }
142
143 #[must_use]
147 pub fn sanitize(mut self) -> Option<Self> {
148 if self.len() <= 1 {
149 return Some(self);
150 }
151 let mut lset = RsHashSet::default();
152 let mut idx = 0;
153 while idx < self.len() {
154 let l = self[idx];
155 if lset.contains(&!l) {
156 return None;
158 }
159 if lset.contains(&l) {
160 self.lits.remove(idx);
161 } else {
162 lset.insert(l);
163 idx += 1;
164 }
165 }
166 Some(self)
167 }
168
169 pub fn add(&mut self, lit: Lit) {
171 self.lits.push(lit);
172 }
173
174 pub fn remove(&mut self, lit: Lit) -> bool {
177 for (i, l) in self.lits.iter().enumerate() {
178 if *l == lit {
179 self.lits.swap_remove(i);
180 return true;
181 }
182 }
183 false
184 }
185
186 pub fn remove_thorough(&mut self, lit: Lit) -> bool {
188 let mut idxs = Vec::new();
189 for (i, l) in self.lits.iter().enumerate() {
190 if *l == lit {
191 idxs.push(i);
192 }
193 }
194 for i in idxs.iter().rev() {
195 self.lits.remove(*i);
196 }
197 !idxs.is_empty()
198 }
199}
200
201impl ops::Deref for Clause {
202 type Target = Cl;
203
204 fn deref(&self) -> &Self::Target {
205 Cl::new(self)
206 }
207}
208
209impl std::ops::DerefMut for Clause {
210 fn deref_mut(&mut self) -> &mut Self::Target {
211 Cl::new_mut(self)
212 }
213}
214
215impl AsRef<[Lit]> for Clause {
216 fn as_ref(&self) -> &[Lit] {
217 &self.lits
218 }
219}
220
221impl AsMut<[Lit]> for Clause {
222 fn as_mut(&mut self) -> &mut [Lit] {
223 &mut self.lits
224 }
225}
226
227impl AsRef<Cl> for Clause {
228 fn as_ref(&self) -> &Cl {
229 Cl::new(self)
230 }
231}
232
233impl AsMut<Cl> for Clause {
234 fn as_mut(&mut self) -> &mut Cl {
235 Cl::new_mut(self)
236 }
237}
238
239impl<const N: usize> From<[Lit; N]> for Clause {
240 fn from(value: [Lit; N]) -> Self {
241 Self {
242 lits: Vec::from(value),
243 }
244 }
245}
246
247impl From<&[Lit]> for Clause {
248 fn from(value: &[Lit]) -> Self {
249 Self {
250 lits: Vec::from(value),
251 }
252 }
253}
254
255impl Extend<Lit> for Clause {
256 fn extend<T: IntoIterator<Item = Lit>>(&mut self, iter: T) {
257 self.lits.extend(iter);
258 }
259}
260
261impl IntoIterator for Clause {
262 type Item = Lit;
263
264 type IntoIter = std::vec::IntoIter<Lit>;
265
266 #[inline]
267 fn into_iter(self) -> Self::IntoIter {
268 self.lits.into_iter()
269 }
270}
271
272impl FromIterator<Lit> for Clause {
273 fn from_iter<T: IntoIterator<Item = Lit>>(iter: T) -> Self {
274 Self {
275 lits: Vec::from_iter(iter),
276 }
277 }
278}
279
280impl<'a> IntoIterator for &'a Clause {
281 type Item = &'a Lit;
282
283 type IntoIter = std::slice::Iter<'a, Lit>;
284
285 fn into_iter(self) -> Self::IntoIter {
286 self.lits.iter()
287 }
288}
289
290impl<'a> IntoIterator for &'a mut Clause {
291 type Item = &'a mut Lit;
292
293 type IntoIter = std::slice::IterMut<'a, Lit>;
294
295 fn into_iter(self) -> Self::IntoIter {
296 self.lits.iter_mut()
297 }
298}
299
300impl fmt::Display for Clause {
301 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
302 write!(f, "({})", self.iter().format("|"))
303 }
304}
305
306impl fmt::Debug for Clause {
307 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
308 write!(f, "({})", self.iter().format("|"))
309 }
310}
311
312#[cfg(feature = "proof-logging")]
313impl pigeons::ConstraintLike<crate::types::Var> for Clause {
314 fn rhs(&self) -> isize {
315 1
316 }
317
318 fn sum_iter(&self) -> impl Iterator<Item = (isize, pigeons::Axiom<crate::types::Var>)> {
319 self.lits.iter().map(|l| (1, pigeons::Axiom::from(*l)))
320 }
321}
322
323#[cfg(feature = "proof-logging")]
324impl pigeons::ConstraintLike<crate::types::Var> for Cl {
325 fn rhs(&self) -> isize {
326 1
327 }
328
329 fn sum_iter(&self) -> impl Iterator<Item = (isize, pigeons::Axiom<crate::types::Var>)> {
330 self.lits.iter().map(|l| (1, pigeons::Axiom::from(*l)))
331 }
332}
333
334#[macro_export]
336macro_rules! clause {
337 () => {
338 $crate::types::Clause::new()
339 };
340 ( $($l:expr),* ) => {
341 {
342 let mut tmp_clause = $crate::types::Clause::new();
343 $(
344 tmp_clause.add($l);
345 )*
346 tmp_clause
347 }
348 };
349}
350
351#[derive(PartialEq, Eq, Hash)]
355#[repr(transparent)]
356pub struct Cl {
357 lits: [Lit],
358}
359
360impl Cl {
361 pub fn new<S: AsRef<[Lit]> + ?Sized>(s: &S) -> &Cl {
374 unsafe { &*(std::ptr::from_ref::<[Lit]>(s.as_ref()) as *const Cl) }
375 }
376
377 pub fn new_mut<S: AsMut<[Lit]> + ?Sized>(s: &mut S) -> &mut Cl {
379 unsafe { &mut *(std::ptr::from_mut::<[Lit]>(s.as_mut()) as *mut Cl) }
380 }
381
382 #[inline]
384 #[must_use]
385 pub fn len(&self) -> usize {
386 self.lits.len()
387 }
388
389 #[inline]
391 #[must_use]
392 pub fn is_empty(&self) -> bool {
393 self.lits.is_empty()
394 }
395
396 #[inline]
398 pub fn iter(&self) -> impl Iterator<Item = &Lit> {
399 self.lits.iter()
400 }
401
402 #[inline]
404 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Lit> {
405 self.lits.iter_mut()
406 }
407
408 #[must_use]
410 pub fn evaluate(&self, assignment: &Assignment) -> TernaryVal {
411 self.iter()
412 .fold(TernaryVal::False, |val, l| match assignment.lit_value(*l) {
413 TernaryVal::True => TernaryVal::True,
414 TernaryVal::DontCare => {
415 if val == TernaryVal::False {
416 TernaryVal::DontCare
417 } else {
418 val
419 }
420 }
421 TernaryVal::False => val,
422 })
423 }
424
425 #[must_use]
427 pub fn is_tautology(&self) -> bool {
428 if self.is_empty() {
429 return false;
430 }
431 for (idx, &l1) in self[0..self.len() - 1].iter().enumerate() {
432 for &l2 in &self[idx + 1..] {
433 if l1 == !l2 {
434 return true;
435 }
436 }
437 }
438 false
439 }
440
441 pub fn sort(&mut self) {
443 self.lits.sort_unstable();
444 }
445
446 #[inline]
448 #[must_use]
449 pub fn is_unit(&self) -> bool {
450 self.lits.len() == 1
451 }
452
453 #[inline]
455 #[must_use]
456 pub fn is_binary(&self) -> bool {
457 self.lits.len() == 2
458 }
459}
460
461impl AsRef<[Lit]> for Cl {
462 fn as_ref(&self) -> &[Lit] {
463 &self.lits
464 }
465}
466
467impl AsMut<[Lit]> for Cl {
468 fn as_mut(&mut self) -> &mut [Lit] {
469 &mut self.lits
470 }
471}
472
473impl<I> ops::Index<I> for Cl
474where
475 I: slice::SliceIndex<[Lit]>,
476{
477 type Output = <I as slice::SliceIndex<[Lit]>>::Output;
478
479 #[inline]
480 fn index(&self, index: I) -> &Self::Output {
481 &self.lits[index]
482 }
483}
484
485impl<I> ops::IndexMut<I> for Cl
486where
487 I: slice::SliceIndex<[Lit]>,
488{
489 #[inline]
490 fn index_mut(&mut self, index: I) -> &mut Self::Output {
491 &mut self.lits[index]
492 }
493}
494
495impl<'a> IntoIterator for &'a Cl {
496 type Item = &'a Lit;
497
498 type IntoIter = std::slice::Iter<'a, Lit>;
499
500 #[inline]
501 fn into_iter(self) -> Self::IntoIter {
502 self.lits.iter()
503 }
504}
505
506impl<'a> IntoIterator for &'a mut Cl {
507 type Item = &'a mut Lit;
508
509 type IntoIter = std::slice::IterMut<'a, Lit>;
510
511 #[inline]
512 fn into_iter(self) -> Self::IntoIter {
513 self.lits.iter_mut()
514 }
515}
516
517impl fmt::Display for Cl {
518 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
519 write!(f, "({})", self.iter().format("|"))
520 }
521}
522
523impl fmt::Debug for Cl {
524 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
525 write!(f, "({})", self.iter().format("|"))
526 }
527}
528
529impl AsRef<Cl> for [Lit] {
530 fn as_ref(&self) -> &Cl {
531 Cl::new(self)
532 }
533}
534
535impl AsMut<Cl> for [Lit] {
536 fn as_mut(&mut self) -> &mut Cl {
537 Cl::new_mut(self)
538 }
539}
540
541#[derive(Hash, Eq, PartialEq, Clone, Debug)]
543#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
544pub enum CardConstraint {
545 Ub(CardUbConstr),
547 Lb(CardLbConstr),
549 Eq(CardEqConstr),
551}
552
553impl fmt::Display for CardConstraint {
554 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
555 match self {
556 CardConstraint::Ub(c) => write!(f, "{c}"),
557 CardConstraint::Lb(c) => write!(f, "{c}"),
558 CardConstraint::Eq(c) => write!(f, "{c}"),
559 }
560 }
561}
562
563macro_rules! write_lit_sum {
564 ($f:expr, $vec:expr) => {{
565 for i in 0..$vec.len() {
566 if i < $vec.len() - 1 {
567 write!($f, "{} + ", $vec[i])?;
568 } else {
569 write!($f, "{}", $vec[i])?;
570 }
571 }
572 }};
573}
574
575impl CardConstraint {
576 #[must_use]
578 pub fn new_unit(lit: Lit) -> Self {
579 CardConstraint::Lb(CardLbConstr {
580 lits: vec![lit],
581 b: 1,
582 })
583 }
584
585 pub fn new_ub<LI: LitIter>(lits: LI, b: usize) -> Self {
587 CardConstraint::Ub(CardUbConstr {
588 lits: lits.into_iter().collect(),
589 b,
590 })
591 }
592
593 pub fn new_lb<LI: LitIter>(lits: LI, b: usize) -> Self {
595 CardConstraint::Lb(CardLbConstr {
596 lits: lits.into_iter().collect(),
597 b,
598 })
599 }
600
601 pub fn new_eq<LI: LitIter>(lits: LI, b: usize) -> Self {
603 CardConstraint::Eq(CardEqConstr {
604 lits: lits.into_iter().collect(),
605 b,
606 })
607 }
608
609 pub fn add<LI: LitIter>(&mut self, lits: LI) {
611 match self {
612 CardConstraint::Ub(constr) => constr.lits.extend(lits),
613 CardConstraint::Lb(constr) => constr.lits.extend(lits),
614 CardConstraint::Eq(constr) => constr.lits.extend(lits),
615 }
616 }
617
618 #[must_use]
620 pub fn bound(&self) -> usize {
621 match self {
622 CardConstraint::Ub(CardUbConstr { b, .. })
623 | CardConstraint::Lb(CardLbConstr { b, .. })
624 | CardConstraint::Eq(CardEqConstr { b, .. }) => *b,
625 }
626 }
627
628 #[must_use]
630 pub fn len(&self) -> usize {
631 match self {
632 CardConstraint::Ub(constr) => constr.lits.len(),
633 CardConstraint::Lb(constr) => constr.lits.len(),
634 CardConstraint::Eq(constr) => constr.lits.len(),
635 }
636 }
637
638 #[must_use]
640 pub fn is_empty(&self) -> bool {
641 self.len() == 0
642 }
643
644 #[must_use]
646 pub fn n_lits(&self) -> usize {
647 self.len()
648 }
649
650 #[deprecated(
652 since = "0.7.0",
653 note = "`change_bound` has been renamed to `set_bound`"
654 )]
655 pub fn change_bound(&mut self, b: usize) {
656 self.set_bound(b);
657 }
658
659 pub fn set_bound(&mut self, bound: usize) {
661 match self {
662 CardConstraint::Ub(CardUbConstr { b, .. })
663 | CardConstraint::Lb(CardLbConstr { b, .. })
664 | CardConstraint::Eq(CardEqConstr { b, .. }) => *b = bound,
665 }
666 }
667
668 #[must_use]
670 pub fn is_tautology(&self) -> bool {
671 match self {
672 CardConstraint::Ub(constr) => constr.is_tautology(),
673 CardConstraint::Lb(constr) => constr.is_tautology(),
674 CardConstraint::Eq(_) => false,
675 }
676 }
677
678 #[must_use]
680 pub fn is_unsat(&self) -> bool {
681 match self {
682 CardConstraint::Ub(_) => false,
683 CardConstraint::Lb(constr) => constr.is_unsat(),
684 CardConstraint::Eq(constr) => constr.is_unsat(),
685 }
686 }
687
688 #[must_use]
690 pub fn is_positive_assignment(&self) -> bool {
691 match self {
692 CardConstraint::Ub(_) => false,
693 CardConstraint::Lb(constr) => constr.is_positive_assignment(),
694 CardConstraint::Eq(constr) => constr.is_positive_assignment(),
695 }
696 }
697
698 #[must_use]
700 pub fn is_negative_assignment(&self) -> bool {
701 match self {
702 CardConstraint::Ub(constr) => constr.is_negative_assignment(),
703 CardConstraint::Lb(_) => false,
704 CardConstraint::Eq(constr) => constr.is_negative_assignment(),
705 }
706 }
707
708 #[must_use]
710 pub fn is_clause(&self) -> bool {
711 match self {
712 CardConstraint::Ub(constr) => constr.is_clause(),
713 CardConstraint::Lb(constr) => constr.is_clause(),
714 CardConstraint::Eq(_) => false,
715 }
716 }
717
718 #[must_use]
721 pub fn normalize(mut self) -> Self {
722 let norm = |lits: &mut Vec<Lit>| {
723 if lits.len() <= 1 {
724 return;
725 }
726 lits.sort_unstable();
727 };
728 match &mut self {
729 CardConstraint::Ub(constr) => norm(&mut constr.lits),
730 CardConstraint::Lb(constr) => norm(&mut constr.lits),
731 CardConstraint::Eq(constr) => norm(&mut constr.lits),
732 }
733 self
734 }
735
736 #[must_use]
738 pub fn into_lits(self) -> Vec<Lit> {
739 match self {
740 CardConstraint::Ub(constr) => constr.lits,
741 CardConstraint::Lb(constr) => constr.lits,
742 CardConstraint::Eq(constr) => constr.lits,
743 }
744 }
745
746 pub fn into_clause(self) -> Result<Clause, RequiresClausal> {
752 if !self.is_clause() {
753 return Err(RequiresClausal);
754 }
755 match self {
756 CardConstraint::Ub(constr) => Ok(constr.lits.into_iter().map(Lit::not).collect()),
757 CardConstraint::Lb(constr) => Ok(Clause::from_iter(constr.lits)),
758 CardConstraint::Eq(_) => unreachable!(),
759 }
760 }
761
762 #[inline]
764 pub fn iter(&self) -> std::slice::Iter<'_, Lit> {
765 match self {
766 CardConstraint::Ub(constr) => constr.lits.iter(),
767 CardConstraint::Lb(constr) => constr.lits.iter(),
768 CardConstraint::Eq(constr) => constr.lits.iter(),
769 }
770 }
771
772 #[inline]
774 pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, Lit> {
775 match self {
776 CardConstraint::Ub(constr) => constr.lits.iter_mut(),
777 CardConstraint::Lb(constr) => constr.lits.iter_mut(),
778 CardConstraint::Eq(constr) => constr.lits.iter_mut(),
779 }
780 }
781
782 #[must_use]
784 pub fn evaluate(&self, assign: &Assignment) -> TernaryVal {
785 #[allow(clippy::range_plus_one)]
786 let range = self
787 .iter()
788 .fold(0..0, |rng, &lit| match assign.lit_value(lit) {
789 TernaryVal::True => rng.start + 1..rng.end + 1,
790 TernaryVal::False => rng,
791 TernaryVal::DontCare => rng.start..rng.end + 1,
792 });
793 if range.contains(&self.bound()) {
794 return TernaryVal::DontCare;
795 }
796 match self {
797 CardConstraint::Ub(CardUbConstr { b, .. }) => (range.start <= *b).into(),
798 CardConstraint::Lb(CardLbConstr { b, .. }) => (range.start >= *b).into(),
799 CardConstraint::Eq(CardEqConstr { b, .. }) => (range.start == *b).into(),
800 }
801 }
802}
803
804impl<'slf> IntoIterator for &'slf CardConstraint {
805 type Item = &'slf Lit;
806
807 type IntoIter = std::slice::Iter<'slf, Lit>;
808
809 fn into_iter(self) -> Self::IntoIter {
810 self.iter()
811 }
812}
813
814impl<'slf> IntoIterator for &'slf mut CardConstraint {
815 type Item = &'slf mut Lit;
816
817 type IntoIter = std::slice::IterMut<'slf, Lit>;
818
819 fn into_iter(self) -> Self::IntoIter {
820 self.iter_mut()
821 }
822}
823
824impl From<Clause> for CardConstraint {
825 fn from(value: Clause) -> Self {
826 CardConstraint::new_lb(value, 1)
827 }
828}
829
830#[cfg(feature = "proof-logging")]
831impl pigeons::ConstraintLike<crate::types::Var> for CardConstraint {
832 fn rhs(&self) -> isize {
833 match self {
834 CardConstraint::Ub(c) => {
835 isize::try_from(c.lits.len())
836 .expect("cannot handle more than `isize::MAX` literals")
837 - isize::try_from(c.b).expect("cannot handle bounds larger than `isize::MAX`")
838 }
839 CardConstraint::Lb(c) => {
840 isize::try_from(c.b).expect("cannot handle bounds larger than `isize::MAX`")
841 }
842 CardConstraint::Eq(_) => {
843 panic!("VeriPB does not support equality constraints in the proof")
844 }
845 }
846 }
847
848 fn sum_iter(&self) -> impl Iterator<Item = (isize, pigeons::Axiom<crate::types::Var>)> {
849 match self {
850 CardConstraint::Ub(CardUbConstr { lits, .. }) => PigeonLitIter {
851 lits: lits.iter(),
852 negate: true,
853 },
854 CardConstraint::Lb(CardLbConstr { lits, .. })
855 | CardConstraint::Eq(CardEqConstr { lits, .. }) => PigeonLitIter {
856 lits: lits.iter(),
857 negate: false,
858 },
859 }
860 }
861}
862
863#[cfg(feature = "proof-logging")]
864struct PigeonLitIter<'a> {
865 lits: std::slice::Iter<'a, Lit>,
866 negate: bool,
867}
868
869#[cfg(feature = "proof-logging")]
870impl Iterator for PigeonLitIter<'_> {
871 type Item = (isize, pigeons::Axiom<crate::types::Var>);
872
873 fn next(&mut self) -> Option<Self::Item> {
874 self.lits.next().map(|l| {
875 (
876 1,
877 if self.negate {
878 pigeons::Axiom::from(!*l)
879 } else {
880 pigeons::Axiom::from(*l)
881 },
882 )
883 })
884 }
885}
886
887#[derive(Hash, Eq, PartialEq, Clone, Debug)]
889#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
890pub struct CardUbConstr {
891 lits: Vec<Lit>,
892 b: usize,
893}
894
895impl fmt::Display for CardUbConstr {
896 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
897 write_lit_sum!(f, self.lits);
898 write!(f, " <= {}", self.b)
899 }
900}
901
902impl CardUbConstr {
903 #[must_use]
905 pub fn decompose(self) -> (Vec<Lit>, usize) {
906 (self.lits, self.b)
907 }
908
909 pub(crate) fn decompose_ref(&self) -> (&Vec<Lit>, &usize) {
911 (&self.lits, &self.b)
912 }
913
914 #[must_use]
916 pub fn invert(mut self) -> CardLbConstr {
917 self.lits.iter_mut().for_each(|l| {
918 *l = !*l;
919 });
920 let length = self.lits.len();
921 CardLbConstr {
922 lits: self.lits,
923 b: length - self.b,
924 }
925 }
926
927 #[must_use]
929 pub fn is_tautology(&self) -> bool {
930 self.b >= self.lits.len()
931 }
932
933 #[must_use]
935 pub fn is_negative_assignment(&self) -> bool {
936 self.b == 0
937 }
938
939 #[must_use]
941 pub fn is_clause(&self) -> bool {
942 self.b + 1 == self.lits.len()
943 }
944}
945
946#[derive(Hash, Eq, PartialEq, Clone, Debug)]
948#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
949pub struct CardLbConstr {
950 lits: Vec<Lit>,
951 b: usize,
952}
953
954impl fmt::Display for CardLbConstr {
955 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
956 write_lit_sum!(f, self.lits);
957 write!(f, " >= {}", self.b)
958 }
959}
960
961impl CardLbConstr {
962 #[must_use]
964 pub fn decompose(self) -> (Vec<Lit>, usize) {
965 (self.lits, self.b)
966 }
967
968 pub(crate) fn decompose_ref(&self) -> (&Vec<Lit>, &usize) {
970 (&self.lits, &self.b)
971 }
972
973 #[must_use]
975 pub fn invert(mut self) -> CardUbConstr {
976 self.lits.iter_mut().for_each(|l| {
977 *l = !*l;
978 });
979 let length = self.lits.len();
980 CardUbConstr {
981 lits: self.lits,
982 b: length - self.b,
983 }
984 }
985
986 #[must_use]
988 pub fn is_tautology(&self) -> bool {
989 self.b == 0
990 }
991
992 #[must_use]
994 pub fn is_unsat(&self) -> bool {
995 self.b > self.lits.len()
996 }
997
998 #[must_use]
1000 pub fn is_positive_assignment(&self) -> bool {
1001 self.b == self.lits.len()
1002 }
1003
1004 #[must_use]
1006 pub fn is_clause(&self) -> bool {
1007 self.b == 1
1008 }
1009}
1010
1011#[derive(Hash, Eq, PartialEq, Clone, Debug)]
1013#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1014pub struct CardEqConstr {
1015 lits: Vec<Lit>,
1016 b: usize,
1017}
1018
1019impl fmt::Display for CardEqConstr {
1020 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1021 write_lit_sum!(f, self.lits);
1022 write!(f, " = {}", self.b)
1023 }
1024}
1025
1026impl CardEqConstr {
1027 #[must_use]
1029 pub fn decompose(self) -> (Vec<Lit>, usize) {
1030 (self.lits, self.b)
1031 }
1032
1033 pub(crate) fn decompose_ref(&self) -> (&Vec<Lit>, &usize) {
1035 (&self.lits, &self.b)
1036 }
1037
1038 #[must_use]
1040 pub fn split(self) -> (CardLbConstr, CardUbConstr) {
1041 (
1042 CardLbConstr {
1043 lits: self.lits.clone(),
1044 b: self.b,
1045 },
1046 CardUbConstr {
1047 lits: self.lits,
1048 b: self.b,
1049 },
1050 )
1051 }
1052
1053 #[must_use]
1055 pub fn is_unsat(&self) -> bool {
1056 self.b > self.lits.len()
1057 }
1058
1059 #[must_use]
1061 pub fn is_positive_assignment(&self) -> bool {
1062 self.b == self.lits.len()
1063 }
1064
1065 #[must_use]
1067 pub fn is_negative_assignment(&self) -> bool {
1068 self.b == 0
1069 }
1070}
1071
1072#[derive(Error, Debug)]
1074pub enum PbToCardError {
1075 #[error("the PB constraint is not a cardinality constraint")]
1077 NotACard,
1078 #[error("the PB constraint is unsatisfiable")]
1080 Unsat,
1081 #[error("the PB constraint is a tautology")]
1083 Tautology,
1084}
1085
1086#[derive(Eq, PartialEq, Clone, Debug)]
1090#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1091pub enum PbConstraint {
1092 Ub(PbUbConstr),
1094 Lb(PbLbConstr),
1096 Eq(PbEqConstr),
1098}
1099
1100impl fmt::Display for PbConstraint {
1101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1102 match self {
1103 PbConstraint::Ub(c) => write!(f, "{c}"),
1104 PbConstraint::Lb(c) => write!(f, "{c}"),
1105 PbConstraint::Eq(c) => write!(f, "{c}"),
1106 }
1107 }
1108}
1109
1110macro_rules! write_wlit_sum {
1111 ($f:expr, $vec:expr) => {{
1112 for i in 0..$vec.len() {
1113 if i < $vec.len() - 1 {
1114 write!($f, "{} {} + ", $vec[i].1, $vec[i].0)?;
1115 } else {
1116 write!($f, "{} {}", $vec[i].1, $vec[i].0)?;
1117 }
1118 }
1119 }};
1120}
1121
1122impl PbConstraint {
1123 #[must_use]
1125 pub fn new_unit(lit: Lit) -> Self {
1126 PbConstraint::Lb(PbLbConstr {
1127 lits: vec![(lit, 1)],
1128 weight_sum: 1,
1129 b: 1,
1130 })
1131 }
1132
1133 fn convert_input_lits<LI: IWLitIter>(lits: LI) -> (impl WLitIter, usize, isize) {
1135 let mut b_add = 0;
1136 let mut weight_sum = 0;
1137 let lits: Vec<(Lit, usize)> = lits
1138 .into_iter()
1139 .map(|(l, w)| {
1140 if w >= 0 {
1141 weight_sum += w.unsigned_abs();
1142 (l, w.unsigned_abs())
1143 } else {
1144 b_add -= w;
1145 weight_sum += w.unsigned_abs();
1146 (!l, w.unsigned_abs())
1147 }
1148 })
1149 .collect();
1150 (lits, weight_sum, b_add)
1151 }
1152
1153 pub fn new_ub<LI: IWLitIter>(lits: LI, b: isize) -> Self {
1155 let (lits, weight_sum, b_add) = PbConstraint::convert_input_lits(lits);
1156 PbConstraint::Ub(PbUbConstr {
1157 lits: lits.into_iter().collect(),
1158 weight_sum,
1159 b: b + b_add,
1160 })
1161 }
1162
1163 pub fn new_ub_unsigned<LI: WLitIter>(lits: LI, b: isize) -> Self {
1165 let lits: Vec<_> = lits.into_iter().collect();
1166 let weight_sum = lits.iter().fold(0, |sum, (_, w)| sum + w);
1167 PbConstraint::Ub(PbUbConstr {
1168 lits,
1169 weight_sum,
1170 b,
1171 })
1172 }
1173
1174 pub fn new_lb<LI: IWLitIter>(lits: LI, b: isize) -> Self {
1176 let (lits, weight_sum, b_add) = PbConstraint::convert_input_lits(lits);
1177 PbConstraint::Lb(PbLbConstr {
1178 lits: lits.into_iter().collect(),
1179 weight_sum,
1180 b: b + b_add,
1181 })
1182 }
1183
1184 pub fn new_lb_unsigned<LI: WLitIter>(lits: LI, b: isize) -> Self {
1186 let lits: Vec<_> = lits.into_iter().collect();
1187 let weight_sum = lits.iter().fold(0, |sum, (_, w)| sum + w);
1188 PbConstraint::Lb(PbLbConstr {
1189 lits,
1190 weight_sum,
1191 b,
1192 })
1193 }
1194
1195 pub fn new_eq<LI: IWLitIter>(lits: LI, b: isize) -> Self {
1197 let (lits, weight_sum, b_add) = PbConstraint::convert_input_lits(lits);
1198 PbConstraint::Eq(PbEqConstr {
1199 lits: lits.into_iter().collect(),
1200 weight_sum,
1201 b: b + b_add,
1202 })
1203 }
1204
1205 pub fn new_eq_unsigned<LI: WLitIter>(lits: LI, b: isize) -> Self {
1207 let lits: Vec<_> = lits.into_iter().collect();
1208 let weight_sum = lits.iter().fold(0, |sum, (_, w)| sum + w);
1209 PbConstraint::Eq(PbEqConstr {
1210 lits,
1211 weight_sum,
1212 b,
1213 })
1214 }
1215
1216 #[must_use]
1218 pub fn weight_sum(&self) -> usize {
1219 match self {
1220 PbConstraint::Ub(c) => c.weight_sum,
1221 PbConstraint::Lb(c) => c.weight_sum,
1222 PbConstraint::Eq(c) => c.weight_sum,
1223 }
1224 }
1225
1226 fn get_data(&mut self) -> (&mut Vec<(Lit, usize)>, &mut usize, &mut isize) {
1228 match self {
1229 PbConstraint::Ub(constr) => (&mut constr.lits, &mut constr.weight_sum, &mut constr.b),
1230 PbConstraint::Lb(constr) => (&mut constr.lits, &mut constr.weight_sum, &mut constr.b),
1231 PbConstraint::Eq(constr) => (&mut constr.lits, &mut constr.weight_sum, &mut constr.b),
1232 }
1233 }
1234
1235 pub fn set_bound(&mut self, bound: isize) {
1237 match self {
1238 PbConstraint::Ub(PbUbConstr { b, .. })
1239 | PbConstraint::Lb(PbLbConstr { b, .. })
1240 | PbConstraint::Eq(PbEqConstr { b, .. }) => *b = bound,
1241 }
1242 }
1243
1244 pub fn add<LI: IWLitIter>(&mut self, lits: LI) {
1246 let (lits, add_weight_sum, b_add) = PbConstraint::convert_input_lits(lits);
1247 let (data_lits, weight_sum, b) = self.get_data();
1248 data_lits.extend(lits);
1249 *weight_sum += add_weight_sum;
1250 *b += b_add;
1251 }
1252
1253 #[must_use]
1255 pub fn bound(&self) -> isize {
1256 match self {
1257 PbConstraint::Ub(PbUbConstr { b, .. })
1258 | PbConstraint::Lb(PbLbConstr { b, .. })
1259 | PbConstraint::Eq(PbEqConstr { b, .. }) => *b,
1260 }
1261 }
1262
1263 #[must_use]
1265 pub fn len(&self) -> usize {
1266 match self {
1267 PbConstraint::Ub(constr) => constr.lits.len(),
1268 PbConstraint::Lb(constr) => constr.lits.len(),
1269 PbConstraint::Eq(constr) => constr.lits.len(),
1270 }
1271 }
1272
1273 #[must_use]
1275 pub fn is_empty(&self) -> bool {
1276 self.len() == 0
1277 }
1278
1279 #[must_use]
1281 pub fn n_lits(&self) -> usize {
1282 self.len()
1283 }
1284
1285 #[must_use]
1287 pub fn is_tautology(&self) -> bool {
1288 match self {
1289 PbConstraint::Ub(constr) => constr.is_tautology(),
1290 PbConstraint::Lb(constr) => constr.is_tautology(),
1291 PbConstraint::Eq(_) => false,
1292 }
1293 }
1294
1295 #[must_use]
1297 pub fn is_unsat(&self) -> bool {
1298 match self {
1299 PbConstraint::Ub(constr) => constr.is_unsat(),
1300 PbConstraint::Lb(constr) => constr.is_unsat(),
1301 PbConstraint::Eq(constr) => constr.is_unsat(),
1302 }
1303 }
1304
1305 #[must_use]
1307 pub fn is_positive_assignment(&self) -> bool {
1308 match self {
1309 PbConstraint::Ub(_) => false,
1310 PbConstraint::Lb(constr) => constr.is_positive_assignment(),
1311 PbConstraint::Eq(constr) => constr.is_positive_assignment(),
1312 }
1313 }
1314
1315 #[must_use]
1317 pub fn is_negative_assignment(&self) -> bool {
1318 match self {
1319 PbConstraint::Ub(constr) => constr.is_negative_assignment(),
1320 PbConstraint::Lb(_) => false,
1321 PbConstraint::Eq(constr) => constr.is_negative_assignment(),
1322 }
1323 }
1324
1325 #[must_use]
1327 pub fn is_card(&self) -> bool {
1328 match self {
1329 PbConstraint::Ub(constr) => constr.find_unit_weight().is_some(),
1330 PbConstraint::Lb(constr) => constr.find_unit_weight().is_some(),
1331 PbConstraint::Eq(constr) => constr.find_unit_weight().is_some(),
1332 }
1333 }
1334
1335 #[must_use]
1337 pub fn is_clause(&self) -> bool {
1338 match self {
1339 PbConstraint::Ub(constr) => constr.is_clause(),
1340 PbConstraint::Lb(constr) => constr.is_clause(),
1341 PbConstraint::Eq(_) => false,
1342 }
1343 }
1344
1345 #[must_use]
1348 pub fn normalize(self) -> Self {
1349 let norm = |mut lits: Vec<(Lit, usize)>| {
1350 if lits.len() <= 1 {
1351 return lits;
1352 }
1353 lits.sort_unstable();
1354 let mut merged = Vec::new();
1355 for (l, w) in lits {
1356 match merged.last_mut() {
1357 Some((l2, w2)) => {
1358 if l == *l2 {
1359 *w2 += w;
1360 } else {
1361 merged.push((l, w));
1362 }
1363 }
1364 None => merged.push((l, w)),
1365 }
1366 }
1367 merged
1368 };
1369 match self {
1370 PbConstraint::Ub(constr) => PbConstraint::Ub(PbUbConstr {
1371 lits: norm(constr.lits),
1372 ..constr
1373 }),
1374 PbConstraint::Lb(constr) => PbConstraint::Lb(PbLbConstr {
1375 lits: norm(constr.lits),
1376 ..constr
1377 }),
1378 PbConstraint::Eq(constr) => PbConstraint::Eq(PbEqConstr {
1379 lits: norm(constr.lits),
1380 ..constr
1381 }),
1382 }
1383 }
1384
1385 pub fn into_card_constr(self) -> Result<CardConstraint, PbToCardError> {
1393 if self.is_tautology() {
1394 return Err(PbToCardError::Tautology);
1395 }
1396 if self.is_unsat() {
1397 return Err(PbToCardError::Unsat);
1398 }
1399 Ok(match self {
1400 PbConstraint::Ub(constr) => {
1401 let unit_weight = constr.find_unit_weight();
1402 let b = constr.b.unsigned_abs();
1404 match unit_weight {
1405 None => return Err(PbToCardError::NotACard),
1406 Some(unit_weight) => {
1407 let lits = constr.lits.into_iter().map(|(l, _)| l);
1408 CardConstraint::new_ub(lits, b / unit_weight)
1409 }
1410 }
1411 }
1412 PbConstraint::Lb(constr) => {
1413 let unit_weight = constr.find_unit_weight();
1414 let b = constr.b.unsigned_abs();
1416 match unit_weight {
1417 None => return Err(PbToCardError::NotACard),
1418 Some(unit_weight) => {
1419 let lits = constr.lits.into_iter().map(|(l, _)| l);
1420 CardConstraint::new_lb(
1421 lits,
1422 b / unit_weight + usize::from(b % unit_weight != 0),
1423 )
1424 }
1425 }
1426 }
1427 PbConstraint::Eq(constr) => {
1428 let unit_weight = constr.find_unit_weight();
1429 let b = constr.b.unsigned_abs();
1431 match unit_weight {
1432 None => return Err(PbToCardError::NotACard),
1433 Some(unit_weight) => {
1434 if b % unit_weight != 0 {
1435 return Err(PbToCardError::Unsat);
1436 }
1437 let lits = constr.lits.into_iter().map(|(l, _)| l);
1438 CardConstraint::new_eq(lits, b / unit_weight)
1439 }
1440 }
1441 }
1442 })
1443 }
1444
1445 #[must_use]
1452 pub fn extend_to_card_constr(self) -> CardConstraint {
1453 match self {
1454 PbConstraint::Ub(constr) => CardConstraint::Ub(constr.extend_to_card_constr()),
1455 PbConstraint::Lb(constr) => CardConstraint::Lb(constr.extend_to_card_constr()),
1456 PbConstraint::Eq(constr) => CardConstraint::Eq(constr.extend_to_card_constr()),
1457 }
1458 }
1459
1460 pub fn into_clause(self) -> Result<Clause, RequiresClausal> {
1466 if !self.is_clause() {
1467 return Err(RequiresClausal);
1468 }
1469 match self {
1470 PbConstraint::Ub(constr) => Ok(constr.lits.into_iter().map(|(lit, _)| !lit).collect()),
1471 PbConstraint::Lb(constr) => Ok(constr.lits.into_iter().map(|(lit, _)| lit).collect()),
1472 PbConstraint::Eq(_) => unreachable!(),
1473 }
1474 }
1475
1476 #[must_use]
1478 pub fn into_lits(self) -> impl WLitIter {
1479 match self {
1480 PbConstraint::Ub(constr) => constr.lits,
1481 PbConstraint::Lb(constr) => constr.lits,
1482 PbConstraint::Eq(constr) => constr.lits,
1483 }
1484 }
1485
1486 #[inline]
1488 pub fn iter(&self) -> std::slice::Iter<'_, (Lit, usize)> {
1489 match self {
1490 PbConstraint::Ub(constr) => constr.lits.iter(),
1491 PbConstraint::Lb(constr) => constr.lits.iter(),
1492 PbConstraint::Eq(constr) => constr.lits.iter(),
1493 }
1494 }
1495
1496 #[inline]
1498 pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, (Lit, usize)> {
1499 match self {
1500 PbConstraint::Ub(constr) => constr.lits.iter_mut(),
1501 PbConstraint::Lb(constr) => constr.lits.iter_mut(),
1502 PbConstraint::Eq(constr) => constr.lits.iter_mut(),
1503 }
1504 }
1505
1506 #[must_use]
1508 pub fn evaluate(&self, assign: &Assignment) -> TernaryVal {
1509 #[allow(clippy::range_plus_one)]
1510 let range = self
1511 .iter()
1512 .fold(0..0, |rng, &(lit, coeff)| match assign.lit_value(lit) {
1513 TernaryVal::True => rng.start + coeff..rng.end + coeff,
1514 TernaryVal::False => rng,
1515 TernaryVal::DontCare => rng.start..rng.end + coeff,
1516 });
1517 match (isize::try_from(range.start), isize::try_from(range.end)) {
1518 (Ok(start), Ok(end)) => {
1519 if (start..end).contains(&self.bound()) {
1520 return TernaryVal::DontCare;
1521 }
1522 match self {
1523 PbConstraint::Ub(PbUbConstr { b, .. }) => (start <= *b).into(),
1524 PbConstraint::Lb(PbLbConstr { b, .. }) => (start >= *b).into(),
1525 PbConstraint::Eq(PbEqConstr { b, .. }) => (start == *b).into(),
1526 }
1527 }
1528 (Ok(start), Err(_)) => match self {
1529 PbConstraint::Ub(PbUbConstr { b, .. }) => {
1530 if (start..).contains(b) {
1531 return TernaryVal::DontCare;
1532 }
1533 TernaryVal::True
1534 }
1535 PbConstraint::Lb(PbLbConstr { b, .. }) | PbConstraint::Eq(PbEqConstr { b, .. }) => {
1536 if (start..).contains(b) {
1537 return TernaryVal::DontCare;
1538 }
1539 TernaryVal::False
1540 }
1541 },
1542 (Err(_), Err(_)) => matches!(self, PbConstraint::Lb(_)).into(),
1543 (Err(_), Ok(_)) => unreachable!(), }
1545 }
1546}
1547
1548#[cfg(feature = "proof-logging")]
1549impl pigeons::ConstraintLike<crate::types::Var> for PbConstraint {
1550 fn rhs(&self) -> isize {
1551 match self {
1552 PbConstraint::Ub(c) => {
1553 isize::try_from(c.weight_sum).expect("can handle at most `isize::MAX` weight sum")
1554 - c.b
1555 }
1556 PbConstraint::Lb(c) => c.b,
1557 PbConstraint::Eq(_) => {
1558 panic!("VeriPB does not support equality constraints in the proof")
1559 }
1560 }
1561 }
1562
1563 fn sum_iter(&self) -> impl Iterator<Item = (isize, pigeons::Axiom<crate::types::Var>)> {
1564 match self {
1565 PbConstraint::Ub(PbUbConstr { lits, .. }) => PigeonWLitIter {
1566 lits: lits.iter(),
1567 negate: true,
1568 },
1569 PbConstraint::Lb(PbLbConstr { lits, .. })
1570 | PbConstraint::Eq(PbEqConstr { lits, .. }) => PigeonWLitIter {
1571 lits: lits.iter(),
1572 negate: false,
1573 },
1574 }
1575 }
1576}
1577
1578#[cfg(feature = "proof-logging")]
1579struct PigeonWLitIter<'a> {
1580 lits: std::slice::Iter<'a, (Lit, usize)>,
1581 negate: bool,
1582}
1583
1584#[cfg(feature = "proof-logging")]
1585impl Iterator for PigeonWLitIter<'_> {
1586 type Item = (isize, pigeons::Axiom<crate::types::Var>);
1587
1588 fn next(&mut self) -> Option<Self::Item> {
1589 self.lits.next().map(|(l, w)| {
1590 (
1591 isize::try_from(*w).expect("can only handle coefficients up to `isize::MAX`"),
1592 if self.negate {
1593 pigeons::Axiom::from(!*l)
1594 } else {
1595 pigeons::Axiom::from(*l)
1596 },
1597 )
1598 })
1599 }
1600}
1601
1602impl<'slf> IntoIterator for &'slf PbConstraint {
1603 type Item = &'slf (Lit, usize);
1604
1605 type IntoIter = std::slice::Iter<'slf, (Lit, usize)>;
1606
1607 fn into_iter(self) -> Self::IntoIter {
1608 self.iter()
1609 }
1610}
1611
1612impl<'slf> IntoIterator for &'slf mut PbConstraint {
1613 type Item = &'slf mut (Lit, usize);
1614
1615 type IntoIter = std::slice::IterMut<'slf, (Lit, usize)>;
1616
1617 fn into_iter(self) -> Self::IntoIter {
1618 self.iter_mut()
1619 }
1620}
1621
1622impl From<Clause> for PbConstraint {
1623 fn from(value: Clause) -> Self {
1624 PbConstraint::new_lb(value.into_iter().map(|l| (l, 1)), 1)
1625 }
1626}
1627
1628impl From<CardConstraint> for PbConstraint {
1629 fn from(value: CardConstraint) -> Self {
1630 match value {
1631 CardConstraint::Ub(constr) => PbConstraint::new_ub(
1632 constr.lits.into_iter().map(|l| (l, 1)),
1633 isize::try_from(constr.b).expect("cannot handle bounds higher than `isize::MAX`"),
1634 ),
1635 CardConstraint::Lb(constr) => PbConstraint::new_lb(
1636 constr.lits.into_iter().map(|l| (l, 1)),
1637 isize::try_from(constr.b).expect("cannot handle bounds higher than `isize::MAX`"),
1638 ),
1639 CardConstraint::Eq(constr) => PbConstraint::new_eq(
1640 constr.lits.into_iter().map(|l| (l, 1)),
1641 isize::try_from(constr.b).expect("cannot handle bounds higher than `isize::MAX`"),
1642 ),
1643 }
1644 }
1645}
1646
1647#[derive(Eq, PartialEq, Clone, Debug)]
1649#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1650pub struct PbUbConstr {
1651 lits: Vec<(Lit, usize)>,
1652 weight_sum: usize,
1653 b: isize,
1654}
1655
1656impl fmt::Display for PbUbConstr {
1657 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1658 write_wlit_sum!(f, self.lits);
1659 write!(f, " <= {}", self.b)
1660 }
1661}
1662
1663impl PbUbConstr {
1664 #[must_use]
1666 pub fn decompose(self) -> (Vec<(Lit, usize)>, isize) {
1667 (self.lits, self.b)
1668 }
1669
1670 pub(crate) fn decompose_ref(&self) -> (&Vec<(Lit, usize)>, &isize) {
1672 (&self.lits, &self.b)
1673 }
1674
1675 #[must_use]
1681 pub fn invert(mut self) -> PbLbConstr {
1682 self.lits.iter_mut().for_each(|(l, _)| {
1683 *l = !*l;
1684 });
1685 PbLbConstr {
1686 lits: self.lits,
1687 weight_sum: self.weight_sum,
1688 b: -self.b
1689 + isize::try_from(self.weight_sum)
1690 .expect("cannot handle weight sum larger than `isize::MAX`"),
1691 }
1692 }
1693
1694 #[must_use]
1701 pub fn extend_to_card_constr(self) -> CardUbConstr {
1702 CardUbConstr {
1703 lits: self
1704 .lits
1705 .into_iter()
1706 .flat_map(|(l, w)| std::iter::repeat(l).take(w))
1707 .collect(),
1708 b: self.b.unsigned_abs(),
1709 }
1710 }
1711
1712 #[must_use]
1714 pub fn is_tautology(&self) -> bool {
1715 if self.b < 0 {
1716 return false;
1717 }
1718 self.b.unsigned_abs() >= self.weight_sum
1719 }
1720
1721 #[must_use]
1723 pub fn is_unsat(&self) -> bool {
1724 self.b < 0
1725 }
1726
1727 #[must_use]
1729 pub fn is_negative_assignment(&self) -> bool {
1730 if self.is_unsat() {
1731 return false;
1732 }
1733 let min_coeff: usize = self
1734 .lits
1735 .iter()
1736 .fold(usize::MAX, |min, (_, coeff)| std::cmp::min(min, *coeff));
1737 min_coeff > self.b.unsigned_abs()
1739 }
1740
1741 #[must_use]
1743 pub fn find_unit_weight(&self) -> Option<usize> {
1744 let mut unit_weight = None;
1745 for (_, w) in &self.lits {
1746 if let Some(uw) = unit_weight {
1747 if uw != *w {
1748 return None;
1749 }
1750 } else {
1751 unit_weight = Some(*w);
1752 }
1753 }
1754 unit_weight
1755 }
1756
1757 #[must_use]
1759 pub fn is_clause(&self) -> bool {
1760 if self.is_tautology() {
1761 return false;
1762 }
1763 if self.is_unsat() {
1764 return false;
1765 }
1766 let min_coeff: usize = self
1767 .lits
1768 .iter()
1769 .fold(usize::MAX, |min, (_, coeff)| std::cmp::min(min, *coeff));
1770 self.weight_sum <= self.b.unsigned_abs() + min_coeff
1772 && self.weight_sum > self.b.unsigned_abs()
1773 }
1774}
1775
1776#[derive(Eq, PartialEq, Clone, Debug)]
1778#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1779pub struct PbLbConstr {
1780 lits: Vec<(Lit, usize)>,
1781 weight_sum: usize,
1782 b: isize,
1783}
1784
1785impl fmt::Display for PbLbConstr {
1786 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1787 write_wlit_sum!(f, self.lits);
1788 write!(f, " >= {}", self.b)
1789 }
1790}
1791
1792impl PbLbConstr {
1793 #[must_use]
1795 pub fn decompose(self) -> (Vec<(Lit, usize)>, isize) {
1796 (self.lits, self.b)
1797 }
1798
1799 pub(crate) fn decompose_ref(&self) -> (&Vec<(Lit, usize)>, &isize) {
1801 (&self.lits, &self.b)
1802 }
1803
1804 #[must_use]
1810 pub fn invert(mut self) -> PbUbConstr {
1811 self.lits.iter_mut().for_each(|(l, _)| {
1812 *l = !*l;
1813 });
1814 PbUbConstr {
1815 lits: self.lits,
1816 weight_sum: self.weight_sum,
1817 b: -self.b
1818 + isize::try_from(self.weight_sum)
1819 .expect("cannot handle weight sum larger than `isize::MAX`"),
1820 }
1821 }
1822
1823 #[must_use]
1830 pub fn extend_to_card_constr(self) -> CardLbConstr {
1831 CardLbConstr {
1832 lits: self
1833 .lits
1834 .into_iter()
1835 .flat_map(|(l, w)| std::iter::repeat(l).take(w))
1836 .collect(),
1837 b: self.b.unsigned_abs(),
1838 }
1839 }
1840
1841 #[must_use]
1843 pub fn is_tautology(&self) -> bool {
1844 self.b <= 0
1845 }
1846
1847 #[must_use]
1849 pub fn is_unsat(&self) -> bool {
1850 if self.b < 0 {
1851 return false;
1852 }
1853 self.b.unsigned_abs() > self.weight_sum
1854 }
1855
1856 #[must_use]
1858 pub fn is_positive_assignment(&self) -> bool {
1859 if self.b < 0 || self.is_unsat() {
1860 return false;
1861 }
1862 let min_coeff: usize = self
1863 .lits
1864 .iter()
1865 .fold(usize::MAX, |min, (_, coeff)| std::cmp::min(min, *coeff));
1866 self.b.unsigned_abs() + min_coeff > self.weight_sum
1868 }
1869
1870 #[must_use]
1872 pub fn find_unit_weight(&self) -> Option<usize> {
1873 let mut unit_weight = None;
1874 for (_, w) in &self.lits {
1875 if let Some(uw) = unit_weight {
1876 if uw != *w {
1877 return None;
1878 }
1879 } else {
1880 unit_weight = Some(*w);
1881 }
1882 }
1883 unit_weight
1884 }
1885
1886 #[must_use]
1888 pub fn is_clause(&self) -> bool {
1889 if self.is_tautology() {
1890 return false;
1891 }
1892 if self.is_unsat() {
1893 return false;
1894 }
1895 let min_coeff: usize = self
1896 .lits
1897 .iter()
1898 .fold(usize::MAX, |min, (_, coeff)| std::cmp::min(min, *coeff));
1899 self.b.unsigned_abs() <= min_coeff
1901 }
1902}
1903
1904#[derive(Eq, PartialEq, Clone, Debug)]
1906#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1907pub struct PbEqConstr {
1908 lits: Vec<(Lit, usize)>,
1909 weight_sum: usize,
1910 b: isize,
1911}
1912
1913impl fmt::Display for PbEqConstr {
1914 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1915 write_wlit_sum!(f, self.lits);
1916 write!(f, " = {}", self.b)
1917 }
1918}
1919
1920impl PbEqConstr {
1921 #[must_use]
1923 pub fn decompose(self) -> (Vec<(Lit, usize)>, isize) {
1924 (self.lits, self.b)
1925 }
1926
1927 pub(crate) fn decompose_ref(&self) -> (&Vec<(Lit, usize)>, &isize) {
1929 (&self.lits, &self.b)
1930 }
1931
1932 #[must_use]
1934 pub fn split(self) -> (PbLbConstr, PbUbConstr) {
1935 (
1936 PbLbConstr {
1937 lits: self.lits.clone(),
1938 weight_sum: self.weight_sum,
1939 b: self.b,
1940 },
1941 PbUbConstr {
1942 lits: self.lits,
1943 weight_sum: self.weight_sum,
1944 b: self.b,
1945 },
1946 )
1947 }
1948
1949 #[must_use]
1956 pub fn extend_to_card_constr(self) -> CardEqConstr {
1957 CardEqConstr {
1958 lits: self
1959 .lits
1960 .into_iter()
1961 .flat_map(|(l, w)| std::iter::repeat(l).take(w))
1962 .collect(),
1963 b: self.b.unsigned_abs(),
1964 }
1965 }
1966
1967 #[must_use]
1972 pub fn is_unsat(&self) -> bool {
1973 if self.b < 0 {
1974 return true;
1975 }
1976 self.b.unsigned_abs() > self.weight_sum
1977 }
1978
1979 #[must_use]
1981 pub fn is_positive_assignment(&self) -> bool {
1982 if self.b < 0 {
1983 return false;
1984 }
1985 self.b.unsigned_abs() == self.weight_sum
1986 }
1987
1988 #[must_use]
1990 pub fn is_negative_assignment(&self) -> bool {
1991 if self.b < 0 {
1992 return false;
1993 }
1994 self.b.unsigned_abs() == 0
1995 }
1996
1997 #[must_use]
1999 pub fn find_unit_weight(&self) -> Option<usize> {
2000 let mut unit_weight = None;
2001 for (_, w) in &self.lits {
2002 if let Some(uw) = unit_weight {
2003 if uw != *w {
2004 return None;
2005 }
2006 } else {
2007 unit_weight = Some(*w);
2008 }
2009 }
2010 unit_weight
2011 }
2012}
2013
2014#[cfg(test)]
2015mod tests {
2016 use super::{CardConstraint, Cl, PbConstraint};
2017 use crate::{
2018 lit,
2019 types::{Assignment, TernaryVal},
2020 var,
2021 };
2022
2023 #[test]
2024 fn clause_remove() {
2025 let mut cl = clause![lit![0], lit![1], lit![2], lit![1]];
2026 assert!(!cl.remove(lit![3]));
2027 assert!(cl.remove(lit![1]));
2028 assert_eq!(cl.len(), 3);
2029 }
2030
2031 #[test]
2032 fn clause_remove_thorough() {
2033 let mut cl = clause![lit![0], lit![1], lit![2], lit![1]];
2034 assert!(!cl.remove_thorough(lit![3]));
2035 assert!(cl.remove_thorough(lit![1]));
2036 assert_eq!(cl.len(), 2);
2037 }
2038
2039 #[test]
2040 fn clause_normalize() {
2041 let taut = clause![lit![0], lit![1], lit![2], lit![3], !lit![2]];
2042 assert_eq!(taut.normalize(), None);
2043 let cl = clause![
2044 lit![5],
2045 !lit![2],
2046 !lit![3],
2047 lit![17],
2048 lit![0],
2049 lit![1],
2050 !lit![2]
2051 ];
2052 assert_eq!(
2053 cl.normalize(),
2054 Some(clause![
2055 lit![0],
2056 lit![1],
2057 !lit![2],
2058 !lit![3],
2059 lit![5],
2060 lit![17]
2061 ])
2062 );
2063 }
2064
2065 macro_rules! assign {
2066 ($val:expr) => {{
2067 let mut assign = Assignment::default();
2068 assign.assign_var(var![0], (($val & 1) == 1).into());
2069 assign.assign_var(var![1], ((($val >> 1) & 1) == 1).into());
2070 assign.assign_var(var![2], (($val >> 2) & 1 == 1).into());
2071 assign
2072 }};
2073 }
2074
2075 #[test]
2076 fn clause_evaluate() {
2077 let cl = clause![lit![0], lit![1], lit![2]];
2078 assert_eq!(cl.evaluate(&assign!(0b000)), TernaryVal::False);
2079 assert_eq!(cl.evaluate(&assign!(0b001)), TernaryVal::True);
2080 assert_eq!(cl.evaluate(&assign!(0b010)), TernaryVal::True);
2081 assert_eq!(cl.evaluate(&assign!(0b011)), TernaryVal::True);
2082 assert_eq!(cl.evaluate(&assign!(0b100)), TernaryVal::True);
2083 assert_eq!(cl.evaluate(&assign!(0b101)), TernaryVal::True);
2084 assert_eq!(cl.evaluate(&assign!(0b110)), TernaryVal::True);
2085 assert_eq!(cl.evaluate(&assign!(0b111)), TernaryVal::True);
2086 assert_eq!(
2087 cl.evaluate(&assign!(0b000).truncate(var![1])),
2088 TernaryVal::DontCare
2089 );
2090 }
2091
2092 #[test]
2093 fn clause_is_tautology() {
2094 assert!(!Cl::new(&[lit![0], lit![1], lit![2]]).is_tautology());
2095 assert!(Cl::new(&[lit![0], !lit![0], lit![2]]).is_tautology());
2096 assert!(Cl::new(&[!lit![2], !lit![0], lit![2]]).is_tautology());
2097 }
2098
2099 #[test]
2100 fn card_is_tautology() {
2101 let lits = vec![lit![0], lit![1], lit![2]];
2102 assert!(CardConstraint::new_ub(lits.clone(), 3).is_tautology());
2103 assert!(!CardConstraint::new_ub(lits.clone(), 2).is_tautology());
2104 assert!(CardConstraint::new_lb(lits.clone(), 0).is_tautology());
2105 assert!(!CardConstraint::new_lb(lits.clone(), 1).is_tautology());
2106 assert!(!CardConstraint::new_eq(lits.clone(), 2).is_tautology());
2107 }
2108
2109 #[test]
2110 fn card_is_unsat() {
2111 let lits = vec![lit![0], lit![1], lit![2]];
2112 assert!(!CardConstraint::new_ub(lits.clone(), 1).is_unsat());
2113 assert!(!CardConstraint::new_lb(lits.clone(), 3).is_unsat());
2114 assert!(CardConstraint::new_lb(lits.clone(), 4).is_unsat());
2115 assert!(!CardConstraint::new_eq(lits.clone(), 2).is_unsat());
2116 assert!(CardConstraint::new_eq(lits.clone(), 4).is_unsat());
2117 }
2118
2119 #[test]
2120 fn card_is_positive_assignment() {
2121 let lits = vec![lit![0], lit![1], lit![2]];
2122 assert!(!CardConstraint::new_ub(lits.clone(), 1).is_positive_assignment());
2123 assert!(CardConstraint::new_lb(lits.clone(), 3).is_positive_assignment());
2124 assert!(!CardConstraint::new_lb(lits.clone(), 2).is_positive_assignment());
2125 assert!(CardConstraint::new_eq(lits.clone(), 3).is_positive_assignment());
2126 assert!(!CardConstraint::new_eq(lits.clone(), 2).is_positive_assignment());
2127 }
2128
2129 #[test]
2130 fn card_is_negative_assignment() {
2131 let lits = vec![lit![0], lit![1], lit![2]];
2132 assert!(CardConstraint::new_ub(lits.clone(), 0).is_negative_assignment());
2133 assert!(!CardConstraint::new_ub(lits.clone(), 1).is_negative_assignment());
2134 assert!(!CardConstraint::new_lb(lits.clone(), 2).is_negative_assignment());
2135 assert!(CardConstraint::new_eq(lits.clone(), 0).is_negative_assignment());
2136 assert!(!CardConstraint::new_eq(lits.clone(), 1).is_negative_assignment());
2137 }
2138
2139 #[test]
2140 fn card_is_clause() {
2141 let lits = vec![lit![0], lit![1], lit![2]];
2142 assert!(!CardConstraint::new_ub(lits.clone(), 1).is_clause());
2143 assert!(!CardConstraint::new_lb(lits.clone(), 3).is_clause());
2144 assert!(CardConstraint::new_lb(lits.clone(), 1).is_clause());
2145 assert!(!CardConstraint::new_eq(lits.clone(), 2).is_clause());
2146 }
2147
2148 #[test]
2149 fn pb_is_tautology() {
2150 let lits = vec![(lit![0], 1), (lit![1], 2), (lit![2], 3)];
2151 assert!(PbConstraint::new_ub(lits.clone(), 6).is_tautology());
2152 assert!(!PbConstraint::new_ub(lits.clone(), 5).is_tautology());
2153 assert!(PbConstraint::new_lb(lits.clone(), 0).is_tautology());
2154 assert!(!PbConstraint::new_lb(lits.clone(), 1).is_tautology());
2155 assert!(!PbConstraint::new_eq(lits.clone(), 2).is_tautology());
2156 }
2157
2158 #[test]
2159 fn pb_is_unsat() {
2160 let lits = vec![(lit![0], 1), (lit![1], 2), (lit![2], 3)];
2161 assert!(!PbConstraint::new_ub(lits.clone(), 1).is_unsat());
2162 assert!(!PbConstraint::new_lb(lits.clone(), 6).is_unsat());
2163 assert!(PbConstraint::new_lb(lits.clone(), 7).is_unsat());
2164 assert!(!PbConstraint::new_eq(lits.clone(), 2).is_unsat());
2165 assert!(PbConstraint::new_eq(lits.clone(), 7).is_unsat());
2166 }
2167
2168 #[test]
2169 fn pb_is_positive_assignment() {
2170 let lits = vec![(lit![0], 1), (lit![1], 2), (lit![2], 3)];
2171 assert!(!PbConstraint::new_ub(lits.clone(), 1).is_positive_assignment());
2172 assert!(PbConstraint::new_lb(lits.clone(), 6).is_positive_assignment());
2173 assert!(!PbConstraint::new_lb(lits.clone(), 2).is_positive_assignment());
2174 assert!(PbConstraint::new_eq(lits.clone(), 6).is_positive_assignment());
2175 assert!(!PbConstraint::new_eq(lits.clone(), 2).is_positive_assignment());
2176 }
2177
2178 #[test]
2179 fn pb_is_negative_assignment() {
2180 let lits = vec![(lit![0], 2), (lit![1], 2), (lit![2], 3)];
2181 assert!(PbConstraint::new_ub(lits.clone(), 1).is_negative_assignment());
2182 assert!(!PbConstraint::new_ub(lits.clone(), 2).is_negative_assignment());
2183 assert!(!PbConstraint::new_lb(lits.clone(), 2).is_negative_assignment());
2184 assert!(PbConstraint::new_eq(lits.clone(), 0).is_negative_assignment());
2185 assert!(!PbConstraint::new_eq(lits.clone(), 1).is_negative_assignment());
2186 }
2187
2188 #[test]
2189 fn pb_is_card() {
2190 let lits = vec![(lit![0], 2), (lit![1], 2), (lit![2], 2)];
2191 assert!(PbConstraint::new_ub(lits.clone(), 1).is_card());
2192 assert!(PbConstraint::new_lb(lits.clone(), 3).is_card());
2193 assert!(PbConstraint::new_eq(lits.clone(), 2).is_card());
2194 let lits = vec![(lit![0], 2), (lit![1], 1), (lit![2], 2)];
2195 assert!(!PbConstraint::new_ub(lits.clone(), 1).is_card());
2196 assert!(!PbConstraint::new_lb(lits.clone(), 3).is_card());
2197 assert!(!PbConstraint::new_eq(lits.clone(), 2).is_card());
2198 }
2199
2200 #[test]
2201 fn pb_is_clause() {
2202 let lits = vec![(lit![0], 2), (lit![1], 3), (lit![2], 2)];
2203 assert!(PbConstraint::new_ub(lits.clone(), 6).is_clause());
2204 assert!(PbConstraint::new_lb(lits.clone(), 2).is_clause());
2205 assert!(!PbConstraint::new_ub(lits.clone(), 7).is_clause());
2206 assert!(!PbConstraint::new_ub(lits.clone(), 4).is_clause());
2207 assert!(!PbConstraint::new_lb(lits.clone(), 3).is_clause());
2208 assert!(!PbConstraint::new_eq(lits.clone(), 2).is_card());
2209 }
2210}