Zulip Chat Archive

Stream: Is there code for X?

Topic: Basis for span of iterated linear map


Lucas Whitfield (Feb 05 2024 at 17:21):

I have V a finite dimensional vector space over some field F, a vector v and an endomorphism f. I want to show that I can find a basis of Span({f[k](v)kN}\{f^{[k]}(v) | k \in \mathbb{N}\}) given by looking at the first k vectors: (v,f(v),...,f[k](v))(v, f(v), ..., f^{[k]}(v)).

Are there any good tricks/results that exist to solve this?

import Mathlib.LinearAlgebra.FiniteDimensional

theorem exists_basis_iterate (F V : Type*) [Field F] [AddCommGroup V] [Module F V] [FiniteDimensional F V]
    (v : V) (f : V →ₗ[F] V) :  (k : ) (B : Basis (Fin k) F (Submodule.span F (Set.range (fun n  f^[n] v)))),
     i : Fin k, B i = f^[i] v := sorry

Junyan Xu (Feb 05 2024 at 17:37):

I'm not aware of any shortcut and I'd just define k to be the smallest such that f^[k] v isn't in the span of f^[i] v with i < k, and then inductively show f^[i] v with i < k are linearly independent using docs#linearIndependent_fin_snoc and docs#Nat.le_induction, and separately inductively show f^[i] v with i >= k lie in their span (where docs#Submodule.span_image could be useful).

Anatole Dedecker (Feb 05 2024 at 18:07):

There’s also an abstract argument through F[X] modules right ? Do we have the necessary glue for this ?

Jireh Loreaux (Feb 05 2024 at 18:41):

I don't think we do, but it would probably be nice to have it because I bet it would make all these sorts of generalized eigenvector / Jordan canonical form / rational canonical form arguments smoother in the long run.

Adam Topaz (Feb 05 2024 at 18:56):

I thought we had the structure theorem for modules over PIDs?

Adam Topaz (Feb 05 2024 at 18:57):

And I would hope that mathlib knows about the basis of K[X]/(f)K[X]/(f) in terms of monomials.

Riccardo Brasca (Feb 05 2024 at 19:06):

We have! It's in Mathlib.LinearAlgebra.FreeModule.PID.

Riccardo Brasca (Feb 05 2024 at 19:06):

It can probably be stated in several way and we may need some glue, but I think all the mathematics is there.

Anatole Dedecker (Feb 05 2024 at 19:17):

Ah, and the glue would be docs#Module.AEval' right?

Johan Commelin (Feb 05 2024 at 19:21):

It's maybe not exactly the result you are looking for, but often LinearMap.eventually_codisjoint_ker_pow_range_pow is quite useful.

Jireh Loreaux (Feb 05 2024 at 20:34):

Ah, I had no idea about Module.AEval'!

Junyan Xu (Feb 05 2024 at 21:46):

Following @Anatole Dedecker's idea:

import Mathlib.RingTheory.AdjoinRoot
import Mathlib.RingTheory.MvPolynomial.Basic

variable {F V : Type*} [Field F] [AddCommGroup V] [Module F V] [FiniteDimensional F V] (v : V) (f : V →ₗ[F] V)

open scoped Polynomial

noncomputable section

def toAEval' : F[X] →ₗ[F[X]] Module.AEval' f := LinearMap.toSpanSingleton F[X] _ (.of f v)

def gen : F[X] := Submodule.IsPrincipal.generator (LinearMap.ker (toAEval' v f))

def toAEval'' : F[X] →ₗ[F] V := (Module.AEval'.of f).symm ∘ₗ (toAEval' v f).restrictScalars F

lemma gen_ne_zero : gen v f  0 := fun h 
  Polynomial.not_finite <| FiniteDimensional.of_injective (toAEval'' v f) <| by
    apply_fun (Ideal.span {·}) at h
    rwa [gen, Ideal.span_singleton_generator,
      Ideal.span_singleton_eq_bot.mpr rfl, LinearMap.ker_eq_bot] at h

theorem toAEval''_monomial_one (n : ) : toAEval'' v f (Polynomial.monomial n 1) = f^[n] v := by
  simp [toAEval'', toAEval', LinearMap.coe_pow]

theorem range_toAEVal' : LinearMap.range (toAEval'' v f) = Submodule.span F (Set.range (f^[·] v)) := by
  rw [LinearMap.range_eq_map,  (Polynomial.basisMonomials F).span_eq, Submodule.map_span,  Set.range_comp]
  simp_rw [Function.comp, Polynomial.coe_basisMonomials, toAEval''_monomial_one]

def genEquiv : AdjoinRoot (gen v f) ≃ₗ[F] Submodule.span F (Set.range (f^[·] v)) :=
  (Submodule.quotEquivOfEq _ _ <| Submodule.IsPrincipal.span_singleton_generator _).restrictScalars F
    ≪≫ₗ (toAEval'' v f).quotKerEquivRange ≪≫ₗ .ofEq _ _ (range_toAEVal' v f)

theorem exists_basis_iterate :  (k : ) (B : Basis (Fin k) F <| Submodule.span F <| Set.range (f^[·] v)),
     i : Fin k, B i = f^[i] v :=
  _, (AdjoinRoot.powerBasis <| gen_ne_zero v f).basis.map (genEquiv v f), fun i  by
    rw [Basis.map_apply, PowerBasis.coe_basis]
    change toAEval'' v f (Polynomial.X ^ i) = _
    rw [ Polynomial.monomial_one_right_eq_X_pow, toAEval''_monomial_one]⟩

Anatole Dedecker (Feb 05 2024 at 21:52):

Nice, I’ve learnt a dozen of "algebra in Lean" tricks by reading this :tada:

Patrick Massot (Feb 05 2024 at 21:53):

What is ≪≫ₗ??

Anatole Dedecker (Feb 05 2024 at 21:54):

Is it annoying to define the generator in terms of docs#Submodule.annihilator instead ? I think it would be more natural

Anatole Dedecker (Feb 05 2024 at 21:55):

Patrick Massot said:

What is ≪≫ₗ??

docs#LinearEquiv.trans

Junyan Xu (Feb 05 2024 at 22:14):

Anatole Dedecker said:

Is it annoying to define the generator in terms of docs#Submodule.annihilator instead ? I think it would be more natural

You'd need to obtain a F[X]-module structure on Submodule.span F (Set.range (f^[·] v)) (or rather its copy in Module.AEval' f) using docs#Module.AEval.mapSubmodule, which may or may not be simpler ...

Anatole Dedecker (Feb 05 2024 at 22:20):

Could you move only v to Module.AEval' f and take the F[X]-span there ?

Junyan Xu (Feb 05 2024 at 22:28):

Not sure what you mean, but we could restrict f : V →ₗ[F] V (i.e. f : Module.End F V) to f' : Module.End F (Submodule.span F (Set.range (f^[·] v))) using docs#LinearMap.domRestrict and docs#LinearMap.codRestrict, and then we can just take minpoly F f'. But another concern is that iterated f is not defeq to iterated f', and I don't know whether a relevant lemma exists ...

Anatole Dedecker (Feb 05 2024 at 22:31):

I mean define gen as a generator of the annihilator of Submodule.span F[X] (AEval'.of f v) (hope that makes sense, I’m on mobile…)

Junyan Xu (Feb 05 2024 at 22:56):

I think my definition of gen makes things easier because it's the generator of a kernel, so you can immediately apply the first isomorphism theorem and get an isomorphism between the quotient (defeq to AdjoinRoot) and the range (a submodule in Module.AEval' f). With your suggestion

  def gen : F[X] := Submodule.IsPrincipal.generator (Submodule.span F[X] {Module.AEval'.of f v}).annihilator

although the annihilator is also defined as a kernel

    Submodule.annihilator N = LinearMap.ker (LinearMap.lsmul R N)

the image is a submodule in Module.End R N where N := span F[X] {Module.AEval'.of f v}, and it's not straightforward to connect this to a submodule of Module.AEval' f and then to V. I hope I'm not missing something!

Anatole Dedecker (Feb 05 2024 at 23:00):

I haven’t thought about it carefully, I was genuinely asking wether it got harder and I was half-expecting the answer to be yes ! I’ll have to think more about it tomorrow

Anatole Dedecker (Feb 05 2024 at 23:03):

Last idea if you want to try it : what about doing everything in an F[X] module for the multiplication by X map, and then only going back to f at the end, which should be easy since the statement is about F vector spaces with an endomorphism ?

Junyan Xu (Feb 05 2024 at 23:22):

If W is a f.d. F[X]-module and w : W, you should be able to prove

example :  (k : ) (B : Basis (Fin k) F <| Submodule.span F <| Set.range (X ^ ·  w)),
     i : Fin k, B i = X ^ i  w :=

or maybe

example :  (k : ) (B : Basis (Fin k) F <| Submodule.span F[X] w),

the same way.
Then you can apply this to W := Module.AEval' f and use the F-LinearEquiv (or abuse defeq) between W and V and get the result in terms of f^[n]. This definitely seems a reasonable refactoring to do.

Adam Topaz (Feb 05 2024 at 23:45):

Anatole Dedecker said:

Patrick Massot said:

What is ≪≫ₗ??

docs#LinearEquiv.trans

This is motivated by the notation for docs#CategoryTheory.Iso.trans


Last updated: May 02 2025 at 03:31 UTC