Skip to main content

zinc_uair/
constraint_counter.rs

1use crate::{
2    ConstraintBuilder, TraceRow, Uair,
3    dummy_semiring::{DUMMY_SEMIRING_CONFIG, DummySemiring},
4    ideal::ImpossibleIdeal,
5};
6use zinc_utils::{add, from_ref::FromRef};
7
8/// Per-family breakdown of constraint counts. Returned by
9/// [`count_constraints_split`].
10#[derive(Clone, Debug, Default, PartialEq, Eq)]
11pub struct ConstraintCount {
12    /// Number of constraints emitted via
13    /// [`crate::ConstraintBuilder::assert_in_ideal`] or
14    /// [`crate::ConstraintBuilder::assert_zero`] (the $Q[X]$ family).
15    pub q: usize,
16    /// Number of constraints emitted via
17    /// [`crate::ConstraintBuilder::assert_in_fq_ideal`] (the
18    /// $F_{q_i}[X]$ family, aggregated for each prime).
19    pub fq: Vec<usize>,
20}
21
22impl ConstraintCount {
23    pub fn for_prime(&self, idx: usize) -> usize {
24        self.fq.get(idx).cloned().unwrap_or(0)
25    }
26
27    /// Get the total number of polynomial constraints, summed across
28    /// the $Q[X]$ family and all $F_{q_i}[X]$ families.
29    pub fn total(&self) -> usize {
30        add!(self.q, self.fq.iter().sum())
31    }
32}
33
34/// Get the per-family constraint counts in a `Uair`.
35pub fn count_constraints<U: Uair>() -> ConstraintCount {
36    let mut cc = ConstraintCounter::default();
37
38    let sig = U::signature();
39    let (up_dummy, down_dummy) = sig.dummy_rows(DummySemiring);
40    let up_row = TraceRow::from_slice_with_layout(&up_dummy, sig.total_cols().as_column_layout());
41    let down_row =
42        TraceRow::from_slice_with_layout(&down_dummy, sig.down_cols().as_column_layout());
43
44    U::constrain_general(
45        &mut cc,
46        &DUMMY_SEMIRING_CONFIG,
47        up_row,
48        down_row,
49        |_| DummySemiring,
50        |_, _| Some(DummySemiring),
51        ImpossibleIdeal::from_ref,
52        ImpossibleIdeal::from_ref,
53    );
54
55    ConstraintCount { q: cc.q, fq: cc.fq }
56}
57
58#[derive(Clone, Debug, Default)]
59struct ConstraintCounter {
60    q: usize,
61    fq: Vec<usize>,
62}
63
64impl ConstraintBuilder for ConstraintCounter {
65    type Expr = DummySemiring;
66    type Ideal = ImpossibleIdeal;
67    type FqIdeal = ImpossibleIdeal;
68
69    #[allow(clippy::arithmetic_side_effects)]
70    #[inline(always)]
71    fn assert_in_ideal(&mut self, _expr: Self::Expr, _ideal_generator: &Self::Ideal) {
72        self.q += 1;
73    }
74
75    #[allow(clippy::arithmetic_side_effects)]
76    #[inline(always)]
77    fn assert_zero(&mut self, _expr: Self::Expr) {
78        self.q += 1;
79    }
80
81    #[allow(clippy::arithmetic_side_effects)]
82    #[inline(always)]
83    fn assert_in_fq_ideal(&mut self, prime_idx: usize, _expr: Self::Expr, _ideal: &Self::FqIdeal) {
84        if self.fq.len() <= prime_idx {
85            self.fq.resize(prime_idx + 1, 0);
86        }
87        self.fq[prime_idx] += 1;
88    }
89}