use super::{
super::utils::get_trace_len, Felt, FieldElement, MAX_TOP_IDX, ONE, STACK_TRACE_WIDTH, ZERO,
};
use crate::utils::math::batch_inversion;
use alloc::vec::Vec;
use miden_air::trace::stack::{H0_COL_IDX, NUM_STACK_HELPER_COLS, STACK_TOP_SIZE};
pub struct StackTrace {
stack: [Vec<Felt>; STACK_TOP_SIZE],
helpers: [Vec<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: u32) -> Felt {
self.stack[0][clk as usize]
}
#[inline(always)]
pub fn get_stack_value_at(&self, clk: u32, pos: usize) -> Felt {
self.stack[pos][clk as usize]
}
#[inline(always)]
pub fn set_stack_value_at(&mut self, clk: u32, pos: usize, value: Felt) {
self.stack[pos][clk as usize] = value;
}
pub fn copy_stack_state_at(
&mut self,
clk: u32,
start_pos: usize,
stack_depth: Felt,
next_overflow_addr: Felt,
) {
let clk = clk as usize;
for i in start_pos..STACK_TOP_SIZE {
self.stack[i][clk + 1] = self.stack[i][clk];
}
self.set_helpers_at(clk, stack_depth, next_overflow_addr);
}
pub fn stack_shift_left_at(
&mut self,
clk: u32,
start_pos: usize,
last_value: Felt,
next_overflow_addr: Option<Felt>,
) {
let clk = clk as usize;
for i in start_pos..=MAX_TOP_IDX {
self.stack[i - 1][clk + 1] = self.stack[i][clk];
}
self.stack[MAX_TOP_IDX][clk + 1] = last_value;
if let Some(next_overflow_addr) = next_overflow_addr {
let next_depth = self.helpers[0][clk] - ONE;
self.set_helpers_at(clk, next_depth, next_overflow_addr);
} else {
let next_depth = self.helpers[0][clk];
let next_overflow_addr = self.helpers[1][clk];
self.set_helpers_at(clk, next_depth, next_overflow_addr);
}
}
pub fn stack_shift_right_at(&mut self, clk: u32, start_pos: usize) {
let clk = clk as usize;
for i in start_pos..MAX_TOP_IDX {
self.stack[i + 1][clk + 1] = self.stack[i][clk];
}
let next_depth = self.helpers[0][clk] + ONE;
self.set_helpers_at(clk, next_depth, Felt::from(clk as u32));
}
pub fn ensure_trace_capacity(&mut self, clk: u32) {
let current_capacity = get_trace_len(&self.stack);
if clk + 1 >= current_capacity as u32 {
let new_length = current_capacity * 2;
for column in self.stack.iter_mut().chain(self.helpers.iter_mut()) {
column.resize(new_length, ZERO);
}
}
}
pub fn append_state_into(&self, result: &mut Vec<Felt>, clk: u32) {
for column in self.stack.iter() {
result.push(column[clk as usize]);
}
}
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));
self.helpers.into_iter().for_each(|col| trace.push(col));
trace[H0_COL_IDX] = batch_inversion(&trace[H0_COL_IDX]);
trace.try_into().expect("Failed to convert vector to an array")
}
fn set_helpers_at(&mut self, clk: usize, stack_depth: Felt, next_overflow_addr: Felt) {
self.helpers[0][clk + 1] = stack_depth;
self.helpers[1][clk + 1] = next_overflow_addr;
self.helpers[2][clk + 1] = stack_depth - Felt::from(STACK_TOP_SIZE as u32);
}
#[cfg(any(test, feature = "internals"))]
pub fn get_stack_state_at(&self, clk: u32) -> [Felt; STACK_TOP_SIZE] {
let mut result = [ZERO; STACK_TOP_SIZE];
for (result, column) in result.iter_mut().zip(self.stack.iter()) {
*result = column[clk as usize];
}
result
}
#[cfg(test)]
pub fn get_helpers_state_at(&self, clk: u32) -> [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 as usize];
}
result
}
}
fn init_stack_columns(
init_trace_capacity: usize,
init_values: &[Felt],
) -> [Vec<Felt>; STACK_TOP_SIZE] {
let mut stack: Vec<Vec<Felt>> = Vec::with_capacity(STACK_TOP_SIZE);
for i in 0..STACK_TOP_SIZE {
let mut column = Felt::zeroed_vector(init_trace_capacity);
if i < init_values.len() {
column[0] = init_values[i];
}
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,
) -> [Vec<Felt>; NUM_STACK_HELPER_COLS] {
let mut b0 = Felt::zeroed_vector(init_trace_capacity);
b0[0] = Felt::new(init_depth as u64);
let mut b1 = Felt::zeroed_vector(init_trace_capacity);
b1[0] = init_overflow_addr;
let mut h0 = Felt::zeroed_vector(init_trace_capacity);
h0[0] = Felt::try_from((init_depth - STACK_TOP_SIZE) as u64)
.expect("value is greater than or equal to the field modulus");
[b0, b1, h0]
}