arnaucube
arnaucube/hyperplonkPublic Self-hosted repository
hyperplonk/arithmetic/src/multilinear_polynomial.rs
arithmetic/src/multilinear_polynomial.rsRaw
  1use crate::{util::get_batched_nv, ArithErrors};
  2use ark_ff::{Field, PrimeField};
  3use ark_poly::MultilinearExtension;
  4use ark_std::{end_timer, rand::RngCore, start_timer};
  5#[cfg(feature = "parallel")]
  6use rayon::prelude::{IndexedParallelIterator, IntoParallelRefMutIterator, ParallelIterator};
  7use std::sync::Arc;
  8
  9pub use ark_poly::DenseMultilinearExtension;
 10
 11/// Sample a random list of multilinear polynomials.
 12/// Returns
 13/// - the list of polynomials,
 14/// - its sum of polynomial evaluations over the boolean hypeArcube.
 15pub fn random_mle_list<F: PrimeField, R: RngCore>(
 16    nv: usize,
 17    degree: usize,
 18    rng: &mut R,
 19) -> (Vec<Arc<DenseMultilinearExtension<F>>>, F) {
 20    let start = start_timer!(|| "sample random mle list");
 21    let mut multiplicands = Vec::with_capacity(degree);
 22    for _ in 0..degree {
 23        multiplicands.push(Vec::with_capacity(1 << nv))
 24    }
 25    let mut sum = F::zero();
 26
 27    for _ in 0..(1 << nv) {
 28        let mut product = F::one();
 29
 30        for e in multiplicands.iter_mut() {
 31            let val = F::rand(rng);
 32            e.push(val);
 33            product *= val;
 34        }
 35        sum += product;
 36    }
 37
 38    let list = multiplicands
 39        .into_iter()
 40        .map(|x| Arc::new(DenseMultilinearExtension::from_evaluations_vec(nv, x)))
 41        .collect();
 42
 43    end_timer!(start);
 44    (list, sum)
 45}
 46
 47// Build a randomize list of mle-s whose sum is zero.
 48pub fn random_zero_mle_list<F: PrimeField, R: RngCore>(
 49    nv: usize,
 50    degree: usize,
 51    rng: &mut R,
 52) -> Vec<Arc<DenseMultilinearExtension<F>>> {
 53    let start = start_timer!(|| "sample random zero mle list");
 54
 55    let mut multiplicands = Vec::with_capacity(degree);
 56    for _ in 0..degree {
 57        multiplicands.push(Vec::with_capacity(1 << nv))
 58    }
 59    for _ in 0..(1 << nv) {
 60        multiplicands[0].push(F::zero());
 61        for e in multiplicands.iter_mut().skip(1) {
 62            e.push(F::rand(rng));
 63        }
 64    }
 65
 66    let list = multiplicands
 67        .into_iter()
 68        .map(|x| Arc::new(DenseMultilinearExtension::from_evaluations_vec(nv, x)))
 69        .collect();
 70
 71    end_timer!(start);
 72    list
 73}
 74
 75pub fn identity_permutation<F: PrimeField>(num_vars: usize, num_chunks: usize) -> Vec<F> {
 76    let len = (num_chunks as u64) * (1u64 << num_vars);
 77    (0..len).map(F::from).collect()
 78}
 79
 80/// A list of MLEs that represents an identity permutation
 81pub fn identity_permutation_mles<F: PrimeField>(
 82    num_vars: usize,
 83    num_chunks: usize,
 84) -> Vec<Arc<DenseMultilinearExtension<F>>> {
 85    let mut res = vec![];
 86    for i in 0..num_chunks {
 87        let shift = (i * (1 << num_vars)) as u64;
 88        let s_id_vec = (shift..shift + (1u64 << num_vars)).map(F::from).collect();
 89        res.push(Arc::new(DenseMultilinearExtension::from_evaluations_vec(
 90            num_vars, s_id_vec,
 91        )));
 92    }
 93    res
 94}
 95
 96pub fn random_permutation<F: PrimeField, R: RngCore>(
 97    num_vars: usize,
 98    num_chunks: usize,
 99    rng: &mut R,
100) -> Vec<F> {
101    let len = (num_chunks as u64) * (1u64 << num_vars);
102    let mut s_id_vec: Vec<F> = (0..len).map(F::from).collect();
103    let mut s_perm_vec = vec![];
104    for _ in 0..len {
105        let index = rng.next_u64() as usize % s_id_vec.len();
106        s_perm_vec.push(s_id_vec.remove(index));
107    }
108    s_perm_vec
109}
110
111/// A list of MLEs that represent a random permutation
112pub fn random_permutation_mles<F: PrimeField, R: RngCore>(
113    num_vars: usize,
114    num_chunks: usize,
115    rng: &mut R,
116) -> Vec<Arc<DenseMultilinearExtension<F>>> {
117    let s_perm_vec = random_permutation(num_vars, num_chunks, rng);
118    let mut res = vec![];
119    let n = 1 << num_vars;
120    for i in 0..num_chunks {
121        res.push(Arc::new(DenseMultilinearExtension::from_evaluations_vec(
122            num_vars,
123            s_perm_vec[i * n..i * n + n].to_vec(),
124        )));
125    }
126    res
127}
128
129pub fn evaluate_opt<F: Field>(poly: &DenseMultilinearExtension<F>, point: &[F]) -> F {
130    assert_eq!(poly.num_vars, point.len());
131    fix_variables(poly, point).evaluations[0]
132}
133
134pub fn fix_variables<F: Field>(
135    poly: &DenseMultilinearExtension<F>,
136    partial_point: &[F],
137) -> DenseMultilinearExtension<F> {
138    assert!(
139        partial_point.len() <= poly.num_vars,
140        "invalid size of partial point"
141    );
142    let nv = poly.num_vars;
143    let mut poly = poly.evaluations.to_vec();
144    let dim = partial_point.len();
145    // evaluate single variable of partial point from left to right
146    for (i, point) in partial_point.iter().enumerate().take(dim) {
147        poly = fix_one_variable_helper(&poly, nv - i, point);
148    }
149
150    DenseMultilinearExtension::<F>::from_evaluations_slice(nv - dim, &poly[..(1 << (nv - dim))])
151}
152
153fn fix_one_variable_helper<F: Field>(data: &[F], nv: usize, point: &F) -> Vec<F> {
154    let mut res = vec![F::zero(); 1 << (nv - 1)];
155
156    // evaluate single variable of partial point from left to right
157    #[cfg(not(feature = "parallel"))]
158    for i in 0..(1 << (nv - 1)) {
159        res[i] = data[i] + (data[(i << 1) + 1] - data[i << 1]) * point;
160    }
161
162    #[cfg(feature = "parallel")]
163    res.par_iter_mut().enumerate().for_each(|(i, x)| {
164        *x = data[i << 1] + (data[(i << 1) + 1] - data[i << 1]) * point;
165    });
166
167    res
168}
169
170pub fn evaluate_no_par<F: Field>(poly: &DenseMultilinearExtension<F>, point: &[F]) -> F {
171    assert_eq!(poly.num_vars, point.len());
172    fix_variables_no_par(poly, point).evaluations[0]
173}
174
175fn fix_variables_no_par<F: Field>(
176    poly: &DenseMultilinearExtension<F>,
177    partial_point: &[F],
178) -> DenseMultilinearExtension<F> {
179    assert!(
180        partial_point.len() <= poly.num_vars,
181        "invalid size of partial point"
182    );
183    let nv = poly.num_vars;
184    let mut poly = poly.evaluations.to_vec();
185    let dim = partial_point.len();
186    // evaluate single variable of partial point from left to right
187    for i in 1..dim + 1 {
188        let r = partial_point[i - 1];
189        for b in 0..(1 << (nv - i)) {
190            poly[b] = poly[b << 1] + (poly[(b << 1) + 1] - poly[b << 1]) * r;
191        }
192    }
193    DenseMultilinearExtension::from_evaluations_slice(nv - dim, &poly[..(1 << (nv - dim))])
194}
195
196/// merge a set of polynomials. Returns an error if the
197/// polynomials do not share a same number of nvs.
198pub fn merge_polynomials<F: PrimeField>(
199    polynomials: &[Arc<DenseMultilinearExtension<F>>],
200) -> Result<Arc<DenseMultilinearExtension<F>>, ArithErrors> {
201    let nv = polynomials[0].num_vars();
202    for poly in polynomials.iter() {
203        if nv != poly.num_vars() {
204            return Err(ArithErrors::InvalidParameters(
205                "num_vars do not match for polynomials".to_string(),
206            ));
207        }
208    }
209
210    let merged_nv = get_batched_nv(nv, polynomials.len());
211    let mut scalars = vec![];
212    for poly in polynomials.iter() {
213        scalars.extend_from_slice(poly.to_evaluations().as_slice());
214    }
215    scalars.extend_from_slice(vec![F::zero(); (1 << merged_nv) - scalars.len()].as_ref());
216    Ok(Arc::new(DenseMultilinearExtension::from_evaluations_vec(
217        merged_nv, scalars,
218    )))
219}
220
221pub fn fix_last_variables_no_par<F: PrimeField>(
222    poly: &DenseMultilinearExtension<F>,
223    partial_point: &[F],
224) -> DenseMultilinearExtension<F> {
225    let mut res = fix_last_variable_no_par(poly, partial_point.last().unwrap());
226    for p in partial_point.iter().rev().skip(1) {
227        res = fix_last_variable_no_par(&res, p);
228    }
229    res
230}
231
232fn fix_last_variable_no_par<F: PrimeField>(
233    poly: &DenseMultilinearExtension<F>,
234    partial_point: &F,
235) -> DenseMultilinearExtension<F> {
236    let nv = poly.num_vars();
237    let half_len = 1 << (nv - 1);
238    let mut res = vec![F::zero(); half_len];
239    for (i, e) in res.iter_mut().enumerate().take(half_len) {
240        *e = poly.evaluations[i]
241            + *partial_point * (poly.evaluations[i + half_len] - poly.evaluations[i]);
242    }
243    DenseMultilinearExtension::from_evaluations_vec(nv - 1, res)
244}
245pub fn fix_last_variables<F: PrimeField>(
246    poly: &DenseMultilinearExtension<F>,
247    partial_point: &[F],
248) -> DenseMultilinearExtension<F> {
249    assert!(
250        partial_point.len() <= poly.num_vars,
251        "invalid size of partial point"
252    );
253    let nv = poly.num_vars;
254    let mut poly = poly.evaluations.to_vec();
255    let dim = partial_point.len();
256    // evaluate single variable of partial point from left to right
257    for (i, point) in partial_point.iter().rev().enumerate().take(dim) {
258        poly = fix_last_variable_helper(&poly, nv - i, point);
259    }
260
261    DenseMultilinearExtension::<F>::from_evaluations_slice(nv - dim, &poly[..(1 << (nv - dim))])
262}
263
264fn fix_last_variable_helper<F: Field>(data: &[F], nv: usize, point: &F) -> Vec<F> {
265    let half_len = 1 << (nv - 1);
266    let mut res = vec![F::zero(); half_len];
267
268    // evaluate single variable of partial point from left to right
269    #[cfg(not(feature = "parallel"))]
270    for b in 0..half_len {
271        res[b] = data[b] + (data[b + half_len] - data[b]) * point;
272    }
273
274    #[cfg(feature = "parallel")]
275    res.par_iter_mut().enumerate().for_each(|(i, x)| {
276        *x = data[i] + (data[i + half_len] - data[i]) * point;
277    });
278
279    res
280}