use alloc::vec::Vec;
use miden_air::{
RowIndex,
trace::stack::{H0_COL_IDX, NUM_STACK_HELPER_COLS},
};
use miden_core::{FieldElement, stack::MIN_STACK_DEPTH};
use miden_utils_indexing::IndexVec;
pub trait TraceLen {
fn trace_length(&self) -> usize;
}
impl TraceLen for [IndexVec<RowIndex, Felt>] {
fn trace_length(&self) -> usize {
self[0].len()
}
}
impl TraceLen for [Vec<Felt>] {
fn trace_length(&self) -> usize {
self[0].len()
}
}
use super::{Felt, MAX_TOP_IDX, ONE, STACK_TRACE_WIDTH, ZERO};
use crate::utils::math::batch_inversion;
#[derive(Debug)]
pub struct StackTrace {
stack: [IndexVec<RowIndex, Felt>; MIN_STACK_DEPTH],
helpers: [IndexVec<RowIndex, Felt>; NUM_STACK_HELPER_COLS],
}
impl StackTrace {
pub fn new(
init_values: &[Felt],
init_trace_capacity: usize,
init_depth: usize,
init_overflow_addr: Felt,
) -> Self {
StackTrace {
stack: init_stack_columns(init_trace_capacity, init_values),
helpers: init_helper_columns(init_trace_capacity, init_depth, init_overflow_addr),
}
}
#[inline(always)]
pub fn peek_at(&self, clk: RowIndex) -> Felt {
self.stack[0][clk]
}
#[inline(always)]
pub fn get_stack_value_at(&self, clk: RowIndex, pos: usize) -> Felt {
self.stack[pos][clk]
}
#[inline(always)]
pub fn set_stack_value_at(&mut self, clk: RowIndex, pos: usize, value: Felt) {
self.stack[pos][clk] = value;
}
pub fn copy_stack_state_at(
&mut self,
clk: usize,
start_pos: usize,
stack_depth: Felt,
next_overflow_addr: Felt,
) {
for i in start_pos..MIN_STACK_DEPTH {
self.stack[i][(clk + 1).into()] = self.stack[i][clk.into()];
}
self.set_helpers_at(clk, stack_depth, next_overflow_addr);
}
pub(super) fn stack_shift_left_no_helpers(
&mut self,
clk: RowIndex,
start_pos: usize,
last_value: Felt,
next_overflow_addr: Option<Felt>,
) -> (Felt, Felt) {
let clk = clk.as_usize();
for i in start_pos..=MAX_TOP_IDX {
self.stack[i - 1][(clk + 1).into()] = self.stack[i][clk.into()];
}
self.stack[MAX_TOP_IDX][(clk + 1).into()] = last_value;
if let Some(next_overflow_addr) = next_overflow_addr {
let next_depth = self.helpers[0][clk.into()] - ONE;
(next_depth, next_overflow_addr)
} else {
let next_depth = self.helpers[0][clk.into()];
let next_overflow_addr = self.helpers[1][clk.into()];
(next_depth, next_overflow_addr)
}
}
pub fn stack_shift_right_at(&mut self, clk: RowIndex, start_pos: usize) {
let clk = clk.as_usize();
for i in start_pos..MAX_TOP_IDX {
self.stack[i + 1][(clk + 1).into()] = self.stack[i][clk.into()];
}
let next_depth = self.helpers[0][clk.into()] + ONE;
self.set_helpers_at(clk, next_depth, Felt::from(clk as u32));
}
pub fn ensure_trace_capacity(&mut self, clk: RowIndex) {
let current_capacity = self.stack.trace_length();
if (clk + 1) >= current_capacity {
let new_length = current_capacity * 2;
for column in self.stack.iter_mut().chain(self.helpers.iter_mut()) {
for _ in column.len()..new_length {
column.push(ZERO).expect("trace capacity within u32 limits");
}
}
}
}
pub fn append_state_into(&self, result: &mut Vec<Felt>, clk: RowIndex) {
for column in self.stack.iter() {
result.push(column[clk]);
}
}
pub fn into_array(self) -> [Vec<Felt>; STACK_TRACE_WIDTH] {
let mut trace = Vec::with_capacity(STACK_TRACE_WIDTH);
self.stack.into_iter().for_each(|col| trace.push(col.into_inner()));
self.helpers.into_iter().for_each(|col| trace.push(col.into_inner()));
trace[H0_COL_IDX] = batch_inversion(&trace[H0_COL_IDX]);
trace.try_into().expect("Failed to convert vector to an array")
}
pub(super) fn set_helpers_at(
&mut self,
clk: usize,
stack_depth: Felt,
next_overflow_addr: Felt,
) {
self.helpers[0][(clk + 1).into()] = stack_depth;
self.helpers[1][(clk + 1).into()] = next_overflow_addr;
self.helpers[2][(clk + 1).into()] = stack_depth - Felt::from(MIN_STACK_DEPTH as u32);
}
#[cfg(any(test, feature = "testing"))]
pub fn get_stack_state_at(&self, clk: RowIndex) -> [Felt; MIN_STACK_DEPTH] {
let mut result = [ZERO; MIN_STACK_DEPTH];
for (result, column) in result.iter_mut().zip(self.stack.iter()) {
*result = column[clk];
}
result
}
#[cfg(test)]
pub fn get_helpers_state_at(&self, clk: RowIndex) -> [Felt; NUM_STACK_HELPER_COLS] {
let mut result = [ZERO; NUM_STACK_HELPER_COLS];
for (result, column) in result.iter_mut().zip(self.helpers.iter()) {
*result = column[clk];
}
result
}
}
fn init_stack_columns(
init_trace_capacity: usize,
init_values: &[Felt],
) -> [IndexVec<RowIndex, Felt>; MIN_STACK_DEPTH] {
let mut stack: Vec<IndexVec<RowIndex, Felt>> = Vec::with_capacity(MIN_STACK_DEPTH);
for i in 0..MIN_STACK_DEPTH {
let column = if i < init_values.len() {
let mut column = IndexVec::with_capacity(init_trace_capacity);
column.push(init_values[i]).expect("trace capacity within u32 limits");
for _ in 1..init_trace_capacity {
column.push(Felt::ZERO).expect("trace capacity within u32 limits");
}
column
} else {
let mut column = IndexVec::with_capacity(init_trace_capacity);
for _ in 0..init_trace_capacity {
column.push(Felt::ZERO).expect("trace capacity within u32 limits");
}
column
};
stack.push(column)
}
stack.try_into().expect("Failed to convert vector to an array")
}
fn init_helper_columns(
init_trace_capacity: usize,
init_depth: usize,
init_overflow_addr: Felt,
) -> [IndexVec<RowIndex, Felt>; NUM_STACK_HELPER_COLS] {
let mut b0 = IndexVec::with_capacity(init_trace_capacity);
b0.push(Felt::new(init_depth as u64)).expect("trace capacity within u32 limits");
for _ in 1..init_trace_capacity {
b0.push(Felt::ZERO).expect("trace capacity within u32 limits");
}
let mut b1 = IndexVec::with_capacity(init_trace_capacity);
b1.push(init_overflow_addr).expect("trace capacity within u32 limits");
for _ in 1..init_trace_capacity {
b1.push(Felt::ZERO).expect("trace capacity within u32 limits");
}
let mut h0 = IndexVec::with_capacity(init_trace_capacity);
let h0_value = Felt::try_from((init_depth - MIN_STACK_DEPTH) as u64)
.expect("value is greater than or equal to the field modulus");
h0.push(h0_value).expect("trace capacity within u32 limits");
for _ in 1..init_trace_capacity {
h0.push(Felt::ZERO).expect("trace capacity within u32 limits");
}
[b0, b1, h0]
}