diff --git a/executor/src/witgen/affine_expression.rs b/executor/src/witgen/affine_expression.rs index fcbc7f6297..0d8d2d3580 100644 --- a/executor/src/witgen/affine_expression.rs +++ b/executor/src/witgen/affine_expression.rs @@ -200,7 +200,7 @@ where /// we can deduce the values of all components from the offset part. pub fn solve_with_range_constraints( &self, - known_constraints: &impl RangeConstraintSet, + known_constraints: &dyn RangeConstraintSet, ) -> EvalResult { // Try to solve directly. let value = self.solve()?; @@ -272,7 +272,7 @@ where /// where `dividend` and `divisor` are known and `remainder` is range-constrained to be smaller than `divisor`. fn try_solve_division( &self, - known_constraints: &impl RangeConstraintSet, + known_constraints: &dyn RangeConstraintSet, ) -> Option> { // Detect pattern: `dividend = divisor * quotient + remainder` let (first, second, offset) = match self { @@ -332,7 +332,7 @@ where fn try_transfer_constraints( &self, - known_constraints: &impl RangeConstraintSet, + known_constraints: &dyn RangeConstraintSet, ) -> Option<(K, RangeConstraint)> { // We are looking for X = a * Y + b * Z + ... or -X = a * Y + b * Z + ... // where X is least constrained. @@ -378,7 +378,7 @@ where /// Returns an empty vector if it is not able to solve the equation. fn try_solve_through_constraints( &self, - known_constraints: &impl RangeConstraintSet, + known_constraints: &dyn RangeConstraintSet, ) -> EvalResult { // Get constraints from coefficients and also collect unconstrained indices. let (constraints, unconstrained): (Vec<_>, Vec) = self diff --git a/executor/src/witgen/data_structures/caller_data.rs b/executor/src/witgen/data_structures/caller_data.rs index 545ad8c27a..e0275c1f7a 100644 --- a/executor/src/witgen/data_structures/caller_data.rs +++ b/executor/src/witgen/data_structures/caller_data.rs @@ -3,7 +3,7 @@ use powdr_number::FieldElement; use crate::witgen::{ machines::LookupCell, - processor::{Left, OuterQuery}, + processor::{Arguments, OuterQuery}, EvalError, EvalResult, EvalValue, }; @@ -14,20 +14,20 @@ pub struct CallerData<'a, 'b, T> { /// The raw data of the caller. Unknown values should be ignored. data: Vec, /// The affine expressions of the caller. - left: &'b Left<'a, T>, + arguments: &'b Arguments<'a, T>, } impl<'a, 'b, T: FieldElement> From<&'b OuterQuery<'a, '_, T>> for CallerData<'a, 'b, T> { /// Builds a `CallerData` from an `OuterQuery`. fn from(outer_query: &'b OuterQuery<'a, '_, T>) -> Self { let data = outer_query - .left + .arguments .iter() .map(|l| l.constant_value().unwrap_or_default()) .collect(); Self { data, - left: &outer_query.left, + arguments: &outer_query.arguments, } } } @@ -37,7 +37,7 @@ impl CallerData<'_, '_, T> { pub fn as_lookup_cells(&mut self) -> Vec> { self.data .iter_mut() - .zip_eq(self.left.iter()) + .zip_eq(self.arguments.iter()) .map(|(value, left)| match left.constant_value().is_some() { true => LookupCell::Input(value), false => LookupCell::Output(value), @@ -52,7 +52,7 @@ impl<'a, 'b, T: FieldElement> From> for EvalResult<'a, T> /// Note that this function assumes that the lookup was successful and complete. fn from(data: CallerData<'a, 'b, T>) -> EvalResult<'a, T> { let mut result = EvalValue::complete(vec![]); - for (l, v) in data.left.iter().zip_eq(data.data.iter()) { + for (l, v) in data.arguments.iter().zip_eq(data.data.iter()) { if !l.is_constant() { let evaluated = l.clone() - (*v).into(); match evaluated.solve() { diff --git a/executor/src/witgen/data_structures/mutable_state.rs b/executor/src/witgen/data_structures/mutable_state.rs index 1d2641df3a..f4cbe65bda 100644 --- a/executor/src/witgen/data_structures/mutable_state.rs +++ b/executor/src/witgen/data_structures/mutable_state.rs @@ -7,10 +7,10 @@ use bit_vec::BitVec; use powdr_number::FieldElement; use crate::witgen::{ + global_constraints::RangeConstraintSet, machines::{KnownMachine, LookupCell, Machine}, range_constraints::RangeConstraint, - rows::RowPair, - EvalError, EvalResult, QueryCallback, + AffineExpression, AlgebraicVariable, EvalError, EvalResult, QueryCallback, }; /// The container and access method for machines and the query callback. @@ -61,11 +61,16 @@ impl<'a, T: FieldElement, Q: QueryCallback> MutableState<'a, T, Q> { machine.can_process_call_fully(self, identity_id, known_inputs, range_constraints) } - /// Call the machine responsible for the right-hand-side of an identity given its ID - /// and the row pair of the caller. - pub fn call(&self, identity_id: u64, caller_rows: &RowPair<'_, 'a, T>) -> EvalResult<'a, T> { + /// Call the machine responsible for the right-hand-side of an identity given its ID, + /// the evaluated arguments and the caller's range constraints. + pub fn call( + &self, + identity_id: u64, + arguments: &[AffineExpression, T>], + range_constraints: &dyn RangeConstraintSet, T>, + ) -> EvalResult<'a, T> { self.responsible_machine(identity_id)? - .process_plookup_timed(self, identity_id, caller_rows) + .process_plookup_timed(self, identity_id, arguments, range_constraints) } /// Call the machine responsible for the right-hand-side of an identity given its ID, diff --git a/executor/src/witgen/global_constraints.rs b/executor/src/witgen/global_constraints.rs index f4dd4fef10..f2621cfedb 100644 --- a/executor/src/witgen/global_constraints.rs +++ b/executor/src/witgen/global_constraints.rs @@ -47,25 +47,26 @@ impl<'a, T: FieldElement> RangeConstraintSet, T> } /// A range constraint set that combines two other range constraint sets. -pub struct CombinedRangeConstraintSet<'a, R1, R2, K, T> +pub struct CombinedRangeConstraintSet<'a, R, K, T> where T: FieldElement, - R1: RangeConstraintSet, - R2: RangeConstraintSet, + R: RangeConstraintSet, { - range_constraints1: &'a R1, - range_constraints2: &'a R2, + range_constraints1: &'a dyn RangeConstraintSet, + range_constraints2: &'a R, _marker_k: PhantomData, _marker_t: PhantomData, } -impl<'a, R1, R2, K, T> CombinedRangeConstraintSet<'a, R1, R2, K, T> +impl<'a, R, K, T> CombinedRangeConstraintSet<'a, R, K, T> where T: FieldElement, - R1: RangeConstraintSet, - R2: RangeConstraintSet, + R: RangeConstraintSet, { - pub fn new(range_constraints1: &'a R1, range_constraints2: &'a R2) -> Self { + pub fn new( + range_constraints1: &'a dyn RangeConstraintSet, + range_constraints2: &'a R, + ) -> Self { Self { range_constraints1, range_constraints2, @@ -75,12 +76,11 @@ where } } -impl RangeConstraintSet for CombinedRangeConstraintSet<'_, R1, R2, K, T> +impl RangeConstraintSet for CombinedRangeConstraintSet<'_, R, K, T> where T: FieldElement, K: Copy, - R1: RangeConstraintSet, - R2: RangeConstraintSet, + R: RangeConstraintSet, { fn range_constraint(&self, id: K) -> Option> { match ( diff --git a/executor/src/witgen/identity_processor.rs b/executor/src/witgen/identity_processor.rs index 37c0f7704d..943cc17352 100644 --- a/executor/src/witgen/identity_processor.rs +++ b/executor/src/witgen/identity_processor.rs @@ -75,7 +75,17 @@ impl<'a, 'c, T: FieldElement, Q: QueryCallback> IdentityProcessor<'a, 'c, T, return Ok(status); } - self.mutable_state.call(id, rows) + let left = match left + .expressions + .iter() + .map(|e| rows.evaluate(e)) + .collect::, _>>() + { + Ok(expressions) => expressions, + Err(incomplete_cause) => return Ok(EvalValue::incomplete(incomplete_cause)), + }; + + self.mutable_state.call(id, &left, rows) } /// Handles the lookup that connects the current machine to the calling machine. @@ -102,11 +112,11 @@ impl<'a, 'c, T: FieldElement, Q: QueryCallback> IdentityProcessor<'a, 'c, T, .ok_or(EvalError::Generic("Selector is not 1!".to_string()))?; let range_constraint = - CombinedRangeConstraintSet::new(outer_query.caller_rows, current_rows); + CombinedRangeConstraintSet::new(outer_query.range_constraints, current_rows); let mut updates = EvalValue::complete(vec![]); - for (l, r) in outer_query.left.iter().zip(right.expressions.iter()) { + for (l, r) in outer_query.arguments.iter().zip(right.expressions.iter()) { match current_rows.evaluate(r) { Ok(r) => { let result = (l.clone() - r).solve_with_range_constraints(&range_constraint)?; diff --git a/executor/src/witgen/machines/block_machine.rs b/executor/src/witgen/machines/block_machine.rs index c52fee38ac..3006d23f5a 100644 --- a/executor/src/witgen/machines/block_machine.rs +++ b/executor/src/witgen/machines/block_machine.rs @@ -12,15 +12,17 @@ use crate::witgen::block_processor::BlockProcessor; use crate::witgen::data_structures::caller_data::CallerData; use crate::witgen::data_structures::finalizable_data::FinalizableData; use crate::witgen::data_structures::mutable_state::MutableState; +use crate::witgen::global_constraints::RangeConstraintSet; use crate::witgen::jit::function_cache::FunctionCache; use crate::witgen::jit::witgen_inference::CanProcessCall; use crate::witgen::processor::{OuterQuery, Processor, SolverState}; use crate::witgen::range_constraints::RangeConstraint; -use crate::witgen::rows::{Row, RowIndex, RowPair}; +use crate::witgen::rows::{Row, RowIndex}; use crate::witgen::sequence_iterator::{ DefaultSequenceIterator, ProcessingSequenceCache, ProcessingSequenceIterator, }; use crate::witgen::util::try_to_simple_poly; +use crate::witgen::AffineExpression; use crate::witgen::{machines::Machine, EvalError, EvalValue, IncompleteCause, QueryCallback}; use bit_vec::BitVec; use powdr_ast::analyzed::{DegreeRange, PolyID, PolynomialType}; @@ -202,10 +204,12 @@ impl<'a, T: FieldElement> Machine<'a, T> for BlockMachine<'a, T> { &mut self, mutable_state: &'b MutableState<'a, T, Q>, identity_id: u64, - caller_rows: &'b RowPair<'b, 'a, T>, + arguments: &[AffineExpression, T>], + range_constraints: &dyn RangeConstraintSet, T>, ) -> EvalResult<'a, T> { let previous_len = self.data.len(); - let result = self.process_plookup_internal(mutable_state, identity_id, caller_rows); + let result = + self.process_plookup_internal(mutable_state, identity_id, arguments, range_constraints); if let Ok(assignments) = &result { if !assignments.is_complete() { // rollback the changes. @@ -406,22 +410,26 @@ impl<'a, T: FieldElement> BlockMachine<'a, T> { RowIndex::from_i64(self.rows() as i64 - 1, self.degree) } - fn process_plookup_internal<'b, Q: QueryCallback>( + fn process_plookup_internal>( &mut self, mutable_state: &MutableState<'a, T, Q>, identity_id: u64, - caller_rows: &'b RowPair<'b, 'a, T>, + arguments: &[AffineExpression, T>], + range_constraints: &dyn RangeConstraintSet, T>, ) -> EvalResult<'a, T> { - let outer_query = - match OuterQuery::try_new(caller_rows, self.parts.connections[&identity_id]) { - Ok(outer_query) => outer_query, - Err(incomplete_cause) => return Ok(EvalValue::incomplete(incomplete_cause)), - }; + let outer_query = match OuterQuery::try_new( + arguments, + range_constraints, + self.parts.connections[&identity_id], + ) { + Ok(outer_query) => outer_query, + Err(incomplete_cause) => return Ok(EvalValue::incomplete(incomplete_cause)), + }; log::trace!("Start processing block machine '{}'", self.name()); log::trace!("Left values of lookup:"); if log::log_enabled!(log::Level::Trace) { - for l in &outer_query.left { + for l in &outer_query.arguments { log::trace!(" {}", l); } } @@ -430,7 +438,11 @@ impl<'a, T: FieldElement> BlockMachine<'a, T> { return Err(EvalError::RowsExhausted(self.name.clone())); } - let known_inputs = outer_query.left.iter().map(|e| e.is_constant()).collect(); + let known_inputs = outer_query + .arguments + .iter() + .map(|e| e.is_constant()) + .collect(); if self .function_cache .compile_cached(mutable_state, identity_id, &known_inputs) @@ -445,7 +457,7 @@ impl<'a, T: FieldElement> BlockMachine<'a, T> { // TODO this assumes we are always using the same lookup for this machine. let mut sequence_iterator = self .processing_sequence_cache - .get_processing_sequence(&outer_query.left); + .get_processing_sequence(&outer_query.arguments); if !sequence_iterator.has_steps() { // Shortcut, no need to do anything. @@ -477,7 +489,7 @@ impl<'a, T: FieldElement> BlockMachine<'a, T> { // We solved the query, so report it to the cache. self.processing_sequence_cache - .report_processing_sequence(&outer_query.left, sequence_iterator); + .report_processing_sequence(&outer_query.arguments, sequence_iterator); Ok(updates) } ProcessResult::Incomplete(updates) => { @@ -486,7 +498,7 @@ impl<'a, T: FieldElement> BlockMachine<'a, T> { self.name() ); self.processing_sequence_cache - .report_incomplete(&outer_query.left); + .report_incomplete(&outer_query.arguments); Ok(updates) } } diff --git a/executor/src/witgen/machines/double_sorted_witness_machine_16.rs b/executor/src/witgen/machines/double_sorted_witness_machine_16.rs index 79f305da60..01b7f1787a 100644 --- a/executor/src/witgen/machines/double_sorted_witness_machine_16.rs +++ b/executor/src/witgen/machines/double_sorted_witness_machine_16.rs @@ -5,10 +5,12 @@ use itertools::Itertools; use super::{ConnectionKind, LookupCell, Machine, MachineParts}; use crate::witgen::data_structures::mutable_state::MutableState; +use crate::witgen::global_constraints::RangeConstraintSet; use crate::witgen::machines::compute_size_and_log; -use crate::witgen::rows::RowPair; use crate::witgen::util::try_to_simple_poly; -use crate::witgen::{EvalError, EvalResult, FixedData, QueryCallback}; +use crate::witgen::{ + AffineExpression, AlgebraicVariable, EvalError, EvalResult, FixedData, QueryCallback, +}; use crate::witgen::{EvalValue, IncompleteCause}; use powdr_number::{DegreeType, FieldElement, LargeInt}; @@ -234,9 +236,10 @@ impl<'a, T: FieldElement> Machine<'a, T> for DoubleSortedWitnesses16<'a, T> { &mut self, _mutable_state: &MutableState<'a, T, Q>, identity_id: u64, - caller_rows: &RowPair<'_, 'a, T>, + arguments: &[AffineExpression, T>], + range_constraints: &dyn RangeConstraintSet, T>, ) -> EvalResult<'a, T> { - self.process_plookup_internal(identity_id, caller_rows) + self.process_plookup_internal(identity_id, arguments, range_constraints) } fn take_witness_col_values<'b, Q: QueryCallback>( @@ -410,7 +413,8 @@ impl<'a, T: FieldElement> DoubleSortedWitnesses16<'a, T> { pub fn process_plookup_internal( &mut self, identity_id: u64, - caller_rows: &RowPair<'_, 'a, T>, + arguments: &[AffineExpression, T>], + range_constraints: &dyn RangeConstraintSet, T>, ) -> EvalResult<'a, T> { // We blindly assume the lookup is of the form // OP { operation_id, ADDR_high, ADDR_low, STEP, X_high, X_low } is @@ -420,14 +424,7 @@ impl<'a, T: FieldElement> DoubleSortedWitnesses16<'a, T> { // - operation_id == 1: Write // - operation_id == 2: Bootloader write - let args = self.parts.connections[&identity_id] - .left - .expressions - .iter() - .map(|e| caller_rows.evaluate(e).unwrap()) - .collect::>(); - - let operation_id = match args[0].constant_value() { + let operation_id = match arguments[0].constant_value() { Some(v) => v, None => { return Ok(EvalValue::incomplete( @@ -441,7 +438,7 @@ impl<'a, T: FieldElement> DoubleSortedWitnesses16<'a, T> { let is_normal_write = operation_id == T::from(OPERATION_ID_WRITE); let is_bootloader_write = operation_id == T::from(OPERATION_ID_BOOTLOADER_WRITE); let is_write = is_bootloader_write || is_normal_write; - let addr = match (args[1].constant_value(), args[2].constant_value()) { + let addr = match (arguments[1].constant_value(), arguments[2].constant_value()) { (Some(high), Some(low)) => Word32(high, low), _ => { return Ok(EvalValue::incomplete( @@ -460,13 +457,13 @@ impl<'a, T: FieldElement> DoubleSortedWitnesses16<'a, T> { self.is_initialized.insert(addr, true); } - let step = args[3] + let step = arguments[3] .constant_value() - .ok_or_else(|| format!("Step must be known but is: {}", args[3]))?; + .ok_or_else(|| format!("Step must be known but is: {}", arguments[3]))?; let step_word = Word32::from(step.to_degree()); - let value1_expr = &args[4]; - let value2_expr = &args[5]; + let value1_expr = &arguments[4]; + let value2_expr = &arguments[5]; log::trace!( "Query addr=0x{:x}, step={step}, write: {is_write}, value: ({} {})", @@ -521,10 +518,10 @@ impl<'a, T: FieldElement> DoubleSortedWitnesses16<'a, T> { let value_high_fe: T = value_high.into(); let ass = (value1_expr.clone() - value_high_fe.into()) - .solve_with_range_constraints(caller_rows)?; + .solve_with_range_constraints(range_constraints)?; assignments.combine(ass); let ass2 = (value2_expr.clone() - value_low_fe.into()) - .solve_with_range_constraints(caller_rows)?; + .solve_with_range_constraints(range_constraints)?; assignments.combine(ass2); self.trace .insert( diff --git a/executor/src/witgen/machines/double_sorted_witness_machine_32.rs b/executor/src/witgen/machines/double_sorted_witness_machine_32.rs index 5c1409404f..6a56e68eb0 100644 --- a/executor/src/witgen/machines/double_sorted_witness_machine_32.rs +++ b/executor/src/witgen/machines/double_sorted_witness_machine_32.rs @@ -7,13 +7,16 @@ use itertools::Itertools; use super::{LookupCell, Machine, MachineParts}; use crate::witgen::data_structures::caller_data::CallerData; use crate::witgen::data_structures::mutable_state::MutableState; +use crate::witgen::global_constraints::RangeConstraintSet; use crate::witgen::jit::witgen_inference::CanProcessCall; use crate::witgen::machines::compute_size_and_log; use crate::witgen::processor::OuterQuery; use crate::witgen::range_constraints::RangeConstraint; -use crate::witgen::rows::RowPair; use crate::witgen::util::try_to_simple_poly; -use crate::witgen::{EvalError, EvalResult, EvalValue, FixedData, IncompleteCause, QueryCallback}; +use crate::witgen::{ + AffineExpression, AlgebraicVariable, EvalError, EvalResult, EvalValue, FixedData, + IncompleteCause, QueryCallback, +}; use powdr_number::{DegreeType, FieldElement, LargeInt}; @@ -240,10 +243,11 @@ impl<'a, T: FieldElement> Machine<'a, T> for DoubleSortedWitnesses32<'a, T> { &mut self, mutable_state: &MutableState<'a, T, Q>, identity_id: u64, - caller_rows: &RowPair<'_, 'a, T>, + arguments: &[AffineExpression, T>], + range_constraints: &dyn RangeConstraintSet, T>, ) -> EvalResult<'a, T> { let connection = self.parts.connections[&identity_id]; - let outer_query = match OuterQuery::try_new(caller_rows, connection) { + let outer_query = match OuterQuery::try_new(arguments, range_constraints, connection) { Ok(outer_query) => outer_query, Err(incomplete_cause) => return Ok(EvalValue::incomplete(incomplete_cause)), }; diff --git a/executor/src/witgen/machines/dynamic_machine.rs b/executor/src/witgen/machines/dynamic_machine.rs index c70937003f..68d34a265b 100644 --- a/executor/src/witgen/machines/dynamic_machine.rs +++ b/executor/src/witgen/machines/dynamic_machine.rs @@ -5,13 +5,14 @@ use std::collections::{BTreeMap, HashMap}; use crate::witgen::block_processor::BlockProcessor; use crate::witgen::data_structures::finalizable_data::FinalizableData; use crate::witgen::data_structures::mutable_state::MutableState; +use crate::witgen::global_constraints::RangeConstraintSet; use crate::witgen::machines::{Machine, MachineParts}; use crate::witgen::processor::{OuterQuery, SolverState}; -use crate::witgen::rows::{Row, RowIndex, RowPair}; +use crate::witgen::rows::{Row, RowIndex}; use crate::witgen::sequence_iterator::{DefaultSequenceIterator, ProcessingSequenceIterator}; use crate::witgen::vm_processor::VmProcessor; use crate::witgen::{ - AlgebraicVariable, EvalError, EvalResult, EvalValue, FixedData, QueryCallback, + AffineExpression, AlgebraicVariable, EvalError, EvalResult, EvalValue, FixedData, QueryCallback, }; use super::LookupCell; @@ -64,17 +65,23 @@ impl<'a, T: FieldElement> Machine<'a, T> for DynamicMachine<'a, T> { &mut self, mutable_state: &MutableState<'a, T, Q>, identity_id: u64, - caller_rows: &'b RowPair<'b, 'a, T>, + arguments: &[AffineExpression, T>], + range_constraints: &dyn RangeConstraintSet, T>, ) -> EvalResult<'a, T> { let identity = *self.parts.connections.get(&identity_id).unwrap(); - let outer_query = match OuterQuery::try_new(caller_rows, identity) { + let outer_query = match OuterQuery::try_new(arguments, range_constraints, identity) { Ok(outer_query) => outer_query, Err(incomplete_cause) => return Ok(EvalValue::incomplete(incomplete_cause)), }; log::trace!("Start processing secondary VM '{}'", self.name()); log::trace!("Arguments:"); - for (r, l) in identity.right.expressions.iter().zip(&outer_query.left) { + for (r, l) in identity + .right + .expressions + .iter() + .zip(&outer_query.arguments) + { log::trace!(" {r} = {l}"); } diff --git a/executor/src/witgen/machines/fixed_lookup_machine.rs b/executor/src/witgen/machines/fixed_lookup_machine.rs index a4ca37ace8..9e983744af 100644 --- a/executor/src/witgen/machines/fixed_lookup_machine.rs +++ b/executor/src/witgen/machines/fixed_lookup_machine.rs @@ -14,7 +14,6 @@ use crate::witgen::global_constraints::{GlobalConstraints, RangeConstraintSet}; use crate::witgen::jit::witgen_inference::CanProcessCall; use crate::witgen::processor::OuterQuery; use crate::witgen::range_constraints::RangeConstraint; -use crate::witgen::rows::RowPair; use crate::witgen::util::try_to_simple_poly; use crate::witgen::{EvalError, EvalValue, IncompleteCause, QueryCallback}; use crate::witgen::{EvalResult, FixedData}; @@ -231,17 +230,17 @@ impl<'a, T: FieldElement> FixedLookup<'a, T> { &mut self, mutable_state: &MutableState<'a, T, Q>, identity_id: u64, - rows: &RowPair<'_, 'a, T>, outer_query: OuterQuery<'a, '_, T>, ) -> EvalResult<'a, T> { let right = self.connections[&identity_id].right; - if outer_query.left.len() == 1 && !outer_query.left.first().unwrap().is_constant() { + if outer_query.arguments.len() == 1 && !outer_query.arguments.first().unwrap().is_constant() + { if let Some(column_reference) = try_to_simple_poly(&right.expressions[0]) { // Lookup of the form "c $ [ X ] in [ B ]". Might be a conditional range check. return self.process_range_check( - rows, - outer_query.left.first().unwrap(), + outer_query.range_constraints, + outer_query.arguments.first().unwrap(), AlgebraicVariable::Column(column_reference), ); } @@ -262,7 +261,7 @@ impl<'a, T: FieldElement> FixedLookup<'a, T> { fn process_range_check( &self, - rows: &RowPair<'_, '_, T>, + range_constraints: &dyn RangeConstraintSet, T>, lhs: &AffineExpression, T>, rhs: AlgebraicVariable<'a>, ) -> EvalResult<'a, T> { @@ -270,7 +269,7 @@ impl<'a, T: FieldElement> FixedLookup<'a, T> { // from the rhs to the lhs. let equation = lhs.clone() - AffineExpression::from_variable_id(rhs); let range_constraints = UnifiedRangeConstraints { - witness_constraints: rows, + witness_constraints: range_constraints, global_constraints: &self.global_constraints, }; let updates = equation.solve_with_range_constraints(&range_constraints)?; @@ -388,15 +387,16 @@ impl<'a, T: FieldElement> Machine<'a, T> for FixedLookup<'a, T> { &mut self, mutable_state: &MutableState<'a, T, Q>, identity_id: u64, - caller_rows: &RowPair<'_, 'a, T>, + arguments: &[AffineExpression, T>], + range_constraints: &dyn RangeConstraintSet, T>, ) -> EvalResult<'a, T> { let identity = self.connections[&identity_id]; - let outer_query = match OuterQuery::try_new(caller_rows, identity) { + let outer_query = match OuterQuery::try_new(arguments, range_constraints, identity) { Ok(outer_query) => outer_query, Err(incomplete_cause) => return Ok(EvalValue::incomplete(incomplete_cause)), }; - self.process_plookup_internal(mutable_state, identity_id, caller_rows, outer_query) + self.process_plookup_internal(mutable_state, identity_id, outer_query) } fn process_lookup_direct<'c, Q: QueryCallback>( @@ -482,12 +482,12 @@ impl<'a, T: FieldElement> Machine<'a, T> for FixedLookup<'a, T> { /// This is useful in order to transfer range constraints from fixed columns to /// witness columns (see [FixedLookup::process_range_check]). pub struct UnifiedRangeConstraints<'a, 'b, T: FieldElement> { - witness_constraints: &'b RowPair<'b, 'a, T>, + witness_constraints: &'b dyn RangeConstraintSet, T>, global_constraints: &'b GlobalConstraints, } impl<'a, T: FieldElement> RangeConstraintSet, T> - for UnifiedRangeConstraints<'_, '_, T> + for UnifiedRangeConstraints<'a, '_, T> { fn range_constraint(&self, var: AlgebraicVariable<'a>) -> Option> { let poly = match var { diff --git a/executor/src/witgen/machines/mod.rs b/executor/src/witgen/machines/mod.rs index 9617a6f5e6..f01c0fe125 100644 --- a/executor/src/witgen/machines/mod.rs +++ b/executor/src/witgen/machines/mod.rs @@ -20,10 +20,10 @@ use self::sorted_witness_machine::SortedWitnesses; use self::write_once_memory::WriteOnceMemory; use super::data_structures::identity::{BusReceive, Identity}; +use super::global_constraints::RangeConstraintSet; use super::jit::witgen_inference::CanProcessCall; use super::range_constraints::RangeConstraint; -use super::rows::RowPair; -use super::{EvalError, EvalResult, FixedData, QueryCallback}; +use super::{AffineExpression, AlgebraicVariable, EvalError, EvalResult, FixedData, QueryCallback}; mod block_machine; mod double_sorted_witness_machine_16; @@ -79,10 +79,11 @@ pub trait Machine<'a, T: FieldElement>: Send + Sync { &mut self, mutable_state: &'b MutableState<'a, T, Q>, identity_id: u64, - caller_rows: &'b RowPair<'b, 'a, T>, + arguments: &[AffineExpression, T>], + range_constraints: &dyn RangeConstraintSet, T>, ) -> EvalResult<'a, T> { record_start(self.name()); - let result = self.process_plookup(mutable_state, identity_id, caller_rows); + let result = self.process_plookup(mutable_state, identity_id, arguments, range_constraints); record_end(self.name()); result } @@ -105,12 +106,13 @@ pub trait Machine<'a, T: FieldElement>: Send + Sync { /// Processes a connection of a given ID (which must be known to the callee). /// Returns an error if the query leads to a constraint failure. - /// Otherwise, it computes any updates to the caller row pair and returns them. + /// Otherwise, it computes any updates to the variables in the arguments and returns them. fn process_plookup<'b, Q: QueryCallback>( &mut self, mutable_state: &'b MutableState<'a, T, Q>, identity_id: u64, - caller_rows: &'b RowPair<'b, 'a, T>, + arguments: &[AffineExpression, T>], + range_constraints: &dyn RangeConstraintSet, T>, ) -> EvalResult<'a, T>; /// Process a connection of a given ID (which must be known to the callee). @@ -209,9 +211,10 @@ impl<'a, T: FieldElement> Machine<'a, T> for KnownMachine<'a, T> { &mut self, mutable_state: &'b MutableState<'a, T, Q>, identity_id: u64, - caller_rows: &'b RowPair<'b, 'a, T>, + arguments: &[AffineExpression, T>], + range_constraints: &dyn RangeConstraintSet, T>, ) -> EvalResult<'a, T> { - match_variant!(self, m => m.process_plookup(mutable_state, identity_id, caller_rows)) + match_variant!(self, m => m.process_plookup(mutable_state, identity_id, arguments, range_constraints)) } fn process_lookup_direct<'b, 'c, Q: QueryCallback>( diff --git a/executor/src/witgen/machines/second_stage_machine.rs b/executor/src/witgen/machines/second_stage_machine.rs index f51af11b5c..360308fa4e 100644 --- a/executor/src/witgen/machines/second_stage_machine.rs +++ b/executor/src/witgen/machines/second_stage_machine.rs @@ -6,12 +6,15 @@ use crate::witgen::block_processor::BlockProcessor; use crate::witgen::data_structures::finalizable_data::FinalizableData; use crate::witgen::data_structures::identity::Identity; use crate::witgen::data_structures::mutable_state::MutableState; +use crate::witgen::global_constraints::RangeConstraintSet; use crate::witgen::machines::{Machine, MachineParts}; use crate::witgen::processor::SolverState; -use crate::witgen::rows::{Row, RowIndex, RowPair}; +use crate::witgen::rows::{Row, RowIndex}; use crate::witgen::sequence_iterator::{DefaultSequenceIterator, ProcessingSequenceIterator}; use crate::witgen::vm_processor::VmProcessor; -use crate::witgen::{EvalError, EvalResult, FixedData, QueryCallback}; +use crate::witgen::{ + AffineExpression, AlgebraicVariable, EvalError, EvalResult, FixedData, QueryCallback, +}; use super::LookupCell; @@ -55,7 +58,8 @@ impl<'a, T: FieldElement> Machine<'a, T> for SecondStageMachine<'a, T> { &mut self, _mutable_state: &MutableState<'a, T, Q>, _identity_id: u64, - _caller_rows: &'b RowPair<'b, 'a, T>, + _arguments: &[AffineExpression, T>], + _range_constraints: &dyn RangeConstraintSet, T>, ) -> EvalResult<'a, T> { panic!("SecondStageMachine can't be called by other machines!") } diff --git a/executor/src/witgen/machines/sorted_witness_machine.rs b/executor/src/witgen/machines/sorted_witness_machine.rs index dfc95b858e..f2498ee795 100644 --- a/executor/src/witgen/machines/sorted_witness_machine.rs +++ b/executor/src/witgen/machines/sorted_witness_machine.rs @@ -1,7 +1,7 @@ use std::collections::{BTreeMap, HashMap}; use super::super::affine_expression::AffineExpression; -use super::{Connection, EvalResult, FixedData, LookupCell}; +use super::{EvalResult, FixedData, LookupCell}; use super::{Machine, MachineParts}; use crate::witgen::affine_expression::AlgebraicVariable; use crate::witgen::data_structures::identity::Identity; @@ -9,7 +9,7 @@ use crate::witgen::data_structures::mutable_state::MutableState; use crate::witgen::evaluators::fixed_evaluator::FixedEvaluator; use crate::witgen::evaluators::partial_expression_evaluator::PartialExpressionEvaluator; use crate::witgen::evaluators::symbolic_evaluator::SymbolicEvaluator; -use crate::witgen::rows::RowPair; +use crate::witgen::global_constraints::RangeConstraintSet; use crate::witgen::{EvalError, EvalValue, IncompleteCause, QueryCallback}; use itertools::Itertools; use num_traits::One; @@ -26,7 +26,6 @@ use powdr_number::{DegreeType, FieldElement}; pub struct SortedWitnesses<'a, T: FieldElement> { degree: DegreeType, rhs_references: BTreeMap>, - connections: BTreeMap>, key_col: PolyID, /// Position of the witness columns in the data. witness_positions: HashMap, @@ -99,7 +98,6 @@ impl<'a, T: FieldElement> SortedWitnesses<'a, T> { Some(SortedWitnesses { degree, rhs_references, - connections: parts.connections.clone(), name, key_col, witness_positions, @@ -222,9 +220,10 @@ impl<'a, T: FieldElement> Machine<'a, T> for SortedWitnesses<'a, T> { &mut self, _mutable_state: &MutableState<'a, T, Q>, identity_id: u64, - caller_rows: &RowPair<'_, 'a, T>, + arguments: &[AffineExpression, T>], + _range_constraints: &dyn RangeConstraintSet, T>, ) -> EvalResult<'a, T> { - self.process_plookup_internal(identity_id, caller_rows) + self.process_plookup_internal(identity_id, arguments) } fn take_witness_col_values<'b, Q: QueryCallback>( @@ -262,21 +261,15 @@ impl<'a, T: FieldElement> SortedWitnesses<'a, T> { fn process_plookup_internal( &mut self, identity_id: u64, - caller_rows: &RowPair<'_, 'a, T>, + arguments: &[AffineExpression, T>], ) -> EvalResult<'a, T> { - let left = self.connections[&identity_id] - .left - .expressions - .iter() - .map(|e| caller_rows.evaluate(e).unwrap()) - .collect::>(); let rhs = self.rhs_references.get(&identity_id).unwrap(); let key_index = rhs.iter().position(|&x| x.poly_id == self.key_col).unwrap(); - let key_value = left[key_index].constant_value().ok_or_else(|| { + let key_value = arguments[key_index].constant_value().ok_or_else(|| { format!( "Value of unique key must be known: {} = {}", - left[key_index], rhs[key_index] + arguments[key_index], rhs[key_index] ) })?; @@ -285,7 +278,7 @@ impl<'a, T: FieldElement> SortedWitnesses<'a, T> { .data .entry(key_value) .or_insert_with(|| vec![None; self.witness_positions.len()]); - for (l, &r) in left.iter().zip(rhs.iter()).skip(1) { + for (l, &r) in arguments.iter().zip(rhs.iter()).skip(1) { let stored_value = &mut stored_values[self.witness_positions[&r.poly_id]]; match stored_value { // There is a stored value diff --git a/executor/src/witgen/machines/write_once_memory.rs b/executor/src/witgen/machines/write_once_memory.rs index ff34fb949a..c26460ac23 100644 --- a/executor/src/witgen/machines/write_once_memory.rs +++ b/executor/src/witgen/machines/write_once_memory.rs @@ -7,10 +7,12 @@ use powdr_ast::analyzed::{PolyID, PolynomialType}; use powdr_number::{DegreeType, FieldElement}; use crate::witgen::data_structures::mutable_state::MutableState; +use crate::witgen::global_constraints::RangeConstraintSet; use crate::witgen::{ - rows::RowPair, util::try_to_simple_poly, EvalError, EvalResult, EvalValue, FixedData, - IncompleteCause, QueryCallback, + util::try_to_simple_poly, EvalError, EvalResult, EvalValue, FixedData, IncompleteCause, + QueryCallback, }; +use crate::witgen::{AffineExpression, AlgebraicVariable}; use super::{Connection, LookupCell, Machine, MachineParts}; @@ -134,16 +136,10 @@ impl<'a, T: FieldElement> WriteOnceMemory<'a, T> { fn process_plookup_internal( &mut self, identity_id: u64, - caller_rows: &RowPair<'_, 'a, T>, + arguments: &[AffineExpression, T>], ) -> EvalResult<'a, T> { let identity = self.connections[&identity_id]; - let args = identity - .left - .expressions - .iter() - .map(|e| caller_rows.evaluate(e).unwrap()) - .collect::>(); - let (key_expressions, value_expressions): (Vec<_>, Vec<_>) = args + let (key_expressions, value_expressions): (Vec<_>, Vec<_>) = arguments .iter() .zip(identity.right.expressions.iter()) .partition(|(_, r)| { @@ -252,9 +248,10 @@ impl<'a, T: FieldElement> Machine<'a, T> for WriteOnceMemory<'a, T> { &mut self, _mutable_state: &'b MutableState<'a, T, Q>, identity_id: u64, - caller_rows: &RowPair<'_, 'a, T>, + arguments: &[AffineExpression, T>], + _range_constraints: &dyn RangeConstraintSet, T>, ) -> EvalResult<'a, T> { - self.process_plookup_internal(identity_id, caller_rows) + self.process_plookup_internal(identity_id, arguments) } fn take_witness_col_values<'b, Q: QueryCallback>( diff --git a/executor/src/witgen/processor.rs b/executor/src/witgen/processor.rs index 58383e6eaa..00c742425d 100644 --- a/executor/src/witgen/processor.rs +++ b/executor/src/witgen/processor.rs @@ -12,6 +12,7 @@ use crate::witgen::data_structures::mutable_state::MutableState; use crate::witgen::{query_processor::QueryProcessor, util::try_to_simple_poly, Constraint}; use super::data_structures::identity::Identity; +use super::global_constraints::RangeConstraintSet; use super::machines::{Connection, MachineParts}; use super::FixedData; use super::{ @@ -25,7 +26,7 @@ use super::{ Constraints, EvalError, EvalValue, IncompleteCause, QueryCallback, }; -pub type Left<'a, T> = Vec, T>>; +pub type Arguments<'a, T> = Vec, T>>; /// The data mutated by the processor pub(crate) struct SolverState<'a, T: FieldElement> { @@ -51,35 +52,29 @@ impl<'a, T: FieldElement> SolverState<'a, T> { /// Data needed to handle an outer query. #[derive(Clone)] pub struct OuterQuery<'a, 'b, T: FieldElement> { - /// Rows of the calling machine. - pub caller_rows: &'b RowPair<'b, 'a, T>, + /// Range constraints of the caller. + pub range_constraints: &'b dyn RangeConstraintSet, T>, /// Connection. pub connection: Connection<'a, T>, - /// The left side of the connection, evaluated. - pub left: Left<'a, T>, + /// The payload of the calling bus send, evaluated. + pub arguments: Arguments<'a, T>, } impl<'a, 'b, T: FieldElement> OuterQuery<'a, 'b, T> { pub fn try_new( - caller_rows: &'b RowPair<'b, 'a, T>, + arguments: &'b [AffineExpression, T>], + range_constraints: &'b dyn RangeConstraintSet, T>, connection: Connection<'a, T>, ) -> Result>> { - // Evaluate once, for performance reasons. - let left = connection - .left - .expressions - .iter() - .map(|e| caller_rows.evaluate(e)) - .collect::>()?; Ok(Self { - caller_rows, + range_constraints, connection, - left, + arguments: arguments.to_vec(), }) } pub fn is_complete(&self) -> bool { - self.left.iter().all(|l| l.is_constant()) + self.arguments.iter().all(|l| l.is_constant()) } } @@ -167,7 +162,7 @@ impl<'a, 'c, T: FieldElement, Q: QueryCallback> Processor<'a, 'c, T, Q> { log::trace!(" Extracting inputs:"); let mut inputs = vec![]; for (l, r) in outer_query - .left + .arguments .iter() .zip(&outer_query.connection.right.expressions) { @@ -355,7 +350,7 @@ Known values in current row (local: {row_index}, global {global_row_index}): .map_err(|e| { log::warn!("Error in outer query: {e}"); log::warn!("Some of the following entries could not be matched:"); - for (l, r) in outer_query.left.iter().zip(right.expressions.iter()) { + for (l, r) in outer_query.arguments.iter().zip(right.expressions.iter()) { if let Ok(r) = row_pair.evaluate(r) { log::warn!(" => {} = {}", l, r); } @@ -475,7 +470,7 @@ Known values in current row (local: {row_index}, global {global_row_index}): progress = true; self.propagate_along_copy_constraints(row_index, poly, c); } else if let Constraint::Assignment(v) = c { - let left = &mut self.outer_query.as_mut().unwrap().left; + let left = &mut self.outer_query.as_mut().unwrap().arguments; log::trace!(" => {} (outer) = {}", poly, v); for l in left.iter_mut() { l.assign(*var, *v);