Skip to content

Commit 69be2d2

Browse files
committed
Implement basic dynamic bus
1 parent 90b0d3e commit 69be2d2

File tree

7 files changed

+63
-44
lines changed

7 files changed

+63
-44
lines changed

executor/src/witgen/data_structures/identity.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -295,16 +295,15 @@ fn convert_phantom_bus_interaction<T: FieldElement>(
295295
},
296296
_ => (false, bus_interaction.multiplicity.clone()),
297297
};
298-
let bus_id = match bus_interaction.bus_id {
299-
AlgebraicExpression::Number(id) => id,
300-
// TODO: Relax this for sends when implementing dynamic sends
301-
_ => panic!("Expected first payload entry to be a static ID"),
302-
};
303298
let selected_payload = SelectedExpressions {
304299
selector: bus_interaction.latch.clone(),
305300
expressions: bus_interaction.payload.0.clone(),
306301
};
307302
if is_receive {
303+
let bus_id = match bus_interaction.bus_id {
304+
AlgebraicExpression::Number(id) => id,
305+
_ => panic!("Expected first payload entry of a receive to be a static ID"),
306+
};
308307
IdentityOrReceive::Receive(BusReceive {
309308
bus_id,
310309
multiplicity: Some(multiplicity),
@@ -314,7 +313,7 @@ fn convert_phantom_bus_interaction<T: FieldElement>(
314313
assert_eq!(multiplicity, bus_interaction.latch);
315314
IdentityOrReceive::Identity(Identity::BusSend(BusSend {
316315
identity_id: bus_interaction.id,
317-
bus_id: AlgebraicExpression::Number(bus_id),
316+
bus_id: bus_interaction.bus_id.clone(),
318317
selected_payload,
319318
}))
320319
}

executor/src/witgen/eval_result.rs

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ pub enum IncompleteCause<K = usize> {
3333
NonConstantQueryMatchScrutinee,
3434
/// Query element is not constant.
3535
NonConstantQueryElement,
36+
/// Bus ID is not constant.
37+
NonConstantBusID,
3638
/// A required argument was not provided
3739
NonConstantRequiredArgument(&'static str),
3840
/// The left selector in a lookup is not constant. Example: `x * {1} in [{1}]` where `x` is not constant.

executor/src/witgen/global_constraints.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,10 @@ fn propagate_constraints<T: FieldElement>(
256256
}
257257
}
258258
Identity::BusSend(send) => {
259-
let receive = send.try_match_static(bus_receives).unwrap();
259+
let receive = match send.try_match_static(bus_receives) {
260+
Some(r) => r,
261+
None => return false,
262+
};
260263
if !send.selected_payload.selector.is_one() {
261264
return false;
262265
}

executor/src/witgen/identity_processor.rs

+15-11
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use powdr_number::FieldElement;
77
use crate::witgen::data_structures::mutable_state::MutableState;
88
use crate::witgen::{global_constraints::CombinedRangeConstraintSet, EvalError};
99

10-
use super::data_structures::identity::Identity;
10+
use super::data_structures::identity::{BusSend, Identity};
1111
use super::{
1212
affine_expression::AlgebraicVariable, processor::OuterQuery, rows::RowPair, EvalResult,
1313
EvalValue, IncompleteCause, QueryCallback,
@@ -37,11 +37,7 @@ impl<'a, 'c, T: FieldElement, Q: QueryCallback<T>> IdentityProcessor<'a, 'c, T,
3737
) -> EvalResult<'a, T> {
3838
let result = match identity {
3939
Identity::Polynomial(identity) => self.process_polynomial_identity(identity, rows),
40-
Identity::BusSend(bus_interaction) => self.process_machine_call(
41-
bus_interaction.bus_id().unwrap(),
42-
&bus_interaction.selected_payload,
43-
rows,
44-
),
40+
Identity::BusSend(bus_interaction) => self.process_machine_call(bus_interaction, rows),
4541
Identity::Connect(..) => {
4642
// TODO this is not the right cause.
4743
Ok(EvalValue::incomplete(IncompleteCause::SolvingFailed))
@@ -67,15 +63,15 @@ impl<'a, 'c, T: FieldElement, Q: QueryCallback<T>> IdentityProcessor<'a, 'c, T,
6763

6864
fn process_machine_call(
6965
&mut self,
70-
bus_id: T,
71-
left: &'a powdr_ast::analyzed::SelectedExpressions<T>,
66+
bus_send: &'a BusSend<T>,
7267
rows: &RowPair<'_, 'a, T>,
7368
) -> EvalResult<'a, T> {
74-
if let Some(status) = self.handle_left_selector(&left.selector, rows) {
69+
if let Some(status) = self.handle_left_selector(&bus_send.selected_payload.selector, rows) {
7570
return Ok(status);
7671
}
7772

78-
let left = match left
73+
let arguments = match bus_send
74+
.selected_payload
7975
.expressions
8076
.iter()
8177
.map(|e| rows.evaluate(e))
@@ -85,7 +81,15 @@ impl<'a, 'c, T: FieldElement, Q: QueryCallback<T>> IdentityProcessor<'a, 'c, T,
8581
Err(incomplete_cause) => return Ok(EvalValue::incomplete(incomplete_cause)),
8682
};
8783

88-
self.mutable_state.call(bus_id, &left, rows)
84+
let bus_id = match rows.evaluate(&bus_send.bus_id) {
85+
Ok(bus_id) => match bus_id.constant_value() {
86+
Some(bus_id) => bus_id,
87+
None => return Ok(EvalValue::incomplete(IncompleteCause::NonConstantBusID)),
88+
},
89+
Err(incomplete_cause) => return Ok(EvalValue::incomplete(incomplete_cause)),
90+
};
91+
92+
self.mutable_state.call(bus_id, &arguments, rows)
8993
}
9094

9195
/// Handles the lookup that connects the current machine to the calling machine.

executor/src/witgen/multiplicity_column_generator.rs

+31-22
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@ impl<'a, T: FieldElement> MultiplicityColumnGenerator<'a, T> {
3535
) -> HashMap<String, Vec<T>> {
3636
record_start(MULTIPLICITY_WITGEN_NAME);
3737

38-
// A map from multiplicity column ID to the vector of multiplicities.
39-
let mut multiplicity_columns = BTreeMap::new();
40-
4138
let (identities, _) = convert_identities(self.fixed.analyzed);
4239

4340
let all_columns = witness_columns
@@ -75,11 +72,11 @@ impl<'a, T: FieldElement> MultiplicityColumnGenerator<'a, T> {
7572
})
7673
.map(|(bus_id, bus_receive)| {
7774
let (size, rhs_tuples) =
78-
self.get_tuples(&terminal_values, &bus_receive.selected_payload);
75+
self.get_tuples(&terminal_values, &bus_receive.selected_payload, None);
7976

8077
let index = rhs_tuples
8178
.into_iter()
82-
.map(|(i, tuple)| {
79+
.map(|(i, tuple, _)| {
8380
// There might be multiple identical rows, but it's fine, we can pick any.
8481
(tuple, i)
8582
})
@@ -104,28 +101,35 @@ impl<'a, T: FieldElement> MultiplicityColumnGenerator<'a, T> {
104101
})
105102
.collect::<BTreeMap<_, _>>();
106103

104+
// A map from multiplicity column ID to the vector of multiplicities.
105+
let mut multiplicity_columns = receive_infos
106+
.values()
107+
.map(|info| (info.multiplicity_column, vec![0; info.size]))
108+
.collect::<BTreeMap<_, _>>();
109+
107110
// Increment multiplicities for all bus sends.
108-
for (bus_send, bus_receive) in identities.iter().filter_map(|i| match i {
109-
Identity::BusSend(bus_send) => receive_infos
110-
.get(&bus_send.bus_id().unwrap())
111-
.map(|bus_receive| (bus_send, bus_receive)),
111+
for bus_send in identities.iter().filter_map(|i| match i {
112+
Identity::BusSend(bus_send) => Some(bus_send),
112113
_ => None,
113114
}) {
114-
let (_, lhs_tuples) = self.get_tuples(&terminal_values, &bus_send.selected_payload);
115-
116-
let multiplicities = multiplicity_columns
117-
.entry(bus_receive.multiplicity_column)
118-
.or_insert_with(|| vec![0; bus_receive.size]);
119-
assert_eq!(multiplicities.len(), bus_receive.size);
115+
let (_, lhs_tuples) = self.get_tuples(
116+
&terminal_values,
117+
&bus_send.selected_payload,
118+
Some(&bus_send.bus_id),
119+
);
120120

121121
// Looking up the index is slow, so we do it in parallel.
122122
let indices = lhs_tuples
123123
.into_par_iter()
124-
.map(|(_, tuple)| bus_receive.index[&tuple])
124+
.filter_map(|(_, tuple, bus_id)| {
125+
receive_infos.get(&bus_id.unwrap()).map(|receive_info| {
126+
(receive_info.multiplicity_column, receive_info.index[&tuple])
127+
})
128+
})
125129
.collect::<Vec<_>>();
126130

127-
for index in indices {
128-
multiplicities[index] += 1;
131+
for (multiplicity_column, index) in indices {
132+
multiplicity_columns.get_mut(&multiplicity_column).unwrap()[index] += 1;
129133
}
130134
}
131135

@@ -151,7 +155,8 @@ impl<'a, T: FieldElement> MultiplicityColumnGenerator<'a, T> {
151155
&self,
152156
terminal_values: &OwnedTerminalValues<T>,
153157
selected_expressions: &SelectedExpressions<T>,
154-
) -> (usize, Vec<(usize, Vec<T>)>) {
158+
bus_id: Option<&AlgebraicExpression<T>>,
159+
) -> (usize, Vec<(usize, Vec<T>, Option<T>)>) {
155160
let machine_size = selected_expressions
156161
.expressions
157162
.iter()
@@ -178,17 +183,21 @@ impl<'a, T: FieldElement> MultiplicityColumnGenerator<'a, T> {
178183
terminal_values.row(row),
179184
&self.fixed.intermediate_definitions,
180185
);
181-
let result = evaluator.evaluate(&selected_expressions.selector);
186+
let selector = evaluator.evaluate(&selected_expressions.selector);
182187

183-
assert!(result.is_zero() || result.is_one(), "Non-binary selector");
184-
result.is_one().then(|| {
188+
assert!(
189+
selector.is_zero() || selector.is_one(),
190+
"Non-binary selector"
191+
);
192+
selector.is_one().then(|| {
185193
(
186194
row,
187195
selected_expressions
188196
.expressions
189197
.iter()
190198
.map(|expression| evaluator.evaluate(expression))
191199
.collect::<Vec<_>>(),
200+
bus_id.map(|bus_id| evaluator.evaluate(bus_id)),
192201
)
193202
})
194203
})

executor/src/witgen/vm_processor.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -364,9 +364,12 @@ impl<'a, 'c, T: FieldElement, Q: QueryCallback<T>> VmProcessor<'a, 'c, T, Q> {
364364
.filter_map(|(index, (ident, _))| match ident {
365365
Identity::BusSend(send) => send
366366
.try_match_static(&self.fixed_data.bus_receives)
367-
.unwrap()
368-
.has_arbitrary_multiplicity()
369-
.then_some((index, &send.selected_payload)),
367+
// Filter dynamic lookups
368+
.and_then(|receive| {
369+
receive
370+
.has_arbitrary_multiplicity()
371+
.then_some((index, &send.selected_payload))
372+
}),
370373
_ => None,
371374
})
372375
.max_by_key(|(_, left)| left.expressions.len())

pipeline/tests/asm.rs

-1
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,6 @@ fn static_bus_multi() {
251251
}
252252

253253
#[test]
254-
#[should_panic = "Expected first payload entry to be a static ID"]
255254
fn dynamic_bus() {
256255
// Witgen does not currently support this.
257256
let f = "asm/dynamic_bus.asm";

0 commit comments

Comments
 (0)