use crate::primitives::arith::{partial_products_num_denom_chunk, partial_products_quotient_terms};
use super::*;
pub fn compute_partial_products(
raw_trace: &TracePolynomials<LagrangeBasis>,
raw_setup: &SetupPolynomials<LagrangeBasis>,
non_residues_by_beta: &SVec<EF>,
beta: &DExt,
gamma: &DExt,
num_cols_per_product: usize,
storage: &mut GenericArgumentsStorage<LagrangeBasis>,
) -> CudaResult<()> {
let TracePolynomials { variable_cols, .. } = raw_trace;
let ArgumentsPolynomials {
mut z_polys,
mut partial_products,
..
} = storage.as_polynomials_mut();
let z_poly = &mut z_polys[0];
let SetupPolynomials {
permutation_cols, ..
} = raw_setup;
assert_eq!(variable_cols.len(), permutation_cols.len());
assert_eq!(non_residues_by_beta.len(), variable_cols.len());
let domain_size = variable_cols[0].domain_size();
let num_partial_products = variable_cols.chunks(num_cols_per_product).len() - 1;
assert_eq!(partial_products.len(), num_partial_products);
let mut omega_values = dvec!(domain_size);
helpers::compute_domain_elems(&mut omega_values, domain_size)?;
helpers::set_value(z_poly.c0.storage.as_mut(), &DF::one()?)?;
helpers::set_zero(z_poly.c1.storage.as_mut())?;
let mut num: ComplexPoly<LagrangeBasis> = ComplexPoly::empty(domain_size)?;
let mut denum: ComplexPoly<LagrangeBasis> = ComplexPoly::empty(domain_size)?;
let mut partial_products_iter = partial_products.iter_mut();
for ((non_residues_chunk, variable_cols_chunk), sigma_cols_chunk) in non_residues_by_beta
.chunks(num_cols_per_product)
.zip(variable_cols.chunks(num_cols_per_product))
.zip(permutation_cols.chunks(num_cols_per_product))
{
let num = if let Some(partial_product) = partial_products_iter.next() {
partial_product
} else {
&mut num
};
partial_products_num_denom_chunk(
num,
&mut denum,
variable_cols_chunk,
sigma_cols_chunk,
&omega_values,
non_residues_chunk,
beta,
gamma,
num_cols_per_product,
domain_size,
)?;
denum.inverse()?;
num.mul_assign(&denum)?;
z_poly.mul_assign(num)?;
}
assert!(partial_products_iter.next().is_none());
z_poly.shifted_grand_product()?;
let mut prev_product = z_poly.clone();
for partial_product in partial_products.iter_mut() {
partial_product.mul_assign(&prev_product)?;
prev_product = partial_product.clone();
}
Ok(())
}
#[allow(clippy::too_many_arguments)]
#[allow(dead_code)]
pub fn compute_quotient_for_partial_products_naive<'a, 'b>(
trace: &TracePolynomials<'a, CosetEvaluations>,
setup: &SetupPolynomials<'a, CosetEvaluations>,
argument: &ArgumentsPolynomials<'a, CosetEvaluations>,
omega_values: &Poly<'a, CosetEvaluations>,
num_cols_per_product: usize,
beta: DExt,
gamma: DExt,
non_residues_by_beta: &DVec<EF>,
powers_of_alpha: Vec<DExt>,
quotient: &mut ComplexPoly<'b, CosetEvaluations>,
) -> CudaResult<()>
where
'a: 'b,
{
let TracePolynomials { variable_cols, .. } = trace;
let SetupPolynomials {
permutation_cols, ..
} = setup;
let ArgumentsPolynomials {
z_polys,
partial_products,
..
} = argument;
let z_poly = &z_polys[0];
let mut non_residues_by_beta_transformed = vec![];
for el in non_residues_by_beta.to_vec()?.into_iter() {
let el: DExt = el.into();
non_residues_by_beta_transformed.push(el);
}
assert_eq!(powers_of_alpha.len(), partial_products.len() + 1);
assert_eq!(non_residues_by_beta.len(), variable_cols.len(),);
let domain_size = variable_cols[0].domain_size();
assert_eq!(omega_values.domain_size(), domain_size);
let mut shifted_z = ComplexPoly::clone(z_poly);
shifted_z.rotate()?;
let mut lhs = vec![];
for p in partial_products.iter() {
lhs.push(p);
}
lhs.push(&shifted_z);
let mut rhs = vec![];
rhs.push(z_poly);
for p in partial_products.iter() {
rhs.push(p);
}
assert_eq!(lhs.len(), rhs.len());
let omega_values = ComplexPoly::<CosetEvaluations>::from_real(omega_values)?;
for (
((((existing_lhs, existing_rhs), variable_cols_chunk), sigma_cols_chunk), alpha),
non_residues_chunk,
) in lhs
.iter()
.zip(rhs.iter())
.zip(variable_cols.chunks(num_cols_per_product))
.zip(permutation_cols.chunks(num_cols_per_product))
.zip(powers_of_alpha.iter())
.zip(non_residues_by_beta_transformed.chunks(num_cols_per_product))
{
let mut num = ComplexPoly::<CosetEvaluations>::one(domain_size)?;
let mut denum = num.clone();
for ((non_residue_by_beta, variable_col), sigma_col) in non_residues_chunk
.iter()
.zip(variable_cols_chunk.iter())
.zip(sigma_cols_chunk.iter())
{
let mut current_num = omega_values.clone();
current_num.scale_real(non_residue_by_beta)?;
let variable_col = variable_col.clone();
current_num.add_assign_real(&variable_col)?;
current_num.add_constant(&gamma)?;
let mut current_denum = ComplexPoly::<CosetEvaluations>::from_real(sigma_col)?;
current_denum.scale_real(&beta)?;
current_denum.add_assign_real(&variable_col)?;
current_denum.add_constant(&gamma)?;
num.mul_assign(¤t_num)?;
denum.mul_assign(¤t_denum)?;
}
denum.mul_assign(existing_lhs)?;
num.mul_assign(existing_rhs)?;
denum.sub_assign(&num)?;
denum.scale(alpha)?;
quotient.add_assign(&denum)?;
}
Ok(())
}
#[allow(clippy::too_many_arguments)]
pub fn compute_quotient_for_partial_products(
variable_cols: &[Poly<CosetEvaluations>],
permutation_cols: &[Poly<CosetEvaluations>],
z_poly: &ComplexPoly<CosetEvaluations>,
partial_products: &[ComplexPoly<CosetEvaluations>],
omega_values: &Poly<CosetEvaluations>,
num_cols_per_product: usize,
beta: &DExt,
gamma: &DExt,
non_residues_by_beta: &SVec<EF>,
powers_of_alpha: &SVec<EF>,
quotient: &mut ComplexPoly<CosetEvaluations>,
) -> CudaResult<()> {
let num_polys = variable_cols.len();
let domain_size = variable_cols[0].domain_size();
assert_eq!(powers_of_alpha.len(), partial_products.len() + 1);
assert_eq!(non_residues_by_beta.len(), num_polys);
assert_eq!(omega_values.domain_size(), domain_size);
partial_products_quotient_terms(
partial_products,
z_poly,
variable_cols,
permutation_cols,
omega_values,
powers_of_alpha,
non_residues_by_beta,
beta,
gamma,
quotient,
num_cols_per_product,
num_polys,
domain_size,
)?;
Ok(())
}