Skip to content

Commit

Permalink
Revert "removed computing line coeffs (#643)"
Browse files Browse the repository at this point in the history
This reverts commit a150b8f.
  • Loading branch information
spapinistarkware committed Jun 30, 2024
1 parent f59f722 commit f89c821
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 11 deletions.
56 changes: 49 additions & 7 deletions crates/prover/src/core/backend/cpu/quotients.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
use itertools::izip;
use num_traits::Zero;
use num_traits::{One, Zero};

use super::CpuBackend;
use crate::core::backend::{Backend, Col};
use crate::core::constraints::point_vanishing_fraction;
use crate::core::circle::CirclePoint;
use crate::core::constraints::{complex_conjugate_line_coeffs, point_vanishing_fraction};
use crate::core::fields::m31::BaseField;
use crate::core::fields::qm31::SecureField;
use crate::core::fields::secure_column::SecureColumn;
use crate::core::fields::FieldExpOps;
use crate::core::pcs::quotients::{ColumnSampleBatch, QuotientOps};
use crate::core::pcs::quotients::{ColumnSampleBatch, PointSample, QuotientOps};
use crate::core::poly::circle::{CircleDomain, CircleEvaluation, SecureEvaluation};
use crate::core::poly::BitReversedOrder;
use crate::core::utils::bit_reverse;
use crate::core::utils::{bit_reverse, bit_reverse_index};

impl QuotientOps for CpuBackend {
fn accumulate_quotients(
Expand All @@ -26,8 +27,14 @@ impl QuotientOps for CpuBackend {
// TODO(spapini): bit reverse iterator.
for row in 0..domain.size() {
// TODO(alonh): Make an efficient bit reverse domain iterator, possibly for AVX backend.
let row_value =
accumulate_row_quotients(sample_batches, columns, &quotient_constants, row);
let domain_point = domain.at(bit_reverse_index(row, domain.log_size()));
let row_value = accumulate_row_quotients(
sample_batches,
columns,
&quotient_constants,
row,
domain_point,
);
values.set(row, row_value);
}
SecureEvaluation { domain, values }
Expand All @@ -41,10 +48,12 @@ pub fn accumulate_row_quotients(
columns: &[&CircleEvaluation<CpuBackend, BaseField, BitReversedOrder>],
quotient_constants: &QuotientConstants<CpuBackend>,
row: usize,
_domain_point: CirclePoint<BaseField>,
) -> SecureField {
let mut row_accumulator = SecureField::zero();
for (sample_batch, batch_coeff, denominator_inverses) in izip!(
for (sample_batch, _line_coeffs, batch_coeff, denominator_inverses) in izip!(
sample_batches,
&quotient_constants.line_coeffs,
&quotient_constants.batch_random_coeffs,
&quotient_constants.denominator_inverses
) {
Expand All @@ -60,6 +69,34 @@ pub fn accumulate_row_quotients(
row_accumulator
}

/// Precompute the complex conjugate line coefficients for each column in each sample batch.
/// Specifically, for the i-th (in a sample batch) column's numerator term
/// `alpha^i * (c * F(p) - (a * p.y + b))`, we precompute and return the constants:
/// (`alpha^i * a`, `alpha^i * b`, `alpha^i * c`).
pub fn column_line_coeffs(
sample_batches: &[ColumnSampleBatch],
random_coeff: SecureField,
) -> Vec<Vec<(SecureField, SecureField, SecureField)>> {
sample_batches
.iter()
.map(|sample_batch| {
let mut alpha = SecureField::one();
sample_batch
.columns_and_values
.iter()
.map(|(_, sampled_value)| {
alpha *= random_coeff;
let sample = PointSample {
point: sample_batch.point,
value: *sampled_value,
};
complex_conjugate_line_coeffs(&sample, alpha)
})
.collect()
})
.collect()
}

/// Precompute the random coefficients used to linearly combine the batched quotients.
/// Specifically, for each sample batch we compute random_coeff^(number of columns in the batch),
/// which is used to linearly combine the batch with the next one.
Expand Down Expand Up @@ -110,16 +147,21 @@ pub fn quotient_constants(
random_coeff: SecureField,
domain: CircleDomain,
) -> QuotientConstants<CpuBackend> {
let line_coeffs = column_line_coeffs(sample_batches, random_coeff);
let batch_random_coeffs = batch_random_coeffs(sample_batches, random_coeff);
let denominator_inverses = denominator_inverses(sample_batches, domain);
QuotientConstants {
line_coeffs,
batch_random_coeffs,
denominator_inverses,
}
}

/// Holds the precomputed constant values used in each quotient evaluation.
pub struct QuotientConstants<B: Backend> {
/// The line coefficients for each quotient numerator term. For more details see
/// [self::column_line_coeffs].
pub line_coeffs: Vec<Vec<(SecureField, SecureField, SecureField)>>,
/// The random coefficients used to linearly combine the batched quotients For more details see
/// [self::batch_random_coeffs].
pub batch_random_coeffs: Vec<SecureField>,
Expand Down
11 changes: 9 additions & 2 deletions crates/prover/src/core/backend/simd/quotients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use super::column::SecureFieldVec;
use super::m31::{PackedBaseField, LOG_N_LANES, N_LANES};
use super::qm31::PackedSecureField;
use super::SimdBackend;
use crate::core::backend::cpu::quotients::{batch_random_coeffs, QuotientConstants};
use crate::core::backend::cpu::quotients::{
batch_random_coeffs, column_line_coeffs, QuotientConstants,
};
use crate::core::backend::{Col, Column};
use crate::core::circle::CirclePoint;
use crate::core::fields::m31::BaseField;
Expand Down Expand Up @@ -54,6 +56,8 @@ impl QuotientOps for SimdBackend {
}
}

// TODO(Ohad): no longer using pair_vanishing, remove domain_point_vec and line_coeffs, or write a
// function that deals with quotients over pair_vanishing polynomials.
pub fn accumulate_row_quotients(
sample_batches: &[ColumnSampleBatch],
columns: &[&CircleEvaluation<SimdBackend, BaseField, BitReversedOrder>],
Expand All @@ -62,8 +66,9 @@ pub fn accumulate_row_quotients(
_domain_point_vec: (PackedBaseField, PackedBaseField),
) -> PackedSecureField {
let mut row_accumulator = PackedSecureField::zero();
for (sample_batch, batch_coeff, denominator_inverses) in izip!(
for (sample_batch, _, batch_coeff, denominator_inverses) in izip!(
sample_batches,
&quotient_constants.line_coeffs,
&quotient_constants.batch_random_coeffs,
&quotient_constants.denominator_inverses
) {
Expand Down Expand Up @@ -151,9 +156,11 @@ fn quotient_constants(
random_coeff: SecureField,
domain: CircleDomain,
) -> QuotientConstants<SimdBackend> {
let line_coeffs = column_line_coeffs(sample_batches, random_coeff);
let batch_random_coeffs = batch_random_coeffs(sample_batches, random_coeff);
let denominator_inverses = denominator_inverses(sample_batches, domain);
QuotientConstants {
line_coeffs,
batch_random_coeffs,
denominator_inverses,
}
Expand Down
92 changes: 90 additions & 2 deletions crates/prover/src/core/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ use num_traits::One;

use super::circle::{CirclePoint, Coset};
use super::fields::m31::BaseField;
use super::fields::qm31::SecureField;
use super::fields::ExtensionOf;
use super::pcs::quotients::PointSample;
use crate::core::fields::ComplexConjugate;

/// Evaluates a vanishing polynomial of the coset at a point.
pub fn coset_vanishing<F: ExtensionOf<BaseField>>(coset: Coset, mut p: CirclePoint<F>) -> F {
Expand Down Expand Up @@ -80,16 +83,61 @@ pub fn point_vanishing_fraction<F: ExtensionOf<BaseField>, EF: ExtensionOf<F>>(
(h.y, (EF::one() + h.x))
}

/// Evaluates a point on a line between a point and its complex conjugate.
/// Relies on the fact that every polynomial F over the base field holds:
/// F(p*) == F(p)* (* being the complex conjugate).
pub fn complex_conjugate_line(
point: CirclePoint<SecureField>,
value: SecureField,
p: CirclePoint<BaseField>,
) -> SecureField {
// TODO(AlonH): This assertion will fail at a probability of 1 to 2^62. Use a better solution.
assert_ne!(
point.y,
point.y.complex_conjugate(),
"Cannot evaluate a line with a single point ({point:?})."
);
value
+ (value.complex_conjugate() - value) * (-point.y + p.y)
/ (point.complex_conjugate().y - point.y)
}

/// Evaluates the coefficients of a line between a point and its complex conjugate. Specifically,
/// `a, b, and c, s.t. a*x + b -c*y = 0` for (x,y) being (sample.y, sample.value) and
/// (conj(sample.y), conj(sample.value)).
/// Relies on the fact that every polynomial F over the base
/// field holds: F(p*) == F(p)* (* being the complex conjugate).
pub fn complex_conjugate_line_coeffs(
sample: &PointSample,
alpha: SecureField,
) -> (SecureField, SecureField, SecureField) {
// TODO(AlonH): This assertion will fail at a probability of 1 to 2^62. Use a better solution.
assert_ne!(
sample.point.y,
sample.point.y.complex_conjugate(),
"Cannot evaluate a line with a single point ({:?}).",
sample.point
);
let a = sample.value.complex_conjugate() - sample.value;
let c = sample.point.complex_conjugate().y - sample.point.y;
let b = sample.value * c - a * sample.point.y;
(alpha * a, alpha * b, alpha * c)
}

#[cfg(test)]
mod tests {
use num_traits::Zero;

use super::{coset_vanishing, point_excluder, point_vanishing};
use crate::core::backend::cpu::CpuCirclePoly;
use crate::core::backend::cpu::{CpuCircleEvaluation, CpuCirclePoly};
use crate::core::circle::{CirclePoint, CirclePointIndex, Coset};
use crate::core::constraints::pair_vanishing;
use crate::core::constraints::{complex_conjugate_line, pair_vanishing};
use crate::core::fields::m31::{BaseField, M31};
use crate::core::fields::qm31::SecureField;
use crate::core::fields::{ComplexConjugate, FieldExpOps};
use crate::core::poly::circle::CanonicCoset;
use crate::core::poly::NaturalOrder;
use crate::core::test_utils::secure_eval_to_base_eval;
use crate::m31;

#[test]
Expand Down Expand Up @@ -171,4 +219,44 @@ mod tests {
polynomial.eval_at_point(oods_point).complex_conjugate()
);
}

#[test]
fn test_point_vanishing_degree() {
// Create a polynomial over a circle domain.
let log_domain_size = 7;
let domain_size = 1 << log_domain_size;
let polynomial = CpuCirclePoly::new((0..domain_size).map(|i| m31!(i)).collect());

// Create a larger domain.
let log_large_domain_size = log_domain_size + 1;
let large_domain_size = 1 << log_large_domain_size;
let large_domain = CanonicCoset::new(log_large_domain_size).circle_domain();

// Create a vanish point that is not in the large domain.
let vanish_point = CirclePoint::get_point(97);
let vanish_point_value = polynomial.eval_at_point(vanish_point);

// Compute the quotient polynomial.
let mut quotient_polynomial_values = Vec::with_capacity(large_domain_size as usize);
for point in large_domain.iter() {
let line = complex_conjugate_line(vanish_point, vanish_point_value, point);
let mut value = polynomial.eval_at_point(point.into_ef()) - line;
value /= pair_vanishing(
vanish_point,
vanish_point.complex_conjugate(),
point.into_ef(),
);
quotient_polynomial_values.push(value);
}
let quotient_evaluation = CpuCircleEvaluation::<SecureField, NaturalOrder>::new(
large_domain,
quotient_polynomial_values,
);
let quotient_polynomial = secure_eval_to_base_eval(&quotient_evaluation)
.bit_reverse()
.interpolate();

// Check that the quotient polynomial is indeed in the wanted fft space.
assert!(quotient_polynomial.is_in_fft_space(log_domain_size));
}
}
3 changes: 3 additions & 0 deletions crates/prover/src/core/pcs/quotients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::core::poly::circle::{
use crate::core::poly::BitReversedOrder;
use crate::core::prover::VerificationError;
use crate::core::queries::SparseSubCircleDomain;
use crate::core::utils::bit_reverse_index;

pub trait QuotientOps: PolyOps {
/// Accumulates the quotients of the columns at the given domain.
Expand Down Expand Up @@ -152,11 +153,13 @@ pub fn fri_answers_for_log_size(
// TODO(spapini): bit reverse iterator.
let mut values = Vec::new();
for row in 0..domain.size() {
let domain_point = domain.at(bit_reverse_index(row, log_size));
let value = accumulate_row_quotients(
&sample_batches,
&column_evals.iter().collect_vec(),
&quotient_constants,
row,
domain_point,
);
values.push(value);
}
Expand Down

0 comments on commit f89c821

Please sign in to comment.