Skip to content

Commit

Permalink
Backend
Browse files Browse the repository at this point in the history
  • Loading branch information
spapinistarkware committed Feb 22, 2024
1 parent f51dc4f commit d23cd5b
Show file tree
Hide file tree
Showing 16 changed files with 424 additions and 252 deletions.
73 changes: 38 additions & 35 deletions src/core/air/evaluation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use core::slice;

use super::{ComponentTrace, ComponentVisitor};
use crate::core::backend::{Backend, CPUBackend, Col};
use crate::core::fields::m31::BaseField;
use crate::core::fields::qm31::SecureField;
use crate::core::fields::Field;
Expand All @@ -15,11 +16,11 @@ use crate::core::poly::circle::{CircleDomain, CircleEvaluation, CirclePoly};
/// Computes f(P0), the combined polynomial at that point.
pub struct PointEvaluationAccumulator {
random_coeff: SecureField,
// Accumulated evaluations for each log_size.
// Each `sub_accumulation` holds `sum_{i=0}^{n-1} evaluation_i * alpha^(n-1-i)`,
// where `n` is the number of accumulated evaluations for this log_size.
/// Accumulated evaluations for each log_size.
/// Each `sub_accumulation` holds `sum_{i=0}^{n-1} evaluation_i * alpha^(n-1-i)`,
/// where `n` is the number of accumulated evaluations for this log_size.
sub_accumulations: Vec<SecureField>,
// Number of accumulated evaluations for each log_size.
/// Number of accumulated evaluations for each log_size.
n_accumulated: Vec<usize>,
}
impl PointEvaluationAccumulator {
Expand Down Expand Up @@ -59,20 +60,19 @@ impl PointEvaluationAccumulator {
}
}

type Column = Vec<SecureField>;

/// Accumulates evaluations of u_i(P), each at an evaluation domain of the size of that polynomial.
/// Computes the coefficients of f(P).
pub struct DomainEvaluationAccumulator {
pub struct DomainEvaluationAccumulator<B: Backend> {
random_coeff: SecureField,
// Accumulated evaluations for each log_size.
// Each `sub_accumulation` holds `sum_{i=0}^{n-1} evaluation_i * alpha^(n-1-i)`,
// where `n` is the number of accumulated evaluations for this log_size.
sub_accumulations: Vec<Column>,
// Number of accumulated evaluations for each log_size.
/// Accumulated evaluations for each log_size.
/// Each `sub_accumulation` holds `sum_{i=0}^{n-1} evaluation_i * alpha^(n-1-i)`,
/// where `n` is the number of accumulated evaluations for this log_size.
sub_accumulations: Vec<Col<B, SecureField>>,
/// Number of accumulated evaluations for each log_size.
n_cols_per_size: Vec<usize>,
}
impl DomainEvaluationAccumulator {

impl<B: Backend> DomainEvaluationAccumulator<B> {
/// Creates a new accumulator.
/// `random_coeff` should be a secure random field element, drawn from the channel.
/// `max_log_size` is the maximum log_size of the accumulated evaluations.
Expand All @@ -81,7 +81,7 @@ impl DomainEvaluationAccumulator {
Self {
random_coeff,
sub_accumulations: (0..(max_log_size + 1))
.map(|n| vec![SecureField::default(); 1 << n])
.map(|n| Col::<B, SecureField>::from_iter(vec![SecureField::default(); 1 << n]))
.collect(),
n_cols_per_size: vec![0; max_log_size + 1],
}
Expand All @@ -95,7 +95,7 @@ impl DomainEvaluationAccumulator {
pub fn columns<const N: usize>(
&mut self,
n_cols_per_size: [(u32, usize); N],
) -> [ColumnAccumulator<'_>; N] {
) -> [ColumnAccumulator<'_, B>; N] {
n_cols_per_size.iter().for_each(|(log_size, n_col)| {
self.n_cols_per_size[*log_size as usize] += n_col;
});
Expand All @@ -108,8 +108,15 @@ impl DomainEvaluationAccumulator {
})
}

/// Returns the log size of the resulting polynomial.
pub fn log_size(&self) -> u32 {
(self.sub_accumulations.len() - 1) as u32
}
}

impl DomainEvaluationAccumulator<CPUBackend> {
/// Computes f(P) as coefficients.
pub fn finalize(self) -> CirclePoly<SecureField> {
pub fn finalize(self) -> CirclePoly<CPUBackend, SecureField> {
let mut res_coeffs = vec![SecureField::default(); 1 << self.log_size()];
let res_log_size = self.log_size();
for (coeffs, n_cols) in self
Expand All @@ -120,7 +127,7 @@ impl DomainEvaluationAccumulator {
if log_size == 0 {
return values;
}
CircleEvaluation::new(
CircleEvaluation::<CPUBackend, SecureField>::new(
CircleDomain::constraint_evaluation_domain(log_size as u32),
values,
)
Expand All @@ -142,34 +149,29 @@ impl DomainEvaluationAccumulator {

CirclePoly::new(res_coeffs)
}

/// Returns the log_size of the resulting polynomial.
pub fn log_size(&self) -> u32 {
(self.sub_accumulations.len() - 1) as u32
}
}

/// An domain accumulator for polynomials of a single size.
pub struct ColumnAccumulator<'a> {
pub struct ColumnAccumulator<'a, B: Backend> {
random_coeff: SecureField,
col: &'a mut Column,
col: &'a mut Col<B, SecureField>,
}
impl<'a> ColumnAccumulator<'a> {
impl<'a> ColumnAccumulator<'a, CPUBackend> {
pub fn accumulate(&mut self, index: usize, evaluation: BaseField) {
let accum = &mut self.col[index];
*accum = *accum * self.random_coeff + evaluation;
}
}

/// Evaluates components' constraint polynomials and aggregates them into a composition polynomial.
pub struct ConstraintEvaluator<'a> {
traces: slice::Iter<'a, ComponentTrace<'a>>,
evaluation_accumulator: DomainEvaluationAccumulator,
pub struct ConstraintEvaluator<'a, B: Backend> {
traces: slice::Iter<'a, ComponentTrace<'a, B>>,
evaluation_accumulator: DomainEvaluationAccumulator<B>,
}

impl<'a> ConstraintEvaluator<'a> {
impl<'a> ConstraintEvaluator<'a, CPUBackend> {
pub fn new(
traces: &'a [ComponentTrace<'a>],
traces: &'a [ComponentTrace<'a, CPUBackend>],
max_log_size: u32,
random_coeff: SecureField,
) -> Self {
Expand All @@ -179,13 +181,13 @@ impl<'a> ConstraintEvaluator<'a> {
}
}

pub fn finalize(self) -> CirclePoly<SecureField> {
pub fn finalize(self) -> CirclePoly<CPUBackend, SecureField> {
self.evaluation_accumulator.finalize()
}
}

impl<'a> ComponentVisitor for ConstraintEvaluator<'a> {
fn visit<C: crate::core::air::Component>(&mut self, component: &C) {
impl<'a, B: Backend> ComponentVisitor<B> for ConstraintEvaluator<'a, B> {
fn visit<C: crate::core::air::Component<B>>(&mut self, component: &C) {
component.evaluate_constraint_quotients_on_domain(
self.traces.next().expect("no more component traces"),
&mut self.evaluation_accumulator,
Expand All @@ -201,6 +203,7 @@ mod tests {
use rand::{Rng, SeedableRng};

use super::*;
use crate::core::backend::cpu::CPUCircleEvaluation;
use crate::core::circle::CirclePoint;
use crate::core::fields::m31::{M31, P};
use crate::qm31;
Expand Down Expand Up @@ -264,7 +267,7 @@ mod tests {
let alpha = qm31!(2, 3, 4, 5);

// Use accumulator.
let mut accumulator = DomainEvaluationAccumulator::new(alpha, LOG_SIZE_BOUND);
let mut accumulator = DomainEvaluationAccumulator::<CPUBackend>::new(alpha, LOG_SIZE_BOUND);
let n_cols_per_size: [(u32, usize); (LOG_SIZE_BOUND - LOG_SIZE_MIN) as usize] =
array::from_fn(|i| {
let current_log_size = LOG_SIZE_MIN + i as u32;
Expand Down Expand Up @@ -295,7 +298,7 @@ mod tests {
let mut res = SecureField::default();
for (log_size, values) in pairs.into_iter() {
res = res * alpha
+ CircleEvaluation::new(
+ CPUCircleEvaluation::new(
CircleDomain::constraint_evaluation_domain(log_size),
values,
)
Expand Down
33 changes: 17 additions & 16 deletions src/core/air/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::ops::Deref;
use self::evaluation::{
ConstraintEvaluator, DomainEvaluationAccumulator, PointEvaluationAccumulator,
};
use super::backend::{Backend, CPUBackend};
use super::circle::CirclePoint;
use super::fields::m31::BaseField;
use super::fields::qm31::SecureField;
Expand All @@ -18,18 +19,18 @@ pub mod evaluation;
/// For instance, all interaction elements are assumed to be present in it.
/// Therefore, an AIR is generated only after the initial trace commitment phase.
// TODO(spapini): consider renaming this struct.
pub trait Air {
fn visit_components<V: ComponentVisitor>(&self, v: &mut V);
pub trait Air<B: Backend> {
fn visit_components<V: ComponentVisitor<B>>(&self, v: &mut V);

fn max_constraint_log_degree_bound(&self) -> u32;
}

pub trait AirExt: Air {
pub trait AirExt: Air<CPUBackend> {
fn compute_composition_polynomial(
&self,
random_coeff: SecureField,
component_traces: &[ComponentTrace<'_>],
) -> CirclePoly<SecureField> {
component_traces: &[ComponentTrace<'_, CPUBackend>],
) -> CirclePoly<CPUBackend, SecureField> {
let mut evaluator = ConstraintEvaluator::new(
component_traces,
self.max_constraint_log_degree_bound(),
Expand All @@ -40,10 +41,10 @@ pub trait AirExt: Air {
}
}

impl<A: Air> AirExt for A {}
impl<A: Air<CPUBackend>> AirExt for A {}

pub trait ComponentVisitor {
fn visit<C: Component>(&mut self, component: &C);
pub trait ComponentVisitor<B: Backend> {
fn visit<C: Component<B>>(&mut self, component: &C);
}

/// Holds the mask offsets at each column.
Expand Down Expand Up @@ -78,7 +79,7 @@ impl Deref for Mask {

/// A component is a set of trace columns of various sizes along with a set of
/// constraints on them.
pub trait Component {
pub trait Component<B: Backend> {
fn max_constraint_log_degree_bound(&self) -> u32;

/// Returns the degree bounds of each trace column.
Expand All @@ -90,8 +91,8 @@ pub trait Component {
// Note: This will be computed using a MaterializedGraph.
fn evaluate_constraint_quotients_on_domain(
&self,
trace: &ComponentTrace<'_>,
evaluation_accumulator: &mut DomainEvaluationAccumulator,
trace: &ComponentTrace<'_, B>,
evaluation_accumulator: &mut DomainEvaluationAccumulator<B>,
);

fn mask(&self) -> Mask;
Expand All @@ -103,7 +104,7 @@ pub trait Component {
fn mask_points_and_values(
&self,
point: CirclePoint<SecureField>,
trace: &ComponentTrace<'_>,
trace: &ComponentTrace<'_, B>,
) -> (ColumnVec<CirclePoint<SecureField>>, ColumnVec<SecureField>) {
let domains = trace
.columns
Expand Down Expand Up @@ -134,12 +135,12 @@ pub trait Component {
// TODO(spapini): Extra functions for FRI and decommitment.
}

pub struct ComponentTrace<'a> {
pub columns: Vec<&'a CirclePoly<BaseField>>,
pub struct ComponentTrace<'a, B: Backend> {
pub columns: Vec<&'a CirclePoly<B, BaseField>>,
}

impl<'a> ComponentTrace<'a> {
pub fn new(columns: Vec<&'a CirclePoly<BaseField>>) -> Self {
impl<'a, B: Backend> ComponentTrace<'a, B> {
pub fn new(columns: Vec<&'a CirclePoly<B, BaseField>>) -> Self {
Self { columns }
}
}
27 changes: 27 additions & 0 deletions src/core/backend/cpu/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use std::fmt::Debug;

use super::{Backend, Column, FieldOps};
use crate::core::fields::Field;
use crate::core::poly::circle::{CircleEvaluation, CirclePoly};
use crate::core::poly::NaturalOrder;

mod poly;

#[derive(Copy, Clone, Debug)]
pub struct CPUBackend;

impl Backend for CPUBackend {}

impl<F: Field> FieldOps<F> for CPUBackend {
type Column = Vec<F>;
}

impl<F: Clone + Debug> Column<F> for Vec<F> {
fn len(&self) -> usize {
self.len()
}
}

pub type CPUCirclePoly<F> = CirclePoly<CPUBackend, F>;
pub type CPUCircleEvaluation<F, EvalOrder = NaturalOrder> =
CircleEvaluation<CPUBackend, F, EvalOrder>;
Loading

0 comments on commit d23cd5b

Please sign in to comment.