lean4-htt/tests/lean/run/grind_ac_5.lean
Leonardo de Moura 4135674021
feat: add funCC (function-valued congruence closure) to grind (#11323)
This PR introduces a new `grind` option, `funCC` (enabled by default),
which extends congruence closure to *function-valued* equalities. When
`funCC` is enabled, `grind` tracks equalities of **partially applied
functions**, allowing reasoning steps such as:
```lean
a : Nat → Nat 
f : (Nat → Nat) → (Nat → Nat)
h : f a = a
⊢ (f a) m = a m

g : Nat → Nat
f : Nat → Nat → Nat
h : f a = g
⊢ f a b = g b
```

Given an application `f a₁ a₂ … aₙ`, when `funCC := true` and function
equality is enabled for `f`, `grind` generates and tracks equalities for
all partial applications:

* `f a₁`
* `f a₁ a₂`
* …
* `f a₁ a₂ … aₙ`

This allows equalities such as `f a₁ = g` to propagate through further
applications.

**When is function equality enabled for a symbol?**

Function equality is enabled for `f` in the following cases:

1. `f` is **not a constant** (e.g., a lambda, a local function, or a
function parameter).
2. `f` is a **structure field projection**, provided the structure is
**not a `class`**.
3. `f` is a constant marked with  `@[grind funCC]`

Users can also enable function equality for specific constants in a
single call using:
```lean
grind [funCC f, funCC g]
```

**Examples:**

```lean
example (m : Nat) (a : Nat → Nat) (f : (Nat → Nat) → (Nat → Nat)) (h : f a = a) :
    f a m = a m := by
  grind

example (m : Nat) (a : Nat → Nat) (f : (Nat → Nat) → (Nat → Nat)) (h : f a = a) :
    f a m = a m := by
  fail_if_success grind -funCC -- fails if `funCC` is disabled
  grind
```

```lean
example (a b : Nat) (g : Nat → Nat) (f : Nat → Nat → Nat) (h : f a = g) :
    f a b = g b := by
  grind

example (a b : Nat) (g : Nat → Nat) (f : Nat → Nat → Nat) (h : f a = g) :
    f a b = g b := by
  fail_if_success grind -funCC
  grind
```

**Enabling per-symbol with parameters or attributes**

```lean
opaque f : Nat → Nat → Nat
opaque g : Nat → Nat

example (a b c : Nat) : f a = g → b = c → f a b = g c := by
  grind [funCC f, funCC g]

attribute [grind funCC] f g

example (a b c : Nat) : f a = g → b = c → f a b = g c := by
  grind
```

This feature substantially improves `grind`’s support for higher-order
and partially-applied function equalities, while preserving
compatibility with first-order SMT behavior when `funCC` is disabled.

Closes #11309
2025-11-23 05:06:41 +00:00

115 lines
2.9 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/--
error: `grind` failed
case grind
a b c d e f : Nat
h : max a b = max c d
h_1 : max b e = max d (max e f)
h_2 : ¬max c (max d e) = max (max a d) f
⊢ False
[grind] Goal diagnostics
[facts] Asserted facts
[prop] max a b = max c d
[prop] max b e = max d (max e f)
[prop] ¬max c (max d e) = max (max a d) f
[eqc] False propositions
[prop] max c (max d e) = max (max a d) f
[eqc] Equivalence classes
[eqc] {max a b, max c d}
[eqc] {max b e, max d (max e f)}
[assoc] Operator `max`
[basis] Basis
[_] max c d = max a b
[_] max b (max c e) = max a (max b e)
[_] max b (max e f) = max b e
[_] max b (max d e) = max b e
[_] max d (max e f) = max b e
[_] max a (max b d) = max a b
[_] max a (max b c) = max a b
[diseqs] Disequalities
[_] max a (max b e) ≠ max a (max d f)
[properties] Properties
[_] commutative
[_] idempotent
[_] identity: `0`
-/
#guard_msgs in
example (a b c d e f : Nat) :
max a b = max c d →
max b e = max d (max e f) →
max c (max d e) = max (max a d) f := by
grind -lia only
/--
error: `grind` failed
case grind
α : Sort u
op : ααα
inst : Std.Associative op
a b c d : α
h : op a b = op c d
h_1 : ¬op (op a b) (op b c) = op (op c d) c
⊢ False
[grind] Goal diagnostics
[facts] Asserted facts
[prop] Std.Associative op
[prop] op a b = op c d
[prop] ¬op (op a b) (op b c) = op (op c d) c
[eqc] True propositions
[prop] Std.Associative op
[eqc] False propositions
[prop] op (op a b) (op b c) = op (op c d) c
[eqc] Equivalence classes
[eqc] {op (op a b), op (op c d)}
[eqc] {op a b, op c d}
[assoc] Operator `op`
[basis] Basis
[_] op c d = op a b
[diseqs] Disequalities
[_] op a (op b (op b c)) ≠ op a (op b c)
-/
#guard_msgs in
example {α : Sort u} (op : ααα) [Std.Associative op] (a b c d : α)
: op a b = op c d → op (op a b) (op b c) = op (op c d) c := by
grind only
set_option warn.sorry false
set_option grind.debug true
opaque op : Int → Int → Int
instance : Std.Associative op := sorry
instance : Std.Commutative op := sorry
local infixr:64 "∘" => op
/--
error: `grind` failed
case grind
a b c d e p q : Int
h : a∘b = c∘d
h_1 : a∘q = p
h_2 : ¬(c∘d)∘e = a∘p∘q
⊢ False
[grind] Goal diagnostics
[facts] Asserted facts
[prop] a∘b = c∘d
[prop] a∘q = p
[prop] ¬(c∘d)∘e = a∘p∘q
[eqc] False propositions
[prop] (c∘d)∘e = a∘p∘q
[eqc] Equivalence classes
[eqc] {p, a∘q}
[eqc] {a∘b, c∘d}
[assoc] Operator `op`
[basis] Basis
[_] a∘q = p
[_] c∘d = a∘b
[diseqs] Disequalities
[_] a∘b∘e ≠ p∘p
[properties] Properties
[_] commutative
-/
#guard_msgs in
example (a b c d e p q : Int) :
a ∘ b = c ∘ d →
a ∘ q = p →
(c ∘ d) ∘ e = a ∘ (p ∘ q) := by
grind only