Skip to content

Commit

Permalink
intsrument fft-bases with test scaffolding
Browse files Browse the repository at this point in the history
  • Loading branch information
thor314 committed Jan 10, 2024
1 parent 5a888a9 commit 27e6b7f
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 46 deletions.
4 changes: 0 additions & 4 deletions air/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,6 @@ pub trait Air<F: Field> {
None => self.num_columns(),
}
}

// todo(tk): verify ok to drop ths
// protected:
// uint64_t trace_length_;
}

/// Helper NewType for the `get_mask` of the Air.
Expand Down
10 changes: 5 additions & 5 deletions algebra/src/domains/list_of_cosets.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
//! mirror: https://github.com/starkware-libs/stone-prover/blob/00b274b55c82077184be4c0758f7bed18950eaba/src/starkware/algebra/domains/list_of_cosets.h
//! mirror: https://github.com/starkware-libs/stone-prover/blob/00b274b55c82077184be4c0758f7bed18950eaba/src/starkware/algebra/domains/list_of_cosets.cc
use ark_ff::Field;
use fft_utils::FftBases;
use ark_ff::FftField;
use fft_utils::{Base, FftBases};

/// ListOfCosets is a union of cosets of a group. Let G be a multiplicative subgroup of the
/// field of size coset_size, then the instance represents a set which is a union of the
/// cosets s_0 # G, s_1 # G , ... , s_{n_cosets-1} # G (where # is the group opperation).
#[derive(Clone, Debug)]
pub struct ListOfCosets<F: Field> {
pub fft_bases: Box<FftBases<F>>,
pub struct ListOfCosets<F: FftField, B: Base> {
pub fft_bases: Box<FftBases<F, B>>,
pub cosets_offsets: Vec<F>,
pub trace_generator: F,
}

// intentionally unimplemented: group(), get_field(), trace_generator(), cosets_offsets(), bases
impl<F: Field> ListOfCosets<F> {
impl<F: FftField, B: Base> ListOfCosets<F, B> {
/// Constructs an instance with a group of size coset_size and the number of cosets is n_cosets.
/// The cosets offsets are as follows:
///
Expand Down
1 change: 1 addition & 0 deletions fft_utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ edition = "2021"
[dependencies]
utils = { path = "../utils" }
ark-ff = "0.4.2"
ark-std = "0.4.0"
220 changes: 184 additions & 36 deletions fft_utils/src/fft_bases.rs
Original file line number Diff line number Diff line change
@@ -1,64 +1,212 @@
//! mirror: https://github.com/starkware-libs/stone-prover/blob/00b274b55c82077184be4c0758f7bed18950eaba/src/starkware/fft_utils/fft_bases.h
//! todo: need to find differences between DomainT = FftDomain<GroupT>, and my types,
//! ark_ff::FftField
use ark_ff::Field;
use std::marker::PhantomData;

use ark_ff::{FftField, Field};
use utils::assert_on_release;

// TODO(TK 2024-01-09):
// placeholder trait until I find out what Base needs to be
pub trait Base: Clone + std::fmt::Debug {}
pub type DomainT<F> = F;

/// Contains information about FFT/FRI layers. For a domain of size 2^N, there are N layers.
/// Layer i reduces a domain of size 2^(N-i) to a domain of size 2^(N-i-1). This means we have N+1
/// domains (Layer i transform from domain i to domain i+1). The last domain is of size 1, with an
/// empty basis.
#[derive(Debug, Clone)]
// TODO(TK 2024-01-09): maybe Field -> FftField
// avoid the <X>Impl C++ type pattern.
// intentionally unimplemented: get_field()
pub struct FftBases<F: Field> {
// TODO(TK 2024-01-09): C++ implementation is generic over BasesT and GroupT, may need diff api
// avoid the <X>Impl C++ type pattern. We will need an FFT domain over the group, and a Fieldelement
// from the group, which seems... hmm unsure intentionally unimplemented: get_field(), num_layers
#[derive(Debug, Clone)]
pub struct FftBases<F: FftField, B: Base> {
pub num_layers: usize,
pub bases: Vec<DomainT<F>>,
pub bases: Vec<B>,
_todo_f: PhantomData<F>,
}

impl<F: Field> FftBases<F> {
pub fn new(bases: Vec<DomainT<F>>) -> Self {
impl<F: FftField, B: Base> FftBases<F, B> {
pub fn new(bases: Vec<DomainT<B>>) -> Self {
assert_on_release(!bases.is_empty(), "basis must not be empty");
// TODO(TK 2024-01-09): fix lata
// TODO(TK 2024-01-09): fix later
// assert_on_release(!bases.last().basis_size() == 0, "basis must end in an empty domain");

Self { num_layers: bases.len(), bases }
Self { num_layers: bases.len(), bases, _todo_f: PhantomData }
}

/// Returns an FftBasesImpl instance that is derived from the original FftBasesImpl
/// by changing the offsets in all the layers.
/// The offset at layer i is obtained from the offset at layer i-1 using a 2 to 1 mapping.
/// The result is independent of the offset in the original FftBasesImpl instance.
pub fn get_shifted_bases(&self, offset: &F) -> &FftBases<F, B> {
// B(self[0].get_shifted_domain(offset))
todo!()
}

pub fn get_shifted_bases(&self, offset: &F) -> &FftBases<F> { todo!() }
// todo:
// template <typename BasesT, typename GroupT>
// std::tuple<std::unique_ptr<FftBases>, std::vector<FieldElement>>
// FftBasesCommonImpl<BasesT, GroupT>::SplitToCosets(size_t n_log_cosets) const {
// https://github.com/starkware-libs/stone-prover/blob/00b274b55c82077184be4c0758f7bed18950eaba/src/starkware/fft_utils/fft_bases.inl#L27C1-L29C79
pub fn split_to_cosets(&self, n_log_cosets: usize) -> (FftBases<F, B>, Vec<F>) {
assert_on_release(!self.bases.is_empty(), "bases must not be empty");
let domain = self[0].clone();
// let basis: Vec<F> = domain.basis();
// assert_on_release(basis.len() >= n_log_cosets, "too many cosets requested");

pub fn split_to_cosets(&self, n_log_cosets: usize) -> (&FftBases<F>, Vec<F>) { todo!() }
// let (cosets_bases, offsets_domain) = B::split_domain(domain, n_log_cosets);
// let offsets: Vec<F> = offsets_domain.into_iter().collect();
// // prior: std::vector<FieldElement> offsets({offsets_domain.begin(), offsets_domain.end()});
// ASSERT_RELEASE(offsets.len() == usize::pow2(n_log_cosets), "Wrong number of offsets");

// (coset_bases, offsets)
todo!()
}

pub fn apply_basis_transform(&self, point: &F, layer_index: usize) -> F {
// assert_on_release(layer_index < self.num_layers(), "layer index out of range");
// B::apply_basis_transform_tmpl(point, layer_index)
todo!()
}

// TODO(TK 2024-01-09): unergonomic, move to From trait for Base
pub fn base_from_layer(&self, idx: usize) -> B {
assert_on_release(idx < self.bases.len(), "index out of bounds");
// B(self.bases[idx].clone())
todo!()
}

pub fn apply_basis_transform(point: &F, layer_index: usize) -> F { todo!() }
// TODO(TK 2024-01-09): unergonomic, move to From trait for Base
// pub fn from_layer_as_unique(&self, idx: usize) -> Self { Self::new(self.base_from_layer(idx)) }
}

// impl<F: Field> std::ops::Index<usize> for FftBases<F> {
// type Output = FftBase<F>;
impl<F: FftField, B: Base> std::ops::Index<usize> for FftBases<F, B> {
type Output = B;

// fn index(&self, idx: usize) -> &Self::Output { &self.bases[idx] }
// }
fn index(&self, idx: usize) -> &Self::Output { &self.bases[idx] }
}

/// Creates a series of FFT domains.
/// The i'th domain is start_offset^i*<g^i>.
/// The domains are ordered according to the Order paramater.
// TODO(TK 2024-01-09): clarify what this C++ type sigil is
// C++ note: template <
// typename FieldElementT,
// MultiplicativeGroupOrdering Order = MultiplicativeGroupOrdering::kBitReversedOrder>
// friend class FftBasesCommonImpl<
// MultiplicativeFftBases<FieldElementT, Order>, FftMultiplicativeGroup<FieldElementT>>;
// using GroupT = FftMultiplicativeGroup<FieldElementT>;
// using DomainT = FftDomain<GroupT>;
// static const MultiplicativeGroupOrdering kOrder = Order;
#[derive(Debug, Clone)]
pub struct DomainT<F: Field> {
pub domain: FftDomainBase<F>,
pub struct MultiplicativeFftBases<F: Field> {
_field: F,
}
// https://github.com/starkware-libs/stone-prover/blob/00b274b55c82077184be4c0758f7bed18950eaba/src/starkware/fft_utils/fft_bases.h#L165 stopping here until further need

#[derive(Debug, Clone)]
pub struct FftDomainBase<F: Field> {
pub coset_size: F,
pub coset_offset: usize,
pub coset_index: usize,
pub coset_size_log: usize,
pub coset_offset_log: usize,
pub coset_index_log: usize,
pub coset_size_inv: usize,
pub coset_offset_inv: usize,
pub coset_index_inv: usize,
pub coset_size_inv_log: usize,
pub coset_offset_inv_log: usize,
pub coset_index_inv_log: usize,
impl<F: Field> MultiplicativeFftBases<F> {
pub fn new(generator: &F, log_n: usize, start_offset: &F) -> Self {
{
todo!()
// Self {}
}
}

// todo
// pub fn is_natural_order() -> bool { self.order == MultiplicativeGroupOrdering::kNaturalOrder}

// TODO(TK 2024-01-09): domain stuff giving me hell
pub fn is_natural_order(domain: &F) -> bool {
todo!()
// domain.coset_offset == 1 && domain.coset_index == 0
}
}

// todo: temp
#[derive(Debug, Clone)]
pub struct FftBase<F: Field>(F);
// todo: https://github.com/starkware-libs/stone-prover/blob/00b274b55c82077184be4c0758f7bed18950eaba/src/starkware/fft_utils/fft_bases.inl#L42
// impl From<Domain> for MultiplicativeFftBases<F> {
// fn from(domain: Domain) -> Self { Self::from(&domain) }
// }

// mirror: https://github.com/starkware-libs/stone-prover/blob/00b274b55c82077184be4c0758f7bed18950eaba/src/starkware/fft_utils/fft_bases.inl#L21
pub fn apply_dim_one_vanishing_polynomial<F: Field>(point: &F, basis_element: &F) -> F {
*point * (*point + *basis_element)
}

// https://github.com/starkware-libs/stone-prover/blob/00b274b55c82077184be4c0758f7bed18950eaba/src/starkware/fft_utils/fft_bases.inl#L62
pub fn invoke_bases_template_version<F: FftField, B: Base, H, I, O>(
func: H,
bases: &FftBases<F, B>,
) where
H: Fn(I) -> O,
{
todo!()
}

#[cfg(test)]
mod test {
// mirror: https://github.com/starkware-libs/stone-prover/blob/00b274b55c82077184be4c0758f7bed18950eaba/src/starkware/fft_utils/fft_bases_test.cc
// TODO(TK 2024-01-09): complete tests
use super::*;

// TODO(TK 2024-01-09): temp typeholder
#[derive(Debug, Clone)]
struct TestFieldElement {
elem: usize,
// _f: PhantomData<F>
}

// Tests that the domains in Reversered order bases were derived correctly from the domain
// start_offset*<g> where g is an element of order 8.
fn test_reversed_order_multiplicative_bases() {
todo!();
}

// Tests that the domains in Natural Order bases were derived correctly from the domain
// start_offset*<g> where g is an element of order 8.
fn test_natural_order_multiplicative_bases(
g: &TestFieldElement,
start_offset: &TestFieldElement,
bases: &impl Base,
) {
todo!()
}

#[test]
fn fft_bases_test_multiplicative() {
// let mut rng = ark_std::test_rng();
todo!()
}

#[allow(clippy::extra_unused_type_parameters)]
fn test_get_shifted_bases<F>(log_n: usize) {
// let _a = F::one();
// let mut rng = ark_std::test_rng();
todo!()
}

#[test]
fn fft_bases_get_shifted() { test_get_shifted_bases::<TestFieldElement>(4) }

#[test]
fn test_fft_bases_from_layer() {
// let mut rng = ark_std::test_rng();
todo!()
}

// C++ testing with several types:
// using BasesTypes = ::testing::Types<
// MultiplicativeFftBases<TestFieldElement, MultiplicativeGroupOrdering::kBitReversedOrder>,
// MultiplicativeFftBases<TestFieldElement, MultiplicativeGroupOrdering::kNaturalOrder>>;

// template <typename>
// class FftBasesTyped : public ::testing::Test {};

// TYPED_TEST_CASE(FftBasesTyped, BasesTypes);

// https://github.com/starkware-libs/stone-prover/blob/00b274b55c82077184be4c0758f7bed18950eaba/src/starkware/fft_utils/fft_bases_test.cc#L161
// fn test_split<F: Field, B: Base>(domain: B::Domain, n: usize){}

// a couple other things
}
2 changes: 1 addition & 1 deletion fft_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
#![allow(dead_code)]

mod fft_bases;
pub use fft_bases::FftBases;
pub use fft_bases::{Base, FftBases};

0 comments on commit 27e6b7f

Please sign in to comment.