in air/src/air/tests.rs [69:217]
fn get_boundary_constraints() {
// define assertions
let values = vec![
BaseElement::new(1),
BaseElement::new(2),
BaseElement::new(3),
BaseElement::new(4),
];
let assertions = vec![
Assertion::single(0, 0, BaseElement::new(3)), // register 0, step 0 -> group 0
Assertion::single(0, 9, BaseElement::new(5)), // register 0, step 9 -> group 1
Assertion::single(1, 9, BaseElement::new(9)), // register 0, step 9 -> group 1
Assertion::sequence(0, 2, 4, values.clone()), // register 0, steps 2, 6, 10, 14 -> group 4
Assertion::sequence(1, 2, 4, values.clone()), // register 1, steps 2, 6, 10, 14 -> group 4
Assertion::sequence(1, 0, 8, values[..2].to_vec()), // register 1, steps 0, 8 -> group 2
Assertion::sequence(0, 3, 8, values[..2].to_vec()), // register 0, steps 3, 11 -> group 3
Assertion::periodic(1, 3, 8, BaseElement::new(7)), // register 1, steps 3, 11 -> group 3
];
// instantiate mock AIR
let trace_length = 16;
let air = MockAir::with_assertions(assertions, trace_length);
let no_poly_offset = (0, BaseElement::ONE);
let g = BaseElement::get_root_of_unity(log2(trace_length)); // trace domain generator
// build coefficients for random liner combination; these will be derived for assertions
// sorted first by stride, then by first step, and finally by register (similar to the order)
// of assertions above
let mut prng = build_prng();
let mut expected_cc = BTreeMap::<usize, (BaseElement, BaseElement)>::new();
expected_cc.insert(0, prng.draw_pair().unwrap());
expected_cc.insert(1, prng.draw_pair().unwrap());
expected_cc.insert(2, prng.draw_pair().unwrap());
expected_cc.insert(6, prng.draw_pair().unwrap());
expected_cc.insert(7, prng.draw_pair().unwrap());
expected_cc.insert(3, prng.draw_pair().unwrap());
expected_cc.insert(4, prng.draw_pair().unwrap());
expected_cc.insert(5, prng.draw_pair().unwrap());
// get boundary constraints from AIR, and sort constraint groups so that the order
// is stable; the original order is just by degree_adjustment
let mut prng = build_prng();
let coefficients = (0..8)
.map(|_| prng.draw_pair().unwrap())
.collect::<Vec<(BaseElement, BaseElement)>>();
let mut groups = air.get_boundary_constraints(&coefficients);
groups.sort_by(|g1, g2| {
if g1.degree_adjustment() == g2.degree_adjustment() {
let n1 = &g1.divisor().numerator()[0].1;
let n2 = &g2.divisor().numerator()[0].1;
n1.as_int().partial_cmp(&n2.as_int()).unwrap()
} else {
g1.degree_adjustment()
.partial_cmp(&g2.degree_adjustment())
.unwrap()
}
});
assert_eq!(5, groups.len());
// group 0
let group = &groups[0];
assert_eq!(1, group.divisor().degree());
assert_eq!(vec![(1, g.exp(0))], group.divisor().numerator());
assert_eq!(1, group.constraints().len());
let constraint = &group.constraints()[0];
assert_eq!(0, constraint.register());
assert_eq!(vec![BaseElement::new(3)], constraint.poly());
assert_eq!(no_poly_offset, constraint.poly_offset());
assert_eq!(expected_cc[&0], constraint.cc().clone());
// group 1
let group = &groups[1];
assert_eq!(1, group.divisor().degree());
assert_eq!(vec![(1, g.exp(9))], group.divisor().numerator());
assert_eq!(2, group.constraints().len());
let constraint = &group.constraints()[0];
assert_eq!(0, constraint.register());
assert_eq!(vec![BaseElement::new(5)], constraint.poly());
assert_eq!(no_poly_offset, constraint.poly_offset());
assert_eq!(expected_cc[&1], constraint.cc().clone());
let constraint = &group.constraints()[1];
assert_eq!(1, constraint.register());
assert_eq!(vec![BaseElement::new(9)], constraint.poly());
assert_eq!(no_poly_offset, constraint.poly_offset());
assert_eq!(expected_cc[&2], constraint.cc().clone());
// group 2
let group = &groups[2];
assert_eq!(2, group.divisor().degree());
assert_eq!(vec![(2, g.exp(0))], group.divisor().numerator());
assert_eq!(1, group.constraints().len());
let constraint = &group.constraints()[0];
assert_eq!(1, constraint.register());
assert_eq!(
build_sequence_poly(&values[..2], trace_length),
constraint.poly()
);
assert_eq!(no_poly_offset, constraint.poly_offset());
assert_eq!(expected_cc[&3], constraint.cc().clone());
// group 3
let group = &groups[3];
assert_eq!(2, group.divisor().degree());
assert_eq!(vec![(2, g.exp(2 * 3))], group.divisor().numerator());
assert_eq!(2, group.constraints().len());
let constraint = &group.constraints()[0];
assert_eq!(0, constraint.register());
assert_eq!(
build_sequence_poly(&values[..2], trace_length),
constraint.poly()
);
assert_eq!((3, g.inv().exp(3)), constraint.poly_offset());
assert_eq!(expected_cc[&4], constraint.cc().clone());
let constraint = &group.constraints()[1];
assert_eq!(1, constraint.register());
assert_eq!(vec![BaseElement::new(7)], constraint.poly());
assert_eq!(no_poly_offset, constraint.poly_offset());
assert_eq!(expected_cc[&5], constraint.cc().clone());
// group 4
let group = &groups[4];
assert_eq!(4, group.divisor().degree());
assert_eq!(vec![(4, g.exp(4 * 2))], group.divisor().numerator());
assert_eq!(2, group.constraints().len());
let constraint = &group.constraints()[0];
assert_eq!(0, constraint.register());
assert_eq!(
build_sequence_poly(&values, trace_length),
constraint.poly()
);
assert_eq!((2, g.inv().exp(2)), constraint.poly_offset());
assert_eq!(expected_cc[&6], constraint.cc().clone());
let constraint = &group.constraints()[1];
assert_eq!(1, constraint.register());
assert_eq!(
build_sequence_poly(&values, trace_length),
constraint.poly()
);
assert_eq!((2, g.inv().exp(2)), constraint.poly_offset());
assert_eq!(expected_cc[&7], constraint.cc().clone());
}