Theory Scalar_Restriction_Bridge

theory Scalar_Restriction_Bridge
  imports "HOL-New_Algebra.Steinitz"
begin

section ‹Restriction of scalars for carrier-based vector spaces›

text ‹
The upper carrier is an arbitrary vector space, not a field.  In particular,
it may be the zero space.  The lower vector space describes the intermediate
field over the smaller field, using the same scalar operations.  These
parameters can also describe subfields of a noncommutative ambient ring and a
vector subspace of that ring.
›

locale scalar_restriction_tower =
  lower: Vector_Space K sadd smult szero sone sadd szero F smult +
  upper: Vector_Space F sadd smult szero sone vadd vzero E scale
  for K F :: "'s set"
    and sadd smult :: "'s ⇒ 's ⇒ 's"
    and szero sone :: 's
    and vadd :: "'v ⇒ 'v ⇒ 'v"
    and vzero :: 'v
    and E :: "'v set"
    and scale :: "'s ⇒ 'v ⇒ 'v" +
  assumes base_subset: "K ⊆ F"
begin

sublocale direct: Vector_Space K sadd smult szero sone vadd vzero E scale
proof (intro Vector_Space.intro Vector_Space_axioms.intro)
  show "Field K sadd smult szero sone" by (rule lower.Field_axioms)
  show "Abelian_Group E vadd vzero" by (rule upper.vadd_group)
  show "⋀a v. ⟦a ∈ K; v ∈ E⟧ ⟹ scale a v ∈ E"
    using base_subset by (blast intro: upper.scale_closed)
  show "⋀a u v. ⟦a ∈ K; u ∈ E; v ∈ E⟧ ⟹
      scale a (vadd u v) = vadd (scale a u) (scale a v)"
    using base_subset by (blast intro: upper.scale_distrib_vadd)
  show "⋀a b v. ⟦a ∈ K; b ∈ K; v ∈ E⟧ ⟹
      scale (sadd a b) v = vadd (scale a v) (scale b v)"
    using base_subset by (blast intro: upper.scale_distrib_add)
  show "⋀a b v. ⟦a ∈ K; b ∈ K; v ∈ E⟧ ⟹
      scale (smult a b) v = scale a (scale b v)"
    using base_subset by (blast intro: upper.scale_scale)
  show "⋀v. v ∈ E ⟹ scale sone v = v"
    by (rule upper.scale_one)
qed

text ‹Restricting the field changes the allowed coefficients, but not
the expression for a linear combination.›

lemma restricted_lincomb:
  "direct.lincomb c A = upper.lincomb c A"
  by (simp only: direct.lincomb_def)

definition product_basis :: "'s set ⇒ 'v set ⇒ 'v set"
  where "product_basis B C = (λ(b,c). scale b c) ` (B × C)"

lemma product_basis_finite:
  assumes "finite B" "finite C"
  shows "finite (product_basis B C)"
  using assms by (simp add: product_basis_def)

lemma product_basis_subset:
  assumes "B ⊆ F" "C ⊆ E"
  shows "product_basis B C ⊆ E"
  using assms unfolding product_basis_def by (auto intro: upper.scale_closed)

lemma product_basis_empty [simp]:
  "product_basis B {} = {}"
  by (simp add: product_basis_def)

lemma lower_basis_nonzero:
  assumes B: "lower.basis B" and b: "b ∈ B"
  shows "b ≠ szero"
proof
  assume "b = szero"
  have ind: "lower.lin_indep B" by (rule lower.basis_lin_indep[OF B])
  have "b ∉ lower.span (B - {b})"
    by (rule lower.lin_indep_not_in_span[OF ind b])
  moreover have "b ∈ lower.span (B - {b})"
    using ‹b = szero› lower.span_zero by simp
  ultimately show False by contradiction
qed

lemma upper_basis_scaled_unique:
  assumes C: "upper.basis C" and c: "c ∈ C" and d: "d ∈ C"
    and b: "b ∈ F" and e: "e ∈ F"
    and eq: "scale b c = scale e d"
  shows "b = (if c = d then e else szero)"
proof -
  have finC: "finite C" and CE: "C ⊆ E"
    using C by (auto simp: upper.basis_def)
  have ind: "upper.mod.lin_indep C"
    by (rule iffD1[OF upper.lin_indep_iff_mod_lin_indep[OF finC CE]
        upper.basis_lin_indep[OF C]])
  have cE: "c ∈ E" and dE: "d ∈ E" using CE c d by blast+
  have coeff_b: "upper.mod.coeffs_on (λ_. b) {c}"
    by (rule upper.mod.coeffs_onI) (simp add: b)
  have coeff_e: "upper.mod.coeffs_on (λ_. e) {d}"
    by (rule upper.mod.coeffs_onI) (simp add: e)
  have comb:
    "upper.mod.lincomb (λ_. b) {c} = upper.mod.lincomb (λ_. e) {d}"
    using eq by (simp add: cE dE b e)
  have "(if c ∈ {c} then b else szero) =
    (if c ∈ {d} then e else szero)"
    by (rule upper.mod.lin_indep_lincomb_unique_gen[OF ind _ _ _ _ coeff_b coeff_e comb])
      (use c d in auto)
  then show ?thesis by simp
qed

lemma product_basis_injective:
  assumes B: "lower.basis B" and C: "upper.basis C"
  shows "inj_on (λ(b,c). scale b c) (B × C)"
proof (rule inj_onI)
  fix x y
  assume x: "x ∈ B × C" and y: "y ∈ B × C"
    and eq: "(λ(b,c). scale b c) x = (λ(b,c). scale b c) y"
  obtain b c where x': "x = (b,c)" and b: "b ∈ B" and c: "c ∈ C"
    using x by (cases x) auto
  obtain e d where y': "y = (e,d)" and e: "e ∈ B" and d: "d ∈ C"
    using y by (cases y) auto
  have BF: "B ⊆ F" using B by (auto simp: lower.basis_def)
  have bF: "b ∈ F" and eF: "e ∈ F" using BF b e by blast+
  have scaled: "scale b c = scale e d" using eq x' y' by simp
  have unique: "b = (if c = d then e else szero)"
    by (rule upper_basis_scaled_unique[OF C c d bF eF scaled])
  have "c = d" using unique lower_basis_nonzero[OF B b] by (cases "c = d") auto
  then have "b = e" using unique by simp
  then show "x = y" using x' y' ‹c = d› by simp
qed

lemma scalar_lower_combination_in_product_span:
  assumes BF: "B ⊆ F" and CE: "C ⊆ E" and c: "c ∈ C"
    and fin: "finite T" and TB: "T ⊆ B"
    and coeff: "⋀b. b ∈ T ⟹ f b ∈ K"
  shows "scale (lower.lincomb f T) c ∈ direct.span (product_basis B C)"
proof -
  have PE: "product_basis B C ⊆ E" by (rule product_basis_subset[OF BF CE])
  have cE: "c ∈ E" using c CE by blast
  have step: "scale (lower.lincomb f U) c ∈ direct.span (product_basis B C)"
    if "finite U" "U ⊆ B" "∀b∈U. f b ∈ K" for U
    using that
  proof (induction U rule: finite_induct)
    case empty
    then show ?case
      by (simp add: upper.mod.scale_zero_scalar cE)
  next
    case (insert b U)
    have bF: "b ∈ F" and UF: "U ⊆ F"
      using insert.prems BF by auto
    have fK: "f b ∈ K" and fUK: "⋀x. x ∈ U ⟹ f x ∈ K"
      using insert.prems by auto
    have fF: "f b ∈ F" and fUF: "⋀x. x ∈ U ⟹ f x ∈ F"
      using fK fUK base_subset by blast+
    have tailF: "lower.lincomb f U ∈ F"
      by (rule lower.lincomb_closed[OF UF fUK])
    have termF: "smult (f b) b ∈ F"
      by (rule lower.scale_closed[OF fK bF])
    have termsU: "(λx. smult (f x) x) ∈ U → F"
      using UF fUK by (auto intro: lower.scale_closed)
    have split: "lower.lincomb f (insert b U) =
        sadd (smult (f b) b) (lower.lincomb f U)"
      using lower.vadd.fincomp_insert[OF insert.hyps(1,2) termsU termF]
      by (simp only: lower.lincomb_def)
    have base: "scale b c ∈ direct.span (product_basis B C)"
    proof (rule direct.span_incl[OF PE])
      show "scale b c ∈ product_basis B C"
        using insert.prems c by (auto simp: product_basis_def)
    qed
    have first: "scale (smult (f b) b) c ∈ direct.span (product_basis B C)"
      using direct.span_scale[OF PE fK base] upper.scale_scale[OF fF bF cE] by simp
    have rest: "scale (lower.lincomb f U) c ∈ direct.span (product_basis B C)"
      using insert.IH insert.prems by auto
    have "vadd (scale (smult (f b) b) c) (scale (lower.lincomb f U) c)
        ∈ direct.span (product_basis B C)"
      by (rule direct.span_vadd[OF PE first rest])
    then show ?case
      using upper.scale_distrib_add[OF termF tailF cE] by (simp only: split)
  qed
  show ?thesis by (rule step[OF fin TB]) (use coeff in blast)
qed

lemma fincomp_in_direct_span:
  assumes PE: "P ⊆ E" and fin: "finite A"
    and terms: "⋀a. a ∈ A ⟹ g a ∈ direct.span P"
  shows "upper.vadd.fincomp g A ∈ direct.span P"
  using fin terms
proof (induction A rule: finite_induct)
  case empty
  then show ?case by simp
next
  case (insert a A)
  have ga: "g a ∈ direct.span P" using insert.prems by simp
  have rest: "upper.vadd.fincomp g A ∈ direct.span P"
    using insert.IH insert.prems by blast
  have gE: "g ∈ insert a A → E"
    using insert.prems direct.span_subset_V[OF PE] by blast
  have "vadd (g a) (upper.vadd.fincomp g A) ∈ direct.span P"
    by (rule direct.span_vadd[OF PE ga rest])
  then show ?case using insert.hyps gE by simp
qed

lemma product_basis_spanning:
  assumes B: "lower.basis B" and C: "upper.basis C"
  shows "direct.spanning (product_basis B C)"
proof -
  have finB: "finite B" and BF: "B ⊆ F"
    using B by (auto simp: lower.basis_def)
  have finC: "finite C" and CE: "C ⊆ E"
    using C by (auto simp: upper.basis_def)
  have PE: "product_basis B C ⊆ E" by (rule product_basis_subset[OF BF CE])
  have finP: "finite (product_basis B C)" by (rule product_basis_finite[OF finB finC])
  have lower_span: "lower.spanning B" by (rule lower.basis_spanning[OF B])
  have upper_span: "upper.spanning C" by (rule upper.basis_spanning[OF C])
  have all_span: "x ∈ direct.span (product_basis B C)" if xE: "x ∈ E" for x
  proof -
    obtain d where d: "d ∈ C →E F" and x: "x = upper.lincomb d C"
      using upper_span xE by (auto simp: upper.spanning_def)
    have summand: "scale (d c) c ∈ direct.span (product_basis B C)" if c: "c ∈ C" for c
    proof -
      have dcF: "d c ∈ F" using d c by auto
      obtain f where f: "f ∈ B →E K" and dc: "d c = lower.lincomb f B"
        using lower_span dcF by (auto simp: lower.spanning_def)
      have "scale (lower.lincomb f B) c ∈ direct.span (product_basis B C)"
        by (rule scalar_lower_combination_in_product_span[OF BF CE c finB subset_refl])
          (use f in auto)
      then show ?thesis using dc by simp
    qed
    have "upper.vadd.fincomp (λc. scale (d c) c) C
        ∈ direct.span (product_basis B C)"
      by (rule fincomp_in_direct_span[OF PE finC summand])
    then show ?thesis using x by (simp add: upper.lincomb_def)
  qed
  have "direct.mod.spanning (product_basis B C)"
    by (rule direct.mod.spanningI[OF PE all_span])
  then show ?thesis
    using direct.spanning_iff_mod_spanning[OF finP PE] by blast
qed

lemma scale_lower_lincomb:
  assumes BF: "B ⊆ F" and cE: "c ∈ E"
    and fK: "⋀b. b ∈ B ⟹ f b ∈ K"
  shows "scale (lower.lincomb f B) c =
    upper.vadd.fincomp (λb. scale (smult (f b) b) c) B"
proof -
  have terms: "(λb. smult (f b) b) ∈ B → F"
    using BF fK by (auto intro: lower.scale_closed)
  have hom: "scale (lower.vadd.fincomp (λb. smult (f b) b) B) c =
      upper.vadd.fincomp (λb. scale (smult (f b) b) c) B"
  proof (rule fincomp_hom[OF lower.vadd.commutative_monoid_axioms
        upper.vadd.commutative_monoid_axioms])
    show "⋀x. x ∈ F ⟹ scale x c ∈ E"
      by (rule upper.scale_closed[OF _ cE])
    show "scale szero c = vzero" by (rule upper.mod.scale_zero_scalar[OF cE])
    show "⋀x y. ⟦x ∈ F; y ∈ F⟧ ⟹
        scale (sadd x y) c = vadd (scale x c) (scale y c)"
      by (rule upper.scale_distrib_add[OF _ _ cE])
    show "(λb. smult (f b) b) ∈ B → F" by (rule terms)
  qed
  show ?thesis using hom by (simp only: lower.lincomb_def)
qed

lemma vector_fincomp_cartesian:
  assumes finB: "finite B" and finC: "finite C"
    and gE: "⋀b c. ⟦b ∈ B; c ∈ C⟧ ⟹ g (b,c) ∈ E"
  shows "upper.vadd.fincomp g (B × C) =
    upper.vadd.fincomp (λc. upper.vadd.fincomp (λb. g (b,c)) B) C"
proof -
  have disjoint: "pairwise (λc d. disjnt (B × {c}) (B × {d})) C"
    by (auto simp: pairwise_def disjnt_def)
  have union: "(⋃c∈C. B × {c}) = B × C" by blast
  have split:
    "upper.vadd.fincomp g (B × C) =
      upper.vadd.fincomp (λc. upper.vadd.fincomp g (B × {c})) C"
    using upper.vadd.fincomp_UN_disjoint[OF finC _ disjoint, of g] finB gE union
    by auto
  have slice: "upper.vadd.fincomp g (B × {c}) =
      upper.vadd.fincomp (λb. g (b,c)) B" if c: "c ∈ C" for c
  proof -
    have image: "(λb. (b,c)) ` B = B × {c}" by auto
    have valid: "g ∈ ((λb. (b,c)) ` B) → E"
      using gE c by auto
    have injective: "inj_on (λb. (b,c)) B" by (auto simp: inj_on_def)
    show ?thesis using upper.vadd.fincomp_reindex[OF valid injective] image by simp
  qed
  show ?thesis using split slice
    by (intro trans[OF split] upper.vadd.fincomp_cong')
      (auto intro: upper.vadd.fincomp_closed gE)
qed

lemma product_lincomb_nested:
  assumes B: "lower.basis B" and C: "upper.basis C"
    and fK: "⋀v. v ∈ product_basis B C ⟹ f v ∈ K"
  shows "direct.lincomb f (product_basis B C) =
    upper.lincomb (λc. lower.lincomb (λb. f (scale b c)) B) C"
proof -
  have finB: "finite B" and BF: "B ⊆ F"
    using B by (auto simp: lower.basis_def)
  have finC: "finite C" and CE: "C ⊆ E"
    using C by (auto simp: upper.basis_def)
  have PE: "product_basis B C ⊆ E" by (rule product_basis_subset[OF BF CE])
  have fk: "f (scale b c) ∈ K" if b: "b ∈ B" and c: "c ∈ C" for b c
  proof (rule fK)
    show "scale b c ∈ product_basis B C" using b c by (auto simp: product_basis_def)
  qed
  have terms: "(λv. scale (f v) v) ∈ product_basis B C → E"
    using PE fK base_subset by (auto intro: upper.scale_closed)
  have inj: "inj_on (λ(b,c). scale b c) (B × C)"
    by (rule product_basis_injective[OF B C])
  have reindex: "upper.vadd.fincomp (λv. scale (f v) v) (product_basis B C) =
      upper.vadd.fincomp (λ(b,c). scale (f (scale b c)) (scale b c)) (B × C)"
    using upper.vadd.fincomp_reindex[OF terms[unfolded product_basis_def] inj]
    by (simp only: product_basis_def case_prod_unfold)
  have pairE: "scale (f (scale b c)) (scale b c) ∈ E"
    if "b ∈ B" "c ∈ C" for b c
    using BF CE base_subset fk[OF that] that by (auto intro: upper.scale_closed)
  have cart:
    "upper.vadd.fincomp (λ(b,c). scale (f (scale b c)) (scale b c)) (B × C) =
      upper.vadd.fincomp (λc. upper.vadd.fincomp
        (λb. scale (f (scale b c)) (scale b c)) B) C"
  proof -
    have pairE': "(λ(b,c). scale (f (scale b c)) (scale b c)) (b,c) ∈ E"
      if "b ∈ B" "c ∈ C" for b c
      using pairE[OF that] by simp
    note result = vector_fincomp_cartesian[where g="λ(b,c). scale (f (scale b c)) (scale b c)",
        OF finB finC pairE']
    show ?thesis using result by simp
  qed
  have inner:
    "upper.vadd.fincomp (λb. scale (f (scale b c)) (scale b c)) B =
      scale (lower.lincomb (λb. f (scale b c)) B) c"
    if c: "c ∈ C" for c
  proof -
    have cE: "c ∈ E" using CE c by blast
    have rightE: "(λb. scale (smult (f (scale b c)) b) c) ∈ B → E"
    proof
      fix b assume b: "b ∈ B"
      have bF: "b ∈ F" using BF b by blast
      have "smult (f (scale b c)) b ∈ F"
        by (rule lower.scale_closed[OF fk[OF b c] bF])
      then show "scale (smult (f (scale b c)) b) c ∈ E"
        by (rule upper.scale_closed[OF _ cE])
    qed
    have equal:
      "upper.vadd.fincomp (λb. scale (f (scale b c)) (scale b c)) B =
       upper.vadd.fincomp (λb. scale (smult (f (scale b c)) b) c) B"
    proof (rule upper.vadd.fincomp_cong'[OF refl rightE])
      fix b assume b: "b ∈ B"
      have fbF: "f (scale b c) ∈ F" using fk[OF b c] base_subset by blast
      have bF: "b ∈ F" using BF b by blast
      show "scale (f (scale b c)) (scale b c) = scale (smult (f (scale b c)) b) c"
        by (rule upper.scale_scale[OF fbF bF cE, symmetric])
    qed
    show ?thesis using equal scale_lower_lincomb[OF BF cE, of "λb. f (scale b c)"] fk c
      by simp
  qed
  have dF: "lower.lincomb (λb. f (scale b c)) B ∈ F" if "c ∈ C" for c
    by (rule lower.lincomb_closed[OF BF]) (use fk that in auto)
  have outer:
    "upper.vadd.fincomp (λc. upper.vadd.fincomp
        (λb. scale (f (scale b c)) (scale b c)) B) C =
      upper.vadd.fincomp (λc. scale (lower.lincomb (λb. f (scale b c)) B) c) C"
    by (rule upper.vadd.fincomp_cong'[OF refl])
      (use dF CE inner in ‹auto intro: upper.scale_closed›)
  have whole:
    "upper.vadd.fincomp (λv. scale (f v) v) (product_basis B C) =
     upper.vadd.fincomp (λc. scale (lower.lincomb (λb. f (scale b c)) B) c) C"
    by (rule trans[OF reindex], rule trans[OF cart outer])
  show ?thesis
    unfolding direct.lincomb_def upper.lincomb_def by (rule whole)
qed

lemma product_basis_independent:
  assumes B: "lower.basis B" and C: "upper.basis C"
  shows "direct.lin_indep (product_basis B C)"
proof -
  have finB: "finite B" and BF: "B ⊆ F"
    using B by (auto simp: lower.basis_def)
  have finC: "finite C" and CE: "C ⊆ E"
    using C by (auto simp: upper.basis_def)
  have PE: "product_basis B C ⊆ E" by (rule product_basis_subset[OF BF CE])
  have finP: "finite (product_basis B C)" by (rule product_basis_finite[OF finB finC])
  have lower_ind: "lower.lin_indep B" by (rule lower.basis_lin_indep[OF B])
  have upper_ind: "upper.lin_indep C" by (rule upper.basis_lin_indep[OF C])
  have zero_coeff:
    "∀v∈product_basis B C. f v = szero"
    if f: "f ∈ product_basis B C →E K"
      and zero: "direct.lincomb f (product_basis B C) = vzero" for f
  proof -
    define d where "d c = lower.lincomb (λb. f (scale b c)) B" for c
    have fk: "f (scale b c) ∈ K" if b: "b ∈ B" and c: "c ∈ C" for b c
      using f b c by (auto simp: product_basis_def)
    have dF: "d c ∈ F" if c: "c ∈ C" for c
      unfolding d_def by (rule lower.lincomb_closed[OF BF]) (use fk c in auto)
    have dPi: "restrict d C ∈ C →E F" using dF by auto
    have fkp: "⋀v. v ∈ product_basis B C ⟹ f v ∈ K"
      using f by auto
    have nested: "direct.lincomb f (product_basis B C) =
        upper.lincomb (λc. lower.lincomb (λb. f (scale b c)) B) C"
      by (rule product_lincomb_nested[OF B C fkp])
    have d_eq: "d = (λc. lower.lincomb (λb. f (scale b c)) B)"
      by (rule ext) (simp only: d_def)
    have combine: "upper.lincomb d C = vzero"
      using nested zero by (simp only: d_eq)
    have combine_restrict: "upper.lincomb (restrict d C) C = vzero"
    proof -
      have "upper.lincomb (restrict d C) C = upper.lincomb d C"
        by (rule upper.lincomb_cong[OF CE]) (use dF in auto)
      then show ?thesis using combine by simp
    qed
    have dzero: "d c = szero" if c: "c ∈ C" for c
    proof -
      have "restrict d C c = szero"
        using upper_ind dPi combine_restrict c unfolding upper.lin_indep_def by blast
      then show ?thesis using c by simp
    qed
    have fzero: "f (scale b c) = szero" if b: "b ∈ B" and c: "c ∈ C" for b c
    proof -
      define h where "h = (λb. f (scale b c))"
      have hK: "⋀b. b ∈ B ⟹ h b ∈ K"
        using fk c by (simp add: h_def)
      have hPi: "restrict h B ∈ B →E K" using hK by auto
      have comb0: "lower.lincomb (restrict h B) B = szero"
      proof -
        have "lower.lincomb (restrict h B) B = lower.lincomb h B"
          by (rule lower.lincomb_cong[OF BF]) (use hK in auto)
        then show ?thesis using dzero[OF c] by (simp add: d_def h_def)
      qed
      have "restrict h B b = szero"
        using lower_ind hPi comb0 b unfolding lower.lin_indep_def by blast
      then show ?thesis using b by (simp add: h_def)
    qed
    show ?thesis using fzero by (auto simp: product_basis_def)
  qed
  show ?thesis unfolding direct.lin_indep_def using finP PE zero_coeff by blast
qed

theorem product_basis:
  assumes B: "lower.basis B" and C: "upper.basis C"
  shows "direct.basis (product_basis B C)"
proof (rule direct.basisI)
  show "direct.spanning (product_basis B C)"
    by (rule product_basis_spanning[OF B C])
  show "direct.lin_indep (product_basis B C)"
    by (rule product_basis_independent[OF B C])
qed

lemma product_basis_in_direct_span:
  assumes B: "lower.basis B" and C: "upper.basis C"
    and b: "b ∈ B" and c: "c ∈ C"
  shows "scale b c ∈ direct.span (product_basis B C)"
proof -
  have BF: "B ⊆ F" and CE: "C ⊆ E"
    using B C by (auto simp: lower.basis_def upper.basis_def)
  have "scale b c ∈ product_basis B C"
    using b c by (auto simp: product_basis_def)
  then show ?thesis
    by (rule direct.span_incl[OF product_basis_subset[OF BF CE]])
qed

text ‹Cardinality uniqueness turns a product basis into the dimension
formula.›

lemma dimension_from_product_basis:
  assumes B: "lower.basis B" and C: "upper.basis C"
    and P: "direct.basis (product_basis B C)"
    and inj: "inj_on (λ(b,c). scale b c) (B × C)"
  shows "direct.dimension = lower.dimension * upper.dimension"
proof -
  have cardP: "card (product_basis B C) = card B * card C"
    unfolding product_basis_def
    by (simp add: card_image[OF inj] card_cartesian_product)
  have "direct.dimension = card (product_basis B C)"
    by (rule direct.dimension_eq_any_field[OF P])
  also have "… = card B * card C" by (rule cardP)
  also have "… = lower.dimension * upper.dimension"
    using lower.dimension_eq_any_field[OF B] upper.dimension_eq_any_field[OF C]
    by simp
  finally show ?thesis .
qed

theorem finite_dimension_tower:
  assumes lower_finite: "∃B. lower.basis B"
    and upper_finite: "∃C. upper.basis C"
  shows "∃P. direct.basis P"
    and "direct.dimension = lower.dimension * upper.dimension"
proof -
  obtain B where B: "lower.basis B" using lower_finite by blast
  obtain C where C: "upper.basis C" using upper_finite by blast
  have P: "direct.basis (product_basis B C)" by (rule product_basis[OF B C])
  show "∃P. direct.basis P" using P by blast
  show "direct.dimension = lower.dimension * upper.dimension"
    by (rule dimension_from_product_basis[OF B C P product_basis_injective[OF B C]])
qed

text ‹The zero space has an empty basis over either field.  This case
must not be excluded by an index type or by requiring the upper carrier to be
a field.›

lemma zero_space_tower:
  assumes "E = {vzero}"
  shows "direct.basis {}" "upper.basis {}"
    and "direct.dimension = lower.dimension * upper.dimension"
proof -
  show D: "direct.basis {}" by (rule direct.basis_empty_trivial[OF assms])
  show U: "upper.basis {}" by (rule upper.basis_empty_trivial[OF assms])
  have "direct.dimension = 0"
    using direct.dimension_eq_any_field[OF D] by simp
  moreover have "upper.dimension = 0"
    using upper.dimension_eq_any_field[OF U] by simp
  ultimately show "direct.dimension = lower.dimension * upper.dimension" by simp
qed

end

end