|
1 |
| -use std::{collections::BTreeMap, io, marker::PhantomData, path::PathBuf, sync::Arc}; |
| 1 | +use std::{ |
| 2 | + collections::BTreeMap, |
| 3 | + hash::{DefaultHasher, Hash, Hasher}, |
| 4 | + io, |
| 5 | + marker::PhantomData, |
| 6 | + path::PathBuf, |
| 7 | + sync::Arc, |
| 8 | +}; |
2 | 9 |
|
3 | 10 | use connection_constraint_checker::{Connection, ConnectionConstraintChecker};
|
4 | 11 | use machine::Machine;
|
5 | 12 | use polynomial_constraint_checker::PolynomialConstraintChecker;
|
6 |
| -use powdr_ast::analyzed::Analyzed; |
| 13 | +use powdr_ast::{ |
| 14 | + analyzed::{AlgebraicExpression, Analyzed}, |
| 15 | + parsed::visitor::AllChildren, |
| 16 | +}; |
7 | 17 | use powdr_executor::{constant_evaluator::VariablySizedColumn, witgen::WitgenCallback};
|
8 | 18 | use powdr_number::{DegreeType, FieldElement};
|
9 | 19 |
|
@@ -70,37 +80,61 @@ impl<F: FieldElement> Backend<F> for MockBackend<F> {
|
70 | 80 | &self,
|
71 | 81 | witness: &[(String, Vec<F>)],
|
72 | 82 | prev_proof: Option<Proof>,
|
73 |
| - _witgen_callback: WitgenCallback<F>, |
| 83 | + witgen_callback: WitgenCallback<F>, |
74 | 84 | ) -> Result<Proof, Error> {
|
75 | 85 | if prev_proof.is_some() {
|
76 | 86 | unimplemented!();
|
77 | 87 | }
|
78 | 88 |
|
| 89 | + let challenges = self |
| 90 | + .machine_to_pil |
| 91 | + .values() |
| 92 | + .flat_map(|pil| pil.identities.iter()) |
| 93 | + .flat_map(|identity| identity.all_children()) |
| 94 | + .filter_map(|expr| match expr { |
| 95 | + AlgebraicExpression::Challenge(challenge) => { |
| 96 | + // Use the hash of the ID as the challenge. |
| 97 | + // This way, if the same challenge is used by different machines, they will |
| 98 | + // have the same value. |
| 99 | + let mut hasher = DefaultHasher::new(); |
| 100 | + challenge.id.hash(&mut hasher); |
| 101 | + Some((challenge.id, F::from(hasher.finish()))) |
| 102 | + } |
| 103 | + _ => None, |
| 104 | + }) |
| 105 | + .collect::<BTreeMap<_, _>>(); |
| 106 | + |
79 | 107 | let machines = self
|
80 | 108 | .machine_to_pil
|
| 109 | + // TODO: We should probably iterate in parallel, because Machine::try_new might generate |
| 110 | + // later-stage witnesses, which is expensive. |
| 111 | + // However, for now, doing it sequentially simplifies debugging. |
81 | 112 | .iter()
|
82 |
| - .filter_map(|(machine, pil)| { |
83 |
| - Machine::try_new(machine.clone(), witness, &self.fixed, pil) |
| 113 | + .filter_map(|(machine_name, pil)| { |
| 114 | + Machine::try_new( |
| 115 | + machine_name.clone(), |
| 116 | + witness, |
| 117 | + &self.fixed, |
| 118 | + pil, |
| 119 | + &witgen_callback, |
| 120 | + &challenges, |
| 121 | + ) |
84 | 122 | })
|
85 | 123 | .map(|machine| (machine.machine_name.clone(), machine))
|
86 | 124 | .collect::<BTreeMap<_, _>>();
|
87 | 125 |
|
88 |
| - let mut is_ok = true; |
89 |
| - for (_, machine) in machines.iter() { |
90 |
| - let result = PolynomialConstraintChecker::new(machine).check(); |
91 |
| - is_ok &= !result.has_errors(); |
92 |
| - } |
93 |
| - |
94 |
| - is_ok &= ConnectionConstraintChecker { |
| 126 | + let is_ok = machines.values().all(|machine| { |
| 127 | + !PolynomialConstraintChecker::new(machine, &challenges) |
| 128 | + .check() |
| 129 | + .has_errors() |
| 130 | + }) && ConnectionConstraintChecker { |
95 | 131 | connections: &self.connections,
|
96 | 132 | machines,
|
| 133 | + challenges: &challenges, |
97 | 134 | }
|
98 | 135 | .check()
|
99 | 136 | .is_ok();
|
100 | 137 |
|
101 |
| - // TODO: |
102 |
| - // - Check later-stage witness |
103 |
| - |
104 | 138 | match is_ok {
|
105 | 139 | true => Ok(Vec::new()),
|
106 | 140 | false => Err(Error::BackendError("Constraint check failed".to_string())),
|
|
0 commit comments