Merge pull request #524 from powdr-labs/processor-tests

Add unit test to Processor
This commit is contained in:
chriseth
2023-08-28 10:05:47 +02:00
committed by GitHub
4 changed files with 132 additions and 26 deletions

View File

@@ -164,9 +164,9 @@ impl<T: FieldElement> FixedLookup<T> {
_fixed_data: &FixedData<T>,
identities: &[&Identity<T>],
witness_names: &HashSet<&str>,
) -> Option<Box<Self>> {
) -> Option<Self> {
if identities.is_empty() && witness_names.is_empty() {
Some(Box::default())
Some(Default::default())
} else {
None
}

View File

@@ -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,

View File

@@ -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<T>,
degree: DegreeType,
fixed_cols: ColumnMap<FixedColumn<'a, T>>,
witness_cols: ColumnMap<WitnessColumn<'a, T>>,
fixed_col_values: &'a [(&'a str, Vec<T>)],
) -> 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,

View File

@@ -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<T: FieldElement>(fixed_data: &FixedData<T>) -> BTreeMap<String, PolyID> {
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<T: FieldElement, R>(
src: &str,
f: impl Fn(&mut Processor<T>, BTreeMap<String, PolyID>) -> 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<T: FieldElement>(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::<GoldilocksField>(src, &[(7, "Fibonacci.y", 34)]);
}
}