diff --git a/src/Lean/Meta/ExprDefEq.lean b/src/Lean/Meta/ExprDefEq.lean index c4546d3eed..8da28164f6 100644 --- a/src/Lean/Meta/ExprDefEq.lean +++ b/src/Lean/Meta/ExprDefEq.lean @@ -1757,10 +1757,21 @@ private def isDefEqDeltaStep (t s : Expr) : MetaM DeltaStepResult := do | .lt => unfold t (return .unknown) (k · s) | .gt => unfold s (return .unknown) (k t ·) | .eq => - unfold t - (unfold s (return .unknown) (k t ·)) - (fun t => unfold s (k t s) (k t ·)) + -- Remark: if `t` and `s` are both some `f`-application, we use `tryHeuristic` + -- if `f` is not a projection. The projection case generates a performance regression. + if tInfo.name == sInfo.name && !(← isProjectionFn tInfo.name) then + if t.isApp && s.isApp && (← tryHeuristic t s) then + return .eq + else + unfoldBoth t s + else + unfoldBoth t s where + unfoldBoth (t s : Expr) : MetaM DeltaStepResult := do + unfold t + (unfold s (return .unknown) (k t ·)) + (fun t => unfold s (k t s) (k t ·)) + k (t s : Expr) : MetaM DeltaStepResult := do let t ← whnfCore t let s ← whnfCore s diff --git a/tests/lean/run/3965.lean b/tests/lean/run/3965.lean new file mode 100644 index 0000000000..35c4500f1b --- /dev/null +++ b/tests/lean/run/3965.lean @@ -0,0 +1,206 @@ +section Mathlib.Logic.Function.Iterate + +universe u v + +variable {α : Type u} + +/-- Iterate a function. -/ +def Nat.iterate {α : Sort u} (op : α → α) : Nat → α → α := sorry + +notation:max f "^["n"]" => Nat.iterate f n + +theorem Function.iterate_succ' (f : α → α) (n : Nat) : f^[n.succ] = f ∘ f^[n] := sorry + +end Mathlib.Logic.Function.Iterate + +section Mathlib.Data.Quot + +variable {α : Sort _} + +noncomputable def Quot.out {r : α → α → Prop} (q : Quot r) : α := sorry + +end Mathlib.Data.Quot + +section Mathlib.Init.Order.Defs + +universe u +variable {α : Type u} + +section Preorder + +class Preorder (α : Type u) extends LE α, LT α where + +variable [Preorder α] + +theorem lt_of_lt_of_le : ∀ {a b c : α}, a < b → b ≤ c → a < c := sorry + +end Preorder + +variable [LE α] + +theorem le_total : ∀ a b : α, a ≤ b ∨ b ≤ a := sorry + +end Mathlib.Init.Order.Defs + +section Mathlib.Order.RelClasses + +universe u + +class IsWellOrder (α : Type u) (r : α → α → Prop) : Prop + +end Mathlib.Order.RelClasses + +section Mathlib.Order.SetNotation + +universe u v +variable {α : Type u} {ι : Sort v} + +class SupSet (α : Type _) where + +def iSup [SupSet α] (s : ι → α) : α := sorry + +end Mathlib.Order.SetNotation + +section Mathlib.SetTheory.Ordinal.Basic + +noncomputable section + +universe u v w + +variable {α : Type u} + +structure WellOrder : Type (u + 1) where + α : Type u + +instance Ordinal.isEquivalent : Setoid WellOrder := sorry + +def Ordinal : Type (u + 1) := Quotient Ordinal.isEquivalent + +instance (o : Ordinal) : LT o.out.α := sorry + +namespace Ordinal + +def typein (r : α → α → Prop) [IsWellOrder α r] (a : α) : Ordinal := sorry + +instance partialOrder : Preorder Ordinal := sorry + +theorem typein_lt_self {o : Ordinal} (i : o.out.α) : + @typein _ (· < ·) sorry i < o := sorry + +instance : SupSet Ordinal := sorry + +end Ordinal + +end + +end Mathlib.SetTheory.Ordinal.Basic + +section Mathlib.SetTheory.Ordinal.Arithmetic + +noncomputable section + +universe u v w + +namespace Ordinal + +def sup {ι : Type u} (f : ι → Ordinal.{max u v}) : Ordinal.{max u v} := + iSup f + +def lsub {ι} (f : ι → Ordinal) : Ordinal := + sup f + +def blsub₂ (o₁ o₂ : Ordinal) (op : {a : Ordinal} → (a < o₁) → {b : Ordinal} → (b < o₂) → Ordinal) : + Ordinal := + lsub (fun x : o₁.out.α × o₂.out.α => op (typein_lt_self x.1) (typein_lt_self x.2)) + +theorem lt_blsub₂ {o₁ o₂ : Ordinal} + (op : {a : Ordinal} → (a < o₁) → {b : Ordinal} → (b < o₂) → Ordinal) {a b : Ordinal} + (ha : a < o₁) (hb : b < o₂) : op ha hb < blsub₂ o₁ o₂ op := sorry + + +end Ordinal + +end + +end Mathlib.SetTheory.Ordinal.Arithmetic + +section Mathlib.SetTheory.Ordinal.FixedPoint + +noncomputable section + +universe u v + +namespace Ordinal + +section + +variable {ι : Type u} {f : ι → Ordinal.{max u v} → Ordinal.{max u v}} + +def nfpFamily (f : ι → Ordinal → Ordinal) (a : Ordinal) : Ordinal := + sup (List.foldr f a) + +end + +section + +variable {f : Ordinal.{u} → Ordinal.{u}} + +def nfp (f : Ordinal → Ordinal) : Ordinal → Ordinal := + nfpFamily fun _ : Unit => f + +theorem lt_nfp {a b} : a < nfp f b ↔ ∃ n, a < f^[n] b := sorry + +end + +end Ordinal + +end + +end Mathlib.SetTheory.Ordinal.FixedPoint + +section Mathlib.SetTheory.Ordinal.Principal + +universe u v w + +namespace Ordinal + +def Principal (op : Ordinal → Ordinal → Ordinal) (o : Ordinal) : Prop := + ∀ ⦃a b⦄, a < o → b < o → op a b < o + +theorem principal_nfp_blsub₂ (op : Ordinal → Ordinal → Ordinal) (o : Ordinal) : + Principal op (nfp (fun o' => blsub₂.{u, u, u} o' o' (@fun a _ b _ => op a b)) o) := + fun a b ha hb => by + rw [lt_nfp] at * + rcases ha with ⟨m, hm⟩ + rcases hb with ⟨n, hn⟩ + rcases le_total + ((fun o' => blsub₂.{u, u, u} o' o' (@fun a _ b _ => op a b))^[m] o) + ((fun o' => blsub₂.{u, u, u} o' o' (@fun a _ b _ => op a b))^[n] o) with h | h + · refine ⟨n+1, ?_⟩ + rw [Function.iterate_succ'] + -- after https://github.com/leanprover/lean4/pull/3965 this requires `lt_blsub₂.{u}` or we get + -- `stuck at solving universe constraint max u ?u =?= u` + -- Note that there are two solutions: 0 and u. Both of them work. + exact lt_blsub₂.{u} (@fun a _ b _ => op a b) (lt_of_lt_of_le hm h) hn + · sorry + +-- Trying again with 0 +theorem principal_nfp_blsub₂' (op : Ordinal → Ordinal → Ordinal) (o : Ordinal) : + Principal op (nfp (fun o' => blsub₂.{u, u, u} o' o' (@fun a _ b _ => op a b)) o) := + fun a b ha hb => by + rw [lt_nfp] at * + rcases ha with ⟨m, hm⟩ + rcases hb with ⟨n, hn⟩ + rcases le_total + ((fun o' => blsub₂.{u, u, u} o' o' (@fun a _ b _ => op a b))^[m] o) + ((fun o' => blsub₂.{u, u, u} o' o' (@fun a _ b _ => op a b))^[n] o) with h | h + · refine ⟨n+1, ?_⟩ + rw [Function.iterate_succ'] + -- universe 0 also works here + exact lt_blsub₂.{0} (@fun a _ b _ => op a b) (lt_of_lt_of_le hm h) hn + · sorry + + +end Ordinal + +end Mathlib.SetTheory.Ordinal.Principal diff --git a/tests/lean/run/3965_2.lean b/tests/lean/run/3965_2.lean new file mode 100644 index 0000000000..ee0df78c25 --- /dev/null +++ b/tests/lean/run/3965_2.lean @@ -0,0 +1,98 @@ +section Mathlib.Init.Order.Defs + +universe u + +variable {α : Type u} + +class PartialOrder (α : Type u) extends LE α, LT α where + +theorem le_antisymm [PartialOrder α] : ∀ {a b : α}, a ≤ b → b ≤ a → a = b := sorry + +end Mathlib.Init.Order.Defs + +section Mathlib.Init.Data.Nat.Lemmas + +namespace Nat + +instance : PartialOrder Nat where + le := Nat.le + lt := Nat.lt + +section Find + +variable {p : Nat → Prop} + +private def lbp (m n : Nat) : Prop := + m = n + 1 ∧ ∀ k ≤ n, ¬p k + +variable [DecidablePred p] (H : ∃ n, p n) + +private def wf_lbp {p : Nat → Prop} (H : ∃ n, p n) : WellFounded (@lbp p) := sorry + +protected noncomputable def findX : { n // p n ∧ ∀ m < n, ¬p m } := + @WellFounded.fix _ (fun k => (∀ n < k, ¬p n) → { n // p n ∧ ∀ m < n, ¬p m }) lbp (wf_lbp H) + sorry 0 sorry + +protected noncomputable def find {p : Nat → Prop} [DecidablePred p] (H : ∃ n, p n) : Nat := + (Nat.findX H).1 + +protected theorem find_spec : p (Nat.find H) := sorry + +protected theorem find_min' {m : Nat} (h : p m) : Nat.find H ≤ m := sorry + +end Find + +end Nat + +end Mathlib.Init.Data.Nat.Lemmas + +section Mathlib.Logic.Basic + +theorem Exists.fst {b : Prop} {p : b → Prop} : Exists p → b + | ⟨h, _⟩ => h + +end Mathlib.Logic.Basic + +section Mathlib.Order.Basic + +open Function + +def PartialOrder.lift {α β} [PartialOrder β] (f : α → β) : PartialOrder α where + le x y := f x ≤ f y + lt x y := f x < f y + +end Mathlib.Order.Basic + +section Mathlib.Data.Fin.Basic + +instance {n : Nat} : PartialOrder (Fin n) := + PartialOrder.lift Fin.val + +end Mathlib.Data.Fin.Basic + +section Mathlib.Data.Fin.Tuple.Basic + +universe u v + +namespace Fin + +variable {n : Nat} + +def find : ∀ {n : Nat} (p : Fin n → Prop) [DecidablePred p], Option (Fin n) + | 0, _p, _ => none + | n + 1, p, _ => by + exact + Option.casesOn (@find n (fun i ↦ p (i.castLT sorry)) _) + (if _ : p (Fin.last n) then some (Fin.last n) else none) fun i ↦ + some (i.castLT sorry) + +theorem nat_find_mem_find {p : Fin n → Prop} [DecidablePred p] + (h : ∃ i, ∃ hin : i < n, p ⟨i, hin⟩) : + (⟨Nat.find h, (Nat.find_spec h).fst⟩ : Fin n) ∈ find p := by + rcases hf : find p with f | f + · sorry + · exact Option.some_inj.2 (le_antisymm sorry (Nat.find_min' _ ⟨f.2, sorry⟩)) + +end Fin + +end Mathlib.Data.Fin.Tuple.Basic