use dashmap::DashMap;
use itertools::Itertools;
use crate::core::air::{Component, Components};
use crate::core::fields::m31::BaseField;
use crate::core::fields::qm31::SecureField;
use crate::core::pcs::TreeVec;
use crate::core::poly::circle::CircleDomain;
use crate::core::ColumnVec;
use crate::prover::air::accumulation::DomainEvaluationAccumulator;
use crate::prover::backend::{Backend, Col};
use crate::prover::poly::circle::{CircleCoefficients, CircleEvaluation, SecureCirclePoly};
use crate::prover::poly::twiddles::TwiddleTree;
use crate::prover::poly::BitReversedOrder;
use crate::prover::CirclePoint;
pub type WeightsHashMap<B> = DashMap<(u32, CirclePoint<SecureField>), Col<B, SecureField>>;
pub trait ComponentProver<B: Backend>: Component {
fn evaluate_constraint_quotients_on_domain(
&self,
trace: &Trace<'_, B>,
evaluation_accumulator: &mut DomainEvaluationAccumulator<B>,
);
}
pub struct Trace<'a, B: Backend> {
pub polys: TreeVec<ColumnVec<&'a Poly<B>>>,
}
pub struct Poly<B: Backend> {
pub coeffs: Option<CircleCoefficients<B>>,
pub evals: CircleEvaluation<B, BaseField, BitReversedOrder>,
}
impl<B: Backend> Poly<B> {
pub const fn new(
coeffs: Option<CircleCoefficients<B>>,
evals: CircleEvaluation<B, BaseField, BitReversedOrder>,
) -> Self {
Self { coeffs, evals }
}
pub fn eval_at_point(
&self,
point: CirclePoint<SecureField>,
weights_hash_map: Option<&WeightsHashMap<B>>,
) -> SecureField {
if let Some(coeffs) = &self.coeffs {
coeffs.eval_at_point(point)
} else {
self.evals.barycentric_eval_at_point(
&weights_hash_map
.unwrap()
.get(&(self.evals.domain.log_size(), point))
.expect("weights should exist for all sampled points"),
)
}
}
pub fn get_evaluation_on_domain(
&self,
domain: CircleDomain,
twiddles: &TwiddleTree<B>,
) -> CircleEvaluation<B, BaseField, BitReversedOrder> {
if let Some(coeffs) = &self.coeffs {
coeffs.evaluate_with_twiddles(domain, twiddles)
} else {
panic!("The polynomial's coefficients are not stored");
}
}
}
pub struct ComponentProvers<'a, B: Backend> {
pub components: Vec<&'a dyn ComponentProver<B>>,
pub n_preprocessed_columns: usize,
}
impl<B: Backend> ComponentProvers<'_, B> {
pub fn components(&self) -> Components<'_> {
Components {
components: self
.components
.iter()
.map(|c| *c as &dyn Component)
.collect_vec(),
n_preprocessed_columns: self.n_preprocessed_columns,
}
}
pub fn compute_composition_polynomial(
&self,
random_coeff: SecureField,
trace: &Trace<'_, B>,
) -> SecureCirclePoly<B> {
let total_constraints: usize = self.components.iter().map(|c| c.n_constraints()).sum();
let mut accumulator = DomainEvaluationAccumulator::new(
random_coeff,
self.components().composition_log_degree_bound(),
total_constraints,
);
for component in &self.components {
component.evaluate_constraint_quotients_on_domain(trace, &mut accumulator)
}
accumulator.finalize()
}
}