Zulip Chat Archive

Stream: general

Topic: Semilinear maps


Frédéric Dupuis (Aug 19 2021 at 18:33):

For a while now, the fact that mathlib doesn't have conjugate linear maps has been blocking progress. For example, the map that takes an operator to its adjoint on a complex Hilbert space is a conjugate linear map, and so is the Riesz representation. This also prevents us from developing the orthogonal group, the unitary group, etc, properly. (See here for a discussion of this issue.)

Last October, @Yury G. Kudryashov proposed a solution involving redefining linear maps to be semilinear maps. A semilinear map f is a map from an R-module to an S-module with a ring equivalence σbetween R and S, such that f (c • x) = (σ c) • (f x). If we plug in the identity into σ, we get regular linear maps, and if we plug in the complex conjugate, we get conjugate linear maps. There are also other examples (e.g. Frobenius-linear maps) where this is useful which are covered by this general formulation.

Now, together with @Heather Macbeth and @Rob Lewis , we have implemented this idea on a ~1-month old version of mathlib! The result can be found on branch semilinear-option2. The main issue that we had to overcome involved composition of such maps, and symm for linear equivalences: having things like σ₁₂.trans σ₂₃ or σ.symm in the types of semilinear maps creates major problems. For example, we want the composition of two conjugate-linear maps to be a regular linear map, not
a conj.trans conj-linear map. To solve this issue, following a discussion from back in January, we created two typeclasses to make Lean infer the right ring equivalence. The first one is [ring_equiv_comp_triple σ₁₂ σ₂₃ σ₁₃] which expresses the fact that σ₁₂.trans σ₂₃ = σ₁₃, and the second one is [ring_equiv_inv_pair σ₁₂ σ₂₁] which states that σ₁₂ and σ₂₁ are inverses of each other. Note that (again following @Yury G. Kudryashov 's idea) we have introduced notation to ensure that regular linear maps can still be used as before, i.e. M →ₗ[R] N still works as before to mean a regular linear map.

This mostly works well (maybe even surprisingly so!). Regular linear maps work essentially the same as
before, and we have a proof-of-concept file that shows how it handles conjugate-linear maps (linear_algebra/conjugate_linear.lean).

Now, even though overall it works quite well, there is still a small cost to be paid:

  1. We have phased out the notation M →ₗ N (where the ring is not specified).
  2. When defining a regular linear map directly using the structure (i.e. when specifying to_fun, map_smul' and so on), there is a ring_equiv.refl that shows up in map_smul'. This can mostly be dsimp'ed away, but is mildly annoying.
  3. Elaboration seems slightly more brittle, and it fails a little bit more often than before. For example, when f is a linear map and g is something that can be coerced to a linear map (say a linear equiv), one has to write ↑g to make it work, or sometimes even to add a type annotation. This also occurs when using trans twice (i.e. e₁.trans (e₂.trans e₃)). To mitigate this problem, we have added new notation for composition of regular linear maps (∘ₗ for comp and ≫ₗ for trans). (Note that this is only provided to fix occasional elaboration issues and we don't necessarily expect this to replace comp and trans.)
  4. It seems to exacerbate the bug discussed here for reasons that we don't understand all that well right now. It manifests itself in very slow calls to the tactic ext, and the quick fix is to manually use the right ext lemma.
  5. A few random other issues that didn't arise often enough to see a pattern.

We would of course be very interested in PRing this to mathlib, and since this is such a big change we would like to solicit discussion here before actually going through with this.

Any thoughts?

Patrick Massot (Aug 19 2021 at 18:48):

Point 1 is no issue at all. I didn't even remember that notation existed. Point 2 seems very minor. Points 3 to 5 are extremely hard to evaluate without using the new setup.

Patrick Massot (Aug 19 2021 at 18:49):

Note also that the elaboration issue may change in Lean 4. I have no idea whether it would become better or worse.

Adam Topaz (Aug 19 2021 at 18:50):

Is there a particular reason why you want to use a ring equivalence as opposed to just a ring hom?

Heather Macbeth (Aug 19 2021 at 18:51):

@Adam Topaz Semilinear maps over a ring hom behave badly for certain constructions, in particular docs#submodule.map and docs#linear_map.range. It's not impossible to do the generalization to ring homs, but it's a lot less lightweight.

Adam Topaz (Aug 19 2021 at 18:52):

I'm mostly thinking of some examples from number theory... for example you might want to consider Frobenius semilinear maps over a non-perfect field.

Adam Topaz (Aug 19 2021 at 18:53):

It would be a shame to do such a massive refactor only to find out that it's not general enough to cover natural examples

Heather Macbeth (Aug 19 2021 at 18:54):

In particular, whenever map or range appear in a proof, you have to bump up your assumptions to the ring hom being a ring equiv (well, a one-sided equiv is enough ...). So you get include ... and omit ... everywhere.

Heather Macbeth (Aug 19 2021 at 18:54):

I tried it at branch#semilinear5 if you're curious. (see this commit
https://github.com/leanprover-community/mathlib/commit/a3a1cfc7accf602f92cd5e0e52a72bfce4735072 ) ... but got bored halfway through linear_algebra.basic

Heather Macbeth (Aug 19 2021 at 19:00):

Adam Topaz said:

It would be a shame to do such a massive refactor only to find out that it's not general enough to cover natural examples

I don't think the current version would preclude generalizing further to ring homs someday; the two tasks are basically independent. One mathlib has the ring equiv generalization, if you want to further generalize to ring homs, find-and-replacing most of the R ≃+* R₂ in the library to R →+* R₂ is the easy part, the hard part is fixing every proof involving map.

Eric Wieser (Aug 19 2021 at 19:04):

Why would you need include / omit vs just a cast from a ring_equiv to a ring_hom?

Anatole Dedecker (Aug 19 2021 at 19:06):

Yes that's what I was about to say. How hard would it be to setup the def to use ring_hom and then for the annoying lemmas you assume it's the coercion of some ring_equiv ?

Heather Macbeth (Aug 19 2021 at 19:07):

You still have to fix every annoying lemma separately, and that's the big task. Because in some sections of the library the needs-fixing lemmas are closely interspersed with the don't-need-fixing lemmas.

Eric Wieser (Aug 19 2021 at 19:07):

I have a hunch it might be best to setup the def to take just a plain function, for unification reasons

Anatole Dedecker (Aug 19 2021 at 19:08):

Oh okay I see the issue with include and omit now

Frédéric Dupuis (Aug 19 2021 at 19:08):

You would also have to be very careful to ensure that regular linear maps are defined with σ being the coercion from a ring_equiv.refl to a ring_hom and not a ring_hom.id. I'm not sure how annoying this would get.

Adam Topaz (Aug 19 2021 at 19:12):

docs#submodule.map should work whenever you're semilinear over a surjective ring hom. So again even for map using an equivalence is possibly not the right generalization (in my opinion)

Heather Macbeth (Aug 19 2021 at 19:13):

Right, this is what I was getting at with "one-sided equiv"

Heather Macbeth (Aug 19 2021 at 19:19):

Adam Topaz said:

I'm mostly thinking of some examples from number theory... for example you might want to consider Frobenius semilinear maps over a non-perfect field.

In this example, are the ring homs surjective?

Adam Topaz (Aug 19 2021 at 19:19):

No.

Heather Macbeth (Aug 19 2021 at 19:22):

So presumably one never uses the map construction for them anyway (i.e., we don't know a use case where we'd want map for semilinear maps over a surjective, non-bijective ring hom).

Eric Wieser (Aug 19 2021 at 19:34):

Frédéric Dupuis said:

You would also have to be very careful to ensure that regular linear maps are defined with σ being the coercion from a ring_equiv.refl to a ring_hom and not a ring_hom.id. I'm not sure how annoying this would get.

This is what I was referring to when I said
Eric Wieser said:

I have a hunch it might be best to setup the def to take just a plain function, for unification reasons

You're correct that ↑ring_equiv.refl = ring_hom.id is problematic as it is not true by rfl, but ⇑ring_equiv.refl = ⇑ring_hom.id does not suffer from the same problem.

Eric Wieser (Aug 19 2021 at 19:35):

Heather Macbeth said:

You still have to fix every annoying lemma separately, and that's the big task. Because in some sections of the library the needs-fixing lemmas are closely interspersed with the don't-need-fixing lemmas.

If we get the generality of the definition right we can always relax the lemmas about it later

Heather Macbeth (Aug 19 2021 at 19:36):

Eric Wieser said:

You're correct that ↑ring_equiv.refl = ring_hom.id is problematic as it is not true by rfl, but ⇑ring_equiv.refl = ⇑ring_hom.id does not suffer from the same problem.

Frederic was responding to Anatole's comment. The natural way in our formalism would be neither, but instead to use two ring homs together with

class ring_equiv_inv_pair : Prop :=
(is_inv_pair₁ : σ'.comp σ = ring_hom.id R₁)
(is_inv_pair₂ : σ.comp σ' = ring_hom.id R₂)

Eric Wieser (Aug 19 2021 at 19:41):

I guess the idea for writing lemmas that match A →ₗ[⇑σ] B or A →ₗ[↑σ] B would work for the σ : R ≃+* R' case but not for the surjective case @Adam Topaz was thinking about, since we don't have bundled surjective maps.

Heather Macbeth (Aug 19 2021 at 19:45):

Eric, what problem are you trying to address exactly? The experiment I tried at
https://github.com/leanprover-community/mathlib/commit/a3a1cfc7accf602f92cd5e0e52a72bfce4735072
failed for lack of energy, not because there was any technical problem.

Heather Macbeth (Aug 19 2021 at 19:47):

If we really want to allow for surjective rather than bijective ring homs in submodule.map, then split my typeclass above as

class ring_equiv_inv_pair_left : Prop :=
(is_inv_pair₁ : σ'.comp σ = ring_hom.id R₁) -- `σ` has a left inverse

class ring_equiv_inv_pair_right : Prop :=
(is_inv_pair₂ : σ.comp σ' = ring_hom.id R₂) -- `σ` has a right inverse

and use only the appropriate one.

Eric Wieser (Aug 19 2021 at 19:51):

I'm just exploring the consequences of Adam's suggestion to use ring_homs, because it was my first thought too. I haven't made any attempt at actually trying to do it or thought of a particularly compelling reason to do so.

Heather Macbeth (Aug 19 2021 at 19:51):

But at that commit I am using ring homs ...?

Eric Wieser (Aug 19 2021 at 19:52):

I think I somehow missed the message where you posted that 5 branch the first time; apologies!

Frédéric Dupuis (Aug 19 2021 at 20:00):

I think if we really want to have ring_homs instead of ring_equivs, we'll need to have a few more of these typeclasses to express the fact that they are surjective/bijective/whatever. Having to pass these facts as parameters to every lemma sounds untenable.

Heather Macbeth (Aug 19 2021 at 20:08):

@Frédéric Dupuis If we only need bijective, then nothing needs to change; we can get by with the same two typeclasses ring_equiv_comp_triple and ring_equiv_inv_pair as before, right?

Heather Macbeth (Aug 19 2021 at 20:08):

With ring_equiv_inv_pair expressing bijectivity.

Frédéric Dupuis (Aug 19 2021 at 20:23):

Well, the case where we only need bijective is basically what we've done. If we want to be able to define linear maps over any ring_hom, with lemmas that only work in specific cases (i.e. when σ is surjective bijective), then I think we need some more typeclasses.

Adam Topaz (Aug 19 2021 at 20:56):

Suppose that σ:AB\sigma : A \to B is a morphism of rings and let B0B_0 denote the image of σ\sigma.
Let f:MNf : M \to N be a σ\sigma-semilinear map.
Let HH be an AA-submodule of MM. The image f(H)f(H) is a B0B_0-submodule of NN. Consider the base-change BB0f(H)B \otimes_{B_0} f(H) of this B0B_0-submodule. This is now a BB-module, and it comes equipped with a natural morphism of BB-modules to NN. We can then take the image of this map. In explicit terms, this is going to be the BB-submodule of NN generated by the image of ff as a function. I think this deserves to be the correct generalization of docs#submodule.map for a semilinear map, and it doesn't require any further assumptions on σ\sigma.

Adam Topaz (Aug 19 2021 at 20:56):

The carrier set will not be defeq to the image of f as a function, of course, but it will be propeq in the case where σ\sigma is surjective.

Heather Macbeth (Aug 19 2021 at 21:00):

I see, so define submodule.map to have carrier span (f '' H) rather than just f '' H.

Johan Commelin (Aug 27 2021 at 10:36):

feat(linear_algebra): introduce notation for linear_map.comp and linear_equiv.trans #8857

is a PR by @Frédéric Dupuis that prepares the notation changes.

Johan Commelin (Aug 27 2021 at 10:37):

I'm in favour of making this change, but it would be good to try to align the notation as much as possible with the notation used in the category theory library.

Eric Wieser (Aug 27 2021 at 10:38):

What part of semilinear maps motivated the new notation?

Heather Macbeth (Aug 27 2021 at 13:42):

Frédéric Dupuis said:

  1. Elaboration seems slightly more brittle, and it fails a little bit more often than before. For example, when f is a linear map and g is something that can be coerced to a linear map (say a linear equiv), one has to write ↑g to make f.comp ↑g work, or sometimes even to add a type annotation. This also occurs when using trans twice (i.e. e₁.trans (e₂.trans e₃)). To mitigate this problem, we have added new notation for composition of regular linear maps (∘ₗ for comp and ≫ₗ for trans). (Note that this is only provided to fix occasional elaboration issues and we don't necessarily expect this to replace comp and trans.)

Adam Topaz (Aug 27 2021 at 15:40):

I guess the notation hack

notation f `∘'` := f.comp

will not help at all with this elaboration issue...

Frédéric Dupuis (Aug 27 2021 at 16:47):

Johan Commelin said:

I'm in favour of making this change, but it would be good to try to align the notation as much as possible with the notation used in the category theory library.

Did you have any specific suggestion in mind? In any case I agree; in fact I picked ≫ₗ for trans precisely to look like the category theory notation.

Frédéric Dupuis (Aug 27 2021 at 16:49):

Adam Topaz said:

I guess the notation hack

notation f `∘'` := f.comp

will not help at all with this elaboration issue...

Not yet :-) But in the upcoming main PR, it will be changed to

infixr ` ∘ₗ `:80 := @linear_map.comp _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
  (ring_hom.id _) (ring_hom.id _) (ring_hom.id _) ring_hom_comp_triple.ids

to hardcode the fact that both maps involved are plain linear maps.

Johan Commelin (Aug 27 2021 at 17:41):

Doesn't category theory use something like <<>> (but then the fancy unicode variant)?

Adam Topaz (Aug 27 2021 at 17:41):

See right after src#category_theory.iso.trans

Frédéric Dupuis (Aug 27 2021 at 18:08):

I see! I took my inspiration from src#category_theory.category_struct. Maybe the other one would be better.

Frédéric Dupuis (Aug 30 2021 at 12:28):

I have now changed the notation for trans to ≪≫ₗ.

Anne Baanen (Sep 06 2021 at 12:48):

People have had a week to complain, so now the notation is consistent, I'm going ahead and merging the PR.

Johan Commelin (Sep 07 2021 at 11:10):

@Heather Macbeth I'm doing some preliminary experiments with a is_tensor_product class. So far I'm mostly amazed by how often tensor products have already been used/imported in mathlib.

Frédéric Dupuis (Sep 19 2021 at 01:12):

I have now created the main PR for this: #9272. The main change since the discussion here is that we made it work with ring_homs instead of ring_equivs. The diff looks huge but it's not as bad as it looks: almost all of the meat is in algebra/module/basic and linear_algebra/basic, and the rest is small routine fixes.


Last updated: Dec 20 2023 at 11:08 UTC