@@ -9,8 +9,9 @@ use patronus::expr::{
99 Context , DenseExprMetaData , DenseExprSet , Expr , ExprMap , ExprRef , ExprSet , ForEachChild ,
1010 count_expr_uses, traversal,
1111} ;
12+ use patronus:: smt:: Error :: Parser ;
1213use polysub:: { Coef , Mod , PhaseOptPolynom , VarIndex } ;
13- use rustc_hash:: FxHashSet ;
14+ use rustc_hash:: { FxHashMap , FxHashSet } ;
1415use std:: collections:: VecDeque ;
1516
1617/// Used for backwards substitution
@@ -20,12 +21,20 @@ pub fn backwards_sub(
2021 ctx : & Context ,
2122 input_vars : & FxHashSet < VarIndex > ,
2223 todo : Vec < ( VarIndex , ExprRef ) > ,
24+ gate_level_expr : ExprRef ,
2325 spec : Poly ,
2426) -> Poly {
2527 let root_vars: Vec < _ > = todo. iter ( ) . map ( |( v, _) | * v) . collect ( ) ;
2628 let root_exprs: Vec < _ > = todo. iter ( ) . map ( |( _, e) | * e) . collect ( ) ;
2729 let root_uses = analyze_uses ( ctx, & root_exprs) ;
2830
31+ // check to see if there are any half adders we can identify
32+ let xor_and_pairs = find_xor_and_pairs ( ctx, gate_level_expr) ;
33+ println ! ( "XOR/AND: {xor_and_pairs:?}" ) ;
34+
35+ let same_input = find_expr_with_same_inputs ( ctx, gate_level_expr) ;
36+ println ! ( "SAME INPUT: {same_input:?}" ) ;
37+
2938 // empirically, it looks like we should not use a stack
3039 let mut todo: VecDeque < _ > = todo. into ( ) ;
3140 let mut spec: PolyOpt = spec. into ( ) ;
@@ -39,8 +48,10 @@ pub fn backwards_sub(
3948 let mut seen = DenseExprSet :: default ( ) ;
4049
4150 while !todo. is_empty ( ) {
42- let min_idx = try_exhaustive ( ctx, input_vars, & spec, todo. iter ( ) . cloned ( ) , & root_uses) ;
43- let ( output_var, gate) = todo. swap_remove_back ( min_idx) . unwrap ( ) ;
51+ //let gate_idx = try_exhaustive(ctx, input_vars, &spec, todo.iter().cloned(), &root_uses);
52+ // println!("CHOICE: {todo:?}");
53+ let gate_idx = pick_smallest_use ( todo. iter ( ) . cloned ( ) , & root_uses) ;
54+ let ( output_var, gate) = todo. swap_remove_back ( gate_idx) . unwrap ( ) ;
4455
4556 // chose variable to replace
4657 //let (output_var, gate) = todo.pop_back().unwrap();
@@ -162,6 +173,15 @@ fn replace_gate(
162173 }
163174}
164175
176+ fn pick_smallest_use (
177+ todo : impl Iterator < Item = ( VarIndex , ExprRef ) > ,
178+ root_uses : & impl ExprMap < BitSet > ,
179+ ) -> usize {
180+ let uses: Vec < _ > = todo. map ( |( _, gate) | root_uses[ gate] . len ( ) ) . collect ( ) ;
181+ let min_uses = * uses. iter ( ) . min ( ) . unwrap ( ) ;
182+ uses. iter ( ) . position ( |u| * u == min_uses) . unwrap ( )
183+ }
184+
165185fn try_exhaustive (
166186 ctx : & Context ,
167187 input_vars : & FxHashSet < VarIndex > ,
@@ -268,3 +288,58 @@ fn analyze_uses(ctx: &Context, roots: &[ExprRef]) -> impl ExprMap<BitSet> {
268288
269289 out
270290}
291+
292+ /// Tries to identify two expressions which correspond to "a and b" and "a xor b".
293+ fn find_xor_and_pairs ( ctx : & Context , gate_level : ExprRef ) -> Vec < ( ExprRef , ExprRef ) > {
294+ let mut xor = FxHashMap :: default ( ) ;
295+ let mut and = FxHashMap :: default ( ) ;
296+ traversal:: bottom_up ( ctx, gate_level, |ctx, e, _| match ctx[ e] . clone ( ) {
297+ Expr :: BVXor ( a, b, 1 ) => {
298+ xor. insert ( two_expr_key ( a, b) , e) ;
299+ }
300+ Expr :: BVAnd ( a, b, 1 ) => {
301+ and. insert ( two_expr_key ( a, b) , e) ;
302+ }
303+ _ => { }
304+ } ) ;
305+ let mut out = vec ! [ ] ;
306+ for ( key, xor_e) in xor. iter ( ) {
307+ if let Some ( and_e) = and. get ( key) {
308+ out. push ( ( * xor_e, * and_e) ) ;
309+ }
310+ }
311+ out
312+ }
313+
314+ fn find_expr_with_same_inputs ( ctx : & Context , gate_level : ExprRef ) -> Vec < ( ExprRef , ExprRef ) > {
315+ let mut others = FxHashMap :: default ( ) ;
316+ traversal:: bottom_up ( ctx, gate_level, |ctx, e, _| match ctx[ e] . clone ( ) {
317+ Expr :: BVXor ( a, b, 1 ) | Expr :: BVAnd ( a, b, 1 ) | Expr :: BVOr ( a, b, 1 ) => {
318+ let v = others. entry ( two_expr_key ( a, b) ) . or_insert ( vec ! [ ] ) ;
319+ if !v. contains ( & e) {
320+ v. push ( e) ;
321+ }
322+ }
323+ _ => { }
324+ } ) ;
325+
326+ let mut out = vec ! [ ] ;
327+ for ( key, value) in others {
328+ if value. len ( ) > 1 {
329+ match value. as_slice ( ) {
330+ [ a, b] => out. push ( ( * a, * b) ) ,
331+ other => todo ! ( "{other:?}" ) ,
332+ }
333+ }
334+ }
335+ out
336+ }
337+
338+ /// Sorts the two expressions to generate a unique key
339+ fn two_expr_key ( a : ExprRef , b : ExprRef ) -> ( ExprRef , ExprRef ) {
340+ if usize:: from ( a) <= usize:: from ( b) {
341+ ( a, b)
342+ } else {
343+ ( b, a)
344+ }
345+ }
0 commit comments