use alloc::vec::Vec;
use p3_field::{ExtensionField, Field};
use p3_matrix::dense::RowMajorMatrix;
use crate::PolynomialSpace;
#[derive(Clone, Debug)]
pub struct PeriodicLdeTable<F> {
values: RowMajorMatrix<F>,
height: usize,
}
impl<F: Clone + Send + Sync> PeriodicLdeTable<F> {
pub const fn new(values: RowMajorMatrix<F>) -> Self {
let height = match values.values.len().checked_div(values.width) {
Some(h) => h,
None => 0,
};
debug_assert!(
height == 0 || height.is_power_of_two(),
"PeriodicLdeTable height must be a power of two for bitmask indexing"
);
Self { values, height }
}
pub fn empty() -> Self {
Self {
values: RowMajorMatrix::new(Vec::new(), 0),
height: 0,
}
}
pub const fn is_empty(&self) -> bool {
self.values.values.is_empty()
}
pub const fn width(&self) -> usize {
self.values.width
}
pub const fn height(&self) -> usize {
self.height
}
#[inline]
pub fn get(&self, lde_idx: usize, col_idx: usize) -> &F {
let height = self.height;
debug_assert!(height > 0, "cannot index into empty periodic table");
let row_idx = lde_idx & (height - 1);
&self.values.values[row_idx * self.values.width + col_idx]
}
}
pub trait PeriodicEvaluator<F: Field, D: PolynomialSpace<Val = F>> {
fn eval_on_lde(
periodic_table: &[Vec<F>],
trace_domain: &D,
lde_domain: &D,
) -> PeriodicLdeTable<F>;
fn eval_at_point<EF: ExtensionField<F>>(
periodic_table: &[Vec<F>],
trace_domain: &D,
point: EF,
) -> Vec<EF>;
}
impl<F: Field, D: PolynomialSpace<Val = F>> PeriodicEvaluator<F, D> for () {
fn eval_on_lde(
periodic_table: &[Vec<F>],
_trace_domain: &D,
_lde_domain: &D,
) -> PeriodicLdeTable<F> {
assert!(
periodic_table.is_empty(),
"AIR has periodic columns but no PeriodicEvaluator was specified. \
Use prove_with_periodic or verify_with_periodic with TwoAdicPeriodicEvaluator \
or CirclePeriodicEvaluator."
);
PeriodicLdeTable::empty()
}
fn eval_at_point<EF: ExtensionField<F>>(
periodic_table: &[Vec<F>],
_trace_domain: &D,
_point: EF,
) -> Vec<EF> {
assert!(
periodic_table.is_empty(),
"AIR has periodic columns but no PeriodicEvaluator was specified. \
Use prove_with_periodic or verify_with_periodic with TwoAdicPeriodicEvaluator \
or CirclePeriodicEvaluator."
);
Vec::new()
}
}
#[cfg(test)]
mod tests {
#[cfg(debug_assertions)]
#[test]
#[should_panic(expected = "PeriodicLdeTable height must be a power of two")]
fn new_panics_on_non_power_of_two_height() {
use alloc::vec;
use p3_baby_bear::BabyBear;
use p3_field::PrimeCharacteristicRing;
use super::*;
type F = BabyBear;
let (a, b, c) = (F::ONE, F::TWO, F::from_u8(3));
let _ = PeriodicLdeTable::new(RowMajorMatrix::new(vec![a, b, c], 1));
}
}