Skip to content

Commit 98f72ae

Browse files
cocoheartsbfan05OsamaAlkhodairyjonathanpwangAlex Zhao
authored
feat: single page groupby (#75)
* feat: sorted_limbs chip checking each limb less than limb_bits bits * wip * feat: completed sorted_limbs chip with tests * wip * feat: SortedLimbsChip with LessThan subchip * feat: less_than subchip refactored * feat: rename SortedLimbsChip to AssertSortedChip and write LessThanChip tests * chore: change name of assert sorted chip * chore: fix names in tests for AssertSortedChip * chore: address comments * chore: cleanup * chore: change MAX from generic to instance field for LessThanChip and AssertSortedChip * wip: added extra bits to middle chip trace * wip * adding connection to IsEqualVec chip * feat: IsLessThanChip to compare two numbers * feat: IsLessThanTuple subchip for different limb_bits * test: added tests for partially and non-allocated pages * test: added negative tests * added constraints * adding comments * feat: IsLessThanTupleChip subchip in AssertSortedChip * renaming * removing TODO comments * fixing clippy * chore: renaming to idx and data * chore: address comments first pass * chore: moving page_controller inside page_read * chore: refactor AssertSorted, IsEqual, IsLessThan, and IsLessThanTuple chips * chore: address comments * chore: eliminate high dim poly from IsLessThanTupleChip * chore: fix tests * chore: address comments for AssertSortedChip * chore: cleanup AssertSorted * chore: cleanup * chore: include roundtrip flatten and from_slice tests * feat: flatten and from_slice for IO and Aux columns * wip: final page chip * remove txt file * feat: final_page_chip * feat: integrating all chips for page_read_write * fixing lib * using field bits() * adding extra communication between checker and final chip * muting clippy * renaming to AIR * adding comments * comment fix * optimization to one less bus * feat: air struct, columns struct, from_slice * comments * moving old page_controller inside page_read * updateing comment * completed group_by main air and chip * chore: remove input_bus * chore: add is_alloc column for arb page lengths * saving copies * merged final_page from PR #45 (page r/w checker) * full merge for page-rw-checker * wip: inner join * feat: more general FinalPageAir * making IsEqualVecAuxCols clonable * remove group-by-output, add subair and subairbridge for group-by * enforcing unallocated rows to be zero * aligning with new less than chip * wip * using Air::eval instead of SubAir::eval * fix comment * wip * removed arguments from load_page for readability * addressing comments and adding common/ directory with Page struct * wip * chore: revising integration tests, fixing more width and index bugs * controller complete * controller complete * chore: fixed constraint/width bugs, debugging interactions * chore: finish merge * chore: finish merge * adding less than constraints * adding comments * more comments * chore: cleaning code, merging common::page characteristics * chore: debugging widths * chore: fixed more indexing bugs, searching for interaction bug * chore: refactor col_index_map using Range<usize> * added keygen and prove functions to controller * added verify function to controller * feat: add `check-cumulative_sums` to debug prover * chore: turn off debug for negative tests * feat: fix final bug * feat: last debug, generalizing and expanding testcases * chore: refactor tests with abstractions, rename to tests.rs * chore: correct previous commit, adding tests.rs to history * chore: refactor using Page::random * chore: refactor set_up_keygen_builder * debugging unallocated rows * chore: filter group-by-input.request() by allocated rows, refactor row allocation in tests * feat: adjusting constraints for unallocated rows, adding group_by_alloc column for unallocated rows * docs(chips): method and constraint docstrings * feat: corrected constraints and added complete group_by vec range, debugging range-bus error * fix: imp page_controller::refresh_range_checker, iterated tests now work * feat: negative tests that prank final_chip trace values, docs * docs(page_controller, tests): comprehensive docstrings and inline comments * Add additional page_controller fns, add static test (#100) * chore: auto-implement `Rap` when builder is not `Sync` (#80) * [feat] Query binary (#46) * Add MVP bin * Add MVP bin * Update cache command * Refactor cmd line items * Mock subcommand + logical interface updates * Update interface for reading db * Change interface to read * Change interface to read * Add write command * Add output command for write * Feat/m1 execution air (#66) * feat: sorted_limbs chip checking each limb less than limb_bits bits * wip * feat: completed sorted_limbs chip with tests * wip * feat: SortedLimbsChip with LessThan subchip * feat: less_than subchip refactored * feat: rename SortedLimbsChip to AssertSortedChip and write LessThanChip tests * chore: change name of assert sorted chip * chore: fix names in tests for AssertSortedChip * chore: address comments * chore: cleanup * chore: change MAX from generic to instance field for LessThanChip and AssertSortedChip * wip: added extra bits to middle chip trace * wip * adding connection to IsEqualVec chip * feat: IsLessThanChip to compare two numbers * feat: IsLessThanTuple subchip for different limb_bits * test: added tests for partially and non-allocated pages * test: added negative tests * added constraints * adding comments * feat: IsLessThanTupleChip subchip in AssertSortedChip * renaming * removing TODO comments * fixing clippy * chore: renaming to idx and data * chore: address comments first pass * chore: moving page_controller inside page_read * chore: refactor AssertSorted, IsEqual, IsLessThan, and IsLessThanTuple chips * chore: address comments * chore: eliminate high dim poly from IsLessThanTupleChip * chore: fix tests * chore: address comments for AssertSortedChip * chore: cleanup AssertSorted * chore: cleanup * chore: include roundtrip flatten and from_slice tests * feat: flatten and from_slice for IO and Aux columns * wip: final page chip * remove txt file * feat: final_page_chip * feat: integrating all chips for page_read_write * fixing lib * using field bits() * adding extra communication between checker and final chip * muting clippy * renaming to AIR * adding comments * wip * wip * feat: execution air finished --------- Co-authored-by: bfan <[email protected]> Co-authored-by: Osama Alkhodairy <[email protected]> Co-authored-by: Jonathan Wang <[email protected]> * Add print flag to afi command, update readmes * Update warnings * wip keygen * wip: start prove * Predicate * wip: prove and verify * change branches * Add to_page for Table * Use btreemap * Update functions * Update page to/from * Update tests * Add predicate binary * wip: proof not serializable * chore: patch stuff * add serde bounds * feat: zk commands (not debugged yet) * update mockdb * wip: mold into new format * chore: remove extraneous stuff * [WIP: query-binary] Merge r/w changes (#69) * Add is_less_than_bits chip (#60) * Add is_less_than_bits chip * Address zlangely's comments * Remove chip and use from_bool * Use row_mut * Add comments explaining comparison_check * Add alt version of is_less_than_bits chip * Replace is_less_than_bits with alt version, address comments * Fix lint issues * Feat/is less than bits tuple chip (#63) * Add is_less_than_tuple_bits chip * Incorporate is_less_than_bits feedback into is_less_than_tuple_bits * Add is_less_than_tuple_bits chip * Use match and cmp instead of else if * Adjust for new is_less_than_bits chip * chore: remove range_max field from IsLessThanAir and IsLessThanTupleAir (#65) * chore: derive serialize for proof (#67) * feat: page read write checker (#45) * feat: sorted_limbs chip checking each limb less than limb_bits bits * wip * feat: completed sorted_limbs chip with tests * wip * feat: SortedLimbsChip with LessThan subchip * feat: less_than subchip refactored * feat: rename SortedLimbsChip to AssertSortedChip and write LessThanChip tests * chore: change name of assert sorted chip * chore: fix names in tests for AssertSortedChip * chore: address comments * chore: cleanup * chore: change MAX from generic to instance field for LessThanChip and AssertSortedChip * wip: added extra bits to middle chip trace * wip * adding connection to IsEqualVec chip * feat: IsLessThanChip to compare two numbers * feat: IsLessThanTuple subchip for different limb_bits * test: added tests for partially and non-allocated pages * test: added negative tests * added constraints * adding comments * feat: IsLessThanTupleChip subchip in AssertSortedChip * renaming * removing TODO comments * fixing clippy * chore: renaming to idx and data * chore: address comments first pass * chore: moving page_controller inside page_read * chore: refactor AssertSorted, IsEqual, IsLessThan, and IsLessThanTuple chips * chore: address comments * chore: eliminate high dim poly from IsLessThanTupleChip * chore: fix tests * chore: address comments for AssertSortedChip * chore: cleanup AssertSorted * chore: cleanup * chore: include roundtrip flatten and from_slice tests * feat: flatten and from_slice for IO and Aux columns * wip: final page chip * remove txt file * feat: final_page_chip * feat: integrating all chips for page_read_write * fixing lib * using field bits() * adding extra communication between checker and final chip * muting clippy * renaming to AIR * adding comments * comment fix * optimization to one less bus * comments * moving old page_controller inside page_read * updateing comment * feat: more general FinalPageAir * making IsEqualVecAuxCols clonable * enforcing unallocated rows to be zero * aligning with new less than chip * using Air::eval instead of SubAir::eval * fix comment * removed arguments from load_page for readability * addressing comments and adding common/ directory with Page struct --------- Co-authored-by: bfan <[email protected]> Co-authored-by: Jonathan Wang <[email protected]> * Update to/from page and table tests * Update tests * chore: satisfy clippy (#68) * Fix execution_air test * Update --------- Co-authored-by: TlatoaniHJ <[email protected]> Co-authored-by: bfan05 <[email protected]> Co-authored-by: Jonathan Wang <[email protected]> Co-authored-by: Osama Alkhodairy <[email protected]> Co-authored-by: Zach Langley <[email protected]> * Tmp: remove predicate * Update readme * Update commands for newest rows * feat: add tracing and switch default fri params to log_blowup_factor = 3 * chore: update logging * Fix readme typo * Fix clippy warnings * Update to handle input byte lengths * Remove extraneous code * Revert 9f02efc^..9bad23e * Update logical interface to add byte lengths * Remove generics from logical-interface * merging new Offline Checker changes * Revert "change branches" This reverts commit ec8639f. * Update mock read/write commands * chore: add `mock describe` command * chore: do not overwrite db if exists * chore: remove schema config * chore: switch config back to data_bytes=1024 --------- Co-authored-by: MonkeyKing-1 <[email protected]> Co-authored-by: bfan <[email protected]> Co-authored-by: Osama Alkhodairy <[email protected]> Co-authored-by: Jonathan Wang <[email protected]> Co-authored-by: Zach Langley <[email protected]> Co-authored-by: TlatoaniHJ <[email protected]> * perf: Offline Checker Optimization (#82) * perf: removed 2*data_len columns from the offline checker * renaming to air * Add macros for testing * Additional tests * Remove unused function * Update naming and add comment * Feat/rename page air update from slice (#84) * feat: rename my page air and update from slice * add renamed files * feat: rename final page air * chore: fix lint and rename idx_limb_bits --------- Co-authored-by: Jonathan Wang <[email protected]> * chore: add sp1 eDSL (#87) * chore: make fields public in SumAir (#88) * feat: main chips for VM (#76) --------- Co-authored-by: Alex Zhao <[email protected]> Co-authored-by: bfan <[email protected]> Co-authored-by: Zach Langley <[email protected]> * feat: added enum for operation, bool for sorted, adjust get_width(), request() * feat: drop group_by_page from aux_trace if self.sorted * feat: drop page from column index_map if sorted * feat: update interactions to not send internally if sorted * chore: add to lib.rs, rename to receiving_indexed_output_page_air * chore: fix linter, tests still pass in unsorted case * feat: from_partitioned_slice, tests pass * Feat/Verify Aggregation VM with binary (#89) * Create stark-vm crate * Add lib.rs, add afs-chips dependency, add CPU chip * Make and use OpCode enum * Refactor CPU tests Refactor CPU tests, add positive tests for CPU, fix relevant bugs in AIR and trace generation * Add program chip Add program chip, move instruction frequency calculation to CPU trace, add positive tests for program * Actually add program chip Include program chip (+ positive tests) in commit (forgot to last time), add negative tests, change cpu::trace::Memory to return 0 for cells that haven't been written to, change CPU's generate_trace to terminate when pc goes out of bounds (previously was only when pc = -1) * feat: imp arithmetic unit, minus tests * Use destructuring in cpu/air.rs * Add negative test for CPU * Reformat cpu and program * chore: fix generate_trace, remove AUChip and replace with AUAir * Add explanations for test programs * chore: resolve conflict * Derive new for instruction Add dependency on derive-new, derive new for Instruction, use that in cpu/tests/mod.rs, add comment explaining program used in test_negative. * chore: change Operation to MemoryAccess * Align MemoryAccess with memory chip Refactor MemoryAccess for eventual merge with memory::MemoryAccess. Analogously change MemoryAccessCols.value to .data for consistency. * fix(au): width misalignment, incorrect trace generation * fix(au bridge): positive tests run * fix(trace): fix bug in AUCols::new, add negative tests * chore: rename AUAir -> FieldArithmeticAir, remove AUChip * Add terminate instruction Add terminate instruction, and use to make sure CPU trace height is power of 2. Also make sure that program trace height is power of 2 by adding jumps to same instruction. Refactor tests using ::from_size to construct Instruction, MemoryAccess, ArithmeticOperation. * chore: un-expand constraints using AB::Expr::one() * Address some zlangley comments * docs(au) * Commit zlangley suggestion Co-authored-by: Zach Langley <[email protected]> * Commit zlangley suggestion Co-authored-by: Zach Langley <[email protected]> * Make inst_width.clone() unnecessary * Address zlangley comment * Rename as_b, as_c to d, e * feat: Memory op interactions * Add negative test for termination check * Add failing test for secret write vulnerability * Add failing test for disable write vulnerability * Add failing test for disable read vulnerability * Check access enabled in AIR * Actually fix access enabled check * Simplify cpu/tests/mod.rs * Don't mock arithmetic chip when testing with is_field_arithmetic = false * chore: add test for invalid read * Attempt to write integration test * Conditionally use arith chip in integration test * Fix integration test wrt range checker * Lint * Use unique memory timestamp instead of clock cycle * chore: rename MemoryAccess clock field to timestamp * feat: change default FRI config to blowup factor 4 (#73) * feat: Offline Checker delete support (#74) * added new columns * squashing inner_join * feat: supporting delete in Offline Checker * removing pub * adding option in controller to provide initial ProverData * keeping page_controller as a directory for simplicity * adding option to generate ProverTraceData * addressing comments * deriving new in PageCols * feat: add engines for BabyBear with blake3 and keccak256 (#78) * chore: auto-implement `Rap` when builder is not `Sync` (#80) * [feat] Query binary (#46) * Add MVP bin * Add MVP bin * Update cache command * Refactor cmd line items * Mock subcommand + logical interface updates * Update interface for reading db * Change interface to read * Change interface to read * Add write command * Add output command for write * Feat/m1 execution air (#66) * feat: sorted_limbs chip checking each limb less than limb_bits bits * wip * feat: completed sorted_limbs chip with tests * wip * feat: SortedLimbsChip with LessThan subchip * feat: less_than subchip refactored * feat: rename SortedLimbsChip to AssertSortedChip and write LessThanChip tests * chore: change name of assert sorted chip * chore: fix names in tests for AssertSortedChip * chore: address comments * chore: cleanup * chore: change MAX from generic to instance field for LessThanChip and AssertSortedChip * wip: added extra bits to middle chip trace * wip * adding connection to IsEqualVec chip * feat: IsLessThanChip to compare two numbers * feat: IsLessThanTuple subchip for different limb_bits * test: added tests for partially and non-allocated pages * test: added negative tests * added constraints * adding comments * feat: IsLessThanTupleChip subchip in AssertSortedChip * renaming * removing TODO comments * fixing clippy * chore: renaming to idx and data * chore: address comments first pass * chore: moving page_controller inside page_read * chore: refactor AssertSorted, IsEqual, IsLessThan, and IsLessThanTuple chips * chore: address comments * chore: eliminate high dim poly from IsLessThanTupleChip * chore: fix tests * chore: address comments for AssertSortedChip * chore: cleanup AssertSorted * chore: cleanup * chore: include roundtrip flatten and from_slice tests * feat: flatten and from_slice for IO and Aux columns * wip: final page chip * remove txt file * feat: final_page_chip * feat: integrating all chips for page_read_write * fixing lib * using field bits() * adding extra communication between checker and final chip * muting clippy * renaming to AIR * adding comments * wip * wip * feat: execution air finished --------- Co-authored-by: bfan <[email protected]> Co-authored-by: Osama Alkhodairy <[email protected]> Co-authored-by: Jonathan Wang <[email protected]> * Add print flag to afi command, update readmes * Update warnings * wip keygen * wip: start prove * Predicate * wip: prove and verify * change branches * Add to_page for Table * Use btreemap * Update functions * Update page to/from * Update tests * Add predicate binary * wip: proof not serializable * chore: patch stuff * add serde bounds * feat: zk commands (not debugged yet) * update mockdb * wip: mold into new format * chore: remove extraneous stuff * [WIP: query-binary] Merge r/w changes (#69) * Add is_less_than_bits chip (#60) * Add is_less_than_bits chip * Address zlangely's comments * Remove chip and use from_bool * Use row_mut * Add comments explaining comparison_check * Add alt version of is_less_than_bits chip * Replace is_less_than_bits with alt version, address comments * Fix lint issues * Feat/is less than bits tuple chip (#63) * Add is_less_than_tuple_bits chip * Incorporate is_less_than_bits feedback into is_less_than_tuple_bits * Add is_less_than_tuple_bits chip * Use match and cmp instead of else if * Adjust for new is_less_than_bits chip * chore: remove range_max field from IsLessThanAir and IsLessThanTupleAir (#65) * chore: derive serialize for proof (#67) * feat: page read write checker (#45) * feat: sorted_limbs chip checking each limb less than limb_bits bits * wip * feat: completed sorted_limbs chip with tests * wip * feat: SortedLimbsChip with LessThan subchip * feat: less_than subchip refactored * feat: rename SortedLimbsChip to AssertSortedChip and write LessThanChip tests * chore: change name of assert sorted chip * chore: fix names in tests for AssertSortedChip * chore: address comments * chore: cleanup * chore: change MAX from generic to instance field for LessThanChip and AssertSortedChip * wip: added extra bits to middle chip trace * wip * adding connection to IsEqualVec chip * feat: IsLessThanChip to compare two numbers * feat: IsLessThanTuple subchip for different limb_bits * test: added tests for partially and non-allocated pages * test: added negative tests * added constraints * adding comments * feat: IsLessThanTupleChip subchip in AssertSortedChip * renaming * removing TODO comments * fixing clippy * chore: renaming to idx and data * chore: address comments first pass * chore: moving page_controller inside page_read * chore: refactor AssertSorted, IsEqual, IsLessThan, and IsLessThanTuple chips * chore: address comments * chore: eliminate high dim poly from IsLessThanTupleChip * chore: fix tests * chore: address comments for AssertSortedChip * chore: cleanup AssertSorted * chore: cleanup * chore: include roundtrip flatten and from_slice tests * feat: flatten and from_slice for IO and Aux columns * wip: final page chip * remove txt file * feat: final_page_chip * feat: integrating all chips for page_read_write * fixing lib * using field bits() * adding extra communication between checker and final chip * muting clippy * renaming to AIR * adding comments * comment fix * optimization to one less bus * comments * moving old page_controller inside page_read * updateing comment * feat: more general FinalPageAir * making IsEqualVecAuxCols clonable * enforcing unallocated rows to be zero * aligning with new less than chip * using Air::eval instead of SubAir::eval * fix comment * removed arguments from load_page for readability * addressing comments and adding common/ directory with Page struct --------- Co-authored-by: bfan <[email protected]> Co-authored-by: Jonathan Wang <[email protected]> * Update to/from page and table tests * Update tests * chore: satisfy clippy (#68) * Fix execution_air test * Update --------- Co-authored-by: TlatoaniHJ <[email protected]> Co-authored-by: bfan05 <[email protected]> Co-authored-by: Jonathan Wang <[email protected]> Co-authored-by: Osama Alkhodairy <[email protected]> Co-authored-by: Zach Langley <[email protected]> * Tmp: remove predicate * Update readme * Update commands for newest rows * feat: add tracing and switch default fri params to log_blowup_factor = 3 * chore: update logging * Fix readme typo * Fix clippy warnings * Update to handle input byte lengths * Remove extraneous code * Revert 9f02efc^..9bad23e * Update logical interface to add byte lengths * Remove generics from logical-interface * merging new Offline Checker changes * Revert "change branches" This reverts commit ec8639f. * Update mock read/write commands * chore: add `mock describe` command * chore: do not overwrite db if exists * chore: remove schema config * chore: switch config back to data_bytes=1024 --------- Co-authored-by: MonkeyKing-1 <[email protected]> Co-authored-by: bfan <[email protected]> Co-authored-by: Osama Alkhodairy <[email protected]> Co-authored-by: Jonathan Wang <[email protected]> Co-authored-by: Zach Langley <[email protected]> Co-authored-by: TlatoaniHJ <[email protected]> * perf: Offline Checker Optimization (#82) * perf: removed 2*data_len columns from the offline checker * renaming to air * Add macros for testing * Additional tests * Remove unused function * Update naming and add comment * Feat/rename page air update from slice (#84) * feat: rename my page air and update from slice * add renamed files * feat: rename final page air * chore: fix lint and rename idx_limb_bits --------- Co-authored-by: Jonathan Wang <[email protected]> * VM binary * Resolve merge conflicts * Add back fibonacci integration test * Redo CLI test * Remove extraneous au directory * Fix lint * Remove keys and proof * Remove commented code * Use FromStr to parse OpCode * VM* -> Vm*, VM -> VirtualMachine * Return Result from VmConfig::read_config_file * Minor zlangley comments * Remove 8 * Use zip for chips and traces Co-authored-by: Zach Langley <[email protected]> * zip_eq -> zip * Use Path and replace unwrap with ? * Removed unnecessary casts * Fix lint * Address jonathan comments, fix proof file path * Delete prove.bin * Use zip_eq and remove unnecessary clones * Use eyre::Result in asm/mod.rs * Fix lint --------- Co-authored-by: Alex Zhao <[email protected]> Co-authored-by: bfan <[email protected]> Co-authored-by: Zach Langley <[email protected]> Co-authored-by: Jonathan Wang <[email protected]> Co-authored-by: Osama Alkhodairy <[email protected]> Co-authored-by: Yu Jiang Tham <[email protected]> Co-authored-by: MonkeyKing-1 <[email protected]> Co-authored-by: Yu Jiang Tham <[email protected]> * Chore/Remove CpuChip (#94) * Remove CpuChip * Remove CpuChip * Rebase * Feat/convert sp1 compiler to output our ISA (#93) * Conversion to ISA working for Fibonacci * Modify signature of conversion functions to allow nontrivial extension field * Fix utility register * Fix translation of load and store instrucctions for size != 1 * Fix SubFIN and DivFIN compilation Note: should add test to check DivFIN * Remove now unused instruction.rs * Fix lint * Fix lint 2 * Return execution from execute_program * fix: error where answer became intermediate columns * fix: error where answer became intermediate columns * fix: fixed width issues, progressing to constraint issues * fix: fixed width issues, progressing to constraint issues * fix: request allocation generation, group_by cols for sorted cases * chore: adjusting tests to have multiplicity in rows * chore: IndexScanPageAir use from_partitioned_slice (#97) * chore: IndexScanPageAir use from_partitioned_slice * chore: directly use local_page and local_aux * chore: address comments * chore: use tip * chore: fixing randomized colliding page generation * fix: caught typo in interactions, unsorted tests pass * fix: bug in sorted page generation, tests now pass * chore: randomizing (trimming) negative test loops * chore: address review comments * feat: page controller loads cached `ProverTraceData` * chore: reduce test cases for speed --------- Co-authored-by: bfan <[email protected]> Co-authored-by: Osama Alkhodairy <[email protected]> Co-authored-by: Jonathan Wang <[email protected]> Co-authored-by: Alex Zhao <[email protected]> Co-authored-by: Yu Jiang Tham <[email protected]> Co-authored-by: MonkeyKing-1 <[email protected]> Co-authored-by: Zach Langley <[email protected]> Co-authored-by: TlatoaniHJ <[email protected]> Co-authored-by: Yu Jiang Tham <[email protected]>
1 parent 812fa4b commit 98f72ae

File tree

26 files changed

+2013
-2
lines changed

26 files changed

+2013
-2
lines changed

chips/src/common/page.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ impl Page {
3737
}
3838
}
3939

40+
pub fn to_2d_vec(&self) -> Vec<Vec<u32>> {
41+
self.rows.iter().map(|row| row.to_vec()).collect()
42+
}
43+
4044
/// Returns a random page with the given parameters in the proper format
4145
/// Note that max_idx and max_data are not inclusive
4246
pub fn random(
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
use std::iter;
2+
3+
use afs_stark_backend::air_builders::PartitionedAirBuilder;
4+
use p3_air::{Air, AirBuilder, BaseAir};
5+
use p3_field::Field;
6+
use p3_matrix::Matrix;
7+
8+
use crate::common::page_cols::PageCols;
9+
use crate::is_equal_vec::columns::IsEqualVecIOCols;
10+
use crate::sub_chip::{AirConfig, SubAir};
11+
12+
use super::columns::{GroupByAuxCols, GroupByCols, GroupedPageCols};
13+
use super::GroupByAir;
14+
15+
impl<F: Field> BaseAir<F> for GroupByAir {
16+
fn width(&self) -> usize {
17+
self.get_width()
18+
}
19+
}
20+
21+
impl<AB: PartitionedAirBuilder> Air<AB> for GroupByAir
22+
where
23+
AB::M: Clone,
24+
{
25+
/// Re-references builder into page_trace and aux_trace, then slices into local and next rows
26+
/// to evaluate using SubAir::eval(GroupByAir)
27+
fn eval(&self, builder: &mut AB) {
28+
let page_trace: &<AB as AirBuilder>::M = &builder.partitioned_main()[0];
29+
let aux_trace: &<AB as AirBuilder>::M = &builder.partitioned_main()[1];
30+
31+
// get the current row and the next row
32+
let (local_page, next_page) = (page_trace.row_slice(0), page_trace.row_slice(1));
33+
let (local_aux, next_aux) = (aux_trace.row_slice(0), aux_trace.row_slice(1));
34+
35+
let local_cols = GroupByCols::from_partitioned_slice(&local_page, &local_aux, self);
36+
let next_cols = GroupByCols::from_partitioned_slice(&next_page, &next_aux, self);
37+
drop((local_page, next_page, local_aux, next_aux));
38+
39+
SubAir::eval(
40+
self,
41+
builder,
42+
(local_cols.page, next_cols.page),
43+
(local_cols.aux, next_cols.aux),
44+
);
45+
}
46+
}
47+
48+
impl AirConfig for GroupByAir {
49+
type Cols<T> = GroupByCols<T>;
50+
}
51+
52+
impl<AB: PartitionedAirBuilder> SubAir<AB> for GroupByAir {
53+
/// `io` consists of `(local_page, next_page)` only the page, including `is_alloc`
54+
type IoView = (PageCols<AB::Var>, PageCols<AB::Var>);
55+
/// `aux.0` is `local.aux`, `aux.1` is `next.aux`.
56+
///
57+
/// `aux` consists of everything that isn't `io`, including
58+
/// `sorted_group_by`, `sorted_group_by_alloc`, `aggregated`, and `partial_aggregated`
59+
type AuxView = (GroupByAuxCols<AB::Var>, GroupByAuxCols<AB::Var>);
60+
61+
/// Constrains `sorted_group_by` along with `partial_aggregated` to hold correct values
62+
/// with minimal constraints.
63+
///
64+
/// In fact `sorted_group_by` is not necessarily sorted. The only constraints are that
65+
/// allocated rows are placed at the beginning, and like rows are placed together.
66+
///
67+
/// Like rows being placed together is enforced by the constraints on `MyFinalPage`, since
68+
/// all rows marked `final` are sent to MyFinalPage and hence must be pairwise distinct.
69+
fn eval(
70+
&self,
71+
builder: &mut AB,
72+
(local_page, next_page): Self::IoView,
73+
(local_aux, next_aux): Self::AuxView,
74+
) {
75+
// Return either grouped columns (if not None) or the respective columns from the page
76+
// (the latter occurs if the page is already assumed to be grouped appropriated)
77+
let get_grouped = |page: PageCols<AB::Var>, grouped: Option<GroupedPageCols<AB::Var>>| {
78+
grouped.unwrap_or_else(|| GroupedPageCols {
79+
is_alloc: page.is_alloc,
80+
group_by: self.group_by_cols.iter().map(|&i| page.data[i]).collect(),
81+
to_aggregate: page.data[self.aggregated_col],
82+
})
83+
};
84+
let local_grouped = get_grouped(local_page, local_aux.grouped);
85+
let next_grouped = get_grouped(next_page, next_aux.grouped);
86+
87+
let is_equal_io = IsEqualVecIOCols {
88+
x: iter::once(local_grouped.is_alloc)
89+
.chain(local_grouped.group_by)
90+
.collect(),
91+
y: iter::once(next_grouped.is_alloc)
92+
.chain(next_grouped.group_by)
93+
.collect(),
94+
prod: local_aux.eq_next,
95+
};
96+
97+
// constrain eq_next to hold the correct value
98+
SubAir::eval(
99+
&self.is_equal_vec_air,
100+
&mut builder.when_transition(),
101+
is_equal_io,
102+
local_aux.is_equal_vec_aux,
103+
);
104+
105+
// if grouped is_alloc changes, then is_final must be 1, even if eq_next is also 1
106+
let grouped_is_alloc_diff = local_grouped.is_alloc - next_grouped.is_alloc;
107+
builder.when_transition().assert_eq(
108+
grouped_is_alloc_diff.clone(),
109+
grouped_is_alloc_diff * local_aux.is_final,
110+
);
111+
112+
// constrain is_final to be 1 iff eq_next == false and local_grouped.is_alloc is 1
113+
builder.assert_eq(
114+
local_aux.is_final,
115+
local_grouped.is_alloc - local_grouped.is_alloc * local_aux.eq_next,
116+
);
117+
118+
// constrain last vector equality to 0
119+
// because previously only constrained on transition
120+
builder.when_last_row().assert_zero(local_aux.eq_next);
121+
122+
// initialize partial sum at first row
123+
builder
124+
.when_first_row()
125+
.assert_eq(local_aux.partial_aggregated, local_grouped.to_aggregate);
126+
127+
// constrain partials to sum correctly
128+
builder.when_transition().assert_eq(
129+
next_aux.partial_aggregated,
130+
local_aux.eq_next * local_aux.partial_aggregated + next_grouped.to_aggregate,
131+
);
132+
133+
// constrain allocated rows come first
134+
builder.when_transition().assert_eq(
135+
next_grouped.is_alloc * local_grouped.is_alloc,
136+
next_grouped.is_alloc,
137+
);
138+
}
139+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
use std::iter;
2+
3+
use crate::sub_chip::SubAirBridge;
4+
use afs_stark_backend::interaction::{AirBridge, Interaction};
5+
use p3_air::VirtualPairCol;
6+
use p3_field::PrimeField64;
7+
8+
use super::columns::GroupByCols;
9+
use super::GroupByAir;
10+
11+
impl<F: PrimeField64> AirBridge<F> for GroupByAir {
12+
fn sends(&self) -> Vec<Interaction<F>> {
13+
let col_indices_vec: Vec<usize> = (0..self.get_width()).collect();
14+
let col_indices = GroupByCols::from_slice(&col_indices_vec, self);
15+
SubAirBridge::sends(self, col_indices)
16+
}
17+
18+
fn receives(&self) -> Vec<Interaction<F>> {
19+
let col_indices_vec: Vec<usize> = (0..self.get_width()).collect();
20+
let col_indices = GroupByCols::from_slice(&col_indices_vec, self);
21+
SubAirBridge::receives(self, col_indices)
22+
}
23+
}
24+
25+
impl<F: PrimeField64> SubAirBridge<F> for GroupByAir {
26+
/// Sends desired columns (group_by and to_aggregate) from input page internally with count
27+
/// `is_alloc`, and sends answer columns with count `is_final`.
28+
fn sends(&self, col_indices: GroupByCols<usize>) -> Vec<Interaction<F>> {
29+
assert_eq!(col_indices.aux.grouped.is_some(), !self.sorted);
30+
let group_by_col_indices = if let Some(grouped) = col_indices.aux.grouped {
31+
grouped.group_by
32+
} else {
33+
self.group_by_cols
34+
.iter()
35+
.map(|&i| col_indices.page.data[i])
36+
.collect()
37+
};
38+
// fields = group_by cols, partial_aggregated
39+
// count = is_final
40+
let output_sent_fields = group_by_col_indices
41+
.into_iter()
42+
.chain(iter::once(col_indices.aux.partial_aggregated))
43+
.map(VirtualPairCol::single_main)
44+
.collect();
45+
let output_count = VirtualPairCol::single_main(col_indices.aux.is_final);
46+
let mut interactions = vec![Interaction {
47+
fields: output_sent_fields,
48+
count: output_count,
49+
argument_index: self.output_bus,
50+
}];
51+
if !self.sorted {
52+
// Must do internal grouping of page based on group_by columns
53+
// Sends from columns in input page to internal bus
54+
let internal_sent_fields = self
55+
.group_by_cols
56+
.iter()
57+
.chain(iter::once(&self.aggregated_col))
58+
.map(|&i| VirtualPairCol::single_main(col_indices.page.data[i]))
59+
.collect();
60+
let internal_count = VirtualPairCol::single_main(col_indices.page.is_alloc);
61+
62+
interactions.push(Interaction {
63+
fields: internal_sent_fields,
64+
count: internal_count,
65+
argument_index: self.internal_bus,
66+
});
67+
}
68+
interactions
69+
}
70+
71+
/// Receives desired columns (`sorted_group_by` and `aggregated`) internally with count
72+
/// `is_alloc`.
73+
fn receives(&self, col_indices: GroupByCols<usize>) -> Vec<Interaction<F>> {
74+
if self.sorted {
75+
return vec![];
76+
}
77+
78+
let grouped = col_indices.aux.grouped.unwrap();
79+
let internal_received_fields: Vec<VirtualPairCol<F>> = grouped
80+
.group_by
81+
.into_iter()
82+
.chain(iter::once(grouped.to_aggregate))
83+
.map(VirtualPairCol::single_main)
84+
.collect();
85+
let internal_count = VirtualPairCol::single_main(grouped.is_alloc);
86+
87+
vec![Interaction {
88+
fields: internal_received_fields,
89+
count: internal_count,
90+
argument_index: self.internal_bus,
91+
}]
92+
}
93+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
use super::GroupByAir;
2+
use crate::{common::page_cols::PageCols, is_equal_vec::columns::IsEqualVecAuxCols};
3+
use std::ops::Range;
4+
5+
/// Since `GroupByChip` contains a `LessThanChip` subchip and an `IsEqualVecChip` subchip, a subset of
6+
/// the columns are those of the `LessThanChip` and `IsEqualVecChip`.
7+
///
8+
/// The `io` columns consist only of the cached page, because output is sent to `MyFinalPage`. The
9+
/// `aux` columns are all other columns.
10+
///
11+
/// Implements two methods:
12+
///
13+
/// * `from_slice`: Takes a slice and returns a `GroupByCols` struct.
14+
/// * `index_map`: Returns a `GroupByColsIndexMap` struct, used to index all other structs and
15+
/// defines the order of segments in a slice.
16+
pub struct GroupByCols<T> {
17+
/// Page with `idx_len = 0` because the page does not need an index.
18+
pub page: PageCols<T>,
19+
pub aux: GroupByAuxCols<T>,
20+
}
21+
22+
/// The `aux` columns are all non-cached columns.
23+
pub struct GroupByAuxCols<T> {
24+
/// If page is not already grouped, extra columns are needed to do the grouping.
25+
pub grouped: Option<GroupedPageCols<T>>,
26+
pub partial_aggregated: T,
27+
pub is_final: T,
28+
pub eq_next: T,
29+
pub is_equal_vec_aux: IsEqualVecAuxCols<T>,
30+
}
31+
32+
/// The columns that are relevant to the GroupBy operation.
33+
pub struct GroupedPageCols<T> {
34+
pub is_alloc: T,
35+
pub group_by: Vec<T>,
36+
pub to_aggregate: T,
37+
}
38+
39+
/// Maps parts of the `GroupByCols` to their indices. Note that `sorted_group_by_combined_range` is
40+
/// a range containing `sorted_group_by_alloc` and `sorted_group_by_range`. Indexes by the
41+
/// respective partition, not by the complete row.
42+
pub struct GroupByColsIndexMap {
43+
pub allocated_idx: usize,
44+
pub page_range: Range<usize>,
45+
pub sorted_group_by_alloc: usize,
46+
pub sorted_group_by_range: Range<usize>,
47+
pub sorted_group_by_combined_range: Range<usize>,
48+
pub to_aggregate: usize,
49+
pub partial_aggregated: usize,
50+
pub is_final: usize,
51+
pub eq_next: usize,
52+
pub is_equal_vec_aux_range: Range<usize>,
53+
}
54+
55+
impl<T: Clone> GroupByCols<T> {
56+
/// Takes a slice and returns a `GroupByCols` struct.
57+
pub fn from_slice(slc: &[T], group_by_air: &GroupByAir) -> Self {
58+
assert_eq!(slc.len(), group_by_air.get_width());
59+
Self::from_partitioned_slice(
60+
&slc[..group_by_air.page_width],
61+
&slc[group_by_air.page_width..],
62+
group_by_air,
63+
)
64+
}
65+
66+
pub fn from_partitioned_slice(page: &[T], aux: &[T], group_by_air: &GroupByAir) -> Self {
67+
assert_eq!(page.len(), group_by_air.page_width);
68+
assert_eq!(
69+
aux.len(),
70+
group_by_air.get_width() - group_by_air.page_width
71+
);
72+
73+
let index_map = GroupByCols::<T>::index_map(group_by_air);
74+
75+
let grouped = if !group_by_air.sorted {
76+
Some(GroupedPageCols {
77+
is_alloc: aux[index_map.sorted_group_by_alloc].clone(),
78+
group_by: aux[index_map.sorted_group_by_range].to_vec(),
79+
to_aggregate: aux[index_map.to_aggregate].clone(),
80+
})
81+
} else {
82+
None
83+
};
84+
85+
let partial_aggregated = aux[index_map.partial_aggregated].clone();
86+
let is_final = aux[index_map.is_final].clone();
87+
let eq_next = aux[index_map.eq_next].clone();
88+
let is_equal_vec_aux = IsEqualVecAuxCols::from_slice(
89+
&aux[index_map.is_equal_vec_aux_range],
90+
group_by_air.group_by_cols.len() + 1,
91+
);
92+
93+
let data_len = group_by_air.page_width - 1;
94+
Self {
95+
page: PageCols::from_slice(page, 0, data_len),
96+
aux: GroupByAuxCols {
97+
grouped,
98+
partial_aggregated,
99+
is_final,
100+
eq_next,
101+
is_equal_vec_aux,
102+
},
103+
}
104+
}
105+
106+
/// Returns a `GroupByColsIndexMap` struct, used to index all other structs and defines the
107+
/// order of segments in a slice. Indexes by the respective partition, not by the complete row.
108+
pub fn index_map(group_by_air: &GroupByAir) -> GroupByColsIndexMap {
109+
let num_group_by = group_by_air.group_by_cols.len();
110+
let eq_vec_width = IsEqualVecAuxCols::<T>::get_width(num_group_by + 1);
111+
112+
let allocated_idx = 0;
113+
let page_range = if !group_by_air.sorted {
114+
allocated_idx + 1..group_by_air.page_width
115+
} else {
116+
0..0
117+
};
118+
let sorted_group_by_alloc = 0;
119+
let sorted_group_by_range =
120+
sorted_group_by_alloc + 1..sorted_group_by_alloc + 1 + num_group_by;
121+
let sorted_group_by_combined_range = sorted_group_by_alloc..sorted_group_by_range.end;
122+
let aggregated_idx = sorted_group_by_range.end;
123+
let partial_aggregated_idx = if !group_by_air.sorted {
124+
aggregated_idx + 1
125+
} else {
126+
0
127+
};
128+
let is_final_idx = partial_aggregated_idx + 1;
129+
let eq_next_idx = is_final_idx + 1;
130+
let is_equal_vec_aux_range = eq_next_idx + 1..eq_next_idx + 1 + eq_vec_width;
131+
132+
GroupByColsIndexMap {
133+
allocated_idx,
134+
page_range,
135+
sorted_group_by_alloc,
136+
sorted_group_by_range,
137+
sorted_group_by_combined_range,
138+
to_aggregate: aggregated_idx,
139+
partial_aggregated: partial_aggregated_idx,
140+
is_final: is_final_idx,
141+
eq_next: eq_next_idx,
142+
is_equal_vec_aux_range,
143+
}
144+
}
145+
}

0 commit comments

Comments
 (0)