Zulip Chat Archive

Stream: mathlib4

Topic: LinearAlgebra.Dual


Yury G. Kudryashov (Apr 27 2023 at 06:01):

Quite a few proofs in !4#3659 fail for the same reason: simp can't apply lemmas about LinearMap to Module.Dual. What should we do? Duplicate API? Write a tactic to automate this? Something else?

Kevin Buzzard (Apr 27 2023 at 07:08):

Not for the same reason, but ext is weaker in lean 4 and to compensate I've been adding extra lemmas.

Yury G. Kudryashov (May 05 2023 at 08:02):

Ping here

Eric Wieser (May 05 2023 at 08:18):

Shouldn't docs#module.dual be reducible?

Eric Wieser (May 05 2023 at 08:19):

I don't see what the point is in having it not be; are there any instances that disagree between the dual and underlying map?

Yury G. Kudryashov (May 05 2023 at 17:57):

Let me try to make it reducible in Lean 3.

Eric Wieser (May 05 2023 at 18:18):

docs#weak_dual should be reducible too I think

Yury G. Kudryashov (May 05 2023 at 18:22):

Why? It has a different topology.

Yury G. Kudryashov (May 05 2023 at 18:23):

UPD: You mean, wek_dual should reducibly unfold to weak_bilin. Probably, yes. I wrote the previous comment before reading the source.

Eric Wieser (May 05 2023 at 19:03):

I made the same assumption in another thread!

Yury G. Kudryashov (May 06 2023 at 01:23):

I tried to make it reducible and I get a timeout in the same file.

Yury G. Kudryashov (May 06 2023 at 01:24):

(I'm talking about module.dual)

Yury G. Kudryashov (May 06 2023 at 01:24):

See branch#YK-dual

Tchsurvives (May 06 2023 at 17:51):

i was looking at this, and it seems to compile fine in lean4. just that there are linting issues. is all that is left a simple clean up? or are you guys still working on it. i would be happy to attempt the clean up

Eric Wieser (May 06 2023 at 20:02):

The timeout seems to be a problem in simps

Eric Wieser (May 06 2023 at 20:11):

I pushed a fix, the rest of that file is now happy on branch#YK-dual

Yury G. Kudryashov (May 07 2023 at 15:35):

@Eric Wieser Thanks! @Tchsurvives I think that we should merge #18963, wait for mathport, then sync !4#3659

Matthew Ballard (May 17 2023 at 16:28):

I forward ported the changes from #18963. If this thing ever built, it surely does not now. Issues

  • broken dot notation on LinearMap
  • timeouts
  • universe issues stemming from Cardinal.lift.{max v u, u}

Kevin Buzzard (May 17 2023 at 16:39):

My understanding is that broken dot notation on LinearMap is issue lean4#1910 .

Matthew Ballard (May 17 2023 at 16:41):

I see. Thanks! I will do the dumb workaround until then.

Matthew Ballard (May 17 2023 at 16:42):

That is if my computer doesn't melt through the desk after turning off heartbeats on one of these timeouts :hot:

Matthew Ballard (May 17 2023 at 21:01):

This files drains all my happiness at the speed bump from :eta:

Eric Wieser (May 18 2023 at 07:14):

I forward ported the changes from #18963.

It might have been a better idea to start fresh; I think the old PR has quite a few hacks that should no longer be necessary as of #18963

Matthew Ballard (May 18 2023 at 12:34):

I’ll step back and try this.

Matthew Ballard (May 18 2023 at 20:57):

Did this. Did help with some timeouts. Added one. Currently working on this on a different branch. Will merge soon

Matthew Ballard (May 19 2023 at 14:52):

Thanks to @Chris Hughes for clearing one timeout. For the second (and third), W.dualPairing is exceptional slow for [Field K] and W : Subspace K V. For example,

example (W : Submodule R M) : Module.Dual R M  dualAnnihilator W →ₗ[R] Module.Dual R W := Submodule.dualPairing W

is instantaneous while

example (W : Subspace K V) : Module.Dual K V  dualAnnihilator W →ₗ[K] Module.Dual K W :=
    W.dualPairing

times out to the order of 400000 heartbeats

Matthew Ballard (May 19 2023 at 14:54):

Replacing W.dualPairing with sorry is instantaneous

Eric Wieser (May 19 2023 at 15:00):

docs#submodule.dual_pairing

Eric Wieser (May 19 2023 at 15:00):

Does adding by exact to the start of either spelling change the duration?

Matthew Ballard (May 19 2023 at 15:00):

Let me check

Eric Wieser (May 19 2023 at 15:01):

There was some weirdness in Lean3 where the value of the definition would fill in the metavariables in its type

Matthew Ballard (May 19 2023 at 15:15):

Eric Wieser said:

Does adding by exact to the start of either spelling change the duration?

No improvement in time

Kevin Buzzard (May 19 2023 at 15:15):

Changing (K : Type _) (V : Type _) to (K : Type u) (V : Type v) makes it not time out (but it's still slow). I find this quite surprising!

Matthew Ballard (May 19 2023 at 15:16):

Aha!

Matthew Ballard (May 19 2023 at 15:16):

Suggestively I already had to do some universe triage

Kevin Buzzard (May 19 2023 at 15:16):

(K : Type _) (V : Type v) times out

Matthew Ballard (May 19 2023 at 15:17):

It is K

Matthew Ballard (May 19 2023 at 15:18):

It is a rather brutal time out without that. Over 9000000

Eric Wieser (May 19 2023 at 15:18):

Kevin Buzzard said:

Changing (K : Type _) (V : Type _) to (K : Type u) (V : Type v) makes it not time out (but it's still slow). I find this quite surprising!

We should definitely do this then. When we write Type _ we almost always mean Type new_u and we're just lazy. In Lean3 these were basically identical, but lean 4 goes on a unification wild goose chase in every lemma

Eric Wieser (May 19 2023 at 15:19):

Can we have a macro %Type such that K : %Type just means universes uK, K : Type uK?

Matthew Ballard (May 19 2023 at 15:23):

Matthew Ballard said:

It is a rather brutal time out without that. Over 9000000

dualPairing_eq goes down to 400000 now

Matthew Ballard (May 19 2023 at 15:25):

There is some universe gymnastics with Cardinal.lift and max u v already in the file

Kevin Buzzard (May 19 2023 at 15:38):

theorem dualPairing_eq (W : Subspace K V₁) :
    W.dualPairing = W.quotAnnihilatorEquiv.toLinearMap := by
  ext
  rfl

takes longer if you make the universes explicit?! ext takes 11.8 seconds not 7.79 on my machine shrug

Matthew Ballard (May 19 2023 at 15:40):

I couldn't get past the declaration without explicit universes and didn't profile yet

Kevin Buzzard (May 19 2023 at 16:01):

Here is the behaviour of Type u behaving better than Type _ on mathlib master:

import Mathlib.LinearAlgebra.FiniteDimensional
import Mathlib.LinearAlgebra.Projection
import Mathlib.LinearAlgebra.SesquilinearForm
import Mathlib.RingTheory.Finiteness
import Mathlib.LinearAlgebra.FreeModule.Finite.Basic

noncomputable section

namespace Module

universe u v

variable (R : Type u) (M : Type v)

variable [CommSemiring R] [AddCommMonoid M] [Module R M]

/-- The dual space of an R-module M is the R-module of linear maps `M → R`. -/
@[reducible]
def Dual :=
  M →ₗ[R] R
#align module.dual Module.Dual

/-- The canonical pairing of a vector space and its algebraic dual. -/
def dualPairing (R M) [CommSemiring R] [AddCommMonoid M] [Module R M] :
    Module.Dual R M →ₗ[R] M →ₗ[R] R :=
  LinearMap.id
#align module.dual_pairing Module.dualPairing

end Module

namespace Submodule

universe u v

variable {R : Type u} {M : Type v} [CommSemiring R] [AddCommMonoid M] [Module R M]

variable {W : Submodule R M}

def dualRestrict (W : Submodule R M) : Module.Dual R M →ₗ[R] Module.Dual R W :=
  LinearMap.domRestrict' W

def dualAnnihilator {R : Type u} {M : Type v} [CommSemiring R] [AddCommMonoid M] [Module R M]
    (W : Submodule R M) : Submodule R <| Module.Dual R M :=
  LinearMap.ker W.dualRestrict

end Submodule

section CommRing

variable {R M M' : Type _}

variable [CommRing R] [AddCommGroup M] [Module R M] [AddCommGroup M'] [Module R M']

namespace Submodule

def dualPairing (W : Submodule R M) : Module.Dual R M  W.dualAnnihilator →ₗ[R] W →ₗ[R] R :=
  W.dualAnnihilator.liftQ W.dualRestrict le_rfl
#align submodule.dual_pairing Submodule.dualPairing

end Submodule

end CommRing

section test -- fun starts here

open Submodule

variable (R : Type _) (M : Type _) [CommRing R] [AddCommGroup M] [Module R M]

-- instant for rings.
example (W : Submodule R M) : Module.Dual R M  dualAnnihilator W →ₗ[R] Module.Dual R W :=
  W.dualPairing

-- But for fields it's slow. And how slow it is depends on whether you named your
-- universes!

-- Ku and Vu have explicit named universes
variable (Ku : Type u) (Vu : Type v) [Field Ku] [AddCommGroup Vu] [Module Ku Vu]

-- This is much slower than the ring example
example (W : Submodule Ku Vu) : Module.Dual Ku Vu  dualAnnihilator W →ₗ[Ku] Module.Dual Ku W :=
  W.dualPairing

-- But without explicit named universes...
variable (K : Type _) (V : Type _) [Field K] [AddCommGroup V] [Module K V]

-- this times out!
--set_option maxHeartbeats 1000000 in
example (W : Submodule K V) : Module.Dual K V  dualAnnihilator W →ₗ[K] Module.Dual K W :=
  W.dualPairing

end test

Kevin Buzzard (May 19 2023 at 16:11):

Note that this doesn't help with answering the question of why fields are slower than rings.

Matthew Ballard (May 19 2023 at 16:41):

This is slow but does not need bumps

def comp_dualPairing_mkQ_eq (W : Subspace K V₁) :
    LinearMap.comp W.dualPairing (mkQ W.dualAnnihilator) =
    LinearMap.comp W.quotAnnihilatorEquiv.toLinearMap (mkQ W.dualAnnihilator) := by
  ext
  rfl

Trying to stick this into dualPairing_eq is as bad as not

Kevin Buzzard (May 19 2023 at 20:05):

Here is the relevant trace for

variable (R : Type _) (M : Type _) [CommRing R] [AddCommGroup M] [Module R M]

example (W : Submodule R M) : Module.Dual R M  dualAnnihilator W →ₗ[R] Module.Dual R W :=
  W.dualPairing

:

(pp.all off)
[Meta.isDefEq] [0.003974s] ✅ Module.Dual R M ⧸ Submodule.dualAnnihilator W →ₗ[R]
      Module.Dual R { x // x ∈ W } =?= Module.Dual R M ⧸ Submodule.dualAnnihilator W →ₗ[R] { x // x ∈ W } →ₗ[R] R ▶

(pp.all on)
@LinearMap.{?u.18485, ?u.18485, max ?u.18488 ?u.18485, max ?u.18488 ?u.18485} R R
      (@CommSemiring.toSemiring.{?u.18485} R (@CommRing.toCommSemiring.{?u.18485} R inst✝²))
...
=?=
@LinearMap.{?u.18485, ?u.18485, max (max ?u.18485 ?u.18488) ?u.18488 ?u.18485,
          max ?u.18485 ?u.18488}
      R R (@CommSemiring.toSemiring.{?u.18485} R (@CommRing.toCommSemiring.{?u.18485} R inst✝²))
...

The universes don't quite match up, but the terms (which are huge) at least start off the same, and it wouldn't surprise me if they are very close to being the same modulo universe issues. Here in contrast is the trace for the fields, when we include the universes:

variable (Ku : Type u) (Vu : Type v) [Field Ku] [AddCommGroup Vu] [Module Ku Vu]

example (W : Submodule Ku Vu) : Module.Dual Ku Vu  dualAnnihilator W →ₗ[Ku] Module.Dual Ku W :=
  W.dualPairing

:

(pp.all off)
[Meta.isDefEq] [2.535892s] ✅ Module.Dual Ku Vu ⧸ Submodule.dualAnnihilator W →ₗ[Ku]
      Module.Dual Ku { x // x ∈ W } =?= Module.Dual Ku Vu ⧸ Submodule.dualAnnihilator W →ₗ[Ku] { x // x ∈ W } →ₗ[Ku] Ku ▼

(pp.all on)
LinearMap.{u, u, max v u, max v u} Ku Ku
      (@DivisionSemiring.toSemiring.{u} Ku (@Semifield.toDivisionSemiring.{u} Ku (@Field.toSemifield.{u} Ku inst✝²)))
...
=?=
@LinearMap.{u, u, max (max u v) v u, max u v} Ku Ku
      (@CommSemiring.toSemiring.{u} Ku
...

It takes a while to reconcile. It is not one big long thing, it's a huge tree of fairly quick things. Making the universes explicit means that Lean does not have to contemplate questions like ?u.18485 =?= ?u.18488 but allowing fields seems to make the total number of questions Lean asks rocket up. There are questions like AddMonoid.toAddSemigroup =?= AddMonoid.toAddSemigroup which in the ring case are just rfl and closed in 0.0000... seconds, but in the field case involve a lot of unfolding.

Making universes implicit as well just pushes it over the edge. But there are two independent issues here.

Matthew Ballard (May 19 2023 at 20:08):

Yeah it goes into the quotient many times each with a decent cost.

Matthew Ballard (May 19 2023 at 20:43):

I don't see a good near-term solution other than merge with the bumps in place for the moment so I've marked in awaiting-review

Matthew Ballard (May 19 2023 at 21:21):

Advert for !4#4124 LinearAlgebra.Contraction. It is almost across the line but I will be preparing/traveling this weekend. Please finish it off


Last updated: Dec 20 2023 at 11:08 UTC