Skip to content

Commit c7fd4f4

Browse files
committed
sca: backwards substitution terminates, but with unexpected result
1 parent be3f1f0 commit c7fd4f4

File tree

2 files changed

+43
-10
lines changed

2 files changed

+43
-10
lines changed

patronus-sca/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ rust-version.workspace = true
1313
patronus = { path = "../patronus" }
1414
baa = {version = "0.17.1", features = ["bigint"]}
1515
rustc-hash.workspace = true
16-
polysub = "0.1.7"
16+
polysub = "0.1.8"

patronus-sca/src/lib.rs

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use baa::{BitVecOps, BitVecValue, BitVecValueRef};
66
use patronus::expr::traversal::TraversalCmd;
77
use patronus::expr::{
88
Context, DenseExprMetaData, Expr, ExprRef, ForEachChild, SerializableIrNode, Simplifier,
9-
SparseExprMap, TypeCheck, WidthInt, simplify_single_expression, traversal,
9+
SparseExprMap, TypeCheck, WidthInt, count_expr_uses, simplify_single_expression, traversal,
1010
};
1111
use polysub::{Coef, Polynom, Term, VarIndex};
1212
use rustc_hash::{FxHashMap, FxHashSet};
@@ -44,9 +44,15 @@ pub fn simplify_word_level_equality(ctx: &mut Context, p: ScaEqualityProblem) ->
4444
.collect();
4545

4646
// now we can perform backwards substitution
47-
backwards_sub(ctx, gate_outputs.into(), spec);
47+
let result = backwards_sub(ctx, gate_outputs.into(), spec);
4848

49-
todo!("check the result of backwards substitution")
49+
if result.is_zero() {
50+
println!("The SAME!")
51+
} else {
52+
println!("DIFFERENT: {result}")
53+
}
54+
55+
None
5056
}
5157

5258
type DefaultCoef = polysub::ArrayCoef<8>;
@@ -68,15 +74,32 @@ fn var_to_expr(v: polysub::VarIndex) -> ExprRef {
6874
usize::from(v).into()
6975
}
7076

71-
fn backwards_sub(ctx: &Context, mut todo: VecDeque<(VarIndex, ExprRef)>, mut spec: Poly) {
77+
fn is_gate(expr: &Expr) -> bool {
78+
matches!(
79+
expr,
80+
Expr::BVNot(_, 1) | Expr::BVAnd(_, _, 1) | Expr::BVOr(_, _, 1) | Expr::BVXor(_, _, 1)
81+
)
82+
}
83+
84+
fn backwards_sub(ctx: &Context, mut todo: VecDeque<(VarIndex, ExprRef)>, mut spec: Poly) -> Poly {
7285
let m = spec.get_mod();
86+
println!("MOD={m:?} ({} bits)", m.bits());
7387
let one: DefaultCoef = Coef::from_i64(1, m);
88+
println!("one = {one:?}");
7489
let minus_one: DefaultCoef = Coef::from_i64(-1, m);
75-
let mut on_todo = FxHashSet::default();
90+
println!("minus_one = {minus_one:?}");
91+
// first, we count how often expressions are used
92+
let roots: Vec<_> = todo.iter().map(|(_, e)| *e).collect();
93+
let mut uses = count_expr_uses(ctx, roots);
7694

7795
while let Some((output_var, gate)) = todo.pop_back() {
78-
println!("{output_var}, {}", expr_to_var(gate) == output_var);
79-
on_todo.remove(&gate);
96+
println!(
97+
"{output_var}, {}, {:?} ({})",
98+
expr_to_var(gate) == output_var,
99+
&ctx[gate],
100+
spec.size()
101+
);
102+
80103
let add_children = match ctx[gate].clone() {
81104
Expr::BVOr(a, b, 1) => {
82105
// a || b = !(!a && !b)
@@ -86,12 +109,16 @@ fn backwards_sub(ctx: &Context, mut todo: VecDeque<(VarIndex, ExprRef)>, mut spe
86109
(one.clone(), vec![x1].into()),
87110
(minus_one.clone(), vec![x0, x1].into()),
88111
];
112+
assert_ne!(gate, a);
113+
assert_ne!(gate, b);
89114
spec.replace_var(output_var, &monoms);
90115
true
91116
}
92117
Expr::BVAnd(a, b, 1) => {
93118
let (x0, x1) = exprs_to_vars_commutative(a, b);
94119
let monoms = [(one.clone(), vec![x0, x1].into())];
120+
assert_ne!(gate, a);
121+
assert_ne!(gate, b);
95122
spec.replace_var(output_var, &monoms);
96123
true
97124
}
@@ -101,6 +128,7 @@ fn backwards_sub(ctx: &Context, mut todo: VecDeque<(VarIndex, ExprRef)>, mut spe
101128
(one.clone(), vec![].into()),
102129
(minus_one.clone(), vec![x0].into()),
103130
];
131+
assert_ne!(gate, a);
104132
spec.replace_var(output_var, &monoms);
105133
true
106134
}
@@ -113,13 +141,18 @@ fn backwards_sub(ctx: &Context, mut todo: VecDeque<(VarIndex, ExprRef)>, mut spe
113141
};
114142
if add_children {
115143
ctx[gate].for_each_child(|&e| {
116-
if !on_todo.contains(&e) {
117-
on_todo.insert(e);
144+
// reduce the use by one
145+
let prev_uses = uses[e];
146+
assert!(prev_uses > 0);
147+
uses[e] = prev_uses - 1;
148+
// did the use count just go down to zero?
149+
if prev_uses == 1 && is_gate(&ctx[e]) {
118150
todo.push_front((expr_to_var(e), e));
119151
}
120152
});
121153
}
122154
}
155+
spec
123156
}
124157

125158
fn poly_for_bv_expr(ctx: &mut Context, e: ExprRef) -> Poly {

0 commit comments

Comments
 (0)