I have a new puzzle for simp debugging lovers. I tried to minimize but it's a very shy bug which very quickly disappear.
import Mathlib.Analysis.InnerProductSpace.Projection
lemma Prod.snd_mk { α β : Type * } ( a : α ) ( b : β ) : ( a , b ) . 2 = b := rfl
example { E : Type * } [ NormedAddCommGroup E ] [ InnerProductSpace ℝ E ] ( v : E ) ( t : ℝ ) :
orthogonalProjection ( Submodule.span ℝ {( t , v ) . snd }) = 0 := by
simp only [ Prod.snd_mk ] -- fails to make progress and to report it didn't make progress
-- dsimp only [Prod.snd_mk] -- works
sorry
The goal here is to get simp to transform (t, v).snd into v.
If you do it twice it doesn't make progress the second time
I think we're missing a congruence lemma for docs#orthogonalProjection , as it takes a dependently-typed argument
Or the auto-generated ones are broken
In 4 places of the expression, the following
| | | | |-' Prod.snd' -- app
| | | | | |-' Real' ' [] ' -- const
| | | | | |-' _uniq.2901' -- fvar
| | | | | |-' Prod.mk' -- app
| | | | | | |-' Real' ' [] ' -- const
| | | | | | |-' _uniq.2901' -- fvar
| | | | | | |-' _uniq.2905' -- fvar
| | | | | | |-' _uniq.2904' -- fvar
was replaced by
| | | | |-' _uniq.2904' -- fvar
inspect : ' orthogonalProjection ( Submodule.span ℝ {( t , v ) . snd }) = 0 '
' Eq' -- app
|-' ContinuousLinearMap' -- app
| |-' Real' ' [] ' -- const
| |-' Real' ' [] ' -- const
| |-' DivisionSemiring.toSemiring' -- app
| | |-' Real' ' [] ' -- const
| | |-' Semifield.toDivisionSemiring' -- app
| | | |-' Real' ' [] ' -- const
| | | |-' Field.toSemifield' -- app
| | | | |-' Real' ' [] ' -- const
| | | | |-' NormedField.toField' -- app
| | | | | |-' Real' ' [] ' -- const
| | | | | |-' DenselyNormedField.toNormedField' -- app
| | | | | | |-' Real' ' [] ' -- const
| | | | | | |-' IsROrC.toDenselyNormedField' -- app
| | | | | | | |-' Real' ' [] ' -- const
| | | | | | | |-' Real.isROrC' ' [] ' -- const
| |-' DivisionSemiring.toSemiring' -- app
| | |-' Real' ' [] ' -- const
| | |-' Semifield.toDivisionSemiring' -- app
| | | |-' Real' ' [] ' -- const
| | | |-' Field.toSemifield' -- app
| | | | |-' Real' ' [] ' -- const
| | | | |-' NormedField.toField' -- app
| | | | | |-' Real' ' [] ' -- const
| | | | | |-' DenselyNormedField.toNormedField' -- app
| | | | | | |-' Real' ' [] ' -- const
| | | | | | |-' IsROrC.toDenselyNormedField' -- app
| | | | | | | |-' Real' ' [] ' -- const
| | | | | | | |-' Real.isROrC' ' [] ' -- const
| |-' RingHom.id' -- app
| | |-' Real' ' [] ' -- const
| | |-' Semiring.toNonAssocSemiring' -- app
| | | |-' Real' ' [] ' -- const
| | | |-' DivisionSemiring.toSemiring' -- app
| | | | |-' Real' ' [] ' -- const
| | | | |-' Semifield.toDivisionSemiring' -- app
| | | | | |-' Real' ' [] ' -- const
| | | | | |-' Field.toSemifield' -- app
| | | | | | |-' Real' ' [] ' -- const
| | | | | | |-' NormedField.toField' -- app
| | | | | | | |-' Real' ' [] ' -- const
| | | | | | | |-' DenselyNormedField.toNormedField' -- app
| | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | |-' IsROrC.toDenselyNormedField' -- app
| | | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | | |-' Real.isROrC' ' [] ' -- const
| |-' _uniq.2901' -- fvar
| |-' UniformSpace.toTopologicalSpace' -- app
| | |-' _uniq.2901' -- fvar
| | |-' PseudoMetricSpace.toUniformSpace' -- app
| | | |-' _uniq.2901' -- fvar
| | | |-' SeminormedAddCommGroup.toPseudoMetricSpace' -- app
| | | | |-' _uniq.2901' -- fvar
| | | | |-' NormedAddCommGroup.toSeminormedAddCommGroup' -- app
| | | | | |-' _uniq.2901' -- fvar
| | | | | |-' _uniq.2902' -- fvar
| |-' AddCommGroup.toAddCommMonoid' -- app
| | |-' _uniq.2901' -- fvar
| | |-' NormedAddCommGroup.toAddCommGroup' -- app
| | | |-' _uniq.2901' -- fvar
| | | |-' _uniq.2902' -- fvar
| |-' Subtype' -- app
| | |-' _uniq.2901' -- fvar
| | |- ( 'x' ) -- lam
| | | |-' _uniq.2901' -- fvar
| | | |-' Membership.mem' -- app
| | | | |-' _uniq.2901' -- fvar
| | | | |-' Submodule' -- app
| | | | | |-' Real' ' [] ' -- const
| | | | | |-' _uniq.2901' -- fvar
| | | | | |-' DivisionSemiring.toSemiring' -- app
| | | | | | |-' Real' ' [] ' -- const
| | | | | | |-' Semifield.toDivisionSemiring' -- app
| | | | | | | |-' Real' ' [] ' -- const
| | | | | | | |-' Field.toSemifield' -- app
| | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | |-' NormedField.toField' -- app
| | | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | | |-' DenselyNormedField.toNormedField' -- app
| | | | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | | | |-' IsROrC.toDenselyNormedField' -- app
| | | | | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | | | | |-' Real.isROrC' ' [] ' -- const
| | | | | |-' AddCommGroup.toAddCommMonoid' -- app
| | | | | | |-' _uniq.2901' -- fvar
| | | | | | |-' NormedAddCommGroup.toAddCommGroup' -- app
| | | | | | | |-' _uniq.2901' -- fvar
| | | | | | | |-' _uniq.2902' -- fvar
| | | | | |-' NormedSpace.toModule' -- app
| | | | | | |-' Real' ' [] ' -- const
| | | | | | |-' _uniq.2901' -- fvar
| | | | | | |-' DenselyNormedField.toNormedField' -- app
| | | | | | | |-' Real' ' [] ' -- const
| | | | | | | |-' IsROrC.toDenselyNormedField' -- app
| | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | |-' Real.isROrC' ' [] ' -- const
| | | | | | |-' NormedAddCommGroup.toSeminormedAddCommGroup' -- app
| | | | | | | |-' _uniq.2901' -- fvar
| | | | | | | |-' _uniq.2902' -- fvar
| | | | | | |-' InnerProductSpace.toNormedSpace' -- app
| | | | | | | |-' Real' ' [] ' -- const
| | | | | | | |-' _uniq.2901' -- fvar
| | | | | | | |-' Real.isROrC' ' [] ' -- const
| | | | | | | |-' _uniq.2902' -- fvar
| | | | | | | |-' _uniq.2903' -- fvar
| | | | |-' SetLike.instMembership' -- app
| | | | | |-' Submodule' -- app
| | | | | | |-' Real' ' [] ' -- const
| | | | | | |-' _uniq.2901' -- fvar
| | | | | | |-' DivisionSemiring.toSemiring' -- app
| | | | | | | |-' Real' ' [] ' -- const
| | | | | | | |-' Semifield.toDivisionSemiring' -- app
| | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | |-' Field.toSemifield' -- app
| | | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | | |-' NormedField.toField' -- app
| | | | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | | | |-' DenselyNormedField.toNormedField' -- app
| | | | | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | | | | |-' IsROrC.toDenselyNormedField' -- app
| | | | | | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | | | | | |-' Real.isROrC' ' [] ' -- const
| | | | | | |-' AddCommGroup.toAddCommMonoid' -- app
| | | | | | | |-' _uniq.2901' -- fvar
| | | | | | | |-' NormedAddCommGroup.toAddCommGroup' -- app
| | | | | | | | |-' _uniq.2901' -- fvar
| | | | | | | | |-' _uniq.2902' -- fvar
| | | | | | |-' NormedSpace.toModule' -- app
| | | | | | | |-' Real' ' [] ' -- const
| | | | | | | |-' _uniq.2901' -- fvar
| | | | | | | |-' DenselyNormedField.toNormedField' -- app
| | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | |-' IsROrC.toDenselyNormedField' -- app
| | | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | | |-' Real.isROrC' ' [] ' -- const
| | | | | | | |-' NormedAddCommGroup.toSeminormedAddCommGroup' -- app
| | | | | | | | |-' _uniq.2901' -- fvar
| | | | | | | | |-' _uniq.2902' -- fvar
| | | | | | | |-' InnerProductSpace.toNormedSpace' -- app
| | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | |-' _uniq.2901' -- fvar
| | | | | | | | |-' Real.isROrC' ' [] ' -- const
| | | | | | | | |-' _uniq.2902' -- fvar
| | | | | | | | |-' _uniq.2903' -- fvar
| | | | | |-' _uniq.2901' -- fvar
| | | | | |-' Submodule.setLike' -- app
| | | | | | |-' Real' ' [] ' -- const
| | | | | | |-' _uniq.2901' -- fvar
| | | | | | |-' DivisionSemiring.toSemiring' -- app
| | | | | | | |-' Real' ' [] ' -- const
| | | | | | | |-' Semifield.toDivisionSemiring' -- app
| | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | |-' Field.toSemifield' -- app
| | | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | | |-' NormedField.toField' -- app
| | | | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | | | |-' DenselyNormedField.toNormedField' -- app
| | | | | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | | | | |-' IsROrC.toDenselyNormedField' -- app
| | | | | | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | | | | | |-' Real.isROrC' ' [] ' -- const
| | | | | | |-' AddCommGroup.toAddCommMonoid' -- app
| | | | | | | |-' _uniq.2901' -- fvar
| | | | | | | |-' NormedAddCommGroup.toAddCommGroup' -- app
| | | | | | | | |-' _uniq.2901' -- fvar
| | | | | | | | |-' _uniq.2902' -- fvar
| | | | | | |-' NormedSpace.toModule' -- app
| | | | | | | |-' Real' ' [] ' -- const
| | | | | | | |-' _uniq.2901' -- fvar
| | | | | | | |-' DenselyNormedField.toNormedField' -- app
| | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | |-' IsROrC.toDenselyNormedField' -- app
| | | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | | |-' Real.isROrC' ' [] ' -- const
| | | | | | | |-' NormedAddCommGroup.toSeminormedAddCommGroup' -- app
| | | | | | | | |-' _uniq.2901' -- fvar
| | | | | | | | |-' _uniq.2902' -- fvar
| | | | | | | |-' InnerProductSpace.toNormedSpace' -- app
| | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | |-' _uniq.2901' -- fvar
| | | | | | | | |-' Real.isROrC' ' [] ' -- const
| | | | | | | | |-' _uniq.2902' -- fvar
| | | | | | | | |-' _uniq.2903' -- fvar
| | | | |- '0' -- bvar
| | | | |-' Submodule.span' -- app
| | | | | |-' Real' ' [] ' -- const
| | | | | |-' _uniq.2901' -- fvar
| | | | | |-' Real.semiring' ' [] ' -- const
| | | | | |-' AddCommGroup.toAddCommMonoid' -- app
| | | | | | |-' _uniq.2901' -- fvar
| | | | | | |-' NormedAddCommGroup.toAddCommGroup' -- app
| | | | | | | |-' _uniq.2901' -- fvar
| | | | | | | |-' _uniq.2902' -- fvar
| | | | | |-' NormedSpace.toModule' -- app
| | | | | | |-' Real' ' [] ' -- const
| | | | | | |-' _uniq.2901' -- fvar
| | | | | | |-' DenselyNormedField.toNormedField' -- app
| | | | | | | |-' Real' ' [] ' -- const
| | | | | | | |-' IsROrC.toDenselyNormedField' -- app
| | | | | | | | |-' Real' ' [] ' -- const
| | | | | | | | |-' Real.isROrC' ' [] ' -- const
| | | | | | |-' NormedAddCommGroup.toSeminormedAddCommGroup' -- app
| | | | | | | |-' _uniq.2901' -- fvar
| | | | | | | |-' _uniq.2902' -- fvar
| | | | | | |-' InnerProductSpace.toNormedSpace' -- app
| | | | | | | |-' Real' ' [] ' -- const
| | | | | | | |-' _uniq.2901' -- fvar
| | | | | | | |-' Real.isROrC' ' [] ' -- const
| | | | | | | |-' _uniq.2902' -- fvar
| | | | | | | |-' _uniq.2903' -- fvar
| | | | | |-' Singleton.singleton' -- app
| | | | | | |-' _uniq.2901' -- fvar
| | | | | | |-' Set' -- app
| | | | | | | |-' _uniq.2901' -- fvar
| | | | | | |-' Set.instSingletonSet' -- app
| | | | | | | |-' _uniq.2901' -- fvar
Interesting. So indeed simp does something, but no what we expected.
Here's a hint, the congruence lemma for orthogonalProjection needs to be a HEq
def orthogonalProjection.congr { 𝕜 E : Type * } [ IsROrC 𝕜 ] [ NormedAddCommGroup E ]
[ InnerProductSpace 𝕜 E ] ( K K' : Submodule 𝕜 E ) ( h : K = K' ) [ HasOrthogonalProjection K ] :
haveI : HasOrthogonalProjection K' := by cases h ; assumption
HEq ( orthogonalProjection K ) ( orthogonalProjection K' ) := by
congr !
Rewriting K in orthogonalProjection K changes the type
dsimp can make progress because it's allowed to change K to something that's defeq
Upon better inspection, it seems that simp simplified the product inside the type of the left-hand side of the equality, but failed to enter the lhs and perform the substitution there.
Of the probably 22 places where the expression could change, simp seems to only "see" 4, all inside the type and none in the actual terms.
Here you can see the locations where the relevant mvar appears, the end of the implicit argument to Eq. and the beginning of the LHS.
image.png
Again this does not explain why the Lean 3 simplifier was happy to do its job and the Lean 4 simplifier isn't.
The diff highlights how the expression became, only the first 4 occurrences were rewritten.
No, this is just a text based description!
Sorry, it is bed-time! Have fun with this puzzle!
@Damiano Testa When simp comes across "fixed" variables it will usually dsimp them, but I'm not sure it will always do so.
(@Patrick Massot It doesn't help simp make progress, but I noticed that Prod.snd_mk is specialized to Type instead of Type*!)
Oops, that's a copy-paste mistake.
I'll fix it in my post above to avoid confusion.
Last updated: May 02 2025 at 03:31 UTC