use alloc::vec::Vec;
use core::ops::{Add, Mul, Sub};
use p3_field::{Algebra, Dup, ExtensionField, Field, PrimeCharacteristicRing};
use p3_matrix::dense::{RowMajorMatrix, RowMajorMatrixView};
pub trait WindowAccess<T> {
fn current_slice(&self) -> &[T];
fn next_slice(&self) -> &[T];
#[inline]
fn current(&self, i: usize) -> Option<T>
where
T: Clone,
{
self.current_slice().get(i).cloned()
}
#[inline]
fn next(&self, i: usize) -> Option<T>
where
T: Clone,
{
self.next_slice().get(i).cloned()
}
}
#[derive(Debug, Clone, Copy)]
pub struct RowWindow<'a, T> {
current: &'a [T],
next: &'a [T],
}
impl<'a, T> RowWindow<'a, T> {
#[inline]
pub fn from_view(view: &RowMajorMatrixView<'a, T>) -> Self {
let width = view.width;
assert_eq!(
view.values.len(),
2 * width,
"RowWindow::from_view: expected 2 rows (2*{width} elements), got {}",
view.values.len()
);
let (current, next) = view.values.split_at(width);
Self { current, next }
}
#[inline]
pub fn from_two_rows(current: &'a [T], next: &'a [T]) -> Self {
debug_assert_eq!(
current.len(),
next.len(),
"RowWindow::from_two_rows: row lengths differ ({} vs {})",
current.len(),
next.len()
);
Self { current, next }
}
}
impl<T> WindowAccess<T> for RowWindow<'_, T> {
#[inline]
fn current_slice(&self) -> &[T] {
self.current
}
#[inline]
fn next_slice(&self) -> &[T] {
self.next
}
}
pub trait BaseAir<F>: Sync {
fn width(&self) -> usize;
fn preprocessed_trace(&self) -> Option<RowMajorMatrix<F>> {
None
}
fn main_next_row_columns(&self) -> Vec<usize> {
(0..self.width()).collect()
}
fn preprocessed_next_row_columns(&self) -> Vec<usize> {
self.preprocessed_trace()
.map(|t| (0..t.width).collect())
.unwrap_or_default()
}
fn num_constraints(&self) -> Option<usize> {
None
}
fn max_constraint_degree(&self) -> Option<usize> {
None
}
fn num_public_values(&self) -> usize {
0
}
}
pub trait Air<AB: AirBuilder>: BaseAir<AB::F> {
fn eval(&self, builder: &mut AB);
}
pub trait AirBuilder: Sized {
type F: PrimeCharacteristicRing + Sync;
type Expr: Algebra<Self::F> + Algebra<Self::Var>;
type Var: Into<Self::Expr>
+ Copy
+ Send
+ Sync
+ Add<Self::F, Output = Self::Expr>
+ Add<Self::Var, Output = Self::Expr>
+ Add<Self::Expr, Output = Self::Expr>
+ Sub<Self::F, Output = Self::Expr>
+ Sub<Self::Var, Output = Self::Expr>
+ Sub<Self::Expr, Output = Self::Expr>
+ Mul<Self::F, Output = Self::Expr>
+ Mul<Self::Var, Output = Self::Expr>
+ Mul<Self::Expr, Output = Self::Expr>;
type PreprocessedWindow: WindowAccess<Self::Var> + Clone;
type MainWindow: WindowAccess<Self::Var> + Clone;
type PublicVar: Into<Self::Expr> + Copy;
fn main(&self) -> Self::MainWindow;
fn preprocessed(&self) -> &Self::PreprocessedWindow;
fn is_first_row(&self) -> Self::Expr;
fn is_last_row(&self) -> Self::Expr;
fn is_transition(&self) -> Self::Expr {
self.is_transition_window(2)
}
fn is_transition_window(&self, size: usize) -> Self::Expr;
fn when<I: Into<Self::Expr>>(&mut self, condition: I) -> FilteredAirBuilder<'_, Self> {
FilteredAirBuilder {
inner: self,
condition: condition.into(),
}
}
fn when_ne<I1: Into<Self::Expr>, I2: Into<Self::Expr>>(
&mut self,
x: I1,
y: I2,
) -> FilteredAirBuilder<'_, Self> {
self.when(x.into() - y.into())
}
fn when_first_row(&mut self) -> FilteredAirBuilder<'_, Self> {
self.when(self.is_first_row())
}
fn when_last_row(&mut self) -> FilteredAirBuilder<'_, Self> {
self.when(self.is_last_row())
}
fn when_transition(&mut self) -> FilteredAirBuilder<'_, Self> {
self.when(self.is_transition())
}
fn when_transition_window(&mut self, size: usize) -> FilteredAirBuilder<'_, Self> {
self.when(self.is_transition_window(size))
}
fn assert_zero<I: Into<Self::Expr>>(&mut self, x: I);
fn assert_zeros<const N: usize, I: Into<Self::Expr>>(&mut self, array: [I; N]) {
for elem in array {
self.assert_zero(elem);
}
}
fn assert_bools<const N: usize, I: Into<Self::Expr>>(&mut self, array: [I; N]) {
let zero_array = array.map(|x| x.into().bool_check());
self.assert_zeros(zero_array);
}
fn assert_one<I: Into<Self::Expr>>(&mut self, x: I) {
self.assert_zero(x.into() - Self::Expr::ONE);
}
fn assert_eq<I1: Into<Self::Expr>, I2: Into<Self::Expr>>(&mut self, x: I1, y: I2) {
self.assert_zero(x.into() - y.into());
}
fn public_values(&self) -> &[Self::PublicVar] {
&[]
}
fn assert_bool<I: Into<Self::Expr>>(&mut self, x: I) {
self.assert_zero(x.into().bool_check());
}
}
pub trait PeriodicAirBuilder: AirBuilder {
type PeriodicVar: Into<Self::Expr> + Copy;
fn periodic_values(&self) -> &[Self::PeriodicVar];
}
pub trait AirBuilderWithContext: AirBuilder {
type EvalContext;
fn eval_context(&self) -> &Self::EvalContext;
}
pub trait ExtensionBuilder: AirBuilder<F: Field> {
type EF: ExtensionField<Self::F>;
type ExprEF: Algebra<Self::Expr> + Algebra<Self::EF>;
type VarEF: Into<Self::ExprEF> + Copy + Send + Sync;
fn assert_zero_ext<I>(&mut self, x: I)
where
I: Into<Self::ExprEF>;
fn assert_eq_ext<I1, I2>(&mut self, x: I1, y: I2)
where
I1: Into<Self::ExprEF>,
I2: Into<Self::ExprEF>,
{
self.assert_zero_ext(x.into() - y.into());
}
fn assert_one_ext<I>(&mut self, x: I)
where
I: Into<Self::ExprEF>,
{
self.assert_eq_ext(x, Self::ExprEF::ONE);
}
}
pub trait PermutationAirBuilder: ExtensionBuilder {
type MP: WindowAccess<Self::VarEF>;
type RandomVar: Into<Self::ExprEF> + Copy;
type PermutationVar: Into<Self::ExprEF> + Clone;
fn permutation(&self) -> Self::MP;
fn permutation_randomness(&self) -> &[Self::RandomVar];
fn permutation_values(&self) -> &[Self::PermutationVar];
}
#[derive(Debug)]
pub struct FilteredAirBuilder<'a, AB: AirBuilder> {
pub inner: &'a mut AB,
condition: AB::Expr,
}
impl<AB: AirBuilder> FilteredAirBuilder<'_, AB> {
pub fn condition(&self) -> AB::Expr {
self.condition.dup()
}
}
impl<AB: AirBuilder> AirBuilder for FilteredAirBuilder<'_, AB> {
type F = AB::F;
type Expr = AB::Expr;
type Var = AB::Var;
type PreprocessedWindow = AB::PreprocessedWindow;
type MainWindow = AB::MainWindow;
type PublicVar = AB::PublicVar;
fn main(&self) -> Self::MainWindow {
self.inner.main()
}
fn preprocessed(&self) -> &Self::PreprocessedWindow {
self.inner.preprocessed()
}
fn is_first_row(&self) -> Self::Expr {
self.inner.is_first_row()
}
fn is_last_row(&self) -> Self::Expr {
self.inner.is_last_row()
}
fn is_transition(&self) -> Self::Expr {
self.inner.is_transition()
}
fn is_transition_window(&self, size: usize) -> Self::Expr {
self.inner.is_transition_window(size)
}
fn assert_zero<I: Into<Self::Expr>>(&mut self, x: I) {
self.inner.assert_zero(self.condition() * x.into());
}
fn public_values(&self) -> &[Self::PublicVar] {
self.inner.public_values()
}
}
impl<AB: PeriodicAirBuilder> PeriodicAirBuilder for FilteredAirBuilder<'_, AB> {
type PeriodicVar = AB::PeriodicVar;
fn periodic_values(&self) -> &[Self::PeriodicVar] {
self.inner.periodic_values()
}
}
impl<AB: ExtensionBuilder> ExtensionBuilder for FilteredAirBuilder<'_, AB> {
type EF = AB::EF;
type ExprEF = AB::ExprEF;
type VarEF = AB::VarEF;
fn assert_zero_ext<I>(&mut self, x: I)
where
I: Into<Self::ExprEF>,
{
let ext_x: Self::ExprEF = x.into();
let condition: AB::Expr = self.condition();
self.inner.assert_zero_ext(ext_x * condition);
}
}
impl<AB: PermutationAirBuilder> PermutationAirBuilder for FilteredAirBuilder<'_, AB> {
type MP = AB::MP;
type RandomVar = AB::RandomVar;
type PermutationVar = AB::PermutationVar;
fn permutation(&self) -> Self::MP {
self.inner.permutation()
}
fn permutation_randomness(&self) -> &[Self::RandomVar] {
self.inner.permutation_randomness()
}
fn permutation_values(&self) -> &[Self::PermutationVar] {
self.inner.permutation_values()
}
}
impl<AB: AirBuilderWithContext> AirBuilderWithContext for FilteredAirBuilder<'_, AB> {
type EvalContext = AB::EvalContext;
fn eval_context(&self) -> &Self::EvalContext {
self.inner.eval_context()
}
}