Zulip Chat Archive

Stream: lean4

Topic: mkCongrSimp? error for Set


Kyle Miller (Mar 01 2023 at 15:53):

I noticed that congr doesn't seem to work in some equalities involving Set.

For example, the following congr is a no-op

example (xs ys : Set α) (f g : α  β) (h : xs = ys) : Set.image f xs = Set.image g ys := by
  congr
  sorry

But the following congr generates the expected subgoals

example (s t u v : Set α) : s  t = u  v := by
  congr
  sorry
  sorry

Investigating, the first generates (using mkCongrSimp?) a congr lemma with type

 {α : Type ?u.18640} {β : Type ?u.18662} (f f_1 : α  β),
  f = f_1   (s s_1 : Set α), s = s_1   (a a_1 : β), a = a_1  Set.image f s a = Set.image f_1 s_1 a_1

and the second generates

 {α : Type ?u.18238} [self : Union α] (a a_1 : α), a = a_1   (a_2 a_3 : α), a_2 = a_3  a  a_2 = a_1  a_3

It seems that somehow the definition of Set is being unfolded in the Set.image case and Lean goes and generates a lemma with too much extensionality.

Kyle Miller (Mar 01 2023 at 15:55):

Here's a mathlib-free mwe:

def Set (α : Type _) := α  Prop
def Set.image (f : α  β) (s : Set α) : Set β := fun y =>  x, s x  f x = y

example (s t : Set α) (f g : α  β) : Set.image f s = Set.image g t := by
  congr
  sorry -- congr doesn't do anything

Kyle Miller (Mar 01 2023 at 15:58):

I'm not sure if this is a problem in mkCongrSimp? or a problem in how congr applies the generated congr lemma.

A piece of evidence that it's the latter is that simp can navigate these expressions fine:

example (s t : Set α) (f : α  β) (h : s = t) : Set.image f s = Set.image f t := by
  simp [h]

Gabriel Ebner (Mar 01 2023 at 18:06):

lean4#2128

Gabriel Ebner (Mar 01 2023 at 18:07):

The reason this particular case works with simp is because simp has a fallback for when congruence lemmas cannot be generated.

Kyle Miller (Mar 03 2023 at 00:48):

Just to check, is this the fallback (along with congrArgs)?

Gabriel Ebner (Mar 03 2023 at 02:16):

Yes, that's it. In the beginning, Lean 4 simp didn't have support for auto-generated congruence lemmas at all. Back then, this was the only congr support it had.

Kyle Miller (Mar 03 2023 at 18:46):

Thanks, I was wanting to write a version of docs4#Lean.MVarId.congr? that implemented the fallback algorithm.

Kyle Miller (Mar 03 2023 at 18:47):

Regarding that, I have a conceptual question about isDefEq. I was under the impression that isDefEq should be enough to assign the mvarId metavariable near the end of the following function, but it appears I need to do mvarId.assign explicitly:

def Lean.MVarId.fallbackCongr? (mvarId : MVarId) : MetaM (Option (List MVarId)) :=
  mvarId.withContext do commitWhenSomeNoEx? do
    mvarId.checkNotAssigned `fallbackCongr
    let tgt  mvarId.getType'
    let some (_, lhs, _) := tgt.eq? | return none
    lhs.cleanupAnnotations.withApp fun f args => do
      if args.isEmpty then
        return none
      let infos := ( getFunInfoNArgs f args.size).paramInfo
      let mut goals : Array MVarId := #[]
      let mut pf  mkFreshExprMVar (some ( mkEq f ( mkFreshExprMVar ( inferType f))))
      goals := goals.push pf.mvarId!
      let mut i := 0
      for arg in args do
        if (i < infos.size && not infos[i]!.hasFwdDeps) || ( whnfD ( inferType f)).isArrow then
          let eq  mkFreshExprMVar (some ( mkEq arg ( mkFreshExprMVar ( inferType arg))))
          goals := goals.push eq.mvarId!
          pf  Meta.mkCongr pf eq
        else
          pf  Meta.mkCongrFun pf arg
        i := i + 1

      guard ( isDefEq (mkMVar mvarId) pf)
      mvarId.assign pf -- The isDefEq doesn't appear to assign the metavariable?

      return some goals.toList

Kyle Miller (Mar 03 2023 at 18:48):

I'm also not completely sure if I should be doing isDefEq on the terms themselves (a goal metavariable and a proof) or their types.

Kyle Miller (Mar 03 2023 at 18:50):

(This function is in the work-in-progress mathlib4#2606 for context.)

Gabriel Ebner (Mar 03 2023 at 19:20):

The fallback code isn't a great solution either (see lean4#2128).

Gabriel Ebner (Mar 03 2023 at 19:21):

I can't tell why the isDefEq doesn't work here. Do you have an #mwe? If I had to guess, I'd say that Lean applies proof irrelevance before assigning the metavariable. But then we're using isDefEq to assign mvars all over the place.

Gabriel Ebner (Mar 03 2023 at 19:22):

Oh, we use it all over the place and it's known to be broken: lean4#2054 ...

Kyle Miller (Mar 03 2023 at 19:52):

Thanks, that's good to know about how it's known to not work for propostions.

Kyle Miller (Mar 03 2023 at 19:56):

Regarding the fallback code, I just wanted to give congr! a chance at applying to some useful situations, like from earlier in the thread. Even if it can't handle dependent types, I'm hoping it can handle at least as much as simp can.

I need to rethink it a bit though, since the fallback is happy to apply congruence lemmas even if it's unfolding definitions in the types.

Kyle Miller (Mar 03 2023 at 19:57):

It really negatively affects expressions involving docs4#setOf for example


Last updated: Dec 20 2023 at 11:08 UTC