Inline only at end (#3173)

Fixes https://github.com/powdr-labs/powdr/issues/3113

---------

Co-authored-by: Georg Wiese <georgwiese@gmail.com>
Co-authored-by: schaeff <thibaut@powdrlabs.com>
This commit is contained in:
chriseth
2025-08-25 17:41:02 +02:00
committed by GitHub
parent 608a1f09ca
commit 2748ac0579
14 changed files with 207 additions and 203 deletions

View File

@@ -32,21 +32,28 @@ pub fn replace_constrained_witness_columns<
.indexed_system()
.algebraic_constraints()
.len();
for curr_idx in (0..constraint_count).rev() {
let constraint = &constraint_system.indexed_system().algebraic_constraints()[curr_idx];
loop {
let inlined_vars_count = inlined_vars.len();
for curr_idx in (0..constraint_count).rev() {
let constraint = &constraint_system.indexed_system().algebraic_constraints()[curr_idx];
for (var, expr) in find_inlinable_variables(constraint) {
if should_inline(&var, &expr, constraint_system.indexed_system()) {
log::trace!("Substituting {var} = {expr}");
log::trace!(" (from identity {constraint})");
for (var, expr) in find_inlinable_variables(constraint) {
if should_inline(&var, &expr, constraint_system.indexed_system()) {
log::trace!("Substituting {var} = {expr}");
log::trace!(" (from identity {constraint})");
constraint_system.substitute_by_unknown(&var, &expr);
to_remove_idx.insert(curr_idx);
inlined_vars.insert(var);
constraint_system.substitute_by_unknown(&var, &expr);
to_remove_idx.insert(curr_idx);
inlined_vars.insert(var);
break;
break;
}
}
}
if inlined_vars.len() == inlined_vars_count {
// No more variables to inline
break;
}
}
// remove inlined constraints from system

View File

@@ -363,6 +363,10 @@ where
while let Some(item) = self.constraint_system.pop_front() {
let effects = match item {
ConstraintRef::AlgebraicConstraint(c) => {
if let Some((v1, expr)) = is_simple_equivalence(c) {
self.apply_assignment(&v1, &expr);
continue;
}
c.solve(&self.range_constraints)
.map_err(Error::QseSolvingError)?
.effects
@@ -556,6 +560,24 @@ where
}
}
fn is_simple_equivalence<T: RuntimeConstant, V: Clone + Ord + Eq>(
expr: &GroupedExpression<T, V>,
) -> Option<(V, GroupedExpression<T, V>)> {
if !expr.is_affine() {
return None;
}
let (_, linear, offset) = expr.components();
let [(v1, c1), (v2, c2)] = linear.collect_vec().try_into().ok()?;
if offset.is_zero() && (c1.is_one() || c2.is_one()) && (c1.clone() + c2.clone()).is_zero() {
Some((
v2.clone(),
GroupedExpression::from_unknown_variable(v1.clone()),
))
} else {
None
}
}
/// The currently known range constraints for the variables.
pub struct RangeConstraints<T: FieldElement, V> {
pub range_constraints: HashMap<V, RangeConstraint<T>>,