diff options
Diffstat (limited to 'mathcomp/algebra/vector.v')
| -rw-r--r-- | mathcomp/algebra/vector.v | 2040 |
1 files changed, 2040 insertions, 0 deletions
diff --git a/mathcomp/algebra/vector.v b/mathcomp/algebra/vector.v new file mode 100644 index 0000000..2cb59e9 --- /dev/null +++ b/mathcomp/algebra/vector.v @@ -0,0 +1,2040 @@ +(* (c) Copyright Microsoft Corporation and Inria. All rights reserved. *) +Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq choice fintype bigop. +Require Import finfun tuple ssralg matrix mxalgebra zmodp. + +(******************************************************************************) +(* * Finite dimensional vector spaces *) +(* vectType R == interface structure for finite dimensional (more *) +(* precisely, detachable) vector spaces over R, which *) +(* should be at least a ringType. *) +(* Vector.axiom n M <-> type M is linearly isomorphic to 'rV_n. *) +(* := {v2r : M -> 'rV_n| linear v2r & bijective v2r}. *) +(* VectMixin isoM == packages a proof isoV of Vector.axiom n M as the *) +(* vectType mixin for an n-dimensional R-space *) +(* structure on a type M that is an lmodType R. *) +(* VectType K M mT == packs the vectType mixin mT to into a vectType K *) +(* instance for T; T should have an lmodType K *) +(* canonical instance. *) +(* [vectType R of T for vS] == a copy of the vS : vectType R structure where *) +(* the sort is replaced by T; vS : lmodType R should *) +(* be convertible to a canonical lmodType for T. *) +(* [vectType R of V] == a clone of an existing vectType R structure on V. *) +(* {vspace vT} == the type of (detachable) subspaces of vT; vT *) +(* should have a vectType structure over a fieldType. *) +(* subvs_of U == the subtype of elements of V in the subspace U. *) +(* This is canonically a vectType. *) +(* vsval u == linear injection of u : subvs_of U into V. *) +(* vsproj U v == linear projection of v : V in subvs U. *) +(* 'Hom(aT, rT) == the type of linear functions (homomorphisms) from *) +(* aT to rT, where aT and rT ARE vectType structures. *) +(* Elements of 'Hom(aT, rT) coerce to Coq functions. *) +(* --> Caveat: aT and rT must denote actual vectType structures, not their *) +(* projections on Type. *) +(* linfun f == a vector linear function in 'Hom(aT, rT) that *) +(* coincides with f : aT -> rT when f is linear. *) +(* 'End(vT) == endomorphisms of vT (:= 'Hom(vT, vT)). *) +(* --> The types subvs_of U, 'Hom(aT, rT), 'End(vT), K^o, 'M[K]_(m, n), *) +(* vT * wT, {ffun I -> vT}, vT ^ n all have canonical vectType instances. *) +(* *) +(* Functions: *) +(* <[v]>%VS == the vector space generated by v (a line if v != 0).*) +(* 0%VS == the trivial vector subspace. *) +(* fullv, {:vT} == the complete vector subspace (displays as fullv). *) +(* (U + V)%VS == the join (sum) of two subspaces U and V. *) +(* (U :&: V)%VS == intersection of vector subspaces U and V. *) +(* (U^C)%VS == a complement of the vector subspace U. *) +(* (U :\: V)%VS == a local complement to U :& V in the subspace U. *) +(* \dim U == dimension of a vector space U. *) +(* span X, <<X>>%VS == the subspace spanned by the vector sequence X. *) +(* coord X i v == i'th coordinate of v on X, when v \in <<X>>%VS and *) +(* where X : n.-tuple vT and i : 'I_n. Note that *) +(* coord X i is a scalar function. *) +(* vpick U == a nonzero element of U if U= 0%VS, or 0 if U = 0. *) +(* vbasis U == a (\dim U).-tuple that is a basis of U. *) +(* \1%VF == the identity linear function. *) +(* (f \o g)%VF == the composite of two linear functions f and g. *) +(* (f^-1)%VF == a linear function that is a right inverse to the *) +(* linear function f on the codomain of f. *) +(* (f @: U)%VS == the image of vs by the linear function f. *) +(* (f @^-1: U)%VS == the pre-image of vs by the linear function f. *) +(* lker f == the kernel of the linear function f. *) +(* limg f == the image of the linear function f. *) +(* fixedSpace f == the fixed space of a linear endomorphism f *) +(* daddv_pi U V == projection onto U along V if U and V are disjoint; *) +(* daddv_pi U V + daddv_pi V U is then a projection *) +(* onto the direct sum (U + V)%VS. *) +(* projv U == projection onto U (along U^C, := daddv_pi U U^C). *) +(* addv_pi1 U V == projection onto the subspace U :\: V of U along V. *) +(* addv_pi2 U V == projection onto V along U :\: V; note that *) +(* addv_pi1 U V and addv_pi2 U V are (asymmetrical) *) +(* complementary projections on (U + V)%VS. *) +(* sumv_pi_for defV i == for defV : V = (V \sum_(j <- r | P j) Vs j)%VS, *) +(* j ranging over an eqType, this is a projection on *) +(* a subspace of Vs i, along a complement in V, such *) +(* that \sum_(j <- r | P j) sumv_pi_for defV j is a *) +(* projection onto V if filter P r is duplicate-free *) +(* (e.g., when V := \sum_(j | P j) Vs j). *) +(* sumv_pi V i == notation the above when defV == erefl V, and V is *) +(* convertible to \sum_(j <- r | P j) Vs j)%VS. *) +(* *) +(* Predicates: *) +(* v \in U == v belongs to U (:= (<[v]> <= U)%VS). *) +(* (U <= V)%VS == U is a subspace of V. *) +(* free B == B is a sequence of nonzero linearly independent *) +(* vectors. *) +(* basis_of U b == b is a basis of the subspace U. *) +(* directv S == S is the expression for a direct sum of subspaces. *) +(******************************************************************************) + +Set Implicit Arguments. +Unset Strict Implicit. +Unset Printing Implicit Defensive. +Open Local Scope ring_scope. + +Reserved Notation "{ 'vspace' T }" (at level 0, format "{ 'vspace' T }"). +Reserved Notation "''Hom' ( T , rT )" (at level 8, format "''Hom' ( T , rT )"). +Reserved Notation "''End' ( T )" (at level 8, format "''End' ( T )"). +Reserved Notation "\dim A" (at level 10, A at level 8, format "\dim A"). + +Delimit Scope vspace_scope with VS. + +Import GRing.Theory. + +(* Finite dimension vector space *) +Module Vector. + +Section ClassDef. +Variable R : ringType. + +Definition axiom_def n (V : lmodType R) of phant V := + {v2r : V -> 'rV[R]_n | linear v2r & bijective v2r}. + +Inductive mixin_of (V : lmodType R) := Mixin dim & axiom_def dim (Phant V). + +Structure class_of V := Class { + base : GRing.Lmodule.class_of R V; + mixin : mixin_of (GRing.Lmodule.Pack _ base V) +}. +Local Coercion base : class_of >-> GRing.Lmodule.class_of. + +Structure type (phR : phant R) := Pack {sort; _ : class_of sort; _ : Type}. +Local Coercion sort : type >-> Sortclass. +Variables (phR : phant R) (T : Type) (cT : type phR). +Definition class := let: Pack _ c _ := cT return class_of cT in c. +Definition clone c of phant_id class c := @Pack phR T c T. +Let xT := let: Pack T _ _ := cT in T. +Notation xclass := (class : class_of xT). +Definition dim := let: Mixin n _ := mixin class in n. + +Definition pack b0 (m0 : mixin_of (@GRing.Lmodule.Pack R _ T b0 T)) := + fun bT b & phant_id (@GRing.Lmodule.class _ phR bT) b => + fun m & phant_id m0 m => Pack phR (@Class T b m) T. + +Definition eqType := @Equality.Pack cT xclass xT. +Definition choiceType := @Choice.Pack cT xclass xT. +Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. +Definition lmodType := @GRing.Lmodule.Pack R phR cT xclass xT. + +End ClassDef. +Notation axiom n V := (axiom_def n (Phant V)). + +Section OtherDefs. +Local Coercion sort : type >-> Sortclass. +Local Coercion dim : type >-> nat. +Inductive space (K : fieldType) (vT : type (Phant K)) (phV : phant vT) := + Space (mx : 'M[K]_vT) & <<mx>>%MS == mx. +Inductive hom (R : ringType) (vT wT : type (Phant R)) := + Hom of 'M[R]_(vT, wT). +End OtherDefs. + +Module Import Exports. + +Coercion base : class_of >-> GRing.Lmodule.class_of. +Coercion mixin : class_of >-> mixin_of. +Coercion sort : type >-> Sortclass. +Coercion eqType: type >-> Equality.type. +Bind Scope ring_scope with sort. +Canonical eqType. +Coercion choiceType: type >-> Choice.type. +Canonical choiceType. +Coercion zmodType: type >-> GRing.Zmodule.type. +Canonical zmodType. +Coercion lmodType: type>-> GRing.Lmodule.type. +Canonical lmodType. +Notation vectType R := (@type _ (Phant R)). +Notation VectType R V mV := + (@pack _ (Phant R) V _ mV _ _ id _ id). +Notation VectMixin := Mixin. +Notation "[ 'vectType' R 'of' T 'for' cT ]" := (@clone _ (Phant R) T cT _ idfun) + (at level 0, format "[ 'vectType' R 'of' T 'for' cT ]") : form_scope. +Notation "[ 'vectType' R 'of' T ]" := (@clone _ (Phant R) T _ _ idfun) + (at level 0, format "[ 'vectType' R 'of' T ]") : form_scope. + +Notation "{ 'vspace' vT }" := (space (Phant vT)) : type_scope. +Notation "''Hom' ( aT , rT )" := (hom aT rT) : type_scope. +Notation "''End' ( vT )" := (hom vT vT) : type_scope. + +Prenex Implicits Hom. + +Delimit Scope vspace_scope with VS. +Bind Scope vspace_scope with space. +Delimit Scope lfun_scope with VF. +Bind Scope lfun_scope with hom. + +End Exports. + +(* The contents of this module exposes the matrix encodings, and should *) +(* therefore not be used outside of the vector library implementation. *) +Module InternalTheory. + +Section Iso. +Variables (R : ringType) (vT rT : vectType R). +Local Coercion dim : vectType >-> nat. + +Fact v2r_subproof : axiom vT vT. Proof. by case: vT => T [bT []]. Qed. +Definition v2r := s2val v2r_subproof. + +Let v2r_bij : bijective v2r := s2valP' v2r_subproof. +Fact r2v_subproof : {r2v | cancel r2v v2r}. +Proof. +have r2vP r: {v | v2r v = r}. + by apply: sig_eqW; have [v _ vK] := v2r_bij; exists (v r). +by exists (fun r => sval (r2vP r)) => r; case: (r2vP r). +Qed. +Definition r2v := sval r2v_subproof. + +Lemma r2vK : cancel r2v v2r. Proof. exact: (svalP r2v_subproof). Qed. +Lemma r2v_inj : injective r2v. Proof. exact: can_inj r2vK. Qed. +Lemma v2rK : cancel v2r r2v. Proof. by have/bij_can_sym:= r2vK; apply. Qed. +Lemma v2r_inj : injective v2r. Proof. exact: can_inj v2rK. Qed. + +Canonical v2r_linear := Linear (s2valP v2r_subproof : linear v2r). +Canonical r2v_linear := Linear (can2_linear v2rK r2vK). +End Iso. + +Section Vspace. +Variables (K : fieldType) (vT : vectType K). +Local Coercion dim : vectType >-> nat. + +Definition b2mx n (X : n.-tuple vT) := \matrix_i v2r (tnth X i). +Lemma b2mxK n (X : n.-tuple vT) i : r2v (row i (b2mx X)) = X`_i. +Proof. by rewrite rowK v2rK -tnth_nth. Qed. + +Definition vs2mx {phV} (U : @space K vT phV) := let: Space mx _ := U in mx. +Lemma gen_vs2mx (U : {vspace vT}) : <<vs2mx U>>%MS = vs2mx U. +Proof. by apply/eqP; rewrite /vs2mx; case: U. Qed. + +Fact mx2vs_subproof m (A : 'M[K]_(m, vT)) : <<(<<A>>)>>%MS == <<A>>%MS. +Proof. by rewrite genmx_id. Qed. +Definition mx2vs {m} A : {vspace vT} := Space _ (@mx2vs_subproof m A). + +Canonical space_subType := [subType for @vs2mx (Phant vT)]. +Lemma vs2mxK : cancel vs2mx mx2vs. +Proof. by move=> v; apply: val_inj; rewrite /= gen_vs2mx. Qed. +Lemma mx2vsK m (M : 'M_(m, vT)) : (vs2mx (mx2vs M) :=: M)%MS. +Proof. exact: genmxE. Qed. +End Vspace. + +Section Hom. +Variables (R : ringType) (aT rT : vectType R). +Definition f2mx (f : 'Hom(aT, rT)) := let: Hom A := f in A. +Canonical hom_subType := [newType for f2mx]. +End Hom. + +Arguments Scope mx2vs [_ _ nat_scope matrix_set_scope]. +Prenex Implicits v2r r2v v2rK r2vK b2mx vs2mx vs2mxK f2mx. + +End InternalTheory. + +End Vector. +Export Vector.Exports. +Import Vector.InternalTheory. + +Section VspaceDefs. + +Variables (K : fieldType) (vT : vectType K). +Implicit Types (u : vT) (X : seq vT) (U V : {vspace vT}). + +Definition space_eqMixin := Eval hnf in [eqMixin of {vspace vT} by <:]. +Canonical space_eqType := EqType {vspace vT} space_eqMixin. +Definition space_choiceMixin := Eval hnf in [choiceMixin of {vspace vT} by <:]. +Canonical space_choiceType := ChoiceType {vspace vT} space_choiceMixin. + +Definition dimv U := \rank (vs2mx U). +Definition subsetv U V := (vs2mx U <= vs2mx V)%MS. +Definition vline u := mx2vs (v2r u). + +(* Vspace membership is defined as line inclusion. *) +Definition pred_of_vspace phV (U : Vector.space phV) : pred_class := + fun v => (vs2mx (vline v) <= vs2mx U)%MS. +Canonical vspace_predType := + @mkPredType _ (unkeyed {vspace vT}) (@pred_of_vspace _). + +Definition fullv : {vspace vT} := mx2vs 1%:M. +Definition addv U V := mx2vs (vs2mx U + vs2mx V). +Definition capv U V := mx2vs (vs2mx U :&: vs2mx V). +Definition complv U := mx2vs (vs2mx U)^C. +Definition diffv U V := mx2vs (vs2mx U :\: vs2mx V). +Definition vpick U := r2v (nz_row (vs2mx U)). +Fact span_key : unit. Proof. by []. Qed. +Definition span_expanded_def X := mx2vs (b2mx (in_tuple X)). +Definition span := locked_with span_key span_expanded_def. +Canonical span_unlockable := [unlockable fun span]. +Definition vbasis_def U := + [tuple r2v (row i (row_base (vs2mx U))) | i < dimv U]. +Definition vbasis := locked_with span_key vbasis_def. +Canonical vbasis_unlockable := [unlockable fun vbasis]. + +(* coord and directv are defined in the VectorTheory section. *) + +Definition free X := dimv (span X) == size X. +Definition basis_of U X := (span X == U) && free X. + +End VspaceDefs. + +Coercion pred_of_vspace : Vector.space >-> pred_class. +Notation "\dim U" := (dimv U) : nat_scope. +Notation "U <= V" := (subsetv U V) : vspace_scope. +Notation "U <= V <= W" := (subsetv U V && subsetv V W) : vspace_scope. +Notation "<[ v ] >" := (vline v) : vspace_scope. +Notation "<< X >>" := (span X) : vspace_scope. +Notation "0" := (vline 0) : vspace_scope. +Implicit Arguments fullv [[K] [vT]]. +Prenex Implicits subsetv addv capv complv diffv span free basis_of. + +Notation "U + V" := (addv U V) : vspace_scope. +Notation "U :&: V" := (capv U V) : vspace_scope. +Notation "U ^C" := (complv U) (at level 8, format "U ^C") : vspace_scope. +Notation "U :\: V" := (diffv U V) : vspace_scope. +Notation "{ : vT }" := (@fullv _ vT) (only parsing) : vspace_scope. + +Notation "\sum_ ( i <- r | P ) U" := + (\big[addv/0%VS]_(i <- r | P%B) U%VS) : vspace_scope. +Notation "\sum_ ( i <- r ) U" := + (\big[addv/0%VS]_(i <- r) U%VS) : vspace_scope. +Notation "\sum_ ( m <= i < n | P ) U" := + (\big[addv/0%VS]_(m <= i < n | P%B) U%VS) : vspace_scope. +Notation "\sum_ ( m <= i < n ) U" := + (\big[addv/0%VS]_(m <= i < n) U%VS) : vspace_scope. +Notation "\sum_ ( i | P ) U" := + (\big[addv/0%VS]_(i | P%B) U%VS) : vspace_scope. +Notation "\sum_ i U" := + (\big[addv/0%VS]_i U%VS) : vspace_scope. +Notation "\sum_ ( i : t | P ) U" := + (\big[addv/0%VS]_(i : t | P%B) U%VS) (only parsing) : vspace_scope. +Notation "\sum_ ( i : t ) U" := + (\big[addv/0%VS]_(i : t) U%VS) (only parsing) : vspace_scope. +Notation "\sum_ ( i < n | P ) U" := + (\big[addv/0%VS]_(i < n | P%B) U%VS) : vspace_scope. +Notation "\sum_ ( i < n ) U" := + (\big[addv/0%VS]_(i < n) U%VS) : vspace_scope. +Notation "\sum_ ( i 'in' A | P ) U" := + (\big[addv/0%VS]_(i in A | P%B) U%VS) : vspace_scope. +Notation "\sum_ ( i 'in' A ) U" := + (\big[addv/0%VS]_(i in A) U%VS) : vspace_scope. + +Notation "\bigcap_ ( i <- r | P ) U" := + (\big[capv/fullv]_(i <- r | P%B) U%VS) : vspace_scope. +Notation "\bigcap_ ( i <- r ) U" := + (\big[capv/fullv]_(i <- r) U%VS) : vspace_scope. +Notation "\bigcap_ ( m <= i < n | P ) U" := + (\big[capv/fullv]_(m <= i < n | P%B) U%VS) : vspace_scope. +Notation "\bigcap_ ( m <= i < n ) U" := + (\big[capv/fullv]_(m <= i < n) U%VS) : vspace_scope. +Notation "\bigcap_ ( i | P ) U" := + (\big[capv/fullv]_(i | P%B) U%VS) : vspace_scope. +Notation "\bigcap_ i U" := + (\big[capv/fullv]_i U%VS) : vspace_scope. +Notation "\bigcap_ ( i : t | P ) U" := + (\big[capv/fullv]_(i : t | P%B) U%VS) (only parsing) : vspace_scope. +Notation "\bigcap_ ( i : t ) U" := + (\big[capv/fullv]_(i : t) U%VS) (only parsing) : vspace_scope. +Notation "\bigcap_ ( i < n | P ) U" := + (\big[capv/fullv]_(i < n | P%B) U%VS) : vspace_scope. +Notation "\bigcap_ ( i < n ) U" := + (\big[capv/fullv]_(i < n) U%VS) : vspace_scope. +Notation "\bigcap_ ( i 'in' A | P ) U" := + (\big[capv/fullv]_(i in A | P%B) U%VS) : vspace_scope. +Notation "\bigcap_ ( i 'in' A ) U" := + (\big[capv/fullv]_(i in A) U%VS) : vspace_scope. + +Section VectorTheory. + +Variables (K : fieldType) (vT : vectType K). +Implicit Types (a : K) (u v w : vT) (X Y : seq vT) (U V W : {vspace vT}). + +Local Notation subV := (@subsetv K vT) (only parsing). +Local Notation addV := (@addv K vT) (only parsing). +Local Notation capV := (@capv K vT) (only parsing). + +(* begin hide *) + +(* Internal theory facts *) +Let vs2mxP U V : reflect (U = V) (vs2mx U == vs2mx V)%MS. +Proof. by rewrite (sameP genmxP eqP) !gen_vs2mx; apply: eqP. Qed. + +Let memvK v U : (v \in U) = (v2r v <= vs2mx U)%MS. +Proof. by rewrite -genmxE. Qed. + +Let mem_r2v rv U : (r2v rv \in U) = (rv <= vs2mx U)%MS. +Proof. by rewrite memvK r2vK. Qed. + +Let vs2mx0 : @vs2mx K vT _ 0 = 0. +Proof. by rewrite /= linear0 genmx0. Qed. + +Let vs2mxD U V : vs2mx (U + V) = (vs2mx U + vs2mx V)%MS. +Proof. by rewrite /= genmx_adds !gen_vs2mx. Qed. + +Let vs2mx_sum := big_morph _ vs2mxD vs2mx0. + +Let vs2mxI U V : vs2mx (U :&: V) = (vs2mx U :&: vs2mx V)%MS. +Proof. by rewrite /= genmx_cap !gen_vs2mx. Qed. + +Let vs2mxF : vs2mx {:vT} = 1%:M. +Proof. by rewrite /= genmx1. Qed. + +Let row_b2mx n (X : n.-tuple vT) i : row i (b2mx X) = v2r X`_i. +Proof. by rewrite -tnth_nth rowK. Qed. + +Let span_b2mx n (X : n.-tuple vT) : span X = mx2vs (b2mx X). +Proof. by rewrite unlock tvalK; case: _ / (esym _). Qed. + +Let mul_b2mx n (X : n.-tuple vT) (rk : 'rV_n) : + \sum_i rk 0 i *: X`_i = r2v (rk *m b2mx X). +Proof. +rewrite mulmx_sum_row linear_sum; apply: eq_bigr => i _. +by rewrite row_b2mx linearZ /= v2rK. +Qed. + +Let lin_b2mx n (X : n.-tuple vT) k : + \sum_(i < n) k i *: X`_i = r2v (\row_i k i *m b2mx X). +Proof. by rewrite -mul_b2mx; apply: eq_bigr => i _; rewrite mxE. Qed. + +Let free_b2mx n (X : n.-tuple vT) : free X = row_free (b2mx X). +Proof. by rewrite /free /dimv span_b2mx genmxE size_tuple. Qed. +(* end hide *) + +Fact vspace_key U : pred_key U. Proof. by []. Qed. +Canonical vspace_keyed U := KeyedPred (vspace_key U). + +Lemma memvE v U : (v \in U) = (<[v]> <= U)%VS. Proof. by []. Qed. + +Lemma vlineP v1 v2 : reflect (exists k, v1 = k *: v2) (v1 \in <[v2]>)%VS. +Proof. +apply: (iffP idP) => [|[k ->]]; rewrite memvK genmxE ?linearZ ?scalemx_sub //. +by case/sub_rVP=> k; rewrite -linearZ => /v2r_inj->; exists k. +Qed. + +Fact memv_submod_closed U : submod_closed U. +Proof. +split=> [|a u v]; rewrite !memvK ?linear0 ?sub0mx // => Uu Uv. +by rewrite linearP addmx_sub ?scalemx_sub. +Qed. +Canonical memv_opprPred U := OpprPred (memv_submod_closed U). +Canonical memv_addrPred U := AddrPred (memv_submod_closed U). +Canonical memv_zmodPred U := ZmodPred (memv_submod_closed U). +Canonical memv_submodPred U := SubmodPred (memv_submod_closed U). + +Lemma mem0v U : 0 \in U. Proof. exact : rpred0. Qed. +Lemma memvN U v : (- v \in U) = (v \in U). Proof. exact: rpredN. Qed. +Lemma memvD U : {in U &, forall u v, u + v \in U}. Proof. exact : rpredD. Qed. +Lemma memvB U : {in U &, forall u v, u - v \in U}. Proof. exact : rpredB. Qed. +Lemma memvZ U k : {in U, forall v, k *: v \in U}. Proof. exact : rpredZ. Qed. + +Lemma memv_suml I r (P : pred I) vs U : + (forall i, P i -> vs i \in U) -> \sum_(i <- r | P i) vs i \in U. +Proof. exact: rpred_sum. Qed. + +Lemma memv_line u : u \in <[u]>%VS. +Proof. by apply/vlineP; exists 1; rewrite scale1r. Qed. + +Lemma subvP U V : reflect {subset U <= V} (U <= V)%VS. +Proof. +apply: (iffP rV_subP) => sU12 u. + by rewrite !memvE /subsetv !genmxE => /sU12. +by have:= sU12 (r2v u); rewrite !memvE /subsetv !genmxE r2vK. +Qed. + +Lemma subvv U : (U <= U)%VS. Proof. exact/subvP. Qed. +Hint Resolve subvv. + +Lemma subv_trans : transitive subV. +Proof. by move=> U V W /subvP sUV /subvP sVW; apply/subvP=> u /sUV/sVW. Qed. + +Lemma subv_anti : antisymmetric subV. +Proof. by move=> U V; apply/vs2mxP. Qed. + +Lemma eqEsubv U V : (U == V) = (U <= V <= U)%VS. +Proof. by apply/eqP/idP=> [-> | /subv_anti//]; rewrite subvv. Qed. + +Lemma vspaceP U V : U =i V <-> U = V. +Proof. +split=> [eqUV | -> //]; apply/subv_anti/andP. +by split; apply/subvP=> v; rewrite eqUV. +Qed. + +Lemma subvPn {U V} : reflect (exists2 u, u \in U & u \notin V) (~~ (U <= V)%VS). +Proof. +apply: (iffP idP) => [|[u Uu]]; last by apply: contra => /subvP->. +case/row_subPn=> i; set vi := row i _ => V'vi. +by exists (r2v vi); rewrite memvK r2vK ?row_sub. +Qed. + +(* Empty space. *) +Lemma sub0v U : (0 <= U)%VS. +Proof. exact: mem0v. Qed. + +Lemma subv0 U : (U <= 0)%VS = (U == 0%VS). +Proof. by rewrite eqEsubv sub0v andbT. Qed. + +Lemma memv0 v : v \in 0%VS = (v == 0). +Proof. by apply/idP/eqP=> [/vlineP[k ->] | ->]; rewrite (scaler0, mem0v). Qed. + +(* Full space *) + +Lemma subvf U : (U <= fullv)%VS. Proof. by rewrite /subsetv vs2mxF submx1. Qed. +Lemma memvf v : v \in fullv. Proof. exact: subvf. Qed. + +(* Picking a non-zero vector in a subspace. *) +Lemma memv_pick U : vpick U \in U. Proof. by rewrite mem_r2v nz_row_sub. Qed. + +Lemma vpick0 U : (vpick U == 0) = (U == 0%VS). +Proof. by rewrite -memv0 mem_r2v -subv0 /subV vs2mx0 !submx0 nz_row_eq0. Qed. + +(* Sum of subspaces. *) +Lemma subv_add U V W : (U + V <= W)%VS = (U <= W)%VS && (V <= W)%VS. +Proof. by rewrite /subV vs2mxD addsmx_sub. Qed. + +Lemma addvS U1 U2 V1 V2 : (U1 <= U2 -> V1 <= V2 -> U1 + V1 <= U2 + V2)%VS. +Proof. by rewrite /subV !vs2mxD; apply: addsmxS. Qed. + +Lemma addvSl U V : (U <= U + V)%VS. +Proof. by rewrite /subV vs2mxD addsmxSl. Qed. + +Lemma addvSr U V : (V <= U + V)%VS. +Proof. by rewrite /subV vs2mxD addsmxSr. Qed. + +Lemma addvC : commutative addV. +Proof. by move=> U V; apply/vs2mxP; rewrite !vs2mxD addsmxC submx_refl. Qed. + +Lemma addvA : associative addV. +Proof. by move=> U V W; apply/vs2mxP; rewrite !vs2mxD addsmxA submx_refl. Qed. + +Lemma addv_idPl {U V}: reflect (U + V = U)%VS (V <= U)%VS. +Proof. by rewrite /subV (sameP addsmx_idPl eqmxP) -vs2mxD; apply: vs2mxP. Qed. + +Lemma addv_idPr {U V} : reflect (U + V = V)%VS (U <= V)%VS. +Proof. by rewrite addvC; apply: addv_idPl. Qed. + +Lemma addvv : idempotent addV. +Proof. by move=> U; apply/addv_idPl. Qed. + +Lemma add0v : left_id 0%VS addV. +Proof. by move=> U; apply/addv_idPr/sub0v. Qed. + +Lemma addv0 : right_id 0%VS addV. +Proof. by move=> U; apply/addv_idPl/sub0v. Qed. + +Lemma sumfv : left_zero fullv addV. +Proof. by move=> U; apply/addv_idPl/subvf. Qed. + +Lemma addvf : right_zero fullv addV. +Proof. by move=> U; apply/addv_idPr/subvf. Qed. + +Canonical addv_monoid := Monoid.Law addvA add0v addv0. +Canonical addv_comoid := Monoid.ComLaw addvC. + +Lemma memv_add u v U V : u \in U -> v \in V -> u + v \in (U + V)%VS. +Proof. by rewrite !memvK genmxE linearD; apply: addmx_sub_adds. Qed. + +Lemma memv_addP {w U V} : + reflect (exists2 u, u \in U & exists2 v, v \in V & w = u + v) + (w \in U + V)%VS. +Proof. +apply: (iffP idP) => [|[u Uu [v Vv ->]]]; last exact: memv_add. +rewrite memvK genmxE => /sub_addsmxP[r /(canRL v2rK)->]. +rewrite linearD /=; set u := r2v _; set v := r2v _. +by exists u; last exists v; rewrite // mem_r2v submxMl. +Qed. + +Section BigSum. +Variable I : finType. +Implicit Type P : pred I. + +Lemma sumv_sup i0 P U Vs : + P i0 -> (U <= Vs i0)%VS -> (U <= \sum_(i | P i) Vs i)%VS. +Proof. by move=> Pi0 /subv_trans-> //; rewrite (bigD1 i0) ?addvSl. Qed. +Implicit Arguments sumv_sup [P U Vs]. + +Lemma subv_sumP {P Us V} : + reflect (forall i, P i -> Us i <= V)%VS (\sum_(i | P i) Us i <= V)%VS. +Proof. +apply: (iffP idP) => [sUV i Pi | sUV]. + by apply: subv_trans sUV; apply: sumv_sup Pi _. +by elim/big_rec: _ => [|i W Pi sWV]; rewrite ?sub0v // subv_add sUV. +Qed. + +Lemma memv_sumr P vs (Us : I -> {vspace vT}) : + (forall i, P i -> vs i \in Us i) -> + \sum_(i | P i) vs i \in (\sum_(i | P i) Us i)%VS. +Proof. by move=> Uv; apply/rpred_sum=> i Pi; apply/(sumv_sup i Pi)/Uv. Qed. + +Lemma memv_sumP {P} {Us : I -> {vspace vT}} {v} : + reflect (exists2 vs, forall i, P i -> vs i \in Us i + & v = \sum_(i | P i) vs i) + (v \in \sum_(i | P i) Us i)%VS. +Proof. +apply: (iffP idP) => [|[vs Uv ->]]; last exact: memv_sumr. +rewrite memvK vs2mx_sum => /sub_sumsmxP[r /(canRL v2rK)->]. +pose f i := r2v (r i *m vs2mx (Us i)); rewrite linear_sum /=. +by exists f => //= i _; rewrite mem_r2v submxMl. +Qed. + +End BigSum. + +(* Intersection *) + +Lemma subv_cap U V W : (U <= V :&: W)%VS = (U <= V)%VS && (U <= W)%VS. +Proof. by rewrite /subV vs2mxI sub_capmx. Qed. + +Lemma capvS U1 U2 V1 V2 : (U1 <= U2 -> V1 <= V2 -> U1 :&: V1 <= U2 :&: V2)%VS. +Proof. by rewrite /subV !vs2mxI; apply: capmxS. Qed. + +Lemma capvSl U V : (U :&: V <= U)%VS. +Proof. by rewrite /subV vs2mxI capmxSl. Qed. + +Lemma capvSr U V : (U :&: V <= V)%VS. +Proof. by rewrite /subV vs2mxI capmxSr. Qed. + +Lemma capvC : commutative capV. +Proof. by move=> U V; apply/vs2mxP; rewrite !vs2mxI capmxC submx_refl. Qed. + +Lemma capvA : associative capV. +Proof. by move=> U V W; apply/vs2mxP; rewrite !vs2mxI capmxA submx_refl. Qed. + +Lemma capv_idPl {U V} : reflect (U :&: V = U)%VS (U <= V)%VS. +Proof. by rewrite /subV(sameP capmx_idPl eqmxP) -vs2mxI; apply: vs2mxP. Qed. + +Lemma capv_idPr {U V} : reflect (U :&: V = V)%VS (V <= U)%VS. +Proof. by rewrite capvC; apply: capv_idPl. Qed. + +Lemma capvv : idempotent capV. +Proof. by move=> U; apply/capv_idPl. Qed. + +Lemma cap0v : left_zero 0%VS capV. +Proof. by move=> U; apply/capv_idPl/sub0v. Qed. + +Lemma capv0 : right_zero 0%VS capV. +Proof. by move=> U; apply/capv_idPr/sub0v. Qed. + +Lemma capfv : left_id fullv capV. +Proof. by move=> U; apply/capv_idPr/subvf. Qed. + +Lemma capvf : right_id fullv capV. +Proof. by move=> U; apply/capv_idPl/subvf. Qed. + +Canonical capv_monoid := Monoid.Law capvA capfv capvf. +Canonical capv_comoid := Monoid.ComLaw capvC. + +Lemma memv_cap w U V : (w \in U :&: V)%VS = (w \in U) && (w \in V). +Proof. by rewrite !memvE subv_cap. Qed. + +Lemma memv_capP {w U V} : reflect (w \in U /\ w \in V) (w \in U :&: V)%VS. +Proof. by rewrite memv_cap; apply: andP. Qed. + +Lemma vspace_modl U V W : (U <= W -> U + (V :&: W) = (U + V) :&: W)%VS. +Proof. +by move=> sUV; apply/vs2mxP; rewrite !(vs2mxD, vs2mxI); exact/eqmxP/matrix_modl. +Qed. + +Lemma vspace_modr U V W : (W <= U -> (U :&: V) + W = U :&: (V + W))%VS. +Proof. by rewrite -!(addvC W) !(capvC U); apply: vspace_modl. Qed. + +Section BigCap. +Variable I : finType. +Implicit Type P : pred I. + +Lemma bigcapv_inf i0 P Us V : + P i0 -> (Us i0 <= V -> \bigcap_(i | P i) Us i <= V)%VS. +Proof. by move=> Pi0; apply: subv_trans; rewrite (bigD1 i0) ?capvSl. Qed. + +Lemma subv_bigcapP {P U Vs} : + reflect (forall i, P i -> U <= Vs i)%VS (U <= \bigcap_(i | P i) Vs i)%VS. +Proof. +apply: (iffP idP) => [sUV i Pi | sUV]. + by rewrite (subv_trans sUV) ?(bigcapv_inf Pi). +by elim/big_rec: _ => [|i W Pi]; rewrite ?subvf // subv_cap sUV. +Qed. + +End BigCap. + +(* Complement *) +Lemma addv_complf U : (U + U^C)%VS = fullv. +Proof. +apply/vs2mxP; rewrite vs2mxD -gen_vs2mx -genmx_adds !genmxE submx1 sub1mx. +exact: addsmx_compl_full. +Qed. + +Lemma capv_compl U : (U :&: U^C = 0)%VS. +Proof. +apply/val_inj; rewrite [val]/= vs2mx0 vs2mxI -gen_vs2mx -genmx_cap. +by rewrite capmx_compl genmx0. +Qed. + +(* Difference *) +Lemma diffvSl U V : (U :\: V <= U)%VS. +Proof. by rewrite /subV genmxE diffmxSl. Qed. + +Lemma capv_diff U V : ((U :\: V) :&: V = 0)%VS. +Proof. +apply/val_inj; rewrite [val]/= vs2mx0 vs2mxI -(gen_vs2mx V) -genmx_cap. +by rewrite capmx_diff genmx0. +Qed. + +Lemma addv_diff_cap U V : (U :\: V + U :&: V)%VS = U. +Proof. +apply/vs2mxP; rewrite vs2mxD -genmx_adds !genmxE. +exact/eqmxP/addsmx_diff_cap_eq. +Qed. + +Lemma addv_diff U V : (U :\: V + V = U + V)%VS. +Proof. by rewrite -{2}(addv_diff_cap U V) -addvA (addv_idPr (capvSr U V)). Qed. + +(* Subspace dimension. *) +Lemma dimv0 : \dim (0%VS : {vspace vT}) = 0%N. +Proof. by rewrite /dimv vs2mx0 mxrank0. Qed. + +Lemma dimv_eq0 U : (\dim U == 0%N) = (U == 0%VS). +Proof. by rewrite /dimv /= mxrank_eq0 {2}/eq_op /= linear0 genmx0. Qed. + +Lemma dimvf : \dim {:vT} = Vector.dim vT. +Proof. by rewrite /dimv vs2mxF mxrank1. Qed. + +Lemma dim_vline v : \dim <[v]> = (v != 0). +Proof. by rewrite /dimv mxrank_gen rank_rV (can2_eq v2rK r2vK) linear0. Qed. + +Lemma dimvS U V : (U <= V)%VS -> \dim U <= \dim V. +Proof. exact: mxrankS. Qed. + +Lemma dimv_leqif_sup U V : (U <= V)%VS -> \dim U <= \dim V ?= iff (V <= U)%VS. +Proof. exact: mxrank_leqif_sup. Qed. + +Lemma dimv_leqif_eq U V : (U <= V)%VS -> \dim U <= \dim V ?= iff (U == V). +Proof. by rewrite eqEsubv; apply: mxrank_leqif_eq. Qed. + +Lemma eqEdim U V : (U == V) = (U <= V)%VS && (\dim V <= \dim U). +Proof. by apply/idP/andP=> [/eqP | [/dimv_leqif_eq/geq_leqif]] ->. Qed. + +Lemma dimv_compl U : \dim U^C = (\dim {:vT} - \dim U)%N. +Proof. by rewrite dimvf /dimv mxrank_gen mxrank_compl. Qed. + +Lemma dimv_cap_compl U V : (\dim (U :&: V) + \dim (U :\: V))%N = \dim U. +Proof. by rewrite /dimv !mxrank_gen mxrank_cap_compl. Qed. + +Lemma dimv_sum_cap U V : (\dim (U + V) + \dim (U :&: V) = \dim U + \dim V)%N. +Proof. by rewrite /dimv !mxrank_gen mxrank_sum_cap. Qed. + +Lemma dimv_disjoint_sum U V : + (U :&: V = 0)%VS -> \dim (U + V) = (\dim U + \dim V)%N. +Proof. by move=> dxUV; rewrite -dimv_sum_cap dxUV dimv0 addn0. Qed. + +Lemma dimv_add_leqif U V : + \dim (U + V) <= \dim U + \dim V ?= iff (U :&: V <= 0)%VS. +Proof. +by rewrite /dimv /subV !mxrank_gen vs2mx0 genmxE; apply: mxrank_adds_leqif. +Qed. + +Lemma diffv_eq0 U V : (U :\: V == 0)%VS = (U <= V)%VS. +Proof. +rewrite -dimv_eq0 -(eqn_add2l (\dim (U :&: V))) addn0 dimv_cap_compl eq_sym. +by rewrite (dimv_leqif_eq (capvSl _ _)) (sameP capv_idPl eqP). +Qed. + +Lemma dimv_leq_sum I r (P : pred I) (Us : I -> {vspace vT}) : + \dim (\sum_(i <- r | P i) Us i) <= \sum_(i <- r | P i) \dim (Us i). +Proof. +elim/big_rec2: _ => [|i d vs _ le_vs_d]; first by rewrite dim_vline eqxx. +by apply: (leq_trans (dimv_add_leqif _ _)); rewrite leq_add2l. +Qed. + +Section SumExpr. + +(* The vector direct sum theory clones the interface types of the matrix *) +(* direct sum theory (see mxalgebra for the technical details), but *) +(* nevetheless reuses much of the matrix theory. *) +Structure addv_expr := Sumv { + addv_val :> wrapped {vspace vT}; + addv_dim : wrapped nat; + _ : mxsum_spec (vs2mx (unwrap addv_val)) (unwrap addv_dim) +}. + +(* Piggyback on mxalgebra theory. *) +Definition vs2mx_sum_expr_subproof (S : addv_expr) : + mxsum_spec (vs2mx (unwrap S)) (unwrap (addv_dim S)). +Proof. by case: S. Qed. +Canonical vs2mx_sum_expr S := ProperMxsumExpr (vs2mx_sum_expr_subproof S). + +Canonical trivial_addv U := @Sumv (Wrap U) (Wrap (\dim U)) (TrivialMxsum _). + +Structure proper_addv_expr := ProperSumvExpr { + proper_addv_val :> {vspace vT}; + proper_addv_dim :> nat; + _ : mxsum_spec (vs2mx proper_addv_val) proper_addv_dim +}. + +Definition proper_addvP (S : proper_addv_expr) := + let: ProperSumvExpr _ _ termS := S return mxsum_spec (vs2mx S) S in termS. + +Canonical proper_addv (S : proper_addv_expr) := + @Sumv (wrap (S : {vspace vT})) (wrap (S : nat)) (proper_addvP S). + +Section Binary. +Variables S1 S2 : addv_expr. +Fact binary_addv_subproof : + mxsum_spec (vs2mx (unwrap S1 + unwrap S2)) + (unwrap (addv_dim S1) + unwrap (addv_dim S2)). +Proof. by rewrite vs2mxD; apply: proper_mxsumP. Qed. +Canonical binary_addv_expr := ProperSumvExpr binary_addv_subproof. +End Binary. + +Section Nary. +Variables (I : Type) (r : seq I) (P : pred I) (S_ : I -> addv_expr). +Fact nary_addv_subproof : + mxsum_spec (vs2mx (\sum_(i <- r | P i) unwrap (S_ i))) + (\sum_(i <- r | P i) unwrap (addv_dim (S_ i))). +Proof. by rewrite vs2mx_sum; apply: proper_mxsumP. Qed. +Canonical nary_addv_expr := ProperSumvExpr nary_addv_subproof. +End Nary. + +Definition directv_def S of phantom {vspace vT} (unwrap (addv_val S)) := + \dim (unwrap S) == unwrap (addv_dim S). + +End SumExpr. + +Local Notation directv A := (directv_def (Phantom {vspace _} A%VS)). + +Lemma directvE (S : addv_expr) : + directv (unwrap S) = (\dim (unwrap S) == unwrap (addv_dim S)). +Proof. by []. Qed. + +Lemma directvP {S : proper_addv_expr} : reflect (\dim S = S :> nat) (directv S). +Proof. exact: eqnP. Qed. + +Lemma directv_trivial U : directv (unwrap (@trivial_addv U)). +Proof. exact: eqxx. Qed. + +Lemma dimv_sum_leqif (S : addv_expr) : + \dim (unwrap S) <= unwrap (addv_dim S) ?= iff directv (unwrap S). +Proof. +rewrite directvE; case: S => [[U] [d] /= defUd]; split=> //=. +rewrite /dimv; elim: {1}_ {U}_ d / defUd => // m1 m2 A1 A2 r1 r2 _ leA1 _ leA2. +by apply: leq_trans (leq_add leA1 leA2); rewrite mxrank_adds_leqif. +Qed. + +Lemma directvEgeq (S : addv_expr) : + directv (unwrap S) = (\dim (unwrap S) >= unwrap (addv_dim S)). +Proof. by rewrite leq_eqVlt ltnNge eq_sym !dimv_sum_leqif orbF. Qed. + +Section BinaryDirect. + +Lemma directv_addE (S1 S2 : addv_expr) : + directv (unwrap S1 + unwrap S2) + = [&& directv (unwrap S1), directv (unwrap S2) + & unwrap S1 :&: unwrap S2 == 0]%VS. +Proof. +by rewrite /directv_def /dimv vs2mxD -mxdirectE mxdirect_addsE -vs2mxI -vs2mx0. +Qed. + +Lemma directv_addP {U V} : reflect (U :&: V = 0)%VS (directv (U + V)). +Proof. by rewrite directv_addE !directv_trivial; apply: eqP. Qed. + +Lemma directv_add_unique {U V} : + reflect (forall u1 u2 v1 v2, u1 \in U -> u2 \in U -> v1 \in V -> v2 \in V -> + (u1 + v1 == u2 + v2) = ((u1, v1) == (u2, v2))) + (directv (U + V)). +Proof. +apply: (iffP directv_addP) => [dxUV u1 u2 v1 v2 Uu1 Uu2 Vv1 Vv2 | dxUV]. + apply/idP/idP=> [| /eqP[-> ->] //]; rewrite -subr_eq0 opprD addrACA addr_eq0. + move/eqP=> eq_uv; rewrite xpair_eqE -subr_eq0 eq_uv oppr_eq0 subr_eq0 andbb. + by rewrite -subr_eq0 -memv0 -dxUV memv_cap -memvN -eq_uv !memvB. +apply/eqP; rewrite -subv0; apply/subvP=> v /memv_capP[U1v U2v]. +by rewrite memv0 -[v == 0]andbb {1}eq_sym -xpair_eqE -dxUV ?mem0v // addrC. +Qed. + +End BinaryDirect. + +Section NaryDirect. + +Context {I : finType} {P : pred I}. + +Lemma directv_sumP {Us : I -> {vspace vT}} : + reflect (forall i, P i -> Us i :&: (\sum_(j | P j && (j != i)) Us j) = 0)%VS + (directv (\sum_(i | P i) Us i)). +Proof. +rewrite directvE /= /dimv vs2mx_sum -mxdirectE; apply: (equivP mxdirect_sumsP). +by do [split=> dxU i /dxU; rewrite -vs2mx_sum -vs2mxI -vs2mx0] => [/val_inj|->]. +Qed. + +Lemma directv_sumE {Ss : I -> addv_expr} (xunwrap := unwrap) : + reflect [/\ forall i, P i -> directv (unwrap (Ss i)) + & directv (\sum_(i | P i) xunwrap (Ss i))] + (directv (\sum_(i | P i) unwrap (Ss i))). +Proof. +by rewrite !directvE /= /dimv 2!{1}vs2mx_sum -!mxdirectE; apply: mxdirect_sumsE. +Qed. + +Lemma directv_sum_independent {Us : I -> {vspace vT}} : + reflect (forall us, + (forall i, P i -> us i \in Us i) -> \sum_(i | P i) us i = 0 -> + (forall i, P i -> us i = 0)) + (directv (\sum_(i | P i) Us i)). +Proof. +apply: (iffP directv_sumP) => [dxU us Uu u_0 i Pi | dxU i Pi]. + apply/eqP; rewrite -memv0 -(dxU i Pi) memv_cap Uu //= -memvN -sub0r -{1}u_0. + by rewrite (bigD1 i) //= addrC addKr memv_sumr // => j /andP[/Uu]. +apply/eqP; rewrite -subv0; apply/subvP=> v. +rewrite memv_cap memv0 => /andP[Uiv /memv_sumP[us Uu Dv]]. +have: \sum_(j | P j) [eta us with i |-> - v] j = 0. + rewrite (bigD1 i) //= eqxx {1}Dv addrC -sumrB big1 // => j /andP[_ i'j]. + by rewrite (negPf i'j) subrr. +move/dxU/(_ i Pi); rewrite /= eqxx -oppr_eq0 => -> // j Pj. +by have [-> | i'j] := altP eqP; rewrite ?memvN // Uu ?Pj. +Qed. + +Lemma directv_sum_unique {Us : I -> {vspace vT}} : + reflect (forall us vs, + (forall i, P i -> us i \in Us i) -> + (forall i, P i -> vs i \in Us i) -> + (\sum_(i | P i) us i == \sum_(i | P i) vs i) + = [forall (i | P i), us i == vs i]) + (directv (\sum_(i | P i) Us i)). +Proof. +apply: (iffP directv_sum_independent) => [dxU us vs Uu Uv | dxU us Uu u_0 i Pi]. + apply/idP/forall_inP=> [|eq_uv]; last by apply/eqP/eq_bigr => i /eq_uv/eqP. + rewrite -subr_eq0 -sumrB => /eqP/dxU eq_uv i Pi. + by rewrite -subr_eq0 eq_uv // => j Pj; apply: memvB; move: j Pj. +apply/eqP; have:= esym (dxU us \0 Uu _); rewrite u_0 big1_eq eqxx. +by move/(_ _)/forall_inP=> -> // j _; apply: mem0v. +Qed. + +End NaryDirect. + +(* Linear span generated by a list of vectors *) +Lemma memv_span X v : v \in X -> v \in <<X>>%VS. +Proof. +by case/seq_tnthP=> i {v}->; rewrite unlock memvK genmxE (eq_row_sub i) // rowK. +Qed. + +Lemma memv_span1 v : v \in <<[:: v]>>%VS. +Proof. by rewrite memv_span ?mem_head. Qed. + +Lemma dim_span X : \dim <<X>> <= size X. +Proof. by rewrite unlock /dimv genmxE rank_leq_row. Qed. + +Lemma span_subvP {X U} : reflect {subset X <= U} (<<X>> <= U)%VS. +Proof. +rewrite /subV [@span _ _]unlock genmxE. +apply: (iffP row_subP) => /= [sXU | sXU i]. + by move=> _ /seq_tnthP[i ->]; have:= sXU i; rewrite rowK memvK. +by rewrite rowK -memvK sXU ?mem_tnth. +Qed. + +Lemma sub_span X Y : {subset X <= Y} -> (<<X>> <= <<Y>>)%VS. +Proof. by move=> sXY; apply/span_subvP=> v /sXY/memv_span. Qed. + +Lemma eq_span X Y : X =i Y -> (<<X>> = <<Y>>)%VS. +Proof. +by move=> eqXY; apply: subv_anti; rewrite !sub_span // => u; rewrite eqXY. +Qed. + +Lemma span_def X : span X = (\sum_(u <- X) <[u]>)%VS. +Proof. +apply/subv_anti/andP; split. + by apply/span_subvP=> v Xv; rewrite (big_rem v) // memvE addvSl. +by rewrite big_tnth; apply/subv_sumP=> i _; rewrite -memvE memv_span ?mem_tnth. +Qed. + +Lemma span_nil : (<<Nil vT>> = 0)%VS. +Proof. by rewrite span_def big_nil. Qed. + +Lemma span_seq1 v : (<<[:: v]>> = <[v]>)%VS. +Proof. by rewrite span_def big_seq1. Qed. + +Lemma span_cons v X : (<<v :: X>> = <[v]> + <<X>>)%VS. +Proof. by rewrite !span_def big_cons. Qed. + +Lemma span_cat X Y : (<<X ++ Y>> = <<X>> + <<Y>>)%VS. +Proof. by rewrite !span_def big_cat. Qed. + +(* Coordinates function; should perhaps be generalized to nat indices. *) + +Definition coord_expanded_def n (X : n.-tuple vT) i v := + (v2r v *m pinvmx (b2mx X)) 0 i. +Definition coord := locked_with span_key coord_expanded_def. +Canonical coord_unlockable := [unlockable fun coord]. + +Fact coord_is_scalar n (X : n.-tuple vT) i : scalar (coord X i). +Proof. by move=> k u v; rewrite unlock linearP mulmxDl -scalemxAl !mxE. Qed. +Canonical coord_addidive n Xn i := Additive (@coord_is_scalar n Xn i). +Canonical coord_linear n Xn i := AddLinear (@coord_is_scalar n Xn i). + +Lemma coord_span n (X : n.-tuple vT) v : + v \in span X -> v = \sum_i coord X i v *: X`_i. +Proof. +rewrite memvK span_b2mx genmxE => Xv. +by rewrite unlock_with mul_b2mx mulmxKpV ?v2rK. +Qed. + +Lemma coord0 i v : coord [tuple 0] i v = 0. +Proof. +rewrite unlock /pinvmx rank_rV; case: negP => [[] | _]. + by apply/eqP/rowP=> j; rewrite !mxE (tnth_nth 0) /= linear0 mxE. +by rewrite pid_mx_0 !(mulmx0, mul0mx) mxE. +Qed. + +(* Free generator sequences. *) + +Lemma nil_free : free (Nil vT). +Proof. by rewrite /free span_nil dimv0. Qed. + +Lemma seq1_free v : free [:: v] = (v != 0). +Proof. by rewrite /free span_seq1 dim_vline; case: (~~ _). Qed. + +Lemma perm_free X Y : perm_eq X Y -> free X = free Y. +Proof. +by move=> eqX; rewrite /free (perm_eq_size eqX) (eq_span (perm_eq_mem eqX)). +Qed. + +Lemma free_directv X : free X = (0 \notin X) && directv (\sum_(v <- X) <[v]>). +Proof. +have leXi i (v := tnth (in_tuple X) i): true -> \dim <[v]> <= 1 ?= iff (v != 0). + by rewrite -seq1_free -span_seq1 => _; apply/leqif_eq/dim_span. +have [_ /=] := leqif_trans (dimv_sum_leqif _) (leqif_sum leXi). +rewrite sum1_card card_ord !directvE /= /free andbC span_def !(big_tnth _ _ X). +by congr (_ = _ && _); rewrite -has_pred1 -all_predC -big_all big_tnth big_andE. +Qed. + +Lemma free_not0 v X : free X -> v \in X -> v != 0. +Proof. by rewrite free_directv andbC => /andP[_ /memPn]; apply. Qed. + +Lemma freeP n (X : n.-tuple vT) : + reflect (forall k, \sum_(i < n) k i *: X`_i = 0 -> (forall i, k i = 0)) + (free X). +Proof. +rewrite free_b2mx; apply: (iffP idP) => [t_free k kt0 i | t_free]. + suffices /rowP/(_ i): \row_i k i = 0 by rewrite !mxE. + by apply/(row_free_inj t_free)/r2v_inj; rewrite mul0mx -lin_b2mx kt0 linear0. +rewrite -kermx_eq0; apply/rowV0P=> rk /sub_kermxP kt0. +by apply/rowP=> i; rewrite mxE {}t_free // mul_b2mx kt0 linear0. +Qed. + +Lemma coord_free n (X : n.-tuple vT) (i j : 'I_n) : + free X -> coord X j (X`_i) = (i == j)%:R. +Proof. +rewrite unlock free_b2mx => /row_freeP[Ct CtK]; rewrite -row_b2mx. +by rewrite -row_mul -[pinvmx _]mulmx1 -CtK 2!mulmxA mulmxKpV // CtK !mxE. +Qed. + +Lemma coord_sum_free n (X : n.-tuple vT) k j : + free X -> coord X j (\sum_(i < n) k i *: X`_i) = k j. +Proof. +move=> Xfree; rewrite linear_sum (bigD1 j) ?linearZ //= coord_free // eqxx. +rewrite mulr1 big1 ?addr0 // => i /negPf j'i. +by rewrite linearZ /= coord_free // j'i mulr0. +Qed. + +Lemma cat_free X Y : + free (X ++ Y) = [&& free X, free Y & directv (<<X>> + <<Y>>)]. +Proof. +rewrite !free_directv mem_cat directvE /= !big_cat -directvE directv_addE /=. +rewrite negb_or -!andbA; do !bool_congr; rewrite -!span_def. +by rewrite (sameP eqP directv_addP). +Qed. + +Lemma catl_free Y X : free (X ++ Y) -> free X. +Proof. by rewrite cat_free => /and3P[]. Qed. + +Lemma catr_free X Y : free (X ++ Y) -> free Y. +Proof. by rewrite cat_free => /and3P[]. Qed. + +Lemma filter_free p X : free X -> free (filter p X). +Proof. +rewrite -(perm_free (etrans (perm_filterC p X _) (perm_eq_refl X))). +exact: catl_free. +Qed. + +Lemma free_cons v X : free (v :: X) = (v \notin <<X>>)%VS && free X. +Proof. +rewrite (cat_free [:: v]) seq1_free directvEgeq /= span_seq1 dim_vline. +case: eqP => [-> | _] /=; first by rewrite mem0v. +rewrite andbC ltnNge (geq_leqif (dimv_leqif_sup _)) ?addvSr //. +by rewrite subv_add subvv andbT -memvE. +Qed. + +Lemma freeE n (X : n.-tuple vT) : + free X = [forall i : 'I_n, X`_i \notin <<drop i.+1 X>>%VS]. +Proof. +case: X => X /= /eqP <-{n}; rewrite -(big_andE xpredT) /=. +elim: X => [|v X IH_X] /=; first by rewrite nil_free big_ord0. +by rewrite free_cons IH_X big_ord_recl drop0. +Qed. + +Lemma freeNE n (X : n.-tuple vT) : + ~~ free X = [exists i : 'I_n, X`_i \in <<drop i.+1 X>>%VS]. +Proof. by rewrite freeE -negb_exists negbK. Qed. + +Lemma free_uniq X : free X -> uniq X. +Proof. +elim: X => //= v b IH_X; rewrite free_cons => /andP[X'v /IH_X->]. +by rewrite (contra _ X'v) // => /memv_span. +Qed. + +Lemma free_span X v (sumX := fun k => \sum_(x <- X) k x *: x) : + free X -> v \in <<X>>%VS -> + {k | v = sumX k & forall k1, v = sumX k1 -> {in X, k1 =1 k}}. +Proof. +rewrite -{2}[X]in_tupleE => freeX /coord_span def_v. +pose k x := oapp (fun i => coord (in_tuple X) i v) 0 (insub (index x X)). +exists k => [|k1 {def_v}def_v _ /(nthP 0)[i ltiX <-]]. + rewrite /sumX (big_nth 0) big_mkord def_v; apply: eq_bigr => i _. + by rewrite /k index_uniq ?free_uniq // valK. +rewrite /k /= index_uniq ?free_uniq // insubT //= def_v. +by rewrite /sumX (big_nth 0) big_mkord coord_sum_free. +Qed. + +Lemma linear_of_free (rT : lmodType K) X (fX : seq rT) : + {f : {linear vT -> rT} | free X -> size fX = size X -> map f X = fX}. +Proof. +pose f u := \sum_i coord (in_tuple X) i u *: fX`_i. +have lin_f: linear f. + move=> k u v; rewrite scaler_sumr -big_split; apply: eq_bigr => i _. + by rewrite /= scalerA -scalerDl linearP. +exists (Linear lin_f) => freeX eq_szX. +apply/esym/(@eq_from_nth _ 0); rewrite ?size_map eq_szX // => i ltiX. +rewrite (nth_map 0) //= /f (bigD1 (Ordinal ltiX)) //=. +rewrite big1 => [|j /negbTE neqji]; rewrite (coord_free (Ordinal _)) //. + by rewrite eqxx scale1r addr0. +by rewrite eq_sym neqji scale0r. +Qed. + +(* Subspace bases *) + +Lemma span_basis U X : basis_of U X -> <<X>>%VS = U. +Proof. by case/andP=> /eqP. Qed. + +Lemma basis_free U X : basis_of U X -> free X. +Proof. by case/andP. Qed. + +Lemma coord_basis U n (X : n.-tuple vT) v : + basis_of U X -> v \in U -> v = \sum_i coord X i v *: X`_i. +Proof. by move/span_basis <-; apply: coord_span. Qed. + +Lemma nil_basis : basis_of 0 (Nil vT). +Proof. by rewrite /basis_of span_nil eqxx nil_free. Qed. + +Lemma seq1_basis v : v != 0 -> basis_of <[v]> [:: v]. +Proof. by move=> nz_v; rewrite /basis_of span_seq1 // eqxx seq1_free. Qed. + +Lemma basis_not0 x U X : basis_of U X -> x \in X -> x != 0. +Proof. by move/basis_free/free_not0; apply. Qed. + +Lemma basis_mem x U X : basis_of U X -> x \in X -> x \in U. +Proof. by move/span_basis=> <- /memv_span. Qed. + +Lemma cat_basis U V X Y : + directv (U + V) -> basis_of U X -> basis_of V Y -> basis_of (U + V) (X ++ Y). +Proof. +move=> dxUV /andP[/eqP defU freeX] /andP[/eqP defV freeY]. +by rewrite /basis_of span_cat cat_free defU defV // eqxx freeX freeY. +Qed. + +Lemma size_basis U n (X : n.-tuple vT) : basis_of U X -> \dim U = n. +Proof. by case/andP=> /eqP <- /eqnP->; apply: size_tuple. Qed. + +Lemma basisEdim X U : basis_of U X = (U <= <<X>>)%VS && (size X <= \dim U). +Proof. +apply/andP/idP=> [[defU /eqnP <-]| ]; first by rewrite -eqEdim eq_sym. +case/andP=> sUX leXU; have leXX := dim_span X. +rewrite /free eq_sym eqEdim sUX eqn_leq !(leq_trans leXX) //. +by rewrite (leq_trans leXU) ?dimvS. +Qed. + +Lemma basisEfree X U : + basis_of U X = [&& free X, (<<X>> <= U)%VS & \dim U <= size X]. +Proof. +by rewrite andbC; apply: andb_id2r => freeX; rewrite eqEdim (eqnP freeX). +Qed. + +Lemma perm_basis X Y U : perm_eq X Y -> basis_of U X = basis_of U Y. +Proof. +move=> eqXY; congr ((_ == _) && _); last exact: perm_free. +by apply/eq_span; apply: perm_eq_mem. +Qed. + +Lemma vbasisP U : basis_of U (vbasis U). +Proof. +rewrite /basis_of free_b2mx span_b2mx (sameP eqP (vs2mxP _ _)) !genmxE. +have ->: b2mx (vbasis U) = row_base (vs2mx U). + by apply/row_matrixP=> i; rewrite unlock rowK tnth_mktuple r2vK. +by rewrite row_base_free !eq_row_base submx_refl. +Qed. + +Lemma vbasis_mem v U : v \in (vbasis U) -> v \in U. +Proof. exact: (basis_mem (vbasisP _)). Qed. + +Lemma coord_vbasis v U : + v \in U -> v = \sum_(i < \dim U) coord (vbasis U) i v *: (vbasis U)`_i. +Proof. exact: coord_basis (vbasisP U). Qed. + +Section BigSumBasis. + +Variables (I : finType) (P : pred I) (Xs : I -> seq vT). + +Lemma span_bigcat : + (<<\big[cat/[::]]_(i | P i) Xs i>> = \sum_(i | P i) <<Xs i>>)%VS. +Proof. by rewrite (big_morph _ span_cat span_nil). Qed. + +Lemma bigcat_free : + directv (\sum_(i | P i) <<Xs i>>) -> + (forall i, P i -> free (Xs i)) -> free (\big[cat/[::]]_(i | P i) Xs i). +Proof. +rewrite /free directvE /= span_bigcat => /directvP-> /= freeXs. +rewrite (big_morph _ (@size_cat _) (erefl _)) /=. +by apply/eqP/eq_bigr=> i /freeXs/eqP. +Qed. + +Lemma bigcat_basis Us (U := (\sum_(i | P i) Us i)%VS) : + directv U -> (forall i, P i -> basis_of (Us i) (Xs i)) -> + basis_of U (\big[cat/[::]]_(i | P i) Xs i). +Proof. +move=> dxU XsUs; rewrite /basis_of span_bigcat. +have defUs i: P i -> span (Xs i) = Us i by case/XsUs/andP=> /eqP. +rewrite (eq_bigr _ defUs) eqxx bigcat_free // => [|_ /XsUs/andP[]//]. +apply/directvP; rewrite /= (eq_bigr _ defUs) (directvP dxU) /=. +by apply/eq_bigr=> i /defUs->. +Qed. + +End BigSumBasis. + +End VectorTheory. + +Hint Resolve subvv. +Implicit Arguments subvP [K vT U V]. +Implicit Arguments addv_idPl [K vT U V]. +Implicit Arguments addv_idPr [K vT U V]. +Implicit Arguments memv_addP [K vT U V w]. +Implicit Arguments sumv_sup [K vT I P U Vs]. +Implicit Arguments memv_sumP [K vT I P Us v]. +Implicit Arguments subv_sumP [K vT I P Us V]. +Implicit Arguments capv_idPl [K vT U V]. +Implicit Arguments capv_idPr [K vT U V]. +Implicit Arguments memv_capP [K vT U V w]. +Implicit Arguments bigcapv_inf [K vT I P Us V]. +Implicit Arguments subv_bigcapP [K vT I P U Vs]. +Implicit Arguments directvP [K vT S]. +Implicit Arguments directv_addP [K vT U V]. +Implicit Arguments directv_add_unique [K vT U V]. +Implicit Arguments directv_sumP [K vT I P Us]. +Implicit Arguments directv_sumE [K vT I P Ss]. +Implicit Arguments directv_sum_independent [K vT I P Us]. +Implicit Arguments directv_sum_unique [K vT I P Us]. +Implicit Arguments span_subvP [K vT X U]. +Implicit Arguments freeP [K vT n X]. + +Prenex Implicits coord. +Notation directv S := (directv_def (Phantom _ S%VS)). + +(* Linear functions over a vectType *) +Section LfunDefs. + +Variable R : ringType. +Implicit Types aT vT rT : vectType R. + +Fact lfun_key : unit. Proof. by []. Qed. +Definition fun_of_lfun_def aT rT (f : 'Hom(aT, rT)) := + r2v \o mulmxr (f2mx f) \o v2r. +Definition fun_of_lfun := locked_with lfun_key fun_of_lfun_def. +Canonical fun_of_lfun_unlockable := [unlockable fun fun_of_lfun]. +Definition linfun_def aT rT (f : aT -> rT) := + Vector.Hom (lin1_mx (v2r \o f \o r2v)). +Definition linfun := locked_with lfun_key linfun_def. +Canonical linfun_unlockable := [unlockable fun linfun]. + +Definition id_lfun vT := @linfun vT vT idfun. +Definition comp_lfun aT vT rT (f : 'Hom(vT, rT)) (g : 'Hom(aT, vT)) := + linfun (fun_of_lfun f \o fun_of_lfun g). + +End LfunDefs. + +Coercion fun_of_lfun : Vector.hom >-> Funclass. +Notation "\1" := (@id_lfun _ _) : lfun_scope. +Notation "f \o g" := (comp_lfun f g) : lfun_scope. + +Section LfunVspaceDefs. + +Variable K : fieldType. +Implicit Types aT rT : vectType K. + +Definition inv_lfun aT rT (f : 'Hom(aT, rT)) := Vector.Hom (pinvmx (f2mx f)). +Definition lker aT rT (f : 'Hom(aT, rT)) := mx2vs (kermx (f2mx f)). +Fact lfun_img_key : unit. Proof. by []. Qed. +Definition lfun_img_def aT rT f (U : {vspace aT}) : {vspace rT} := + mx2vs (vs2mx U *m f2mx f). +Definition lfun_img := locked_with lfun_img_key lfun_img_def. +Canonical lfun_img_unlockable := [unlockable fun lfun_img]. +Definition lfun_preim aT rT (f : 'Hom(aT, rT)) W := + (lfun_img (inv_lfun f) (W :&: lfun_img f fullv) + lker f)%VS. + +End LfunVspaceDefs. + +Prenex Implicits linfun lfun_img lker lfun_preim. +Notation "f ^-1" := (inv_lfun f) : lfun_scope. +Notation "f @: U" := (lfun_img f%VF%R U) (at level 24) : vspace_scope. +Notation "f @^-1: W" := (lfun_preim f%VF%R W) (at level 24) : vspace_scope. +Notation limg f := (lfun_img f fullv). + +Section LfunZmodType. + +Variables (R : ringType) (aT rT : vectType R). +Implicit Types f g h : 'Hom(aT, rT). + +Canonical lfun_eqMixin := Eval hnf in [eqMixin of 'Hom(aT, rT) by <:]. +Canonical lfun_eqType := EqType 'Hom(aT, rT) lfun_eqMixin. +Definition lfun_choiceMixin := [choiceMixin of 'Hom(aT, rT) by <:]. +Canonical lfun_choiceType := ChoiceType 'Hom(aT, rT) lfun_choiceMixin. + +Fact lfun_is_linear f : linear f. +Proof. by rewrite unlock; apply: linearP. Qed. +Canonical lfun_additive f := Additive (lfun_is_linear f). +Canonical lfun_linear f := AddLinear (lfun_is_linear f). + +Lemma lfunE (ff : {linear aT -> rT}) : linfun ff =1 ff. +Proof. by move=> v; rewrite 2!unlock /= mul_rV_lin1 /= !v2rK. Qed. + +Lemma fun_of_lfunK : cancel (@fun_of_lfun R aT rT) linfun. +Proof. +move=> f; apply/val_inj/row_matrixP=> i. +by rewrite 2!unlock /= !rowE mul_rV_lin1 /= !r2vK. +Qed. + +Lemma lfunP f g : f =1 g <-> f = g. +Proof. +split=> [eq_fg | -> //]; rewrite -[f]fun_of_lfunK -[g]fun_of_lfunK unlock. +by apply/val_inj/row_matrixP=> i; rewrite !rowE !mul_rV_lin1 /= eq_fg. +Qed. + +Definition zero_lfun : 'Hom(aT, rT) := linfun \0. +Definition add_lfun f g := linfun (f \+ g). +Definition opp_lfun f := linfun (-%R \o f). + +Fact lfun_addA : associative add_lfun. +Proof. by move=> f g h; apply/lfunP=> v; rewrite !lfunE /= !lfunE addrA. Qed. + +Fact lfun_addC : commutative add_lfun. +Proof. by move=> f g; apply/lfunP=> v; rewrite !lfunE /= addrC. Qed. + +Fact lfun_add0 : left_id zero_lfun add_lfun. +Proof. by move=> f; apply/lfunP=> v; rewrite lfunE /= lfunE add0r. Qed. + +Lemma lfun_addN : left_inverse zero_lfun opp_lfun add_lfun. +Proof. by move=> f; apply/lfunP=> v; rewrite !lfunE /= lfunE addNr. Qed. + +Definition lfun_zmodMixin := ZmodMixin lfun_addA lfun_addC lfun_add0 lfun_addN. +Canonical lfun_zmodType := Eval hnf in ZmodType 'Hom(aT, rT) lfun_zmodMixin. + +Lemma zero_lfunE x : (0 : 'Hom(aT, rT)) x = 0. Proof. exact: lfunE. Qed. +Lemma add_lfunE f g x : (f + g) x = f x + g x. Proof. exact: lfunE. Qed. +Lemma opp_lfunE f x : (- f) x = - f x. Proof. exact: lfunE. Qed. +Lemma sum_lfunE I (r : seq I) (P : pred I) (fs : I -> 'Hom(aT, rT)) x : + (\sum_(i <- r | P i) fs i) x = \sum_(i <- r | P i) fs i x. +Proof. by elim/big_rec2: _ => [|i _ f _ <-]; rewrite lfunE. Qed. + +End LfunZmodType. + +Section LfunVectType. + +Variables (R : comRingType) (aT rT : vectType R). +Implicit Types f : 'Hom(aT, rT). + +Definition scale_lfun k f := linfun (k \*: f). +Local Infix "*:l" := scale_lfun (at level 40). + +Fact lfun_scaleA k1 k2 f : k1 *:l (k2 *:l f) = (k1 * k2) *:l f. +Proof. by apply/lfunP=> v; rewrite !lfunE /= lfunE scalerA. Qed. + +Fact lfun_scale1 f : 1 *:l f = f. +Proof. by apply/lfunP=> v; rewrite lfunE /= scale1r. Qed. + +Fact lfun_scaleDr k f1 f2 : k *:l (f1 + f2) = k *:l f1 + k *:l f2. +Proof. by apply/lfunP=> v; rewrite !lfunE /= !lfunE scalerDr. Qed. + +Fact lfun_scaleDl f k1 k2 : (k1 + k2) *:l f = k1 *:l f + k2 *:l f. +Proof. by apply/lfunP=> v; rewrite !lfunE /= !lfunE scalerDl. Qed. + +Definition lfun_lmodMixin := + LmodMixin lfun_scaleA lfun_scale1 lfun_scaleDr lfun_scaleDl. +Canonical lfun_lmodType := Eval hnf in LmodType R 'Hom(aT, rT) lfun_lmodMixin. + +Lemma scale_lfunE k f x : (k *: f) x = k *: f x. Proof. exact: lfunE. Qed. + +(* GG: exists (Vector.Hom \o vec_mx) fails in the proof below in 8.3, *) +(* probably because of incomplete type unification. Will it work in 8.4? *) +Fact lfun_vect_iso : Vector.axiom (Vector.dim aT * Vector.dim rT) 'Hom(aT, rT). +Proof. +exists (mxvec \o f2mx) => [a f g|]. + rewrite /= -linearP /= -[A in _ = mxvec A]/(f2mx (Vector.Hom _)). + congr (mxvec (f2mx _)); apply/lfunP=> v; do 2!rewrite lfunE /=. + by rewrite unlock /= -linearP mulmxDr scalemxAr. +apply: Bijective (Vector.Hom \o vec_mx) _ _ => [[A]|A] /=; last exact: vec_mxK. +by rewrite mxvecK. +Qed. + +Definition lfun_vectMixin := VectMixin lfun_vect_iso. +Canonical lfun_vectType := VectType R 'Hom(aT, rT) lfun_vectMixin. + +End LfunVectType. + +Section CompLfun. + +Variables (R : ringType) (wT aT vT rT : vectType R). +Implicit Types (f : 'Hom(vT, rT)) (g : 'Hom(aT, vT)) (h : 'Hom(wT, aT)). + +Lemma id_lfunE u: \1%VF u = u :> aT. Proof. exact: lfunE. Qed. +Lemma comp_lfunE f g u : (f \o g)%VF u = f (g u). Proof. exact: lfunE. Qed. + +Lemma comp_lfunA f g h : (f \o (g \o h) = (f \o g) \o h)%VF. +Proof. by apply/lfunP=> u; do !rewrite lfunE /=. Qed. + +Lemma comp_lfun1l f : (\1 \o f)%VF = f. +Proof. by apply/lfunP=> u; do !rewrite lfunE /=. Qed. + +Lemma comp_lfun1r f : (f \o \1)%VF = f. +Proof. by apply/lfunP=> u; do !rewrite lfunE /=. Qed. + +Lemma comp_lfun0l g : (0 \o g)%VF = 0 :> 'Hom(aT, rT). +Proof. by apply/lfunP=> u; do !rewrite lfunE /=. Qed. + +Lemma comp_lfun0r f : (f \o 0)%VF = 0 :> 'Hom(aT, rT). +Proof. by apply/lfunP=> u; do !rewrite lfunE /=; rewrite linear0. Qed. + +Lemma comp_lfunDl f1 f2 g : ((f1 + f2) \o g = (f1 \o g) + (f2 \o g))%VF. +Proof. by apply/lfunP=> u; do !rewrite lfunE /=. Qed. + +Lemma comp_lfunDr f g1 g2 : (f \o (g1 + g2) = (f \o g1) + (f \o g2))%VF. +Proof. by apply/lfunP=> u; do !rewrite lfunE /=; rewrite linearD. Qed. + +Lemma comp_lfunNl f g : ((- f) \o g = - (f \o g))%VF. +Proof. by apply/lfunP=> u; do !rewrite lfunE /=. Qed. + +Lemma comp_lfunNr f g : (f \o (- g) = - (f \o g))%VF. +Proof. by apply/lfunP=> u; do !rewrite lfunE /=; rewrite linearN. Qed. + +End CompLfun. + +Definition lfun_simp := + (comp_lfunE, scale_lfunE, opp_lfunE, add_lfunE, sum_lfunE, lfunE). + +Section ScaleCompLfun. + +Variables (R : comRingType) (aT vT rT : vectType R). +Implicit Types (f : 'Hom(vT, rT)) (g : 'Hom(aT, vT)). + +Lemma comp_lfunZl k f g : (k *: (f \o g) = (k *: f) \o g)%VF. +Proof. by apply/lfunP=> u; do !rewrite lfunE /=. Qed. + +Lemma comp_lfunZr k f g : (k *: (f \o g) = f \o (k *: g))%VF. +Proof. by apply/lfunP=> u; do !rewrite lfunE /=; rewrite linearZ. Qed. + +End ScaleCompLfun. + +Section LinearImage. + +Variables (K : fieldType) (aT rT : vectType K). +Implicit Types (f g : 'Hom(aT, rT)) (U V : {vspace aT}) (W : {vspace rT}). + +Lemma limgS f U V : (U <= V)%VS -> (f @: U <= f @: V)%VS. +Proof. by rewrite unlock /subsetv !genmxE; apply: submxMr. Qed. + +Lemma limg_line f v : (f @: <[v]> = <[f v]>)%VS. +Proof. +apply/eqP; rewrite 2!unlock eqEsubv /subsetv /= r2vK !genmxE. +by rewrite !(eqmxMr _ (genmxE _)) submx_refl. +Qed. + +Lemma limg0 f : (f @: 0 = 0)%VS. Proof. by rewrite limg_line linear0. Qed. + +Lemma memv_img f v U : v \in U -> f v \in (f @: U)%VS. +Proof. by move=> Uv; rewrite memvE -limg_line limgS. Qed. + +Lemma memv_imgP f w U : + reflect (exists2 u, u \in U & w = f u) (w \in f @: U)%VS. +Proof. +apply: (iffP idP) => [|[u Uu ->]]; last exact: memv_img. +rewrite 2!unlock memvE /subsetv !genmxE => /submxP[ku Drw]. +exists (r2v (ku *m vs2mx U)); last by rewrite /= r2vK -mulmxA -Drw v2rK. +by rewrite memvE /subsetv !genmxE r2vK submxMl. +Qed. + +Lemma lim0g U : (0 @: U = 0 :> {vspace rT})%VS. +Proof. +apply/eqP; rewrite -subv0; apply/subvP=> _ /memv_imgP[u _ ->]. +by rewrite lfunE rpred0. +Qed. + +Lemma eq_in_limg V f g : {in V, f =1 g} -> (f @: V = g @: V)%VS. +Proof. +move=> eq_fg; apply/vspaceP=> y. +by apply/memv_imgP/memv_imgP=> [][x Vx ->]; exists x; rewrite ?eq_fg. +Qed. + +Lemma limg_add f : {morph lfun_img f : U V / U + V}%VS. +Proof. +move=> U V; apply/eqP; rewrite unlock eqEsubv /subsetv /= -genmx_adds. +by rewrite !genmxE !(eqmxMr _ (genmxE _)) !addsmxMr submx_refl. +Qed. + +Lemma limg_sum f I r (P : pred I) Us : + (f @: (\sum_(i <- r | P i) Us i) = \sum_(i <- r | P i) f @: Us i)%VS. +Proof. exact: (big_morph _ (limg_add f) (limg0 f)). Qed. + +Lemma limg_cap f U V : (f @: (U :&: V) <= f @: U :&: f @: V)%VS. +Proof. by rewrite subv_cap !limgS ?capvSl ?capvSr. Qed. + +Lemma limg_bigcap f I r (P : pred I) Us : + (f @: (\bigcap_(i <- r | P i) Us i) <= \bigcap_(i <- r | P i) f @: Us i)%VS. +Proof. +elim/big_rec2: _ => [|i V U _ sUV]; first exact: subvf. +by rewrite (subv_trans (limg_cap f _ U)) ?capvS. +Qed. + +Lemma limg_span f X : (f @: <<X>> = <<map f X>>)%VS. +Proof. +by rewrite !span_def big_map limg_sum; apply: eq_bigr => x _; rewrite limg_line. +Qed. + +Lemma lfunPn f g : reflect (exists u, f u != g u) (f != g). +Proof. +apply: (iffP idP) => [f'g|[x]]; last by apply: contraNneq => /lfunP->. +suffices /subvPn[_ /memv_imgP[u _ ->]]: ~~ (limg (f - g) <= 0)%VS. + by rewrite lfunE /= lfunE /= memv0 subr_eq0; exists u. +apply: contra f'g => /subvP fg0; apply/eqP/lfunP=> u; apply/eqP. +by rewrite -subr_eq0 -opp_lfunE -add_lfunE -memv0 fg0 ?memv_img ?memvf. +Qed. + +Lemma inv_lfun_def f : (f \o f^-1 \o f)%VF = f. +Proof. +apply/lfunP=> u; do !rewrite lfunE /=; rewrite unlock /= !r2vK. +by rewrite mulmxKpV ?submxMl. +Qed. + +Lemma limg_lfunVK f : {in limg f, cancel f^-1%VF f}. +Proof. by move=> _ /memv_imgP[u _ ->]; rewrite -!comp_lfunE inv_lfun_def. Qed. + +Lemma lkerE f U : (U <= lker f)%VS = (f @: U == 0)%VS. +Proof. +rewrite unlock -dimv_eq0 /dimv /subsetv !genmxE mxrank_eq0. +by rewrite (sameP sub_kermxP eqP). +Qed. + +Lemma memv_ker f v : (v \in lker f) = (f v == 0). +Proof. by rewrite -memv0 !memvE subv0 lkerE limg_line. Qed. + +Lemma eqlfunP f g v : reflect (f v = g v) (v \in lker (f - g)). +Proof. by rewrite memv_ker !lfun_simp subr_eq0; apply: eqP. Qed. + +Lemma eqlfun_inP V f g : reflect {in V, f =1 g} (V <= lker (f - g))%VS. +Proof. by apply: (iffP subvP) => E x /E/eqlfunP. Qed. + +Lemma limg_ker_compl f U : (f @: (U :\: lker f) = f @: U)%VS. +Proof. +rewrite -{2}(addv_diff_cap U (lker f)) limg_add; apply/esym/addv_idPl. +by rewrite (subv_trans _ (sub0v _)) // subv0 -lkerE capvSr. +Qed. + +Lemma limg_ker_dim f U : (\dim (U :&: lker f) + \dim (f @: U) = \dim U)%N. +Proof. +rewrite unlock /dimv /= genmx_cap genmx_id -genmx_cap !genmxE. +by rewrite addnC mxrank_mul_ker. +Qed. + +Lemma limg_dim_eq f U : (U :&: lker f = 0)%VS -> \dim (f @: U) = \dim U. +Proof. by rewrite -(limg_ker_dim f U) => ->; rewrite dimv0. Qed. + +Lemma limg_basis_of f U X : + (U :&: lker f = 0)%VS -> basis_of U X -> basis_of (f @: U) (map f X). +Proof. +move=> injUf /andP[/eqP defU /eqnP freeX]. +by rewrite /basis_of /free size_map -limg_span -freeX defU limg_dim_eq ?eqxx. +Qed. + +Lemma lker0P f : reflect (injective f) (lker f == 0%VS). +Proof. +rewrite -subv0; apply: (iffP subvP) => [injf u v eq_fuv | injf u]. + apply/eqP; rewrite -subr_eq0 -memv0 injf //. + by rewrite memv_ker linearB /= eq_fuv subrr. +by rewrite memv_ker memv0 -(inj_eq injf) linear0. +Qed. + +Lemma limg_ker0 f U V : lker f == 0%VS -> (f @: U <= f @: V)%VS = (U <= V)%VS. +Proof. +move/lker0P=> injf; apply/idP/idP=> [/subvP sfUV | ]; last exact: limgS. +by apply/subvP=> u Uu; have /memv_imgP[v Vv /injf->] := sfUV _ (memv_img f Uu). +Qed. + +Lemma eq_limg_ker0 f U V : lker f == 0%VS -> (f @: U == f @: V)%VS = (U == V). +Proof. by move=> injf; rewrite !eqEsubv !limg_ker0. Qed. + +Lemma lker0_lfunK f : lker f == 0%VS -> cancel f f^-1%VF. +Proof. +by move/lker0P=> injf u; apply: injf; rewrite limg_lfunVK ?memv_img ?memvf. +Qed. + +Lemma lker0_compVf f : lker f == 0%VS -> (f^-1 \o f = \1)%VF. +Proof. by move/lker0_lfunK=> fK; apply/lfunP=> u; rewrite !lfunE /= fK. Qed. + +End LinearImage. + +Implicit Arguments memv_imgP [K aT rT f U w]. +Implicit Arguments lfunPn [K aT rT f g]. +Implicit Arguments lker0P [K aT rT f]. +Implicit Arguments eqlfunP [K aT rT f g v]. +Implicit Arguments eqlfun_inP [K aT rT f g V]. + +Section FixedSpace. + +Variables (K : fieldType) (vT : vectType K). +Implicit Types (f : 'End(vT)) (U : {vspace vT}). + +Definition fixedSpace f : {vspace vT} := lker (f - \1%VF). + +Lemma fixedSpaceP f a : reflect (f a = a) (a \in fixedSpace f). +Proof. +by rewrite memv_ker add_lfunE opp_lfunE id_lfunE subr_eq0; apply: eqP. +Qed. + +Lemma fixedSpacesP f U : reflect {in U, f =1 id} (U <= fixedSpace f)%VS. +Proof. by apply: (iffP subvP) => cUf x /cUf/fixedSpaceP. Qed. + +Lemma fixedSpace_limg f U : (U <= fixedSpace f -> f @: U = U)%VS. +Proof. +move/fixedSpacesP=> cUf; apply/vspaceP=> x. +by apply/memv_imgP/idP=> [[{x} x Ux ->] | Ux]; last exists x; rewrite ?cUf. +Qed. + +Lemma fixedSpace_id : fixedSpace \1 = {:vT}%VS. +Proof. +by apply/vspaceP=> x; rewrite memvf; apply/fixedSpaceP; rewrite lfunE. +Qed. + +End FixedSpace. + +Implicit Arguments fixedSpaceP [K vT f a]. +Implicit Arguments fixedSpacesP [K vT f U]. + +Section LinAut. + +Variables (K : fieldType) (vT : vectType K) (f : 'End(vT)). +Hypothesis kerf0 : lker f == 0%VS. + +Lemma lker0_limgf : limg f = fullv. +Proof. +by apply/eqP; rewrite eqEdim subvf limg_dim_eq //= (eqP kerf0) capv0. +Qed. + +Lemma lker0_lfunVK : cancel f^-1%VF f. +Proof. by move=> u; rewrite limg_lfunVK // lker0_limgf memvf. Qed. + +Lemma lker0_compfV : (f \o f^-1 = \1)%VF. +Proof. by apply/lfunP=> u; rewrite !lfunE /= lker0_lfunVK. Qed. + +Lemma lker0_compVKf aT g : (f \o (f^-1 \o g))%VF = g :> 'Hom(aT, vT). +Proof. by rewrite comp_lfunA lker0_compfV comp_lfun1l. Qed. + +Lemma lker0_compKf aT g : (f^-1 \o (f \o g))%VF = g :> 'Hom(aT, vT). +Proof. by rewrite comp_lfunA lker0_compVf ?comp_lfun1l. Qed. + +Lemma lker0_compfK rT h : ((h \o f) \o f^-1)%VF = h :> 'Hom(vT, rT). +Proof. by rewrite -comp_lfunA lker0_compfV comp_lfun1r. Qed. + +Lemma lker0_compfVK rT h : ((h \o f^-1) \o f)%VF = h :> 'Hom(vT, rT). +Proof. by rewrite -comp_lfunA lker0_compVf ?comp_lfun1r. Qed. + +End LinAut. + +Section LinearImageComp. + +Variables (K : fieldType) (aT vT rT : vectType K). +Implicit Types (f : 'Hom(aT, vT)) (g : 'Hom(vT, rT)) (U : {vspace aT}). + +Lemma lim1g U : (\1 @: U)%VS = U. +Proof. +have /andP[/eqP <- _] := vbasisP U; rewrite limg_span map_id_in // => u _. +by rewrite lfunE. +Qed. + +Lemma limg_comp f g U : ((g \o f) @: U = g @: (f @: U))%VS. +Proof. +have /andP[/eqP <- _] := vbasisP U; rewrite !limg_span; congr (span _). +by rewrite -map_comp; apply/eq_map => u; rewrite lfunE. +Qed. + +End LinearImageComp. + +Section LinearPreimage. + +Variables (K : fieldType) (aT rT : vectType K). +Implicit Types (f : 'Hom(aT, rT)) (U : {vspace aT}) (V W : {vspace rT}). + +Lemma lpreim_cap_limg f W : (f @^-1: (W :&: limg f))%VS = (f @^-1: W)%VS. +Proof. by rewrite /lfun_preim -capvA capvv. Qed. + +Lemma lpreim0 f : (f @^-1: 0)%VS = lker f. +Proof. by rewrite /lfun_preim cap0v limg0 add0v. Qed. + +Lemma lpreimS f V W : (V <= W)%VS-> (f @^-1: V <= f @^-1: W)%VS. +Proof. by move=> sVW; rewrite addvS // limgS // capvS. Qed. + +Lemma lpreimK f W : (W <= limg f)%VS -> (f @: (f @^-1: W))%VS = W. +Proof. +move=> sWf; rewrite limg_add (capv_idPl sWf) // -limg_comp. +have /eqP->: (f @: lker f == 0)%VS by rewrite -lkerE. +have /andP[/eqP defW _] := vbasisP W; rewrite addv0 -defW limg_span. +rewrite map_id_in // => x Xx; rewrite lfunE /= limg_lfunVK //. +by apply: span_subvP Xx; rewrite defW. +Qed. + +Lemma memv_preim f u W : (f u \in W) = (u \in f @^-1: W)%VS. +Proof. +apply/idP/idP=> [Wfu | /(memv_img f)]; last first. + by rewrite -lpreim_cap_limg lpreimK ?capvSr // => /memv_capP[]. +rewrite -[u](addNKr (f^-1%VF (f u))) memv_add ?memv_img //. + by rewrite memv_cap Wfu memv_img ?memvf. +by rewrite memv_ker addrC linearB /= subr_eq0 limg_lfunVK ?memv_img ?memvf. +Qed. + +End LinearPreimage. + +Section LfunAlgebra. +(* This section is a bit of a place holder: the instances we build here can't *) +(* be canonical because we are missing an interface for proper vectTypes, *) +(* would sit between Vector and Falgebra. For now, we just supply structure *) +(* definitions here and supply actual instances for F-algebras in a submodule *) +(* of the algebra library (there is currently no actual use of the End(vT) *) +(* algebra structure). Also note that the unit ring structure is missing. *) + +Variables (R : comRingType) (vT : vectType R). +Hypothesis vT_proper : Vector.dim vT > 0. + +Fact lfun1_neq0 : \1%VF != 0 :> 'End(vT). +Proof. +apply/eqP=> /lfunP/(_ (r2v (const_mx 1))); rewrite !lfunE /= => /(canRL r2vK). +by move=> /rowP/(_ (Ordinal vT_proper))/eqP; rewrite linear0 !mxE oner_eq0. +Qed. + +Prenex Implicits comp_lfunA comp_lfun1l comp_lfun1r comp_lfunDl comp_lfunDr. + +Definition lfun_comp_ringMixin := + RingMixin comp_lfunA comp_lfun1l comp_lfun1r comp_lfunDl comp_lfunDr + lfun1_neq0. +Definition lfun_comp_ringType := RingType 'End(vT) lfun_comp_ringMixin. + +(* In the standard endomorphism ring product is categorical composition. *) +Definition lfun_ringMixin : GRing.Ring.mixin_of (lfun_zmodType vT vT) := + GRing.converse_ringMixin lfun_comp_ringType. +Definition lfun_ringType := Eval hnf in RingType 'End(vT) lfun_ringMixin. +Definition lfun_lalgType := Eval hnf in [lalgType R of 'End(vT) + for LalgType R lfun_ringType (fun k x y => comp_lfunZr k y x)]. +Definition lfun_algType := Eval hnf in [algType R of 'End(vT) + for AlgType R _ (fun k (x y : lfun_lalgType) => comp_lfunZl k y x)]. + +End LfunAlgebra. + +Section Projection. + +Variables (K : fieldType) (vT : vectType K). +Implicit Types U V : {vspace vT}. + +Definition daddv_pi U V := Vector.Hom (proj_mx (vs2mx U) (vs2mx V)). +Definition projv U := daddv_pi U U^C. +Definition addv_pi1 U V := daddv_pi (U :\: V) V. +Definition addv_pi2 U V := daddv_pi V (U :\: V). + +Lemma memv_pi U V w : (daddv_pi U V) w \in U. +Proof. by rewrite unlock memvE /subsetv genmxE /= r2vK proj_mx_sub. Qed. + +Lemma memv_proj U w : projv U w \in U. Proof. exact: memv_pi. Qed. + +Lemma memv_pi1 U V w : (addv_pi1 U V) w \in U. +Proof. by rewrite (subvP (diffvSl U V)) ?memv_pi. Qed. + +Lemma memv_pi2 U V w : (addv_pi2 U V) w \in V. Proof. exact: memv_pi. Qed. + +Lemma daddv_pi_id U V u : (U :&: V = 0)%VS -> u \in U -> daddv_pi U V u = u. +Proof. +move/eqP; rewrite -dimv_eq0 memvE /subsetv /dimv !genmxE mxrank_eq0 => /eqP. +by move=> dxUV Uu; rewrite unlock /= proj_mx_id ?v2rK. +Qed. + +Lemma daddv_pi_proj U V w (pi := daddv_pi U V) : + (U :&: V = 0)%VS -> pi (pi w) = pi w. +Proof. by move/daddv_pi_id=> -> //; apply: memv_pi. Qed. + +Lemma daddv_pi_add U V w : + (U :&: V = 0)%VS -> (w \in U + V)%VS -> daddv_pi U V w + daddv_pi V U w = w. +Proof. +move/eqP; rewrite -dimv_eq0 memvE /subsetv /dimv !genmxE mxrank_eq0 => /eqP. +by move=> dxUW UVw; rewrite unlock /= -linearD /= add_proj_mx ?v2rK. +Qed. + +Lemma projv_id U u : u \in U -> projv U u = u. +Proof. exact: daddv_pi_id (capv_compl _). Qed. + +Lemma projv_proj U w : projv U (projv U w) = projv U w. +Proof. exact: daddv_pi_proj (capv_compl _). Qed. + +Lemma memv_projC U w : w - projv U w \in (U^C)%VS. +Proof. +rewrite -{1}[w](daddv_pi_add (capv_compl U)) ?addv_complf ?memvf //. +by rewrite addrC addKr memv_pi. +Qed. + +Lemma limg_proj U : limg (projv U) = U. +Proof. +apply/vspaceP=> u; apply/memv_imgP/idP=> [[u1 _ ->] | ]; first exact: memv_proj. +by exists (projv U u); rewrite ?projv_id ?memv_img ?memvf. +Qed. + +Lemma lker_proj U : lker (projv U) = (U^C)%VS. +Proof. +apply/eqP; rewrite eqEdim andbC; apply/andP; split. + by rewrite dimv_compl -(limg_ker_dim (projv U) fullv) limg_proj addnK capfv. +by apply/subvP=> v; rewrite memv_ker -{2}[v]subr0 => /eqP <-; apply: memv_projC. +Qed. + +Lemma addv_pi1_proj U V w (pi1 := addv_pi1 U V) : pi1 (pi1 w) = pi1 w. +Proof. by rewrite daddv_pi_proj // capv_diff. Qed. + +Lemma addv_pi2_id U V v : v \in V -> addv_pi2 U V v = v. +Proof. by apply: daddv_pi_id; rewrite capvC capv_diff. Qed. + +Lemma addv_pi2_proj U V w (pi2 := addv_pi2 U V) : pi2 (pi2 w) = pi2 w. +Proof. by rewrite addv_pi2_id ?memv_pi2. Qed. + +Lemma addv_pi1_pi2 U V w : + w \in (U + V)%VS -> addv_pi1 U V w + addv_pi2 U V w = w. +Proof. by rewrite -addv_diff; apply: daddv_pi_add; apply: capv_diff. Qed. + +Section Sumv_Pi. + +Variables (I : eqType) (r0 : seq I) (P : pred I) (Vs : I -> {vspace vT}). + +Let sumv_pi_rec i := + fix loop r := if r is j :: r1 then + let V1 := (\sum_(k <- r1) Vs k)%VS in + if j == i then addv_pi1 (Vs j) V1 else (loop r1 \o addv_pi2 (Vs j) V1)%VF + else 0. + +Notation sumV := (\sum_(i <- r0 | P i) Vs i)%VS. +Definition sumv_pi_for V of V = sumV := fun i => sumv_pi_rec i (filter P r0). + +Variables (V : {vspace vT}) (defV : V = sumV). + +Lemma memv_sum_pi i v : sumv_pi_for defV i v \in Vs i. +Proof. +rewrite /sumv_pi_for. +elim: (filter P r0) v => [|j r IHr] v /=; first by rewrite lfunE mem0v. +by case: eqP => [->|_]; rewrite ?lfunE ?memv_pi1 /=. +Qed. + +Lemma sumv_pi_uniq_sum v : + uniq (filter P r0) -> v \in V -> + \sum_(i <- r0 | P i) sumv_pi_for defV i v = v. +Proof. +rewrite /sumv_pi_for defV -!(big_filter r0 P). +elim: (filter P r0) v => [|i r IHr] v /= => [_ | /andP[r'i /IHr{IHr}IHr]]. + by rewrite !big_nil memv0 => /eqP. +rewrite !big_cons eqxx => /addv_pi1_pi2; congr (_ + _ = v). +rewrite -[_ v]IHr ?memv_pi2 //; apply: eq_big_seq => j /=. +by case: eqP => [<- /idPn | _]; rewrite ?lfunE. +Qed. + +End Sumv_Pi. + +End Projection. + +Prenex Implicits daddv_pi projv addv_pi1 addv_pi2. +Notation sumv_pi V := (sumv_pi_for (erefl V)). + +Section SumvPi. + +Variable (K : fieldType) (vT : vectType K). + +Lemma sumv_pi_sum (I : finType) (P : pred I) Vs v (V : {vspace vT}) + (defV : V = (\sum_(i | P i) Vs i)%VS) : + v \in V -> \sum_(i | P i) sumv_pi_for defV i v = v :> vT. +Proof. by apply: sumv_pi_uniq_sum; apply: enum_uniq. Qed. + +Lemma sumv_pi_nat_sum m n (P : pred nat) Vs v (V : {vspace vT}) + (defV : V = (\sum_(m <= i < n | P i) Vs i)%VS) : + v \in V -> \sum_(m <= i < n | P i) sumv_pi_for defV i v = v :> vT. +Proof. by apply: sumv_pi_uniq_sum; apply/filter_uniq/iota_uniq. Qed. + +End SumvPi. + +Section SubVector. + +(* Turn a {vspace V} into a vectType *) +Variable (K : fieldType) (vT : vectType K) (U : {vspace vT}). + +Inductive subvs_of : predArgType := Subvs u & u \in U. + +Definition vsval w := let: Subvs u _ := w in u. +Canonical subvs_subType := Eval hnf in [subType for vsval]. +Definition subvs_eqMixin := Eval hnf in [eqMixin of subvs_of by <:]. +Canonical subvs_eqType := Eval hnf in EqType subvs_of subvs_eqMixin. +Definition subvs_choiceMixin := [choiceMixin of subvs_of by <:]. +Canonical subvs_choiceType := ChoiceType subvs_of subvs_choiceMixin. +Definition subvs_zmodMixin := [zmodMixin of subvs_of by <:]. +Canonical subvs_zmodType := ZmodType subvs_of subvs_zmodMixin. +Definition subvs_lmodMixin := [lmodMixin of subvs_of by <:]. +Canonical subvs_lmodType := LmodType K subvs_of subvs_lmodMixin. + +Lemma subvsP w : vsval w \in U. Proof. exact: valP. Qed. +Lemma subvs_inj : injective vsval. Proof. exact: val_inj. Qed. +Lemma congr_subvs u v : u = v -> vsval u = vsval v. Proof. exact: congr1. Qed. + +Lemma vsval_is_linear : linear vsval. Proof. by []. Qed. +Canonical vsval_additive := Additive vsval_is_linear. +Canonical vsval_linear := AddLinear vsval_is_linear. + +Fact vsproj_key : unit. Proof. by []. Qed. +Definition vsproj_def u := Subvs (memv_proj U u). +Definition vsproj := locked_with vsproj_key vsproj_def. +Canonical vsproj_unlockable := [unlockable fun vsproj]. + +Lemma vsprojK : {in U, cancel vsproj vsval}. +Proof. by rewrite unlock; apply: projv_id. Qed. +Lemma vsvalK : cancel vsval vsproj. +Proof. by move=> w; exact/val_inj/vsprojK/subvsP. Qed. + +Lemma vsproj_is_linear : linear vsproj. +Proof. by move=> k w1 w2; apply: val_inj; rewrite unlock /= linearP. Qed. +Canonical vsproj_additive := Additive vsproj_is_linear. +Canonical vsproj_linear := AddLinear vsproj_is_linear. + +Fact subvs_vect_iso : Vector.axiom (\dim U) subvs_of. +Proof. +exists (fun w => \row_i coord (vbasis U) i (vsval w)). + by move=> k w1 w2; apply/rowP=> i; rewrite !mxE linearP. +exists (fun rw : 'rV_(\dim U) => vsproj (\sum_i rw 0 i *: (vbasis U)`_i)). + move=> w /=; congr (vsproj _ = w): (vsvalK w). + by rewrite {1}(coord_vbasis (subvsP w)); apply: eq_bigr => i _; rewrite mxE. +move=> rw; apply/rowP=> i; rewrite mxE vsprojK. + by rewrite coord_sum_free ?(basis_free (vbasisP U)). +by apply: rpred_sum => j _; rewrite rpredZ ?vbasis_mem ?memt_nth. +Qed. + +Definition subvs_vectMixin := VectMixin subvs_vect_iso. +Canonical subvs_vectType := VectType K subvs_of subvs_vectMixin. + +End SubVector. +Prenex Implicits vsval vsproj vsvalK. +Implicit Arguments subvs_inj [[K] [vT] [U] x1 x2]. +Implicit Arguments vsprojK [[K] [vT] [U] x]. + +Section MatrixVectType. + +Variables (R : ringType) (m n : nat). + +(* The apparently useless => /= in line 1 of the proof performs some evar *) +(* expansions that the Ltac interpretation of exists is incapable of doing. *) +Fact matrix_vect_iso : Vector.axiom (m * n) 'M[R]_(m, n). +Proof. +exists mxvec => /=; first exact: linearP. +by exists vec_mx; [apply: mxvecK | apply: vec_mxK]. +Qed. +Definition matrix_vectMixin := VectMixin matrix_vect_iso. +Canonical matrix_vectType := VectType R 'M[R]_(m, n) matrix_vectMixin. + +End MatrixVectType. + +(* A ring is a one-dimension vector space *) +Section RegularVectType. + +Variable R : ringType. + +Fact regular_vect_iso : Vector.axiom 1 R^o. +Proof. +exists (fun a => a%:M) => [a b c|]; first by rewrite rmorphD scale_scalar_mx. +by exists (fun A : 'M_1 => A 0 0) => [a | A]; rewrite ?mxE // -mx11_scalar. +Qed. +Definition regular_vectMixin := VectMixin regular_vect_iso. +Canonical regular_vectType := VectType R R^o regular_vectMixin. + +End RegularVectType. + +(* External direct product of two vectTypes. *) +Section ProdVector. + +Variables (R : ringType) (vT1 vT2 : vectType R). + +Fact pair_vect_iso : Vector.axiom (Vector.dim vT1 + Vector.dim vT2) (vT1 * vT2). +Proof. +pose p2r (u : vT1 * vT2) := row_mx (v2r u.1) (v2r u.2). +pose r2p w := (r2v (lsubmx w) : vT1, r2v (rsubmx w) : vT2). +have r2pK : cancel r2p p2r by move=> w; rewrite /p2r !r2vK hsubmxK. +have p2rK : cancel p2r r2p by case=> u v; rewrite /r2p row_mxKl row_mxKr !v2rK. +have r2p_lin: linear r2p by move=> a u v; congr (_ , _); rewrite /= !linearP. +by exists p2r; [apply: (@can2_linear _ _ _ (Linear r2p_lin)) | exists r2p]. +Qed. +Definition pair_vectMixin := VectMixin pair_vect_iso. +Canonical pair_vectType := VectType R (vT1 * vT2) pair_vectMixin. + +End ProdVector. + +(* Function from a finType into a ring form a vectype. *) +Section FunVectType. + +Variable (I : finType) (R : ringType) (vT : vectType R). + +(* Type unification with exist is again a problem in this proof. *) +Fact ffun_vect_iso : Vector.axiom (#|I| * Vector.dim vT) {ffun I -> vT}. +Proof. +pose fr (f : {ffun I -> vT}) := mxvec (\matrix_(i < #|I|) v2r (f (enum_val i))). +exists fr => /= [k f g|]. + rewrite /fr -linearP; congr (mxvec _); apply/matrixP=> i j. + by rewrite !mxE /= !ffunE linearP !mxE. +exists (fun r => [ffun i => r2v (row (enum_rank i) (vec_mx r)) : vT]) => [g|r]. + by apply/ffunP=> i; rewrite ffunE mxvecK rowK v2rK enum_rankK. +by apply/(canLR vec_mxK)/matrixP=> i j; rewrite mxE ffunE r2vK enum_valK mxE. +Qed. + +Definition ffun_vectMixin := VectMixin ffun_vect_iso. +Canonical ffun_vectType := VectType R {ffun I -> vT} ffun_vectMixin. + +End FunVectType. + +Canonical exp_vectType (K : fieldType) (vT : vectType K) n := + [vectType K of vT ^ n]. + +(* Solving a tuple of linear equations. *) +Section Solver. + +Variable (K : fieldType) (vT : vectType K). +Variables (n : nat) (lhs : n.-tuple 'End(vT)) (rhs : n.-tuple vT). + +Let lhsf u := finfun ((tnth lhs)^~ u). +Definition vsolve_eq U := finfun (tnth rhs) \in (linfun lhsf @: U)%VS. + +Lemma vsolve_eqP (U : {vspace vT}) : + reflect (exists2 u, u \in U & forall i, tnth lhs i u = tnth rhs i) + (vsolve_eq U). +Proof. +have lhsZ: linear lhsf by move=> a u v; apply/ffunP=> i; rewrite !ffunE linearP. +apply: (iffP memv_imgP) => [] [u Uu sol_u]; exists u => //. + by move=> i; rewrite -[tnth rhs i]ffunE sol_u (lfunE (Linear lhsZ)) ffunE. +by apply/ffunP=> i; rewrite (lfunE (Linear lhsZ)) !ffunE sol_u. +Qed. + +End Solver. + |
