Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: IndPred: track function's motive in a let binding, use withoutProofIrrelevance, no chaining #4839

Merged
merged 11 commits into from
Jul 28, 2024

Conversation

nomeata
Copy link
Contributor

@nomeata nomeata commented Jul 26, 2024

this improves support for structural recursion over inductive
predicates when there are reflexive arguments.

Consider

inductive F: Prop where
  | base
  | step (fn: Nat → F)

-- set_option trace.Meta.IndPredBelow.search true
set_option pp.proofs true

def F.asdf1 : (f : F) → True
  | base => trivial
  | step f => F.asdf1 (f 0)
termination_by structural f => f`

Previously the search for the right induction hypothesis would fail with

could not solve using backwards chaining x✝¹ : F
x✝ : x✝¹.below
f : Nat → F
a✝¹ : ∀ (a : Nat), (f a).below
a✝ : Nat → True
⊢ True

The backchaining process will try to use a✝ : Nat → True, but then has
no idea what to use for Nat.

There are three steps here to fix this.

  1. We let-bind the function's type before the whole process. Now the
    goal is

    funType : F → Prop := fun x => True
    x✝ : x✝¹.below
    f : Nat → F
    a✝¹ : ∀ (a : Nat), (f a).below
    a✝ : ∀ (a : Nat), funType (f a)
    ⊢ funType (f 0)
    
  2. Instead of using the general purpose backchaining proof search, which is more
    powerful than we need here (we need on recursive search and no backtracking),
    we have a custom search that looks for local assumptions that
    provide evidence of funType, and extracts the arguments from that
    “type” application to construct the recursive call.

    Above, it will thus unify f a =?= f 0.

  3. In order to make progress here, we also turn on use withoutProofIrrelevance,
    because else isDefEq is happy to say “they are equal” without actually looking
    at the terms and thus assigning ?a := 0.

This idea of let-binding the function's motive may also be useful for
the other recursion compilers, as it may simplify the FunInd
construction. This is to be investigated.

fixes #4751

…oofIrrelevance

this improves support for structural recursion over inductive
*predicates* when there are reflexive arguments.

Consider
```lean
inductive F: Prop where
  | base
  | step (fn: Nat → F)

-- set_option trace.Meta.IndPredBelow.search true
set_option pp.proofs true

def F.asdf1 : (f : F) → True
  | base => trivial
  | step f => F.asdf1 (f 0)
termination_by structural f => f`
```

Previously the search for the right induction hypothesis would fail with
```
could not solve using backwards chaining x✝¹ : F
x✝ : x✝¹.below
f : Nat → F
a✝¹ : ∀ (a : Nat), (f a).below
a✝ : Nat → True
⊢ True
```

The backchaining process will try to use `a✝ : Nat → True`, but then has
no idea what to use for `Nat`.

There are three steps to fix this.

1. We let-bind the function's type before the whole process. Now the
   goal is

   ```
   motive : F → Prop := fun x => True
   x✝ : x✝¹.below
   f : Nat → F
   a✝¹ : ∀ (a : Nat), (f a).below
   a✝ : ∀ (a : Nat), motive (f a)
   ⊢ motive (f 0)
   ```

2. Next we do more aggressive unification when seeing if an assumption
   matches: Given
   ```
   g a b =?= h c d
   ```
   it continues with `a =?= c` and `b =?= d`, even if `g` is a let-bound
   variable.

3. This gives us `f 0 =?= f ?a`. In order to make progress here, we use
   `withoutProofIrrelevance`, because else `isDefEq` is happy to say
   “they are equal” without actually looking at the terms and thus
   assigning `?a := 0`.

This idea of let-binding the function's motive may also be useful for
the other recursion compilers, as it may simplify the FunInd
construction. This is to be investigated.

fixes #4751
@github-actions github-actions bot temporarily deployed to lean-lang.org/lean4/doc July 26, 2024 07:23 Inactive
@github-actions github-actions bot added the toolchain-available A toolchain is available for this PR, at leanprover/lean4-pr-releases:pr-release-NNNN label Jul 26, 2024
@leanprover-community-mathlib4-bot
Copy link
Collaborator

leanprover-community-mathlib4-bot commented Jul 26, 2024

Mathlib CI status (docs):

  • ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the nightly-with-mathlib branch. Try git rebase 93fa9c8837e071a866b62e2ca73c22a362ccb988 --onto 39e0b41fe1ab4d16f15efb0dc9bd7607a8941713. (2024-07-26 07:40:08)
  • ❗ Batteries CI can not be attempted yet, as the nightly-testing-2024-07-26 tag does not exist there yet. We will retry when you push more commits. If you rebase your branch onto nightly-with-mathlib, Batteries CI should run now. (2024-07-26 10:41:05)
  • ✅ Mathlib branch lean-pr-testing-4839 has successfully built against this PR. (2024-07-27 16:25:03) View Log

@github-actions github-actions bot temporarily deployed to lean-lang.org/lean4/doc July 26, 2024 07:40 Inactive
@github-actions github-actions bot temporarily deployed to lean-lang.org/lean4/doc July 26, 2024 09:35 Inactive
@github-actions github-actions bot temporarily deployed to lean-lang.org/lean4/doc July 26, 2024 10:05 Inactive
@github-actions github-actions bot temporarily deployed to lean-lang.org/lean4/doc July 26, 2024 10:38 Inactive
leanprover-community-mathlib4-bot added a commit to leanprover-community/batteries that referenced this pull request Jul 27, 2024
@github-actions github-actions bot temporarily deployed to lean-lang.org/lean4/doc July 27, 2024 15:14 Inactive
leanprover-community-mathlib4-bot added a commit to leanprover-community/mathlib4 that referenced this pull request Jul 27, 2024
@leanprover-community-mathlib4-bot leanprover-community-mathlib4-bot added the builds-mathlib CI has verified that Mathlib builds against this PR label Jul 27, 2024
@nomeata
Copy link
Contributor Author

nomeata commented Jul 28, 2024

@DanielFabian , this does successfully build mathlib, and I have a sense that this is a step in the right direction. Do you want to have a final look before I merge this, or should I just go ahead?

@nomeata nomeata marked this pull request as ready for review July 28, 2024 15:20
@DanielFabian
Copy link
Contributor

go ahead, imo.

@nomeata nomeata added this pull request to the merge queue Jul 28, 2024
Merged via the queue into master with commit 671ce7a Jul 28, 2024
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
builds-mathlib CI has verified that Mathlib builds against this PR toolchain-available A toolchain is available for this PR, at leanprover/lean4-pr-releases:pr-release-NNNN
Projects
None yet
Development

Successfully merging this pull request may close these issues.

structural recursion over inductive predicates struggle with reflexive inductives
3 participants