pub fn rewrite_with_invention_egraph(
    root: Id,
    inv: &Invention,
    egraph: &mut crate::EGraph,
) -> Expr {
    let inv: PtrInvention = PtrInvention::new(egraph.add_expr(&inv.body.clone().into()), inv.arity, inv.name.clone());

    let treenodes = topological_ordering(root, egraph);

    assert!(!treenodes.iter().any(|n| egraph[*n].nodes[0] == Lambda::Prim(Symbol::from(&inv.name))),
        "Invention {} already in tree", inv.name);

    let mut nodecost_of_treenode: AHashMap<Id,NodeCost> = Default::default();
    
    for treenode in treenodes.iter() {
        // println!("processing id={}: {}", treenode, extract(*treenode, egraph) );

        // clone to appease the borrow checker
        let node = egraph[*treenode].nodes[0].clone();

        let mut nodecost = NodeCost::new(egraph[*treenode].data.inventionless_cost);

        // trying to use the invs at this node
        if let Some(args) = match_expr_with_inv(*treenode, &inv, &mut nodecost_of_treenode, egraph) {
            let cost: i32 =
                COST_TERMINAL // the new primitive for this invention
                + COST_NONTERMINAL * inv.arity as i32 // the chain of app()s needed to apply the new primitive
                + args.iter()
                    .map(|id| nodecost_of_treenode[id]
                        .cost_under_inv(&inv)) // cost under ANY of the invs since we allow multiple to be used!
                    .sum::<i32>(); // sum costs of actual args
                    nodecost.new_cost_under_inv(inv.clone(), cost, Some(args));
        }


        // inventions based on specific node type
        match node {
            Lambda::IVar(_) => { unreachable!() }
            Lambda::Var(_) => {},
            Lambda::Prim(_) => {},
            Lambda::App([f,x]) => {
                let f_nodecost = &nodecost_of_treenode[&f];
                let x_nodecost = &nodecost_of_treenode[&x];
                                
                // costs with inventions as 1 + fcost + xcost. Use inventionless cost as a default.
                // if either fcost or xcost is None (ie infinite)
                let fcost = f_nodecost.cost_under_inv(&inv);
                let xcost = x_nodecost.cost_under_inv(&inv);
                let cost = COST_NONTERMINAL+fcost+xcost;
                nodecost.new_cost_under_inv(inv.clone(), cost, None);
            }
            Lambda::Lam([b]) => {
                // just map +1 over the costs
                let b_nodecost = &nodecost_of_treenode[&b];
                let bcost = b_nodecost.cost_under_inv(&inv);
                nodecost.new_cost_under_inv(inv.clone(), bcost + COST_NONTERMINAL, None);
            }
            Lambda::Programs(roots) => {
                // no filtering for 2+ uses because we're just doing rewriting here
                let cost = roots.iter().map(|root| {
                        nodecost_of_treenode[root].cost_under_inv(&inv)
                    }).sum();
                    nodecost.new_cost_under_inv(inv.clone(), cost, None);
            }
        }

        nodecost_of_treenode.insert(*treenode, nodecost);
    }

    // Now that we've calculated all the costs, we can extract the cheapest one
    extract_from_nodecosts(root, &inv, &nodecost_of_treenode, egraph)
}
/// Same as `rewrite_with_invention` but operates on an egraph instead of an Expr.
/// 
/// For the `EGraph` argument here you can either pass in a fresh egraph constructed by `let mut egraph = EGraph::new(); egraph.add_expr(expr.into())`
/// or if you make repeated calls to this function feel free to pass in the same egraph over and over. It doesn't matter what is in the EGraph already
/// as long as `root` is in it.
Same as `rewrite_with_invention` but operates on an egraph instead of an Expr.
For the `EGraph` argument here you can either pass in a fresh egraph constructed by `let mut egraph = EGraph::new(); egraph.add_expr(expr.into())`
or if you make repeated calls to this function feel free to pass in the same egraph over and over. It doesn't matter what is in the EGraph already
as long as `root` is in it.
Same as ` rewrite_with_invention ` but operates on an egraph instead of an Expr . For the ` EGraph ` argument here you can either pass in a fresh egraph constructed by ` let mut egraph = EGraph :: new () ; egraph . add_expr ( expr . into () ) ` or if you make repeated calls to this function feel free to pass in the same egraph over and over . It doesn ' t matter what is in the EGraph already as long as ` root ` is in it .
pub fn rewrite_with_invention_egraph(
    root: Id,
    inv: &Invention,
    egraph: &mut crate::EGraph,
) -> Expr {
    let inv: PtrInvention = PtrInvention::new(egraph.add_expr(&inv.body.clone().into()), inv.arity, inv.name.clone());
    let treenodes = topological_ordering(root, egraph);
    assert!(!treenodes.iter().any(|n| egraph[*n].nodes[0] == Lambda::Prim(Symbol::from(&inv.name))),
        "Invention {} already in tree", inv.name);
    let mut nodecost_of_treenode: AHashMap<Id,NodeCost> = Default::default();
    for treenode in treenodes.iter() {
        // println!("processing id={}: {}", treenode, extract(*treenode, egraph) );
        // clone to appease the borrow checker
        let node = egraph[*treenode].nodes[0].clone();
        let mut nodecost = NodeCost::new(egraph[*treenode].data.inventionless_cost);
        // trying to use the invs at this node
        if let Some(args) = match_expr_with_inv(*treenode, &inv, &mut nodecost_of_treenode, egraph) {
            let cost: i32 =
                COST_TERMINAL // the new primitive for this invention
                + COST_NONTERMINAL * inv.arity as i32 // the chain of app()s needed to apply the new primitive
                + args.iter()
                    .map(|id| nodecost_of_treenode[id]
                        .cost_under_inv(&inv)) // cost under ANY of the invs since we allow multiple to be used!
                    .sum::<i32>(); // sum costs of actual args
                    nodecost.new_cost_under_inv(inv.clone(), cost, Some(args));
        }
        // inventions based on specific node type
        match node {
            Lambda::IVar(_) => { unreachable!() }
            Lambda::Var(_) => {},
            Lambda::Prim(_) => {},
            Lambda::App([f,x]) => {
                let f_nodecost = &nodecost_of_treenode[&f];
                let x_nodecost = &nodecost_of_treenode[&x];
                // costs with inventions as 1 + fcost + xcost. Use inventionless cost as a default.
                // if either fcost or xcost is None (ie infinite)
                let fcost = f_nodecost.cost_under_inv(&inv);
                let xcost = x_nodecost.cost_under_inv(&inv);
                let cost = COST_NONTERMINAL+fcost+xcost;
                nodecost.new_cost_under_inv(inv.clone(), cost, None);
            }
            Lambda::Lam([b]) => {
                // just map +1 over the costs
                let b_nodecost = &nodecost_of_treenode[&b];
                let bcost = b_nodecost.cost_under_inv(&inv);
                nodecost.new_cost_under_inv(inv.clone(), bcost + COST_NONTERMINAL, None);
            }
            Lambda::Programs(roots) => {
                // no filtering for 2+ uses because we're just doing rewriting here
                let cost = roots.iter().map(|root| {
                        nodecost_of_treenode[root].cost_under_inv(&inv)
                    }).sum();
                    nodecost.new_cost_under_inv(inv.clone(), cost, None);
            }
        }
        nodecost_of_treenode.insert(*treenode, nodecost);
    }
    // Now that we've calculated all the costs, we can extract the cheapest one
    extract_from_nodecosts(root, &inv, &nodecost_of_treenode, egraph)
}
pub fn rewrite_with_invention_egraph ( root : Id , inv : & Invention , egraph : & mut crate :: EGraph , ) -> Expr { let inv : PtrInvention = PtrInvention :: new ( egraph . add_expr ( & inv . body . clone ( ) . into ( ) ) , inv . arity , inv . name . clone ( ) ) ; let treenodes = topological_ordering ( root , egraph ) ; assert ! ( treenodes iter ( ) any ( n egraph [ n ] nodes [ 0 ] Lambda Prim ( Symbol from ( inv name ) ) ) " " inv name ) ; let mut nodecost_of_treenode : AHashMap < Id , NodeCost > = Default :: default ( ) ; for treenode in treenodes . iter ( ) { // println!("processing id={}: {}", treenode, extract(*treenode, egraph) ); // clone to appease the borrow checker let node = egraph [ * treenode ] . nodes [ 0 ] . clone ( ) ; let mut nodecost = NodeCost :: new ( egraph [ * treenode ] . data . inventionless_cost ) ; // trying to use the invs at this node if let Some ( args ) = match_expr_with_inv ( * treenode , & inv , & mut nodecost_of_treenode , egraph ) { let cost : i32 = COST_TERMINAL // the new primitive for this invention + COST_NONTERMINAL * inv . arity as i32 // the chain of app()s needed to apply the new primitive + args . iter ( ) . map ( | id | nodecost_of_treenode [ id ] . cost_under_inv ( & inv ) ) // cost under ANY of the invs since we allow multiple to be used! . sum :: < i32 > ( ) ; // sum costs of actual args nodecost . new_cost_under_inv ( inv . clone ( ) , cost , Some ( args ) ) ; } // inventions based on specific node type match node { Lambda :: IVar ( _ ) => { unreachable ! ( ) } Lambda :: Var ( _ ) => { } , Lambda :: Prim ( _ ) => { } , Lambda :: App ( [ f , x ] ) => { let f_nodecost = & nodecost_of_treenode [ & f ] ; let x_nodecost = & nodecost_of_treenode [ & x ] ; // costs with inventions as 1 + fcost + xcost. Use inventionless cost as a default. // if either fcost or xcost is None (ie infinite) let fcost = f_nodecost . cost_under_inv ( & inv ) ; let xcost = x_nodecost . cost_under_inv ( & inv ) ; let cost = COST_NONTERMINAL + fcost + xcost ; nodecost . new_cost_under_inv ( inv . clone ( ) , cost , None ) ; } Lambda :: Lam ( [ b ] ) => { // just map +1 over the costs let b_nodecost = & nodecost_of_treenode [ & b ] ; let bcost = b_nodecost . cost_under_inv ( & inv ) ; nodecost . new_cost_under_inv ( inv . clone ( ) , bcost + COST_NONTERMINAL , None ) ; } Lambda :: Programs ( roots ) => { // no filtering for 2+ uses because we're just doing rewriting here let cost = roots . iter ( ) . map ( | root | { nodecost_of_treenode [ root ] . cost_under_inv ( & inv ) } ) . sum ( ) ; nodecost . new_cost_under_inv ( inv . clone ( ) , cost , None ) ; } } nodecost_of_treenode . insert ( * treenode , nodecost ) ; } // Now that we've calculated all the costs, we can extract the cheapest one extract_from_nodecosts ( root , & inv , & nodecost_of_treenode , egraph ) }
Same as `rewrite_with_invention` but operates on an egraph instead of an Expr.
Same as ` rewrite_with_invention ` but operates on an egraph instead of an Expr .
root
Id
inv
&Invention
egraph
&mut crate::EGraph
root
Id
inv
&Invention
egraph
&mut crate::EGraph