Theory Axioms_Quantum

section ‹Quantum instantiation of registers›

(* AXIOM INSTANTIATION (use instantiate_laws.py to generate Laws_Quantum.thy)

    # Type classes
    domain → type
    domain_with_simple_complement → finite

    # Types
    some_domain → unit

    # Constants
    comp_update → cblinfun_compose
    id_update → id_cblinfun
    tensor_update → tensor_op
    cdc → register_decomposition_basis

    # Lemmas
    id_update_left → cblinfun_compose_id_left
    id_update_right → cblinfun_compose_id_right
    comp_update_assoc → cblinfun_compose_assoc
    tensor_update_mult → comp_tensor_op

    # Chapter name
    Generic laws about registers → Generic laws about registers, instantiated quantumly
    Generic laws about complements → Generic laws about complements, instantiated quantumly
*)

theory Axioms_Quantum
  imports Jordan_Normal_Form.Matrix_Impl "HOL-Library.Rewrite"
          Complex_Bounded_Operators.Complex_L2
          Hilbert_Space_Tensor_Product.Hilbert_Space_Tensor_Product
          Hilbert_Space_Tensor_Product.Weak_Star_Topology
          Hilbert_Space_Tensor_Product.Partial_Trace
          Hilbert_Space_Tensor_Product.Von_Neumann_Algebras
          With_Type.With_Type
          Misc
begin


unbundle cblinfun_syntax
unbundle no m_inv_syntax


type_synonym 'a update = ('a ell2, 'a ell2) cblinfun

definition preregister :: ('a update  'b update)  bool where
  preregister F  bounded_clinear F  continuous_map weak_star_topology weak_star_topology F

lemma preregister_mult_right: preregister (λa. a oCL z)
  by (auto simp add: bounded_cbilinear.bounded_clinear_left bounded_cbilinear_cblinfun_compose
      preregister_def continuous_map_right_comp_weak_star)

lemma preregister_mult_left: preregister (λa. z oCL a)
  by (auto simp add: bounded_cbilinear.bounded_clinear_right bounded_cbilinear_cblinfun_compose
      preregister_def continuous_map_left_comp_weak_star)

lemma comp_preregister: "preregister F  preregister G  preregister (G  F)"
  by (auto simp add: preregister_def continuous_map_compose comp_bounded_clinear)

lemma id_preregister: preregister id
  unfolding preregister_def by auto

lemma tensor_extensionality:
  preregister F  preregister G  (a b. F (tensor_op a b) = G (tensor_op a b))  F = G
  apply (rule weak_star_clinear_eq_butterfly_ketI)
  by (auto intro!: bounded_clinear.clinear simp: preregister_def simp flip: tensor_ell2_ket tensor_butterfly)

definition register :: ('a update  'b update)  bool where
  "register F  
     bounded_clinear F
    continuous_map weak_star_topology weak_star_topology F
    F id_cblinfun = id_cblinfun 
    (a b. F(a oCL b) = F a oCL F b)
    (a. F (a*) = (F a)*)"

lemma register_of_id: register F  F id_cblinfun = id_cblinfun
  by (simp add: register_def)

lemma register_id: register id
  by (simp add: register_def complex_vector.module_hom_id)

lemma register_preregister: "register F  preregister F"
  unfolding register_def preregister_def by auto

lemma register_comp: "register F  register G  register (G  F)"
  using bounded_clinear_compose continuous_map_compose
  apply (simp add: o_def register_def)
  by blast

lemma register_mult: "register F  cblinfun_compose (F a) (F b) = F (cblinfun_compose a b)"
  unfolding register_def
  by auto

lemma register_tensor_left: register (λa. tensor_op a id_cblinfun)
  by (auto simp add: comp_tensor_op register_def tensor_op_cbilinear tensor_op_adjoint
      intro!: tensor_op_cbilinear.bounded_clinear_left)

lemma register_tensor_right: register (λa. tensor_op id_cblinfun a)
  by (auto simp add: comp_tensor_op register_def tensor_op_cbilinear tensor_op_adjoint
      bounded_cbilinear_apply_bounded_clinear tensor_op_bounded_cbilinear)

definition register_pair ::
  ('a update  'c update)  ('b update  'c update)
          (('a×'b) update  'c update) where
  register_pair F G = (if register F  register G  (a b. F a oCL G b = G b oCL F a) then 
                        SOME R. (a b. register R  R (a o b) = F a oCL G b) else (λ_. 0))

lemma cbilinear_F_comp_G[simp]: clinear F  clinear G  cbilinear (λa b. F a oCL G b)
  unfolding cbilinear_def
  by (auto simp add: clinear_iff bounded_cbilinear.add_left bounded_cbilinear_cblinfun_compose bounded_cbilinear.add_right)

lemma register_projector:
  assumes "register F"
  assumes "is_Proj a"
  shows "is_Proj (F a)"
  using assms unfolding register_def is_Proj_algebraic by metis

lemma register_unitary:
  assumes "register F"
  assumes "unitary a"
  shows "unitary (F a)"
  using assms by (smt (verit, best) register_def unitary_def)

definition register_decomposition_basis Φ = (SOME B. is_ortho_set B  (bB. norm b = 1)  ccspan B = Φ (butterfly (ket undefined) (ket undefined)) *S ) 
  for Φ :: 'a update  'b update

lemma register_decomposition:
  fixes Φ :: 'a update  'b update
  assumes [simp]: register Φ
  shows let 'c::type = register_decomposition_basis Φ in
         (U :: ('a × 'c) ell2 CL 'b ell2. unitary U  
              (θ. Φ θ = sandwich U (θ o id_cblinfun)))
  ― ‹Proof based on @{cite daws21unitalanswer}
proof with_type_intro
  (* note [[simproc del: compatibility_warn]] *)
  define ξ0 :: 'a where ξ0 = undefined

  have bounded_clinear Φ
    using assms register_def by blast
  then have [simp]: clinear Φ
    by (simp add: bounded_clinear.clinear)

  define P where P i = butterfly (ket i) (ket i) for i :: 'a

  note blinfun_cblinfun_eq_bi_unique[transfer_rule del]
  note cblinfun.bi_unique[transfer_rule del]
  note cblinfun.left_unique[transfer_rule del]
  note cblinfun.right_unique[transfer_rule del]
  note cblinfun.right_total[transfer_rule del]
  note id_cblinfun.transfer[transfer_rule del]

  define P' where P' i = Φ (P i) for i :: 'a
  have proj_P': is_Proj (P' i) for i
    by (simp add: P_def P'_def butterfly_is_Proj register_projector)
  have sumP'id2: has_sum_in weak_star_topology (λi. P' i) UNIV id_cblinfun
  proof -
    from has_sum_butterfly_ket
    have has_sum_in weak_star_topology (Φ o (λx. butterfly (ket x) (ket x))) UNIV (Φ id_cblinfun)
      apply (rule has_sum_in_comm_additive[rotated -1])
      using assms 
      by (auto simp: complex_vector.linear_add register_def Modules.additive_def 
          intro!: continuous_map_is_continuous_at_point complex_vector.linear_0 clinear Φ)
    then show ?thesis
      by (simp add: P'_def P_def o_def register_of_id)
  qed
  define S where S i = P' i *S  for i :: 'a
  have P'id: P' i *V ψ = ψ if ψ  space_as_set (S i) for i ψ
    using S_def that proj_P'
    by (metis cblinfun_fixes_range is_Proj_algebraic)

  define S_iso' :: 'a  'a  'a update where S_iso' i j = classical_operator (Some o Transposition.transpose i j) for i j :: 'a
  have S_iso'_apply: S_iso' i j *V ket i = ket j for i j
    by (simp add: S_iso'_def classical_operator_ket classical_operator_exists_inj)
  have S_iso'_unitary: unitary (S_iso' i j) for i j
    by (simp add: S_iso'_def unitary_classical_operator)
  have S_iso'_id: S_iso' i i = id_cblinfun for i
    by (auto intro!: equal_ket simp: S_iso'_def classical_operator_ket classical_operator_exists_inj)
  have S_iso'_adj_apply: (S_iso' i j)* *V ket j = ket i for i j
    by (metis S_iso'_apply S_iso'_unitary cblinfun_apply_cblinfun_compose id_cblinfun_apply unitaryD1)
  define S_iso where S_iso i j = Φ (S_iso' i j) for i j
  have uni_S_iso: unitary (S_iso i j) for i j
    by (simp add: S_iso_def S_iso'_unitary register_unitary)
  have S_iso_S: S_iso i j *S S i = S j for i j
  proof -
    have S_iso i j *S S i = S_iso i j *S P' i *S S_iso j i *S 
      by (simp add: S_def uni_S_iso)
    also have  = S j
      by (simp add: S_def P'_def S_iso_def P_def register_mult butterfly_comp_cblinfun cblinfun_comp_butterfly S_iso'_apply S_iso'_adj_apply
        flip: cblinfun_compose_image)
    finally show ?thesis
      by -
  qed
  have S_iso_id[simp]: S_iso i i = id_cblinfun for i
    by (simp add: S_iso'_id S_iso_def register_of_id)

  obtain B0 where B0: is_ortho_set B0 b. b  B0  norm b = 1 ccspan B0 = S ξ0
    using orthonormal_subspace_basis_exists[where S="{}" and V=S ξ0]
    apply atomize_elim by auto

  have register_decomposition_basis_Φ: is_ortho_set (register_decomposition_basis Φ) 
       (bregister_decomposition_basis Φ. norm b = 1) 
       ccspan (register_decomposition_basis Φ) = S ξ0
    unfolding register_decomposition_basis_def
    apply (rule someI2[where a=B0])
    using B0 by (auto simp: S_def P'_def P_def ξ0_def)

  define B where B i = S_iso ξ0 i ` register_decomposition_basis Φ for i
  have Bξ0: B ξ0 = register_decomposition_basis Φ
    using B_def by force
  have orthoB: is_ortho_set (B i) for i
  proof -
    have 1: x  register_decomposition_basis Φ 
           y  register_decomposition_basis Φ 
           S_iso ξ0 i *V x  S_iso ξ0 i *V y  is_orthogonal (S_iso ξ0 i *V x) (S_iso ξ0 i *V y) for x y
      by (metis (no_types, lifting) register_decomposition_basis_Φ UNIV_I cblinfun_apply_cblinfun_compose cblinfun_fixes_range cinner_adj_left id_cblinfun_adjoint is_ortho_set_def top_ccsubspace.rep_eq uni_S_iso unitaryD1 unitary_id unitary_range)
    have 2: x  register_decomposition_basis Φ  S_iso ξ0 i *V x  0 for x
      by (metis register_decomposition_basis_Φ cinner_ket_same cinner_zero_left cnorm_eq_1 isometry_preserves_norm orthogonal_ket uni_S_iso unitary_isometry)
    from 1 2 show ?thesis
      by (auto simp add: B_def is_ortho_set_def)
  qed
  have normalB: b. b  B i  norm b = 1 for i
    by (metis (no_types, lifting) register_decomposition_basis_Φ B_def imageE isometry_preserves_norm uni_S_iso unitary_twosided_isometry)
  have cspanB: ccspan (B i) = S i for i
    by (simp add: B_def register_decomposition_basis_Φ Bξ0 S_iso_S flip: cblinfun_image_ccspan)

  from orthoB have indepB: cindependent (B i) for i
    by (simp add: Complex_Inner_Product.is_ortho_set_cindependent)

  have orthoBiBj: is_orthogonal x y if x  B i and y  B j and i  j for x y i j
  proof -
    have P' i oCL P' j = 0
      using i  j
      by (simp add: P'_def P_def register_mult butterfly_comp_butterfly cinner_ket
          clinear Φ complex_vector.linear_0)
    then have *: Proj (ccspan (B i)) oCL Proj (ccspan (B j)) = 0
      by (simp add: Proj_on_own_range S_def cspanB proj_P')
    then show is_orthogonal x y
      by (meson orthogonal_projectors_orthogonal_spaces orthogonal_spaces_ccspan that(1) that(2))
  qed

  define B' where B' = (iUNIV. B i)

  have P'B: P' i = Proj (ccspan (B i)) for i
    unfolding cspanB S_def
    using proj_P' Proj_on_own_range'[symmetric] is_Proj_algebraic by blast

  show register_decomposition_basis Φ  {}
  proof (rule ccontr)
    assume ¬ register_decomposition_basis Φ  {}
    then have B i = {} for i
      by (simp add: B_def)
    then have S i = 0 for i
      using cspanB by force
    then have P' i = 0 for i
      by (simp add: P'B cspanB)
    with sumP'id2
    have has_sum_in weak_star_topology (λi. 0) UNIV id_cblinfun
      by (metis (no_types, lifting) UNIV_I has_sum_in_0 has_sum_in_cong has_sum_in_unique hausdorff_weak_star id_cblinfun_not_0 weak_star_topology_topspace)
    then have id_cblinfun = 0
      using has_sum_in_0 has_sum_in_unique hausdorff_weak_star id_cblinfun_not_0 weak_star_topology_topspace by fast
    then show False
      using id_cblinfun_not_0 by blast
  qed

  from orthoBiBj orthoB have orthoB': is_ortho_set B'
    unfolding B'_def is_ortho_set_def by blast
  then have indepB': cindependent B'
    using is_ortho_set_cindependent by blast

  from orthoBiBj orthoB
  have Bdisj: B i  B j = {} if i  j for i j
    unfolding is_ortho_set_def
    using cinner_eq_zero_iff that
    by fastforce

  fix rep_c :: 'c  'b ell2
  assume bij_rep_c: bij_betw rep_c UNIV (register_decomposition_basis Φ)
  then interpret type_definition rep_c inv rep_c register_decomposition_basis Φ
    by (simp add: type_definition_bij_betw_iff)

  from bij_rep_c have bij_rep_c: bij_betw rep_c (UNIV :: 'c set) (B ξ0)
    unfolding Bξ0 by simp

  define u where u = (λ(ξ,α). Φ (butterfly (ket ξ) (ket ξ0)) *V rep_c α) for ξ :: 'a and α :: 'c

  have cinner_u: cinner (u ξα) (u ξ'α') = of_bool (ξα = ξ'α') for ξα ξ'α'
  proof -
    obtain ξ α ξ' α' where ξα: ξα = (ξ,α) and ξ'α': ξ'α' = (ξ',α')
      apply atomize_elim by auto
    have cinner (u (ξ,α)) (u (ξ', α')) = cinner (Φ (butterfly (ket ξ) (ket ξ0)) *V rep_c α) (Φ (butterfly (ket ξ') (ket ξ0)) *V rep_c α')
      unfolding u_def by simp
    also have  = cinner ((Φ (butterfly (ket ξ') (ket ξ0)))* *V Φ (butterfly (ket ξ) (ket ξ0)) *V rep_c α) (rep_c α')
      by (simp add: cinner_adj_left)
    also have  = cinner (Φ (butterfly (ket ξ') (ket ξ0) *) *V Φ (butterfly (ket ξ) (ket ξ0)) *V rep_c α) (rep_c α')
      by (metis (no_types, lifting) assms register_def)
    also have  = cinner (Φ (butterfly (ket ξ0) (ket ξ') oCL butterfly (ket ξ) (ket ξ0)) *V rep_c α) (rep_c α')
      by (simp add: register_mult cblinfun_apply_cblinfun_compose[symmetric])
    also have  = cinner (Φ (of_bool (ξ'=ξ) *C butterfly (ket ξ0) (ket ξ0)) *V rep_c α) (rep_c α')
      by (simp add: cinner_ket_left ket.rep_eq)
    also have  = of_bool (ξ'=ξ) * cinner (Φ (butterfly (ket ξ0) (ket ξ0)) *V rep_c α) (rep_c α')
      by (simp add: complex_vector.linear_0)
    also have  = of_bool (ξ'=ξ) * cinner (P' ξ0 *V rep_c α) (rep_c α')
      using P_def P'_def by simp
    also have  = of_bool (ξ'=ξ) * cinner (rep_c α) (rep_c α')
      apply (subst P'id)
      apply (metis Bξ0 Rep ccspan_superset cspanB in_mono)
      by simp
    also have  = of_bool (ξ'=ξ) * of_bool (α=α')
      using bij_rep_c orthoB normalB unfolding is_ortho_set_def
      by (smt (verit, best) Bξ0 Rep Rep_inject cnorm_eq_1 of_bool_eq(1) of_bool_eq(2))
    finally show ?thesis
      by (simp add: ξ'α' ξα)
  qed
  define U where U = cblinfun_extension (range ket) (u o inv ket)
  have Uapply: U *V ket ξα = u ξα for ξα
  proof -
    have aux: (a b aa ba. u (a, b) C u (aa, ba) = of_bool (a = aa  b = ba))  norm (u (a, b))  1 for a b
      by (metis (full_types) cinner_u cnorm_eq_1 of_bool_eq_1_iff order_refl)
    then show ?thesis
      unfolding U_def
      apply (subst cblinfun_extension_apply)
      using cinner_u by (auto intro!: cblinfun_extension_exists_ortho[where B=1])
  qed
  have isometry U
    apply (rule_tac orthogonal_on_basis_is_isometry[where B=range ket])
    by (auto simp: Uapply cinner_u)
  
  have 1: U* oCL Φ θ oCL U = θ o id_cblinfun for θ
  proof -
    have *: U* oCL Φ (butterfly (ket ξ) (ket η)) oCL U = butterfly (ket ξ) (ket η) o id_cblinfun for ξ η
    proof (rule equal_ket, rename_tac ξ1α)
      fix ξ1α obtain ξ1 :: 'a and α :: 'c where ξ1α: ξ1α = (ξ1,α) 
        apply atomize_elim by auto
      have (U* oCL Φ (butterfly (ket ξ) (ket η)) oCL U) *V ket ξ1α = U* *V Φ (butterfly (ket ξ) (ket η)) *V Φ (butterfly (ket ξ1) (ket ξ0)) *V rep_c α
        unfolding cblinfun_apply_cblinfun_compose ξ1α Uapply u_def by simp
      also have  = U* *V Φ (butterfly (ket ξ) (ket η) oCL butterfly (ket ξ1) (ket ξ0)) *V rep_c α
         by (metis assms register_mult simp_a_oCL_b')
      also have  = U* *V Φ (of_bool (η=ξ1) *C butterfly (ket ξ) (ket ξ0)) *V rep_c α
        by (simp add: cinner_ket)
      also have  = of_bool (η=ξ1) *C U* *V Φ (butterfly (ket ξ) (ket ξ0)) *V rep_c α
        by (simp add: complex_vector.linear_scale)
      also have  = of_bool (η=ξ1) *C U* *V U *V ket (ξ, α)
        unfolding Uapply u_def by simp
      also from isometry U have  = of_bool (η=ξ1) *C ket (ξ, α)
        unfolding cblinfun_apply_cblinfun_compose[symmetric] by simp
      also have  = (butterfly (ket ξ) (ket η) *V ket ξ1) s ket α
        by (simp add: tensor_ell2_scaleC1 tensor_ell2_ket)
      also have  = (butterfly (ket ξ) (ket η) o id_cblinfun) *V ket ξ1α
        by (simp add: ξ1α tensor_op_ket)
      finally show (U* oCL Φ (butterfly (ket ξ) (ket η)) oCL U) *V ket ξ1α = (butterfly (ket ξ) (ket η) o id_cblinfun) *V ket ξ1α
        by -
    qed

    have cont1: continuous_map weak_star_topology weak_star_topology (λa. U* oCL Φ a oCL U)
      apply (subst asm_rl[of (λa. U* oCL Φ a oCL U) = (λx. x oCL U) o (λx. U* oCL x) o Φ])
       apply force
      apply (intro continuous_map_compose[where X'=weak_star_topology])
      using assms register_def continuous_map_left_comp_weak_star continuous_map_right_comp_weak_star by blast+

    have *: U* oCL Φ θ oCL U = θ o id_cblinfun if θ  cspan (range (λ(ξ, η). butterfly (ket ξ) (ket η))) for θ
      apply (rule complex_vector.linear_eq_on[where x=θ, OF _ _ that])
        apply (intro clinear Φ
          clinear_compose[OF _ clinear_cblinfun_compose_left, unfolded o_def]
          clinear_compose[OF _ clinear_cblinfun_compose_right, unfolded o_def])
       apply simp
      using * by fast
    have U* oCL Φ θ oCL U = θ o id_cblinfun 
      if θ  (weak_star_topology closure_of (cspan (range (λ(ξ, η). butterfly (ket ξ) (ket η))))) for θ
      apply (rule closure_of_eqI[OF _ _ that])
      using * cont1 left_amplification_weak_star_cont by auto
    with butterkets_weak_star_dense show ?thesis
      by auto
  qed
  have unitary U
  proof -
    have Φ (butterfly (ket ξ) (ket ξ1)) *S   U *S  for ξ ξ1
    proof -
      have *: Φ (butterfly (ket ξ) (ket ξ0)) *V b  space_as_set (U *S ) if b  B ξ0 for b
        apply (subst asm_rl[of Φ (butterfly (ket ξ) (ket ξ0)) *V b = u (ξ, inv rep_c b)])
         apply (simp add: u_def, metis bij_betw_inv_into_right bij_rep_c that)
        by (metis Uapply cblinfun_apply_in_image)

      have Φ (butterfly (ket ξ) (ket ξ1)) *S  = Φ (butterfly (ket ξ) (ket ξ0)) *S Φ (butterfly (ket ξ0) (ket ξ0)) *S Φ (butterfly (ket ξ0) (ket ξ1)) *S 
        unfolding cblinfun_compose_image[symmetric] register_mult[OF assms]
        by simp
      also have   Φ (butterfly (ket ξ) (ket ξ0)) *S Φ (butterfly (ket ξ0) (ket ξ0)) *S 
        by (meson cblinfun_image_mono top_greatest)
      also have  = Φ (butterfly (ket ξ) (ket ξ0)) *S S ξ0
        by (simp add: S_def P'_def P_def)
      also have  = Φ (butterfly (ket ξ) (ket ξ0)) *S ccspan (B ξ0)
        by (simp add: cspanB)
      also have  = ccspan (Φ (butterfly (ket ξ) (ket ξ0)) ` B ξ0)
        by (meson cblinfun_image_ccspan)
      also have   U *S 
        by (rule ccspan_leqI, use * in auto)
      finally show ?thesis by -
    qed
    then have ccspan {Φ (butterfly (ket ξ) (ket ξ)) *V α |ξ α. True}  U *S 
      apply (rule_tac ccspan_leqI)
      using cblinfun_apply_in_image less_eq_ccsubspace.rep_eq by blast
    moreover have ccspan {Φ (butterfly (ket ξ) (ket ξ)) *V α |ξ α. True} = 
    proof -
      define Q where Q = Proj (- ccspan {Φ (butterfly (ket ξ) (ket ξ)) *V α |ξ α. True})
      have has_sum_in weak_star_topology (λξ. Q oCL Φ (butterfly (ket ξ) (ket ξ))) UNIV (Q oCL id_cblinfun)
        apply (rule has_sum_in_comm_additive[where g=cblinfun_compose Q and T=weak_star_topology, unfolded o_def])
        using sumP'id2
        by (auto simp add: continuous_map_left_comp_weak_star P'_def P_def cblinfun_compose_add_right Modules.additive_def)
      moreover have Q oCL Φ (butterfly (ket ξ) (ket ξ)) = 0 for ξ
        apply (rule equal_ket)
        apply (simp add: Q_def Proj_ortho_compl cblinfun.diff_left)
        apply (subst Proj_fixes_image)
        by (auto intro!: ccspan_superset[THEN set_mp])
      ultimately have Q = 0
        apply (rule_tac has_sum_in_unique)
        by auto
      then show ?thesis
        by (smt (verit, del_insts) Q_def Proj_ortho_compl Proj_range cblinfun_image_id right_minus_eq)
    qed
    ultimately have U *S  = 
      by (simp add: top.extremum_unique)
    with isometry U show unitary U
      by (rule surj_isometry_is_unitary)
  qed

  have Φ θ = U oCL (θ o id_cblinfun) oCL U* for θ
  proof -
    from unitary U
    have Φ θ = (U oCL U*) oCL Φ θ oCL (U oCL U*)
      by simp
    also have  = U oCL (U*  oCL Φ θ oCL U) oCL U*
      by (simp add: cblinfun_assoc_left)
    also have  = U oCL (θ o id_cblinfun) oCL U*
      using 1 by simp
    finally show ?thesis
      by -
  qed

  with unitary U show U :: ('a × 'c) ell2 CL 'b ell2. unitary U  (θ. Φ θ = sandwich U (θ o id_cblinfun))
    by (auto simp: sandwich_apply)
qed

lemma register_bounded_clinear: register F  bounded_clinear F
  using preregister_def register_preregister by blast

lemma clinear_register: register F  clinear F
  using bounded_clinear.clinear register_bounded_clinear by blast

lemma weak_star_cont_register: register F  continuous_map weak_star_topology weak_star_topology F
  using register_def by blast

lemma register_inv_weak_star_continuous:
  assumes register F
  shows continuous_map (subtopology weak_star_topology (range F)) weak_star_topology (inv F)
proof (rule continuous_map_iff_preserves_convergence, rename_tac K a)
  fix K a
  assume limit_id: limitin (subtopology weak_star_topology (range F)) id a K
  from register_decomposition
  have let 'c::type = register_decomposition_basis F in
        limitin weak_star_topology (inv F) (inv F a) K
  proof with_type_mp
    from assms show register F by -
  next
    with_type_case
    then obtain U :: ('a × 'c) ell2 CL 'b ell2 
      where unitary U and FU: F θ = sandwich U (θ o id_cblinfun) for θ
      by auto
    define δ :: 'c ell2 CL 'c ell2 where δ = selfbutter (ket (undefined))
    then have [simp]: trace_class δ
      by simp
    define u where u t = U oCL (from_trace_class t o δ) oCL U* for t
    have [simp]: trace_class (u t) for t
      unfolding u_def
      apply (rule trace_class_comp_left)
      apply (rule trace_class_comp_right)
      by (simp add: trace_class_tensor)
    have uF: trace (from_trace_class t oCL a) = trace (u t oCL F a) for t a 
    proof -
      have trace (from_trace_class t oCL a) = trace (from_trace_class t oCL a) * trace (δ oCL id_cblinfun)
        by (simp add: δ_def trace_butterfly)
      also have  = trace ((from_trace_class t oCL a) o (δ oCL id_cblinfun))
        by (simp add: trace_class_comp_left trace_tensor)
      also have  = trace ((from_trace_class t o δ) oCL (a o id_cblinfun))
        by (simp add: comp_tensor_op)
      also have  = trace (U* oCL u t oCL U oCL (a o id_cblinfun))
        using unitary U
        by (simp add: u_def lift_cblinfun_comp[OF unitaryD1] cblinfun_compose_assoc)
      also have  = trace (u t oCL U oCL (a o id_cblinfun) oCL U*)
        apply (subst (2) circularity_of_trace)
        by (simp_all add: trace_class_comp_left cblinfun_compose_assoc)
      also have  = trace (u t oCL F a)
        by (simp add: sandwich_apply FU cblinfun_compose_assoc)
      finally show ?thesis
        by -
    qed
    from limit_id
    have a  range F and KrangeF: F a in K. a  range F and limit_id': limitin weak_star_topology id a K
      unfolding limitin_subtopology by auto
    from a  range F have FiFa: F (inv F a) = a
      by (simp add: f_inv_into_f)
    from KrangeF
    have *: F x in K. trace (from_trace_class t oCL F (inv F x)) = trace (from_trace_class t oCL x) for t
      apply (rule eventually_mono)
      by (simp add: f_inv_into_f)
    from limit_id' have ((λa'. trace (from_trace_class t oCL a'))  trace (from_trace_class t oCL a)) K for t
      unfolding limitin_weak_star_topology' by simp
    then have *: ((λa'. trace (from_trace_class t oCL F (inv F a')))  trace (from_trace_class t oCL F (inv F a))) K for t
      unfolding FiFa using * by (rule tendsto_cong[THEN iffD2, rotated])
    have ((λa'. trace (u t oCL F (inv F a')))  trace (u t oCL F (inv F a))) K for t
      using *[of Abs_trace_class (u t)]
      by (simp add: Abs_trace_class_inverse)
    then have ((λa'. trace (from_trace_class t oCL inv F a'))  trace (from_trace_class t oCL inv F a)) K for t
      by (simp add: uF[symmetric])
    then show limitin weak_star_topology (inv F) (inv F a) K
      by (simp add: limitin_weak_star_topology')
  qed
  note this[cancel_with_type]
  then show limitin weak_star_topology (inv F) (inv F a) K
    by -
qed

lemma register_inj: inj_on F X if [simp]: register F
proof -
  have let 'c::type = register_decomposition_basis F in inj F
    using register_decomposition[OF register F] 
  proof with_type_mp
    with_type_case
    then obtain U :: ('a × 'c) ell2 CL 'b ell2
      where unitary U and F: F a = Complex_Bounded_Linear_Function.sandwich U (a o id_cblinfun) for a
      apply atomize_elim by auto
    have inj (Complex_Bounded_Linear_Function.sandwich U)
      by (smt (verit, best) unitary U cblinfun_assoc_left inj_onI sandwich_apply cblinfun_compose_id_right cblinfun_compose_id_left unitary_def)
    moreover have inj (λa::'a ell2 CL _. a o id_cblinfun)
      by (rule inj_tensor_left, simp)
    ultimately show inj F
      unfolding F
      by (smt (z3) inj_def)
  qed
  from this[THEN with_type_prepare_cancel, cancel_type_definition, OF with_type_nonempty, OF this]
  show inj_on F X
    by (simp add: inj_on_def)
qed

lemma register_norm: norm (F a) = norm a if register F
proof -
  from register_decomposition[OF that]
  have let 'c::type = register_decomposition_basis F in
         norm (F a) = norm a
  proof with_type_mp
    with_type_case
    then obtain U :: ('a × 'c) ell2 CL 'b ell2 where unitary U
      and FU: F θ = sandwich U (θ o id_cblinfun) for θ
      by metis
    show norm (F a) = norm a
      using unitary U
      by (simp add: FU sandwich_apply norm_isometry_compose norm_isometry_compose' norm_isometry tensor_op_norm)
  qed
  note this[cancel_with_type]
  then show ?thesis
    by simp
qed

lemma unitary_sandwich_register: unitary a  register (sandwich a)
  by (auto simp: sandwich_apply register_def cblinfun.bounded_clinear_right
      lift_cblinfun_comp[OF unitaryD1] lift_cblinfun_comp[OF unitaryD2]
      cblinfun_assoc_left)

lemma register_adj: register F  F (a*) = (F a)*
  using register_def by blast

lemma right_register_tensor_ex: T :: ('a × 'b) update  ('a × 'c) update. 
        register T  (a b. T (a o b) = a o F b) if register F
proof -
  from register_decomposition[OF register F]
  have let 'g::type = register_decomposition_basis F in
        T :: ('a × 'b) update  ('a × 'c) update. 
        register T  (a b. T (a o b) = a o F b)
  proof with_type_mp
    with_type_case
    then obtain U :: ('b × 'g) ell2 CL 'c ell2 
      where [simp]: unitary U and F: F θ = sandwich U *V θ o id_cblinfun for θ
      by auto
    define T :: ('a × 'b) update  ('a × 'c) update
      where T = sandwich (id_cblinfun o U) o sandwich assoc_ell2 o (λab. ab o id_cblinfun)
    have register T
      by (auto intro!: register_comp register_tensor_left unitary_sandwich_register unitary_tensor_op simp add: T_def)
    moreover have T (a o b) = a o F b for a b
      by (simp add: T_def F sandwich_tensor_op)
    ultimately show T :: ('a × 'b) update  ('a × 'c) update. register T  (a b. T (a o b) = a o F b)
      by auto
  qed
  from this[cancel_with_type]
  show ?thesis
    by -
qed




(* Things that are probably missing to do the proof from page 44 in the register-paper:

- Existence of T(a⊗ob) = F(a)⊗oG(b) [proven via completely pos. maps and Takesaki; maybe we can do it easier with the explicit representation of F,G?]
- Inverse of (- ⊗o d) is weak*-continuous (shown in Conway-op, Prop 46.6).  [Similar to register_inv_weak_star_continuous?]

*)
lemma 
  fixes F :: 'a update  'c update and G
  assumes [simp]: register F register G
  assumes FG_comm: a b. F a oCL G b = G b oCL F a
  shows register_pair_apply: (register_pair F G) (tensor_op a b) = F a oCL G b
    and register_pair_is_register: register (register_pair F G)
proof -
  have *: register_pair F G = (SOME R. a b. register R  R (a o b) = F a oCL G b)
    using assms unfolding register_pair_def by simp
  from register_decomposition[OF register F] 
  have let 'd::type = register_decomposition_basis F in
        R. a b. register R  R (a o b) = F a oCL G b
  proof with_type_mp
    with_type_case
(*     fix Rep :: ‹'d ⇒ 'c ell2› and Abs
    assume ‹type_definition Rep Abs (register_decomposition_basis F)›
    assume ‹(∃U :: ('a × 'd) ell2 ⇒CL 'c ell2. unitary U ∧ 
              (∀θ. F θ = sandwich U (θ ⊗o id_cblinfun)))› *)
    then obtain U :: ('a × 'd) ell2 CL 'c ell2 where [simp]: unitary U
      and FU: F θ = sandwich U (θ o id_cblinfun) for θ
      by metis
    from register_decomposition[OF register G]
    have let 'f::type = register_decomposition_basis G in
          R. a b. register R  R (a o b) = F a oCL G b
    proof with_type_mp
      with_type_case
      then obtain V :: ('b × 'f) ell2 CL 'c ell2 where [simp]: unitary V
        and GU: G θ = sandwich V (θ o id_cblinfun) for θ
        by metis
      show FG. a b. register FG  FG (a o b) = F a oCL G b
      proof -
        define G' and ι :: 'd update  ('a × 'd) update and G1 
          where G' = sandwich (U*) o G and ι d = id_cblinfun o d and G1 = inv ι o G' for d
        have [simp]: register G'
          by (simp add: G'_def register_comp unitary_sandwich_register)
        then have [simp]: bounded_clinear G'
          by (meson register_bounded_clinear)
        then have [simp]: clinear G'
          by (simp add: bounded_clinear.axioms(1))

        
        have range G' = sandwich (U*) ` range G
          by (simp add: GU G'_def image_image)
        also have   sandwich (U*) ` commutant (range F)
          by (auto intro!: image_mono simp: commutant_def FG_comm)
        also have  = commutant (sandwich (U*) ` range F)
          by (simp add: sandwich_unitary_commutant)
        also have  = commutant (range (λa. a o id_cblinfun))
          apply (rule arg_cong[where f=commutant])
          by (simp add: FU image_image flip: sandwich_compose cblinfun_apply_cblinfun_compose)
        also have  = range (λd. id_cblinfun o d)
          by (rule commutant_tensor1)
        also have  = range ι
          by (simp add: ι_def[abs_def])
        finally have range_G': range G'  range ι
          by -

        have continuous_map weak_star_topology weak_star_topology G'
          by (auto intro!: continuous_map_compose[where X'=weak_star_topology] simp: G'_def  weak_star_cont_register)
        then have cont_G': continuous_map weak_star_topology (subtopology weak_star_topology (range ι)) G'
          using range_G' by (auto intro!: continuous_map_into_subtopology)

        have [simp]: register ι
          by (simp add: ι_def[abs_def] register_tensor_right)
        then have cont_invι: continuous_map (subtopology weak_star_topology (range ι)) weak_star_topology (inv ι)
          by (rule register_inv_weak_star_continuous)
        have ι_inj: x = y if ι x = ι y for x y
          by (metis register ι invI register_inj that)

        have [simp]: register G1
        proof (unfold register_def, intro conjI allI)
          from cont_G' cont_invι 
          show cont_G1: continuous_map weak_star_topology weak_star_topology G1
            using G1_def continuous_map_compose by blast
          have ι_cancel: ι (inv ι x) = x if x  range G' for x
            by (meson f_inv_into_f range_G' subsetD that)

          show bounded_clinear G1
            using range_G' 
            by (auto intro!: bounded_clinearI[where K=1] ι_inj 
                simp: G1_def complex_vector.linear_add[of ι] bounded_clinear.clinear clinear_register
                ι_cancel range_subsetD complex_vector.linear_scale[of ι] register_norm[of G']
                simp flip: complex_vector.linear_add[of G'] complex_vector.linear_scale[of G']
                register_norm[of ι])
          show G1 id_cblinfun = id_cblinfun
            by (auto intro!: ι_inj register_of_id[of G'] simp add: G1_def ι_cancel register_of_id[of ι])
          show adj_G1: G1 (a*) = (G1 a)* for a
            using range_G' 
            by (auto intro!: ι_inj 
                simp: G1_def ι_cancel register_adj[of ι]
                simp flip: register_adj[of G'])
          show mult_G1: G1 (a oCL b) = G1 a oCL G1 b for a b
            using range_G' 
            by (auto intro!: bounded_clinearI[where K=1] ι_inj 
                simp: G1_def ι_cancel register_mult[of G']
                simp flip: register_mult[of ι])
        qed

        obtain T :: ('a × 'b) update  ('a × 'd) update
          where [simp]: register T and T_apply: T (a o b) = a o G1 b for a b
          using register G1 right_register_tensor_ex by blast
      
        define FG where FG = sandwich U o T
        then have [simp]: register FG
          by (auto intro!: register_comp unitary_sandwich_register simp add: FG_def)

        have FG (a o b) = F a oCL G b for a b
        proof -
          have FG_a: FG (a o id_cblinfun) = F a
            by (simp add: FG_def T_apply register_of_id FU)
          have FG (id_cblinfun o b) = sandwich U (ι (G1 b))
            by (simp add: FG_def T_apply ι_def)
          also have  = sandwich U (G' b)
            apply (rule arg_cong[where f=cblinfun_apply _])
            by (metis G1_def UNIV_I f_inv_into_f image_subset_iff o_def range_G')
          also have  = G b
            by (smt (verit) G'_def unitary U cblinfun_apply_cblinfun_compose cblinfun_compose_id_left cblinfun_compose_id_right comp_def id_cblinfun_adjoint sandwich.rep_eq sandwich_compose unitaryD2)
          finally have FG_b: FG (id_cblinfun o b) = G b
            by -
          have FG (a o b) = FG (a o id_cblinfun) oCL FG (id_cblinfun o b)
            by (simp add: comp_tensor_op register_mult)
          also have  = F a oCL G b
            by (simp add: FG_a FG_b)
          finally show ?thesis
            by -
        qed
        with register FG show ?thesis
          by metis
      qed
    qed
    from this[cancel_with_type]
    show R. a b. register R  R (a o b) = F a oCL G b
      by -
  qed
  from this[cancel_with_type]
  have R. a b. register R  R (a o b) = F a oCL G b
    by -
  then have a b. register (register_pair F G)  (register_pair F G) (a o b) = F a oCL G b
    unfolding * by (smt (verit) someI_ex)
  then show (register_pair F G) (tensor_op a b) = F a oCL G b and register (register_pair F G)
    by auto
qed

unbundle no cblinfun_syntax

end