remainder/
mle.rs

1//! An [Mle] is a Multilinear Extension that contains a more complex type (i.e.
2//! `T`, or `(T, T)` or `ExampleStruct`)
3
4use core::fmt::Debug;
5
6use evals::EvaluationsIterator;
7use serde::{Deserialize, Serialize};
8
9use crate::{claims::RawClaim, layer::LayerId};
10use shared_types::Field;
11
12use self::mle_enum::MleEnum;
13use dyn_clonable::*;
14
15/// Contains the default, dense implementation of an [Mle].
16pub mod dense;
17
18/// Contains an implementation of the zero [Mle].
19pub mod zero;
20
21/// Contains a wrapper type around [Mle] implementations.
22pub mod mle_enum;
23
24/// Defines [betavalues::BetaValues], a struct for storing the bookkeeping
25/// tables of Beta functions.
26pub mod betavalues;
27
28/// Defines [crate::mle::evals::Evaluations] and
29/// [crate::mle::evals::MultilinearExtension] for representing un-indexed MLEs.
30pub mod evals;
31
32/// Defines [crate::mle::mle_description::MleDescription], i.e. the in-circuit-context description
33/// of a [crate::mle::evals::MultilinearExtension] which includes "prefix vars" and "free vars" but
34/// not the actual evaluations of the function over the hypercube.
35pub mod mle_description;
36
37/// Defines [crate::mle::verifier_mle::VerifierMle], i.e. the verifier's view of a "fully-bound" MLE
38/// with a prover-claimed value.
39pub mod verifier_mle;
40
41// TODO!(Maybe this type needs PartialEq, could be easily implemented with a
42// random id...).
43/// The trait that defines how a semantic Type (T) and a MultiLinearEvaluation
44/// containing field elements (F) interact. T should always be a composite type
45/// containing Fs. For example (F, F) or a struct containing Fs.
46///
47/// If you want to construct an Mle, or use an Mle for some non-cryptographic
48/// computation (e.g. wit gen) then you should always use the iterator adaptors
49/// IntoIterator and FromIterator, this is to ensure that the semantic ordering
50/// within T is always consistent.
51#[allow(clippy::len_without_is_empty)]
52#[clonable]
53pub trait Mle<F: Field>: Clone + Debug + Send + Sync {
54    /// Returns the number of free variables this Mle is defined on.
55    /// Equivalently, this is the log_2 of the size of the unpruned bookkeeping
56    /// table.
57    fn num_free_vars(&self) -> usize;
58
59    /// An MLE is fully bounded if it has no more free variables.
60    fn is_fully_bounded(&self) -> bool {
61        self.num_free_vars() == 0
62    }
63
64    /// Get the padded set of evaluations over the boolean hypercube; useful for
65    /// constructing the input layer.
66    fn get_padded_evaluations(&self) -> Vec<F>;
67
68    /// Mutates the MLE in order to set the prefix bits. This is needed when we
69    /// are working with dataparallel circuits and new bits need to be added.
70    fn add_prefix_bits(&mut self, new_bits: Vec<MleIndex<F>>);
71
72    /// Get the layer ID of the associated MLE.
73    fn layer_id(&self) -> LayerId;
74
75    /// Returns the length of the current bookkeeping table.
76    fn len(&self) -> usize;
77
78    /// Returns an iterator over the evaluations of the current MLE.
79    fn iter(&self) -> EvaluationsIterator<'_, F>;
80
81    /// Returns the first element in the bookkeeping table corresponding to the
82    /// value of this Dense MLE when all free variables are set to zero. This
83    /// operations never panics (see [evals::MultilinearExtension::first])
84    fn first(&self) -> F;
85
86    /// If this is a fully-bound Dense MLE, it returns its value.
87    /// Otherwise panics.
88    fn value(&self) -> F;
89
90    /// Returns the first element of the evaluations table (if any).
91    fn get(&self, index: usize) -> Option<F>;
92
93    /// Get the indicies of the `Mle` that this `MleRef` represents.
94    fn mle_indices(&self) -> &[MleIndex<F>];
95
96    /// Fix the variable at `round_index` at a given `challenge` point. Mutates
97    /// `self` to be the bookeeping table for the new MLE.
98    ///
99    /// If the new MLE becomes fully bound, returns the evaluation of the fully
100    /// bound Mle.
101    fn fix_variable(&mut self, round_index: usize, challenge: F) -> Option<RawClaim<F>>;
102
103    /// Fix the (indexed) free variable at `indexed_bit_index` with a given
104    /// challenge `point`. Mutates `self`` to be the bookeeping table for the
105    /// new MLE.  If the new MLE becomes fully bound, returns the evaluation of
106    /// the fully bound MLE in the form of a [crate::claims::RawClaim].
107    ///
108    /// # Panics
109    /// If `indexed_bit_index` does not correspond to a
110    /// `MleIndex::Indexed(indexed_bit_index)` in `mle_indices`.
111    fn fix_variable_at_index(&mut self, indexed_bit_index: usize, point: F) -> Option<RawClaim<F>>;
112
113    /// Mutates the [MleIndex]es stored in `self` that are [MleIndex::Free] and
114    /// turns them into [MleIndex::Indexed] with the bit index being determined
115    /// from `curr_index`.
116    /// Returns the `(curr_index + number of IndexedBits now in the MleIndices)`.
117    fn index_mle_indices(&mut self, curr_index: usize) -> usize;
118
119    /// Get the associated enum that this MLE is a part of ([MleEnum::Dense] or [MleEnum::Zero]).
120    fn get_enum(self) -> MleEnum<F>;
121}
122
123/// Represents all the possible types of indices for an [Mle].
124#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
125pub enum MleIndex<F> {
126    /// A "selector" bit for fixed MLE access.
127    Fixed(bool),
128
129    /// An "unbound" bit that iterates over the contents of the MLE.
130    Free,
131
132    /// An "unbound" bit where the particular b_i in the larger expression has
133    /// been set.
134    Indexed(usize),
135
136    /// An index that has been bound to a random challenge by the sumcheck
137    /// protocol.
138    Bound(F, usize),
139}
140
141impl<F: Field> MleIndex<F> {
142    /// If `self` is a [MleIndex::Free] bit, turns it into an
143    /// [MleIndex::Indexed] with index `bit`.  Otherwise, `self` is not
144    /// modified.
145    pub fn index_var(&mut self, bit: usize) {
146        if let MleIndex::Free = self {
147            *self = Self::Indexed(bit)
148        }
149    }
150
151    /// If `self` is `Indexed(idx)`, bind it to `chal`, i.e. turn it into
152    /// a `Bound(chal, idx)` variant. Otherwise, `self` is not modified.
153    pub fn bind_index(&mut self, chal: F) {
154        if let MleIndex::Indexed(bit) = self {
155            *self = Self::Bound(chal, *bit)
156        }
157    }
158
159    /// Evaluate this `MleIndex`.
160    /// * `Fixed(bit)` evaluates to `0` or `1` when `bit` is `false` or `true`
161    ///   respectively.
162    /// * `Free` bits are *not* evaluated, i.e. `None` is returned.
163    /// * `IndexedBit(idx)` bits are *not* evaluated, i.e. `None` is returned.
164    /// * `Bound(chal, idx)` variants evaluate to `chal`.
165    pub fn val(&self) -> Option<F> {
166        match self {
167            MleIndex::Fixed(true) => Some(F::ONE),
168            MleIndex::Fixed(false) => Some(F::ZERO),
169            MleIndex::Bound(chal, _) => Some(*chal),
170            _ => None,
171        }
172    }
173}
174
175#[cfg(test)]
176mod test {
177    use super::MleIndex;
178    use shared_types::Fr;
179
180    #[test]
181    fn test_mle_index_val() {
182        // 0 selector bit.
183        assert_eq!(MleIndex::<Fr>::Fixed(false).val(), Some(Fr::zero()));
184
185        // 1 selector bit.
186        assert_eq!(MleIndex::<Fr>::Fixed(true).val(), Some(Fr::one()));
187
188        // Bound index.
189        assert_eq!(
190            MleIndex::<Fr>::Bound(Fr::from(42), 0).val(),
191            Some(Fr::from(42))
192        );
193
194        // Free index.
195        assert_eq!(MleIndex::<Fr>::Free.val(), None);
196
197        // Indexed bit index.
198        assert_eq!(MleIndex::<Fr>::Indexed(42).val(), None);
199    }
200
201    #[test]
202    fn test_mle_index_bind() {
203        // An `Fixed` index remains unaffected.
204        let mut mle_index: MleIndex<Fr> = MleIndex::Fixed(true);
205        mle_index.bind_index(Fr::from(17));
206        assert_eq!(mle_index, MleIndex::<Fr>::Fixed(true));
207
208        // A `Free` index remains unaffected.
209        let mut mle_index: MleIndex<Fr> = MleIndex::Free;
210        mle_index.bind_index(Fr::from(17));
211        assert_eq!(mle_index, MleIndex::<Fr>::Free);
212
213        // An `IndexedBit` index gets bound.
214        let mut mle_index: MleIndex<Fr> = MleIndex::Indexed(42);
215        mle_index.bind_index(Fr::from(17));
216        assert_eq!(mle_index, MleIndex::<Fr>::Bound(Fr::from(17), 42));
217
218        // An `Bound` index remains unaffected.
219        let mut mle_index: MleIndex<Fr> = MleIndex::Bound(Fr::from(17), 42);
220        mle_index.bind_index(Fr::from(37));
221        assert_eq!(mle_index, MleIndex::<Fr>::Bound(Fr::from(17), 42));
222    }
223
224    #[test]
225    fn test_mle_index_index() {
226        // An `Fixed` index remains unaffected.
227        let mut mle_index: MleIndex<Fr> = MleIndex::Fixed(true);
228        mle_index.index_var(17);
229        assert_eq!(mle_index, MleIndex::<Fr>::Fixed(true));
230
231        // A `Free` index becomes `IndexedBit`.
232        let mut mle_index: MleIndex<Fr> = MleIndex::Free;
233        mle_index.index_var(17);
234        assert_eq!(mle_index, MleIndex::<Fr>::Indexed(17));
235
236        // An `IndexedBit` index remains unaffected.
237        let mut mle_index: MleIndex<Fr> = MleIndex::Indexed(42);
238        mle_index.index_var(17);
239        assert_eq!(mle_index, MleIndex::<Fr>::Indexed(42));
240
241        // An `Bound` index remains unaffected.
242        let mut mle_index: MleIndex<Fr> = MleIndex::Bound(Fr::from(17), 42);
243        mle_index.index_var(37);
244        assert_eq!(mle_index, MleIndex::<Fr>::Bound(Fr::from(17), 42));
245    }
246}