Skip to content

Commit

Permalink
Evaluaton of fixed columns that are constant outside the first and la…
Browse files Browse the repository at this point in the history
…st row.
  • Loading branch information
chriseth committed Jan 15, 2025
1 parent e4ebab3 commit 3d8e903
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 15 deletions.
31 changes: 29 additions & 2 deletions executor-utils/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use itertools::Itertools;
use powdr_ast::analyzed::Analyzed;
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, BTreeSet};
Expand Down Expand Up @@ -41,6 +42,9 @@ impl<T: FieldElement> WitgenCallback<T> {
#[derive(Serialize, Deserialize)]
pub struct VariablySizedColumn<F> {
column_by_size: BTreeMap<DegreeType, Vec<F>>,
/// If this is Some(x), then all sizes of this column have this value
/// in all rows except the first and the last.
constant_inner_value: Option<F>,
}

#[derive(Debug)]
Expand All @@ -66,23 +70,46 @@ impl<F> VariablySizedColumn<F> {
.get(&size)
.map(|column| column.as_slice())
}

/// If this returns Some(x), then all sizes of this column have this value
/// in all rows except the first and the last.
pub fn has_constant_inner_value(&self) -> &Option<F> {
&self.constant_inner_value
}
}

impl<F> From<Vec<F>> for VariablySizedColumn<F> {
impl<F: PartialEq + Copy> From<Vec<F>> for VariablySizedColumn<F> {
fn from(column: Vec<F>) -> Self {
let constant_inner_value = constant_inner_value(&column);
VariablySizedColumn {
column_by_size: [(column.len() as DegreeType, column)].into_iter().collect(),
constant_inner_value,
}
}
}

impl<F> From<Vec<Vec<F>>> for VariablySizedColumn<F> {
impl<F: PartialEq + Copy> From<Vec<Vec<F>>> for VariablySizedColumn<F> {
fn from(columns: Vec<Vec<F>>) -> Self {
let constant_inner_values = columns
.iter()
.map(|v| constant_inner_value(v))
.collect::<Option<Vec<_>>>();
let constant_inner_value =
constant_inner_values.and_then(|v| v.iter().all_equal_value().ok().cloned());
VariablySizedColumn {
column_by_size: columns
.into_iter()
.map(|column| (column.len() as DegreeType, column))
.collect(),
constant_inner_value,
}
}
}

fn constant_inner_value<F: PartialEq + Copy>(column: &[F]) -> Option<F> {
column[1..column.len() - 1]
.iter()
.all_equal_value()
.ok()
.cloned()
}
42 changes: 30 additions & 12 deletions executor/src/witgen/jit/single_step_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,12 @@ impl<'a, T: FieldElement> SingleStepProcessor<'a, T> {
(id, row_offset)
});
let block_size = 1;
let witgen = WitgenInference::new(self.fixed_data, NoEval, known_variables);

let witgen = WitgenInference::new(self.fixed_data, self, known_variables);

Processor::new(
self.fixed_data,
NoEval,
self,
identities,
block_size,
false,
Expand All @@ -74,16 +75,11 @@ impl<'a, T: FieldElement> SingleStepProcessor<'a, T> {
}
}

#[derive(Clone)]
pub struct NoEval;

impl<T: FieldElement> FixedEvaluator<T> for NoEval {
fn evaluate(&self, _var: &AlgebraicReference, _row_offset: i32) -> Option<T> {
// We can only return something here if the fixed column is constant
// in the region we are considering.
// This might be the case if we know we are not evaluating the first or the last
// row, but this is not yet implemented.
None
/// Evaluator for fixed columns which are constant except for the first and last row.
impl<T: FieldElement> FixedEvaluator<T> for &SingleStepProcessor<'_, T> {
fn evaluate(&self, var: &AlgebraicReference, _row_offset: i32) -> Option<T> {
assert!(var.is_fixed());
self.fixed_data.fixed_cols[&var.poly_id].has_constant_inner_value()
}
}

Expand Down Expand Up @@ -148,6 +144,25 @@ mod test {
);
}

#[test]
fn fib_with_boundary_conditions() {
let input = "
namespace M(256);
col fixed FIRST = [1] + [0]*;
col fixed LAST = [0]* + [1];
let X;
let Y;
FIRST * (X - 1) = 0;
FIRST * (Y - 1) = 0;
(X' - Y) * (1 - LAST) = 0;
(Y' - (X + Y)) * (1 - LAST) = 0;";
let code = generate_single_step(input, "M").unwrap();
assert_eq!(
format_code(&code),
"M::X[1] = M::Y[0];\nM::Y[1] = (M::X[0] + M::Y[0]);"
);
}

#[test]
fn no_progress() {
let input = "namespace M(256); let X; let Y; X' = X;";
Expand Down Expand Up @@ -241,4 +256,7 @@ machine_call(2, [Known(call_var(2, 1, 0)), Known(call_var(2, 1, 1)), Unknown(cal
VM::instr_mul[1] = 1;"
);
}

#[test]
fn eval_fixed_on_inner_rows() {}
}
6 changes: 5 additions & 1 deletion executor/src/witgen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ pub struct FixedColumn<'a, T> {
values: &'a VariablySizedColumn<T>,
}

impl<'a, T> FixedColumn<'a, T> {
impl<'a, T: FieldElement> FixedColumn<'a, T> {
pub fn new(name: &'a str, values: &'a VariablySizedColumn<T>) -> FixedColumn<'a, T> {
let name = name.to_string();
FixedColumn { name, values }
Expand All @@ -589,6 +589,10 @@ impl<'a, T> FixedColumn<'a, T> {
let max_size = self.values.available_sizes().into_iter().max().unwrap() as DegreeType;
self.values(max_size)
}

pub fn has_constant_inner_value(&self) -> Option<T> {
*self.values.has_constant_inner_value()
}
}

#[derive(Debug)]
Expand Down

0 comments on commit 3d8e903

Please sign in to comment.