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}