Skip to content

Commit

Permalink
feat: From<Vec<Registers>>
Browse files Browse the repository at this point in the history
  • Loading branch information
rkdud007 committed Nov 21, 2024
1 parent f17d7a3 commit 985c9d6
Showing 1 changed file with 216 additions and 1 deletion.
217 changes: 216 additions & 1 deletion crates/brainfuck_prover/src/components/processor/table.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use brainfuck_vm::registers::Registers;
use num_traits::Zero;
use stwo_prover::core::fields::m31::BaseField;

/// Represents a single row in the Processor Table.
Expand Down Expand Up @@ -34,6 +35,26 @@ pub struct ProcessorTableRow {
mvi: BaseField,
}

impl ProcessorTableRow {
/// Creates a row for the [`MemoryTable`] which is considered 'dummy'.
///
/// A 'dummy' row, is a row that is not part of the execution trace from the Brainfuck program
/// execution.
/// They are used for padding and filling the `clk` gaps after sorting by `mp`, to enforce the
/// correct sorting.
pub fn new_dummy(clk: BaseField, ip: BaseField) -> Self {
Self {
clk,
ip,
ci: BaseField::zero(),
ni: BaseField::zero(),
mp: BaseField::zero(),
mv: BaseField::zero(),
mvi: BaseField::zero(),
}
}
}

impl From<&Registers> for ProcessorTableRow {
fn from(registers: &Registers) -> Self {
Self {
Expand Down Expand Up @@ -78,13 +99,57 @@ impl ProcessorTable {
pub fn add_row(&mut self, row: ProcessorTableRow) {
self.table.push(row);
}

/// Adds multiple rows to the Processor Table.
///
/// # Arguments
/// * `rows` - A vector of [`ProcessorTableRow`] to add to the table.
///
/// This method extends the `table` vector with the provided rows.
fn add_rows(&mut self, rows: Vec<ProcessorTableRow>) {
self.table.extend(rows);
}

/// Pads the Processor table with dummy rows up to the next power of two length.
///
/// Each dummy row increase clk, preserve ip, set others to zero.
///
/// Does nothing if the table is empty.
fn pad(&mut self) {
if let Some(last_row) = self.table.last().cloned() {
let trace_len = self.table.len();
let padding_offset = (trace_len.next_power_of_two() - trace_len) as u32;
for i in 1..=padding_offset {
// TODO: i think ip should change in padding but trace returning like this
self.add_row(ProcessorTableRow::new_dummy(
last_row.clk + BaseField::from(i),
last_row.ip,
));
}
}
}
}

impl From<Vec<Registers>> for ProcessorTable {
fn from(registers: Vec<Registers>) -> Self {
let mut processor_table = Self::new();

let rows = registers.iter().map(|x| x.into()).collect();
processor_table.add_rows(rows);
processor_table.pad();

processor_table
}
}

#[cfg(test)]
mod tests {
use super::*;
use brainfuck_vm::registers::Registers;
use brainfuck_vm::{
compiler::Compiler, registers::Registers, test_helper::create_test_machine,
};
use num_traits::{One, Zero};
use stwo_prover::core::fields::FieldExpOps;

#[test]
fn test_processor_table_row_from_registers() {
Expand Down Expand Up @@ -179,4 +244,154 @@ mod tests {

assert_eq!(processor_table.table, rows,);
}

#[test]
fn test_processor_table_from_registers_example_program() {
// Create a small program and compile it
let code = "+>,<[>+.<-]";
let mut compiler = Compiler::new(code);
let instructions = compiler.compile();
// Create a machine and execute the program
let (mut machine, _) = create_test_machine(&instructions, &[1]);
let () = machine.execute().expect("Failed to execute machine");

// Get the trace of the executed program
let trace = machine.trace();

// Convert the trace to an `ProcessorTable`
let processor_table: ProcessorTable = trace.into();

// Create the expected `ProcessorTable`
let process_0 = ProcessorTableRow {
clk: BaseField::zero(),
ip: BaseField::zero(),
ci: BaseField::from(43),
ni: BaseField::from(62),
mp: BaseField::zero(),
mv: BaseField::zero(),
mvi: BaseField::zero(),
};

let process_1 = ProcessorTableRow {
clk: BaseField::one(),
ip: BaseField::one(),
ci: BaseField::from(62),
ni: BaseField::from(44),
mp: BaseField::zero(),
mv: BaseField::one(),
mvi: BaseField::one(),
};

let process_2 = ProcessorTableRow {
clk: BaseField::from(2),
ip: BaseField::from(2),
ci: BaseField::from(44),
ni: BaseField::from(60),
mp: BaseField::one(),
mv: BaseField::zero(),
mvi: BaseField::zero(),
};

let process_3 = ProcessorTableRow {
clk: BaseField::from(3),
ip: BaseField::from(3),
ci: BaseField::from(60),
ni: BaseField::from(91),
mp: BaseField::one(),
mv: BaseField::one(),
mvi: BaseField::one(),
};

let process_4 = ProcessorTableRow {
clk: BaseField::from(4),
ip: BaseField::from(4),
ci: BaseField::from(91),
ni: BaseField::from(12),
mp: BaseField::zero(),
mv: BaseField::one(),
mvi: BaseField::one(),
};

let process_5 = ProcessorTableRow {
clk: BaseField::from(5),
ip: BaseField::from(6),
ci: BaseField::from(62),
ni: BaseField::from(43),
mp: BaseField::zero(),
mv: BaseField::one(),
mvi: BaseField::one(),
};

let process_6 = ProcessorTableRow {
clk: BaseField::from(6),
ip: BaseField::from(7),
ci: BaseField::from(43),
ni: BaseField::from(46),
mp: BaseField::one(),
mv: BaseField::one(),
mvi: BaseField::one(),
};

let process_7 = ProcessorTableRow {
clk: BaseField::from(7),
ip: BaseField::from(8),
ci: BaseField::from(46),
ni: BaseField::from(60),
mp: BaseField::one(),
mv: BaseField::from(2),
mvi: BaseField::from(2).inverse(),
};

let process_8 = ProcessorTableRow {
clk: BaseField::from(8),
ip: BaseField::from(9),
ci: BaseField::from(60),
ni: BaseField::from(45),
mp: BaseField::one(),
mv: BaseField::from(2),
mvi: BaseField::from(2).inverse(),
};

let process_9 = ProcessorTableRow {
clk: BaseField::from(9),
ip: BaseField::from(10),
ci: BaseField::from(45),
ni: BaseField::from(93),
mp: BaseField::zero(),
mv: BaseField::one(),
mvi: BaseField::one(),
};

let process_10 = ProcessorTableRow {
clk: BaseField::from(10),
ip: BaseField::from(11),
ci: BaseField::from(93),
ni: BaseField::from(6),
mp: BaseField::zero(),
mv: BaseField::zero(),
mvi: BaseField::zero(),
};

let process_11 = ProcessorTableRow {
clk: BaseField::from(11),
ip: BaseField::from(13),
ci: BaseField::zero(),
ni: BaseField::zero(),
mp: BaseField::zero(),
mv: BaseField::zero(),
mvi: BaseField::zero(),
};

let mut expected_processor_table = ProcessorTable {
table: vec![
process_0, process_1, process_2, process_3, process_4, process_5, process_6,
process_7, process_8, process_9, process_10, process_11,
],
};

expected_processor_table.pad();

// Verify that the processor table is correct
assert_eq!(processor_table, expected_processor_table);
}
}

0 comments on commit 985c9d6

Please sign in to comment.