use alloc::vec::Vec;
use super::{AirContext, ConstraintDivisor, ExtensionOf, FieldElement};
mod frame;
pub use frame::EvaluationFrame;
mod degree;
pub use degree::TransitionConstraintDegree;
const MIN_CYCLE_LENGTH: usize = 2;
pub struct TransitionConstraints<E: FieldElement> {
main_constraint_coef: Vec<E>,
main_constraint_degrees: Vec<TransitionConstraintDegree>,
aux_constraint_coef: Vec<E>,
aux_constraint_degrees: Vec<TransitionConstraintDegree>,
divisor: ConstraintDivisor<E::BaseField>,
}
impl<E: FieldElement> TransitionConstraints<E> {
pub fn new(context: &AirContext<E::BaseField>, composition_coefficients: &[E]) -> Self {
assert_eq!(
context.num_transition_constraints(),
composition_coefficients.len(),
"number of transition constraints must match the number of composition coefficient tuples"
);
let divisor = ConstraintDivisor::from_transition(
context.trace_len(),
context.num_transition_exemptions(),
);
let main_constraint_degrees = context.main_transition_constraint_degrees.clone();
let aux_constraint_degrees = context.aux_transition_constraint_degrees.clone();
let (main_constraint_coef, aux_constraint_coef) =
composition_coefficients.split_at(context.main_transition_constraint_degrees.len());
Self {
main_constraint_coef: main_constraint_coef.to_vec(),
main_constraint_degrees,
aux_constraint_coef: aux_constraint_coef.to_vec(),
aux_constraint_degrees,
divisor,
}
}
pub fn main_constraint_degrees(&self) -> &[TransitionConstraintDegree] {
&self.main_constraint_degrees
}
pub fn num_main_constraints(&self) -> usize {
self.main_constraint_degrees.len()
}
pub fn main_constraint_coef(&self) -> Vec<E> {
self.main_constraint_coef.clone()
}
pub fn aux_constraint_degrees(&self) -> &[TransitionConstraintDegree] {
&self.aux_constraint_degrees
}
pub fn num_aux_constraints(&self) -> usize {
self.aux_constraint_degrees.len()
}
pub fn aux_constraint_coef(&self) -> Vec<E> {
self.aux_constraint_coef.clone()
}
pub fn divisor(&self) -> &ConstraintDivisor<E::BaseField> {
&self.divisor
}
pub fn combine_evaluations<F>(&self, main_evaluations: &[F], aux_evaluations: &[E], x: F) -> E
where
F: FieldElement<BaseField = E::BaseField>,
E: ExtensionOf<F>,
{
let mut result = main_evaluations
.iter()
.zip(self.main_constraint_coef.iter())
.fold(E::ZERO, |acc, (&const_eval, &coef)| acc + coef.mul_base(const_eval));
if !self.aux_constraint_coef.is_empty() {
result += aux_evaluations
.iter()
.zip(self.aux_constraint_coef.iter())
.fold(E::ZERO, |acc, (&const_eval, &coef)| acc + coef * const_eval);
};
let z = E::from(self.divisor.evaluate_at(x));
result / z
}
}