Theory Acyclicity
theory Acyclicity
  imports Main
begin
section ‹Acyclicity›
text ‹ Two of the discussed bounding algorithms ("top-down" and "bottom-up") exploit acyclicity
of the system under projection on sets of state variables closed under mutual variable dependency. 
[Abdulaziz et al., p.11] 
This specific notion of acyclicity is formalised using topologically sorted dependency graphs 
induced by the variable dependency relation. [Abdulaziz et al., p.14]›
subsection "Topological Sorting of Dependency Graphs"
 
fun top_sorted_abs where
  "top_sorted_abs R [] = True"
| "top_sorted_abs R (h # l) = (list_all (λx. ¬R x h) l ∧ top_sorted_abs R l)"
lemma top_sorted_abs_mem: 
  assumes "(top_sorted_abs R (h # l))" "(ListMem x l)"
  shows "(¬ R x h)"
  using assms
  by (auto simp add: ListMem_iff list.pred_set)
lemma top_sorted_cons: 
  assumes "top_sorted_abs R (h # l)"
  shows "(top_sorted_abs R l)"
  using assms
  by simp
subsection ‹The Weightiest Path Function (wlp)›
text ‹ The weightiest path function is a generalization of an algorithm which computes the
longest path in a DAG starting at a given vertex `v`. Its arguments are the relation `R` which
induces the graph, a weighing function `w` assigning weights to vertices, an accumulating functions
`f` and `g` which aggregate vertex weights into a path weight and the weights of different paths
respectively, the considered vertex and the graph represented as a topological sorted list. 
[Abdulaziz et al., p.18] 
Typical weight combining functions have the properties defined by `geq\_arg` and `increasing`. 
[Abdulaziz et al., p.18] ›
fun wlp where
  "wlp R w g f x [] = w x"
| "wlp R w g f x (h # l) = (if R x h
    then g (f (w x) (wlp R w g f h l)) (wlp R w g f x l)
    else wlp R w g f x l
  )"
definition geq_arg where 
  "geq_arg f ≡ (∀x y. (x ≤ f x y) ∧ (y ≤ f x y))"
lemma individual_weight_less_eq_lp: 
  fixes w :: "'a ⇒ nat"
  assumes "geq_arg g"
  shows "(w x ≤ wlp R w g f x l)"
  using assms
  unfolding geq_arg_def
proof (induction l arbitrary: R w g f x)
  case (Cons a l)
  then show ?case
    using Cons.IH Cons.prems
  proof (cases "R x a")
    case True
    then show ?thesis 
      using Cons le_trans wlp.simps(2)
      by smt
  next
    case False
    then show ?thesis 
      using Cons
      by simp
  qed
qed simp
lemma lp_geq_lp_from_successor:
  fixes vtx1 and f g :: "nat ⇒ nat ⇒ nat"
  assumes "geq_arg f" "geq_arg g" "(∀vtx. ListMem vtx G ⟶ ¬R vtx vtx)" "R vtx2 vtx1" 
    "ListMem vtx1 G" "top_sorted_abs R G" 
  shows "(f (w vtx2) (wlp R w g f vtx1 G) ≤ (wlp R w g f vtx2 G))" 
  using assms
  unfolding geq_arg_def
proof (induction G arbitrary: vtx1 f g R vtx2)
  case Nil
  then show ?case 
    using ListMem_iff
    by fastforce
next
  case (Cons a G)
  show ?case 
  proof (auto)
    assume P1: "R vtx1 a" "R vtx2 a"
    then show "
        f (w vtx2) (g (f (w vtx1) (wlp R w g f a G)) (wlp R w g f vtx1 G))
        ≤ g (f (w vtx2) (wlp R w g f a G)) (wlp R w g f vtx2 G)"
      using Cons.prems(3, 5, 6)
      by (metis ListMem_iff set_ConsD top_sorted_abs_mem)
  next 
    assume P2: "R vtx1 a" "¬ R vtx2 a" 
    then show "
        f (w vtx2) (g (f (w vtx1) (wlp R w g f a G)) (wlp R w g f vtx1 G)) 
        ≤ wlp R w g f vtx2 G"
      using Cons.prems(4, 5, 6)
      by (metis ListMem_iff set_ConsD top_sorted_abs_mem) 
  next 
    assume P3: "¬ R vtx1 a" "R vtx2 a" 
    then show "
        f (w vtx2) (wlp R w g f vtx1 G) 
        ≤ g (f (w vtx2) (wlp R w g f a G)) (wlp R w g f vtx2 G)"
    proof -
      have f1: "∀n na. n ≤ g n na ∧ na ≤ g n na"
        using Cons.prems(2) by blast
      have f2: "vtx1 = a ∨ vtx1 ∈ set G"
        by (meson Cons.prems(5) ListMem_iff set_ConsD)
      obtain aa :: "('a ⇒ 'a ⇒ bool) ⇒ 'a" where
        "∀x2. (∃v5. ListMem v5 G ∧ x2 v5 v5) = (ListMem (aa x2) G ∧ x2 (aa x2) (aa x2))"
        by moura
      then have "
          ListMem (aa R) G ∧ R (aa R) (aa R) 
          ∨ ¬ ListMem vtx1 G ∨ f (w vtx2) (wlp R w g f vtx1 G) ≤ wlp R w g f vtx2 G"
        using f1 by (metis (no_types) Cons.IH Cons.prems(1, 4, 6) top_sorted_cons)
      then show ?thesis
        using f2 f1 by (meson Cons.prems(3) ListMem_iff insert le_trans)
    qed
  next 
    assume P4: "¬ R vtx1 a" "¬ R vtx2 a"
    then show "f (w vtx2) (wlp R w g f vtx1 G) ≤ wlp R w g f vtx2 G"
    proof -
      have f1: "top_sorted_abs R G"
        using Cons.prems(6) by fastforce
      have "ListMem vtx1 G"
        by (metis Cons.prems(4) Cons.prems(5) ListMem_iff P4(2) set_ConsD)
      then show ?thesis
        using f1 by (simp add: Cons.IH Cons.prems(1, 2, 3, 4) insert)
    qed 
  qed
qed
definition increasing where
  "increasing f ≡ (∀e b c d. (e ≤ c) ∧ (b ≤ d) ⟶ (f e b ≤ f c d))"
lemma weight_fun_leq_imp_lp_leq: "⋀x.
  (increasing f)
  ⟹ (increasing g)
  ⟹ (∀y. ListMem y l ⟶ w1 y ≤ w2 y) 
  ⟹ (w1 x ≤ w2 x)
  ⟹ (wlp R w1 g f x l ≤ wlp R w2 g f x l)
"
  unfolding increasing_def
  by (induction l) (auto simp add: elem insert)
lemma wlp_congruence_rule: 
  fixes l1 l2 R1 R2 w1 w2 g1 g2 f1 f2 x1 x2 
  assumes "(l1 = l2)" "(∀y. ListMem y l2 ⟶ (R1 x1 y = R2 x2 y))"
    "(∀y. ListMem y l2 ⟶ (R1 y x1 = R2 y x2))" "(w1 x1 = w2 x2)" 
    "(∀y1 y2. (y1 = y2) ⟶ (f1 (w1 x1) y1 = f2 (w2 x2) y2))" 
    "(∀y1 y2 z1 z2. (y1 = y2) ∧ (z1 = z2) ⟶ ((g1 (f1 (w1 x1) y1) z1) = (g2 (f2 (w2 x2) y2) z2)))"
    "(∀x y. ListMem x l2 ∧ ListMem y l2 ⟶ (R1 x y = R2 x y))"
    "(∀x. ListMem x l2 ⟶ (w1 x = w2 x))"
    "(∀x y z. ListMem x l2 ⟶ (g1 (f1 (w1 x) y) z = g2 (f2 (w2 x) y) z))"
    "(∀x y. ListMem x l2 ⟶ (f1 (w1 x) y = f2 (w1 x) y))"
  shows "((wlp R1 w1 g1 f1 x1 l1) = (wlp R2 w2 g2 f2 x2 l2))"
  using assms
proof (induction l2 arbitrary: l1 x1 x2)
  case (Cons a l2)
  then have "(wlp R1 w1 g1 f1 x1 l2) = (wlp R2 w2 g2 f2 x2 l2)"
    using Cons
    by (simp add: insert)
  moreover have "(wlp R1 w1 g1 f1 a l2) = (wlp R2 w2 g2 f2 a l2)"
    using Cons
    by (simp add: elem insert)
  ultimately show ?case
    by (simp add: Cons.prems(1,2, 6) elem)
qed auto
lemma wlp_ite_weights: 
  fixes x
  assumes "∀y. ListMem y l1 ⟶ P y" "P x"
  shows "((wlp R (λy. if P y then w1 y else w2 y) g f x l1) = (wlp R w1 g f x l1))"
  using assms 
proof (induction l1 arbitrary: R P w1 w2 f g)
  case (Cons a l1)
  let ?w1="(λy. if P y then w1 y else w2 y)"
  let ?w2="w1"
  {
    have "∀y. ListMem y l1 ⟶ P y" 
      using Cons.prems(1) insert
      by fast
    then have "((wlp R (λy. if P y then w1 y else w2 y) g f x l1) = (wlp R w1 g f x l1))" 
      using Cons.prems(2) Cons.IH
      by blast
  }
  note 1 = this
  { 
    have "(if P x then w1 x else w2 x) = w1 x" 
      "∀y1 y2. y1 = y2 ⟶ f (if P x then w1 x else w2 x) y1 = f (w1 x) y2"
      "∀y1 y2 z1 z2. 
        y1 = y2 ∧ z1 = z2 
        ⟶ g (f (if P x then w1 x else w2 x) y1) z1 = g (f (w1 x) y2) z2"
      "∀x. ListMem x (a # l1) ⟶ (if P x then w1 x else w2 x) = w1 x"
      "∀x y z. 
        ListMem x (a # l1) 
        ⟶ g (f (if P x then w1 x else w2 x) y) z = g (f (w1 x) y) z"
      "∀x y.
        ListMem x (a # l1) ⟶ f (if P x then w1 x else w2 x) y = f (if P x then w1 x else w2 x) y"
      using Cons.prems(1, 2)
      by simp+
    then have "wlp R (λy. if P y then w1 y else w2 y) g f x (a # l1) = wlp R w1 g f x (a # l1)"
      using Cons wlp_congruence_rule[of "a # l1" "a # l1" R x R x "?w1" "?w2" f f g g] 
      by blast
  }
  then show ?case
    by blast
qed auto
lemma map_wlp_ite_weights: "
  (∀x. ListMem x l1 ⟶ P x) 
  ⟹ (∀x. ListMem x l2 ⟶ P x) 
  ⟹ (
    map (λx. wlp R (λy. if P y then w1 y else w2 y) g f x l1) l2 
    = map (λx. wlp R w1 g f x l1) l2
  )
"
  apply(induction l2)
   apply(auto)
  subgoal by (simp add: elem wlp_congruence_rule)
  subgoal by (simp add: insert)
  done
lemma wlp_weight_lamda_exp: "⋀x. wlp R w g f x l = wlp R (λy. w y) g f x l"
proof -
  fix x
  show "wlp R w g f x l = wlp R (λy. w y) g f x l" 
    by(induction l) auto
qed
lemma img_wlp_ite_weights: "
  (∀x. ListMem x l ⟶ P x) 
  ⟹ (∀x. x ∈ s ⟶ P x) 
  ⟹ (
    (λx. wlp R (λy. if P y then w1 y else w2 y) g f x l) ` s 
    = (λx. wlp R w1 g f x l) ` s
  )
"
proof -
  assume P1: "∀x. ListMem x l ⟶ P x"
  assume P2: "∀x. x ∈ s ⟶ P x"
  show "(
    (λx. wlp R (λy. if P y then w1 y else w2 y) g f x l) ` s 
    = (λx. wlp R w1 g f x l) ` s
  )" 
    by (auto simp add:  P1 P2 image_iff wlp_ite_weights)
qed
end