Theory QueryGraph
theory QueryGraph
  imports Complex_Main "Graph_Additions" "Selectivities" "JoinTree"
begin
section ‹Query Graphs›
locale query_graph = graph +
  fixes sel :: "'b weight_fun"
  fixes cf :: "'a ⇒ real"
  assumes sel_sym: "⟦tail G e⇩1 = head G e⇩2; head G e⇩1 = tail G e⇩2⟧ ⟹ sel e⇩1 = sel e⇩2"
      and not_arc_sel_1: "e ∉ arcs G ⟹ sel e = 1"
      and sel_pos: "sel e > 0"
      and sel_leq_1: "sel e ≤ 1"
      and pos_cards: "x ∈ verts G ⟹ cf x > 0"
begin
subsection ‹Function for Join Trees and Selectivities›
definition matching_sel :: "'a selectivity ⇒ bool" where
  "matching_sel f = (∀x y.
      (∃e. (tail G e) = x ∧ (head G e) = y ∧ f x y = sel e)
    ∨ ((∄e. (tail G e) = x ∧ (head G e) = y) ∧ f x y = 1))"
definition match_sel :: "'a selectivity" where
  "match_sel x y =
    (if ∃e ∈ arcs G. (tail G e) = x ∧ (head G e) = y
    then sel (THE e. e ∈ arcs G ∧ (tail G e) = x ∧ (head G e) = y) else 1)"
definition matching_rels :: "'a joinTree ⇒ bool" where
  "matching_rels t = (relations t ⊆ verts G)"
definition remove_sel :: "'a ⇒ 'b weight_fun" where
  "remove_sel x = (λb. if b∈{a ∈ arcs G. tail G a = x ∨ head G a = x} then 1 else sel b)"
definition valid_tree :: "'a joinTree ⇒ bool" where
  "valid_tree t = (relations t = verts G ∧ distinct_relations t)"
fun no_cross_products :: "'a joinTree ⇒ bool" where
  "no_cross_products (Relation rel) = True"
| "no_cross_products (Join l r) = ((∃x∈relations l. ∃y∈relations r. x →⇘G⇙ y)
    ∧ no_cross_products l ∧ no_cross_products r)"
subsection "Proofs"
text ‹
  Proofs that a query graph satisifies basic properties of join trees and selectivities.
›
lemma sel_less_arc: "sel x < 1 ⟹ x ∈ arcs G"
  using not_arc_sel_1 by force
lemma joinTree_card_pos: "matching_rels t ⟹ pos_rel_cards cf t"
  by(induction t) (auto simp: pos_cards pos_rel_cards_def matching_rels_def)
lemma symmetric_arcs: "x∈arcs G ⟹ ∃y. head G x = tail G y ∧ tail G x = head G y"
  using sym_arcs symmetric_conv by fast
lemma arc_ends_eq_impl_sel_eq: "head G x = head G y ⟹ tail G x = tail G y ⟹ sel x = sel y"
  using sel_sym symmetric_arcs not_arc_sel_1 by metis
lemma arc_ends_eq_impl_arc_eq:
  "⟦e1 ∈ arcs G; e2 ∈ arcs G; head G e1 = head G e2; tail G e1 = tail G e2⟧ ⟹ e1 = e2"
  using no_multi_alt by blast
lemma matching_sel_simp_if_not1:
  "⟦matching_sel sf; sf x y ≠ 1⟧ ⟹ ∃e ∈ arcs G. tail G e = x ∧ head G e = y ∧ sf x y = sel e"
  using not_arc_sel_1 unfolding matching_sel_def by fastforce
lemma matching_sel_simp_if_arc:
  "⟦matching_sel sf; e ∈ arcs G⟧ ⟹ sf (tail G e) (head G e) = sel e"
  unfolding matching_sel_def by (metis arc_ends_eq_impl_sel_eq)
lemma matching_sel1_if_no_arc: "matching_sel sf ⟹ ¬(x →⇘G⇙ y ∨ y →⇘G⇙ x) ⟹ sf x y = 1"
  using not_arc_sel_1 unfolding arcs_ends_def arc_to_ends_def matching_sel_def image_iff by metis
lemma matching_sel_alt_aux1:
  "matching_sel f
    ⟹ (∀x y. (∃e ∈ arcs G. (tail G e) = x ∧ (head G e) = y ∧ f x y = sel e)
            ∨ ((∄e. e ∈ arcs G ∧ (tail G e) = x ∧ (head G e) = y) ∧ f x y = 1))"
  by (metis matching_sel_def arc_ends_eq_impl_sel_eq not_arc_sel_1)
lemma matching_sel_alt_aux2:
  "(∀x y.(∃e ∈ arcs G. (tail G e) = x ∧ (head G e) = y ∧ f x y = sel e)
      ∨ ((∄e. e ∈ arcs G ∧ (tail G e) = x ∧ (head G e) = y) ∧ f x y = 1))
    ⟹ matching_sel f"
  by (fastforce simp: not_arc_sel_1 matching_sel_def)
lemma matching_sel_alt:
  "matching_sel f
    = (∀x y. (∃e ∈ arcs G. (tail G e) = x ∧ (head G e) = y ∧ f x y = sel e)
          ∨ ((∄e. e ∈ arcs G ∧ (tail G e) = x ∧ (head G e) = y) ∧ f x y = 1))"
  using matching_sel_alt_aux1 matching_sel_alt_aux2 by blast
lemma matching_sel_symm:
  assumes "matching_sel f"
  shows "sel_symm f"
  unfolding sel_symm_def
proof (standard, standard)
  fix x y
  show "f x y = f y x"
  proof(cases "∃e∈arcs G. (head G e) = x ∧ (tail G e) = y")
    case True
    then show ?thesis using assms symmetric_arcs sel_sym unfolding matching_sel_def by metis
  next
    case False
    then show ?thesis by (metis assms symmetric_arcs matching_sel_def not_arc_sel_1 sel_sym)
  qed
qed
lemma matching_sel_reasonable: "matching_sel f ⟹ sel_reasonable f"
  using sel_reasonable_def matching_sel_def sel_pos sel_leq_1
  by (metis le_numeral_extra(4) less_numeral_extra(1))
lemma matching_reasonable_cards:
  "⟦matching_sel f; matching_rels t⟧ ⟹ reasonable_cards cf f t"
  by (simp add: joinTree_card_pos matching_sel_reasonable pos_sel_reason_impl_reason)
lemma matching_sel_unique_aux:
  assumes "matching_sel f" "matching_sel g"
  shows "f x y = g x y"
proof(cases "∃e. tail G e = x ∧ head G e = y")
  case True
  then show ?thesis
    using assms arc_ends_eq_impl_sel_eq unfolding matching_sel_def by metis
next
  case False
  then show ?thesis using assms unfolding matching_sel_def by fastforce
qed
lemma matching_sel_unique: "⟦matching_sel f; matching_sel g⟧ ⟹ f = g"
  using matching_sel_unique_aux by blast
lemma match_sel_matching[intro]: "matching_sel match_sel"
  unfolding matching_sel_alt
proof(standard,standard)
  fix x y
  show "(∃e∈arcs G. tail G e = x ∧ head G e = y ∧ match_sel x y = sel e) ∨
          ((∄e. e ∈ arcs G ∧ tail G e = x ∧ head G e = y) ∧ match_sel x y = 1)"
  proof(cases "∃e ∈ arcs G. tail G e = x ∧ head G e = y")
    case True
    then obtain e where e_def: "e ∈ arcs G" "tail G e = x" "head G e = y" by blast
    then have "match_sel x y = sel (THE e. e ∈ arcs G ∧ tail G e = x ∧ head G e = y)"
      unfolding match_sel_def by auto
    moreover have "(THE e. e ∈ arcs G ∧ tail G e = x ∧ head G e = y) = e"
      using e_def arc_ends_eq_impl_arc_eq by blast
    ultimately show ?thesis using e_def by blast
  next
    case False
    then show ?thesis unfolding match_sel_def by auto
  qed
qed
corollary match_sel_unique: "matching_sel f ⟹ f = match_sel"
  using matching_sel_unique by blast
corollary match_sel1_if_no_arc: "¬(x →⇘G⇙ y ∨ y →⇘G⇙ x) ⟹ match_sel x y = 1"
  using matching_sel1_if_no_arc by blast
corollary match_sel_symm[intro]: "sel_symm match_sel"
  using matching_sel_symm by blast
corollary match_sel_reasonable[intro]: "sel_reasonable match_sel"
  using matching_sel_reasonable by blast
corollary match_reasonable_cards: "matching_rels t ⟹ reasonable_cards cf match_sel t"
  using matching_reasonable_cards by blast
lemma matching_rels_trans: "matching_rels (Join l r) = (matching_rels l ∧ matching_rels r)"
  using matching_rels_def by simp
lemma first_node_in_verts_if_rels_eq_verts: "relations t = verts G ⟹ first_node t ∈ verts G"
  unfolding first_node_eq_hd using inorder_eq_set hd_in_set[OF inorder_nempty] by fast
lemma first_node_in_verts_if_valid: "valid_tree t ⟹ first_node t ∈ verts G"
  using first_node_in_verts_if_rels_eq_verts valid_tree_def by simp
lemma dominates_sym: "(x →⇘G⇙ y) ⟷ (y →⇘G⇙ x)"
  using graph_symmetric by blast
lemma no_cross_mirror_eq: "no_cross_products (mirror t) = no_cross_products t"
  using graph_symmetric by(induction t) auto
lemma no_cross_create_ldeep_rev_app:
  "⟦ys≠[]; no_cross_products (create_ldeep_rev (xs@ys))⟧ ⟹ no_cross_products (create_ldeep_rev ys)"
proof(induction "xs@ys" arbitrary: xs rule: create_ldeep_rev.induct)
  case (2 x)
  then show ?case by (metis append_eq_Cons_conv append_is_Nil_conv)
next
  case (3 x y zs)
  then show ?case
  proof(cases xs)
    case Nil
    then show ?thesis using "3.prems"(2) by simp
  next
    case (Cons x' xs')
    have "no_cross_products (Join (create_ldeep_rev (y#zs)) (Relation x))"
      using "3.hyps"(2) "3.prems"(2) create_ldeep_rev.simps(3)[of x y zs] by simp
    then have "no_cross_products (create_ldeep_rev (y#zs))" by simp
    then show ?thesis using "3.hyps" "3.prems"(1) Cons by simp
  qed
qed(simp)
lemma no_cross_create_ldeep_app:
  "⟦xs≠[]; no_cross_products (create_ldeep (xs@ys))⟧ ⟹ no_cross_products (create_ldeep xs)"
  by (simp add: create_ldeep_def no_cross_create_ldeep_rev_app)
lemma matching_rels_if_no_cross: "⟦∀r. t ≠ Relation r; no_cross_products t⟧ ⟹ matching_rels t"
  unfolding matching_rels_def by(induction t) fastforce+
lemma no_cross_awalk:
  "⟦matching_rels t; no_cross_products t; x ∈ relations t; y ∈ relations t⟧
    ⟹ ∃p. awalk x p y ∧ set (awalk_verts x p) ⊆ relations t"
proof(induction t arbitrary: x y)
  case (Relation rel)
  then have "x ∈ verts G" using matching_rels_def by blast
  then have "awalk x [] x" by (simp add: awalk_Nil_iff)
  then show ?case using Relation(3,4) by force
next
  case (Join l r)
  then consider "x ∈ relations l" "y ∈ relations l" | "x ∈ relations r" "y ∈ relations l"
    | "x ∈ relations l" "y ∈ relations r" | "x ∈ relations r" "y ∈ relations r"
    by force
  then show ?case
  proof(cases)
    case 1
    then show ?thesis using Join.IH(1)[of x y] Join.prems(1,2) matching_rels_trans by auto
  next
    case 2
    then obtain x' y' e where e_def:
        "x' ∈ relations r" "y' ∈ relations l" "tail G e = y'" "head G e = x'" "e ∈ arcs G"
      using Join.prems(2) by auto
    then obtain e2 where e2_def: "tail G e2 = x'" "head G e2 = y'" "e2 ∈ arcs G"
      using symmetric_conv by force
    obtain p1 where p1_def: "awalk y' p1 y ∧ set (awalk_verts y' p1) ⊆ relations l"
      using Join.IH(1) Join.prems(1,2) 2(2) matching_rels_trans e_def(2) by fastforce
    obtain p2 where p2_def: "awalk x p2 x' ∧ set (awalk_verts x p2) ⊆ relations r"
      using Join.IH(2) Join.prems(1,2) 2(1) matching_rels_trans e_def(1) by fastforce
    have "awalk x (p2@[e2]@p1) y"
      using e2_def p1_def p2_def awalk_appendI arc_implies_awalk by blast
    moreover from this have "set (awalk_verts x (p2@[e2]@p1)) ⊆ relations (Join l r)"
      using p1_def p2_def awalk_verts_append3 by auto
    ultimately show ?thesis by blast
  next
    case 3
    then obtain x' y' e where e_def:
        "x' ∈ relations l" "y' ∈ relations r" "tail G e = x'" "head G e = y'" "e ∈ arcs G"
      using Join.prems(2) by auto
    obtain p1 where p1_def: "awalk y' p1 y ∧ set (awalk_verts y' p1) ⊆ relations r"
      using Join.IH(2) Join.prems(1,2) 3(2) matching_rels_trans e_def(2) by fastforce
    obtain p2 where p2_def: "awalk x p2 x' ∧ set (awalk_verts x p2) ⊆ relations l"
      using Join.IH(1) Join.prems(1,2) 3(1) matching_rels_trans e_def(1) by fastforce
    have "awalk x (p2@[e]@p1) y"
      using e_def(3-5) p1_def p2_def awalk_appendI arc_implies_awalk by blast
    moreover from this have "set (awalk_verts x (p2@[e]@p1)) ⊆ relations (Join l r)"
      using p1_def p2_def awalk_verts_append3 by auto
    ultimately show ?thesis by blast
  next
    case 4
    then show ?thesis using Join.IH(2)[of x y] Join.prems(1,2) matching_rels_trans by auto
  qed
qed
lemma no_cross_apath:
  "⟦matching_rels t; no_cross_products t; x ∈ relations t; y ∈ relations t⟧
    ⟹ ∃p. apath x p y ∧ set (awalk_verts x p) ⊆ relations t"
  using no_cross_awalk apath_awalk_to_apath awalk_to_apath_verts_subset by blast
lemma no_cross_reachable:
  "⟦matching_rels t; no_cross_products t; x ∈ relations t; y ∈ relations t⟧ ⟹ x →⇧* y"
  using no_cross_awalk reachable_awalk by blast
corollary reachable_if_no_cross:
  "⟦∃t. relations t = verts G ∧ no_cross_products t; x ∈ verts G; y ∈ verts G⟧ ⟹ x →⇧* y"
  using no_cross_reachable matching_rels_def by blast
lemma remove_sel_sym:
  "⟦tail G e⇩1 = head G e⇩2; head G e⇩1 = tail G e⇩2⟧ ⟹ (remove_sel x) e⇩1 = (remove_sel x) e⇩2"
  by(metis (no_types, lifting) mem_Collect_eq not_arc_sel_1 remove_sel_def sel_sym)+
lemma remove_sel_1: "e ∉ arcs G ⟹ (remove_sel x) e = 1"
  apply(cases "e∈{a ∈ arcs G. tail G a = x ∨ head G a = x}")
  by(auto simp: not_arc_sel_1 sel_sym remove_sel_def)
lemma del_vert_remove_sel_1:
  assumes "e ∉ arcs ((del_vert x))"
  shows "(remove_sel x) e = 1"
proof(cases "e∈{a ∈ arcs G. tail G a = x ∨ head G a = x}")
  case True
  then show ?thesis by (simp add: remove_sel_def)
next
  case False
  then have "e ∉ arcs G" using assms arcs_del_vert by simp
  then show ?thesis using remove_sel_def not_arc_sel_1 by simp
qed
lemma remove_sel_pos: "remove_sel x e > 0"
  by(cases "e∈{a ∈ arcs G. tail G a = x ∨ head G a = x}") (auto simp: remove_sel_def sel_pos)
lemma remove_sel_leq_1: "remove_sel x e ≤ 1"
  by(cases "e∈{a ∈ arcs G. tail G a = x ∨ head G a = x}") (auto simp: remove_sel_def sel_leq_1)
lemma del_vert_pos_cards: "x ∈ verts (del_vert y) ⟹ cf x > 0"
  by(cases "x=y") (auto simp: remove_sel_def del_vert_def pos_cards)
lemma del_vert_remove_sel_query_graph:
  "query_graph G sel cf ⟹ query_graph (del_vert x) (remove_sel x) cf"
  by (simp add: del_vert_pos_cards del_vert_remove_sel_1 graph_del_vert remove_sel_sym
      remove_sel_leq_1 remove_sel_pos query_graph.intro graph_axioms head_del_vert
      query_graph_axioms_def tail_del_vert)
lemma finite_nempty_set_min:
  assumes "xs ≠ {}" and "finite xs"
  shows "∃x. min_degree xs x"
proof -
  have "finite xs" using assms(2) by simp
  then show ?thesis
  using assms proof (induction "xs" rule: finite_induct)
    case empty
    then show ?case by simp
  next
    case ind: (insert x xs)
    then show ?case
    proof(cases xs)
      case emptyI
      then show ?thesis by (metis order_refl singletonD singletonI)
    next
      case (insertI xs' x')
      then have "∃a. min_degree xs a" using ind by simp
      then show ?thesis
        using ind by (metis order_trans insert_iff le_cases)
    qed
  qed
qed
lemma no_cross_reachable_graph':
  "⟦∃t. relations t = verts G ∧ no_cross_products t; x∈verts G; y∈verts G⟧
    ⟹ x →⇧*⇘mk_symmetric G⇙ y"
  by (simp add: reachable_mk_symmetricI reachable_if_no_cross)
lemma verts_nempty_if_tree: "∃t. relations t ⊆ verts G ⟹ verts G ≠ {}"
  using relations_nempty by fast
lemma connected_if_tree: "∃t. relations t = verts G ∧ no_cross_products t ⟹ connected G"
  using no_cross_reachable_graph' connected_def strongly_connected_def verts_nempty_if_tree
  by fastforce
end
locale nempty_query_graph = query_graph +
  assumes non_empty: "verts G ≠ {}"
subsection ‹Pair Query Graph›
text ‹Alternative definition based on pair graphs›
locale pair_query_graph = pair_graph +
  fixes sel :: "('a × 'a) weight_fun"
  fixes cf :: "'a ⇒ real"
  assumes sel_sym: "⟦tail G e⇩1 = head G e⇩2; head G e⇩1 = tail G e⇩2⟧ ⟹ sel e⇩1 = sel e⇩2"
      and not_arc_sel_1: "e ∉ parcs G ⟹ sel e = 1"
      and sel_pos: "sel e > 0"
      and sel_leq_1: "sel e ≤ 1"
      and pos_cards: "x ∈ pverts G ⟹ cf x > 0"
sublocale pair_query_graph ⊆ query_graph
  by(unfold_locales) (auto simp: sel_sym not_arc_sel_1 sel_pos sel_leq_1 pos_cards)
context pair_query_graph
begin
lemma "matching_sel f ⟷ (∀x y. sel (x,y) = f x y)"
  using matching_sel_def sel_sym by fastforce
end
end