Theory ASC_Example

theory ASC_Example
  imports ASC_Hoare
begin


section ‹ Example product machines and properties ›

text ‹
This section provides example FSMs and shows that the assumptions on the inputs of the adaptive
state counting algorithm are not vacuous.
›


subsection ‹ Constructing FSMs from transition relations ›

text ‹
This subsection provides a function to more easily create FSMs, only requiring a set of
transition-tuples and an initial state.
›


fun from_rel :: "('state × ('in × 'out) × 'state) set ⇒ 'state ⇒ ('in, 'out, 'state) FSM" where
"from_rel rel q0 = ⦇ succ = λ io p . { q . (p,io,q) ∈ rel },
                    inputs = image (fst ∘ fst ∘ snd) rel,
                    outputs = image (snd ∘ fst ∘ snd) rel,
                    initial = q0 ⦈"



lemma nodes_from_rel : "nodes (from_rel rel q0) ⊆ insert q0 (image (snd ∘ snd) rel)"
  (is "nodes ?M ⊆ insert q0 (image (snd ∘ snd) rel)")
proof -
  have "⋀ q io p . q ∈ succ ?M io p ⟹ q ∈ image (snd ∘ snd) rel"
    by force
  have "⋀ q . q ∈ nodes ?M ⟹ q = q0 ∨ q ∈ image (snd ∘ snd) rel"
  proof -
    fix q assume "q ∈ nodes ?M"
    then show "q = q0 ∨ q ∈ image (snd ∘ snd) rel"
    proof (cases rule: FSM.nodes.cases)
      case initial
      then show ?thesis by auto
    next
      case (execute p a)
      then show ?thesis
        using ‹⋀ q io p . q ∈ succ ?M io p ⟹ q ∈ image (snd ∘ snd) rel› by blast
    qed
  qed
  then show "nodes ?M ⊆ insert q0 (image (snd ∘ snd) rel)"
    by blast
qed



fun well_formed_rel :: "('state × ('in × 'out) × 'state) set ⇒ bool" where
  "well_formed_rel rel = (finite rel
                          ∧ (∀ s1 x y . (x ∉ image (fst ∘ fst ∘ snd) rel
                                            ∨ y ∉ image (snd ∘ fst ∘ snd) rel)
                                        ⟶ ¬(∃ s2 . (s1,(x,y),s2) ∈ rel))
                          ∧ rel ≠ {})"

lemma well_formed_from_rel :
  assumes "well_formed_rel rel"
  shows "well_formed (from_rel rel q0)"  (is "well_formed ?M")
proof -
  have "nodes ?M ⊆ insert q0 (image (snd ∘ snd) rel)"
    using nodes_from_rel[of rel q0] by auto
  moreover have "finite (insert q0 (image (snd ∘ snd) rel))"
    using assms by auto
  ultimately have "finite (nodes ?M)"
    by (simp add: Finite_Set.finite_subset)
  moreover have "finite (inputs ?M)" "finite (outputs ?M)"
    using assms by auto
  ultimately have "finite_FSM ?M"
    by auto

  moreover have "inputs ?M ≠ {}"
    using assms by auto
  moreover have "outputs ?M ≠ {}"
    using assms by auto
  moreover have "⋀ s1 x y . (x ∉ inputs ?M ∨ y ∉ outputs ?M) ⟶ succ ?M (x,y) s1 = {}"
    using assms by auto

  ultimately show ?thesis
    by auto
qed




fun completely_specified_rel_over :: "('state × ('in × 'out) × 'state) set ⇒ 'state set ⇒ bool"
  where
  "completely_specified_rel_over rel nods = (∀ s1 ∈ nods .
                                                ∀ x ∈ image (fst ∘ fst ∘ snd) rel .
                                                  ∃ y ∈ image (snd ∘ fst ∘ snd) rel .
                                                    ∃ s2 . (s1,(x,y),s2) ∈ rel)"

lemma completely_specified_from_rel :
  assumes "completely_specified_rel_over rel (nodes ((from_rel rel q0)))"
  shows "completely_specified (from_rel rel q0)"  (is "completely_specified ?M")
  unfolding completely_specified.simps
proof
  fix s1 assume "s1 ∈ nodes (from_rel rel q0)"
  show  "∀x∈inputs ?M. ∃y∈outputs ?M. ∃s2. s2 ∈ succ ?M (x, y) s1"
  proof
    fix x assume "x ∈ inputs (from_rel rel q0)"
    then have "x ∈  image (fst ∘ fst ∘ snd) rel"
      using assms by auto

    obtain y s2 where "y ∈ image (snd ∘ fst ∘ snd) rel" "(s1,(x,y),s2) ∈ rel"
      using assms ‹s1 ∈ nodes (from_rel rel q0)› ‹x ∈  image (fst ∘ fst ∘ snd) rel›
      by (meson completely_specified_rel_over.elims(2))

    then have "y ∈ outputs (from_rel rel q0)" "s2 ∈ succ (from_rel rel q0) (x, y) s1"
      by auto

    then show "∃y∈outputs (from_rel rel q0). ∃s2. s2 ∈ succ (from_rel rel q0) (x, y) s1"
      by blast
  qed
qed





fun observable_rel :: "('state × ('in × 'out) × 'state) set ⇒ bool" where
  "observable_rel rel = (∀ io s1 . { s2 . (s1,io,s2) ∈ rel } = {}
                                    ∨ (∃ s2 . { s2' . (s1,io,s2') ∈ rel } = {s2}))"

lemma observable_from_rel :
  assumes "observable_rel rel"
  shows "observable (from_rel rel q0)"  (is "observable ?M")
proof -
  have "⋀ io s1 . { s2 . (s1,io,s2) ∈ rel } = succ ?M io s1"
    by auto
  then show ?thesis using assms by auto
qed





abbreviation "OFSM_rel rel q0 ≡ well_formed_rel rel
                                ∧ completely_specified_rel_over rel (nodes (from_rel rel q0))
                                ∧ observable_rel rel"

lemma OFMS_from_rel :
  assumes "OFSM_rel rel q0"
  shows "OFSM (from_rel rel q0)"
  by (metis assms completely_specified_from_rel observable_from_rel well_formed_from_rel)




subsection ‹ Example FSMs and properties ›



abbreviation "MS_rel :: (nat×(nat×nat)×nat) set ≡ {(0,(0,0),1), (0,(0,1),1), (1,(0,2),1)}"
abbreviation "MS :: (nat,nat,nat) FSM ≡ from_rel MS_rel 0"

abbreviation "MI_rel :: (nat×(nat×nat)×nat) set ≡ {(0,(0,0),1), (0,(0,1),1), (1,(0,2),0)}"
abbreviation "MI :: (nat,nat,nat) FSM ≡ from_rel MI_rel 0"

lemma example_nodes :
  "nodes MS = {0,1}" "nodes MI = {0,1}"
proof -
  have "0 ∈ nodes MS" by auto
  have "1 ∈ succ MS (0,0) 0" by auto
  have "1 ∈ nodes MS"
    by (meson ‹0 ∈ nodes MS› ‹1 ∈ succ MS (0, 0) 0› succ_nodes)

  have "{0,1} ⊆ nodes MS"
    using ‹0 ∈ nodes MS› ‹1 ∈ nodes MS› by auto
  moreover have "nodes MS ⊆ {0,1}"
    using nodes_from_rel[of MS_rel 0] by auto
  ultimately show "nodes MS = {0,1}"
    by blast
next
  have "0 ∈ nodes MI" by auto
  have "1 ∈ succ MI (0,0) 0" by auto
  have "1 ∈ nodes MI"
    by (meson ‹0 ∈ nodes MI› ‹1 ∈ succ MI (0, 0) 0› succ_nodes)

  have "{0,1} ⊆ nodes MI"
    using ‹0 ∈ nodes MI› ‹1 ∈ nodes MI› by auto
  moreover have "nodes MI ⊆ {0,1}"
    using nodes_from_rel[of MI_rel 0] by auto
  ultimately show "nodes MI = {0,1}"
    by blast
qed



lemma example_OFSM :
  "OFSM MS" "OFSM MI"
proof -
  have "well_formed_rel MS_rel"
    unfolding well_formed_rel.simps by auto

  moreover have "completely_specified_rel_over MS_rel (nodes (from_rel MS_rel 0))"
    unfolding completely_specified_rel_over.simps
  proof
    fix s1 assume "(s1::nat) ∈ nodes (from_rel MS_rel 0)"
    then have "s1 ∈ (insert 0 (image (snd ∘ snd) MS_rel))"
      using nodes_from_rel[of MS_rel 0] by blast
    moreover have "completely_specified_rel_over MS_rel (insert 0 (image (snd ∘ snd) MS_rel))"
      unfolding completely_specified_rel_over.simps by auto
    ultimately show "∀x∈(fst ∘ fst ∘ snd) ` MS_rel.
                      ∃y∈(snd ∘ fst ∘ snd) ` MS_rel. ∃s2. (s1, (x, y), s2) ∈ MS_rel"
      by simp
  qed

  moreover have "observable_rel MS_rel"
    by auto

  ultimately have "OFSM_rel MS_rel 0"
    by auto

  then show "OFSM MS"
    using OFMS_from_rel[of MS_rel 0] by linarith
next
  have "well_formed_rel MI_rel"
    unfolding well_formed_rel.simps by auto

  moreover have "completely_specified_rel_over MI_rel (nodes (from_rel MI_rel 0))"
    unfolding completely_specified_rel_over.simps
  proof
    fix s1 assume "(s1::nat) ∈ nodes (from_rel MI_rel 0)"
    then have "s1 ∈ (insert 0 (image (snd ∘ snd) MI_rel))"
      using nodes_from_rel[of MI_rel 0] by blast
    have "completely_specified_rel_over MI_rel (insert 0 (image (snd ∘ snd) MI_rel))"
      unfolding completely_specified_rel_over.simps by auto
    show "∀x∈(fst ∘ fst ∘ snd) ` MI_rel.
            ∃y∈(snd ∘ fst ∘ snd) ` MI_rel. ∃s2. (s1, (x, y), s2) ∈ MI_rel"
      by (meson ‹completely_specified_rel_over MI_rel (insert 0 ((snd ∘ snd) ` MI_rel))›
          ‹s1 ∈ insert 0 ((snd ∘ snd) ` MI_rel)› completely_specified_rel_over.elims(2))
  qed

  moreover have "observable_rel MI_rel"
    by auto

  ultimately have "OFSM_rel MI_rel 0"
    by auto

  then show "OFSM MI"
    using OFMS_from_rel[of MI_rel 0] by linarith
qed



lemma example_fault_domain : "asc_fault_domain MS MI 2"
proof -
  have "inputs MS = inputs MI"
    by auto
  moreover have "card (nodes MI) ≤ 2"
    using example_nodes(2) by auto
  ultimately show "asc_fault_domain MS MI 2"
    by auto
qed

abbreviation "FAILI :: (nat×nat) ≡ (3,3)"
abbreviation "PMI :: (nat, nat, nat×nat) FSM ≡ ⦇
            succ = (λ a (p1,p2) . (if (p1 ∈ nodes MS ∧ p2 ∈ nodes MI ∧ (fst a ∈ inputs MS)
                                        ∧ (snd a ∈ outputs MS ∪ outputs MI))
                                    then (if (succ MS a p1 = {} ∧ succ MI a p2 ≠ {})
                                      then {FAILI}
                                      else (succ MS a p1 × succ MI a p2))
                                    else {})),
            inputs = inputs MS,
            outputs = outputs MS ∪ outputs MI,
            initial = (initial MS, initial MI)
          ⦈"

lemma example_productF : "productF MS MI FAILI PMI"
proof -
  have "inputs MS = inputs MI"
    by auto
  moreover have "fst FAILI ∉ nodes MS"
    using example_nodes(1) by auto
  moreover have "snd FAILI ∉ nodes MI"
    using example_nodes(2) by auto
  ultimately show ?thesis
    unfolding productF.simps by blast
qed



abbreviation "VI :: nat list set ≡ {[],[0]}"

lemma example_det_state_cover : "is_det_state_cover MS VI"
proof -
  have "d_reaches MS (initial MS) [] (initial MS)"
    by auto
  then have "initial MS ∈ d_reachable MS (initial MS)"
    unfolding d_reachable.simps by blast

  have "d_reached_by MS (initial MS) [0] 1 [1] [0]"
  proof
    show "length [0] = length [0] ∧
    length [0] = length [1] ∧ path MS (([0] || [0]) || [1]) (initial MS)
                            ∧ target (([0] || [0]) || [1]) (initial MS) = 1"
      by auto

    have "⋀ys2 tr2.
       length [0] = length ys2
          ∧ length [0] = length tr2
          ∧ path MS (([0] || ys2) || tr2) (initial MS)
            ⟶ target (([0] || ys2) || tr2) (initial MS) = 1"
    proof
      fix ys2 tr2 assume "length [0] = length ys2 ∧ length [0] = length tr2
                            ∧ path MS (([0] || ys2) || tr2) (initial MS)"
      then have "length ys2 = 1" "length tr2 = 1" "path MS (([0] || ys2) || tr2) (initial MS)"
        by auto
      moreover obtain y2 where "ys2 = [y2]"
        using ‹length ys2 = 1›
        by (metis One_nat_def ‹length [0] = length ys2 ∧ length [0] = length tr2
            ∧ path MS (([0] || ys2) || tr2) (initial MS)› append.simps(1) append_butlast_last_id
            butlast_snoc length_butlast length_greater_0_conv list.size(3) nat.simps(3))
      moreover obtain t2 where "tr2 = [t2]"
        using ‹length tr2 = 1›
        by (metis One_nat_def ‹length [0] = length ys2 ∧ length [0] = length tr2
            ∧ path MS (([0] || ys2) || tr2) (initial MS)› append.simps(1) append_butlast_last_id
            butlast_snoc length_butlast length_greater_0_conv list.size(3) nat.simps(3))
      ultimately have "path MS [((0,y2),t2)] (initial MS)"
        by auto
      then have "t2 ∈ succ MS (0,y2) (initial MS)"
        by auto
      moreover have "⋀ y . succ MS (0,y) (initial MS) ⊆ {1}"
        by auto
      ultimately have "t2 = 1"
        by blast

      show "target (([0] || ys2) || tr2) (initial MS) = 1"
        using ‹ys2 = [y2]› ‹tr2 = [t2]› ‹t2 = 1› by auto
    qed
    then show "∀ys2 tr2.
       length [0] = length ys2 ∧ length [0] = length tr2
          ∧ path MS (([0] || ys2) || tr2) (initial MS)
            ⟶ target (([0] || ys2) || tr2) (initial MS) = 1"
      by auto
  qed

  then have "d_reaches MS (initial MS) [0] 1"
    unfolding d_reaches.simps by blast
  then have "1 ∈ d_reachable MS (initial MS)"
    unfolding d_reachable.simps by blast

  then have "{0,1} ⊆ d_reachable MS (initial MS)"
    using ‹initial MS ∈ d_reachable MS (initial MS)› by auto
  moreover have "d_reachable MS (initial MS) ⊆ nodes MS"
  proof
    fix s assume "s∈d_reachable MS (initial MS)"
    then have "s ∈ reachable MS (initial MS)"
      using d_reachable_reachable by auto
    then show "s ∈ nodes MS"
      by blast
  qed
  ultimately have "d_reachable MS (initial MS) = {0,1}"
    using example_nodes(1) by blast



  fix f' :: "nat ⇒ nat list"
  let ?f = "f'( 0 := [], 1 := [0])"

  have "is_det_state_cover_ass MS ?f"
    unfolding is_det_state_cover_ass.simps
  proof
    show "?f (initial MS) = []" by auto
    show "∀s∈d_reachable MS (initial MS). d_reaches MS (initial MS) (?f s) s"
    proof
      fix s assume "s∈d_reachable MS (initial MS)"
      then have "s ∈ reachable MS (initial MS)"
        using d_reachable_reachable by auto
      then have "s ∈ nodes MS"
        by blast
      then have "s = 0 ∨ s = 1"
        using example_nodes(1) by blast
      then show "d_reaches MS (initial MS) (?f s) s"
      proof
        assume "s = 0"
        then show "d_reaches MS (initial MS) (?f s) s"
          using ‹d_reaches MS (initial MS) [] (initial MS)› by auto
      next
        assume "s = 1"
        then show "d_reaches MS (initial MS) (?f s) s"
          using ‹d_reaches MS (initial MS) [0] 1› by auto
      qed
    qed
  qed

  moreover have "VI = image ?f (d_reachable MS (initial MS))"
    using ‹d_reachable MS (initial MS) = {0,1}› by auto

  ultimately show ?thesis
    unfolding is_det_state_cover.simps by blast
qed



abbreviation "ΩI::(nat,nat) ATC set ≡ { Node 0 (λ y . Leaf) }"

lemma "applicable_set MS ΩI"
  by auto


lemma example_test_tools : "test_tools MS MI FAILI PMI VI ΩI"
  using example_productF example_det_state_cover by auto




lemma OFSM_not_vacuous :
  "∃ M :: (nat,nat,nat) FSM . OFSM M"
  using example_OFSM(1) by blast


lemma fault_domain_not_vacuous :
  "∃ (M2::(nat,nat,nat) FSM) (M1::(nat,nat,nat) FSM) m . asc_fault_domain M2 M1 m"
  using example_fault_domain by blast


lemma test_tools_not_vacuous :
  "∃ (M2::(nat,nat,nat) FSM)
     (M1::(nat,nat,nat) FSM)
     (FAIL::(nat×nat))
     (PM::(nat,nat,nat×nat) FSM)
     (V::(nat list set))
     (Ω::(nat,nat) ATC set) . test_tools M2 M1 FAIL PM V Ω"
proof (rule exI, rule exI)
  show "∃ FAIL PM V Ω. test_tools MS MI FAIL PM V Ω"
    using example_test_tools by blast
qed

lemma precondition_not_vacuous :
  shows "∃ (M2::(nat,nat,nat) FSM)
           (M1::(nat,nat,nat) FSM)
           (FAIL::(nat×nat))
           (PM::(nat,nat,nat×nat) FSM)
           (V::(nat list set))
           (Ω::(nat,nat) ATC set)
           (m :: nat) .
              OFSM M1 ∧ OFSM M2 ∧ asc_fault_domain M2 M1 m ∧ test_tools M2 M1 FAIL PM V Ω"
proof (intro exI)
  show "OFSM MI ∧ OFSM MS ∧ asc_fault_domain MS MI 2 ∧ test_tools MS MI FAILI PMI VI ΩI"
    using example_OFSM(2,1) example_fault_domain example_test_tools by linarith
qed

end