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

Integrate single step #2338

Draft
wants to merge 41 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
20cba4f
Integrate single step functions.
chriseth Jan 14, 2025
0d6d957
Human-readable formatting of JIT witgen (error) state.
chriseth Jan 16, 2025
dffe70a
remove word repetition.
chriseth Jan 20, 2025
1cdb383
Elevate some trace messages to debug.
chriseth Jan 20, 2025
257f161
Termination plus merging.
chriseth Jan 20, 2025
d964409
Ignore prover functions for now.
chriseth Jan 20, 2025
09e1f88
Fix block size.
chriseth Jan 20, 2025
8bb0601
Merge branch 'nice_jit_processor_error_summary' into testa
chriseth Jan 20, 2025
4d23a9a
Report better error.
chriseth Jan 20, 2025
abb49bc
Format connection identities.
chriseth Jan 20, 2025
2aa4399
Merge branch 'nice_jit_processor_error_summary' into integrate_single…
chriseth Jan 20, 2025
3103fe6
Pad properly.
chriseth Jan 20, 2025
7cf57b3
Merge branch 'nice_jit_processor_error_summary' into integrate_single…
chriseth Jan 20, 2025
ff84937
Fix formatting and add test.
chriseth Jan 21, 2025
f9b2523
Merge branch 'nice_jit_processor_error_summary' into integrate_single…
chriseth Jan 21, 2025
eda7805
Mark "unselected" lookups as complete.
chriseth Jan 21, 2025
178cba3
Access to nonconstant fixed columns.
chriseth Jan 21, 2025
bbed563
Interpreter.
chriseth Jan 21, 2025
4533878
Clean up known.
chriseth Jan 21, 2025
8fe94ac
clarify comment.
chriseth Jan 21, 2025
a52e814
Merge branch 'access_to_nonconstant_fixed_columns' into integrate_sin…
chriseth Jan 21, 2025
19c42ef
Merge remote-tracking branch 'origin/main' into integrate_single_step
chriseth Jan 23, 2025
76c734b
Merge remote-tracking branch 'origin/main' into integrate_single_step
chriseth Jan 23, 2025
c6c0490
fix merge conflicts.
chriseth Jan 23, 2025
12c351b
fix expectations after merge.
chriseth Jan 23, 2025
a4bf424
add comment.
chriseth Jan 23, 2025
57aece3
Fix last row.
chriseth Jan 23, 2025
ac96acb
trace.
chriseth Jan 23, 2025
6d2bb8f
Compute last row.
chriseth Jan 23, 2025
6e43430
fix
chriseth Jan 24, 2025
0d1ef11
remove prover functions for now.
chriseth Jan 24, 2025
ea3885c
combine functions.
chriseth Jan 24, 2025
8716d0c
typo
chriseth Jan 24, 2025
90ccad4
Extract compute_row_block.
chriseth Jan 24, 2025
9abf7e3
fix
chriseth Jan 24, 2025
abcfc56
update comment.
chriseth Jan 24, 2025
ca9c312
Merge remote-tracking branch 'origin/extract_compute_row_block' into …
chriseth Jan 24, 2025
554f4ca
Merge remote-tracking branch 'origin/main' into integrate_single_step
chriseth Jan 24, 2025
065cd80
simplify
chriseth Jan 24, 2025
84fa507
Merge remote-tracking branch 'origin/main' into integrate_single_step
chriseth Jan 27, 2025
65cc013
Merge remote-tracking branch 'origin/main' into integrate_single_step
chriseth Jan 28, 2025
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: 3 additions & 3 deletions executor/src/witgen/data_structures/column_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ use std::{
use powdr_ast::analyzed::{PolyID, PolynomialType};

// Marker types for each PolynomialType
#[derive(Clone, Copy)]
#[derive(Debug, Clone, Copy)]
pub struct Witness;

#[derive(Clone, Copy)]
#[derive(Debug, Clone, Copy)]
pub struct Fixed;

pub trait PolynomialTypeTrait {
Expand All @@ -30,7 +30,7 @@ pub type FixedColumnMap<V> = ColumnMap<V, Fixed>;
/// A Map indexed by polynomial ID, for a specific polynomial type (e.g. fixed or witness).
/// For performance reasons, it uses a Vec<V> internally and assumes that the polynomial IDs
/// are contiguous.
#[derive(Clone)]
#[derive(Debug, Clone)]
pub struct ColumnMap<V, T: PolynomialTypeTrait> {
values: Vec<V>,
_ptype: PhantomData<T>,
Expand Down
7 changes: 7 additions & 0 deletions executor/src/witgen/data_structures/finalizable_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,13 @@ impl<'a, T: FieldElement> FinalizableData<'a, T> {
}
}

/// Returns this data as a vector of rows in progress.
/// Panics if any data has been finalized already.
pub fn into_rows_in_progress(self) -> Vec<Row<T>> {
assert!(self.finalized_data.is_empty());
self.post_finalized_data
}

pub fn extend(&mut self, other: Self) {
assert!(other.finalized_data.is_empty());
self.post_finalized_data.extend(other.post_finalized_data);
Expand Down
4 changes: 2 additions & 2 deletions executor/src/witgen/jit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ mod debug_formatter;
mod effect;
pub(crate) mod function_cache;
mod interpreter;
mod processor;
pub(crate) mod processor;
mod prover_function_heuristics;
mod single_step_processor;
pub(crate) mod single_step_processor;
mod symbolic_expression;
mod variable;
pub(crate) mod witgen_inference;
Expand Down
1 change: 1 addition & 0 deletions executor/src/witgen/jit/prover_function_heuristics.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(unused)]
use powdr_ast::{
analyzed::{Expression, PolynomialReference, Reference},
parsed::{FunctionCall, FunctionKind, LambdaExpression, Number},
Expand Down
151 changes: 119 additions & 32 deletions executor/src/witgen/jit/single_step_processor.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
#![allow(dead_code)]

use itertools::Itertools;
use powdr_ast::analyzed::{
AlgebraicExpression as Expression, AlgebraicReference, PolyID, PolynomialType,
};
use powdr_number::FieldElement;

use crate::witgen::{machines::MachineParts, FixedData};
use powdr_number::{FieldElement, KnownField};

use crate::witgen::{
data_structures::{
finalizable_data::{ColumnLayout, CompactDataRef},
mutable_state::MutableState,
},
jit::compiler::compile_effects,
machines::MachineParts,
FixedData, QueryCallback,
};

use super::{
compiler::WitgenFunction,
effect::Effect,
processor::Processor,
prover_function_heuristics::decode_simple_prover_functions,
variable::{Cell, Variable},
witgen_inference::{CanProcessCall, FixedEvaluator, WitgenInference},
};
Expand All @@ -23,17 +29,85 @@ const SINGLE_STEP_MACHINE_MAX_BRANCH_DEPTH: usize = 6;
pub struct SingleStepProcessor<'a, T: FieldElement> {
fixed_data: &'a FixedData<'a, T>,
machine_parts: MachineParts<'a, T>,
column_layout: ColumnLayout,
single_step_function: Option<Option<WitgenFunction<T>>>,
}

impl<'a, T: FieldElement> SingleStepProcessor<'a, T> {
pub fn new(fixed_data: &'a FixedData<'a, T>, machine_parts: MachineParts<'a, T>) -> Self {
pub fn new(
fixed_data: &'a FixedData<'a, T>,
machine_parts: MachineParts<'a, T>,
column_layout: ColumnLayout,
) -> Self {
SingleStepProcessor {
fixed_data,
machine_parts,
column_layout,
single_step_function: None,
}
}

pub fn generate_code(
pub fn try_compile(&mut self, can_process: impl CanProcessCall<T>) -> bool {
if !matches!(T::known_field(), Some(KnownField::GoldilocksField)) {
// Currently, we only support the Goldilocks fields
// We could run the interpreter on other fields, though.
return false;
}

match self.single_step_function {
Some(None) => return false,
Some(Some(_)) => return true,
None => {}
}
match self.generate_code(can_process.clone()) {
Err(e) => {
// These errors can be pretty verbose and are quite common currently.
let e = e.to_string().lines().take(5).join("\n");
log::debug!("=> Error generating JIT code: {e}\n...");
false
}
Ok(code) => {
log::debug!("Generated code ({} steps)", code.len());
log::debug!("Compiling effects...");

let known_inputs = self
.machine_parts
.witnesses
.iter()
.map(|&id| self.cell(id, 0))
.collect_vec();
self.single_step_function = Some(Some(
compile_effects(
self.column_layout.first_column_id,
self.column_layout.column_count,
&known_inputs,
&code,
)
.unwrap(),
));
log::trace!("Compilation done.");
true
}
}
}

/// Computes the next row from the previous row.
/// Due to fixed columns being evaluated, the caller must ensure that
/// neither the already known nor the to be computed row are the first or last row.
/// This means that the two first rows must be fully computed.
pub fn compute_next_row<'d, Q: QueryCallback<T>>(
&self,
mutable_state: &MutableState<'a, T, Q>,
data: CompactDataRef<'d, T>,
) {
assert!(data.row_offset > 0);
let Some(Some(f)) = self.single_step_function.as_ref() else {
panic!("try_compile must be called first")
};
f.call(self.fixed_data, mutable_state, &mut [], data);
}

fn generate_code(
&self,
can_process: impl CanProcessCall<T>,
) -> Result<Vec<Effect<T, Variable>>, String> {
Expand Down Expand Up @@ -67,18 +141,18 @@ impl<'a, T: FieldElement> SingleStepProcessor<'a, T> {
})
.collect_vec();

let mut witgen =
let witgen =
WitgenInference::new(self.fixed_data, self, known_variables, complete_identities);

let prover_assignments = decode_simple_prover_functions(&self.machine_parts)
.into_iter()
.map(|(col_name, value)| (self.column(&col_name), value))
.collect_vec();
// let prover_assignments = decode_simple_prover_functions(&self.machine_parts)
// .into_iter()
// .map(|(col_name, value)| (self.column(&col_name), value))
// .collect_vec();

// TODO we should only do it if other methods fail, because it is "provide_if_unknown"
for (col, value) in &prover_assignments {
witgen.assign_constant(col, 1, *value);
}
// // TODO we should only do it if other methods fail, because it is "provide_if_unknown"
// for (col, value) in &prover_assignments {
// witgen.assign_constant(col, 1, *value);
// }

Processor::new(
self.fixed_data,
Expand All @@ -87,8 +161,19 @@ impl<'a, T: FieldElement> SingleStepProcessor<'a, T> {
requested_known,
SINGLE_STEP_MACHINE_MAX_BRANCH_DEPTH,
)
// We use a block size of two since we need two completed submachine calls,
// and we start out with all submachine calls on the first row already completed.
.with_block_size(2)
.generate_code(can_process, witgen)
.map_err(|e| e.to_string())
.map_err(|e| {
let err_str = e.to_string();
log::trace!("\nCode generation faild for main machine:\n {err_str}");
let shortened_error = err_str
.lines()
.take(10)
.format("\n ");
format!("Code generation failed: {shortened_error}\nRun with RUST_LOG=trace to see the code generated so far.")
})
.map(|r| r.code)
}

Expand All @@ -100,6 +185,7 @@ impl<'a, T: FieldElement> SingleStepProcessor<'a, T> {
})
}

#[allow(unused)]
fn column(&self, name: &str) -> Expression<T> {
Expression::Reference(AlgebraicReference {
name: name.to_string(),
Expand Down Expand Up @@ -129,7 +215,7 @@ mod test {
use powdr_number::GoldilocksField;

use crate::witgen::{
data_structures::mutable_state::MutableState,
data_structures::{finalizable_data::ColumnLayout, mutable_state::MutableState},
global_constraints,
jit::effect::{format_code, Effect},
machines::KnownMachine,
Expand Down Expand Up @@ -166,7 +252,8 @@ mod test {
let mutable_state = MutableState::new(machines.into_iter(), &|_| {
Err("Query not implemented".to_string())
});
SingleStepProcessor::new(&fixed_data, machine_parts)
let layout = ColumnLayout::from_id_list(machine_parts.witnesses.iter());
SingleStepProcessor::new(&fixed_data, machine_parts, layout)
.generate_code(&mutable_state)
.map_err(|e| e.to_string())
}
Expand Down Expand Up @@ -206,12 +293,13 @@ namespace M(256);
let err = generate_single_step(input, "M").err().unwrap();
assert_eq!(
err.to_string(),
"Unable to derive algorithm to compute required values: \
No variable available to branch on.\nThe following variables or values are still missing: M::Y[1]\n\
The following branch decisions were taken:\n\
\n\
Generated code so far:\n\
M::X[1] = M::X[0];"
"Code generation failed: Unable to derive algorithm to compute required values: No variable available to branch on.
The following variables or values are still missing: M::Y[1]
The following branch decisions were taken:

Generated code so far:
M::X[1] = M::X[0];
Run with RUST_LOG=trace to see the code generated so far."
);
}

Expand Down Expand Up @@ -325,12 +413,11 @@ VM::instr_mul[1] = 1;"
Ok(_) => panic!("Expected error"),
Err(e) => {
let expected = "\
Main::is_arith $ [ Main::a, Main::b, Main::c ]
??? 2 ??? ???

Main::is_arith 2 Main::b Main::c
??? ??? ???
";
Main::is_arith $ [ Main::a, Main::b, Main::c ]
??? 2 ??? ???
Copy link
Member Author

Choose a reason for hiding this comment

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

Not really sure why this is now indented.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, I used the same code as we have for the block machine, where it is indented as well.


Main::is_arith 2 Main::b Main::c
??? ??? ???";
assert!(
e.contains(expected),
"Error did not contain expected substring. Error:\n{e}\nExpected substring:\n{expected}"
Expand Down
Loading
Loading