Theory Compressed_Oracle_Is_RO

section ‹‹Compressed_Oracle_Is_RO› -- Equivalence of compressed oracle and regular random oracle›

theory Compressed_Oracle_Is_RO imports
    Registers.Pure_States
    CO_Operations
begin

lemma swap_function_oracle_measure_generic:
  fixes standard_query
  fixes X :: ‹'x update ⇒ 'mem update› and Y :: ‹'y::ab_group_add update ⇒ 'mem update›
  assumes std_query_Some: ‹⋀H x y z. H x = Some z ⟹ standard_query *V (ket (x,y,H)) = ket (x, y + z, H)› (* e.g. standard_query_ket_full_Some *)
  assumes [register]: ‹compatible X Y›
  shows ‹(Fst o X; (Fst o Y; Snd)) standard_query oCL Snd (proj (ket (Some o h)))
            = Fst ((X;Y) (function_oracle h)) oCL Snd (proj (ket (Some o h)))›
proof -
  note [[simproc del: Laws_Quantum.compatibility_warn]]
  let ?goal = ?thesis
  have [register]: ‹register (Fst o X; (Fst o Y; Snd :: _ ⇒ ('mem × ('x ⇀ 'y)) update))›
    by simp
  from register_decomposition[OF this]
  have ‹let 'd::type = register_decomposition_basis (Fst o X; (Fst o Y; Snd :: _ ⇒ ('mem × ('x ⇀ 'y)) update)) in ?thesis›
  proof with_type_mp
    case with_type_mp
    then obtain U :: ‹(('x × 'y × ('x ⇒ 'y option)) × 'd) ell2 ⇒CL ('mem × ('x ⇒ 'y option)) ell2› 
      where ‹unitary U› and unwrap: ‹(Fst ∘ X;(Fst ∘ Y;Snd)) θ = sandwich U *V (θ ⊗o id_cblinfun)› for θ
      by blast
    have unwrap_Snd: ‹Snd a = sandwich U *V ((id_cblinfun ⊗o (id_cblinfun ⊗o a)) ⊗o id_cblinfun)› for a
      apply (rewrite at Snd to ‹(Fst ∘ X;(Fst ∘ Y;Snd)) o Snd o Snd› DEADID.rel_mono_strong)
       apply (simp add: register_pair_Snd)
      by (simp add: unwrap Snd_def)
    have unwrap_Fst_XY: ‹(Fst o (X;Y)) a = sandwich U *V assoc (a ⊗o id_cblinfun) ⊗o id_cblinfun›
      for a
      apply (rewrite at ‹Fst o (X;Y)› to ‹(Fst ∘ X;(Fst ∘ Y;Snd)) o assoc o Fst› DEADID.rel_mono_strong)
       apply (simp add: register_pair_Fst register_comp_pair)
      by (simp add: only: o_apply unwrap Fst_def)

    have ‹standard_query ⊗o id_cblinfun oCL
          (id_cblinfun ⊗o id_cblinfun ⊗o proj (ket (Some ∘ h))) ⊗o id_cblinfun =
          assoc (function_oracle h ⊗o id_cblinfun) ⊗o id_cblinfun oCL
          (id_cblinfun ⊗o id_cblinfun ⊗o proj (ket (Some ∘ h))) ⊗o id_cblinfun›
      by (auto intro!: equal_ket
          simp: tensor_op_ket tensor_ell2_ket proj_ket_x_y_ofbool std_query_Some assoc_ell2_sandwich
          sandwich_apply function_oracle_apply)
    then show ?goal
      by (auto intro!: arg_cong[where f=‹sandwich U›]
          simp add: unwrap unwrap_Snd unwrap_Fst_XY[unfolded o_def] sandwich_arg_compose ‹unitary U›)
  qed
  from this[cancel_with_type]
  show ?goal
    by -
qed


lemma standard_query_for_fixed_func_generic:
  fixes standard_query
  fixes X :: ‹'x update ⇒ 'mem update› and Y :: ‹'y::ab_group_add update ⇒ 'mem update›
  assumes ‹⋀H x y z. H x = Some z ⟹ standard_query *V (ket (x,y,H)) = ket (x, y + z, H)› (* e.g. standard_query_ket_full_Some *)
  assumes ‹compatible X Y›
  shows ‹(Fst o X; (Fst o Y; Snd)) standard_query *V (ψ ⊗s ket (Some ∘ h))
            = Fst ((X;Y) (function_oracle h)) *V (ψ ⊗s ket (Some ∘ h))›
proof -
  have ‹(Fst o X; (Fst o Y; Snd)) standard_query *V (ψ ⊗s ket (Some ∘ h))
      = (Fst o X; (Fst o Y; Snd)) standard_query *V Snd (proj (ket (Some o h))) *V (ψ ⊗s ket (Some ∘ h))›
    by (simp add: proj_ket_x_y_ofbool)
  also have ‹… = Fst ((X;Y) (function_oracle h)) *V Snd (proj (ket (Some o h))) *V (ψ ⊗s ket (Some ∘ h))›
    apply (subst cblinfun_apply_cblinfun_compose[symmetric])+
    by (simp_all add: assms swap_function_oracle_measure_generic)
  also have ‹… = Fst ((X;Y) (function_oracle h)) *V (ψ ⊗s ket (Some ∘ h))›
    by (simp add: Proj_fixes_image ccspan.rep_eq complex_vector.span_base flip: cblinfun_apply_cblinfun_compose)
  finally show ?thesis
    by -
qed





end