Theory Monitor

(*<*)
theory Monitor
  imports Checker_Code
begin
(*>*)

section ‹Unverified Explanation-Producing Monitoring Algorithm›

fun merge_part2_raw :: "('a  'b  'c)  ('d set × 'a) list  ('d set × 'b) list  ('d set × 'c) list" where
  "merge_part2_raw f [] _ = []"  
| "merge_part2_raw f ((P1, v1) # part1) part2 = 
    (let part12 = List.map_filter (λ(P2, v2). if P1  P2  {} then Some(P1  P2, f v1 v2) else None) part2 in
     let part2not1 = List.map_filter (λ(P2, v2). if P2 - P1  {} then Some(P2 - P1, v2) else None) part2 in
     part12 @ (merge_part2_raw f part1 part2not1))"

fun merge_part3_raw :: "('a  'b  'c  'e)  ('d set × 'a) list  ('d set × 'b) list  ('d set × 'c) list  ('d set × 'e) list" where
  "merge_part3_raw f [] _ _ = []" 
| "merge_part3_raw f _ [] _ = []" 
| "merge_part3_raw f _ _ [] = []"
| "merge_part3_raw f part1 part2 part3 = merge_part2_raw (λpt3 f'. f' pt3) part3 (merge_part2_raw f part1 part2)"

lemma partition_on_empty_iff: 
  "partition_on X 𝒫  𝒫 = {}  X = {}"
  "partition_on X 𝒫  𝒫  {}  X  {}"
  by (auto simp: partition_on_def)

lemma wf_part_list_filter_inter: 
  defines "inP1 P1 f v1 part2 
     List.map_filter (λ(P2, v2). if P1  P2  {} then Some(P1  P2, f v1 v2) else None) part2"
  assumes "partition_on X (set (map fst ((P1, v1) # part1)))"
    and "partition_on X (set (map fst part2))"
  shows "partition_on P1 (set (map fst (inP1 P1 f v1 part2)))"
    and "distinct (map fst ((P1, v1) # part1))  distinct (map fst (part2)) 
    distinct (map fst (inP1 P1 f v1 part2))"
proof (rule partition_onI)
  show " (set (map fst (inP1 P1 f v1 part2))) = P1"
  proof -
    have "P2. (P1  P2  {}  (v2. (P2, v2)  set part2)  x  P2)  P1  P2  {}"
      if " (fst ` set part2) = P1   (fst ` set part1)" and "x  P1" for x
      using that by (metis (no_types, lifting) Int_iff UN_iff Un_Int_eq(3) empty_iff prod.collapse)
    with partition_onD1[OF assms(2)] partition_onD1[OF assms(3)] show ?thesis
      by (auto simp: map_filter_def inP1_def split: if_splits)
  qed
  show "A1 A2. A1  set (map fst (inP1 P1 f v1 part2)) 
    A2  set (map fst (inP1 P1 f v1 part2))  A1  A2  disjnt A1 A2" 
    using partition_onD2[OF assms(2)] partition_onD2[OF assms(3)]
    by (force simp: disjnt_iff map_filter_def disjoint_def inP1_def split: if_splits)
  show "{}  set (map fst (inP1 P1 f v1 part2))" 
    using assms
    by (auto simp: map_filter_def split: if_splits)
  show "distinct (map fst ((P1, v1) # part1))  distinct (map fst part2) 
    distinct (map fst (inP1 P1 f v1 part2))"
    using partition_onD2[OF assms(3), unfolded disjoint_def, simplified, rule_format]
    by (clarsimp simp: inP1_def map_filter_def distinct_map inj_on_def Ball_def) blast
qed

lemma wf_part_list_filter_minus: 
  defines "notinP2 P1 f v1 part2 
     List.map_filter (λ(P2, v2). if P2 - P1  {} then Some(P2 - P1, v2) else None) part2"
  assumes "partition_on X (set (map fst ((P1, v1) # part1)))"
    and "partition_on X (set (map fst part2))"
  shows "partition_on (X - P1) (set (map fst (notinP2 P1 f v1 part2)))"
    and "distinct (map fst ((P1, v1) # part1))  distinct (map fst (part2)) 
      distinct (map fst (notinP2 P1 f v1 part2))"
proof (rule partition_onI)
  show " (set (map fst (notinP2 P1 f v1 part2))) = X - P1"
  proof -
    have "P2. ((xP2. x  P1)  (v2. (P2, v2)  set part2))  (xP2. x  P1)  x  P2"
      if " (fst ` set part2) = P1   (fst ` set part1)" "x  P1" "(P1', v1)  set part1" "x  P1'" for x P1' v1
      using that by (metis (no_types, lifting) UN_iff Un_iff fst_conv prod.collapse)
    with partition_onD1[OF assms(2)] partition_onD1[OF assms(3)] show ?thesis
      by (auto simp: map_filter_def subset_eq split_beta notinP2_def split: if_splits)
  qed
  show "A1 A2. A1  set (map fst (notinP2 P1 f v1 part2)) 
    A2  set (map fst (notinP2 P1 f v1 part2))  A1  A2  disjnt A1 A2" 
    using partition_onD2[OF assms(3)]
    by (auto simp: disjnt_def map_filter_def disjoint_def notinP2_def Ball_def Bex_def image_iff split: if_splits)
  show "{}  set (map fst (notinP2 P1 f v1 part2))" 
    using assms
    by (auto simp: map_filter_def split: if_splits)
  show "distinct (map fst ((P1, v1) # part1))  distinct (map fst part2) 
    distinct (map fst ((notinP2 P1 f v1 part2)))"
    using partition_onD2[OF assms(3), unfolded disjoint_def]
    by (clarsimp simp: notinP2_def map_filter_def distinct_map inj_on_def Ball_def Bex_def image_iff) blast
qed

lemma wf_part_list_tail: 
  assumes "partition_on X (set (map fst ((P1, v1) # part1)))"
    and "distinct (map fst ((P1, v1) # part1))"
  shows "partition_on (X - P1) (set (map fst part1))"
    and "distinct (map fst part1)"
proof (rule partition_onI)
  show " (set (map fst part1)) = X - P1"
    using partition_onD1[OF assms(1)] partition_onD2[OF assms(1)] assms(2)
    by (auto simp: disjoint_def image_iff)
  show "A1 A2. A1  set (map fst part1)  A2  set (map fst part1)  A1  A2  disjnt A1 A2" 
    using partition_onD2[OF assms(1)]
    by (clarsimp simp: disjnt_def disjoint_def)
      (smt (verit, ccfv_SIG) Diff_disjoint Int_Diff Int_commute fst_conv)
  show "{}  set (map fst part1)" 
    using partition_onD3[OF assms(1)]
    by (auto simp: map_filter_def split: if_splits)
  show "distinct (map fst (part1))"
    using assms(2)
    by auto
qed

lemma partition_on_append: "partition_on X (set xs)  partition_on Y (set ys)  X  Y = {} 
  partition_on (X  Y) (set (xs @ ys))"
  by (auto simp: partition_on_def intro!: disjoint_union)

lemma wf_part_list_merge_part2_raw: 
  "partition_on X (set (map fst part1))  distinct (map fst part1) 
   partition_on X (set (map fst part2))  distinct (map fst part2) 
   partition_on X (set (map fst (merge_part2_raw f part1 part2))) 
     distinct (map fst (merge_part2_raw f part1 part2))"
proof(induct f part1 part2 arbitrary: X rule: merge_part2_raw.induct)
  case (2 f P1 v1 part1 part2)
  let ?inP1 = "List.map_filter (λ(P2, v2). if P1  P2  {} then Some (P1  P2, f v1 v2) else None) part2"
    and ?notinP1 = "List.map_filter (λ(P2, v2). if P2 - P1  {} then Some (P2 - P1, v2) else None) part2"
  have "P1  X = X"
    using "2.prems"
    by (auto simp: partition_on_def)
  have wf_part1: "partition_on (X - P1) (set (map fst part1))"
    "distinct (map fst part1)"
    using wf_part_list_tail "2.prems" by auto
  moreover have wf_notinP1: "partition_on (X - P1) (set (map fst ?notinP1))" 
    "distinct (map fst (?notinP1))"
    using wf_part_list_filter_minus[OF 2(2)[THEN conjunct1]] 
      "2.prems" by auto
  ultimately have IH: "partition_on (X - P1) (set (map fst (merge_part2_raw f part1 (?notinP1))))"
    "distinct (map fst (merge_part2_raw f part1 (?notinP1)))"
    using "2.hyps"[OF refl refl] by auto
  moreover have wf_inP1: "partition_on P1 (set (map fst ?inP1))" "distinct (map fst ?inP1)"
    using wf_part_list_filter_inter[OF 2(2)[THEN conjunct1]]
      "2.prems" by auto
  moreover have "(fst ` set ?inP1)  (fst ` set (merge_part2_raw f part1 (?notinP1))) = {}"
    using IH(1)[THEN partition_onD1]
    by (fastforce simp: map_filter_def split: prod.splits if_splits)
  ultimately show ?case 
    using partition_on_append[OF wf_inP1(1) IH(1)] P1  X = X wf_inP1(2) IH(2)
    by simp
qed simp

lemma wf_part_list_merge_part3_raw: 
  "partition_on X (set (map fst part1))  distinct (map fst part1) 
   partition_on X (set (map fst part2))  distinct (map fst part2) 
   partition_on X (set (map fst part3))  distinct (map fst part3) 
   partition_on X (set (map fst (merge_part3_raw f part1 part2 part3))) 
     distinct (map fst (merge_part3_raw f part1 part2 part3))"
proof(induct f part1 part2 part3 arbitrary: X rule: merge_part3_raw.induct)
  case (4 f v va vb vc vd ve)
  have "partition_on X (set (map fst (v # va)))  distinct (map fst (vb # vc))"
    using 4 by blast
  moreover have "partition_on X (set (map fst (vb # vc)))  distinct (map fst (vb # vc))"
    using 4 by blast
  ultimately have "partition_on X (set (map fst (merge_part2_raw f (v # va) (vb # vc)))) 
   distinct (map fst (merge_part2_raw f (v # va) (vb # vc)))"
    using wf_part_list_merge_part2_raw[of X "(v # va)" "(vb # vc)" f] 4
    by fastforce
  moreover have "partition_on X (set (map fst (vd # ve)))  distinct (map fst (vd # ve))"
    using 4 by blast
  ultimately show ?case 
    using wf_part_list_merge_part2_raw[of X "(vd # ve)" "(merge_part2_raw f (v # va) (vb # vc))" "(λpt3 f'. f' pt3)"]
    by simp
qed auto

lift_definition merge_part2 :: "('a  'a  'a)  ('d, 'a) part  ('d, 'a) part  ('d, 'a) part" is merge_part2_raw
  by (rule wf_part_list_merge_part2_raw)

lift_definition merge_part3 :: "('a  'a  'a  'a)  ('d, 'a) part  ('d, 'a) part  ('d, 'a) part  ('d, 'a) part" is merge_part3_raw
  by (rule wf_part_list_merge_part3_raw)

definition proof_app :: "('n, 'd) proof  ('n, 'd) proof  ('n, 'd) proof" (infixl "" 65) where
  "p  q = (case (p, q) of
   (Inl (SHistorically i li sps), Inl q)  Inl (SHistorically (i+1) li (sps @ [q]))
 | (Inl (SAlways i hi sps), Inl q)  Inl (SAlways (i-1) hi (q # sps))
 | (Inl (SSince sp2 sp1s), Inl q)  Inl (SSince sp2 (sp1s @ [q]))
 | (Inl (SUntil sp1s sp2), Inl q)  Inl (SUntil (q # sp1s) sp2)
 | (Inr (VSince i vp1 vp2s), Inr q)  Inr (VSince (i+1) vp1 (vp2s @ [q]))
 | (Inr (VOnce i li vps), Inr q)  Inr (VOnce (i+1) li (vps @ [q]))
 | (Inr (VEventually i hi vps), Inr q)  Inr (VEventually (i-1) hi (q # vps))
 | (Inr (VSinceInf i li vp2s), Inr q)  Inr (VSinceInf (i+1) li (vp2s @ [q]))
 | (Inr (VUntil i vp2s vp1), Inr q)  Inr (VUntil (i-1) (q # vp2s) vp1)
 | (Inr (VUntilInf i hi vp2s), Inr q)  Inr (VUntilInf (i-1) hi (q # vp2s)))"

definition proof_incr :: "('n, 'd) proof  ('n, 'd) proof" where
  "proof_incr p = (case p of
   Inl (SOnce i sp)  Inl (SOnce (i+1) sp)
 | Inl (SEventually i sp)  Inl (SEventually (i-1) sp)
 | Inl (SHistorically i li sps)  Inl (SHistorically (i+1) li sps)
 | Inl (SAlways i hi sps)  Inl (SAlways (i-1) hi sps)
 | Inr (VSince i vp1 vp2s)  Inr (VSince (i+1) vp1 vp2s)
 | Inr (VOnce i li vps)  Inr (VOnce (i+1) li vps)
 | Inr (VEventually i hi vps)  Inr (VEventually (i-1) hi vps)
 | Inr (VHistorically i vp)  Inr (VHistorically (i+1) vp)
 | Inr (VAlways i vp)  Inr (VAlways (i-1) vp)
 | Inr (VSinceInf i li vp2s)  Inr (VSinceInf (i+1) li vp2s)
 | Inr (VUntil i vp2s vp1)  Inr (VUntil (i-1) vp2s vp1)
 | Inr (VUntilInf i hi vp2s)  Inr (VUntilInf (i-1) hi vp2s))"

definition min_list_wrt :: "(('n, 'd) proof  ('n, 'd) proof  bool)  ('n, 'd) proof list  ('n, 'd) proof" where
  "min_list_wrt r xs = hd [x  xs. y  set xs. r x y]"

definition do_neg :: "('n, 'd) proof  ('n, 'd) proof list" where
  "do_neg p = (case p of
  Inl sp  [Inr (VNeg sp)]
| Inr vp  [Inl (SNeg vp)])"

definition do_or :: "('n, 'd) proof  ('n, 'd) proof  ('n, 'd) proof list" where
  "do_or p1 p2 = (case (p1, p2) of
  (Inl sp1, Inl sp2)  [Inl (SOrL sp1), Inl (SOrR sp2)]
| (Inl sp1, Inr _  )  [Inl (SOrL sp1)]
| (Inr _  , Inl sp2)  [Inl (SOrR sp2)]
| (Inr vp1, Inr vp2)  [Inr (VOr vp1 vp2)])"

definition do_and :: "('n, 'd) proof  ('n, 'd) proof  ('n, 'd) proof list" where
  "do_and p1 p2 = (case (p1, p2) of
  (Inl sp1, Inl sp2)  [Inl (SAnd sp1 sp2)]
| (Inl _  , Inr vp2)  [Inr (VAndR vp2)]
| (Inr vp1, Inl _  )  [Inr (VAndL vp1)]
| (Inr vp1, Inr vp2)  [Inr (VAndL vp1), Inr (VAndR vp2)])"

definition do_imp :: "('n, 'd) proof  ('n, 'd) proof  ('n, 'd) proof list" where
  "do_imp p1 p2 = (case (p1, p2) of
  (Inl _  , Inl sp2)  [Inl (SImpR sp2)]
| (Inl sp1, Inr vp2)  [Inr (VImp sp1 vp2)]
| (Inr vp1, Inl sp2)  [Inl (SImpL vp1), Inl (SImpR sp2)]
| (Inr vp1, Inr _  )  [Inl (SImpL vp1)])"

definition do_iff :: "('n, 'd) proof  ('n, 'd) proof  ('n, 'd) proof list" where
  "do_iff p1 p2 = (case (p1, p2) of
  (Inl sp1, Inl sp2)  [Inl (SIffSS sp1 sp2)]
| (Inl sp1, Inr vp2)  [Inr (VIffSV sp1 vp2)]
| (Inr vp1, Inl sp2)  [Inr (VIffVS vp1 sp2)]
| (Inr vp1, Inr vp2)  [Inl (SIffVV vp1 vp2)])"

definition do_exists :: "'n  ('n, 'd::{default,linorder}) proof + ('d, ('n, 'd) proof) part  ('n, 'd) proof list" where
  "do_exists x p_part = (case p_part of
  Inl p  (case p of
    Inl sp  [Inl (SExists x default sp)]
  | Inr vp  [Inr (VExists x (trivial_part vp))])
| Inr part  (if (xVals part. isl x) then 
                map (λ(D,p). map_sum (SExists x (Min D)) id p) (filter (λ(_, p). isl p) (subsvals part))
              else
                [Inr (VExists x (map_part projr part))]))"

definition do_forall :: "'n  ('n, 'd::{default,linorder}) proof + ('d, ('n, 'd) proof) part  ('n, 'd) proof list" where
  "do_forall x p_part = (case p_part of
  Inl p  (case p of
    Inl sp  [Inl (SForall x (trivial_part sp))]
  | Inr vp  [Inr (VForall x default vp)])
| Inr part  (if (xVals part. isl x) then 
                [Inl (SForall x (map_part projl part))]
              else 
                map (λ(D,p). map_sum id (VForall x (Min D)) p) (filter (λ(_, p). ¬isl p) (subsvals part))))"

definition do_prev :: "nat    nat  ('n, 'd) proof  ('n, 'd) proof list" where
  "do_prev i I t p = (case (p, t < left I) of
  (Inl _ , True)  [Inr (VPrevOutL i)]
| (Inl sp, False)  (if mem t I then [Inl (SPrev sp)] else [Inr (VPrevOutR i)])
| (Inr vp, True)  [Inr (VPrev vp), Inr (VPrevOutL i)]
| (Inr vp, False)  (if mem t I then [Inr (VPrev vp)] else [Inr (VPrev vp), Inr (VPrevOutR i)]))"

definition do_next :: "nat    nat  ('n, 'd) proof  ('n, 'd) proof list" where
  "do_next i I t p = (case (p, t < left I) of
  (Inl _ , True)  [Inr (VNextOutL i)]
| (Inl sp, False)  (if mem t I then [Inl (SNext sp)] else [Inr (VNextOutR i)])
| (Inr vp, True)  [Inr (VNext vp), Inr (VNextOutL i)]
| (Inr vp, False)  (if mem t I then [Inr (VNext vp)] else [Inr (VNext vp), Inr (VNextOutR i)]))"

definition do_once_base :: "nat  nat  ('n, 'd) proof  ('n, 'd) proof list" where
  "do_once_base i a p' = (case (p', a = 0) of
  (Inl sp', True)  [Inl (SOnce i sp')]
| (Inr vp', True)  [Inr (VOnce i i [vp'])]
| ( _ , False)  [Inr (VOnce i i [])])"

definition do_once :: "nat  nat  ('n, 'd) proof  ('n, 'd) proof  ('n, 'd) proof list" where
  "do_once i a p p' = (case (p, a = 0, p') of
  (Inl sp, True,  Inr _ )  [Inl (SOnce i sp)]
| (Inl sp, True,  Inl (SOnce _ sp'))  [Inl (SOnce i sp'), Inl (SOnce i sp)]
| (Inl _ , False, Inl (SOnce _ sp'))  [Inl (SOnce i sp')]
| (Inl _ , False, Inr (VOnce _ li vps'))  [Inr (VOnce i li vps')]
| (Inr _ , True,  Inl (SOnce _ sp'))  [Inl (SOnce i sp')]
| (Inr vp, True,  Inr vp')  [(Inr vp')  (Inr vp)]
| (Inr _ , False, Inl (SOnce _ sp'))  [Inl (SOnce i sp')]
| (Inr _ , False, Inr (VOnce _ li vps'))  [Inr (VOnce i li vps')])"

definition do_eventually_base :: "nat  nat  ('n, 'd) proof  ('n, 'd) proof list" where
  "do_eventually_base i a p' = (case (p', a = 0) of
  (Inl sp', True)  [Inl (SEventually i sp')]
| (Inr vp', True)  [Inr (VEventually i i [vp'])]
| ( _ , False)  [Inr (VEventually i i [])])"

definition do_eventually :: "nat  nat  ('n, 'd) proof  ('n, 'd) proof  ('n, 'd) proof list" where
  "do_eventually i a p p' = (case (p, a = 0, p') of
  (Inl sp, True,  Inr _ )  [Inl (SEventually i sp)]
| (Inl sp, True,  Inl (SEventually _ sp'))  [Inl (SEventually i sp'), Inl (SEventually i sp)]
| (Inl _ , False, Inl (SEventually _ sp'))  [Inl (SEventually i sp')]
| (Inl _ , False, Inr (VEventually _ hi vps'))  [Inr (VEventually i hi vps')]
| (Inr _ , True,  Inl (SEventually _ sp'))  [Inl (SEventually i sp')]
| (Inr vp, True,  Inr vp')  [(Inr vp')  (Inr vp)]
| (Inr _ , False, Inl (SEventually _ sp'))  [Inl (SEventually i sp')]
| (Inr _ , False, Inr (VEventually _ hi vps'))  [Inr (VEventually i hi vps')])"

definition do_historically_base :: "nat  nat  ('n, 'd) proof  ('n, 'd) proof list" where
  "do_historically_base i a p' = (case (p', a = 0) of
  (Inl sp', True)  [Inl (SHistorically i i [sp'])]
| (Inr vp', True)  [Inr (VHistorically i vp')]
| ( _ , False)  [Inl (SHistorically i i [])])"

definition do_historically :: "nat  nat  ('n, 'd) proof  ('n, 'd) proof  ('n, 'd) proof list" where
  "do_historically i a p p' = (case (p, a = 0, p') of
  (Inl _ , True,  Inr (VHistorically _ vp'))  [Inr (VHistorically i vp')]
| (Inl sp, True,  Inl sp')  [(Inl sp')  (Inl sp)]
| (Inl _ , False, Inl (SHistorically _ li sps'))  [Inl (SHistorically i li sps')]
| (Inl _ , False, Inr (VHistorically _ vp'))  [Inr (VHistorically i vp')]
| (Inr vp, True,  Inl _ )  [Inr (VHistorically i vp)]
| (Inr vp, True,  Inr (VHistorically _ vp'))  [Inr (VHistorically i vp), Inr (VHistorically i vp')]
| (Inr _ , False, Inl (SHistorically _ li sps'))  [Inl (SHistorically i li sps')]
| (Inr _ , False, Inr (VHistorically _ vp'))  [Inr (VHistorically i vp')])"

definition do_always_base :: "nat  nat  ('n, 'd) proof  ('n, 'd) proof list" where
  "do_always_base i a p' = (case (p', a = 0) of
  (Inl sp', True)  [Inl (SAlways i i [sp'])]
| (Inr vp', True)  [Inr (VAlways i vp')]
| ( _ , False)  [Inl (SAlways i i [])])"

definition do_always :: "nat  nat  ('n, 'd) proof  ('n, 'd) proof  ('n, 'd) proof list" where
  "do_always i a p p' = (case (p, a = 0, p') of
  (Inl _ , True,  Inr (VAlways _ vp'))  [Inr (VAlways i vp')]
| (Inl sp, True,  Inl sp')  [(Inl sp')  (Inl sp)]
| (Inl _ , False, Inl (SAlways _ hi sps'))  [Inl (SAlways i hi sps')]
| (Inl _ , False, Inr (VAlways _ vp'))  [Inr (VAlways i vp')]
| (Inr vp, True,  Inl _ )  [Inr (VAlways i vp)]
| (Inr vp, True,  Inr (VAlways _ vp'))  [Inr (VAlways i vp), Inr (VAlways i vp')]
| (Inr _ , False, Inl (SAlways _ hi sps'))  [Inl (SAlways i hi sps')]
| (Inr _ , False, Inr (VAlways _ vp'))  [Inr (VAlways i vp')])"

definition do_since_base :: "nat  nat  ('n, 'd) proof  ('n, 'd) proof  ('n, 'd) proof list" where
  "do_since_base i a p1 p2 = (case (p1, p2, a = 0) of
  ( _ , Inl sp2, True)  [Inl (SSince sp2 [])]
| (Inl _ , _ , False)  [Inr (VSinceInf i i [])]
| (Inl _ , Inr vp2, True)  [Inr (VSinceInf i i [vp2])]
| (Inr vp1, _ , False)  [Inr (VSince i vp1 []), Inr (VSinceInf i i [])]
| (Inr vp1, Inr sp2, True)  [Inr (VSince i vp1 [sp2]), Inr (VSinceInf i i [sp2])])"

definition do_since :: "nat  nat  ('n, 'd) proof  ('n, 'd) proof  ('n, 'd) proof  ('n, 'd) proof list" where
  "do_since i a p1 p2 p' = (case (p1, p2, a = 0, p') of 
  (Inl sp1, Inr _ , True, Inl sp')  [(Inl sp')  (Inl sp1)]
| (Inl sp1, _ , False, Inl sp')  [(Inl sp')  (Inl sp1)]
| (Inl sp1, Inl sp2, True, Inl sp')  [(Inl sp')  (Inl sp1), Inl (SSince sp2 [])]
| (Inl _ , Inr vp2, True, Inr (VSinceInf _ _ _ ))  [p'  (Inr vp2)]
| (Inl _ , _ , False, Inr (VSinceInf _ li vp2s'))  [Inr (VSinceInf i li vp2s')]
| (Inl _ , Inr vp2, True, Inr (VSince _ _ _ ))  [p'  (Inr vp2)]
| (Inl _ , _ , False, Inr (VSince _ vp1' vp2s'))  [Inr (VSince i vp1' vp2s')]
| (Inr vp1, Inr vp2, True, Inl _ )  [Inr (VSince i vp1 [vp2])]
| (Inr vp1, _ , False, Inl _ )  [Inr (VSince i vp1 [])]
| (Inr _ , Inl sp2, True, Inl _ )  [Inl (SSince sp2 [])]
| (Inr vp1, Inr vp2, True, Inr (VSinceInf _ _ _ ))  [Inr (VSince i vp1 [vp2]), p'  (Inr vp2)]
| (Inr vp1, _, False, Inr (VSinceInf _ li vp2s'))  [Inr (VSince i vp1 []), Inr (VSinceInf i li vp2s')]
| ( _ , Inl sp2, True, Inr (VSinceInf _ _ _ ))  [Inl (SSince sp2 [])]
| (Inr vp1, Inr vp2, True, Inr (VSince _ _ _ ))  [Inr (VSince i vp1 [vp2]), p'  (Inr vp2)]
| (Inr vp1, _ , False, Inr (VSince _ vp1' vp2s'))  [Inr (VSince i vp1 []), Inr (VSince i vp1' vp2s')]
| ( _ , Inl vp2, True, Inr (VSince _ _ _ ))  [Inl (SSince vp2 [])])"

definition do_until_base :: "nat  nat  ('n, 'd) proof  ('n, 'd) proof  ('n, 'd) proof list" where
  "do_until_base i a p1 p2 = (case (p1, p2, a = 0) of
  ( _ , Inl sp2, True)  [Inl (SUntil [] sp2)]
| (Inl sp1, _ , False)  [Inr (VUntilInf i i [])]
| (Inl sp1, Inr vp2, True)  [Inr (VUntilInf i i [vp2])]
| (Inr vp1, _ , False)  [Inr (VUntil i [] vp1), Inr (VUntilInf i i [])]
| (Inr vp1, Inr vp2, True)  [Inr (VUntil i [vp2] vp1), Inr (VUntilInf i i [vp2])])"

definition do_until :: "nat  nat  ('n, 'd) proof  ('n, 'd) proof  ('n, 'd) proof  ('n, 'd) proof list" where
  "do_until i a p1 p2 p' = (case (p1, p2, a = 0, p') of
  (Inl sp1, Inr _ , True, Inl (SUntil _ _ ))  [p'  (Inl sp1)]
| (Inl sp1, _ , False, Inl (SUntil _ _ ))  [p'  (Inl sp1)]
| (Inl sp1, Inl sp2, True, Inl (SUntil _ _ ))  [p'  (Inl sp1), Inl (SUntil [] sp2)]
| (Inl _ , Inr vp2, True, Inr (VUntilInf _ _ _ ))  [p'  (Inr vp2)]
| (Inl _ , _ , False, Inr (VUntilInf _ hi vp2s'))  [Inr (VUntilInf i hi vp2s')]
| (Inl _ , Inr vp2, True, Inr (VUntil _ _ _ ))  [p'  (Inr vp2)]
| (Inl _ , _ , False, Inr (VUntil _ vp2s' vp1'))  [Inr (VUntil i vp2s' vp1')]
| (Inr vp1, Inr vp2, True, Inl (SUntil _ _ ))  [Inr (VUntil i [vp2] vp1)]
| (Inr vp1, _ , False, Inl (SUntil _ _ ))  [Inr (VUntil i [] vp1)]
| (Inr vp1, Inl sp2, True, Inl (SUntil _ _ ))  [Inl (SUntil [] sp2)]
| (Inr vp1, Inr vp2, True, Inr (VUntilInf _ _ _ ))  [Inr (VUntil i [vp2] vp1), p'  (Inr vp2)]
| (Inr vp1, _ , False, Inr (VUntilInf _ hi vp2s'))  [Inr (VUntil i [] vp1), Inr (VUntilInf i hi vp2s')]
| ( _ , Inl sp2, True, Inr (VUntilInf _ hi vp2s'))  [Inl (SUntil [] sp2)]
| (Inr vp1, Inr vp2, True, Inr (VUntil _ _ _ ))  [Inr (VUntil i [vp2] vp1), p'  (Inr vp2)]
| (Inr vp1, _ , False, Inr (VUntil _ vp2s' vp1'))  [Inr (VUntil i [] vp1), Inr (VUntil i vp2s' vp1')]
| ( _ , Inl sp2, True, Inr (VUntil _ _ _ ))  [Inl (SUntil [] sp2)])"

fun match :: "('n, 'd) Formula.trm list  'd list  ('n  'd) option" where
  "match [] [] = Some Map.empty"
| "match (Formula.Const x # ts) (y # ys) = (if x = y then match ts ys else None)"
| "match (Formula.Var x # ts) (y # ys) = (case match ts ys of
      None  None
    | Some f  (case f x of
        None  Some (f(x  y))
      | Some z  if y = z then Some f else None))"
| "match _ _ = None"

fun pdt_of :: "nat  'n  ('n, 'd :: linorder) Formula.trm list  'n list  ('n  'd) list  ('n, 'd) expl" where
  "pdt_of i r ts [] V = (if List.null V then Leaf (Inr (VPred i r ts)) else Leaf (Inl (SPred i r ts)))"
| "pdt_of i r ts (x # vs) V =
     (let ds = remdups (List.map_filter (λv. v x) V);
          part = tabulate ds (λd. pdt_of i r ts vs (filter (λv. v x = Some d) V)) (pdt_of i r ts vs [])
     in Node x part)"

fun "apply_pdt1" :: "'n list  (('n, 'd) proof  ('n, 'd) proof)  ('n, 'd) expl  ('n, 'd) expl" where
  "apply_pdt1 vs f (Leaf pt) = Leaf (f pt)"
| "apply_pdt1 (z # vs) f (Node x part) =
  (if x = z then
     Node x (map_part (λexpl. apply_pdt1 vs f expl) part)
   else
     apply_pdt1 vs f (Node x part))"
| "apply_pdt1 [] _ (Node _ _) = undefined"

fun "apply_pdt2" :: "'n list  (('n, 'd) proof  ('n, 'd) proof  ('n, 'd) proof)  ('n, 'd) expl  ('n, 'd) expl  ('n, 'd) expl" where
  "apply_pdt2 vs f (Leaf pt1) (Leaf pt2) = Leaf (f pt1 pt2)"
| "apply_pdt2 vs f (Leaf pt1) (Node x part2) = Node x (map_part (apply_pdt1 vs (f pt1)) part2)"
| "apply_pdt2 vs f (Node x part1) (Leaf pt2) = Node x (map_part (apply_pdt1 vs (λpt1. f pt1 pt2)) part1)"
| "apply_pdt2 (z # vs) f (Node x part1) (Node y part2) =
    (if x = z  y = z then
       Node z (merge_part2 (apply_pdt2 vs f) part1 part2)
     else if x = z then
       Node x (map_part (λexpl1. apply_pdt2 vs f expl1 (Node y part2)) part1)
     else if y = z then
       Node y (map_part (λexpl2. apply_pdt2 vs f (Node x part1) expl2) part2)
     else
       apply_pdt2 vs f (Node x part1) (Node y part2))"
| "apply_pdt2 [] _ (Node _ _) (Node _ _) = undefined"

fun "apply_pdt3" :: "'n list  (('n, 'd) proof  ('n, 'd) proof  ('n, 'd) proof  ('n, 'd) proof)  ('n, 'd) expl  ('n, 'd) expl  ('n, 'd) expl  ('n, 'd) expl" where
  "apply_pdt3 vs f (Leaf pt1) (Leaf pt2) (Leaf pt3) = Leaf (f pt1 pt2 pt3)"
| "apply_pdt3 vs f (Leaf pt1) (Leaf pt2) (Node x part3) = Node x (map_part (apply_pdt2 vs (f pt1) (Leaf pt2)) part3)" 
| "apply_pdt3 vs f (Leaf pt1) (Node x part2) (Leaf pt3) = Node x (map_part (apply_pdt2 vs (λpt2. f pt1 pt2) (Leaf pt3)) part2)"
| "apply_pdt3 vs f (Node x part1) (Leaf pt2) (Leaf pt3) = Node x (map_part (apply_pdt2 vs (λpt1. f pt1 pt2) (Leaf pt3)) part1)"
| "apply_pdt3 (w # vs) f (Leaf pt1) (Node y part2) (Node z part3) = 
  (if y = w  z = w then
     Node w (merge_part2 (apply_pdt2 vs (f pt1)) part2 part3)
   else if y = w then
     Node y (map_part (λexpl2. apply_pdt2 vs (f pt1) expl2 (Node z part3)) part2)
   else if z = w then
     Node z (map_part (λexpl3. apply_pdt2 vs (f pt1) (Node y part2) expl3) part3)
   else
     apply_pdt3 vs f (Leaf pt1) (Node y part2) (Node z part3))"
| "apply_pdt3 (w # vs) f (Node x part1) (Node y part2) (Leaf pt3) = 
  (if x = w  y = w then
     Node w (merge_part2 (apply_pdt2 vs (λpt1 pt2. f pt1 pt2 pt3)) part1 part2)
   else if x = w then
     Node x (map_part (λexpl1. apply_pdt2 vs (λpt1 pt2. f pt1 pt2 pt3) expl1 (Node y part2)) part1)
   else if y = w then
     Node y (map_part (λexpl2. apply_pdt2 vs (λpt1 pt2. f pt1 pt2 pt3) (Node x part1) expl2) part2)
   else
     apply_pdt3 vs f (Node x part1) (Node y part2) (Leaf pt3))"
| "apply_pdt3 (w # vs) f (Node x part1) (Leaf pt2) (Node z part3) = 
  (if x = w  z = w then
     Node w (merge_part2 (apply_pdt2 vs (λpt1. f pt1 pt2)) part1 part3)
   else if x = w then
     Node x (map_part (λexpl1. apply_pdt2 vs (λpt1. f pt1 pt2) expl1 (Node z part3)) part1)
   else if z = w then
     Node z (map_part (λexpl3. apply_pdt2 vs (λpt1. f pt1 pt2) (Node x part1) expl3) part3)
   else
     apply_pdt3 vs f (Node x part1) (Leaf pt2) (Node z part3))"
| "apply_pdt3 (w # vs) f (Node x part1) (Node y part2) (Node z part3) = 
  (if x = w  y = w  z = w then
     Node z (merge_part3 (apply_pdt3 vs f) part1 part2 part3)
   else if x = w  y = w then
     Node w (merge_part2 (apply_pdt3 vs (λpt3 pt1 pt2. f pt1 pt2 pt3) (Node z part3)) part1 part2)
   else if x = w  z = w then
     Node w (merge_part2 (apply_pdt3 vs (λpt2 pt1 pt3. f pt1 pt2 pt3) (Node y part2)) part1 part3)
   else if y = w  z = w then
     Node w (merge_part2 (apply_pdt3 vs (λpt1. f pt1) (Node x part1)) part2 part3)
   else if x = w then
     Node x (map_part (λexpl1. apply_pdt3 vs f expl1 (Node y part2) (Node z part3)) part1)
   else if y = w then
     Node y (map_part (λexpl2. apply_pdt3 vs f (Node x part1) expl2 (Node z part3)) part2)
   else if z = w then
     Node z (map_part (λexpl3. apply_pdt3 vs f (Node x part1) (Node y part2) expl3) part3)
   else 
     apply_pdt3 vs f (Node x part1) (Node y part2) (Node z part3))"
| "apply_pdt3 [] _ _ _ _ = undefined"

fun "hide_pdt" :: "'n list  (('n, 'd) proof + ('d, ('n, 'd) proof) part  ('n, 'd) proof)  ('n, 'd) expl  ('n, 'd) expl" where
  "hide_pdt vs f (Leaf pt) = Leaf (f (Inl pt))"
| "hide_pdt [x] f (Node y part) = Leaf (f (Inr (map_part unleaf part)))"
| "hide_pdt (x # xs) f (Node y part) = 
  (if x = y then
     Node y (map_part (hide_pdt xs f) part)
   else
     hide_pdt xs f (Node y part))"
| "hide_pdt [] _ _ = undefined"

context 
  fixes σ :: "('n, 'd :: {default, linorder}) trace" and
  cmp :: "('n, 'd) proof  ('n, 'd) proof  bool"
begin

function (sequential) eval :: "'n list  nat  ('n, 'd) Formula.formula  ('n, 'd) expl" where
  "eval vs i Formula.TT = Leaf (Inl (STT i))"
| "eval vs i Formula.FF = Leaf (Inr (VFF i))"
| "eval vs i (Eq_Const x c) = Node x (tabulate [c] (λc. Leaf (Inl (SEq_Const i x c))) (Leaf (Inr (VEq_Const i x c))))"
| "eval vs i (Formula.Pred r ts) = 
  (pdt_of i r ts (filter (λx. x  Formula.fv (Formula.Pred r ts)) vs) (List.map_filter (match ts) (sorted_list_of_set (snd ` {rd  Γ σ i. fst rd = r}))))"
| "eval vs i (Formula.Neg φ) = apply_pdt1 vs (λp. min_list_wrt cmp (do_neg p)) (eval vs i φ)"
| "eval vs i (Formula.Or φ ψ) = apply_pdt2 vs (λp1 p2. min_list_wrt cmp (do_or p1 p2)) (eval vs i φ) (eval vs i ψ)"
| "eval vs i (Formula.And φ ψ) = apply_pdt2 vs (λp1 p2. min_list_wrt cmp (do_and p1 p2)) (eval vs i φ) (eval vs i ψ)"
| "eval vs i (Formula.Imp φ ψ) = apply_pdt2 vs (λp1 p2. min_list_wrt cmp (do_imp p1 p2)) (eval vs i φ) (eval vs i ψ)"
| "eval vs i (Formula.Iff φ ψ) = apply_pdt2 vs (λp1 p2. min_list_wrt cmp (do_iff p1 p2)) (eval vs i φ) (eval vs i ψ)"
| "eval vs i (Formula.Exists x φ) = hide_pdt (vs @ [x]) (λp. min_list_wrt cmp (do_exists x p)) (eval (vs @ [x]) i φ)"
| "eval vs i (Formula.Forall x φ) = hide_pdt (vs @ [x]) (λp. min_list_wrt cmp (do_forall x p)) (eval (vs @ [x]) i φ)"
| "eval vs i (Formula.Prev I φ) = (if i = 0 then Leaf (Inr VPrevZ) 
                                   else apply_pdt1 vs (λp. min_list_wrt cmp (do_prev i I (Δ σ i) p)) (eval vs (i-1) φ))"
| "eval vs i (Formula.Next I φ) = apply_pdt1 vs (λl. min_list_wrt cmp (do_next i I (Δ σ (i+1)) l)) (eval vs (i+1) φ)"
| "eval vs i (Formula.Once I φ) = 
  (if τ σ i < τ σ 0 + left I then Leaf (Inr (VOnceOut i)) 
   else (let expl = eval vs i φ in
        (if i = 0 then 
           apply_pdt1 vs (λp. min_list_wrt cmp (do_once_base 0 0 p)) expl
         else (if right I  enat (Δ σ i) then
                 apply_pdt2 vs (λp p'. min_list_wrt cmp (do_once i (left I) p p')) expl
                            (eval vs (i-1) (Formula.Once (subtract (Δ σ i) I) φ))
               else apply_pdt1 vs (λp. min_list_wrt cmp (do_once_base i (left I) p)) expl))))"
| "eval vs i (Formula.Historically I φ) = 
  (if τ σ i < τ σ 0 + left I then Leaf (Inl (SHistoricallyOut i)) 
   else (let expl = eval vs i φ in
        (if i = 0 then 
           apply_pdt1 vs (λp. min_list_wrt cmp (do_historically_base 0 0 p)) expl
         else (if right I  enat (Δ σ i) then
                 apply_pdt2 vs (λp p'. min_list_wrt cmp (do_historically i (left I) p p')) expl
                            (eval vs (i-1) (Formula.Historically (subtract (Δ σ i) I) φ))
               else apply_pdt1 vs (λp. min_list_wrt cmp (do_historically_base i (left I) p)) expl))))"
| "eval vs i (Formula.Eventually I φ) = 
  (let expl = eval vs i φ in
  (if right I =  then undefined 
   else (if right I  enat (Δ σ (i+1)) then
           apply_pdt2 vs (λp p'. min_list_wrt cmp (do_eventually i (left I) p p')) expl
                            (eval vs (i+1) (Formula.Eventually (subtract (Δ σ (i+1)) I) φ))
         else apply_pdt1 vs (λp. min_list_wrt cmp (do_eventually_base i (left I) p)) expl)))"
| "eval vs i (Formula.Always I φ) = 
  (let expl = eval vs i φ in
  (if right I =  then undefined 
   else (if right I  enat (Δ σ (i+1)) then
           apply_pdt2 vs (λp p'. min_list_wrt cmp (do_always i (left I) p p')) expl
                            (eval vs (i+1) (Formula.Always (subtract (Δ σ (i+1)) I) φ))
         else apply_pdt1 vs (λp. min_list_wrt cmp (do_always_base i (left I) p)) expl)))"
| "eval vs i (Formula.Since φ I ψ) = 
  (if τ σ i < τ σ 0 + left I then Leaf (Inr (VSinceOut i)) 
   else (let expl1 = eval vs i φ in
         let expl2 = eval vs i ψ in
         (if i = 0 then 
            apply_pdt2 vs (λp1 p2. min_list_wrt cmp (do_since_base 0 0 p1 p2)) expl1 expl2
          else (if right I  enat (Δ σ i) then
                  apply_pdt3 vs (λp1 p2 p'. min_list_wrt cmp (do_since i (left I) p1 p2 p')) expl1 expl2
                             (eval vs (i-1) (Formula.Since φ (subtract (Δ σ i) I) ψ))
                else apply_pdt2 vs (λp1 p2. min_list_wrt cmp (do_since_base i (left I) p1 p2)) expl1 expl2))))"
| "eval vs i (Formula.Until φ I ψ) = 
  (let expl1 = eval vs i φ in
   let expl2 = eval vs i ψ in
   (if right I =  then undefined 
    else (if right I  enat (Δ σ (i+1)) then
            apply_pdt3 vs (λp1 p2 p'. min_list_wrt cmp (do_until i (left I) p1 p2 p')) expl1 expl2
                             (eval vs (i+1) (Formula.Until φ (subtract (Δ σ (i+1)) I) ψ))
          else apply_pdt2 vs (λp1 p2. min_list_wrt cmp (do_until_base i (left I) p1 p2)) expl1 expl2)))"
  by pat_completeness auto

fun dist where
  "dist i (Formula.Once _ _) = i"
| "dist i (Formula.Historically _ _) = i"
| "dist i (Formula.Eventually I _) = LTP σ (case right I of   0 | enat b  (τ σ i + b)) - i"
| "dist i (Formula.Always I _) = LTP σ (case right I of   0 | enat b  (τ σ i + b)) - i"
| "dist i (Formula.Since _ _ _) = i"
| "dist i (Formula.Until _ I _) = LTP σ (case right I of   0 | enat b  (τ σ i + b)) - i"
| "dist _ _ = undefined"

lemma i_less_LTP: "τ σ (Suc i)  b + τ σ i  i < LTP σ (b + τ σ i)"
  by (metis Suc_le_lessD i_le_LTPi_add le_iff_add)

termination eval
  by (relation "measures [λ(_, _, φ). size φ, λ(_, i, φ). dist i φ]")
    (auto simp: add.commute le_diff_conv i_less_LTP intro!: diff_less_mono2)

end

end