lean4-htt/tests/lean/run/grind_funCC.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

94 lines
1.8 KiB
Text

import Lean
example (m : Nat) (a b : Nat → Nat) (h : b = a) :
b m = a m := by
grind
example (m n : Nat) (a b : Nat → Nat → Nat) : b = a → m = n → i = j → b m i = a n j := by
grind
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
grind
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
namespace WithStructure
structure Test where
apply: Unit → Prop
def test : Test := {
apply := fun () => True
}
example : test.apply () := by
grind [test]
end WithStructure
-- grind succeeds without the thunk
namespace WithoutThunk
structure Test where
apply: Prop
def test : Test := {
apply := True
}
example : test.apply := by
grind [test]
end WithoutThunk
-- grind succeeds without structure
namespace WithoutStructure
def Test := Unit → Prop
def test : Test := fun () => True
example : test () := by
grind [test]
end WithoutStructure
namespace Ex
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
fail_if_success grind
simp_all
example (a b c : Nat) : f a = g → b = c → f a b = g c := by
grind [funCC f, funCC g]
example (a b c : Nat) : f a = g → b = c → f a b = g c := by
fail_if_success grind
simp_all
attribute [grind funCC] f g
example (a b c : Nat) : f a = g → b = c → f a b = g c := by
grind
example (a b c : Nat) : f a = g → b = c → f a b = g c := by
fail_if_success grind -funCC
grind
end Ex