From 4ed11e94569063f511d93d3865483031934d186d Mon Sep 17 00:00:00 2001 From: Shahar Papini <43779613+spapinistarkware@users.noreply.github.com> Date: Thu, 21 Mar 2024 13:24:07 +0200 Subject: [PATCH] Use only canonic domains MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change is [Reviewable](https://reviewable.io/reviews/starkware-libs/stwo/463) --- src/core/air/evaluation.rs | 13 +++---- src/core/air/mod.rs | 3 +- src/core/backend/avx512/circle.rs | 13 ++++--- src/core/circle.rs | 21 +---------- src/core/poly/circle/canonic.rs | 11 ------ src/core/poly/circle/domain.rs | 8 +---- src/core/poly/circle/evaluation.rs | 4 +-- src/core/poly/circle/mod.rs | 44 ++--------------------- src/fibonacci/component.rs | 57 ++++++++++++------------------ 9 files changed, 41 insertions(+), 133 deletions(-) diff --git a/src/core/air/evaluation.rs b/src/core/air/evaluation.rs index 9e7f8d36c..cca111d2e 100644 --- a/src/core/air/evaluation.rs +++ b/src/core/air/evaluation.rs @@ -7,7 +7,7 @@ use crate::core::backend::{Backend, CPUBackend, Col, Column}; use crate::core::fields::m31::BaseField; use crate::core::fields::qm31::SecureField; use crate::core::fields::{ExtensionOf, FieldExpOps}; -use crate::core::poly::circle::{CircleDomain, CirclePoly, SecureCirclePoly}; +use crate::core::poly::circle::{CanonicCoset, CirclePoly, SecureCirclePoly}; use crate::core::poly::BitReversedOrder; use crate::core::utils::IteratorMutExt; @@ -169,7 +169,7 @@ impl DomainEvaluationAccumulator { let coeffs = SecureColumn { cols: values.cols.map(|c| { CPUCircleEvaluation::<_, BitReversedOrder>::new( - CircleDomain::constraint_evaluation_domain(log_size as u32), + CanonicCoset::new(log_size as u32).circle_domain(), c, ) .interpolate() @@ -304,12 +304,9 @@ mod tests { let mut res = SecureField::default(); for (log_size, values) in pairs.into_iter() { res = res * alpha - + CPUCircleEvaluation::new( - CircleDomain::constraint_evaluation_domain(log_size), - values, - ) - .interpolate() - .eval_at_point(point); + + CPUCircleEvaluation::new(CanonicCoset::new(log_size).circle_domain(), values) + .interpolate() + .eval_at_point(point); } assert_eq!(accumulator_res, res); diff --git a/src/core/air/mod.rs b/src/core/air/mod.rs index 0f9024585..f90d34d49 100644 --- a/src/core/air/mod.rs +++ b/src/core/air/mod.rs @@ -63,8 +63,7 @@ pub trait Component { /// Returns the degree bounds of each trace column. fn trace_log_degree_bounds(&self) -> Vec; - /// Evaluates the constraint quotients of the component on constraint evaluation domains. - /// See [`super::poly::circle::CircleDomain::constraint_evaluation_domain`]. + /// Evaluates the constraint quotients of the component on the evaluation domain. /// Accumulates quotients in `evaluation_accumulator`. // Note: This will be computed using a MaterializedGraph. fn evaluate_constraint_quotients_on_domain( diff --git a/src/core/backend/avx512/circle.rs b/src/core/backend/avx512/circle.rs index dbe443186..8769ee128 100644 --- a/src/core/backend/avx512/circle.rs +++ b/src/core/backend/avx512/circle.rs @@ -333,9 +333,7 @@ mod tests { use crate::core::backend::Column; use crate::core::circle::CirclePoint; use crate::core::fields::m31::BaseField; - use crate::core::poly::circle::{ - CanonicCoset, CircleDomain, CircleEvaluation, CirclePoly, PolyOps, - }; + use crate::core::poly::circle::{CanonicCoset, CircleEvaluation, CirclePoly, PolyOps}; use crate::core::poly::{BitReversedOrder, NaturalOrder}; use crate::qm31; @@ -359,8 +357,8 @@ mod tests { fn test_eval_extension() { for log_size in MIN_FFT_LOG_SIZE..(CACHED_FFT_LOG_SIZE + 4) { let log_size = log_size as u32; - let domain = CircleDomain::constraint_evaluation_domain(log_size); - let domain_ext = CircleDomain::constraint_evaluation_domain(log_size + 3); + let domain = CanonicCoset::new(log_size).circle_domain(); + let domain_ext = CanonicCoset::new(log_size + 3).circle_domain(); let evaluation = CircleEvaluation::::new( domain, (0..(1 << log_size)) @@ -369,9 +367,10 @@ mod tests { ); let poly = evaluation.clone().interpolate(); let evaluation2 = poly.evaluate(domain_ext); + let poly2 = evaluation2.interpolate(); assert_eq!( - evaluation2.values.to_vec()[..(1 << log_size)], - evaluation.values.to_vec() + poly.extend(log_size + 3).coeffs.to_vec(), + poly2.coeffs.to_vec() ); } } diff --git a/src/core/circle.rs b/src/core/circle.rs index 8c4b1cea6..c0a7b9cf5 100644 --- a/src/core/circle.rs +++ b/src/core/circle.rs @@ -461,26 +461,7 @@ mod tests { use crate::core::circle::{CirclePoint, SECURE_FIELD_CIRCLE_GEN}; use crate::core::fields::qm31::{SecureField, P4}; use crate::core::fields::FieldExpOps; - use crate::core::poly::circle::{CanonicCoset, CircleDomain}; - - #[test] - fn test_domains() { - let log_size = 4; - let canonic_cosets_extensions = [ - CanonicCoset::new(2).evaluation_domain(log_size + 1), - CanonicCoset::new(2).evaluation_domain(log_size + 2), - CanonicCoset::new(log_size - 1).evaluation_domain(log_size), - ]; - - let subgroup_gen = CirclePointIndex::subgroup_gen(log_size); - let constraint_evaluation_domain = CircleDomain::constraint_evaluation_domain(log_size - 1); - - for point_index in constraint_evaluation_domain.iter_indices() { - for eval in &canonic_cosets_extensions { - assert!(eval.find(point_index - subgroup_gen).is_some()); - } - } - } + use crate::core::poly::circle::CanonicCoset; #[test] fn test_iterator() { diff --git a/src/core/poly/circle/canonic.rs b/src/core/poly/circle/canonic.rs index 2e6f37ddc..0e571d51a 100644 --- a/src/core/poly/circle/canonic.rs +++ b/src/core/poly/circle/canonic.rs @@ -45,17 +45,6 @@ impl CanonicCoset { CircleDomain::new(Coset::half_odds(self.coset.log_size - 1)) } - /// Gets a good [CircleDomain] for extension of a poly defined on this coset. - /// The reason the domain looks like this is a bit more intricate, and not covered here. - pub fn evaluation_domain(&self, log_size: u32) -> CircleDomain { - assert!(log_size > self.coset.log_size); - // TODO(spapini): Document why this is like this. - CircleDomain::new(Coset::new( - CirclePointIndex::generator() + CirclePointIndex::subgroup_gen(self.coset.log_size + 1), - log_size - 1, - )) - } - /// Returns the log size of the coset. pub fn log_size(&self) -> u32 { self.coset.log_size diff --git a/src/core/poly/circle/domain.rs b/src/core/poly/circle/domain.rs index 4cf598697..d47141221 100644 --- a/src/core/poly/circle/domain.rs +++ b/src/core/poly/circle/domain.rs @@ -22,12 +22,6 @@ impl CircleDomain { Self { half_coset } } - /// Constructs a domain for constraint evaluation. - pub fn constraint_evaluation_domain(log_size: u32) -> Self { - assert!(log_size > 0); - CircleDomain::new(Coset::new(CirclePointIndex::generator(), log_size - 1)) - } - pub fn iter(&self) -> CircleDomainIterator { self.half_coset .iter() @@ -112,7 +106,7 @@ mod tests { #[test] fn test_circle_domain_iterator() { - let domain = CircleDomain::constraint_evaluation_domain(3); + let domain = CircleDomain::new(Coset::new(CirclePointIndex::generator(), 2)); for (i, point) in domain.iter().enumerate() { if i < 4 { assert_eq!( diff --git a/src/core/poly/circle/evaluation.rs b/src/core/poly/circle/evaluation.rs index 5c52f953d..1d50559ed 100644 --- a/src/core/poly/circle/evaluation.rs +++ b/src/core/poly/circle/evaluation.rs @@ -154,13 +154,13 @@ mod tests { use crate::core::backend::cpu::CPUCircleEvaluation; use crate::core::circle::Coset; use crate::core::fields::m31::BaseField; - use crate::core::poly::circle::{CanonicCoset, CircleDomain}; + use crate::core::poly::circle::CanonicCoset; use crate::core::poly::NaturalOrder; use crate::m31; #[test] fn test_interpolate_non_canonic() { - let domain = CircleDomain::constraint_evaluation_domain(3); + let domain = CanonicCoset::new(3).circle_domain(); assert_eq!(domain.log_size(), 3); let evaluation = CPUCircleEvaluation::<_, NaturalOrder>::new( domain, diff --git a/src/core/poly/circle/mod.rs b/src/core/poly/circle/mod.rs index ab90285a0..f2cdb308d 100644 --- a/src/core/poly/circle/mod.rs +++ b/src/core/poly/circle/mod.rs @@ -14,16 +14,14 @@ pub use secure_poly::{combine_secure_value, SecureCirclePoly}; #[cfg(test)] mod tests { - use super::{CanonicCoset, CircleDomain}; + use super::CanonicCoset; use crate::core::backend::cpu::CPUCircleEvaluation; use crate::core::fields::m31::BaseField; - use crate::core::fields::FieldExpOps; - use crate::core::poly::NaturalOrder; use crate::core::utils::bit_reverse_index; #[test] fn test_interpolate_and_eval() { - let domain = CircleDomain::constraint_evaluation_domain(3); + let domain = CanonicCoset::new(3).circle_domain(); assert_eq!(domain.log_size(), 3); let evaluation = CPUCircleEvaluation::new(domain, (0..8).map(BaseField::from_u32_unchecked).collect()); @@ -32,44 +30,6 @@ mod tests { assert_eq!(evaluation.values, evaluation2.values); } - #[test] - fn test_mixed_degree_example() { - let log_size = 4; - - // Compute domains. - let domain0 = CanonicCoset::new(log_size); - let eval_domain0 = domain0.evaluation_domain(log_size + 4); - let domain1 = CanonicCoset::new(log_size + 2); - let eval_domain1 = domain1.evaluation_domain(log_size + 3); - let constraint_domain = CircleDomain::constraint_evaluation_domain(log_size + 1); - - // Compute values. - let values1: Vec<_> = (0..(domain1.size() as u32)) - .map(BaseField::from_u32_unchecked) - .collect(); - let values0: Vec<_> = values1[1..].iter().step_by(4).map(|x| *x * *x).collect(); - - // Extend. - let trace_eval0 = CPUCircleEvaluation::new_canonical_ordered(domain0, values0); - let eval0 = trace_eval0.interpolate().evaluate(eval_domain0); - let trace_eval1 = CPUCircleEvaluation::new_canonical_ordered(domain1, values1); - let eval1 = trace_eval1.interpolate().evaluate(eval_domain1); - - // Compute constraint. - let constraint_eval = CPUCircleEvaluation::::new( - constraint_domain, - constraint_domain - .iter_indices() - .map(|ind| { - // The constraint is poly0(x+off0)^2 = poly1(x+off1). - eval0.get_at(ind).square() - eval1.get_at(domain1.index_at(1) + ind).square() - }) - .collect(), - ); - // TODO(spapini): Check low degree. - println!("{:?}", constraint_eval); - } - #[test] fn is_canonic_valid_domain() { let canonic_domain = CanonicCoset::new(4).circle_domain(); diff --git a/src/fibonacci/component.rs b/src/fibonacci/component.rs index a1ec44770..09b6be864 100644 --- a/src/fibonacci/component.rs +++ b/src/fibonacci/component.rs @@ -10,7 +10,7 @@ use crate::core::constraints::{coset_vanishing, pair_vanishing}; use crate::core::fields::m31::BaseField; use crate::core::fields::qm31::SecureField; use crate::core::fields::{ExtensionOf, FieldExpOps}; -use crate::core::poly::circle::{CanonicCoset, CircleDomain}; +use crate::core::poly::circle::CanonicCoset; use crate::core::utils::bit_reverse_index; use crate::core::ColumnVec; @@ -85,14 +85,13 @@ impl Component for FibonacciComponent { ) { let poly = &trace.columns[0]; let trace_domain = CanonicCoset::new(self.log_size); - let trace_eval_domain = trace_domain.evaluation_domain(self.log_size + 1); + let trace_eval_domain = CanonicCoset::new(self.log_size + 1).circle_domain(); let trace_eval = poly.evaluate(trace_eval_domain).bit_reverse(); // Step constraint. let constraint_log_degree_bound = trace_domain.log_size() + 1; let [mut accum] = evaluation_accumulator.columns([(constraint_log_degree_bound, 1)]); - let constraint_eval_domain = - CircleDomain::constraint_evaluation_domain(constraint_log_degree_bound); + let constraint_eval_domain = trace_eval_domain; for (off, point_coset) in [ (0, constraint_eval_domain.half_coset), ( @@ -104,28 +103,14 @@ impl Component for FibonacciComponent { let mul = trace_domain.step_size().div(point_coset.step_size); for (i, point) in point_coset.iter().enumerate() { let mask = [eval[i], eval[i as isize + mul], eval[i as isize + 2 * mul]]; - let res = self.step_constraint_eval_quotient_by_mask(point, &mask); - accum.accumulate(bit_reverse_index(i + off, constraint_log_degree_bound), res); - } - } - - // Boundary constraint. - let constraint_log_degree_bound = trace_domain.log_size(); - let [mut accum] = evaluation_accumulator.columns([(constraint_log_degree_bound, 1)]); - let constraint_eval_domain = - CircleDomain::constraint_evaluation_domain(constraint_log_degree_bound); - for (off, point_coset) in [ - (0, constraint_eval_domain.half_coset), - ( - constraint_eval_domain.half_coset.size(), - constraint_eval_domain.half_coset.conjugate(), - ), - ] { - let eval = trace_eval.fetch_eval_on_coset(point_coset.shift(trace_domain.index_at(0))); - for (i, point) in point_coset.iter().enumerate() { - let mask = [eval[i]]; - let res = self.boundary_constraint_eval_quotient_by_mask(point, &mask); - accum.accumulate(bit_reverse_index(i + off, constraint_log_degree_bound), res); + accum.accumulate( + bit_reverse_index(i + off, constraint_log_degree_bound), + self.step_constraint_eval_quotient_by_mask(point, &mask), + ); + accum.accumulate( + bit_reverse_index(i + off, constraint_log_degree_bound), + self.boundary_constraint_eval_quotient_by_mask(point, &[mask[0]]), + ); } } } @@ -140,13 +125,17 @@ impl Component for FibonacciComponent { mask: &ColumnVec>, evaluation_accumulator: &mut PointEvaluationAccumulator, ) { - let res = - self.step_constraint_eval_quotient_by_mask(point, &mask[0][..].try_into().unwrap()); - let constraint_log_degree_bound = self.log_size + 1; - evaluation_accumulator.accumulate(constraint_log_degree_bound, res); - let res = self - .boundary_constraint_eval_quotient_by_mask(point, &mask[0][..1].try_into().unwrap()); - let constraint_log_degree_bound = self.log_size; - evaluation_accumulator.accumulate(constraint_log_degree_bound, res); + let constraints_log_degree_bound = self.log_size + 1; + evaluation_accumulator.accumulate( + constraints_log_degree_bound, + self.step_constraint_eval_quotient_by_mask(point, &mask[0][..].try_into().unwrap()), + ); + evaluation_accumulator.accumulate( + constraints_log_degree_bound, + self.boundary_constraint_eval_quotient_by_mask( + point, + &mask[0][..1].try_into().unwrap(), + ), + ); } }