shared_types/utils/
bookkeeping_table.rs

1use crate::Field;
2use itertools::Itertools;
3
4/// Initializes with every iterated combination of the (binary)
5/// variables in `challenge_coord`.
6///
7/// In other words, if `challenge_coord` is [r_1, r_2, r_3] then
8/// `initialize_tensor` should output the following:
9///
10/// (1 - r_1) * (1 - r_2) * (1 - r_3),
11/// (1 - r_1) * (1 - r_2) * (r_3),
12/// (1 - r_1) * (r_2) * (1 - r_3),
13/// (1 - r_1) * (r_2) * (r_3),
14/// (r_1) * (1 - r_2) * (1 - r_3),
15/// (r_1) * (1 - r_2) * (r_3),
16/// (r_1) * (r_2) * (1 - r_3),
17/// (r_1) * (r_2) * (r_3),
18///
19/// ## Arguments
20/// * `challenge_coord` - Challenge point to be expanded in big-endian.
21pub fn initialize_tensor<F: Field>(challenge_coord: &[F]) -> Vec<F> {
22    let mut cur_table = Vec::with_capacity(1 << challenge_coord.len());
23    cur_table.push(F::ONE);
24    if !challenge_coord.is_empty() {
25        // Dynamic programming algorithm in Tha13 for computing these
26        // equality values and returning them as a vector.
27
28        // Iterate through remaining challenge coordinates in reverse,
29        // starting with the least significant variable.
30        for challenge in challenge_coord.iter().rev() {
31            let (one_minus_r, r) = (F::ONE - challenge, *challenge);
32
33            // Double the size of `cur_table` to hold new values.
34            let len = cur_table.len();
35            cur_table.resize(len * 2, F::ZERO);
36
37            for i in 0..len {
38                cur_table[i + len] = cur_table[i] * r;
39                cur_table[i] *= one_minus_r;
40            }
41        }
42    }
43    cur_table
44}
45
46/// Similar to [initialize_tensor], but takes the RLC of tensors over
47/// a vector of challenge coordinates given the random coefficients.
48pub fn initialize_tensor_rlc<F: Field>(challenge_coord_vec: &[&[F]], random_coeff: &[F]) -> Vec<F> {
49    challenge_coord_vec
50        .iter()
51        .skip(1)
52        .zip(random_coeff.iter().skip(1))
53        .fold(
54            initialize_tensor(challenge_coord_vec[0])
55                .iter()
56                .map(|elem| *elem * random_coeff[0])
57                .collect_vec(),
58            |acc, (elem, random_coeff)| {
59                acc.iter()
60                    .zip(initialize_tensor(elem).iter())
61                    .map(|(acc_elem, next_elem)| *acc_elem + (*next_elem * random_coeff))
62                    .collect_vec()
63            },
64        )
65}