Theory Transport_Galois_Relator_Properties
section ‹Properties of Galois Relator for White-Box Transport Side Conditions›
theory Transport_Galois_Relator_Properties
  imports
    Binary_Relations_Bi_Total
    Binary_Relations_Bi_Unique
    Galois_Connections
    Galois_Relator
begin
paragraph ‹Summary›
text ‹Properties of Galois relator arising as side conditions for white-box transport.›
context galois
begin
paragraph ‹Right-Uniqueness›
context
  fixes P :: "'a ⇒ bool" and Q :: "'b ⇒ bool"
begin
lemma right_unique_at_left_Galois_if_right_unique_at_rightI:
  assumes "right_unique_at Q (≤⇘R⇙)"
  and "((≤⇘L⇙) ⇩h⊴ (≤⇘R⇙)) l r"
  shows "right_unique_at Q (⇘L⇙⪅)"
  using assms by (auto dest: right_unique_atD)
lemma right_unique_at_right_if_right_unique_at_left_GaloisI:
  assumes "right_unique_at Q (⇘L⇙⪅)"
  and "((≤⇘R⇙) ⇒ (≤⇘L⇙)) r"
  shows "right_unique_at Q (≤⇘R⇙)"
  using assms by (blast dest: right_unique_atD)
corollary right_unique_at_left_Galois_iff_right_unique_at_rightI:
  assumes "((≤⇘L⇙) ⇩h⊴ (≤⇘R⇙)) l r"
  and "((≤⇘R⇙) ⇒ (≤⇘L⇙)) r"
  shows "right_unique_at Q (⇘L⇙⪅) ⟷ right_unique_at Q (≤⇘R⇙)"
  using assms right_unique_at_left_Galois_if_right_unique_at_rightI
    right_unique_at_right_if_right_unique_at_left_GaloisI
  by blast
corollary right_unique_on_left_Galois_if_right_unique_at_rightI:
  assumes "right_unique_at Q (≤⇘R⇙)"
  and "((⇘L⇙⪅) ⇛ (⟶)) P Q"
  and "((≤⇘L⇙) ⇩h⊴ (≤⇘R⇙)) l r"
  shows "right_unique_on P (⇘L⇙⪅)"
  using assms by (intro right_unique_on_if_Fun_Rel_imp_if_right_unique_at)
  (blast intro: right_unique_at_left_Galois_if_right_unique_at_rightI)
corollary right_unique_at_right_if_right_unique_on_left_GaloisI:
  assumes "right_unique_on P (⇘L⇙⪅)"
  and "((⇘L⇙⪅) ⇛ (⟵)) P Q"
  and "((≤⇘R⇙) ⇒ (≤⇘L⇙)) r"
  shows "right_unique_at Q (≤⇘R⇙)"
  using assms by (intro right_unique_at_right_if_right_unique_at_left_GaloisI
    right_unique_at_if_Fun_Rel_rev_imp_if_right_unique_on)
corollary right_unique_on_left_Galois_iff_right_unique_at_rightI:
  assumes "((⇘L⇙⪅) ⇛ (⟷)) P Q"
  and "((≤⇘L⇙) ⇩h⊴ (≤⇘R⇙)) l r"
  and "((≤⇘R⇙) ⇒ (≤⇘L⇙)) r"
  shows "right_unique_on P (⇘L⇙⪅) ⟷ right_unique_at Q (≤⇘R⇙)"
  using assms right_unique_on_left_Galois_if_right_unique_at_rightI
    right_unique_at_right_if_right_unique_on_left_GaloisI
  by blast
end
corollary right_unique_left_Galois_if_right_unique_rightI:
  assumes "right_unique (≤⇘R⇙)"
  and "((≤⇘L⇙) ⇩h⊴ (≤⇘R⇙)) l r"
  shows "right_unique (⇘L⇙⪅)"
  using assms by (urule right_unique_at_left_Galois_if_right_unique_at_rightI)
corollary right_unique_right_if_right_unique_left_GaloisI:
  assumes "right_unique (⇘L⇙⪅)"
  and "((≤⇘R⇙) ⇒ (≤⇘L⇙)) r"
  shows "right_unique (≤⇘R⇙)"
  using assms by (urule right_unique_at_right_if_right_unique_at_left_GaloisI)
corollary right_unique_left_Galois_iff_right_unique_rightI:
  assumes "((≤⇘L⇙) ⇩h⊴ (≤⇘R⇙)) l r"
  and "((≤⇘R⇙) ⇒ (≤⇘L⇙)) r"
  shows "right_unique (⇘L⇙⪅) ⟷ right_unique (≤⇘R⇙)"
  using assms right_unique_left_Galois_if_right_unique_rightI
    right_unique_right_if_right_unique_left_GaloisI
  by blast
paragraph ‹Injectivity›
context
  fixes P :: "'a ⇒ bool" and Q :: "'b ⇒ bool"
begin
lemma injective_on_left_Galois_if_rel_injective_on_left:
  assumes "rel_injective_on P (≤⇘L⇙)"
  shows "rel_injective_on P (⇘L⇙⪅)"
  using assms by (auto dest: rel_injective_onD)
lemma rel_injective_on_left_if_injective_on_left_GaloisI:
  assumes "rel_injective_on P (⇘L⇙⪅)"
  and "((≤⇘L⇙) ⇒ (≤⇘R⇙)) l"
  and "((≤⇘L⇙) ⊴⇩h (≤⇘R⇙)) l r"
  shows "rel_injective_on P (≤⇘L⇙)"
  using assms by (intro rel_injective_onI) (blast dest!: rel_injective_onD)
corollary injective_on_left_Galois_iff_rel_injective_on_leftI:
  assumes "((≤⇘L⇙) ⇒ (≤⇘R⇙)) l"
  and "((≤⇘L⇙) ⊴⇩h (≤⇘R⇙)) l r"
  shows "rel_injective_on P (⇘L⇙⪅) ⟷ rel_injective_on P (≤⇘L⇙)"
  using assms injective_on_left_Galois_if_rel_injective_on_left
    rel_injective_on_left_if_injective_on_left_GaloisI
  by blast
corollary injective_at_left_Galois_if_rel_injective_on_leftI:
  assumes "rel_injective_on P (≤⇘L⇙)"
  and "((⇘L⇙⪅) ⇛ (⟵)) P Q"
  shows "rel_injective_at Q (⇘L⇙⪅)"
  using assms by (intro rel_injective_at_if_Fun_Rel_rev_imp_if_rel_injective_on)
  (blast intro: injective_on_left_Galois_if_rel_injective_on_left)
corollary rel_injective_on_left_if_injective_at_left_GaloisI:
  assumes "rel_injective_at Q (⇘L⇙⪅)"
  and "((⇘L⇙⪅) ⇛ (⟶)) P Q"
  and "((≤⇘L⇙) ⇒ (≤⇘R⇙)) l"
  and "((≤⇘L⇙) ⊴⇩h (≤⇘R⇙)) l r"
  shows "rel_injective_on P (≤⇘L⇙)"
  using assms by (intro rel_injective_on_left_if_injective_on_left_GaloisI
    rel_injective_on_if_Fun_Rel_imp_if_rel_injective_at)
corollary injective_at_left_Galois_iff_rel_injective_on_leftI:
  assumes "((⇘L⇙⪅) ⇛ (⟷)) P Q"
  and "((≤⇘L⇙) ⇒ (≤⇘R⇙)) l"
  and "((≤⇘L⇙) ⊴⇩h (≤⇘R⇙)) l r"
  shows "rel_injective_at Q (⇘L⇙⪅) ⟷ rel_injective_on P (≤⇘L⇙)"
  using assms injective_at_left_Galois_if_rel_injective_on_leftI
    rel_injective_on_left_if_injective_at_left_GaloisI
  by blast
end
corollary injective_left_Galois_if_rel_injective_left:
  assumes "rel_injective (≤⇘L⇙)"
  shows "rel_injective (⇘L⇙⪅)"
  using assms by (urule injective_on_left_Galois_if_rel_injective_on_left)
corollary rel_injective_left_if_injective_left_GaloisI:
  assumes "rel_injective (⇘L⇙⪅)"
  and "((≤⇘L⇙) ⇒ (≤⇘R⇙)) l"
  and "((≤⇘L⇙) ⊴⇩h (≤⇘R⇙)) l r"
  shows  "rel_injective (≤⇘L⇙)"
  using assms by (urule rel_injective_on_left_if_injective_on_left_GaloisI)
corollary rel_injective_left_Galois_iff_rel_injective_leftI:
  assumes "((≤⇘L⇙) ⇒ (≤⇘R⇙)) l"
  and "((≤⇘L⇙) ⊴⇩h (≤⇘R⇙)) l r"
  shows "rel_injective (⇘L⇙⪅) ⟷ rel_injective (≤⇘L⇙)"
  using assms injective_left_Galois_if_rel_injective_left
    rel_injective_left_if_injective_left_GaloisI
  by blast
paragraph ‹Bi-Uniqueness›
context
  fixes P :: "'a ⇒ bool" and Q :: "'b ⇒ bool"
begin
corollary bi_unique_on_left_Galois_if_right_unique_at_right_if_rel_injective_on_leftI:
  assumes "rel_injective_on P (≤⇘L⇙)"
  and "right_unique_at Q (≤⇘R⇙)"
  and "((⇘L⇙⪅) ⇛ (⟶)) P Q"
  and "((≤⇘L⇙) ⇩h⊴ (≤⇘R⇙)) l r"
  shows "bi_unique_on P (⇘L⇙⪅)"
  using assms
  by (intro bi_unique_onI right_unique_on_left_Galois_if_right_unique_at_rightI
    injective_on_left_Galois_if_rel_injective_on_left)
corollary rel_injective_on_left_and_right_unique_at_right_if_bi_unique_on_left_GaloisI:
  assumes "bi_unique_on P (⇘L⇙⪅)"
  and "((⇘L⇙⪅) ⇛ (⟵)) P Q"
  and "((≤⇘L⇙) ⇒ (≤⇘R⇙)) l"
  and "((≤⇘R⇙) ⇒ (≤⇘L⇙)) r"
  and "((≤⇘L⇙) ⊴⇩h (≤⇘R⇙)) l r"
  shows "rel_injective_on P (≤⇘L⇙) ∧ right_unique_at Q (≤⇘R⇙)"
  using assms by (intro conjI rel_injective_on_left_if_injective_on_left_GaloisI
    right_unique_at_right_if_right_unique_on_left_GaloisI)
  auto
corollary bi_unique_on_left_Galois_iff_rel_injective_on_left_and_right_unique_at_rightI:
  assumes "((⇘L⇙⪅) ⇛ (⟷)) P Q"
  and "((≤⇘L⇙) ⊣ (≤⇘R⇙)) l r"
  shows "bi_unique_on P (⇘L⇙⪅) ⟷ rel_injective_on P (≤⇘L⇙) ∧ right_unique_at Q (≤⇘R⇙)"
  using assms bi_unique_on_left_Galois_if_right_unique_at_right_if_rel_injective_on_leftI
    rel_injective_on_left_and_right_unique_at_right_if_bi_unique_on_left_GaloisI
  by blast
end
corollary bi_unique_left_Galois_if_right_unique_right_if_rel_injective_leftI:
  assumes "rel_injective (≤⇘L⇙)"
  and "right_unique (≤⇘R⇙)"
  and "((≤⇘L⇙) ⇩h⊴ (≤⇘R⇙)) l r"
  shows "bi_unique (⇘L⇙⪅)"
  by (urule (rr) bi_unique_on_left_Galois_if_right_unique_at_right_if_rel_injective_on_leftI assms)
  auto
corollary rel_injective_left_and_right_unique_right_if_bi_unique_left_GaloisI:
  assumes "bi_unique (⇘L⇙⪅)"
  and "((≤⇘L⇙) ⇒ (≤⇘R⇙)) l"
  and "((≤⇘R⇙) ⇒ (≤⇘L⇙)) r"
  and "((≤⇘L⇙) ⊴⇩h (≤⇘R⇙)) l r"
  shows "rel_injective (≤⇘L⇙) ∧ right_unique (≤⇘R⇙)"
  by (urule (rr) rel_injective_on_left_and_right_unique_at_right_if_bi_unique_on_left_GaloisI assms)
  auto
corollary bi_unique_left_Galois_iff_rel_injective_left_and_right_unique_rightI:
  assumes "((≤⇘L⇙) ⊣ (≤⇘R⇙)) l r"
  shows "bi_unique (⇘L⇙⪅) ⟷ rel_injective (≤⇘L⇙) ∧ right_unique (≤⇘R⇙)"
  using assms bi_unique_left_Galois_if_right_unique_right_if_rel_injective_leftI
    rel_injective_left_and_right_unique_right_if_bi_unique_left_GaloisI
  by blast
paragraph ‹Surjectivity›
context
  fixes Q :: "'b ⇒ bool"
begin
lemma surjective_at_left_Galois_if_rel_surjective_at_rightI:
  assumes "rel_surjective_at Q (≤⇘R⇙)"
  and "((≤⇘R⇙) ⇒ (≤⇘L⇙)) r"
  shows "rel_surjective_at Q (⇘L⇙⪅)"
  using assms by (intro rel_surjective_atI) fast
lemma rel_surjective_at_right_if_surjective_at_left_Galois:
  assumes "rel_surjective_at Q (⇘L⇙⪅)"
  shows "rel_surjective_at Q (≤⇘R⇙)"
  using assms by (intro rel_surjective_atI) (auto)
corollary rel_surjective_at_right_iff_surjective_at_left_GaloisI:
  assumes "((≤⇘R⇙) ⇒ (≤⇘L⇙)) r"
  shows "rel_surjective_at Q (⇘L⇙⪅) ⟷ rel_surjective_at Q (≤⇘R⇙)"
  using assms surjective_at_left_Galois_if_rel_surjective_at_rightI
    rel_surjective_at_right_if_surjective_at_left_Galois
  by blast
end
corollary surjective_left_Galois_if_rel_surjective_rightI:
  assumes "rel_surjective (≤⇘R⇙)"
  and "((≤⇘R⇙) ⇒ (≤⇘L⇙)) r"
  shows "rel_surjective (⇘L⇙⪅)"
  using assms by (urule surjective_at_left_Galois_if_rel_surjective_at_rightI)
corollary rel_surjective_right_if_surjective_left_Galois:
  assumes "rel_surjective (⇘L⇙⪅)"
  shows "rel_surjective (≤⇘R⇙)"
  using assms by (urule rel_surjective_at_right_if_surjective_at_left_Galois)
corollary rel_surjective_right_iff_surjective_left_GaloisI:
  assumes "((≤⇘R⇙) ⇒ (≤⇘L⇙)) r"
  shows "rel_surjective (⇘L⇙⪅) ⟷ rel_surjective (≤⇘R⇙)"
  using assms surjective_left_Galois_if_rel_surjective_rightI
    rel_surjective_right_if_surjective_left_Galois
  by blast
paragraph ‹Left-Totality›
context
  fixes P :: "'a ⇒ bool"
begin
lemma left_total_on_left_Galois_if_left_total_on_leftI:
  assumes "left_total_on P (≤⇘L⇙)"
  and "((≤⇘L⇙) ⇒ (≤⇘R⇙)) l"
  and "((≤⇘L⇙) ⊴⇩h (≤⇘R⇙)) l r"
  shows "left_total_on P (⇘L⇙⪅)"
  using assms by (intro left_total_onI) force
lemma left_total_on_left_if_left_total_on_left_GaloisI:
  assumes "left_total_on P (⇘L⇙⪅)"
  shows "left_total_on P (≤⇘L⇙)"
  using assms by (intro left_total_onI) auto
corollary left_total_on_left_Galois_iff_left_total_on_leftI:
  assumes "((≤⇘L⇙) ⇒ (≤⇘R⇙)) l"
  and "((≤⇘L⇙) ⊴⇩h (≤⇘R⇙)) l r"
  shows "left_total_on P (⇘L⇙⪅) ⟷ left_total_on P (≤⇘L⇙)"
  using assms left_total_on_left_Galois_if_left_total_on_leftI
    left_total_on_left_if_left_total_on_left_GaloisI
  by blast
end
corollary left_total_left_Galois_if_left_total_leftI:
  assumes "left_total (≤⇘L⇙)"
  and "((≤⇘L⇙) ⇒ (≤⇘R⇙)) l"
  and "((≤⇘L⇙) ⊴⇩h (≤⇘R⇙)) l r"
  shows "left_total (⇘L⇙⪅)"
  using assms by (urule left_total_on_left_Galois_if_left_total_on_leftI)
corollary left_total_left_if_left_total_left_Galois:
  assumes "left_total (⇘L⇙⪅)"
  shows "left_total (≤⇘L⇙)"
  using assms by (urule left_total_on_left_if_left_total_on_left_GaloisI)
corollary left_total_left_Galois_iff_left_total_leftI:
  assumes "((≤⇘L⇙) ⇒ (≤⇘R⇙)) l"
  and "((≤⇘L⇙) ⊴⇩h (≤⇘R⇙)) l r"
  shows "left_total (⇘L⇙⪅) ⟷ left_total (≤⇘L⇙)"
  using assms left_total_left_Galois_if_left_total_leftI
    left_total_left_if_left_total_left_Galois
  by blast
paragraph ‹Bi-Totality›
context
  fixes P :: "'a ⇒ bool" and Q :: "'b ⇒ bool"
begin
lemma bi_total_on_left_GaloisI:
  assumes "left_total_on P (≤⇘L⇙)"
  and "rel_surjective_at Q (≤⇘R⇙)"
  and "((≤⇘L⇙) ⇒ (≤⇘R⇙)) l"
  and "((≤⇘R⇙) ⇒ (≤⇘L⇙)) r"
  and "((≤⇘L⇙) ⊴⇩h (≤⇘R⇙)) l r"
  shows "bi_total_on P Q (⇘L⇙⪅)"
  using assms surjective_at_left_Galois_if_rel_surjective_at_rightI
    left_total_on_left_Galois_if_left_total_on_leftI
  by blast
lemma left_total_on_left_rel_surjective_at_right_if_bi_total_on_left_GaloisE:
  assumes "bi_total_on P Q (⇘L⇙⪅)"
  obtains "left_total_on P (≤⇘L⇙)" "rel_surjective_at Q (≤⇘R⇙)"
  using assms rel_surjective_at_right_if_surjective_at_left_Galois
    left_total_on_left_if_left_total_on_left_GaloisI
  by auto
corollary bi_total_on_left_Galois_iff_left_total_on_left_and_rel_surjective_on_rightI:
  assumes "((≤⇘L⇙) ⇒ (≤⇘R⇙)) l"
  and "((≤⇘R⇙) ⇒ (≤⇘L⇙)) r"
  and "((≤⇘L⇙) ⊴⇩h (≤⇘R⇙)) l r"
  shows "bi_total_on P Q (⇘L⇙⪅) ⟷ left_total_on P (≤⇘L⇙) ∧ rel_surjective_at Q (≤⇘R⇙)"
  using assms bi_total_on_left_GaloisI
    left_total_on_left_rel_surjective_at_right_if_bi_total_on_left_GaloisE
  by blast
end
corollary bi_total_left_GaloisI:
  assumes "left_total (≤⇘L⇙)"
  and "rel_surjective (≤⇘R⇙)"
  and "((≤⇘L⇙) ⇒ (≤⇘R⇙)) l"
  and "((≤⇘R⇙) ⇒ (≤⇘L⇙)) r"
  and "((≤⇘L⇙) ⊴⇩h (≤⇘R⇙)) l r"
  shows "bi_total (⇘L⇙⪅)"
  using assms by (urule bi_total_on_left_GaloisI)
corollary left_total_left_rel_surjective_right_if_bi_total_left_GaloisE:
  assumes "bi_total (⇘L⇙⪅)"
  obtains "left_total (≤⇘L⇙)" "rel_surjective (≤⇘R⇙)"
  using assms by (urule (e) left_total_on_left_rel_surjective_at_right_if_bi_total_on_left_GaloisE)
corollary bi_total_left_Galois_iff_left_total_left_and_rel_surjective_rightI:
  assumes "((≤⇘L⇙) ⇒ (≤⇘R⇙)) l"
  and "((≤⇘R⇙) ⇒ (≤⇘L⇙)) r"
  and "((≤⇘L⇙) ⊴⇩h (≤⇘R⇙)) l r"
  shows "bi_total (⇘L⇙⪅) ⟷ left_total (≤⇘L⇙) ∧ rel_surjective (≤⇘R⇙)"
  using assms bi_total_left_GaloisI
    left_total_left_rel_surjective_right_if_bi_total_left_GaloisE
  by blast
paragraph ‹Function Relator›
lemma Fun_Rel_left_Galois_left_Galois_imp_left_rightI:
  assumes monol: "((≤⇘L⇙) ⇒ (≤⇘R⇙)) l"
  and half_gal: "((≤⇘L⇙) ⇩h⊴ (≤⇘R⇙)) l r"
  and perR: "partial_equivalence_rel (≤⇘R⇙)"
  shows "((⇘L⇙⪅) ⇛ (⇘L⇙⪅) ⇛ (⟶)) (≤⇘L⇙) (≤⇘R⇙)"
proof (intro Fun_Rel_relI impI)
  fix x y x' y'
  assume "x ⇘L⇙⪅ y" "x' ⇘L⇙⪅ y'" "x ≤⇘L⇙ x'"
  with half_gal have "l x' ≤⇘R⇙ y'" by auto
  with ‹x ≤⇘L⇙ x'› monol perR have "l x ≤⇘R⇙ y'" by blast
  with ‹x ⇘L⇙⪅ y› half_gal perR have "y ≤⇘R⇙ l x" by (blast dest: symmetricD)
  with perR ‹l x ≤⇘R⇙ y'› show "y ≤⇘R⇙ y'" by blast
qed
lemma Fun_Rel_left_Galois_left_Galois_rev_imp_left_rightI:
  assumes monor: "((≤⇘R⇙) ⇒ (≤⇘L⇙)) r"
  and perL: "partial_equivalence_rel (≤⇘L⇙)"
  shows "((⇘L⇙⪅) ⇛ (⇘L⇙⪅) ⇛ (⟵)) (≤⇘L⇙) (≤⇘R⇙)"
proof (intro Fun_Rel_relI rev_impI)
  fix x y x' y'
  assume "x ⇘L⇙⪅ y" and "x' ⇘L⇙⪅ y'" and "y ≤⇘R⇙ y'"
  with monor perL have "x ≤⇘L⇙ r y'" by fastforce
  with  ‹x' ⇘L⇙⪅ y'› have "x' ≤⇘L⇙ r y'" by auto
  with perL ‹x ≤⇘L⇙ r y'› show "x ≤⇘L⇙ x'" by (blast dest: symmetricD)
qed
corollary Fun_Rel_left_Galois_left_Galois_iff_left_rightI:
  assumes "((≤⇘L⇙) ⇒ (≤⇘R⇙)) l"
  and "((≤⇘R⇙) ⇒ (≤⇘L⇙)) r"
  and "((≤⇘L⇙) ⇩h⊴ (≤⇘R⇙)) l r"
  and "partial_equivalence_rel (≤⇘L⇙)"
  and "partial_equivalence_rel (≤⇘R⇙)"
  shows "((⇘L⇙⪅) ⇛ (⇘L⇙⪅) ⇛ (⟷)) (≤⇘L⇙) (≤⇘R⇙)"
  using assms Fun_Rel_left_Galois_left_Galois_imp_left_rightI
    Fun_Rel_left_Galois_left_Galois_rev_imp_left_rightI
  by (intro Fun_Rel_relI) blast
end
end