diff --git a/executor/src/witgen/machines/fixed_lookup_machine.rs b/executor/src/witgen/machines/fixed_lookup_machine.rs index 2e10b0d3c..305e1ca94 100644 --- a/executor/src/witgen/machines/fixed_lookup_machine.rs +++ b/executor/src/witgen/machines/fixed_lookup_machine.rs @@ -164,9 +164,9 @@ impl FixedLookup { _fixed_data: &FixedData, identities: &[&Identity], witness_names: &HashSet<&str>, - ) -> Option> { + ) -> Option { if identities.is_empty() && witness_names.is_empty() { - Some(Box::default()) + Some(Default::default()) } else { None } diff --git a/executor/src/witgen/machines/machine_extractor.rs b/executor/src/witgen/machines/machine_extractor.rs index 5048c29a5..8752789dc 100644 --- a/executor/src/witgen/machines/machine_extractor.rs +++ b/executor/src/witgen/machines/machine_extractor.rs @@ -119,7 +119,7 @@ pub fn split_out_machines<'a, T: FieldElement>( } } ExtractionOutput { - fixed_lookup: *fixed_lookup, + fixed_lookup, machines, base_identities, base_witnesses: remaining_witnesses, diff --git a/executor/src/witgen/mod.rs b/executor/src/witgen/mod.rs index f438cead9..7604862e3 100644 --- a/executor/src/witgen/mod.rs +++ b/executor/src/witgen/mod.rs @@ -46,27 +46,7 @@ where if degree.is_zero() { panic!("Resulting degree is zero. Please ensure that there is at least one non-constant fixed column to set the degree."); } - let witness_cols = ColumnMap::from( - analyzed - .committed_polys_in_source_order() - .iter() - .enumerate() - .map(|(i, (poly, value))| { - if poly.length.is_some() { - unimplemented!("Committed arrays not implemented.") - } - assert_eq!(i as u64, poly.id); - let col = WitnessColumn::new(i, &poly.absolute_name, value); - col - }), - PolynomialType::Committed, - ); - - let fixed_cols = ColumnMap::from( - fixed_col_values.iter().map(|(n, v)| FixedColumn::new(n, v)), - PolynomialType::Constant, - ); - let fixed = FixedData::new(degree, fixed_cols, witness_cols); + let fixed = FixedData::new(analyzed, degree, fixed_col_values); let identities = substitute_constants(&analyzed.identities, &analyzed.constants); let GlobalConstraints { @@ -204,10 +184,30 @@ pub struct FixedData<'a, T> { impl<'a, T: FieldElement> FixedData<'a, T> { pub fn new( + analyzed: &'a Analyzed, degree: DegreeType, - fixed_cols: ColumnMap>, - witness_cols: ColumnMap>, + fixed_col_values: &'a [(&'a str, Vec)], ) -> Self { + let witness_cols = ColumnMap::from( + analyzed + .committed_polys_in_source_order() + .iter() + .enumerate() + .map(|(i, (poly, value))| { + if poly.length.is_some() { + unimplemented!("Committed arrays not implemented.") + } + assert_eq!(i as u64, poly.id); + let col = WitnessColumn::new(i, &poly.absolute_name, value); + col + }), + PolynomialType::Committed, + ); + + let fixed_cols = ColumnMap::from( + fixed_col_values.iter().map(|(n, v)| FixedColumn::new(n, v)), + PolynomialType::Constant, + ); FixedData { degree, fixed_cols, diff --git a/executor/src/witgen/processor.rs b/executor/src/witgen/processor.rs index 45d2f422a..36e913a41 100644 --- a/executor/src/witgen/processor.rs +++ b/executor/src/witgen/processor.rs @@ -126,3 +126,109 @@ impl<'a, T: FieldElement> Processor<'a, T> { } } } + +#[cfg(test)] +mod tests { + use std::collections::BTreeMap; + + use ast::analyzed::PolyID; + use number::{FieldElement, GoldilocksField}; + use pil_analyzer::analyze_string; + + use crate::{ + constant_evaluator::generate, + witgen::{ + identity_processor::IdentityProcessor, machines::FixedLookup, rows::RowFactory, + FixedData, + }, + }; + + use super::Processor; + + fn name_to_poly_id(fixed_data: &FixedData) -> BTreeMap { + let mut name_to_poly_id = BTreeMap::new(); + for (poly_id, col) in fixed_data.witness_cols.iter() { + name_to_poly_id.insert(col.name.clone(), poly_id); + } + for (poly_id, col) in fixed_data.fixed_cols.iter() { + name_to_poly_id.insert(col.name.clone(), poly_id); + } + name_to_poly_id + } + + /// Constructs a processor for a given PIL, then calls a function on it. + fn do_with_processor( + src: &str, + f: impl Fn(&mut Processor, BTreeMap) -> R, + ) -> R { + let analyzed = analyze_string(src); + let (constants, degree) = generate(&analyzed); + let fixed_data = FixedData::new(&analyzed, degree, &constants); + + // No submachines + let mut fixed_lookup = FixedLookup::default(); + let machines = vec![]; + + // No global range constraints + let global_range_constraints = fixed_data.witness_map_with(None); + + let row_factory = RowFactory::new(&fixed_data, global_range_constraints); + let data = vec![row_factory.fresh_row(); fixed_data.degree as usize]; + let identity_processor = IdentityProcessor::new(&fixed_data, &mut fixed_lookup, machines); + let row_offset = 0; + let identities = analyzed.identities.iter().collect(); + + let mut processor = Processor::new( + row_offset, + data, + identity_processor, + identities, + &fixed_data, + row_factory, + ); + + f(&mut processor, name_to_poly_id(&fixed_data)) + } + + fn solve_and_assert(src: &str, asserted_values: &[(usize, &str, u64)]) { + do_with_processor(src, |processor, poly_ids| { + processor.solve().unwrap(); + + // Can't use processor.finish(), because we don't own it... + let data = processor.data.clone(); + + // In case of any error, this will be useful + for (i, row) in data.iter().enumerate() { + println!("{}", row.render(&format!("Row {i}"), true)); + } + + for &(i, name, expected) in asserted_values.iter() { + let poly_id = poly_ids[name]; + let row = &data[i]; + let actual: T = row[&poly_id].value.unwrap_or_default(); + assert_eq!(actual, T::from(expected)); + } + }) + } + + #[test] + fn test_fibonacci() { + let src = r#" + constant %N = 8; + + namespace Fibonacci(%N); + col fixed ISFIRST = [1] + [0]*; + col fixed ISLAST = [0]* + [1]; + col witness x, y; + + // Start with 1, 1 + ISFIRST * (y - 1) = 0; + ISFIRST * (x - 1) = 0; + + (1-ISLAST) * (x' - y) = 0; + (1-ISLAST) * (y' - (x + y)) = 0; + "#; + + solve_and_assert::(src, &[(7, "Fibonacci.y", 34)]); + } +}