Skip to main content

zinc_uair/
ideal_collector.rs

1use zinc_utils::from_ref::FromRef;
2
3use crate::{
4    ConstraintBuilder, TraceRow, Uair,
5    dummy_semiring::DummySemiring,
6    ideal::{Ideal, IdealCheck, IdealCheckError},
7};
8
9/// A `ConstraintBuilder` that collects
10/// ideals used in a `Uair`.
11pub struct IdealCollector<I: Ideal> {
12    pub ideals: Vec<IdealOrZero<I>>,
13}
14
15impl<I: Ideal> IdealCollector<I> {
16    /// Create a new ideal collector
17    /// and hint the number of constraints
18    /// a target UAIR might have.
19    pub fn new(num_constraints: usize) -> Self {
20        Self {
21            ideals: Vec::with_capacity(num_constraints),
22        }
23    }
24}
25
26/// Given a `Uair` and a hint of how many constraints
27/// it is going to have, creates an `IdealCollector`
28/// object and collects ideals from the `Uair`.
29pub fn collect_ideals<U: Uair>(num_constraints: usize) -> IdealCollector<U::Ideal> {
30    let mut ideal_collector = IdealCollector::new(num_constraints);
31
32    let sig = U::signature();
33    let (up_dummy, down_dummy) = sig.dummy_rows(DummySemiring);
34    let up_row = TraceRow::from_slice_with_layout(&up_dummy, sig.total_cols().as_column_layout());
35    let down_row =
36        TraceRow::from_slice_with_layout(&down_dummy, sig.down_cols().as_column_layout());
37    U::constrain(&mut ideal_collector, up_row, down_row);
38
39    ideal_collector
40}
41
42impl<I> ConstraintBuilder for IdealCollector<I>
43where
44    I: Ideal,
45{
46    type Expr = DummySemiring;
47    type Ideal = IdealOrZero<I>;
48
49    fn assert_in_ideal(&mut self, _expr: Self::Expr, ideal: &Self::Ideal) {
50        self.ideals.push(ideal.clone());
51    }
52
53    fn assert_zero(&mut self, _expr: Self::Expr) {
54        self.ideals.push(IdealOrZero::zero());
55    }
56}
57
58/// Either a non-trivial ideal (from `assert_in_ideal`) or the zero ideal
59/// (from `assert_zero`).
60#[derive(Clone, Copy, Debug)]
61pub enum IdealOrZero<I: Ideal> {
62    NonZero(I),
63    Zero,
64}
65
66impl<I: Ideal> IdealOrZero<I> {
67    pub fn zero() -> Self {
68        IdealOrZero::Zero
69    }
70
71    /// Returns `true` if this is the zero ideal
72    /// (i.e., the ideal used by `assert_zero` constraints).
73    pub fn is_zero_ideal(&self) -> bool {
74        matches!(self, IdealOrZero::Zero)
75    }
76
77    pub fn map<I2: Ideal>(&self, f: impl FnOnce(&I) -> I2) -> IdealOrZero<I2> {
78        match self {
79            IdealOrZero::NonZero(ideal) => IdealOrZero::NonZero(f(ideal)),
80            IdealOrZero::Zero => IdealOrZero::Zero,
81        }
82    }
83}
84
85impl<I: Ideal> Ideal for IdealOrZero<I> {}
86
87impl<I: Ideal> FromRef<IdealOrZero<I>> for IdealOrZero<I> {
88    fn from_ref(value: &IdealOrZero<I>) -> Self {
89        value.clone()
90    }
91}
92
93impl<I: Ideal> FromRef<I> for IdealOrZero<I> {
94    fn from_ref(value: &I) -> Self {
95        IdealOrZero::NonZero(value.clone())
96    }
97}
98
99impl<I: Ideal> IdealCheck<DummySemiring> for IdealOrZero<I> {
100    fn contains(&self, _value: &DummySemiring) -> Result<bool, IdealCheckError> {
101        // Do nothing.
102        Ok(true)
103    }
104}