use super::{Felt, FieldElement, Matrix, Vec};
use core::slice;
use vm_core::utils::uninit_vector;
pub struct TraceFragment<'a> {
data: Vec<&'a mut [Felt]>,
}
impl<'a> TraceFragment<'a> {
pub fn new(capacity: usize) -> Self {
TraceFragment {
data: Vec::with_capacity(capacity),
}
}
pub fn width(&self) -> usize {
self.data.len()
}
pub fn len(&self) -> usize {
self.data[0].len()
}
#[inline(always)]
pub fn set(&mut self, row_idx: usize, col_idx: usize, value: Felt) {
self.data[col_idx][row_idx] = value;
}
pub fn columns(&mut self) -> slice::IterMut<'_, &'a mut [Felt]> {
self.data.iter_mut()
}
pub fn push_column_slice(&mut self, column: &'a mut [Felt], len: usize) -> &'a mut [Felt] {
let (column_fragment, rest) = column.split_at_mut(len);
self.data.push(column_fragment);
rest
}
#[cfg(test)]
pub fn trace_to_fragment(trace: &'a mut [Vec<Felt>]) -> Self {
let mut data = Vec::new();
for column in trace.iter_mut() {
data.push(column.as_mut_slice());
}
Self { data }
}
}
pub trait LookupTableRow {
fn to_value<E: FieldElement<BaseField = Felt>>(
&self,
main_trace: &Matrix<Felt>,
rand_values: &[E],
) -> E;
}
pub fn build_lookup_table_row_values<E: FieldElement<BaseField = Felt>, R: LookupTableRow>(
rows: &[R],
main_trace: &Matrix<Felt>,
rand_values: &[E],
) -> (Vec<E>, Vec<E>) {
let mut row_values = unsafe { uninit_vector(rows.len()) };
let mut inv_row_values = unsafe { uninit_vector(rows.len()) };
let mut acc = E::ONE;
for ((row, value), inv_value) in rows
.iter()
.zip(row_values.iter_mut())
.zip(inv_row_values.iter_mut())
{
*inv_value = acc;
*value = row.to_value(main_trace, rand_values);
debug_assert_ne!(*value, E::ZERO, "row value cannot be ZERO");
acc *= *value;
}
acc = acc.inv();
for i in (0..row_values.len()).rev() {
inv_row_values[i] *= acc;
acc *= row_values[i];
}
(row_values, inv_row_values)
}
pub trait AuxColumnBuilder<H: Copy, R: LookupTableRow, U: HintCycle> {
fn get_table_rows(&self) -> &[R];
fn get_table_hints(&self) -> &[(U, H)];
fn get_multiplicand<E: FieldElement<BaseField = Felt>>(
&self,
hint: H,
row_values: &[E],
inv_row_values: &[E],
) -> E;
fn build_aux_column<E>(&self, main_trace: &Matrix<Felt>, alphas: &[E]) -> Vec<E>
where
E: FieldElement<BaseField = Felt>,
{
let (row_values, inv_row_values) = self.build_row_values(main_trace, alphas);
let mut result = unsafe { uninit_vector(main_trace.num_rows()) };
result[0] = self.init_column_value(&row_values);
let mut result_idx = 0_usize;
for (clk, hint) in self.get_table_hints() {
let clk = clk.as_index();
if result_idx < clk {
let last_value = result[result_idx];
result[(result_idx + 1)..=clk].fill(last_value);
}
result_idx = clk + 1;
let multiplicand = self.get_multiplicand(*hint, &row_values, &inv_row_values);
debug_assert_ne!(E::ZERO, multiplicand);
result[result_idx] = result[clk] * multiplicand;
}
let last_value = result[result_idx];
assert_eq!(last_value, self.final_column_value(&row_values));
if result_idx < result.len() - 1 {
result[(result_idx + 1)..].fill(last_value);
}
result
}
fn build_row_values<E>(&self, main_trace: &Matrix<Felt>, alphas: &[E]) -> (Vec<E>, Vec<E>)
where
E: FieldElement<BaseField = Felt>,
{
build_lookup_table_row_values(self.get_table_rows(), main_trace, alphas)
}
fn init_column_value<E: FieldElement<BaseField = Felt>>(&self, _row_values: &[E]) -> E {
E::ONE
}
fn final_column_value<E: FieldElement<BaseField = Felt>>(&self, _row_values: &[E]) -> E {
E::ONE
}
}
pub trait HintCycle {
fn as_index(&self) -> usize;
}
impl HintCycle for u32 {
fn as_index(&self) -> usize {
*self as usize
}
}
impl HintCycle for u64 {
fn as_index(&self) -> usize {
*self as usize
}
}
#[cfg(test)]
use vm_core::{utils::ToElements, Operation};
#[cfg(test)]
pub fn build_span_with_respan_ops() -> (Vec<Operation>, Vec<Felt>) {
let iv = [1, 3, 5, 7, 9, 11, 13, 15, 17].to_elements();
let ops = vec![
Operation::Push(iv[0]),
Operation::Push(iv[1]),
Operation::Push(iv[2]),
Operation::Push(iv[3]),
Operation::Push(iv[4]),
Operation::Push(iv[5]),
Operation::Push(iv[6]),
Operation::Push(iv[7]),
Operation::Push(iv[8]),
Operation::Add,
Operation::Drop,
Operation::Drop,
Operation::Drop,
Operation::Drop,
Operation::Drop,
Operation::Drop,
Operation::Drop,
Operation::Drop,
];
(ops, iv)
}