Skip to content

Commit 6ea63a7

Browse files
chrisethgeorgwiese
authored andcommitted
Move vm processor (#2136)
Co-authored-by: Georg Wiese <georgwiese@gmail.com>
1 parent be3f75a commit 6ea63a7

9 files changed

+160
-129
lines changed

executor/src/witgen/data_structures/mutable_state.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ impl<'a, T: FieldElement, Q: QueryCallback<T>> MutableState<'a, T, Q> {
4040
}
4141
}
4242

43+
/// Runs the first machine (unless there are no machines) end returns the generated columns.
44+
/// The first machine might call other machines, which is handled automatically.
45+
pub fn run(self) -> HashMap<String, Vec<T>> {
46+
if let Some(first_machine) = self.machines.first() {
47+
first_machine.try_borrow_mut().unwrap().run_timed(&self);
48+
}
49+
self.take_witness_col_values()
50+
}
51+
4352
/// Call the machine responsible for the right-hand-side of an identity given its ID
4453
/// and the row pair of the caller.
4554
pub fn call(&self, identity_id: u64, caller_rows: &RowPair<'_, 'a, T>) -> EvalResult<'a, T> {
@@ -59,7 +68,7 @@ impl<'a, T: FieldElement, Q: QueryCallback<T>> MutableState<'a, T, Q> {
5968
}
6069

6170
/// Extracts the witness column values from the machines.
62-
pub fn take_witness_col_values(self) -> HashMap<String, Vec<T>> {
71+
fn take_witness_col_values(self) -> HashMap<String, Vec<T>> {
6372
// We keep the already processed machines mutably borrowed so that
6473
// "later" machines do not try to create new rows in already processed
6574
// machines.

executor/src/witgen/machines/double_sorted_witness_machine_16.rs

+4
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ impl<'a, T: FieldElement> DoubleSortedWitnesses16<'a, T> {
132132
return None;
133133
}
134134

135+
if parts.connections.is_empty() {
136+
return None;
137+
}
138+
135139
if !parts
136140
.connections
137141
.values()

executor/src/witgen/machines/double_sorted_witness_machine_32.rs

+4
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ impl<'a, T: FieldElement> DoubleSortedWitnesses32<'a, T> {
102102
return None;
103103
}
104104

105+
if parts.connections.is_empty() {
106+
return None;
107+
}
108+
105109
if !parts.connections.values().all(|i| i.is_permutation()) {
106110
return None;
107111
}

executor/src/witgen/generator.rs executor/src/witgen/machines/dynamic_machine.rs

+22-28
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,24 @@ use powdr_ast::analyzed::AlgebraicExpression as Expression;
22
use powdr_number::{DegreeType, FieldElement};
33
use std::collections::{BTreeMap, HashMap};
44

5+
use crate::witgen::block_processor::BlockProcessor;
56
use crate::witgen::data_structures::finalizable_data::FinalizableData;
7+
use crate::witgen::data_structures::multiplicity_counter::MultiplicityCounter;
68
use crate::witgen::data_structures::mutable_state::MutableState;
7-
use crate::witgen::machines::profiling::{record_end, record_start};
8-
use crate::witgen::processor::OuterQuery;
9-
use crate::witgen::EvalValue;
10-
11-
use super::affine_expression::AlgebraicVariable;
12-
use super::block_processor::BlockProcessor;
13-
use super::data_structures::multiplicity_counter::MultiplicityCounter;
14-
use super::machines::{Machine, MachineParts};
15-
use super::processor::SolverState;
16-
use super::rows::{Row, RowIndex, RowPair};
17-
use super::sequence_iterator::{DefaultSequenceIterator, ProcessingSequenceIterator};
18-
use super::vm_processor::VmProcessor;
19-
use super::{EvalResult, FixedData, QueryCallback};
9+
use crate::witgen::machines::{Machine, MachineParts};
10+
use crate::witgen::processor::{OuterQuery, SolverState};
11+
use crate::witgen::rows::{Row, RowIndex, RowPair};
12+
use crate::witgen::sequence_iterator::{DefaultSequenceIterator, ProcessingSequenceIterator};
13+
use crate::witgen::vm_processor::VmProcessor;
14+
use crate::witgen::{AlgebraicVariable, EvalResult, EvalValue, FixedData, QueryCallback};
2015

2116
struct ProcessResult<'a, T: FieldElement> {
2217
eval_value: EvalValue<AlgebraicVariable<'a>, T>,
2318
updated_data: SolverState<'a, T>,
2419
}
2520

26-
pub struct Generator<'a, T: FieldElement> {
21+
/// A machine is generic and can handle lookups that generate a dynamic number of rows.
22+
pub struct DynamicMachine<'a, T: FieldElement> {
2723
fixed_data: &'a FixedData<'a, T>,
2824
parts: MachineParts<'a, T>,
2925
data: FinalizableData<T>,
@@ -34,7 +30,7 @@ pub struct Generator<'a, T: FieldElement> {
3430
multiplicity_counter: MultiplicityCounter,
3531
}
3632

37-
impl<'a, T: FieldElement> Machine<'a, T> for Generator<'a, T> {
33+
impl<'a, T: FieldElement> Machine<'a, T> for DynamicMachine<'a, T> {
3834
fn identity_ids(&self) -> Vec<u64> {
3935
self.parts.identity_ids()
4036
}
@@ -43,6 +39,16 @@ impl<'a, T: FieldElement> Machine<'a, T> for Generator<'a, T> {
4339
&self.name
4440
}
4541

42+
/// Runs the machine without any arguments from the first row.
43+
fn run<Q: QueryCallback<T>>(&mut self, mutable_state: &MutableState<'a, T, Q>) {
44+
assert!(self.data.is_empty());
45+
let first_row = self.compute_partial_first_row(mutable_state);
46+
self.data = self
47+
.process(first_row, 0, mutable_state, None, true)
48+
.updated_data
49+
.block;
50+
}
51+
4652
fn process_plookup<'b, Q: QueryCallback<T>>(
4753
&mut self,
4854
mutable_state: &MutableState<'a, T, Q>,
@@ -110,7 +116,7 @@ impl<'a, T: FieldElement> Machine<'a, T> for Generator<'a, T> {
110116
}
111117
}
112118

113-
impl<'a, T: FieldElement> Generator<'a, T> {
119+
impl<'a, T: FieldElement> DynamicMachine<'a, T> {
114120
pub fn new(
115121
name: String,
116122
fixed_data: &'a FixedData<'a, T>,
@@ -132,18 +138,6 @@ impl<'a, T: FieldElement> Generator<'a, T> {
132138
}
133139
}
134140

135-
/// Runs the machine without any arguments from the first row.
136-
pub fn run<Q: QueryCallback<T>>(&mut self, mutable_state: &MutableState<'a, T, Q>) {
137-
record_start(self.name());
138-
assert!(self.data.is_empty());
139-
let first_row = self.compute_partial_first_row(mutable_state);
140-
self.data = self
141-
.process(first_row, 0, mutable_state, None, true)
142-
.updated_data
143-
.block;
144-
record_end(self.name());
145-
}
146-
147141
fn fill_remaining_rows<Q: QueryCallback<T>>(&mut self, mutable_state: &MutableState<'a, T, Q>) {
148142
if self.data.len() < self.degree as usize + 1 {
149143
assert!(self.latch.is_some());

executor/src/witgen/machines/machine_extractor.rs

+70-40
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,9 @@ use super::fixed_lookup_machine::FixedLookup;
1313
use super::sorted_witness_machine::SortedWitnesses;
1414
use super::FixedData;
1515
use super::KnownMachine;
16+
use crate::witgen::machines::dynamic_machine::DynamicMachine;
1617
use crate::witgen::machines::Connection;
17-
use crate::witgen::{
18-
generator::Generator,
19-
machines::{write_once_memory::WriteOnceMemory, MachineParts},
20-
};
18+
use crate::witgen::machines::{write_once_memory::WriteOnceMemory, MachineParts};
2119
use crate::Identity;
2220

2321
use powdr_ast::analyzed::{
@@ -26,11 +24,6 @@ use powdr_ast::analyzed::{
2624
use powdr_ast::parsed::{self, visitor::AllChildren};
2725
use powdr_number::FieldElement;
2826

29-
pub struct ExtractionOutput<'a, T: FieldElement> {
30-
pub machines: Vec<KnownMachine<'a, T>>,
31-
pub base_parts: MachineParts<'a, T>,
32-
}
33-
3427
pub struct MachineExtractor<'a, T: FieldElement> {
3528
fixed: &'a FixedData<'a, T>,
3629
}
@@ -40,12 +33,10 @@ impl<'a, T: FieldElement> MachineExtractor<'a, T> {
4033
Self { fixed }
4134
}
4235

43-
/// Finds machines in the witness columns and identities
44-
/// and returns a list of machines and the identities
36+
/// Finds machines in the witness columns and identities and returns a list of machines and the identities
4537
/// that are not "internal" to the machines.
46-
pub fn split_out_machines(&self, identities: Vec<&'a Identity<T>>) -> ExtractionOutput<'a, T> {
47-
let mut machines: Vec<KnownMachine<T>> = vec![];
48-
38+
/// The first returned machine is the "main machine", i.e. a machine that has no incoming connections.
39+
pub fn split_out_machines(&self, identities: Vec<&'a Identity<T>>) -> Vec<KnownMachine<'a, T>> {
4940
// Ignore prover functions that reference columns of later stages.
5041
let all_witnesses = self.fixed.witness_cols.keys().collect::<HashSet<_>>();
5142
let current_stage_witnesses = self
@@ -68,6 +59,30 @@ impl<'a, T: FieldElement> MachineExtractor<'a, T> {
6859
})
6960
.collect::<Vec<&analyzed::Expression>>();
7061

62+
if self.fixed.stage() > 0 {
63+
// We expect later-stage witness columns to be accumulators for lookup and permutation arguments.
64+
// These don't behave like normal witness columns (e.g. in a block machine), and they might depend
65+
// on witness columns of more than one machine.
66+
// Therefore, we treat everything as one big machine. Also, we remove lookups and permutations,
67+
// as they are assumed to be handled in stage 0.
68+
let polynomial_identities = identities
69+
.into_iter()
70+
.filter(|identity| matches!(identity, Identity::Polynomial(_)))
71+
.collect::<Vec<_>>();
72+
let machine_parts = MachineParts::new(
73+
self.fixed,
74+
Default::default(),
75+
polynomial_identities,
76+
self.fixed.witness_cols.keys().collect::<HashSet<_>>(),
77+
prover_functions,
78+
);
79+
80+
return build_main_machine(self.fixed, machine_parts)
81+
.into_iter()
82+
.collect();
83+
}
84+
let mut machines: Vec<KnownMachine<T>> = vec![];
85+
7186
let mut publics = PublicsTracker::default();
7287
let mut remaining_witnesses = current_stage_witnesses.clone();
7388
let mut base_identities = identities.clone();
@@ -197,27 +212,33 @@ impl<'a, T: FieldElement> MachineExtractor<'a, T> {
197212
.collect::<Vec<_>>();
198213

199214
log::trace!(
200-
"\nThe base machine contains the following witnesses:\n{}\n identities:\n{}\n and prover functions:\n{}",
201-
remaining_witnesses
202-
.iter()
203-
.map(|s| self.fixed.column_name(s))
204-
.sorted()
205-
.format(", "),
206-
base_identities
207-
.iter()
208-
.format("\n"),
209-
base_prover_functions.iter().format("\n")
210-
);
215+
"\nThe base machine contains the following witnesses:\n{}\n identities:\n{}\n and prover functions:\n{}",
216+
remaining_witnesses
217+
.iter()
218+
.map(|s| self.fixed.column_name(s))
219+
.sorted()
220+
.format(", "),
221+
base_identities
222+
.iter()
223+
.format("\n"),
224+
base_prover_functions.iter().format("\n")
225+
);
211226

212-
ExtractionOutput {
213-
machines,
214-
base_parts: MachineParts::new(
215-
self.fixed,
216-
Default::default(),
217-
base_identities,
218-
remaining_witnesses,
219-
base_prover_functions,
220-
),
227+
let base_parts = MachineParts::new(
228+
self.fixed,
229+
Default::default(),
230+
base_identities,
231+
remaining_witnesses,
232+
base_prover_functions,
233+
);
234+
235+
if let Some(main_machine) = build_main_machine(self.fixed, base_parts) {
236+
std::iter::once(main_machine).chain(machines).collect()
237+
} else {
238+
if !machines.is_empty() {
239+
log::error!("No main machine was extracted, but secondary machines were. Does the system have a cycle?");
240+
}
241+
vec![]
221242
}
222243
}
223244

@@ -358,6 +379,14 @@ impl<'a> PublicsTracker<'a> {
358379
}
359380
}
360381

382+
fn build_main_machine<'a, T: FieldElement>(
383+
fixed_data: &'a FixedData<'a, T>,
384+
machine_parts: MachineParts<'a, T>,
385+
) -> Option<KnownMachine<'a, T>> {
386+
(!machine_parts.witnesses.is_empty())
387+
.then(|| build_machine(fixed_data, machine_parts, |t| format!("Main machine ({t})")))
388+
}
389+
361390
fn build_machine<'a, T: FieldElement>(
362391
fixed_data: &'a FixedData<'a, T>,
363392
machine_parts: MachineParts<'a, T>,
@@ -395,7 +424,9 @@ fn build_machine<'a, T: FieldElement>(
395424
log::debug!("Detected machine: {machine}");
396425
KnownMachine::BlockMachine(machine)
397426
} else {
398-
log::debug!("Detected machine: VM.");
427+
log::debug!("Detected machine: Dynamic machine.");
428+
// If there is a connection to this machine, all connections must have the same latch.
429+
// If there is no connection to this machine, it is the main machine and there is no latch.
399430
let latch = machine_parts.connections
400431
.values()
401432
.fold(None, |existing_latch, identity| {
@@ -411,13 +442,12 @@ fn build_machine<'a, T: FieldElement>(
411442
} else {
412443
Some(current_latch.clone())
413444
}
414-
})
415-
.unwrap();
416-
KnownMachine::Vm(Generator::new(
417-
name_with_type("Vm"),
445+
});
446+
KnownMachine::DynamicMachine(DynamicMachine::new(
447+
name_with_type("Dynamic"),
418448
fixed_data,
419449
machine_parts.clone(),
420-
Some(latch),
450+
latch,
421451
))
422452
}
423453
}

0 commit comments

Comments
 (0)