rustsat/encodings/card/
simulators.rs

1//! # Cardinality Encoding Simulators
2//!
3//! This module contains generic code to simulate cardinality encodings from
4//! other cardinality encodings. This can for example be used to simulate lower
5//! bounding with an encoding that only natively support upper bounding by
6//! negating the input literals.
7
8use std::ops::{Not, Range, RangeBounds};
9
10use super::{
11    BoundBoth, BoundBothIncremental, BoundLower, BoundLowerIncremental, BoundUpper,
12    BoundUpperIncremental, Encode, EncodeIncremental,
13};
14use crate::{
15    encodings::{CollectClauses, EncodeStats, EnforceError, IterInputs, NotEncoded},
16    instances::ManageVars,
17    types::Lit,
18};
19
20/// Simulator type that builds a cardinality encoding of type `CE` over the
21/// negated input literals in order to simulate the other bound type
22#[derive(Debug)]
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24pub struct Inverted<CE>
25where
26    CE: Encode + 'static,
27{
28    card_enc: CE,
29    n_lits: usize,
30}
31
32impl<CE> Default for Inverted<CE>
33where
34    CE: Encode + Default,
35{
36    fn default() -> Self {
37        Self {
38            card_enc: Default::default(),
39            n_lits: Default::default(),
40        }
41    }
42}
43
44impl<CE> Inverted<CE>
45where
46    CE: Encode + 'static,
47{
48    fn convert_encoding_range(&self, range: Range<usize>) -> Range<usize> {
49        let min = self.n_lits() - (range.end - 1);
50        let max = if self.n_lits() >= range.start {
51            self.n_lits() - range.start + 1
52        } else {
53            0
54        };
55        min..max
56    }
57}
58
59impl<CE> From<Vec<Lit>> for Inverted<CE>
60where
61    CE: Encode + From<Vec<Lit>> + 'static,
62{
63    fn from(lits: Vec<Lit>) -> Self {
64        let n = lits.len();
65        let lits: Vec<Lit> = lits.into_iter().map(Lit::not).collect();
66        Self {
67            card_enc: CE::from(lits),
68            n_lits: n,
69        }
70    }
71}
72
73impl<CE> FromIterator<Lit> for Inverted<CE>
74where
75    CE: Encode + From<Vec<Lit>> + 'static,
76{
77    fn from_iter<T: IntoIterator<Item = Lit>>(iter: T) -> Self {
78        let lits: Vec<Lit> = iter.into_iter().collect();
79        Self::from(lits)
80    }
81}
82
83impl<CE> Extend<Lit> for Inverted<CE>
84where
85    CE: Encode + Extend<Lit> + 'static,
86{
87    fn extend<T: IntoIterator<Item = Lit>>(&mut self, iter: T) {
88        let lits: Vec<Lit> = iter.into_iter().map(Lit::not).collect();
89        self.n_lits += lits.len();
90        self.card_enc.extend(lits);
91    }
92}
93
94impl<CE> Encode for Inverted<CE>
95where
96    CE: Encode,
97{
98    fn n_lits(&self) -> usize {
99        self.n_lits
100    }
101}
102
103impl<CE> IterInputs for Inverted<CE>
104where
105    CE: Encode + IterInputs,
106{
107    type Iter<'a> = InvertedIter<CE::Iter<'a>>;
108
109    fn iter(&self) -> Self::Iter<'_> {
110        self.card_enc.iter().map(Lit::not)
111    }
112}
113
114impl<CE> EncodeIncremental for Inverted<CE>
115where
116    CE: EncodeIncremental,
117{
118    fn reserve(&mut self, var_manager: &mut dyn ManageVars) {
119        self.card_enc.reserve(var_manager);
120    }
121}
122
123impl<CE> BoundUpper for Inverted<CE>
124where
125    CE: BoundLower,
126{
127    fn encode_ub<Col, R>(
128        &mut self,
129        range: R,
130        collector: &mut Col,
131        var_manager: &mut dyn ManageVars,
132    ) -> Result<(), crate::OutOfMemory>
133    where
134        Col: CollectClauses,
135        R: RangeBounds<usize>,
136    {
137        self.card_enc.encode_lb(
138            self.convert_encoding_range(super::prepare_ub_range(self, range)),
139            collector,
140            var_manager,
141        )
142    }
143
144    fn enforce_ub(&self, ub: usize) -> Result<Vec<Lit>, NotEncoded> {
145        let lb = if self.n_lits > ub {
146            self.n_lits - ub
147        } else {
148            return Ok(vec![]);
149        };
150        match self.card_enc.enforce_lb(lb) {
151            Ok(assumps) => Ok(assumps),
152            Err(EnforceError::NotEncoded) => Err(NotEncoded),
153            Err(EnforceError::Unsat) => unreachable!(),
154        }
155    }
156}
157
158#[cfg(feature = "proof-logging")]
159impl<CE> super::cert::BoundUpper for Inverted<CE>
160where
161    CE: super::cert::BoundLower + FromIterator<Lit>,
162{
163    fn encode_ub_cert<Col, R, W>(
164        &mut self,
165        range: R,
166        collector: &mut Col,
167        var_manager: &mut dyn ManageVars,
168        proof: &mut pigeons::Proof<W>,
169    ) -> Result<(), crate::encodings::cert::EncodingError>
170    where
171        Col: crate::encodings::cert::CollectClauses,
172        R: RangeBounds<usize>,
173        W: std::io::Write,
174    {
175        self.card_enc.encode_lb_cert(
176            self.convert_encoding_range(super::prepare_ub_range(self, range)),
177            collector,
178            var_manager,
179            proof,
180        )
181    }
182
183    fn encode_ub_constr_cert<Col, W>(
184        constr: (
185            crate::types::constraints::CardUbConstr,
186            pigeons::AbsConstraintId,
187        ),
188        collector: &mut Col,
189        var_manager: &mut dyn ManageVars,
190        proof: &mut pigeons::Proof<W>,
191    ) -> Result<(), crate::encodings::cert::EncodingError>
192    where
193        Col: crate::encodings::cert::CollectClauses,
194        W: std::io::Write,
195        Self: FromIterator<Lit> + Sized,
196    {
197        let constr = (constr.0.invert(), constr.1);
198        match CE::encode_lb_constr_cert(constr, collector, var_manager, proof) {
199            Ok(()) => Ok(()),
200            Err(crate::encodings::cert::ConstraintEncodingError::OutOfMemory(err)) => {
201                Err(err.into())
202            }
203            Err(crate::encodings::cert::ConstraintEncodingError::Proof(err)) => Err(err.into()),
204            Err(crate::encodings::cert::ConstraintEncodingError::Unsat) => unreachable!(),
205        }
206    }
207}
208
209impl<CE> BoundLower for Inverted<CE>
210where
211    CE: BoundUpper,
212{
213    fn encode_lb<Col, R>(
214        &mut self,
215        range: R,
216        collector: &mut Col,
217        var_manager: &mut dyn ManageVars,
218    ) -> Result<(), crate::OutOfMemory>
219    where
220        Col: CollectClauses,
221        R: RangeBounds<usize>,
222    {
223        self.card_enc.encode_ub(
224            self.convert_encoding_range(super::prepare_lb_range(self, range)),
225            collector,
226            var_manager,
227        )
228    }
229
230    fn enforce_lb(&self, lb: usize) -> Result<Vec<Lit>, EnforceError> {
231        let ub = if self.n_lits >= lb {
232            self.n_lits - lb
233        } else {
234            return Err(EnforceError::Unsat);
235        };
236        Ok(self.card_enc.enforce_ub(ub)?)
237    }
238}
239
240#[cfg(feature = "proof-logging")]
241impl<CE> super::cert::BoundLower for Inverted<CE>
242where
243    CE: super::cert::BoundUpper + FromIterator<Lit>,
244{
245    fn encode_lb_cert<Col, R, W>(
246        &mut self,
247        range: R,
248        collector: &mut Col,
249        var_manager: &mut dyn ManageVars,
250        proof: &mut pigeons::Proof<W>,
251    ) -> Result<(), crate::encodings::cert::EncodingError>
252    where
253        Col: crate::encodings::cert::CollectClauses,
254        R: RangeBounds<usize>,
255        W: std::io::Write,
256    {
257        self.card_enc.encode_ub_cert(
258            self.convert_encoding_range(super::prepare_lb_range(self, range)),
259            collector,
260            var_manager,
261            proof,
262        )
263    }
264
265    fn encode_lb_constr_cert<Col, W>(
266        constr: (
267            crate::types::constraints::CardLbConstr,
268            pigeons::AbsConstraintId,
269        ),
270        collector: &mut Col,
271        var_manager: &mut dyn ManageVars,
272        proof: &mut pigeons::Proof<W>,
273    ) -> Result<(), crate::encodings::cert::ConstraintEncodingError>
274    where
275        Col: crate::encodings::cert::CollectClauses,
276        W: std::io::Write,
277        Self: FromIterator<Lit> + Sized,
278    {
279        let constr = (constr.0.invert(), constr.1);
280        CE::encode_ub_constr_cert(constr, collector, var_manager, proof)?;
281        Ok(())
282    }
283}
284
285impl<CE> BoundBoth for Inverted<CE>
286where
287    CE: BoundBoth,
288{
289    fn encode_both<Col, R>(
290        &mut self,
291        range: R,
292        collector: &mut Col,
293        var_manager: &mut dyn ManageVars,
294    ) -> Result<(), crate::OutOfMemory>
295    where
296        Col: CollectClauses,
297        R: RangeBounds<usize> + Clone,
298    {
299        self.card_enc.encode_both(
300            self.convert_encoding_range(super::prepare_both_range(self, range)),
301            collector,
302            var_manager,
303        )
304    }
305
306    fn enforce_eq(&self, b: usize) -> Result<Vec<Lit>, EnforceError> {
307        let b = if self.n_lits >= b {
308            self.n_lits - b
309        } else {
310            return Err(EnforceError::Unsat);
311        };
312        self.card_enc.enforce_eq(b)
313    }
314}
315
316#[cfg(feature = "proof-logging")]
317impl<CE> super::cert::BoundBoth for Inverted<CE>
318where
319    CE: super::cert::BoundBoth + FromIterator<Lit>,
320{
321    fn encode_both_cert<Col, R, W>(
322        &mut self,
323        range: R,
324        collector: &mut Col,
325        var_manager: &mut dyn ManageVars,
326        proof: &mut pigeons::Proof<W>,
327    ) -> Result<(), crate::encodings::cert::EncodingError>
328    where
329        Col: crate::encodings::cert::CollectClauses,
330        R: RangeBounds<usize> + Clone,
331        W: std::io::Write,
332    {
333        self.card_enc.encode_both_cert(
334            self.convert_encoding_range(super::prepare_both_range(self, range)),
335            collector,
336            var_manager,
337            proof,
338        )
339    }
340}
341
342impl<CE> BoundUpperIncremental for Inverted<CE>
343where
344    CE: BoundLowerIncremental,
345{
346    fn encode_ub_change<Col, R>(
347        &mut self,
348        range: R,
349        collector: &mut Col,
350        var_manager: &mut dyn ManageVars,
351    ) -> Result<(), crate::OutOfMemory>
352    where
353        Col: CollectClauses,
354        R: RangeBounds<usize>,
355    {
356        self.card_enc.encode_lb_change(
357            self.convert_encoding_range(super::prepare_ub_range(self, range)),
358            collector,
359            var_manager,
360        )
361    }
362}
363
364#[cfg(feature = "proof-logging")]
365impl<CE> super::cert::BoundUpperIncremental for Inverted<CE>
366where
367    CE: super::cert::BoundLowerIncremental + FromIterator<Lit>,
368{
369    fn encode_ub_change_cert<Col, R, W>(
370        &mut self,
371        range: R,
372        collector: &mut Col,
373        var_manager: &mut dyn ManageVars,
374        proof: &mut pigeons::Proof<W>,
375    ) -> Result<(), crate::encodings::cert::EncodingError>
376    where
377        Col: crate::encodings::cert::CollectClauses,
378        R: RangeBounds<usize>,
379        W: std::io::Write,
380    {
381        self.card_enc.encode_lb_change_cert(
382            self.convert_encoding_range(super::prepare_ub_range(self, range)),
383            collector,
384            var_manager,
385            proof,
386        )
387    }
388}
389
390impl<CE> BoundLowerIncremental for Inverted<CE>
391where
392    CE: BoundUpperIncremental,
393{
394    fn encode_lb_change<Col, R>(
395        &mut self,
396        range: R,
397        collector: &mut Col,
398        var_manager: &mut dyn ManageVars,
399    ) -> Result<(), crate::OutOfMemory>
400    where
401        Col: CollectClauses,
402        R: RangeBounds<usize>,
403    {
404        self.card_enc.encode_ub_change(
405            self.convert_encoding_range(super::prepare_lb_range(self, range)),
406            collector,
407            var_manager,
408        )
409    }
410}
411
412#[cfg(feature = "proof-logging")]
413impl<CE> super::cert::BoundLowerIncremental for Inverted<CE>
414where
415    CE: super::cert::BoundUpperIncremental + FromIterator<Lit>,
416{
417    fn encode_lb_change_cert<Col, R, W>(
418        &mut self,
419        range: R,
420        collector: &mut Col,
421        var_manager: &mut dyn ManageVars,
422        proof: &mut pigeons::Proof<W>,
423    ) -> Result<(), crate::encodings::cert::EncodingError>
424    where
425        Col: crate::encodings::cert::CollectClauses,
426        R: RangeBounds<usize>,
427        W: std::io::Write,
428    {
429        self.card_enc.encode_ub_change_cert(
430            self.convert_encoding_range(super::prepare_lb_range(self, range)),
431            collector,
432            var_manager,
433            proof,
434        )
435    }
436}
437
438impl<CE> BoundBothIncremental for Inverted<CE>
439where
440    CE: BoundBothIncremental,
441{
442    fn encode_both_change<Col, R>(
443        &mut self,
444        range: R,
445        collector: &mut Col,
446        var_manager: &mut dyn ManageVars,
447    ) -> Result<(), crate::OutOfMemory>
448    where
449        Col: CollectClauses,
450        R: RangeBounds<usize> + Clone,
451    {
452        self.card_enc.encode_both_change(
453            self.convert_encoding_range(super::prepare_both_range(self, range)),
454            collector,
455            var_manager,
456        )
457    }
458}
459
460#[cfg(feature = "proof-logging")]
461impl<CE> super::cert::BoundBothIncremental for Inverted<CE>
462where
463    CE: super::cert::BoundBothIncremental + FromIterator<Lit>,
464{
465    fn encode_both_change_cert<Col, R, W>(
466        &mut self,
467        range: R,
468        collector: &mut Col,
469        var_manager: &mut dyn ManageVars,
470        proof: &mut pigeons::Proof<W>,
471    ) -> Result<(), crate::encodings::cert::EncodingError>
472    where
473        Col: crate::encodings::cert::CollectClauses,
474        R: RangeBounds<usize> + Clone,
475        W: std::io::Write,
476    {
477        self.card_enc.encode_both_change_cert(
478            self.convert_encoding_range(super::prepare_both_range(self, range)),
479            collector,
480            var_manager,
481            proof,
482        )
483    }
484}
485
486impl<CE> EncodeStats for Inverted<CE>
487where
488    CE: Encode + EncodeStats,
489{
490    fn n_clauses(&self) -> usize {
491        self.card_enc.n_clauses()
492    }
493
494    fn n_vars(&self) -> u32 {
495        self.card_enc.n_vars()
496    }
497}
498
499type InvertedIter<ICE> = std::iter::Map<ICE, fn(Lit) -> Lit>;
500
501/// Simulator type that builds a combined cardinality encoding supporting both
502/// bounds from two individual cardinality encodings supporting each bound
503/// separately
504#[derive(Debug)]
505#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
506pub struct Double<UBE, LBE>
507where
508    UBE: BoundUpper + 'static,
509    LBE: BoundLower + 'static,
510{
511    ub_enc: UBE,
512    lb_enc: LBE,
513}
514
515impl<UBE, LBE> Default for Double<UBE, LBE>
516where
517    UBE: BoundUpper + Default + 'static,
518    LBE: BoundLower + Default + 'static,
519{
520    fn default() -> Self {
521        Self {
522            ub_enc: Default::default(),
523            lb_enc: Default::default(),
524        }
525    }
526}
527
528impl<UBE, LBE> From<Vec<Lit>> for Double<UBE, LBE>
529where
530    UBE: BoundUpper + From<Vec<Lit>> + 'static,
531    LBE: BoundLower + From<Vec<Lit>> + 'static,
532{
533    fn from(lits: Vec<Lit>) -> Self {
534        Self {
535            ub_enc: UBE::from(lits.clone()),
536            lb_enc: LBE::from(lits),
537        }
538    }
539}
540
541impl<UBE, LBE> FromIterator<Lit> for Double<UBE, LBE>
542where
543    UBE: BoundUpper + From<Vec<Lit>> + 'static,
544    LBE: BoundLower + From<Vec<Lit>> + 'static,
545{
546    fn from_iter<T: IntoIterator<Item = Lit>>(iter: T) -> Self {
547        let lits: Vec<Lit> = iter.into_iter().collect();
548        Self::from(lits)
549    }
550}
551
552impl<UBE, LBE> Extend<Lit> for Double<UBE, LBE>
553where
554    UBE: BoundUpper + Extend<Lit> + 'static,
555    LBE: BoundLower + Extend<Lit> + 'static,
556{
557    fn extend<T: IntoIterator<Item = Lit>>(&mut self, iter: T) {
558        let lits: Vec<Lit> = iter.into_iter().collect();
559        self.ub_enc.extend(lits.clone());
560        self.lb_enc.extend(lits);
561    }
562}
563
564impl<UBE, LBE> Encode for Double<UBE, LBE>
565where
566    UBE: BoundUpper,
567    LBE: BoundLower,
568{
569    fn n_lits(&self) -> usize {
570        self.ub_enc.n_lits()
571    }
572}
573
574impl<UBE, LBE> IterInputs for Double<UBE, LBE>
575where
576    UBE: BoundUpper + IterInputs,
577    LBE: BoundLower,
578{
579    type Iter<'a> = UBE::Iter<'a>;
580
581    fn iter(&self) -> Self::Iter<'_> {
582        self.ub_enc.iter()
583    }
584}
585
586impl<UBE, LBE> EncodeIncremental for Double<UBE, LBE>
587where
588    UBE: BoundUpperIncremental,
589    LBE: BoundLowerIncremental,
590{
591    fn reserve(&mut self, var_manager: &mut dyn ManageVars) {
592        self.ub_enc.reserve(var_manager);
593        self.lb_enc.reserve(var_manager);
594    }
595}
596
597impl<UBE, LBE> BoundUpper for Double<UBE, LBE>
598where
599    UBE: BoundUpper,
600    LBE: BoundLower,
601{
602    fn encode_ub<Col, R>(
603        &mut self,
604        range: R,
605        collector: &mut Col,
606        var_manager: &mut dyn ManageVars,
607    ) -> Result<(), crate::OutOfMemory>
608    where
609        Col: CollectClauses,
610        R: RangeBounds<usize>,
611    {
612        self.ub_enc.encode_ub(range, collector, var_manager)
613    }
614
615    fn enforce_ub(&self, ub: usize) -> Result<Vec<Lit>, NotEncoded> {
616        self.ub_enc.enforce_ub(ub)
617    }
618}
619
620#[cfg(feature = "proof-logging")]
621impl<UBE, LBE> super::cert::BoundUpper for Double<UBE, LBE>
622where
623    UBE: super::cert::BoundUpper + FromIterator<Lit>,
624    LBE: super::cert::BoundLower + FromIterator<Lit>,
625{
626    fn encode_ub_cert<Col, R, W>(
627        &mut self,
628        range: R,
629        collector: &mut Col,
630        var_manager: &mut dyn ManageVars,
631        proof: &mut pigeons::Proof<W>,
632    ) -> Result<(), crate::encodings::cert::EncodingError>
633    where
634        Col: crate::encodings::cert::CollectClauses,
635        R: RangeBounds<usize>,
636        W: std::io::Write,
637    {
638        self.ub_enc
639            .encode_ub_cert(range, collector, var_manager, proof)
640    }
641
642    fn encode_ub_constr_cert<Col, W>(
643        constr: (
644            crate::types::constraints::CardUbConstr,
645            pigeons::AbsConstraintId,
646        ),
647        collector: &mut Col,
648        var_manager: &mut dyn ManageVars,
649        proof: &mut pigeons::Proof<W>,
650    ) -> Result<(), crate::encodings::cert::EncodingError>
651    where
652        Col: crate::encodings::cert::CollectClauses,
653        W: std::io::Write,
654        Self: FromIterator<Lit> + Sized,
655    {
656        UBE::encode_ub_constr_cert(constr, collector, var_manager, proof)
657    }
658}
659
660impl<UBE, LBE> BoundLower for Double<UBE, LBE>
661where
662    UBE: BoundUpper,
663    LBE: BoundLower,
664{
665    fn encode_lb<Col, R>(
666        &mut self,
667        range: R,
668        collector: &mut Col,
669        var_manager: &mut dyn ManageVars,
670    ) -> Result<(), crate::OutOfMemory>
671    where
672        Col: CollectClauses,
673        R: RangeBounds<usize>,
674    {
675        self.lb_enc.encode_lb(range, collector, var_manager)
676    }
677
678    fn enforce_lb(&self, lb: usize) -> Result<Vec<Lit>, EnforceError> {
679        self.lb_enc.enforce_lb(lb)
680    }
681}
682
683#[cfg(feature = "proof-logging")]
684impl<UBE, LBE> super::cert::BoundLower for Double<UBE, LBE>
685where
686    UBE: super::cert::BoundUpper + FromIterator<Lit>,
687    LBE: super::cert::BoundLower + FromIterator<Lit>,
688{
689    fn encode_lb_cert<Col, R, W>(
690        &mut self,
691        range: R,
692        collector: &mut Col,
693        var_manager: &mut dyn ManageVars,
694        proof: &mut pigeons::Proof<W>,
695    ) -> Result<(), crate::encodings::cert::EncodingError>
696    where
697        Col: crate::encodings::cert::CollectClauses,
698        R: RangeBounds<usize>,
699        W: std::io::Write,
700    {
701        self.lb_enc
702            .encode_lb_cert(range, collector, var_manager, proof)
703    }
704
705    fn encode_lb_constr_cert<Col, W>(
706        constr: (
707            crate::types::constraints::CardLbConstr,
708            pigeons::AbsConstraintId,
709        ),
710        collector: &mut Col,
711        var_manager: &mut dyn ManageVars,
712        proof: &mut pigeons::Proof<W>,
713    ) -> Result<(), crate::encodings::cert::ConstraintEncodingError>
714    where
715        Col: crate::encodings::cert::CollectClauses,
716        W: std::io::Write,
717        Self: FromIterator<Lit> + Sized,
718    {
719        LBE::encode_lb_constr_cert(constr, collector, var_manager, proof)
720    }
721}
722
723impl<UBE, LBE> BoundBoth for Double<UBE, LBE>
724where
725    UBE: BoundUpper,
726    LBE: BoundLower,
727{
728}
729
730#[cfg(feature = "proof-logging")]
731impl<UBE, LBE> super::cert::BoundBoth for Double<UBE, LBE>
732where
733    UBE: super::cert::BoundUpper + FromIterator<Lit>,
734    LBE: super::cert::BoundLower + FromIterator<Lit>,
735{
736}
737
738impl<UBE, LBE> BoundUpperIncremental for Double<UBE, LBE>
739where
740    UBE: BoundUpperIncremental,
741    LBE: BoundLowerIncremental,
742{
743    fn encode_ub_change<Col, R>(
744        &mut self,
745        range: R,
746        collector: &mut Col,
747        var_manager: &mut dyn ManageVars,
748    ) -> Result<(), crate::OutOfMemory>
749    where
750        Col: CollectClauses,
751        R: RangeBounds<usize>,
752    {
753        self.ub_enc.encode_ub_change(range, collector, var_manager)
754    }
755}
756
757#[cfg(feature = "proof-logging")]
758impl<UBE, LBE> super::cert::BoundUpperIncremental for Double<UBE, LBE>
759where
760    UBE: super::cert::BoundUpperIncremental + BoundUpperIncremental + FromIterator<Lit>,
761    LBE: super::cert::BoundLowerIncremental + BoundLowerIncremental + FromIterator<Lit>,
762{
763    fn encode_ub_change_cert<Col, R, W>(
764        &mut self,
765        range: R,
766        collector: &mut Col,
767        var_manager: &mut dyn ManageVars,
768        proof: &mut pigeons::Proof<W>,
769    ) -> Result<(), crate::encodings::cert::EncodingError>
770    where
771        Col: crate::encodings::cert::CollectClauses,
772        R: RangeBounds<usize>,
773        W: std::io::Write,
774    {
775        self.ub_enc
776            .encode_ub_change_cert(range, collector, var_manager, proof)
777    }
778}
779
780impl<UBE, LBE> BoundLowerIncremental for Double<UBE, LBE>
781where
782    UBE: BoundUpperIncremental,
783    LBE: BoundLowerIncremental,
784{
785    fn encode_lb_change<Col, R>(
786        &mut self,
787        range: R,
788        collector: &mut Col,
789        var_manager: &mut dyn ManageVars,
790    ) -> Result<(), crate::OutOfMemory>
791    where
792        Col: CollectClauses,
793        R: RangeBounds<usize>,
794    {
795        self.lb_enc.encode_lb_change(range, collector, var_manager)
796    }
797}
798
799#[cfg(feature = "proof-logging")]
800impl<UBE, LBE> super::cert::BoundLowerIncremental for Double<UBE, LBE>
801where
802    UBE: super::cert::BoundUpperIncremental + BoundUpperIncremental + FromIterator<Lit>,
803    LBE: super::cert::BoundLowerIncremental + BoundLowerIncremental + FromIterator<Lit>,
804{
805    fn encode_lb_change_cert<Col, R, W>(
806        &mut self,
807        range: R,
808        collector: &mut Col,
809        var_manager: &mut dyn ManageVars,
810        proof: &mut pigeons::Proof<W>,
811    ) -> Result<(), crate::encodings::cert::EncodingError>
812    where
813        Col: crate::encodings::cert::CollectClauses,
814        R: RangeBounds<usize>,
815        W: std::io::Write,
816    {
817        self.lb_enc
818            .encode_lb_change_cert(range, collector, var_manager, proof)
819    }
820}
821
822impl<UBE, LBE> BoundBothIncremental for Double<UBE, LBE>
823where
824    UBE: BoundUpperIncremental,
825    LBE: BoundLowerIncremental,
826{
827}
828
829#[cfg(feature = "proof-logging")]
830impl<UBE, LBE> super::cert::BoundBothIncremental for Double<UBE, LBE>
831where
832    UBE: super::cert::BoundUpperIncremental + BoundUpperIncremental + FromIterator<Lit>,
833    LBE: super::cert::BoundLowerIncremental + BoundLowerIncremental + FromIterator<Lit>,
834{
835}
836
837impl<UBE, LBE> EncodeStats for Double<UBE, LBE>
838where
839    UBE: EncodeStats + BoundUpper,
840    LBE: EncodeStats + BoundLower,
841{
842    fn n_clauses(&self) -> usize {
843        self.ub_enc.n_clauses() + self.lb_enc.n_clauses()
844    }
845
846    fn n_vars(&self) -> u32 {
847        self.ub_enc.n_vars() + self.lb_enc.n_vars()
848    }
849}