Skip to content

Commit

Permalink
Add facts to the e-graph before eqsat
Browse files Browse the repository at this point in the history
then only check for conditions matching e-class ids in the applier
  • Loading branch information
marcusrossel committed Apr 30, 2024
1 parent 60553d8 commit 919d06b
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 23 deletions.
9 changes: 6 additions & 3 deletions Lean/Egg/Tests/BlockInvalidMatches.lean
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ example : False := by
contradiction

-- This test covers Condition (2) of valid matches.
/-- error: egg failed to prove goal -/
#guard_msgs in
/- error: egg failed to prove goal -/
-- #guard_msgs in
set_option egg.blockInvalidMatches true in
example : (fun x => (fun a => (fun a => a) a) 0) = (fun x => x) := by
egg (config := { exitPoint := some .beforeProof }) [thm₁]
sorry -- egg (config := { exitPoint := some .beforeProof }) [thm₁]
-- TODO: This started failing (in the sense of seeming to loop infinitely) once we started adding
-- all rewrites to the e-graph as facts. That is, when `thm₁` became part of the e-graph.
-- The problem then seems to be β-reduction. Setting `egg.genBetaRw` to false doesn't loop.

-- This theorem is only applicable in the backward direction.
theorem thm₂ : ∀ x y : Nat, x = (fun _ => x) y :=
Expand Down
27 changes: 19 additions & 8 deletions Lean/Egg/Tests/Conditional.lean
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ example (h₁ : x ∧ y) (h₂ : x ∧ y → 1 = 2) : 1 = 2 := by
example (h₁ : x ∧ y) (h₂ : x ∧ y → 1 = 2) : 1 = 2 := by
egg [*]

example (h₁ : x ∧ y) (h₂ : y ∧ x → 1 = 2) : 1 = 2 := by
egg [and_comm.mp h₁, h₂]

example (h₁ : x ∧ y) (h₂ : y ∧ x → 1 = 2) : 1 = 2 := by
have h₁' := and_comm.mp h₁
egg [h₁', h₂]

example (h₁ : x ∧ y) (h₂ : y ∧ x → 1 = 2) : 1 = 2 := by
have := and_comm.mp h₁
egg [*]

example (h₁ : ∀ n, n > 2 → n = x) (h₂ : 3 > 2) : 3 = x := by
egg [h₁, h₂]

Expand All @@ -24,14 +35,6 @@ example {a : Nat} (h : a < b) : a % b = a := by
example {x : Nat} (h₁ : x = y) (h₂ : x = y → 1 = 2) : 1 = 2 := by
egg [h₁, h₂]

-- TODO:
-- This test tricks the condition matcher in egg into using `q` as a fact, because it is in the same
-- e-class as the fact `p`. We might be able to sort this out by generating explanations for
-- congruent facts by remembering which e-class the matched fact came from and checking if we have
-- an equivalent fact that came from Lean.
example {p q r : Prop} (h₁ : p) (h₂ : p ↔ q) (h₃ : q → (p ↔ r)) : p ↔ r := by
sorry -- egg [h₁, h₂, h₃]

example (h₁ : ∀ p, p ∧ p) (h₂ : (∀ p, p ∧ p) → q = True) : q = True := by
egg [h₁, h₂]

Expand All @@ -45,6 +48,14 @@ example (h₁ : x = y) (h₂ : x = y → 1 = 2) : 1 = 2 := by
example (h₁ : Prop) (h₂ : ∀ p : Prop, p → 1 = id 1) : 1 = id 1 := by
egg [h₁, h₂]

-- TODO:
-- This test tricks the condition matcher in egg into using `q` as a fact, because it is in the same
-- e-class as the fact `p`. We might be able to sort this out by generating explanations for
-- congruent facts by remembering which e-class the matched fact came from and checking if we have
-- an equivalent fact that came from Lean.
example {p q r : Prop} (h₁ : p) (h₂ : p ↔ q) (h₃ : q → (p ↔ r)) : p ↔ r := by
sorry -- egg [h₁, h₂, h₃]

/- TODO:
Example of a sensible theorem (rewrite) with an unbound condition:
Expand Down
4 changes: 3 additions & 1 deletion Lean/Egg/Tests/Groups.lean
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ theorem inv_inv : a⁻¹⁻¹ = a := by
calc _ = a⁻¹⁻¹ * (a⁻¹ * a) := by group
_ = _ := by group

-- Note: Without adding all rewrites as facts to the e-graph, the guide `a⁻¹ * (a * b) * (a * b)⁻¹`
-- sufficed to solve this.
theorem inv_mul' : (a * b)⁻¹ = b⁻¹ * a⁻¹ := by
group using a⁻¹ * (a * b) * (a * b)⁻¹
group using b⁻¹ * a⁻¹ * (a * b) * (a * b)⁻¹

theorem inv_inv' : a⁻¹⁻¹ = a := by
group using a⁻¹ * a
1 change: 1 addition & 0 deletions Lean/Egg/Tests/NatLit.lean
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ example : 12345 % 67890 = 12345 := by
example : 12345 % 0 = 12345 := by
egg

set_option egg.genNatLitRws false in
set_option egg.natReduceRws false in
/-- error: egg failed to prove goal -/
#guard_msgs in
Expand Down
9 changes: 5 additions & 4 deletions Rust/src/basic.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::time::Duration;

use std::collections::HashSet;
use egg::*;
use crate::result::*;
use crate::analysis::*;
Expand Down Expand Up @@ -38,14 +38,15 @@ pub fn explain_congr(init: String, goal: String, rw_templates: Vec<RewriteTempla
egraph.add_expr(&expr);
}

let mut fs = vec![];
let mut fact_classes: HashSet<Id> = Default::default();
for f in facts {
let expr = f.parse().map_err(|e : RecExprParseError<_>| Error::Fact(e.to_string()))?;
fs.push(expr);
let class = egraph.add_expr(&expr);
fact_classes.insert(class);
}

let mut rws;
match templates_to_rewrites(rw_templates, fs, cfg.block_invalid_matches, cfg.shift_captured_bvars) {
match templates_to_rewrites(rw_templates, fact_classes, cfg.block_invalid_matches, cfg.shift_captured_bvars) {
Ok(r) => rws = r,
Err(err) => return Err(Error::Rewrite(err.to_string()))
}
Expand Down
12 changes: 5 additions & 7 deletions Rust/src/rewrite.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::collections::HashMap;
use std::collections::HashSet;
use egg::*;
use crate::result::*;
use crate::lean_expr::*;
Expand All @@ -14,7 +15,7 @@ pub struct RewriteTemplate {
pub conds: Vec<Pattern<LeanExpr>>
}

pub fn templates_to_rewrites(templates: Vec<RewriteTemplate>, facts: Vec<RecExpr<LeanExpr>>, block_invalid_matches: bool, shift_captured_bvars: bool) -> Res<Vec<LeanRewrite>> {
pub fn templates_to_rewrites(templates: Vec<RewriteTemplate>, facts: HashSet<Id>, block_invalid_matches: bool, shift_captured_bvars: bool) -> Res<Vec<LeanRewrite>> {
let mut result: Vec<LeanRewrite> = vec![];
for template in templates {
let applier = LeanApplier { rhs: template.rhs, conds: template.conds, facts: facts.clone(), block_invalid_matches, shift_captured_bvars };
Expand All @@ -29,7 +30,7 @@ pub fn templates_to_rewrites(templates: Vec<RewriteTemplate>, facts: Vec<RecExpr
struct LeanApplier {
pub rhs: Pattern<LeanExpr>,
pub conds: Vec<Pattern<LeanExpr>>,
pub facts: Vec<RecExpr<LeanExpr>>,
pub facts: HashSet<Id>,
pub block_invalid_matches: bool,
pub shift_captured_bvars: bool,
}
Expand All @@ -47,15 +48,12 @@ impl Applier<LeanExpr, LeanAnalysis> for LeanApplier {
}
}

'cond_loop: for cond in self.conds.clone() {
for cond in self.conds.clone() {
// `add_instantiation` crashes when the pattern contains variables not covered by the subst.
// This is currently handled in Lean by filtering out rewrites where a condition's variables are not
// covered by the body's variables.
let id = graph.add_instantiation(&cond.ast, subst);
for fact in self.facts.clone() {
if id == graph.add_expr(&fact) { continue 'cond_loop }
}
return vec![] // This is only reached if `cond` is not satisfied by any fact.
if !self.facts.contains(&id) { return vec![] }
}

// A substitution needs no shifting if it does not map any variables to e-classes containing loose bvars.
Expand Down

0 comments on commit 919d06b

Please sign in to comment.