Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bus multi interaction (arbitrary number of columns) #2455

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion ast/src/analyzed/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ impl<T: Display> Display for PhantomBusInteractionIdentity<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(
f,
"Constr::PhantomBusInteraction({}, {}, [{}], {}, [{}], [{}]);",
"Constr::PhantomBusInteraction({}, {}, [{}], {}, [{}], [{}], [{}]);",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point, helper columns are NOT Option yet, but always array.

self.multiplicity,
self.bus_id,
self.payload.0.iter().map(ToString::to_string).format(", "),
Expand All @@ -445,6 +445,10 @@ impl<T: Display> Display for PhantomBusInteractionIdentity<T> {
.iter()
.map(ToString::to_string)
.format(", "),
self.helper_columns
.iter()
.map(ToString::to_string)
.format(", ")
)
}
}
Expand Down
2 changes: 2 additions & 0 deletions ast/src/analyzed/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,8 @@ pub struct PhantomBusInteractionIdentity<T> {
// always expect direct column references, so this is unpacked
// when converting from PIL to this struct.
pub accumulator_columns: Vec<AlgebraicReference>,
// Assumed to be direct column references.
pub helper_columns: Vec<AlgebraicReference>,
}

impl<T> Children<AlgebraicExpression<T>> for PhantomBusInteractionIdentity<T> {
Expand Down
35 changes: 31 additions & 4 deletions executor/src/witgen/bus_accumulator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,9 @@ impl<'a, T: FieldElement, Ext: ExtensionField<T> + Sync> BusAccumulatorGenerator
.bus_interactions
.par_iter()
.flat_map(|bus_interaction| {
let (folded, acc) = self.interaction_columns(bus_interaction);
let (folded, helper, acc) = self.interaction_columns(bus_interaction);
collect_folded_columns(bus_interaction, folded)
.chain(collect_helper_columns(bus_interaction, helper))
.chain(collect_acc_columns(bus_interaction, acc))
.collect::<Vec<_>>()
})
Expand Down Expand Up @@ -179,14 +180,22 @@ impl<'a, T: FieldElement, Ext: ExtensionField<T> + Sync> BusAccumulatorGenerator
result
}

/// New version of interaction_columns that “batches” several bus interactions
/// according to bus_multi_interaction_2.
///
/// Returns a triple:
/// - the folded columns (one per bus interaction)
/// - one helper column per pair of bus interactions
/// - the accumulator column (shared by all interactions)
fn interaction_columns(
&self,
bus_interaction: &PhantomBusInteractionIdentity<T>,
) -> (Vec<Vec<T>>, Vec<Vec<T>>) {
) -> (Vec<Vec<T>>, Vec<Vec<T>>, Vec<Vec<T>>) {
let intermediate_definitions = self.pil.intermediate_definitions();

let size = self.values.height();
let mut folded_list = vec![Ext::zero(); size];
let mut helper_list = vec![Ext::zero(); size];
let mut acc_list = vec![Ext::zero(); size];

for i in 0..size {
Expand All @@ -206,28 +215,35 @@ impl<'a, T: FieldElement, Ext: ExtensionField<T> + Sync> BusAccumulatorGenerator
.collect::<Vec<_>>();
let folded = self.beta - self.fingerprint(&tuple);

let helper = folded.inverse() * multiplicity;

let new_acc = match multiplicity.is_zero() {
true => current_acc,
false => current_acc + folded.inverse() * multiplicity,
false => current_acc + helper,
};

folded_list[i] = folded;
helper_list[i] = helper;
acc_list[i] = new_acc;
}

// Transpose from row-major to column-major & flatten.
let mut folded = vec![Vec::with_capacity(size); Ext::size()];
let mut helper = vec![Vec::with_capacity(size); Ext::size()];
let mut acc = vec![Vec::with_capacity(size); Ext::size()];
for row_index in 0..size {
for (col_index, x) in folded_list[row_index].to_vec().into_iter().enumerate() {
folded[col_index].push(x);
}
for (col_index, x) in helper_list[row_index].to_vec().into_iter().enumerate() {
helper[col_index].push(x);
}
for (col_index, x) in acc_list[row_index].to_vec().into_iter().enumerate() {
acc[col_index].push(x);
}
}

(folded, acc)
(folded, helper, acc)
}

/// Fingerprints a tuples of field elements, using the pre-computed powers of alpha.
Expand Down Expand Up @@ -279,3 +295,14 @@ fn collect_acc_columns<T>(
.zip_eq(acc)
.map(|(column_reference, column)| (column_reference.poly_id, column))
}

fn collect_helper_columns<T>(
bus_interaction: &PhantomBusInteractionIdentity<T>,
helper: Vec<Vec<T>>,
) -> impl Iterator<Item = (PolyID, Vec<T>)> + '_ {
bus_interaction
.helper_columns
.iter()
.zip_eq(helper)
.map(|(column_reference, column)| (column_reference.poly_id, column))
}
14 changes: 7 additions & 7 deletions executor/src/witgen/data_structures/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ mod test {
r"
namespace main(4);
col fixed right_latch = [0, 1]*;
col witness right_selector, left_latch, a, b, multiplicities, folded, acc;
col witness right_selector, left_latch, a, b, multiplicities, folded, acc, helper;
{constraint}

// Selectors should be binary
Expand Down Expand Up @@ -420,9 +420,9 @@ namespace main(4);
// std::protocols::lookup_via_bus::lookup_send and
// std::protocols::lookup_via_bus::lookup_receive.
let (send, receive) = get_generated_bus_interaction_pair(
// The folded expressions and accumulator is ignored in both the bus send and receive, so we just use the same.
r"Constr::PhantomBusInteraction(main::left_latch, 42, [main::a], main::left_latch, [main::folded], [main::acc]);
Constr::PhantomBusInteraction(-main::multiplicities, 42, [main::b], main::right_latch, [main::folded], [main::acc]);",
// The folded expressions, accumulator, and helper columns are ignored in both the bus send and receive, so we just use the same.
r"Constr::PhantomBusInteraction(main::left_latch, 42, [main::a], main::left_latch, [main::folded], [main::acc], [main::helper]);
Constr::PhantomBusInteraction(-main::multiplicities, 42, [main::b], main::right_latch, [main::folded], [main::acc], [main::helper]);",
);
assert_eq!(
send.selected_payload.to_string(),
Expand Down Expand Up @@ -478,9 +478,9 @@ namespace main(4);
// std::protocols::permutation_via_bus::permutation_send and
// std::protocols::permutation_via_bus::permutation_receive.
let (send, receive) = get_generated_bus_interaction_pair(
// The folded expressions and accumulator is ignored in both the bus send and receive, so we just use the same.
r"Constr::PhantomBusInteraction(main::left_latch, 42, [main::a], main::left_latch, [main::folded], [main::acc]);
Constr::PhantomBusInteraction(-(main::right_latch * main::right_selector), 42, [main::b], main::right_latch * main::right_selector, [main::folded], [main::acc]);",
// The folded expressions, accumulator, and helper columns are ignored in both the bus send and receive, so we just use the same.
r"Constr::PhantomBusInteraction(main::left_latch, 42, [main::a], main::left_latch, [main::folded], [main::acc], [main::helper]);
Constr::PhantomBusInteraction(-(main::right_latch * main::right_selector), 42, [main::b], main::right_latch * main::right_selector, [main::folded], [main::acc], [main::helper]);",
);
assert_eq!(
send.selected_payload.to_string(),
Expand Down
13 changes: 13 additions & 0 deletions pil-analyzer/src/condenser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,19 @@ fn to_constraint<T: FieldElement>(
.collect(),
_ => panic!("Expected array, got {:?}", fields[5]),
},
helper_columns: match fields[6].as_ref() {
Value::Array(fields) => fields
.iter()
.map(|f| match to_expr(f) {
AlgebraicExpression::Reference(reference) => {
assert!(!reference.next);
reference
}
_ => panic!("Expected reference, got {f:?}"),
})
.collect(),
_ => panic!("Expected array, got {:?}", fields[6]),
},
}
.into(),
_ => panic!("Expected constraint but got {constraint}"),
Expand Down
6 changes: 5 additions & 1 deletion std/prelude.asm
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ enum Constr {
/// Note that this could refer to witness columns, intermediate columns, or
/// in-lined expressions.
/// - The list of accumulator columns.
PhantomBusInteraction(expr, expr, expr[], expr, expr[], expr[])
/// - The list of helper columns that are intermediate values to help calculate
/// the accumulator columns, so that constraints are always bounded to
/// degree 3. Each set of helper columns is always shared by two bus
/// interactions.
PhantomBusInteraction(expr, expr, expr[], expr, expr[], expr[], expr[])
}

/// This is the result of the "$" operator. It can be used as the left and
Expand Down
Loading
Loading