Theory Finite_Dimensional_Splitting

section ‹Complements in finite-dimensional vector spaces›

theory Finite_Dimensional_Splitting
  imports Rank_Nullity Quotient_Module Module_Iso_Theorems
begin

subsection ‹Dimension of quotient spaces›

no_notation plus (infixl ‹+› 65)
no_notation minus (infixl ‹-› 65)
unbundle no uminus_syntax

text ‹A quotient of a vector space by a subspace inherits the vector-space structure already
  constructed at the module level.  The natural projection is therefore a linear map.›

locale vector_quotient = vector_subspace
begin

sublocale factor: submodule_in_module
  R "(+)" "(⋅)" "𝟬" "𝟭" "(⊕)" "𝟬V" V "(⊙)" W
proof
  show "mod.submodule W" by (rule W_submodule)
qed

lemma quotient_vector_space:
  "Vector_Space R (+) (⋅) 𝟬 𝟭
    factor.qadd (factor.Qclass 𝟬V) factor.Qcarrier factor.qscale"
proof (intro Vector_Space.intro Vector_Space_axioms.intro)
  show "Field R (+) (⋅) 𝟬 𝟭" by unfold_locales
  show "Abelian_Group factor.Qcarrier factor.qadd (factor.Qclass 𝟬V)"
    by (rule factor.quotient.madd_group)
  show "⋀a X. ⟦a ∈ R; X ∈ factor.Qcarrier⟧ ⟹
      factor.qscale a X ∈ factor.Qcarrier"
    by (rule factor.quotient.scale_closed)
  show "⋀a X Y. ⟦a ∈ R; X ∈ factor.Qcarrier; Y ∈ factor.Qcarrier⟧ ⟹
      factor.qscale a (factor.qadd X Y) = factor.qadd (factor.qscale a X) (factor.qscale a Y)"
    by (rule factor.quotient.scale_distrib_madd)
  show "⋀a b X. ⟦a ∈ R; b ∈ R; X ∈ factor.Qcarrier⟧ ⟹
      factor.qscale (a + b) X = factor.qadd (factor.qscale a X) (factor.qscale b X)"
    by (rule factor.quotient.scale_distrib_add)
  show "⋀a b X. ⟦a ∈ R; b ∈ R; X ∈ factor.Qcarrier⟧ ⟹
      factor.qscale (a ⋅ b) X = factor.qscale a (factor.qscale b X)"
    by (rule factor.quotient.scale_scale)
  show "⋀X. X ∈ factor.Qcarrier ⟹ factor.qscale 𝟭 X = X"
    by (rule factor.quotient.scale_one)
qed

sublocale quotient: Vector_Space
  R "(+)" "(⋅)" "𝟬" "𝟭"
  factor.qadd "factor.Qclass 𝟬V" factor.Qcarrier factor.qscale
  by (rule quotient_vector_space)

sublocale projection: linear_map
  R "(+)" "(⋅)" "𝟬" "𝟭"
  V "(⊕)" "𝟬V" "(⊙)"
  factor.Qcarrier factor.qadd "factor.Qclass 𝟬V" factor.qscale factor.nat_proj
  by unfold_locales

text ‹The dimension of a subspace plus the dimension of its quotient is the dimension of the
  ambient space.  This is rank--nullity for the natural quotient projection.›

theorem quotient_dimension:
  assumes B: "basis B"
  shows "plus sub.dimension quotient.dimension = dimension"
  using projection.rank_nullity[OF B] factor.nat_proj_Ker factor.nat_proj_image by simp

lemma quotient_basis_exists:
  assumes B: "basis B"
  shows "∃C. quotient.basis C"
proof -
  obtain A where A: "projection.kernel.sub.basis A"
    using projection.kernel.subspace_basis_exists[OF B] by blast
  have AKer: "A ⊆ factor.nat_proj.Ker"
    using A by (simp add: projection.kernel.sub.basis_def)
  have indA: "lin_indep A"
    using projection.kernel.sub.basis_lin_indep[OF A]
      projection.kernel.sub_lin_indep_iff[OF AKer] by simp
  obtain C where AC: "A ⊆ C" and C: "basis C"
    using basis_extension[OF indA B] by blast
  have "projection.image.sub.basis (factor.nat_proj ` (C ∖ A))"
    by (rule projection.image_basis_complement[OF A C AC])
  then have "quotient.basis (factor.nat_proj ` (C ∖ A))"
    using factor.nat_proj_image by simp
  then show ?thesis by blast
qed

end

subsection ‹Grassmann's dimension formula›

locale vector_subspace_pair = Vector_Space +
  fixes U W :: "'b set"
  assumes U_submodule: "mod.submodule U"
    and W_submodule: "mod.submodule W"
begin

abbreviation sum_carrier where
  "sum_carrier ≡ mod.submodule_sum U W"

abbreviation restricted_projection where
  "restricted_projection ≡ mod.proj_res U W"

abbreviation ambient_submodule where
  "ambient_submodule ≡ mod.submodule"

lemmas ambient_submodule_inter = mod.submodule_inter
lemmas ambient_sum_submodule = mod.submodule_sum_submodule
lemmas ambient_sum_incl_right = mod.submodule_sum_incl_right
lemmas ambient_submodule_subset = mod.submodule_subset
lemmas ambient_submodule_zero = mod.submodule_zero
lemmas ambient_submodule_add = mod.submodule_add
lemmas ambient_submodule_scale = mod.submodule_scale
lemmas ambient_submodule_vector_space = submodule_vector_space
lemmas ambient_proj_res_hom = mod.proj_res_hom
lemmas ambient_proj_res_Ker = mod.proj_res_Ker
lemmas ambient_proj_res_image = mod.proj_res_image

sublocale left: vector_subspace
  R "(+)" "(⋅)" "𝟬" "𝟭" "(⊕)" "𝟬V" V "(⊙)" U
proof
  show "ambient_submodule U" by (rule U_submodule)
qed

sublocale right: vector_quotient
  R "(+)" "(⋅)" "𝟬" "𝟭" "(⊕)" "𝟬V" V "(⊙)" W
proof
  show "ambient_submodule W" by (rule W_submodule)
qed

sublocale inter: vector_subspace
  R "(+)" "(⋅)" "𝟬" "𝟭" "(⊕)" "𝟬V" V "(⊙)" "U ∩ W"
proof
  show "ambient_submodule (U ∩ W)"
    by (rule ambient_submodule_inter[OF U_submodule W_submodule])
qed

sublocale sum: vector_subspace
  R "(+)" "(⋅)" "𝟬" "𝟭" "(⊕)" "𝟬V" V "(⊙)" sum_carrier
proof
  show "ambient_submodule sum_carrier"
    by (rule ambient_sum_submodule[OF U_submodule W_submodule])
qed

text ‹The right summand is also a subspace of the sum.›

sublocale sum_quotient: vector_quotient
  R "(+)" "(⋅)" "𝟬" "𝟭" "(⊕)" "𝟬V" sum_carrier "(⊙)" W
proof
  show "sum.sub.mod.submodule W"
  proof (rule sum.sub.mod.submoduleI)
    show "W ⊆ sum_carrier"
      by (rule ambient_sum_incl_right[OF U_submodule W_submodule])
    show "𝟬V ∈ W" by (rule ambient_submodule_zero[OF W_submodule])
    show "⋀u v. ⟦u ∈ W; v ∈ W⟧ ⟹ u ⊕ v ∈ W"
      by (rule ambient_submodule_add[OF W_submodule])
    show "⋀a v. ⟦a ∈ R; v ∈ W⟧ ⟹ a ⊙ v ∈ W"
      by (rule ambient_submodule_scale[OF W_submodule])
  qed
qed

text ‹Restricting the quotient projection by @{term W} to @{term U} gives a linear map whose
  kernel is @{term "U ∩ W"} and whose image consists of the classes represented in the sum.›

lemma restricted_projection_hom:
  "module_homomorphism R (+) (⋅) 𝟬 𝟭
    U (⊕) 𝟬V (⊙)
    right.factor.Qcarrier right.factor.qadd (right.factor.Qclass 𝟬V)
    right.factor.qscale restricted_projection"
  by (rule ambient_proj_res_hom[OF U_submodule W_submodule])

lemma restricted_linear_map:
  "linear_map R (+) (⋅) 𝟬 𝟭
    U (⊕) 𝟬V (⊙)
    right.factor.Qcarrier right.factor.qadd (right.factor.Qclass 𝟬V)
    right.factor.qscale restricted_projection"
proof (intro linear_map.intro)
  show "Vector_Space R (+) (⋅) 𝟬 𝟭 (⊕) 𝟬V U (⊙)"
    by (rule ambient_submodule_vector_space[OF U_submodule])
  show "Vector_Space R (+) (⋅) 𝟬 𝟭
      right.factor.qadd (right.factor.Qclass 𝟬V)
      right.factor.Qcarrier right.factor.qscale"
    by (rule right.quotient_vector_space)
  show "module_homomorphism R (+) (⋅) 𝟬 𝟭
      U (⊕) 𝟬V (⊙)
      right.factor.Qcarrier right.factor.qadd (right.factor.Qclass 𝟬V)
      right.factor.qscale restricted_projection"
    by (rule restricted_projection_hom)
qed

sublocale restricted: linear_map
  R "(+)" "(⋅)" "𝟬" "𝟭"
  U "(⊕)" "𝟬V" "(⊙)"
  right.factor.Qcarrier right.factor.qadd "right.factor.Qclass 𝟬V"
  right.factor.qscale restricted_projection
  by (rule restricted_linear_map)

lemma quotient_class_eq:
  assumes x: "x ∈ sum_carrier"
  shows "sum_quotient.factor.Qclass x = right.factor.Qclass x"
proof -
  have xV: "x ∈ V"
    using x ambient_submodule_subset
      [OF ambient_sum_submodule[OF U_submodule W_submodule]] by blast
  show ?thesis
    using sum_quotient.factor.madd_sub.Class_is_Left_Coset[OF x]
      right.factor.madd_sub.Class_is_Left_Coset[OF xV] by simp
qed

lemma sum_quotient_carrier_eq:
  "sum_quotient.factor.Qcarrier = right.factor.Qclass ` sum_carrier"
proof
  show "sum_quotient.factor.Qcarrier ⊆ right.factor.Qclass ` sum_carrier"
  proof
    fix X assume X: "X ∈ sum_quotient.factor.Qcarrier"
    then obtain x where x: "x ∈ sum_carrier"
      "X = sum_quotient.factor.Qclass x"
      using sum_quotient.factor.madd_sub.representant_exists by blast
    then show "X ∈ right.factor.Qclass ` sum_carrier"
      using quotient_class_eq[OF x(1)] by blast
  qed
next
  show "right.factor.Qclass ` sum_carrier ⊆ sum_quotient.factor.Qcarrier"
  proof
    fix X assume "X ∈ right.factor.Qclass ` sum_carrier"
    then obtain x where x: "x ∈ sum_carrier" "X = right.factor.Qclass x" by blast
    have "sum_quotient.factor.Qclass x ∈ sum_quotient.factor.Qcarrier"
      using x(1) by simp
    then show "X ∈ sum_quotient.factor.Qcarrier" using x quotient_class_eq by simp
  qed
qed

lemma sum_quotient_carrier_eq_image:
  "sum_quotient.factor.Qcarrier = restricted_projection ` U"
  using sum_quotient_carrier_eq ambient_proj_res_image[OF U_submodule W_submodule] by simp

lemma quotient_add_eq:
  assumes X: "X ∈ sum_quotient.factor.Qcarrier"
    and Y: "Y ∈ sum_quotient.factor.Qcarrier"
  shows "sum_quotient.factor.qadd X Y = right.factor.qadd X Y"
proof -
  obtain x where x: "x ∈ sum_carrier" "X = sum_quotient.factor.Qclass x"
    using X sum_quotient.factor.madd_sub.representant_exists by blast
  obtain y where y: "y ∈ sum_carrier" "Y = sum_quotient.factor.Qclass y"
    using Y sum_quotient.factor.madd_sub.representant_exists by blast
  have xy: "x ⊕ y ∈ sum_carrier"
    by (rule ambient_submodule_add
        [OF ambient_sum_submodule[OF U_submodule W_submodule] x(1) y(1)])
  have xV: "x ∈ V" and yV: "y ∈ V"
    using x y ambient_submodule_subset
      [OF ambient_sum_submodule[OF U_submodule W_submodule]] by auto
  have "sum_quotient.factor.qadd X Y = sum_quotient.factor.Qclass (x ⊕ y)"
    using x y by (simp add: sum_quotient.factor.madd_sub.Class_commutes_with_composition)
  also have "… = right.factor.Qclass (x ⊕ y)" by (rule quotient_class_eq[OF xy])
  also have "… = right.factor.qadd X Y"
    using x y xV yV quotient_class_eq
    by (simp add: right.factor.madd_sub.Class_commutes_with_composition)
  finally show ?thesis .
qed

lemma quotient_scale_eq:
  assumes a: "a ∈ R" and X: "X ∈ sum_quotient.factor.Qcarrier"
  shows "sum_quotient.factor.qscale a X = right.factor.qscale a X"
proof -
  obtain x where x: "x ∈ sum_carrier" "X = sum_quotient.factor.Qclass x"
    using X sum_quotient.factor.madd_sub.representant_exists by blast
  have ax: "a ⊙ x ∈ sum_carrier"
    by (rule ambient_submodule_scale
        [OF ambient_sum_submodule[OF U_submodule W_submodule] a x(1)])
  have xV: "x ∈ V"
    using x ambient_submodule_subset
      [OF ambient_sum_submodule[OF U_submodule W_submodule]] by blast
  have "sum_quotient.factor.qscale a X = sum_quotient.factor.Qclass (a ⊙ x)"
    using a x by (simp add: sum_quotient.factor.qscale_Class)
  also have "… = right.factor.Qclass (a ⊙ x)" by (rule quotient_class_eq[OF ax])
  also have "… = right.factor.qscale a X"
    using a x xV quotient_class_eq by (simp add: right.factor.qscale_Class)
  finally show ?thesis .
qed

definition quotient_embedding where
  "quotient_embedding = restrict id sum_quotient.factor.Qcarrier"

lemma quotient_embedding_apply [simp]:
  "X ∈ sum_quotient.factor.Qcarrier ⟹ quotient_embedding X = X"
  by (simp add: quotient_embedding_def)

lemma quotient_embedding_hom:
  "module_homomorphism R (+) (⋅) 𝟬 𝟭
    sum_quotient.factor.Qcarrier sum_quotient.factor.qadd
    (sum_quotient.factor.Qclass 𝟬V) sum_quotient.factor.qscale
    (restricted_projection ` U) right.factor.qadd (right.factor.Qclass 𝟬V)
    right.factor.qscale quotient_embedding"
proof
  show "quotient_embedding ∈ sum_quotient.factor.Qcarrier →E restricted_projection ` U"
    using sum_quotient_carrier_eq_image
    by (auto simp: quotient_embedding_def PiE_iff extensional_def)
  show "⋀X Y. ⟦X ∈ sum_quotient.factor.Qcarrier;
      Y ∈ sum_quotient.factor.Qcarrier⟧ ⟹
      quotient_embedding (sum_quotient.factor.qadd X Y) =
      right.factor.qadd (quotient_embedding X) (quotient_embedding Y)"
  proof -
    fix X Y assume X: "X ∈ sum_quotient.factor.Qcarrier"
      and Y: "Y ∈ sum_quotient.factor.Qcarrier"
    have XY: "sum_quotient.factor.qadd X Y ∈ sum_quotient.factor.Qcarrier"
      using X Y by (rule sum_quotient.factor.quotient.madd_closed)
    have "quotient_embedding (sum_quotient.factor.qadd X Y) =
        sum_quotient.factor.qadd X Y"
      by (rule quotient_embedding_apply[OF XY])
    also have "… = right.factor.qadd X Y" by (rule quotient_add_eq[OF X Y])
    also have "… = right.factor.qadd (quotient_embedding X) (quotient_embedding Y)"
      using X Y by simp
    finally show "quotient_embedding (sum_quotient.factor.qadd X Y) =
        right.factor.qadd (quotient_embedding X) (quotient_embedding Y)" .
  qed
  show "⋀a X. ⟦a ∈ R; X ∈ sum_quotient.factor.Qcarrier⟧ ⟹
      quotient_embedding (sum_quotient.factor.qscale a X) =
      right.factor.qscale a (quotient_embedding X)"
  proof -
    fix a X assume a: "a ∈ R" and X: "X ∈ sum_quotient.factor.Qcarrier"
    have aX: "sum_quotient.factor.qscale a X ∈ sum_quotient.factor.Qcarrier"
      using a X by (rule sum_quotient.quotient.scale_closed)
    have "quotient_embedding (sum_quotient.factor.qscale a X) =
        sum_quotient.factor.qscale a X"
      by (rule quotient_embedding_apply[OF aX])
    also have "… = right.factor.qscale a X" by (rule quotient_scale_eq[OF a X])
    also have "… = right.factor.qscale a (quotient_embedding X)" using X by simp
    finally show "quotient_embedding (sum_quotient.factor.qscale a X) =
        right.factor.qscale a (quotient_embedding X)" .
  qed
qed

lemma quotient_embedding_linear_map:
  "linear_map R (+) (⋅) 𝟬 𝟭
    sum_quotient.factor.Qcarrier sum_quotient.factor.qadd
    (sum_quotient.factor.Qclass 𝟬V) sum_quotient.factor.qscale
    (restricted_projection ` U) right.factor.qadd (right.factor.Qclass 𝟬V)
    right.factor.qscale quotient_embedding"
proof (intro linear_map.intro)
  show "Vector_Space R (+) (⋅) 𝟬 𝟭
      sum_quotient.factor.qadd (sum_quotient.factor.Qclass 𝟬V)
      sum_quotient.factor.Qcarrier sum_quotient.factor.qscale"
    by (rule sum_quotient.quotient_vector_space)
  show "Vector_Space R (+) (⋅) 𝟬 𝟭
      right.factor.qadd (right.factor.Qclass 𝟬V)
      (restricted_projection ` U) right.factor.qscale"
    by (rule right.quotient.submodule_vector_space[OF restricted.hom.image_submodule])
  show "module_homomorphism R (+) (⋅) 𝟬 𝟭
      sum_quotient.factor.Qcarrier sum_quotient.factor.qadd
      (sum_quotient.factor.Qclass 𝟬V) sum_quotient.factor.qscale
      (restricted_projection ` U) right.factor.qadd (right.factor.Qclass 𝟬V)
      right.factor.qscale quotient_embedding"
    by (rule quotient_embedding_hom)
qed

sublocale quotient_embedding: linear_map
  R "(+)" "(⋅)" "𝟬" "𝟭"
  sum_quotient.factor.Qcarrier sum_quotient.factor.qadd
  "sum_quotient.factor.Qclass 𝟬V" sum_quotient.factor.qscale
  "restricted_projection ` U" right.factor.qadd "right.factor.Qclass 𝟬V"
  right.factor.qscale quotient_embedding
  by (rule quotient_embedding_linear_map)

lemma quotient_embedding_bij:
  "bij_betw quotient_embedding sum_quotient.factor.Qcarrier (restricted_projection ` U)"
  using sum_quotient_carrier_eq_image
  by (auto simp: quotient_embedding_def bij_betw_def inj_on_def)

text ‹∗‹Grassmann's dimension formula.›  The intersection dimension plus the sum
  dimension equals the sum of the two subspace dimensions.›

theorem grassmann_dimension:
  assumes B: "basis B"
  shows "plus inter.sub.dimension sum.sub.dimension =
    plus left.sub.dimension right.sub.dimension"
proof -
  obtain BU where BU: "left.sub.basis BU" using left.subspace_basis_exists[OF B] by blast
  obtain BS where BS: "sum.sub.basis BS" using sum.subspace_basis_exists[OF B] by blast
  obtain BQ where BQ: "sum_quotient.quotient.basis BQ"
    using sum_quotient.quotient_basis_exists[OF BS] by blast
  have rank: "plus inter.sub.dimension restricted.image.sub.dimension = left.sub.dimension"
  proof -
    have ker: "restricted.hom.Ker = U ∩ W"
      unfolding restricted.hom.Ker_def
      using ambient_proj_res_Ker[OF U_submodule W_submodule] by simp
    have dim: "restricted.kernel.sub.dimension = inter.sub.dimension"
      using ker by simp
    show ?thesis using restricted.rank_nullity[OF BU] dim by simp
  qed
  have quotient: "plus right.sub.dimension sum_quotient.quotient.dimension = sum.sub.dimension"
    using sum_quotient.quotient_dimension[OF BS] by simp
  have iso: "sum_quotient.quotient.dimension = restricted.image.sub.dimension"
    using quotient_embedding.dimension_eq_of_bij_betw[OF BQ quotient_embedding_bij] .
  show ?thesis using rank quotient iso by presburger
qed

corollary direct_sum_dimension:
  assumes B: "basis B" and disjoint: "U ∩ W = {𝟬V}"
  shows "sum.sub.dimension = plus left.sub.dimension right.sub.dimension"
proof -
  have empty_basis: "inter.sub.basis {}"
    by (rule inter.sub.basis_empty_trivial[OF disjoint])
  have "inter.sub.dimension = 0"
    using inter.sub.dimension_eq_any_field[OF empty_basis] by simp
  then show ?thesis using grassmann_dimension[OF B] by simp
qed

end

subsection ‹Complements in finite-dimensional vector spaces›

context vector_subspace
begin

text ‹Every subspace of a finite-dimensional vector space has a complementary subspace.
  Extend a basis of the subspace to an ambient basis and take the span of the added basis vectors.
  Independence gives the trivial intersection, while span minimality gives the full sum.›
theorem complementary_subspace_exists:
  assumes B: "basis B"
  shows "∃U. mod.submodule U ∧ W ∩ U = {𝟬V} ∧
    mod.submodule_sum W U = V"
proof -
  obtain A where A: "sub.basis A" and AW: "A ⊆ W"
    using subspace_basis_exists[OF B] sub.basis_def by blast
  then obtain C where AC: "A ⊆ C" and C: "basis C"
    using B basis_extension sub.basis_lin_indep sub_lin_indep_iff by meson
  define D where "D = C ∖ A"
  define U where "U = span D"
  have CV: "C ⊆ V" using C by (simp add: basis_def)
  have DV: "D ⊆ V" using CV D_def by blast
  have U_submodule: "mod.submodule U"
    unfolding U_def by (rule mod.span_submodule[OF DV])

  have "sub.mod.spanning A"
    using sub.basis_module_basis[OF A] by (rule sub.mod.module_basis_spanning)
  then have W_span: "W = span A"
    using sub.mod.spanning_def sub_span_eq by force
  have "mod.lin_indep C"
    using basis_module_basis[OF C] by (rule mod.module_basis_lin_indep)
  then have trivial_intersection: "W ∩ U = {𝟬V}"
    using AC D_def U_def W_span mod.span_inter_eq_trivial by force
  have sum_submodule: "mod.submodule (mod.submodule_sum W U)"
    by (rule mod.submodule_sum_submodule[OF W_submodule U_submodule])
  have A_sum: "A ⊆ mod.submodule_sum W U"
    using AW mod.submodule_sum_incl_left[OF W_submodule U_submodule] by blast
  have D_U: "D ⊆ U"
    unfolding U_def by (rule mod.span_incl[OF DV])
  have D_sum: "D ⊆ mod.submodule_sum W U"
    using D_U mod.submodule_sum_incl_right[OF W_submodule U_submodule] by blast
  have C_sum: "C ⊆ mod.submodule_sum W U"
    using A_sum D_def D_sum by auto
  have span_subset_sum: "span C ⊆ mod.submodule_sum W U"
    by (rule mod.span_minimal[OF sum_submodule C_sum])
  have "span C = V"
    using C CV basis_spanning mod.spanningI mod.spanning_def spanning_span_all by force
  then have "mod.submodule_sum W U = V"
    using mod.submodule_def span_subset_sum sum_submodule by force
  then show ?thesis using U_submodule trivial_intersection by blast
qed

end

context vector_quotient
begin

text ‹Consequently every quotient of a finite-dimensional vector space is represented by a
  complementary subspace of the ambient space.  The isomorphism is not merely existential: it is
  the natural quotient projection restricted to that complement.›
theorem complementary_quotient_isomorphism_exists:
  assumes B: "basis B"
  shows "∃U. mod.submodule U
      ∧ W ∩ U = {𝟬V}
      ∧ mod.submodule_sum W U = V
      ∧ module_homomorphism R (+) (⋅) 𝟬 𝟭
            U (⊕) 𝟬V (⊙)
            factor.Qcarrier factor.qadd (factor.Qclass 𝟬V) factor.qscale
            (mod.proj_res U W)
      ∧ bij_betw (mod.proj_res U W) U factor.Qcarrier"
proof -
  obtain U where U: "mod.submodule U"
    and disjoint: "W ∩ U = {𝟬V}"
    and full: "mod.submodule_sum W U = V"
    using complementary_subspace_exists[OF B] by blast
  have "mod.submodule_sum U W = V"
    using full mod.submodule_sum_commute[OF U W_submodule] by simp
  then show ?thesis using U disjoint full
    using W_submodule mod.complement_quotient_isomorphism by blast
qed

end

notation plus (infixl ‹+› 65)
notation minus (infixl ‹-› 65)
unbundle uminus_syntax

end