in air/src/air/mod.rs [284:329]
fn get_boundary_constraints<E: FieldElement<BaseField = Self::BaseField>>(
&self,
coefficients: &[(E, E)],
) -> Vec<BoundaryConstraintGroup<Self::BaseField, E>> {
// compute inverse of the trace domain generator; this will be used for offset
// computations when creating sequence constraints
let inv_g = self.trace_domain_generator().inv();
// cache inverse twiddles for multi-value assertions in this map so that we don't have
// to re-build them for assertions with identical strides
let mut twiddle_map = BTreeMap::new();
// get the assertions for this computation and make sure that they are all valid in
// the context of this computation; also, sort the assertions in the deterministic order
// so that changing the order of assertions does not change random coefficients that
// get assigned to them
let assertions = prepare_assertions(self.get_assertions(), self.context());
assert_eq!(
assertions.len(),
coefficients.len(),
"number of assertions must match the number of coefficient tuples"
);
// iterate over all assertions, which are sorted first by stride and then by first_step
// in ascending order
let mut groups = BTreeMap::new();
for (i, assertion) in assertions.into_iter().enumerate() {
let key = (assertion.stride(), assertion.first_step());
let group = groups.entry(key).or_insert_with(|| {
BoundaryConstraintGroup::new(
ConstraintDivisor::from_assertion(&assertion, self.trace_length()),
self.trace_poly_degree(),
self.composition_degree(),
)
});
// add a new assertion constraint to the current group (last group in the list)
group.add(assertion, inv_g, &mut twiddle_map, coefficients[i]);
}
// make sure groups are sorted by adjustment degree
let mut groups = groups.into_iter().map(|e| e.1).collect::<Vec<_>>();
groups.sort_by_key(|c| c.degree_adjustment());
groups
}