use super::{
Assertion, BTreeMap, BoundaryConstraint, ConstraintDivisor, ExtensionOf, FieldElement, Vec,
};
#[derive(Debug, Clone)]
pub struct BoundaryConstraintGroup<F, E>
where
F: FieldElement,
E: FieldElement<BaseField = F::BaseField> + ExtensionOf<F>,
{
constraints: Vec<BoundaryConstraint<F, E>>,
divisor: ConstraintDivisor<F::BaseField>,
degree_adjustment: u64,
}
impl<F, E> BoundaryConstraintGroup<F, E>
where
F: FieldElement,
E: FieldElement<BaseField = F::BaseField> + ExtensionOf<F>,
{
pub(super) fn new(
divisor: ConstraintDivisor<F::BaseField>,
trace_poly_degree: usize,
composition_degree: usize,
) -> Self {
let target_degree = composition_degree + divisor.degree();
let degree_adjustment = (target_degree - trace_poly_degree) as u64;
BoundaryConstraintGroup {
constraints: Vec::new(),
divisor,
degree_adjustment,
}
}
pub fn constraints(&self) -> &[BoundaryConstraint<F, E>] {
&self.constraints
}
pub fn divisor(&self) -> &ConstraintDivisor<F::BaseField> {
&self.divisor
}
pub fn degree_adjustment(&self) -> u64 {
self.degree_adjustment
}
pub(super) fn add(
&mut self,
assertion: Assertion<F>,
inv_g: F::BaseField,
twiddle_map: &mut BTreeMap<usize, Vec<F::BaseField>>,
composition_coefficients: (E, E),
) {
self.constraints.push(BoundaryConstraint::new(
assertion,
inv_g,
twiddle_map,
composition_coefficients,
));
}
pub fn evaluate_at(&self, state: &[E], x: E, xp: E) -> E {
debug_assert_eq!(
x.exp(self.degree_adjustment.into()),
xp,
"inconsistent degree adjustment"
);
let mut numerator = E::ZERO;
for constraint in self.constraints().iter() {
let trace_value = state[constraint.column()];
let evaluation = constraint.evaluate_at(x, trace_value);
numerator += evaluation * (constraint.cc().0 + constraint.cc().1 * xp);
}
let denominator = self.divisor.evaluate_at(x);
numerator / denominator
}
}