Zulip Chat Archive

Stream: mathlib4

Topic: use bug


Patrick Massot (Oct 20 2023 at 22:36):

Trying to write exercises for #mil, I wrote the following code that has several issues.

import Mathlib.RingTheory.Ideal.Operations

open BigOperators

example {R : Type*} [CommRing R] {I J : Ideal R} {x : R} :
    x  I * J   (n : ) (a b : Fin n  R), ( i, a i  I  b i  J)   i, a i * b i = x := by
  constructor
  · intro hx
    let P : R  Prop := fun x    n,  a b : Fin n  R, ( (i : Fin n), a i  I  b i  J) 
       i : Fin n, a i * b i = x
    apply Submodule.smul_induction_on (p := P) hx
    intro a ha b hb
    existsi 1
    use fun _  a, fun _  b
    constructor
    tauto
    simp
    rintro x y n, a, b, hab, rfl m, c, d, hcd, rfl
    existsi n + m
    use Fin.addCases a c
    use Fin.addCases b d
    constructor
    · intros i
      constructor
      · induction i using Fin.addCases
        next i =>  simpa using (hab i).1
        next i =>  simpa using (hcd i).1
      · induction i using Fin.addCases
        next i =>  simpa using (hab i).2
        next i =>  simpa using (hcd i).2
    · simp [Fin.sum_univ_add]
  · rintro n, a, b, h, rfl
    apply Ideal.sum_mem
    intro i _
    apply Submodule.mul_mem_mul  (h i).1 (h i).2

First I could sweat we add that kind of lemma somewhere but couldn't find it. Then the two calls to existsi cannot be replaced by use without a weird error unknown free variable '_uniq.259659' (that seem to be a fashionable error message those days). Then I'd like to use apply Submodule.smul_induction_on without defining P first. Then I couldn't find Fin.addCases using Loogle, what would be a good request? Then how to find the correct syntax to use induction using Fin.addCases with the | syntax instead of next?. And finally the brand new aesop powers from @Jireh Loreaux do not seem to be able to replace the last three lines. Short version: nothing worked smoothly in this proof.

Scott Morrison (Oct 21 2023 at 03:19):

What are the new aesop powers? See https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/.60aesop.60.20for.20.60SetLike.60/near/397741320

Jireh Loreaux (Oct 21 2023 at 04:11):

@Patrick Massot as for aesop, it's just missing attributes. I'm going to have a follow-up PR where I add the attributes more widely as I try to golf these sorts of things across the library. I'll try to collect a list of lemmas that need it, so if you run across any just let me know. In this case, I think the attribute to add is:

attribute [aesop safe apply (rule_sets [SetLike])]
  sum_mem
  Submodule.mul_mem_mul

Jireh Loreaux (Oct 21 2023 at 04:18):

This is the | syntax for induction using Fin.addCases, but admittedly I had to go-to-def to see what the names were. I don't think we have a code action for this yet, and I'm not sufficiently experienced with metaprogramming yet to write it.

      · induction i using Fin.addCases with
        | left i =>  simpa using (hab i).1
        | right i =>  simpa using (hcd i).1

Jireh Loreaux (Oct 21 2023 at 04:27):

I don't have a really good suggestion for searching for Fin.addCases unless you know or can guess Case would be in the name. Then ...
@loogle "Cases", FIn (?a + ?b)

loogle (Oct 21 2023 at 04:27):

:exclamation: unknown identifier 'FIn'
Did you mean "Cases", MLList.fin (?a + ?b) or something else?

Jireh Loreaux (Oct 21 2023 at 04:28):

@loogle "Cases", Fin (?a + ?b)

loogle (Oct 21 2023 at 04:28):

:search: Fin.addCases, Fin.lastCases, and 12 more

Jireh Loreaux (Oct 21 2023 at 04:28):

but that's probably too much cheating.

Jireh Loreaux (Oct 21 2023 at 04:54):

i'm not really sure what's going on with the use versus existsi, but the variable it's complaining about it P, which you can see by using this quick tactic I used to show the FVarId associated to a local declaration.

open Lean Meta Elab Tactic

syntax (name := fvar_id) "fvar_id" ident : tactic
elab "fvar_id" h:ident : tactic => withMainContext do
  ( getMainGoal).withContext do
  for ldecl in ( getLCtx) do
    if ldecl.userName == h.getId then
      logInfo m!"{ldecl.userName} : {ldecl.type} has FVarId : {ldecl.fvarId.name}"

Patrick Massot (Oct 21 2023 at 14:34):

@Jireh Loreaux Thank you very much for your answer.

Patrick Massot (Oct 21 2023 at 14:35):

To everyone, here is a somewhat minimized version of the use bug:

import Mathlib.RingTheory.Ideal.Operations

example {R : Type*} [CommRing R] {I J : Ideal R} {x : R} (hx : x  I  J) :
       n: , True := by
   let P : R  Prop := fun x   n : , True
   apply Submodule.smul_induction_on (p := P) hx
   intro a ha b hb
   use' 1

Patrick Massot (Oct 21 2023 at 14:36):

The first idea, which to wrap more stuff into withMainContext is not enough:

import Mathlib.RingTheory.Ideal.Operations

namespace Mathlib.Tactic
open Lean Meta Elab Tactic

/-- Run the `useLoop` on the main goal then discharge remaining explicit `Prop` arguments. -/
def runUse' (eager : Bool) (discharger : TacticM Unit) (args : List Term) : TacticM Unit :=
withMainContext do
  let egoals  focus do
    let (egoals, acc, insts)  useLoop eager ( getGoals) args [] []
    -- Try synthesizing instance arguments
    for inst in insts do
      if !( inst.isAssigned) then
        discard <| observing? do inst.assign ( synthInstance ( inst.getType))
    -- Set the goals.
    setGoals (egoals ++ acc)
    pruneSolvedGoals
    pure egoals
  -- Run the discharger on non-assigned proposition metavariables
  -- (`trivial` uses `assumption`, which isn't great for non-propositions)
  for g in egoals do
    if !( g.isAssigned) then
      if  isProp ( g.getType) then
        trace[tactic.use] "running discharger on {g}"
        discard <| run g discharger

elab (name := useSyntax')
    "use'" discharger?:(Parser.Tactic.discharger)? ppSpace args:term,+ : tactic => do
  runUse false ( mkUseDischarger discharger?) args.getElems.toList

end Mathlib.Tactic

Kyle Miller (Oct 21 2023 at 15:16):

@Patrick Massot I think I found the use bug, but I haven't tested the fix yet

Patrick Massot (Oct 21 2023 at 15:16):

I can test it if you want.

Patrick Massot (Oct 21 2023 at 15:16):

What would be the fix?

Kyle Miller (Oct 21 2023 at 15:17):

I'll push a branch in a moment

Kyle Miller (Oct 21 2023 at 15:29):

@Patrick Massot Here's a WIP branch with a few fixes: #7827

Patrick Massot (Oct 21 2023 at 15:30):

Nice. I can see some pattern here.

Kyle Miller (Oct 21 2023 at 15:39):

@Patrick Massot It looks like at least one of these fixes addressed the problem! Do you think it would be hard to minimize the example so that it can go into the tests/Use file and not need any more imports? I'm guessing the key is that P is let-bound.

Patrick Massot (Oct 21 2023 at 15:40):

Naive minimization didn't work, but I'll try some more.

Jireh Loreaux (Oct 21 2023 at 15:41):

Kyle, I thought that as well, but letI didn't make the problem go away, which I would have expected it to do.

Kyle Miller (Oct 21 2023 at 15:42):

Yeah, got it:

example : let P : Nat  Prop := fun x =>  n : Nat, True; P 1 := by
  intro P
  use 1

Kevin Buzzard (Oct 21 2023 at 15:43):

Nice!

Kyle Miller (Oct 21 2023 at 15:43):

You need a step like intro at the beginning to make sure you have a new local context before the offending tactic, since otherwise you might accidentally be inside a local context that hides the problem.

Patrick Massot (Oct 21 2023 at 15:44):

I wasn't fast enough. And mine is more complicated

example :  _n : Nat,  _k : Nat, True := by
  let P : Nat  Prop := fun _n   _k : Nat, True
  apply Nat.rec (motive := P)
  -- use 1
  existsi 1
  trivial
  intro n _
  existsi 1
  trivial

Patrick Massot (Oct 21 2023 at 15:47):

I delegated the PR, let's wait for CI.


Last updated: Dec 20 2023 at 11:08 UTC