Theory Monitor

(*<*)
theory Monitor
  imports Abstract_Monitor MFOTL Table
begin
(*>*)

section ‹Monitor implementation›

subsection ‹Monitorable formulas›

definition "mmonitorable φ  safe_formula φ  MFOTL.future_reach φ  "

fun mmonitorable_exec :: "'a MFOTL.formula  bool" where
  "mmonitorable_exec (MFOTL.Eq t1 t2) = (MFOTL.is_Const t1  MFOTL.is_Const t2)"
| "mmonitorable_exec (MFOTL.Neg (MFOTL.Eq (MFOTL.Const x) (MFOTL.Const y))) = True"
| "mmonitorable_exec (MFOTL.Neg (MFOTL.Eq (MFOTL.Var x) (MFOTL.Var y))) = (x = y)"
| "mmonitorable_exec (MFOTL.Pred e ts) = True"
| "mmonitorable_exec (MFOTL.Neg (MFOTL.Or (MFOTL.Neg φ) ψ)) = (mmonitorable_exec φ 
    (mmonitorable_exec ψ  MFOTL.fv ψ  MFOTL.fv φ  (case ψ of MFOTL.Neg ψ'  mmonitorable_exec ψ' | _  False)))"
| "mmonitorable_exec (MFOTL.Or φ ψ) = (MFOTL.fv ψ = MFOTL.fv φ  mmonitorable_exec φ  mmonitorable_exec ψ)"
| "mmonitorable_exec (MFOTL.Exists φ) = (mmonitorable_exec φ)"
| "mmonitorable_exec (MFOTL.Prev I φ) = (mmonitorable_exec φ)"
| "mmonitorable_exec (MFOTL.Next I φ) = (mmonitorable_exec φ  right I  )"
| "mmonitorable_exec (MFOTL.Since φ I ψ) = (MFOTL.fv φ  MFOTL.fv ψ 
    (mmonitorable_exec φ  (case φ of MFOTL.Neg φ'  mmonitorable_exec φ' | _  False))  mmonitorable_exec ψ)"
| "mmonitorable_exec (MFOTL.Until φ I ψ) = (MFOTL.fv φ  MFOTL.fv ψ  right I   
    (mmonitorable_exec φ  (case φ of MFOTL.Neg φ'  mmonitorable_exec φ' | _  False))  mmonitorable_exec ψ)"
| "mmonitorable_exec _ = False"

lemma plus_eq_enat_iff: "a + b = enat i  (j k. a = enat j  b = enat k  j + k = i)"
  by (cases a; cases b) auto

lemma minus_eq_enat_iff: "a - enat k = enat i  (j. a = enat j  j - k = i)"
  by (cases a) auto

lemma safe_formula_mmonitorable_exec: "safe_formula φ  MFOTL.future_reach φ    mmonitorable_exec φ"
proof (induct φ rule: safe_formula.induct)
  case (5 φ ψ)
  then show ?case
    unfolding safe_formula.simps future_reach.simps mmonitorable_exec.simps
    by (fastforce split: formula.splits)
next
  case (6 φ ψ)
  then show ?case 
    unfolding safe_formula.simps future_reach.simps mmonitorable_exec.simps
    by (fastforce split: formula.splits)
next
  case (10 φ I ψ)
  then show ?case 
    unfolding safe_formula.simps future_reach.simps mmonitorable_exec.simps
    by (fastforce split: formula.splits)
next
  case (11 φ I ψ)
  then show ?case 
    unfolding safe_formula.simps future_reach.simps mmonitorable_exec.simps
    by (fastforce simp: plus_eq_enat_iff split: formula.splits)
qed (auto simp add: plus_eq_enat_iff minus_eq_enat_iff)

lemma mmonitorable_exec_mmonitorable: "mmonitorable_exec φ  mmonitorable φ"
proof (induct φ rule: mmonitorable_exec.induct)
  case (5 φ ψ)
  then show ?case
    unfolding mmonitorable_def mmonitorable_exec.simps safe_formula.simps
    by (fastforce split: formula.splits)
next
  case (10 φ I ψ)
  then show ?case
    unfolding mmonitorable_def mmonitorable_exec.simps safe_formula.simps
    by (fastforce split: formula.splits)
next
  case (11 φ I ψ)
  then show ?case
    unfolding mmonitorable_def mmonitorable_exec.simps safe_formula.simps
    by (fastforce simp: one_enat_def split: formula.splits)
qed (auto simp add: mmonitorable_def one_enat_def)

lemma monitorable_formula_code[code]: "mmonitorable φ = mmonitorable_exec φ"
  using mmonitorable_exec_mmonitorable safe_formula_mmonitorable_exec mmonitorable_def
  by blast



subsection ‹The executable monitor›

type_synonym ts = nat

type_synonym 'a mbuf2 = "'a table list × 'a table list"
type_synonym 'a msaux = "(ts × 'a table) list"
type_synonym 'a muaux = "(ts × 'a table × 'a table) list"

datatype 'a mformula =
    MRel "'a table"
  | MPred MFOTL.name "'a MFOTL.trm list"
  | MAnd "'a mformula" bool "'a mformula" "'a mbuf2"
  | MOr "'a mformula" "'a mformula" "'a mbuf2"
  | MExists "'a mformula"
  | MPrev  "'a mformula" bool "'a table list" "ts list"
  | MNext  "'a mformula" bool "ts list"
  | MSince bool "'a mformula"  "'a mformula" "'a mbuf2" "ts list" "'a msaux"
  | MUntil bool "'a mformula"  "'a mformula" "'a mbuf2" "ts list" "'a muaux"

record 'a mstate =
  mstate_i :: nat
  mstate_m :: "'a mformula"
  mstate_n :: nat

fun eq_rel :: "nat  'a MFOTL.trm  'a MFOTL.trm  'a table" where
  "eq_rel n (MFOTL.Const x) (MFOTL.Const y) = (if x = y then unit_table n else empty_table)"
| "eq_rel n (MFOTL.Var x) (MFOTL.Const y) = singleton_table n x y"
| "eq_rel n (MFOTL.Const x) (MFOTL.Var y) = singleton_table n y x"
| "eq_rel n (MFOTL.Var x) (MFOTL.Var y) = undefined"

fun neq_rel :: "nat  'a MFOTL.trm  'a MFOTL.trm  'a table" where
  "neq_rel n (MFOTL.Const x) (MFOTL.Const y) = (if x = y then empty_table else unit_table n)"
| "neq_rel n (MFOTL.Var x) (MFOTL.Var y) = (if x = y then empty_table else undefined)"
| "neq_rel _ _ _ = undefined"

fun minit0 :: "nat  'a MFOTL.formula  'a mformula" where
  "minit0 n (MFOTL.Neg φ) = (case φ of
    MFOTL.Eq t1 t2  MRel (neq_rel n t1 t2)
  | MFOTL.Or (MFOTL.Neg φ) ψ  (if safe_formula ψ  MFOTL.fv ψ  MFOTL.fv φ
      then MAnd (minit0 n φ) False (minit0 n ψ) ([], [])
      else (case ψ of MFOTL.Neg ψ  MAnd (minit0 n φ) True (minit0 n ψ) ([], []) | _  undefined))
  | _  undefined)"
| "minit0 n (MFOTL.Eq t1 t2) = MRel (eq_rel n t1 t2)"
| "minit0 n (MFOTL.Pred e ts) = MPred e ts"
| "minit0 n (MFOTL.Or φ ψ) = MOr (minit0 n φ) (minit0 n ψ) ([], [])"
| "minit0 n (MFOTL.Exists φ) = MExists (minit0 (Suc n) φ)"
| "minit0 n (MFOTL.Prev I φ) = MPrev I (minit0 n φ) True [] []"
| "minit0 n (MFOTL.Next I φ) = MNext I (minit0 n φ) True []"
| "minit0 n (MFOTL.Since φ I ψ) = (if safe_formula φ
    then MSince True (minit0 n φ) I (minit0 n ψ) ([], []) [] []
    else (case φ of
      MFOTL.Neg φ  MSince False (minit0 n φ) I (minit0 n ψ) ([], []) [] []
    | _  undefined))"
| "minit0 n (MFOTL.Until φ I ψ) = (if safe_formula φ
    then MUntil True (minit0 n φ) I (minit0 n ψ) ([], []) [] []
    else (case φ of
      MFOTL.Neg φ  MUntil False (minit0 n φ) I (minit0 n ψ) ([], []) [] []
    | _  undefined))"

definition minit :: "'a MFOTL.formula  'a mstate" where
  "minit φ = (let n = MFOTL.nfv φ in mstate_i = 0, mstate_m = minit0 n φ, mstate_n = n)"

fun mprev_next :: "  'a table list  ts list  'a table list × 'a table list × ts list" where
  "mprev_next I [] ts = ([], [], ts)"
| "mprev_next I xs [] = ([], xs, [])"
| "mprev_next I xs [t] = ([], xs, [t])"
| "mprev_next I (x # xs) (t # t' # ts) = (let (ys, zs) = mprev_next I xs (t' # ts)
    in ((if mem (t' - t) I then x else empty_table) # ys, zs))"

fun mbuf2_add :: "'a table list  'a table list  'a mbuf2  'a mbuf2" where
 "mbuf2_add xs' ys' (xs, ys) = (xs @ xs', ys @ ys')"

fun mbuf2_take :: "('a table  'a table  'b)  'a mbuf2  'b list × 'a mbuf2" where
  "mbuf2_take f (x # xs, y # ys) = (let (zs, buf) = mbuf2_take f (xs, ys) in (f x y # zs, buf))"
| "mbuf2_take f (xs, ys) = ([], (xs, ys))"

fun mbuf2t_take :: "('a table  'a table  ts  'b  'b)  'b 
  'a mbuf2  ts list  'b × 'a mbuf2 × ts list" where
  "mbuf2t_take f z (x # xs, y # ys) (t # ts) = mbuf2t_take f (f x y t z) (xs, ys) ts"
| "mbuf2t_take f z (xs, ys) ts = (z, (xs, ys), ts)"

fun match :: "'a MFOTL.trm list  'a list  (nat  'a) option" where
  "match [] [] = Some Map.empty"
| "match (MFOTL.Const x # ts) (y # ys) = (if x = y then match ts ys else None)"
| "match (MFOTL.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"

definition update_since :: "  bool  'a table  'a table  ts 
  'a msaux  'a table × 'a msaux" where
  "update_since I pos rel1 rel2 nt aux =
    (let aux = (case [(t, join rel pos rel1). (t, rel)  aux, nt - t  right I] of
        []  [(nt, rel2)]
      | x # aux'  (if fst x = nt then (fst x, snd x  rel2) # aux' else (nt, rel2) # x # aux'))
    in (foldr (∪) [rel. (t, rel)  aux, left I  nt - t] {}, aux))"

definition update_until :: "  bool  'a table  'a table  ts  'a muaux  'a muaux" where
  "update_until I pos rel1 rel2 nt aux =
    (map (λx. case x of (t, a1, a2)  (t, if pos then join a1 True rel1 else a1  rel1,
      if mem (nt - t) I then a2  join rel2 pos a1 else a2)) aux) @
    [(nt, rel1, if left I = 0 then rel2 else empty_table)]"

fun eval_until :: "  ts  'a muaux  'a table list × 'a muaux" where
  "eval_until I nt [] = ([], [])"
| "eval_until I nt ((t, a1, a2) # aux) = (if t + right I < nt then
    (let (xs, aux) = eval_until I nt aux in (a2 # xs, aux)) else ([], (t, a1, a2) # aux))"

primrec meval :: "nat  ts  'a MFOTL.database  'a mformula  'a table list × 'a mformula" where
  "meval n t db (MRel rel) = ([rel], MRel rel)"
| "meval n t db (MPred e ts) = ([(λf. tabulate f 0 n) ` Option.these
    (match ts ` ((e', x)db. if e = e' then {x} else {}))], MPred e ts)"
| "meval n t db (MAnd φ pos ψ buf) =
    (let (xs, φ) = meval n t db φ; (ys, ψ) = meval n t db ψ;
      (zs, buf) = mbuf2_take (λr1 r2. join r1 pos r2) (mbuf2_add xs ys buf)
    in (zs, MAnd φ pos ψ buf))"
| "meval n t db (MOr φ ψ buf) =
    (let (xs, φ) = meval n t db φ; (ys, ψ) = meval n t db ψ;
      (zs, buf) = mbuf2_take (λr1 r2. r1  r2) (mbuf2_add xs ys buf)
    in (zs, MOr φ ψ buf))"
| "meval n t db (MExists φ) =
    (let (xs, φ) = meval (Suc n) t db φ in (map (λr. tl ` r) xs, MExists φ))"
| "meval n t db (MPrev I φ first buf nts) =
    (let (xs, φ) = meval n t db φ;
      (zs, buf, nts) = mprev_next I (buf @ xs) (nts @ [t])
    in (if first then empty_table # zs else zs, MPrev I φ False buf nts))"
| "meval n t db (MNext I φ first nts) =
    (let (xs, φ) = meval n t db φ;
      (xs, first) = (case (xs, first) of (_ # xs, True)  (xs, False) | a  a);
      (zs, _, nts) = mprev_next I xs (nts @ [t])
    in (zs, MNext I φ first nts))"
| "meval n t db (MSince pos φ I ψ buf nts aux) =
    (let (xs, φ) = meval n t db φ; (ys, ψ) = meval n t db ψ;
      ((zs, aux), buf, nts) = mbuf2t_take (λr1 r2 t (zs, aux).
        let (z, aux) = update_since I pos r1 r2 t aux
        in (zs @ [z], aux)) ([], aux) (mbuf2_add xs ys buf) (nts @ [t])
    in (zs, MSince pos φ I ψ buf nts aux))"
| "meval n t db (MUntil pos φ I ψ buf nts aux) =
    (let (xs, φ) = meval n t db φ; (ys, ψ) = meval n t db ψ;
      (aux, buf, nts) = mbuf2t_take (update_until I pos) aux (mbuf2_add xs ys buf) (nts @ [t]);
      (zs, aux) = eval_until I (case nts of []  t | nt # _  nt) aux
    in (zs, MUntil pos φ I ψ buf nts aux))"

definition mstep :: "'a MFOTL.database × ts  'a mstate  (nat × 'a tuple) set × 'a mstate" where
  "mstep tdb st =
     (let (xs, m) = meval (mstate_n st) (snd tdb) (fst tdb) (mstate_m st)
     in ( (set (map (λ(i, X). (λv. (i, v)) ` X) (List.enumerate (mstate_i st) xs))),
      mstate_i = mstate_i st + length xs, mstate_m = m, mstate_n = mstate_n st))"

lemma mstep_alt: "mstep tdb st =
     (let (xs, m) = meval (mstate_n st) (snd tdb) (fst tdb) (mstate_m st)
     in ((i, X)  set (List.enumerate (mstate_i st) xs). v  X. {(i,v)},
      mstate_i = mstate_i st + length xs, mstate_m = m, mstate_n = mstate_n st))"
  unfolding mstep_def
  by (auto split: prod.split)


subsection ‹Progress›

primrec progress :: "'a MFOTL.trace  'a MFOTL.formula  nat  nat" where
  "progress σ (MFOTL.Pred e ts) j = j"
| "progress σ (MFOTL.Eq t1 t2) j = j"
| "progress σ (MFOTL.Neg φ) j = progress σ φ j"
| "progress σ (MFOTL.Or φ ψ) j = min (progress σ φ j) (progress σ ψ j)"
| "progress σ (MFOTL.Exists φ) j = progress σ φ j"
| "progress σ (MFOTL.Prev I φ) j = (if j = 0 then 0 else min (Suc (progress σ φ j)) j)"
| "progress σ (MFOTL.Next I φ) j = progress σ φ j - 1"
| "progress σ (MFOTL.Since φ I ψ) j = min (progress σ φ j) (progress σ ψ j)"
| "progress σ (MFOTL.Until φ I ψ) j =
    Inf {i. k. k < j  k  min (progress σ φ j) (progress σ ψ j)  τ σ i + right I  τ σ k}"

lemma progress_And[simp]: "progress σ (MFOTL.And φ ψ) j = min (progress σ φ j) (progress σ ψ j)"
  unfolding MFOTL.And_def by simp

lemma progress_And_Not[simp]: "progress σ (MFOTL.And_Not φ ψ) j = min (progress σ φ j) (progress σ ψ j)"
  unfolding MFOTL.And_Not_def by simp

lemma progress_mono: "j  j'  progress σ φ j  progress σ φ j'"
proof (induction φ)
  case (Until φ I ψ)
  then show ?case
    by (cases "right I")
      (auto dest: trans_le_add1[OF τ_mono] intro!: cInf_superset_mono)
qed auto

lemma progress_le: "progress σ φ j  j"
proof (induction φ)
  case (Until φ I ψ)
  then show ?case
    by (cases "right I")
      (auto intro: trans_le_add1[OF τ_mono] intro!: cInf_lower)
qed auto

lemma progress_0[simp]: "progress σ φ 0 = 0"
  using progress_le by auto

lemma progress_ge: "MFOTL.future_reach φ    j. i  progress σ φ j"
proof (induction φ arbitrary: i)
  case (Pred e ts)
  then show ?case by auto
next
  case (Eq t1 t2)
  then show ?case by auto
next
  case (Neg φ)
  then show ?case by simp
next
  case (Or φ1 φ2)
  from Or.prems have "MFOTL.future_reach φ1  "
    by (cases "MFOTL.future_reach φ1") (auto)
  moreover from Or.prems have "MFOTL.future_reach φ2  "
    by (cases "MFOTL.future_reach φ2") (auto)
  ultimately obtain j1 j2 where "i  progress σ φ1 j1" and "i  progress σ φ2 j2"
    using Or.IH[of i] by blast
  then have "i  progress σ (MFOTL.Or φ1 φ2) (max j1 j2)"
    by (cases "j1  j2") (auto elim!: order.trans[OF _ progress_mono])
  then show ?case by blast
next
  case (Exists φ)
  then show ?case by simp
next
  case (Prev I φ)
  from Prev.prems have "MFOTL.future_reach φ  "
    by (cases "MFOTL.future_reach φ") (auto)
  then obtain j where "i  progress σ φ j"
    using Prev.IH[of i] by blast
  then show ?case by (auto intro!: exI[of _ j] elim!: order.trans[OF _ progress_le])
next
  case (Next I φ)
  from Next.prems have "MFOTL.future_reach φ  "
    by (cases "MFOTL.future_reach φ") (auto)
  then obtain j where "Suc i  progress σ φ j"
    using Next.IH[of "Suc i"] by blast
  then show ?case by (auto intro!: exI[of _ j])
next
  case (Since φ1 I φ2)
  from Since.prems have "MFOTL.future_reach φ1  "
    by (cases "MFOTL.future_reach φ1") (auto)
  moreover from Since.prems have "MFOTL.future_reach φ2  "
    by (cases "MFOTL.future_reach φ2") (auto)
  ultimately obtain j1 j2 where "i  progress σ φ1 j1" and "i  progress σ φ2 j2"
    using Since.IH[of i] by blast
  then have "i  progress σ (MFOTL.Since φ1 I φ2) (max j1 j2)"
    by (cases "j1  j2") (auto elim!: order.trans[OF _ progress_mono])
  then show ?case by blast
next
  case (Until φ1 I φ2)
  from Until.prems obtain b where [simp]: "right I = enat b"
    by (cases "right I") (auto)
  obtain i' where "i < i'" and "τ σ i + b + 1  τ σ i'"
    using ex_le_τ[where x="τ σ i + b + 1"] by (auto simp add: less_eq_Suc_le)
  then have 1: "τ σ i + b < τ σ i'" by simp
  from Until.prems have "MFOTL.future_reach φ1  "
    by (cases "MFOTL.future_reach φ1") (auto)
  moreover from Until.prems have "MFOTL.future_reach φ2  "
    by (cases "MFOTL.future_reach φ2") (auto)
  ultimately obtain j1 j2 where "Suc i'  progress σ φ1 j1" and "Suc i'  progress σ φ2 j2"
    using Until.IH[of "Suc i'"] by blast
  then have "i  progress σ (MFOTL.Until φ1 I φ2) (max j1 j2)"
    unfolding progress.simps
  proof (intro cInf_greatest, goal_cases nonempty greatest)
    case nonempty
    then show ?case
      by (auto simp: trans_le_add1[OF τ_mono] intro!: exI[of _ "max j1 j2"])
  next
    case (greatest x)
    with i < i' 1 show ?case
      by (cases "j1  j2")
        (auto dest!: spec[of _ i'] simp: max_absorb1 max_absorb2 less_eq_Suc_le
          elim: order.trans[OF _ progress_le] order.trans[OF _ progress_mono, rotated]
          dest!: not_le_imp_less[THEN less_imp_le] intro!: less_τD[THEN less_imp_le, of σ i x])
  qed
  then show ?case by blast
qed

lemma cInf_restrict_nat:
  fixes x :: nat
  assumes "x  A"
  shows "Inf A = Inf {y  A. y  x}"
  using assms by (auto intro!: antisym intro: cInf_greatest cInf_lower Inf_nat_def1)

lemma progress_time_conv:
  assumes "i<j. τ σ i = τ σ' i"
  shows "progress σ φ j = progress σ' φ j"
proof (induction φ)
  case (Until φ1 I φ2)
  have *: "i  j - 1  i < j" if "j  0" for i
    using that by auto
  with Until show ?case
  proof (cases "right I")
    case (enat b)
    then show ?thesis
    proof (cases "j")
      case (Suc n)
      with enat * Until show ?thesis
        using assms τ_mono[THEN trans_le_add1]
        by (auto 6 0
          intro!: box_equals[OF arg_cong[where f=Inf]
            cInf_restrict_nat[symmetric, where x=n] cInf_restrict_nat[symmetric, where x=n]])
    qed simp
  qed simp
qed simp_all

lemma Inf_UNIV_nat: "(Inf UNIV :: nat) = 0"
  by (simp add: cInf_eq_minimum)

lemma progress_prefix_conv:
  assumes "prefix_of π σ" and "prefix_of π σ'"
  shows "progress σ φ (plen π) = progress σ' φ (plen π)"
  using assms by (auto intro: progress_time_conv τ_prefix_conv)

lemma sat_prefix_conv:
  assumes "prefix_of π σ" and "prefix_of π σ'" and "i < progress σ φ (plen π)"
  shows "MFOTL.sat σ v i φ  MFOTL.sat σ' v i φ"
using assms(3) proof (induction φ arbitrary: v i)
  case (Pred e ts)
  with Γ_prefix_conv[OF assms(1,2)] show ?case by simp
next
  case (Eq t1 t2)
  show ?case by simp
next
  case (Neg φ)
  then show ?case by simp
next
  case (Or φ1 φ2)
  then show ?case by simp
next
  case (Exists φ)
  then show ?case by simp
next
  case (Prev I φ)
  with τ_prefix_conv[OF assms(1,2)] show ?case
    by (cases i) (auto split: if_splits)
next
  case (Next I φ)
  then have "Suc i < plen π"
    by (auto intro: order.strict_trans2[OF _ progress_le[of σ φ]])
  with Next τ_prefix_conv[OF assms(1,2)] show ?case by simp
next
  case (Since φ1 I φ2)
  then have "i < plen π"
    by (auto elim!: order.strict_trans2[OF _ progress_le])
  with Since τ_prefix_conv[OF assms(1,2)] show ?case by auto
next
  case (Until φ1 I φ2)
  from Until.prems obtain b where [simp]: "right I = enat b"
    by (cases "right I") (auto simp add: Inf_UNIV_nat)
  from Until.prems obtain j where "τ σ i + b + 1  τ σ j"
    "j  progress σ φ1 (plen π)" "j  progress σ φ2 (plen π)"
    by atomize_elim (auto 0 4 simp add: less_eq_Suc_le not_le intro: Suc_leI dest: spec[of _ "i"]
      dest!: le_cInf_iff[THEN iffD1, rotated -1])
  then have 1: "k < progress σ φ1 (plen π)" and 2: "k < progress σ φ2 (plen π)"
    if "τ σ k  τ σ i + b" for k
    using that by (fastforce elim!: order.strict_trans2[rotated] intro: less_τD[of σ])+
  have 3: "k < plen π" if "τ σ k  τ σ i + b" for k
    using 1[OF that] by (simp add: less_eq_Suc_le order.trans[OF _ progress_le])

  from Until.prems have "i < progress σ' (MFOTL.Until φ1 I φ2) (plen π)"
    unfolding progress_prefix_conv[OF assms(1,2)] .
  then obtain j where "τ σ' i + b + 1  τ σ' j"
    "j  progress σ' φ1 (plen π)" "j  progress σ' φ2 (plen π)"
    by atomize_elim (auto 0 4 simp add: less_eq_Suc_le not_le intro: Suc_leI dest: spec[of _ "i"]
      dest!: le_cInf_iff[THEN iffD1, rotated -1])
  then have 11: "k < progress σ φ1 (plen π)" and 21: "k < progress σ φ2 (plen π)"
    if "τ σ' k  τ σ' i + b" for k
    unfolding progress_prefix_conv[OF assms(1,2)]
    using that by (fastforce elim!: order.strict_trans2[rotated] intro: less_τD[of σ'])+
  have 31: "k < plen π" if "τ σ' k  τ σ' i + b" for k
    using 11[OF that] by (simp add: less_eq_Suc_le order.trans[OF _ progress_le])

  show ?case unfolding sat.simps
  proof ((intro ex_cong iffI; elim conjE), goal_cases LR RL)
    case (LR j)
    with Until.IH(1)[OF 1] Until.IH(2)[OF 2] τ_prefix_conv[OF assms(1,2) 3] show ?case
      by (auto 0 4 simp: le_diff_conv add.commute dest: less_imp_le order.trans[OF τ_mono, rotated])
  next
    case (RL j)
    with Until.IH(1)[OF 11] Until.IH(2)[OF 21] τ_prefix_conv[OF assms(1,2) 31] show ?case
      by (auto 0 4 simp: le_diff_conv add.commute dest: less_imp_le order.trans[OF τ_mono, rotated])
  qed
qed


subsection ‹Specification›

definition pprogress :: "'a MFOTL.formula  'a MFOTL.prefix  nat" where
  "pprogress φ π = (THE n. σ. prefix_of π σ  progress σ φ (plen π) = n)"

lemma pprogress_eq: "prefix_of π σ  pprogress φ π = progress σ φ (plen π)"
  unfolding pprogress_def using progress_prefix_conv
  by blast

locale future_bounded_mfotl =
  fixes φ :: "'a MFOTL.formula"
  assumes future_bounded: "MFOTL.future_reach φ  "

sublocale future_bounded_mfotl  sliceable_timed_progress "MFOTL.nfv φ" "MFOTL.fv φ" "relevant_events φ"
  "λσ v i. MFOTL.sat σ v i φ" "pprogress φ"
proof (unfold_locales, goal_cases)
  case (1 x)
  then show ?case by (simp add: fvi_less_nfv)
next
  case (2 v v' σ i)
  then show ?case by (simp cong: sat_fvi_cong[rule_format])
next
  case (3 v S σ i)
  then show ?case using sat_slice_iff[of v, symmetric] by simp
next
  case (4 π π')
  moreover obtain σ where "prefix_of π' σ"
    using ex_prefix_of ..
  moreover have "prefix_of π σ"
    using prefix_of_antimono[OF π  π' prefix_of π' σ] .
  ultimately show ?case
    by (simp add: pprogress_eq plen_mono progress_mono)
next
  case (5 σ x)
  obtain j where "x  progress σ φ j"
    using future_bounded progress_ge by blast
  then have "x  pprogress φ (take_prefix j σ)"
    by (simp add: pprogress_eq[of _ σ])
  then show ?case by force
next
  case (6 π σ σ' i v)
  then have "i < progress σ φ (plen π)"
    by (simp add: pprogress_eq)
  with 6 show ?case
    using sat_prefix_conv by blast
next
  case (7 π π')
  then have "plen π = plen π'"
    by transfer (simp add: list_eq_iff_nth_eq)
  moreover obtain σ σ' where "prefix_of π σ" "prefix_of π' σ'"
    using ex_prefix_of by blast+
  moreover have "i < plen π. τ σ i = τ σ' i"
    using 7 calculation
    by transfer (simp add: list_eq_iff_nth_eq)
  ultimately show ?case
    by (simp add: pprogress_eq progress_time_conv)
qed

locale monitorable_mfotl =
  fixes φ :: "'a MFOTL.formula"
  assumes monitorable: "mmonitorable φ"

sublocale monitorable_mfotl  future_bounded_mfotl
  using monitorable by unfold_locales (simp add: mmonitorable_def)


subsection ‹Correctness›

subsubsection ‹Invariants›

definition wf_mbuf2 :: "nat  nat  nat  (nat  'a table  bool)  (nat  'a table  bool) 
  'a mbuf2  bool" where
  "wf_mbuf2 i ja jb P Q buf  i  ja  i  jb  (case buf of (xs, ys) 
    list_all2 P [i..<ja] xs  list_all2 Q [i..<jb] ys)"

definition wf_mbuf2' :: "'a MFOTL.trace  nat  nat  'a list set 
  'a MFOTL.formula  'a MFOTL.formula  'a mbuf2  bool" where
  "wf_mbuf2' σ j n R φ ψ buf  wf_mbuf2 (min (progress σ φ j) (progress σ ψ j))
    (progress σ φ j) (progress σ ψ j)
    (λi. qtable n (MFOTL.fv φ) (mem_restr R) (λv. MFOTL.sat σ (map the v) i φ))
    (λi. qtable n (MFOTL.fv ψ) (mem_restr R) (λv. MFOTL.sat σ (map the v) i ψ)) buf"

lemma wf_mbuf2'_UNIV_alt: "wf_mbuf2' σ j n UNIV φ ψ buf  (case buf of (xs, ys) 
  list_all2 (λi. wf_table n (MFOTL.fv φ) (λv. MFOTL.sat σ (map the v) i φ))
    [min (progress σ φ j) (progress σ ψ j) ..< (progress σ φ j)] xs 
  list_all2 (λi. wf_table n (MFOTL.fv ψ) (λv. MFOTL.sat σ (map the v) i ψ))
    [min (progress σ φ j) (progress σ ψ j) ..< (progress σ ψ j)] ys)"
  unfolding wf_mbuf2'_def wf_mbuf2_def
  by (simp add: mem_restr_UNIV[THEN eqTrueI, abs_def] split: prod.split)

definition wf_ts :: "'a MFOTL.trace  nat  'a MFOTL.formula  'a MFOTL.formula  ts list  bool" where
  "wf_ts σ j φ ψ ts  list_all2 (λi t. t = τ σ i) [min (progress σ φ j) (progress σ ψ j)..<j] ts"

abbreviation "Sincep pos φ I ψ  MFOTL.Since (if pos then φ else MFOTL.Neg φ) I ψ"

definition wf_since_aux :: "'a MFOTL.trace  nat  'a list set  bool 
    'a MFOTL.formula    'a MFOTL.formula  'a msaux  nat  bool" where
  "wf_since_aux σ n R pos φ I ψ aux ne  sorted_wrt (λx y. fst x > fst y) aux 
    (t X. (t, X)  set aux  ne  0  t  τ σ (ne-1)  τ σ (ne-1) - t  right I  (i. τ σ i = t) 
      qtable n (MFOTL.fv ψ) (mem_restr R) (λv. MFOTL.sat σ (map the v) (ne-1) (Sincep pos φ (point (τ σ (ne-1) - t)) ψ)) X) 
    (t. ne  0  t  τ σ (ne-1)  τ σ (ne-1) - t  right I  (i. τ σ i = t) 
      (X. (t, X)  set aux))"

lemma qtable_mem_restr_UNIV: "qtable n A (mem_restr UNIV) Q X = wf_table n A Q X"
  unfolding qtable_def by auto

lemma wf_since_aux_UNIV_alt:
  "wf_since_aux σ n UNIV pos φ I ψ aux ne  sorted_wrt (λx y. fst x > fst y) aux 
    (t X. (t, X)  set aux  ne  0  t  τ σ (ne-1)  τ σ (ne-1) - t  right I  (i. τ σ i = t) 
      wf_table n (MFOTL.fv ψ)
          (λv. MFOTL.sat σ (map the v) (ne-1) (Sincep pos φ (point (τ σ (ne-1) - t)) ψ)) X) 
    (t. ne  0  t  τ σ (ne-1)  τ σ (ne-1) - t  right I  (i. τ σ i = t) 
      (X. (t, X)  set aux))"
  unfolding wf_since_aux_def qtable_mem_restr_UNIV ..

definition wf_until_aux :: "'a MFOTL.trace  nat  'a list set  bool 
    'a MFOTL.formula    'a MFOTL.formula  'a muaux  nat  bool" where
  "wf_until_aux σ n R pos φ I ψ aux ne  list_all2 (λx i. case x of (t, r1, r2)  t = τ σ i 
      qtable n (MFOTL.fv φ) (mem_restr R) (λv. if pos then (k{i..<ne+length aux}. MFOTL.sat σ (map the v) k φ)
          else (k{i..<ne+length aux}. MFOTL.sat σ (map the v) k φ)) r1 
      qtable n (MFOTL.fv ψ) (mem_restr R) (λv. (j. i  j  j < ne + length aux  mem (τ σ j - τ σ i) I 
          MFOTL.sat σ (map the v) j ψ 
          (k{i..<j}. if pos then MFOTL.sat σ (map the v) k φ else ¬ MFOTL.sat σ (map the v) k φ))) r2)
    aux [ne..<ne+length aux]"

lemma wf_until_aux_UNIV_alt:
  "wf_until_aux σ n UNIV pos φ I ψ aux ne  list_all2 (λx i. case x of (t, r1, r2)  t = τ σ i 
      wf_table n (MFOTL.fv φ) (λv. if pos
          then (k{i..<ne+length aux}. MFOTL.sat σ (map the v) k φ)
          else (k{i..<ne+length aux}. MFOTL.sat σ (map the v) k φ)) r1 
      wf_table n (MFOTL.fv ψ) (λv. j. i  j  j < ne + length aux  mem (τ σ j - τ σ i) I 
          MFOTL.sat σ (map the v) j ψ 
          (k{i..<j}. if pos then MFOTL.sat σ (map the v) k φ else ¬ MFOTL.sat σ (map the v) k φ)) r2)
    aux [ne..<ne+length aux]"
  unfolding wf_until_aux_def qtable_mem_restr_UNIV ..
   

inductive wf_mformula :: "'a MFOTL.trace  nat 
  nat  'a list set  'a mformula  'a MFOTL.formula  bool"
  for σ j where
  Eq: "MFOTL.is_Const t1  MFOTL.is_Const t2 
    xMFOTL.fv_trm t1. x < n  xMFOTL.fv_trm t2. x < n 
    wf_mformula σ j n R (MRel (eq_rel n t1 t2)) (MFOTL.Eq t1 t2)"
| neq_Const: "φ = MRel (neq_rel n (MFOTL.Const x) (MFOTL.Const y)) 
    wf_mformula σ j n R φ (MFOTL.Neg (MFOTL.Eq (MFOTL.Const x) (MFOTL.Const y)))"
| neq_Var: "x < n 
    wf_mformula σ j n R (MRel empty_table) (MFOTL.Neg (MFOTL.Eq (MFOTL.Var x) (MFOTL.Var x)))"
| Pred: "xMFOTL.fv (MFOTL.Pred e ts). x < n 
    wf_mformula σ j n R (MPred e ts) (MFOTL.Pred e ts)"
| And: "wf_mformula σ j n R φ φ'  wf_mformula σ j n R ψ ψ' 
    if pos then χ = MFOTL.And φ' ψ'  ¬ (safe_formula (MFOTL.Neg ψ')  MFOTL.fv ψ'  MFOTL.fv φ')
      else χ = MFOTL.And_Not φ' ψ'  safe_formula ψ'  MFOTL.fv ψ'  MFOTL.fv φ' 
    wf_mbuf2' σ j n R φ' ψ' buf 
    wf_mformula σ j n R (MAnd φ pos ψ buf) χ"
| Or: "wf_mformula σ j n R φ φ'  wf_mformula σ j n R ψ ψ' 
    MFOTL.fv φ' = MFOTL.fv ψ' 
    wf_mbuf2' σ j n R φ' ψ' buf 
    wf_mformula σ j n R (MOr φ ψ buf) (MFOTL.Or φ' ψ')"
| Exists: "wf_mformula σ j (Suc n) (lift_envs R) φ φ' 
    wf_mformula σ j n R (MExists φ) (MFOTL.Exists φ')"
| Prev: "wf_mformula σ j n R φ φ' 
    first  j = 0 
    list_all2 (λi. qtable n (MFOTL.fv φ') (mem_restr R) (λv. MFOTL.sat σ (map the v) i φ'))
      [min (progress σ φ' j) (j-1)..<progress σ φ' j] buf 
    list_all2 (λi t. t = τ σ i) [min (progress σ φ' j) (j-1)..<j] nts 
    wf_mformula σ j n R (MPrev I φ first buf nts) (MFOTL.Prev I φ')"
| Next: "wf_mformula σ j n R φ φ' 
    first  progress σ φ' j = 0 
    list_all2 (λi t. t = τ σ i) [progress σ φ' j - 1..<j] nts 
    wf_mformula σ j n R (MNext I φ first nts) (MFOTL.Next I φ')"
| Since: "wf_mformula σ j n R φ φ'  wf_mformula σ j n R ψ ψ' 
    if pos then φ'' = φ' else φ'' = MFOTL.Neg φ' 
    safe_formula φ'' = pos 
    MFOTL.fv φ'  MFOTL.fv ψ' 
    wf_mbuf2' σ j n R φ' ψ' buf 
    wf_ts σ j φ' ψ' nts 
    wf_since_aux σ n R pos φ' I ψ' aux (progress σ (MFOTL.Since φ'' I ψ') j) 
    wf_mformula σ j n R (MSince pos φ I ψ buf nts aux) (MFOTL.Since φ'' I ψ')"
| Until: "wf_mformula σ j n R φ φ'  wf_mformula σ j n R ψ ψ' 
    if pos then φ'' = φ' else φ'' = MFOTL.Neg φ' 
    safe_formula φ'' = pos 
    MFOTL.fv φ'  MFOTL.fv ψ' 
    wf_mbuf2' σ j n R φ' ψ' buf 
    wf_ts σ j φ' ψ' nts 
    wf_until_aux σ n R pos φ' I ψ' aux (progress σ (MFOTL.Until φ'' I ψ') j) 
    progress σ (MFOTL.Until φ'' I ψ') j + length aux = min (progress σ φ' j) (progress σ ψ' j) 
    wf_mformula σ j n R (MUntil pos φ I ψ buf nts aux) (MFOTL.Until φ'' I ψ')"

definition wf_mstate :: "'a MFOTL.formula  'a MFOTL.prefix  'a list set  'a mstate  bool" where
  "wf_mstate φ π R st  mstate_n st = MFOTL.nfv φ  (σ. prefix_of π σ 
    mstate_i st = progress σ φ (plen π) 
    wf_mformula σ (plen π) (mstate_n st) R (mstate_m st) φ)"


subsubsection ‹Initialisation›

lemma minit0_And: "¬ (safe_formula (MFOTL.Neg ψ)  MFOTL.fv ψ  MFOTL.fv φ) 
     minit0 n (MFOTL.And φ ψ) = MAnd (minit0 n φ) True (minit0 n ψ) ([], [])"
  unfolding MFOTL.And_def by simp

lemma minit0_And_Not: "safe_formula ψ  MFOTL.fv ψ  MFOTL.fv φ 
  minit0 n (MFOTL.And_Not φ ψ) = (MAnd (minit0 n φ) False (minit0 n ψ) ([], []))"
  unfolding MFOTL.And_Not_def MFOTL.is_Neg_def by (simp split: formula.split)

lemma wf_mbuf2'_0: "wf_mbuf2' σ 0 n R φ ψ ([], [])"
  unfolding wf_mbuf2'_def wf_mbuf2_def by simp

lemma wf_ts_0: "wf_ts σ 0 φ ψ []"
  unfolding wf_ts_def by simp

lemma wf_since_aux_Nil: "wf_since_aux σ n R pos φ' I ψ' [] 0"
  unfolding wf_since_aux_def by simp

lemma wf_until_aux_Nil: "wf_until_aux σ n R pos φ' I ψ' [] 0"
  unfolding wf_until_aux_def by simp

lemma wf_minit0: "safe_formula φ  xMFOTL.fv φ. x < n 
  wf_mformula σ 0 n R (minit0 n φ) φ"
  by (induction arbitrary: n R rule: safe_formula_induct)
    (auto simp add: minit0_And fvi_And minit0_And_Not fvi_And_Not
      intro!: wf_mformula.intros wf_mbuf2'_0 wf_ts_0 wf_since_aux_Nil wf_until_aux_Nil
      dest: fvi_Suc_bound)

lemma wf_mstate_minit: "safe_formula φ  wf_mstate φ pnil R (minit φ)"
  unfolding wf_mstate_def minit_def Let_def
  by (auto intro!: wf_minit0 fvi_less_nfv)


subsubsection ‹Evaluation›

lemma match_wf_tuple: "Some f = match ts xs  wf_tuple n (tset ts. MFOTL.fv_trm t) (tabulate f 0 n)"
  by (induction ts xs arbitrary: f rule: match.induct)
    (fastforce simp: wf_tuple_def split: if_splits option.splits)+

lemma match_fvi_trm_None: "Some f = match ts xs  tset ts. x  MFOTL.fv_trm t  f x = None"
  by (induction ts xs arbitrary: f rule: match.induct) (auto split: if_splits option.splits)

lemma match_fvi_trm_Some: "Some f = match ts xs  t  set ts  x  MFOTL.fv_trm t  f x  None"
  by (induction ts xs arbitrary: f rule: match.induct) (auto split: if_splits option.splits)

lemma match_eval_trm: "tset ts. iMFOTL.fv_trm t. i < n  Some f = match ts xs 
    map (MFOTL.eval_trm (tabulate (λi. the (f i)) 0 n)) ts = xs"
proof (induction ts xs arbitrary: f rule: match.induct)
  case (3 x ts y ys)
  from 3(1)[symmetric] 3(2,3) show ?case
    by (auto 0 3 dest: match_fvi_trm_Some sym split: option.splits if_splits intro!: eval_trm_cong)
qed (auto split: if_splits)

lemma wf_tuple_tabulate_Some: "wf_tuple n A (tabulate f 0 n)  x  A  x < n  y. f x = Some y"
  unfolding wf_tuple_def by auto

lemma ex_match: "wf_tuple n (tset ts. MFOTL.fv_trm t) v  tset ts. xMFOTL.fv_trm t. x < n 
    f. match ts (map (MFOTL.eval_trm (map the v)) ts) = Some f  v = tabulate f 0 n"
proof (induction ts "map (MFOTL.eval_trm (map the v)) ts" arbitrary: v rule: match.induct)
  case (3 x ts y ys)
  then show ?case
  proof (cases "x  (tset ts. MFOTL.fv_trm t)")
    case True
    with 3 show ?thesis
      by (auto simp: insert_absorb dest!: wf_tuple_tabulate_Some meta_spec[of _ v])
  next
    case False
    with 3(3,4) have
      *: "map (MFOTL.eval_trm (map the v)) ts = map (MFOTL.eval_trm (map the (v[x := None]))) ts"
      by (auto simp: wf_tuple_def nth_list_update intro!: eval_trm_cong)
    from False 3(2-4) obtain f where
      "match ts (map (MFOTL.eval_trm (map the v)) ts) = Some f" "v[x := None] = tabulate f 0 n"
      unfolding *
      by (atomize_elim, intro 3(1)[of "v[x := None]"])
        (auto simp: wf_tuple_def nth_list_update intro!: eval_trm_cong)
    moreover from False this have "f x = None" "length v = n"
      by (auto dest: match_fvi_trm_None[OF sym] arg_cong[of _ _ length])
    ultimately show ?thesis using 3(3)
      by (auto simp: list_eq_iff_nth_eq wf_tuple_def)
  qed
qed (auto simp: wf_tuple_def intro: nth_equalityI)

lemma eq_rel_eval_trm: "v  eq_rel n t1 t2  MFOTL.is_Const t1  MFOTL.is_Const t2 
  xMFOTL.fv_trm t1  MFOTL.fv_trm t2. x < n 
  MFOTL.eval_trm (map the v) t1 = MFOTL.eval_trm (map the v) t2"
  by (cases t1; cases t2) (simp_all add: singleton_table_def split: if_splits)

lemma in_eq_rel: "wf_tuple n (MFOTL.fv_trm t1  MFOTL.fv_trm t2) v 
  MFOTL.is_Const t1  MFOTL.is_Const t2 
  MFOTL.eval_trm (map the v) t1 = MFOTL.eval_trm (map the v) t2 
  v  eq_rel n t1 t2"
  by (cases t1; cases t2)
    (auto simp: singleton_table_def wf_tuple_def unit_table_def intro!: nth_equalityI split: if_splits)

lemma table_eq_rel: "MFOTL.is_Const t1  MFOTL.is_Const t2 
  table n (MFOTL.fv_trm t1  MFOTL.fv_trm t2) (eq_rel n t1 t2)"
  by (cases t1; cases t2; simp)

lemma wf_tuple_Suc_fviD: "wf_tuple (Suc n) (MFOTL.fvi b φ) v  wf_tuple n (MFOTL.fvi (Suc b) φ) (tl v)"
  unfolding wf_tuple_def by (simp add: fvi_Suc nth_tl)

lemma table_fvi_tl: "table (Suc n) (MFOTL.fvi b φ) X  table n (MFOTL.fvi (Suc b) φ) (tl ` X)"
  unfolding table_def by (auto intro: wf_tuple_Suc_fviD)

lemma wf_tuple_Suc_fvi_SomeI: "0  MFOTL.fvi b φ  wf_tuple n (MFOTL.fvi (Suc b) φ) v 
  wf_tuple (Suc n) (MFOTL.fvi b φ) (Some x # v)"
  unfolding wf_tuple_def
  by (auto simp: fvi_Suc less_Suc_eq_0_disj)

lemma wf_tuple_Suc_fvi_NoneI: "0  MFOTL.fvi b φ  wf_tuple n (MFOTL.fvi (Suc b) φ) v 
  wf_tuple (Suc n) (MFOTL.fvi b φ) (None # v)"
  unfolding wf_tuple_def
  by (auto simp: fvi_Suc less_Suc_eq_0_disj)

lemma qtable_project_fv: "qtable (Suc n) (fv φ) (mem_restr (lift_envs R)) P X 
    qtable n (MFOTL.fvi (Suc 0) φ) (mem_restr R)
      (λv. x. P ((if 0  fv φ then Some x else None) # v)) (tl ` X)"
  using neq0_conv by (fastforce simp: image_iff Bex_def fvi_Suc elim!: qtable_cong dest!: qtable_project)

lemma mprev: "mprev_next I xs ts = (ys, xs', ts') 
  list_all2 P [i..<j'] xs  list_all2 (λi t. t = τ σ i) [i..<j] ts  i  j'  i < j 
  list_all2 (λi X. if mem (τ σ (Suc i) - τ σ i) I then P i X else X = empty_table)
    [i..<min j' (j-1)] ys 
  list_all2 P [min j' (j-1)..<j'] xs' 
  list_all2 (λi t. t = τ σ i) [min j' (j-1)..<j] ts'"
proof (induction I xs ts arbitrary: i ys xs' ts' rule: mprev_next.induct)
  case (1 I ts)
  then have "min j' (j-1) = i" by auto
  with 1 show ?case by auto
next
  case (3 I v v' t)
  then have "min j' (j-1) = i" by (auto simp: list_all2_Cons2 upt_eq_Cons_conv)
  with 3 show ?case by auto
next
  case (4 I x xs t t' ts)
  from 4(1)[of "tl ys" xs' ts' "Suc i"] 4(2-6) show ?case
    by (auto simp add: list_all2_Cons2 upt_eq_Cons_conv Suc_less_eq2
      elim!: list.rel_mono_strong split: prod.splits if_splits)
qed simp

lemma mnext: "mprev_next I xs ts = (ys, xs', ts') 
  list_all2 P [Suc i..<j'] xs  list_all2 (λi t. t = τ σ i) [i..<j] ts  Suc i  j'  i < j 
  list_all2 (λi X. if mem (τ σ (Suc i) - τ σ i) I then P (Suc i) X else X = empty_table)
    [i..<min (j'-1) (j-1)] ys 
  list_all2 P [Suc (min (j'-1) (j-1))..<j'] xs' 
  list_all2 (λi t. t = τ σ i) [min (j'-1) (j-1)..<j] ts'"
proof (induction I xs ts arbitrary: i ys xs' ts' rule: mprev_next.induct)
  case (1 I ts)
  then have "min (j' - 1) (j-1) = i" by auto
  with 1 show ?case by auto
next
  case (3 I v v' t)
  then have "min (j' - 1) (j-1) = i" by (auto simp: list_all2_Cons2 upt_eq_Cons_conv)
  with 3 show ?case by auto
next
  case (4 I x xs t t' ts)
  from 4(1)[of "tl ys" xs' ts' "Suc i"] 4(2-6) show ?case
    by (auto simp add: list_all2_Cons2 upt_eq_Cons_conv Suc_less_eq2
      elim!: list.rel_mono_strong split: prod.splits if_splits) (* slow 10 sec *)
qed simp

lemma in_foldr_UnI: "x  A  A  set xs  x  foldr (∪) xs {}"
  by (induction xs) auto

lemma in_foldr_UnE: "x  foldr (∪) xs {}  (A. A  set xs  x  A  P)  P"
  by (induction xs) auto

lemma sat_the_restrict: "fv φ  A  MFOTL.sat σ (map the (restrict A v)) i φ = MFOTL.sat σ (map the v) i φ"
  by (rule sat_fvi_cong) (auto intro!: map_the_restrict)

lemma update_since:
  assumes pre: "wf_since_aux σ n R pos φ I ψ aux ne"
    and qtable1: "qtable n (MFOTL.fv φ) (mem_restr R) (λv. MFOTL.sat σ (map the v) ne φ) rel1"
    and qtable2: "qtable n (MFOTL.fv ψ) (mem_restr R) (λv. MFOTL.sat σ (map the v) ne ψ) rel2"
    and result_eq: "(rel, aux') = update_since I pos rel1 rel2 (τ σ ne) aux"
    and fvi_subset: "MFOTL.fv φ  MFOTL.fv ψ"
  shows "wf_since_aux σ n R pos φ I ψ aux' (Suc ne)"
    and "qtable n (MFOTL.fv ψ) (mem_restr R) (λv. MFOTL.sat σ (map the v) ne (Sincep pos φ I ψ)) rel"
proof -
  let ?wf_tuple = "λv. wf_tuple n (MFOTL.fv ψ) v"
  note sat.simps[simp del]

  define aux0 where "aux0 = [(t, join rel pos rel1). (t, rel)  aux, τ σ ne - t  right I]"
  have sorted_aux0: "sorted_wrt (λx y. fst x > fst y) aux0"
    using pre[unfolded wf_since_aux_def, THEN conjunct1]
    unfolding aux0_def
    by (induction aux) (auto simp add: sorted_wrt_append)
  have in_aux0_1: "(t, X)  set aux0  ne  0  t  τ σ (ne-1)  τ σ ne - t  right I 
      (i. τ σ i = t) 
      qtable n (MFOTL.fv ψ) (mem_restr R) (λv. (MFOTL.sat σ (map the v) (ne-1) (Sincep pos φ (point (τ σ (ne-1) - t)) ψ) 
        (if pos then MFOTL.sat σ (map the v) ne φ else ¬ MFOTL.sat σ (map the v) ne φ))) X" for t X
    unfolding aux0_def using fvi_subset
    by (auto 0 1 elim!: qtable_join[OF _ qtable1] simp: sat_the_restrict
      dest!: assms(1)[unfolded wf_since_aux_def, THEN conjunct2, THEN conjunct1, rule_format])
  then have in_aux0_le_τ: "(t, X)  set aux0  t  τ σ ne" for t X
    by (meson τ_mono diff_le_self le_trans)
  have in_aux0_2: "ne  0  t  τ σ (ne-1)  τ σ ne - t  right I  i. τ σ i = t 
    X. (t, X)  set aux0" for t
  proof -
    fix t
    assume "ne  0" "t  τ σ (ne-1)" "τ σ ne - t  right I" "i. τ σ i = t"
    then obtain X where "(t, X)  set aux"
      by (atomize_elim, intro assms(1)[unfolded wf_since_aux_def, THEN conjunct2, THEN conjunct2, rule_format])
        (auto simp: gr0_conv_Suc elim!: order_trans[rotated] intro!: diff_le_mono τ_mono)
    with τ σ ne - t  right I have "(t, join X pos rel1)  set aux0" 
      unfolding aux0_def by (auto elim!: bexI[rotated] intro!: exI[of _ X])
    then show "X. (t, X)  set aux0"
      by blast
  qed
  have aux0_Nil: "aux0 = []  ne = 0  ne  0  (t. t  τ σ (ne-1)  τ σ ne - t  right I 
        (i. τ σ i = t))"
    using in_aux0_2 by (cases "ne = 0") (auto)

  have aux'_eq: "aux' = (case aux0 of
      []  [(τ σ ne, rel2)]
    | x # aux'  (if fst x = τ σ ne then (fst x, snd x  rel2) # aux' else (τ σ ne, rel2) # x # aux'))"
    using result_eq unfolding aux0_def update_since_def Let_def by simp
  have sorted_aux': "sorted_wrt (λx y. fst x > fst y) aux'"
    unfolding aux'_eq
    using sorted_aux0 in_aux0_le_τ by (cases aux0) (fastforce)+
  have in_aux'_1: "t  τ σ ne  τ σ ne - t  right I  (i. τ σ i = t) 
      qtable n (MFOTL.fv ψ) (mem_restr R) (λv. MFOTL.sat σ (map the v) ne (Sincep pos φ (point (τ σ ne - t)) ψ)) X"
    if aux': "(t, X)  set aux'" for t X
  proof (cases aux0)
    case Nil
    with aux' show ?thesis 
      unfolding aux'_eq using qtable2 aux0_Nil
      by (auto simp: zero_enat_def[symmetric] sat_Since_rec[where i=ne]
        dest: spec[of _ "τ σ (ne-1)"] elim!: qtable_cong[OF _ refl])
  next
    case (Cons a as)
    show ?thesis
    proof (cases "t = τ σ ne")
      case t: True
      show ?thesis
      proof (cases "fst a = τ σ ne")
        case True
        with aux' Cons t have "X = snd a  rel2"
          unfolding aux'_eq using sorted_aux0 by auto
        moreover from in_aux0_1[of "fst a" "snd a"] Cons have "ne  0"
          "fst a  τ σ (ne - 1)" "τ σ ne - fst a  right I" "i. τ σ i = fst a"
          "qtable n (fv ψ) (mem_restr R) (λv. MFOTL.sat σ (map the v) (ne - 1)
            (Sincep pos φ (point (τ σ (ne - 1) - fst a)) ψ)  (if pos then MFOTL.sat σ (map the v) ne φ
              else ¬ MFOTL.sat σ (map the v) ne φ)) (snd a)"
          by auto
        ultimately show ?thesis using qtable2 t True
          by (auto simp: sat_Since_rec[where i=ne] sat.simps(3) elim!: qtable_union)
      next
        case False
        with aux' Cons t have "X = rel2"
          unfolding aux'_eq using sorted_aux0 in_aux0_le_τ[of "fst a" "snd a"] by auto
        with aux' Cons t False show ?thesis
          unfolding aux'_eq using qtable2 in_aux0_2[of "τ σ (ne-1)"] in_aux0_le_τ[of "fst a" "snd a"] sorted_aux0
          by (auto simp: sat_Since_rec[where i=ne] sat.simps(3) zero_enat_def[symmetric] enat_0_iff not_le
            elim!: qtable_cong[OF _ refl] dest!: le_τ_less meta_mp)
    qed
    next
      case False
      with aux' Cons have "(t, X)  set aux0"
        unfolding aux'_eq by (auto split: if_splits)
      then have "ne  0" "t  τ σ (ne - 1)" "τ σ ne - t  right I" "i. τ σ i = t"
        "qtable n (fv ψ) (mem_restr R) (λv. MFOTL.sat σ (map the v) (ne - 1) (Sincep pos φ (point (τ σ (ne - 1) - t)) ψ) 
           (if pos then MFOTL.sat σ (map the v) ne φ else ¬ MFOTL.sat σ (map the v) ne φ)) X"
        using in_aux0_1 by blast+
      with False aux' Cons show ?thesis
        unfolding aux'_eq using qtable2
        by (fastforce simp: sat_Since_rec[where i=ne] sat.simps(3)
          diff_diff_right[where i="τ σ ne" and j="τ σ _ + τ σ ne" and k="τ σ (ne - 1)",
            OF trans_le_add2, simplified] elim!: qtable_cong[OF _ refl] order_trans dest: le_τ_less)
    qed
  qed

  have in_aux'_2: "X. (t, X)  set aux'" if "t  τ σ ne" "τ σ ne - t  right I" "i. τ σ i = t" for t
  proof (cases "t = τ σ ne")
    case True
    then show ?thesis
    proof (cases aux0)
      case Nil
      with True show ?thesis unfolding aux'_eq by simp
    next
      case (Cons a as)
      with True show ?thesis unfolding aux'_eq
        by (cases "fst a = τ σ ne") auto
    qed
  next
    case False
    with that have "ne  0"
      using le_τ_less neq0_conv by blast
    moreover from False that have  "t  τ σ (ne-1)"
      by (metis One_nat_def Suc_leI Suc_pred τ_mono diff_is_0_eq' order.antisym neq0_conv not_le)
    ultimately obtain X where "(t, X)  set aux0" using τ σ ne - t  right I i. τ σ i = t
      by atomize_elim (auto intro!: in_aux0_2)
    then show ?thesis unfolding aux'_eq using False
      by (auto intro: exI[of _ X] split: list.split)
  qed

  show "wf_since_aux σ n R pos φ I ψ aux' (Suc ne)"
    unfolding wf_since_aux_def
    by (auto dest: in_aux'_1 intro: sorted_aux' in_aux'_2)

  have rel_eq: "rel = foldr (∪) [rel. (t, rel)  aux', left I  τ σ ne - t] {}"
    unfolding aux'_eq aux0_def
    using result_eq by (simp add: update_since_def Let_def)
  have rel_alt: "rel = ((t, rel)  set aux'. if left I  τ σ ne - t then rel else empty_table)"
    unfolding rel_eq
    by (auto elim!: in_foldr_UnE bexI[rotated] intro!: in_foldr_UnI)
  show "qtable n (fv ψ) (mem_restr R) (λv. MFOTL.sat σ (map the v) ne (Sincep pos φ I ψ)) rel"
    unfolding rel_alt
  proof (rule qtable_Union[where Qi="λ(t, X) v.
    left I  τ σ ne - t  MFOTL.sat σ (map the v) ne (Sincep pos φ (point (τ σ ne - t)) ψ)"],
    goal_cases finite qtable equiv)
    case (equiv v)
    show ?case
    proof (rule iffI, erule sat_Since_point, goal_cases left right)
      case (left j)
      then show ?case using in_aux'_2[of "τ σ j", OF _ _ exI, OF _ _ refl] by auto
    next
      case right
      then show ?case by (auto elim!: sat_Since_pointD dest: in_aux'_1)
    qed
  qed (auto dest!: in_aux'_1 intro!: qtable_empty)
qed

lemma length_update_until: "length (update_until pos I rel1 rel2 nt aux) = Suc (length aux)"
  unfolding update_until_def by simp

lemma wf_update_until:
  assumes pre: "wf_until_aux σ n R pos φ I ψ aux ne"
    and qtable1: "qtable n (MFOTL.fv φ) (mem_restr R) (λv. MFOTL.sat σ (map the v) (ne + length aux) φ) rel1"
    and qtable2: "qtable n (MFOTL.fv ψ) (mem_restr R) (λv. MFOTL.sat σ (map the v) (ne + length aux) ψ) rel2"
    and fvi_subset: "MFOTL.fv φ  MFOTL.fv ψ"
  shows "wf_until_aux σ n R pos φ I ψ (update_until I pos rel1 rel2 (τ σ (ne + length aux)) aux) ne"
  unfolding wf_until_aux_def length_update_until
  unfolding update_until_def list.rel_map add_Suc_right upt.simps eqTrueI[OF le_add1] if_True
proof (rule list_all2_appendI, unfold list.rel_map, goal_cases old new)
  case old
  show ?case
  proof (rule list.rel_mono_strong[OF assms(1)[unfolded wf_until_aux_def]]; safe, goal_cases mono1 mono2)
    case (mono1 i X Y v)
    then show ?case
      by (fastforce simp: sat_the_restrict less_Suc_eq
        elim!: qtable_join[OF _ qtable1] qtable_union[OF _ qtable1])
  next
    case (mono2 i X Y v)
    then show ?case using fvi_subset
      by (auto 0 3 simp: sat_the_restrict less_Suc_eq split: if_splits
        elim!: qtable_union[OF _ qtable_join_fixed[OF qtable2]]
        elim: qtable_cong[OF _ refl] intro: exI[of _ "ne + length aux"]) (* slow 8 sec*)
  qed
next
  case new
  then show ?case 
    by (auto intro!: qtable_empty qtable1 qtable2[THEN qtable_cong] exI[of _ "ne + length aux"]
      simp: less_Suc_eq zero_enat_def[symmetric])
qed

lemma wf_until_aux_Cons: "wf_until_aux σ n R pos φ I ψ (a # aux) ne 
  wf_until_aux σ n R pos φ I ψ aux (Suc ne)"
  unfolding wf_until_aux_def
  by (simp add: upt_conv_Cons del: upt_Suc cong: if_cong)

lemma wf_until_aux_Cons1: "wf_until_aux σ n R pos φ I ψ ((t, a1, a2) # aux) ne  t = τ σ ne"
  unfolding wf_until_aux_def
  by (simp add: upt_conv_Cons del: upt_Suc)

lemma wf_until_aux_Cons3: "wf_until_aux σ n R pos φ I ψ ((t, a1, a2) # aux) ne 
  qtable n (MFOTL.fv ψ) (mem_restr R) (λv. (j. ne  j  j < Suc (ne + length aux)  mem (τ σ j - τ σ ne) I 
    MFOTL.sat σ (map the v) j ψ  (k{ne..<j}. if pos then MFOTL.sat σ (map the v) k φ else ¬ MFOTL.sat σ (map the v) k φ))) a2"
  unfolding wf_until_aux_def
  by (simp add: upt_conv_Cons del: upt_Suc)

lemma upt_append: "a  b  b  c  [a..<b] @ [b..<c] = [a..<c]"
  by (metis le_Suc_ex upt_add_eq_append)

lemma wf_mbuf2_add:
  assumes "wf_mbuf2 i ja jb P Q buf"
    and "list_all2 P [ja..<ja'] xs"
    and "list_all2 Q [jb..<jb'] ys"
    and "ja  ja'" "jb  jb'"
  shows "wf_mbuf2 i ja' jb' P Q (mbuf2_add xs ys buf)"
  using assms unfolding wf_mbuf2_def
  by (auto 0 3 simp: list_all2_append2 upt_append dest: list_all2_lengthD
    intro: exI[where x="[i..<ja]"] exI[where x="[ja..<ja']"]
           exI[where x="[i..<jb]"] exI[where x="[jb..<jb']"] split: prod.splits)

lemma mbuf2_take_eqD:
  assumes "mbuf2_take f buf = (xs, buf')"
    and "wf_mbuf2 i ja jb P Q buf"
  shows "wf_mbuf2 (min ja jb) ja jb P Q buf'"
    and "list_all2 (λi z. x y. P i x  Q i y  z = f x y) [i..<min ja jb] xs"
  using assms unfolding wf_mbuf2_def
  by (induction f buf arbitrary: i xs buf' rule: mbuf2_take.induct)
    (fastforce simp add: list_all2_Cons2 upt_eq_Cons_conv min_absorb1 min_absorb2 split: prod.splits)+

lemma mbuf2t_take_eqD:
  assumes "mbuf2t_take f z buf nts = (z', buf', nts')"
    and "wf_mbuf2 i ja jb P Q buf"
    and "list_all2 R [i..<j] nts"
    and "ja  j" "jb  j"
  shows "wf_mbuf2 (min ja jb) ja jb P Q buf'"
    and "list_all2 R [min ja jb..<j] nts'"
  using assms unfolding wf_mbuf2_def
  by (induction f z buf nts arbitrary: i z' buf' nts' rule: mbuf2t_take.induct)
    (auto simp add: list_all2_Cons2 upt_eq_Cons_conv less_eq_Suc_le min_absorb1 min_absorb2
      split: prod.split)

lemma mbuf2t_take_induct[consumes 5, case_names base step]:
  assumes "mbuf2t_take f z buf nts = (z', buf', nts')"
    and "wf_mbuf2 i ja jb P Q buf"
    and "list_all2 R [i..<j] nts"
    and "ja  j" "jb  j"
    and "U i z"
    and "k x y t z. i  k  Suc k  ja  Suc k  jb 
      P k x  Q k y  R k t  U k z  U (Suc k) (f x y t z)"
  shows "U (min ja jb) z'"
  using assms unfolding wf_mbuf2_def
  by (induction f z buf nts arbitrary: i z' buf' nts' rule: mbuf2t_take.induct)
    (auto simp add: list_all2_Cons2 upt_eq_Cons_conv less_eq_Suc_le min_absorb1 min_absorb2
       elim!: arg_cong2[of _ _ _ _ U, OF _ refl, THEN iffD1, rotated] split: prod.split)

lemma mbuf2_take_add':
  assumes eq: "mbuf2_take f (mbuf2_add xs ys buf) = (zs, buf')"
    and pre: "wf_mbuf2' σ j n R φ ψ buf"
    and xs: "list_all2 (λi. qtable n (MFOTL.fv φ) (mem_restr R) (λv. MFOTL.sat σ (map the v) i φ))
      [progress σ φ j..<progress σ φ j'] xs"
    and ys: "list_all2 (λi. qtable n (MFOTL.fv ψ) (mem_restr R) (λv. MFOTL.sat σ (map the v) i ψ))
      [progress σ ψ j..<progress σ ψ j'] ys"
    and "j  j'"
  shows "wf_mbuf2' σ j' n R φ ψ buf'"
    and "list_all2 (λi Z. X Y.
      qtable n (MFOTL.fv φ) (mem_restr R) (λv. MFOTL.sat σ (map the v) i φ) X 
      qtable n (MFOTL.fv ψ) (mem_restr R) (λv. MFOTL.sat σ (map the v) i ψ) Y 
      Z = f X Y)
      [min (progress σ φ j) (progress σ ψ j)..<min (progress σ φ j') (progress σ ψ j')] zs"
  using pre unfolding wf_mbuf2'_def
  by (force intro!: mbuf2_take_eqD[OF eq] wf_mbuf2_add[OF _ xs ys] progress_mono[OF j  j'])+

lemma mbuf2t_take_add':
  assumes eq: "mbuf2t_take f z (mbuf2_add xs ys buf) nts = (z', buf', nts')"
    and pre_buf: "wf_mbuf2' σ j n R φ ψ buf"
    and pre_nts: "list_all2 (λi t. t = τ σ i) [min (progress σ φ j) (progress σ ψ j)..<j'] nts"
    and xs: "list_all2 (λi. qtable n (MFOTL.fv φ) (mem_restr R) (λv. MFOTL.sat σ (map the v) i φ))
      [progress σ φ j..<progress σ φ j'] xs"
    and ys: "list_all2 (λi. qtable n (MFOTL.fv ψ) (mem_restr R) (λv. MFOTL.sat σ (map the v) i ψ))
      [progress σ ψ j..<progress σ ψ j'] ys"
    and "j  j'"
  shows "wf_mbuf2' σ j' n R φ ψ buf'"
    and "wf_ts σ j' φ ψ nts'"
  using pre_buf pre_nts unfolding wf_mbuf2'_def wf_ts_def
  by (blast intro!: mbuf2t_take_eqD[OF eq] wf_mbuf2_add[OF _ xs ys] progress_mono[OF j  j']
      progress_le)+

lemma mbuf2t_take_add_induct'[consumes 6, case_names base step]:
  assumes eq: "mbuf2t_take f z (mbuf2_add xs ys buf) nts = (z', buf', nts')"
    and pre_buf: "wf_mbuf2' σ j n R φ ψ buf"
    and pre_nts: "list_all2 (λi t. t = τ σ i) [min (progress σ φ j) (progress σ ψ j)..<j'] nts"
    and xs: "list_all2 (λi. qtable n (MFOTL.fv φ) (mem_restr R) (λv. MFOTL.sat σ (map the v) i φ))
      [progress σ φ j..<progress σ φ j'] xs"
    and ys: "list_all2 (λi. qtable n (MFOTL.fv ψ) (mem_restr R) (λv. MFOTL.sat σ (map the v) i ψ))
      [progress σ ψ j..<progress σ ψ j'] ys"
    and "j  j'"
    and base: "U (min (progress σ φ j) (progress σ ψ j)) z"
    and step: "k X Y z. min (progress σ φ j) (progress σ ψ j)  k 
      Suc k  progress σ φ j'  Suc k  progress σ ψ j' 
      qtable n (MFOTL.fv φ) (mem_restr R) (λv. MFOTL.sat σ (map the v) k φ) X 
      qtable n (MFOTL.fv ψ) (mem_restr R) (λv. MFOTL.sat σ (map the v) k ψ) Y 
      U k z  U (Suc k) (f X Y (τ σ k) z)"
  shows "U (min (progress σ φ j') (progress σ ψ j')) z'"
  using pre_buf pre_nts unfolding wf_mbuf2'_def wf_ts_def
  by (blast intro!: mbuf2t_take_induct[OF eq] wf_mbuf2_add[OF _ xs ys] progress_mono[OF j  j']
      progress_le base step)

lemma progress_Until_le: "progress σ (formula.Until φ I ψ) j  min (progress σ φ j) (progress σ ψ j)"
  by (cases "right I") (auto simp: trans_le_add1 intro!: cInf_lower)

lemma list_all2_upt_Cons: "P a x  list_all2 P [Suc a..<b] xs  Suc a  b 
  list_all2 P [a..<b] (x # xs)"
  by (simp add: list_all2_Cons2 upt_eq_Cons_conv)

lemma list_all2_upt_append: "list_all2 P [a..<b] xs  list_all2 P [b..<c] ys 
  a  b  b  c  list_all2 P [a..<c] (xs @ ys)"
  by (induction xs arbitrary: a) (auto simp add: list_all2_Cons2 upt_eq_Cons_conv)

lemma meval:
  assumes "wf_mformula σ j n R φ φ'"
  shows "case meval n (τ σ j) (Γ σ j) φ of (xs, φn)  wf_mformula σ (Suc j) n R φn φ' 
    list_all2 (λi. qtable n (MFOTL.fv φ') (mem_restr R) (λv. MFOTL.sat σ (map the v) i φ'))
    [progress σ φ' j..<progress σ φ' (Suc j)] xs"
using assms proof (induction φ arbitrary: n R φ')
  case (MRel rel)
  then show ?case
    by (cases pred: wf_mformula)
      (auto simp add: ball_Un intro: wf_mformula.intros qtableI table_eq_rel eq_rel_eval_trm
        in_eq_rel qtable_empty qtable_unit_table)
next
  case (MPred e ts)
  then show ?case
    by (cases pred: wf_mformula)
      (auto 0 4 simp: table_def in_these_eq match_wf_tuple match_eval_trm image_iff dest: ex_match
        split: if_splits intro!: wf_mformula.intros qtableI elim!: bexI[rotated])
next
  case (MAnd φ pos ψ buf)
  from MAnd.prems show ?case
    by (cases pred: wf_mformula)
      (auto simp: fvi_And sat_And fvi_And_Not sat_And_Not sat_the_restrict
       dest!: MAnd.IH split: if_splits prod.splits intro!: wf_mformula.And qtable_join
       dest: mbuf2_take_add' elim!: list.rel_mono_strong)
next
  case (MOr φ ψ buf)
  from MOr.prems show ?case
    by (cases pred: wf_mformula)
      (auto dest!: MOr.IH split: if_splits prod.splits intro!: wf_mformula.Or qtable_union
       dest: mbuf2_take_add' elim!: list.rel_mono_strong)
next
  case (MExists φ)
  from MExists.prems show ?case
    by (cases pred: wf_mformula)
      (force simp: list.rel_map fvi_Suc sat_fvi_cong nth_Cons'
        intro!: wf_mformula.Exists dest!: MExists.IH qtable_project_fv 
        elim!: list.rel_mono_strong table_fvi_tl qtable_cong sat_fvi_cong[THEN iffD1, rotated -1]
        split: if_splits)+
next
  case (MPrev I φ first buf nts)
  from MPrev.prems show ?case
  proof (cases pred: wf_mformula)
    case (Prev ψ)
    let ?xs = "fst (meval n (τ σ j) (Γ σ j) φ)"
    let  = "snd (meval n (τ σ j) (Γ σ j) φ)"
    let ?ls = "fst (mprev_next I (buf @ ?xs) (nts @ [τ σ j]))"
    let ?rs = "fst (snd (mprev_next I (buf @ ?xs) (nts @ [τ σ j])))"
    let ?ts = "snd (snd (mprev_next I (buf @ ?xs) (nts @ [τ σ j])))"
    let ?P = "λi X. qtable n (fv ψ) (mem_restr R) (λv. MFOTL.sat σ (map the v) i ψ) X"
    let ?min = "min (progress σ ψ (Suc j)) (Suc j - 1)"
    from Prev MPrev.IH[of n R ψ] have IH: "wf_mformula σ (Suc j) n R  ψ" and
      "list_all2 ?P [progress σ ψ j..<progress σ ψ (Suc j)] ?xs" by auto
    with Prev(4,5) have "list_all2 (λi X. if mem (τ σ (Suc i) - τ σ i) I then ?P i X else X = empty_table)
        [min (progress σ ψ j) (j - 1)..<?min] ?ls 
       list_all2 ?P [?min..<progress σ ψ (Suc j)] ?rs 
       list_all2 (λi t. t = τ σ i) [?min..<Suc j] ?ts"
      by (intro mprev)
        (auto simp: progress_mono progress_le simp del: 
          intro!: list_all2_upt_append list_all2_appendI order.trans[OF min.cobounded1])
    moreover have "min (Suc (progress σ ψ j)) j = Suc (min (progress σ ψ j) (j-1))" if "j > 0"
      using that by auto
    ultimately show ?thesis using progress_mono[of j "Suc j" σ ψ] Prev(1,3) IH 
      by (auto simp: map_Suc_upt[symmetric] upt_Suc[of 0] list.rel_map qtable_empty_iff
        simp del: upt_Suc elim!: wf_mformula.Prev list.rel_mono_strong
        split: prod.split if_split_asm)
  qed simp
next
  case (MNext I φ first nts)
  from MNext.prems show ?case
  proof (cases pred: wf_mformula)
    case (Next ψ)

    have min[simp]:
      "min (progress σ ψ j - Suc 0) (j - Suc 0) = progress σ ψ j - Suc 0"
      "min (progress σ ψ (Suc j) - Suc 0) j = progress σ ψ (Suc j) - Suc 0" for j
      using progress_le[of σ ψ j] progress_le[of σ ψ "Suc j"] by auto

    let ?xs = "fst (meval n (τ σ j) (Γ σ j) φ)"
    let ?ys = "case (?xs, first) of (_ # xs, True)  xs | _  ?xs"
    let  = "snd (meval n (τ σ j) (Γ σ j) φ)"
    let ?ls = "fst (mprev_next I ?ys (nts @ [τ σ j]))"
    let ?rs = "fst (snd (mprev_next I ?ys (nts @ [τ σ j])))"
    let ?ts = "snd (snd (mprev_next I ?ys (nts @ [τ σ j])))"
    let ?P = "λi X. qtable n (fv ψ) (mem_restr R) (λv. MFOTL.sat σ (map the v) i ψ) X"
    let ?min = "min (progress σ ψ (Suc j) - 1) (Suc j - 1)"
    from Next MNext.IH[of n R ψ] have IH: "wf_mformula σ (Suc j) n R  ψ"
      "list_all2 ?P [progress σ ψ j..<progress σ ψ (Suc j)] ?xs" by auto
    with Next have "list_all2 (λi X. if mem (τ σ (Suc i) - τ σ i) I then ?P (Suc i) X else X = empty_table)
        [progress σ ψ j - 1..<?min] ?ls 
       list_all2 ?P [Suc ?min..<progress σ ψ (Suc j)] ?rs 
       list_all2 (λi t. t = τ σ i) [?min..<Suc j] ?ts" if "progress σ ψ j < progress σ ψ (Suc j)"
      using progress_le[of σ ψ j] that
      by (intro mnext)
        (auto simp: progress_mono list_all2_Cons2 upt_eq_Cons_conv
          intro!: list_all2_upt_append list_all2_appendI split: list.splits)
    then show ?thesis using progress_mono[of j "Suc j" σ ψ] progress_le[of σ ψ "Suc j"] Next IH
      by (cases "progress σ ψ (Suc j) > progress σ ψ j")
        (auto 0 3 simp: qtable_empty_iff le_Suc_eq le_diff_conv
         elim!: wf_mformula.Next list.rel_mono_strong list_all2_appendI
         split: prod.split list.splits if_split_asm)  (* slow 5 sec*)
  qed simp
next
  case (MSince pos φ I ψ buf nts aux)
  note sat.simps[simp del]
  from MSince.prems obtain φ'' φ''' ψ'' where Since_eq: "φ' = MFOTL.Since φ''' I ψ''"
    and pos: "if pos then φ''' = φ'' else φ''' = MFOTL.Neg φ''"
    and pos_eq: "safe_formula φ''' = pos"
    and φ: "wf_mformula σ j n R φ φ''"
    and ψ: "wf_mformula σ j n R ψ ψ''"
    and fvi_subset: "MFOTL.fv φ''  MFOTL.fv ψ''"
    and buf: "wf_mbuf2' σ j n R φ'' ψ'' buf"
    and nts: "wf_ts σ j φ'' ψ'' nts"
    and aux: "wf_since_aux σ n R pos φ'' I ψ'' aux (progress σ (formula.Since φ''' I ψ'') j)"
    by (cases pred: wf_mformula) (auto)
  have φ''': "MFOTL.fv φ''' = MFOTL.fv φ''" "progress σ φ''' j = progress σ φ'' j" for j
    using pos by (simp_all split: if_splits)
  have nts_snoc: "list_all2 (λi t. t = τ σ i)
    [min (progress σ φ'' j) (progress σ ψ'' j)..<Suc j] (nts @ [τ σ j])"
    using nts unfolding wf_ts_def
    by (auto simp add: progress_le[THEN min.coboundedI1] intro: list_all2_appendI)
  have update: "wf_since_aux σ n R pos φ'' I ψ'' (snd (zs, aux')) (progress σ (formula.Since φ''' I ψ'') (Suc j)) 
    list_all2 (λi. qtable n (MFOTL.fv φ'''  MFOTL.fv ψ'') (mem_restr R)
      (λv. MFOTL.sat σ (map the v) i (formula.Since φ''' I ψ'')))
      [progress σ (formula.Since φ''' I ψ'') j..<progress σ (formula.Since φ''' I ψ'') (Suc j)] (fst (zs, aux'))"
    if eval_φ: "fst (meval n (τ σ j) (Γ σ j) φ) = xs"
      and eval_ψ: "fst (meval n (τ σ j) (Γ σ j) ψ) = ys"
      and eq: "mbuf2t_take (λr1 r2 t (zs, aux).
        case update_since I pos r1 r2 t aux of (z, x)  (zs @ [z], x))
        ([], aux) (mbuf2_add xs ys buf) (nts @ [τ σ j]) = ((zs, aux'), buf', nts')"
    for xs ys zs aux' buf' nts'
    unfolding progress.simps φ'''
  proof (rule mbuf2t_take_add_induct'[where j'="Suc j" and z'="(zs, aux')", OF eq buf nts_snoc],
      goal_cases xs ys _ base step)
    case xs
    then show ?case 
      using MSince.IH(1)[OF φ] eval_φ by auto
  next
    case ys
    then show ?case 
      using MSince.IH(2)[OF ψ] eval_ψ by auto
  next
    case base
    then show ?case
     using aux by (simp add: φ''')
  next
    case (step k X Y z)
    then show ?case
      using fvi_subset pos
      by (auto simp: Un_absorb1 elim!: update_since(1) list_all2_appendI dest!: update_since(2)
        split: prod.split if_splits)
  qed simp
  with MSince.IH(1)[OF φ] MSince.IH(2)[OF ψ] show ?case
    by (auto 0 3 simp: Since_eq split: prod.split
      intro: wf_mformula.Since[OF _  _ pos pos_eq fvi_subset]
      elim: mbuf2t_take_add'(1)[OF _ buf nts_snoc] mbuf2t_take_add'(2)[OF _ buf nts_snoc])
next
  case (MUntil pos φ I ψ buf nts aux)
  note sat.simps[simp del] progress.simps[simp del]
  from MUntil.prems obtain φ'' φ''' ψ'' where Until_eq: "φ' = MFOTL.Until φ''' I ψ''"
    and pos: "if pos then φ''' = φ'' else φ''' = MFOTL.Neg φ''"
    and pos_eq: "safe_formula φ''' = pos"
    and φ: "wf_mformula σ j n R φ φ''"
    and ψ: "wf_mformula σ j n R ψ ψ''"
    and fvi_subset: "MFOTL.fv φ''  MFOTL.fv ψ''"
    and buf: "wf_mbuf2' σ j n R φ'' ψ'' buf"
    and nts: "wf_ts σ j φ'' ψ'' nts"
    and aux: "wf_until_aux σ n R pos φ'' I ψ'' aux (progress σ (formula.Until φ''' I ψ'') j)"
    and length_aux: "progress σ (formula.Until φ''' I ψ'') j + length aux =
      min (progress σ φ'' j) (progress σ ψ'' j)"
    by (cases pred: wf_mformula) (auto)
  have φ''': "progress σ φ''' j = progress σ φ'' j" for j
    using pos by (simp_all add: progress.simps split: if_splits)
  have nts_snoc: "list_all2 (λi t. t = τ σ i)
    [min (progress σ φ'' j) (progress σ ψ'' j)..<Suc j] (nts @ [τ σ j])"
    using nts unfolding wf_ts_def
    by (auto simp add: progress_le[THEN min.coboundedI1] intro: list_all2_appendI)
  {
    fix xs ys zs aux' aux'' buf' nts'
    assume eval_φ: "fst (meval n (τ σ j) (Γ σ j) φ) = xs"
      and eval_ψ: "fst (meval n (τ σ j) (Γ σ j) ψ) = ys"
      and eq1: "mbuf2t_take (update_until I pos) aux (mbuf2_add xs ys buf) (nts @ [τ σ j]) =
        (aux', buf', nts')"
      and eq2: "eval_until I (case nts' of []  τ σ j | nt # _  nt) aux' = (zs, aux'')"
    have update1: "wf_until_aux σ n R pos φ'' I ψ'' aux' (progress σ (formula.Until φ''' I ψ'') j) 
      progress σ (formula.Until φ''' I ψ'') j + length aux' =
        min (progress σ φ''' (Suc j)) (progress σ ψ'' (Suc j))"
      using MUntil.IH(1)[OF φ] eval_φ MUntil.IH(2)[OF ψ]
        eval_ψ nts_snoc nts_snoc length_aux aux fvi_subset
      unfolding φ'''
      by (elim mbuf2t_take_add_induct'[where j'="Suc j", OF eq1 buf])
        (auto simp: length_update_until elim: wf_update_until)
    have nts': "wf_ts σ (Suc j) φ'' ψ'' nts'"
      using MUntil.IH(1)[OF φ] eval_φ MUntil.IH(2)[OF ψ] eval_ψ nts_snoc
      unfolding wf_ts_def
      by (intro mbuf2t_take_eqD(2)[OF eq1]) (auto simp: progress_mono progress_le
        intro: wf_mbuf2_add buf[unfolded wf_mbuf2'_def])
    have "i  progress σ (formula.Until φ''' I ψ'') (Suc j) 
      wf_until_aux σ n R pos φ'' I ψ'' aux' i 
      i + length aux' = min (progress σ φ''' (Suc j)) (progress σ ψ'' (Suc j)) 
      wf_until_aux σ n R pos φ'' I ψ'' aux'' (progress σ (formula.Until φ''' I ψ'') (Suc j)) 
        i + length zs = progress σ (formula.Until φ''' I ψ'') (Suc j) 
        i + length zs + length aux'' = min (progress σ φ''' (Suc j)) (progress σ ψ'' (Suc j)) 
        list_all2 (λi. qtable n (MFOTL.fv ψ'') (mem_restr R)
          (λv. MFOTL.sat σ (map the v) i (formula.Until (if pos then φ'' else MFOTL.Neg φ'') I ψ'')))
          [i..<i + length zs] zs" for i
      using eq2
    proof (induction aux' arbitrary: zs aux'' i)
      case Nil
      then show ?case by (auto dest!: antisym[OF progress_Until_le])
    next
      case (Cons a aux')
      obtain t a1 a2 where "a = (t, a1, a2)" by (cases a)
      from Cons.prems(2) have aux': "wf_until_aux σ n R pos φ'' I ψ'' aux' (Suc i)"
        by (rule wf_until_aux_Cons)
      from Cons.prems(2) have 1: "t = τ σ i"
        unfolding a = (t, a1, a2) by (rule wf_until_aux_Cons1)
      from Cons.prems(2) have 3: "qtable n (MFOTL.fv ψ'') (mem_restr R) (λv.
        (ji. j < Suc (i + length aux')  mem (τ σ j - τ σ i) I  MFOTL.sat σ (map the v) j ψ'' 
        (k{i..<j}. if pos then MFOTL.sat σ (map the v) k φ'' else ¬ MFOTL.sat σ (map the v) k φ''))) a2"
        unfolding a = (t, a1, a2) by (rule wf_until_aux_Cons3)
      from Cons.prems(3) have Suc_i_aux': "Suc i + length aux' =
          min (progress σ φ''' (Suc j)) (progress σ ψ'' (Suc j))"
        by simp
      have "i  progress σ (formula.Until φ''' I ψ'') (Suc j)"
        if "enat (case nts' of []  τ σ j | nt # x  nt)  enat t + right I"
        using that nts' unfolding wf_ts_def progress.simps
        by (auto simp add: 1 list_all2_Cons2 upt_eq_Cons_conv φ'''
          intro!: cInf_lower τ_mono elim!: order.trans[rotated] simp del: upt_Suc split: if_splits list.splits)
      moreover
      have "Suc i  progress σ (formula.Until φ''' I ψ'') (Suc j)"
        if "enat t + right I < enat (case nts' of []  τ σ j | nt # x  nt)"
      proof -
        from that obtain m where m: "right I = enat m" by (cases "right I") auto
        have τ_min:  "τ σ (min j k) = min (τ σ j) (τ σ k)" for k
          by (simp add: min_of_mono monoI)
        have le_progress_iff[simp]: "i  progress σ φ i  progress σ φ i = i" for φ i
          using progress_le[of σ φ i] by auto
        have min_Suc[simp]: "min j (Suc j) = j" by auto
        let ?X = "{i. k. k < Suc j  k min (progress σ φ''' (Suc j)) (progress σ ψ'' (Suc j))  enat (τ σ k)  enat (τ σ i) + right I}"
        let ?min = "min j (min (progress σ φ'' (Suc j)) (progress σ ψ'' (Suc j)))"
        have "τ σ ?min  τ σ j"
          by (rule τ_mono) auto
        from m have "?X  {}"
          by (auto dest!: τ_mono[of _ "progress σ φ'' (Suc j)" σ]
           simp: not_le not_less φ''' intro!: exI[of _ "progress σ φ'' (Suc j)"])
        thm less_le_trans[of "τ σ i + m" "τ σ _" "τ σ _ + m"]
        from m show ?thesis
          using that nts' unfolding wf_ts_def progress.simps
          by (intro cInf_greatest[OF ?X  {}])
            (auto simp: 1 φ''' not_le not_less list_all2_Cons2 upt_eq_Cons_conv less_Suc_eq
              simp del: upt_Suc split: list.splits if_splits
              dest!: spec[of _ "?min"] less_le_trans[of "τ σ i + m" "τ σ _" "τ σ _ + m"] less_τD)
      qed
      moreover have *: "k < progress σ ψ (Suc j)" if
        "enat (τ σ i) + right I < enat (case nts' of []  τ σ j | nt # x  nt)"
        "enat (τ σ k - τ σ i)  right I" "ψ = ψ''  ψ = φ''" for k ψ
      proof -
        from that(1,2) obtain m where "right I = enat m"
           "τ σ i + m < (case nts' of []  τ σ j | nt # x  nt)" "τ σ k - τ σ i  m"
          by (cases "right I") auto
        with that(3) nts' progress_le[of σ ψ'' "Suc j"] progress_le[of σ φ'' "Suc j"]
        show ?thesis
          unfolding wf_ts_def le_diff_conv
          by (auto simp: not_le list_all2_Cons2 upt_eq_Cons_conv less_Suc_eq add.commute
            simp del: upt_Suc split: list.splits if_splits dest!: le_less_trans[of "τ σ k"] less_τD)
      qed
      ultimately show ?case using Cons.prems Suc_i_aux'[simplified]
        unfolding a = (t, a1, a2)
        by (auto simp: φ''' 1 sat.simps upt_conv_Cons dest!:  Cons.IH[OF _ aux' Suc_i_aux']
          simp del: upt_Suc split: if_splits prod.splits intro!: iff_exI qtable_cong[OF 3 refl])
    qed
    note this[OF progress_mono[OF le_SucI, OF order.refl] conjunct1[OF update1] conjunct2[OF update1]]
  }
  note update = this
  from MUntil.IH(1)[OF φ] MUntil.IH(2)[OF ψ] pos pos_eq fvi_subset show ?case
    by (auto 0 4 simp: Until_eq φ''' progress.simps(3) split: prod.split if_splits
      dest!: update[OF refl refl, rotated]
      intro!: wf_mformula.Until
      elim!: list.rel_mono_strong qtable_cong
      elim: mbuf2t_take_add'(1)[OF _ buf nts_snoc] mbuf2t_take_add'(2)[OF _ buf nts_snoc])
qed


subsubsection ‹Monitor step›

lemma wf_mstate_mstep: "wf_mstate φ π R st  last_ts π  snd tdb 
  wf_mstate φ (psnoc π tdb) R (snd (mstep tdb st))"
  unfolding wf_mstate_def mstep_def Let_def
  by (fastforce simp add: progress_mono le_imp_diff_is_add split: prod.splits
      elim!: prefix_of_psnocE dest: meval list_all2_lengthD)

lemma mstep_output_iff: 
  assumes "wf_mstate φ π R st" "last_ts π  snd tdb" "prefix_of (psnoc π tdb) σ" "mem_restr R v" 
  shows "(i, v)  fst (mstep tdb st) 
    progress σ φ (plen π)  i  i < progress σ φ (Suc (plen π)) 
    wf_tuple (MFOTL.nfv φ) (MFOTL.fv φ) v  MFOTL.sat σ (map the v) i φ"
proof -
  from prefix_of_psnocE[OF assms(3,2)] have "prefix_of π σ" 
    "Γ σ (plen π) = fst tdb" "τ σ (plen π) = snd tdb" by auto
  moreover from assms(1) prefix_of π σ have "mstate_n st = MFOTL.nfv φ"
    "mstate_i st = progress σ φ (plen π)" "wf_mformula σ (plen π) (mstate_n st) R (mstate_m st) φ"
    unfolding wf_mstate_def by blast+
  moreover from meval[OF wf_mformula σ (plen π) (mstate_n st) R (mstate_m st) φ] obtain Vs st' where
    "meval (mstate_n st) (τ σ (plen π)) (Γ σ (plen π)) (mstate_m st) = (Vs, st')"
    "wf_mformula σ (Suc (plen π)) (mstate_n st) R st' φ"
    "list_all2 (λi. qtable (mstate_n st) (fv φ) (mem_restr R) (λv. MFOTL.sat σ (map the v) i φ))
      [progress σ φ (plen π)..<progress σ φ (Suc (plen π))] Vs" by blast
  moreover from this assms(4) have "qtable (mstate_n st) (fv φ) (mem_restr R)
    (λv. MFOTL.sat σ (map the v) i φ) (Vs ! (i - progress σ φ (plen π)))"
      if "progress σ φ (plen π)  i" "i < progress σ φ (Suc (plen π))"
    using that by (auto simp: list_all2_conv_all_nth
      dest!: spec[of _ "(i - progress σ φ (plen π))"])
  ultimately show ?thesis
    using assms(4) unfolding mstep_def Let_def
    by (auto simp: in_set_enumerate_eq list_all2_conv_all_nth progress_mono le_imp_diff_is_add
      elim!: in_qtableE in_qtableI intro!: bexI[of _ "(i, Vs ! (i - progress σ φ (plen π)))"])
qed


subsubsection ‹Monitor function›

definition minit_safe where
  "minit_safe φ = (if mmonitorable_exec φ then minit φ else undefined)"

lemma minit_safe_minit: "mmonitorable φ  minit_safe φ = minit φ"
  unfolding minit_safe_def monitorable_formula_code by simp

lemma (in monitorable_mfotl) mstep_mverdicts:
  assumes wf: "wf_mstate φ π R st"
    and le[simp]: "last_ts π  snd tdb"
    and restrict: "mem_restr R v"
  shows "(i, v)  fst (mstep tdb st)  (i, v)  M (psnoc π tdb) - M π"
proof -
  obtain σ where p2: "prefix_of (psnoc π tdb) σ"
    using ex_prefix_of by blast
  with le have p1: "prefix_of π σ" by (blast elim!: prefix_of_psnocE)
  show ?thesis
    unfolding M_def
    by (auto 0 3 simp: p2 progress_prefix_conv[OF _ p1] sat_prefix_conv[OF _ p1] not_less
        pprogress_eq[OF p1] pprogress_eq[OF p2]
      dest:  mstep_output_iff[OF wf le p2 restrict, THEN iffD1] spec[of _ σ]
             mstep_output_iff[OF wf le _ restrict, THEN iffD1] progress_sat_cong[OF p1]
      intro: mstep_output_iff[OF wf le p2 restrict, THEN iffD2] p1)
qed

primrec msteps0 where
  "msteps0 [] st = ({}, st)"
| "msteps0 (tdb # π) st =
    (let (V', st') = mstep tdb st; (V'', st'') = msteps0 π st' in (V'  V'', st''))"

primrec msteps0_stateless where
  "msteps0_stateless [] st = {}"
| "msteps0_stateless (tdb # π) st = (let (V', st') = mstep tdb st in V'  msteps0_stateless π st')"

lemma msteps0_msteps0_stateless: "fst (msteps0 w st) = msteps0_stateless w st"
  by (induct w arbitrary: st) (auto simp: split_beta)

lift_definition msteps :: "'a MFOTL.prefix  'a mstate  (nat × 'a option list) set × 'a mstate"
  is msteps0 .

lift_definition msteps_stateless :: "'a MFOTL.prefix  'a mstate  (nat × 'a option list) set"
  is msteps0_stateless .

lemma msteps_msteps_stateless: "fst (msteps w st) = msteps_stateless w st"
  by transfer (rule msteps0_msteps0_stateless)

lemma msteps0_snoc: "msteps0 (π @ [tdb]) st =
   (let (V', st') = msteps0 π st; (V'', st'') = mstep tdb st' in (V'  V'', st''))"
  by (induct π arbitrary: st) (auto split: prod.splits)

lemma msteps_psnoc: "last_ts π  snd tdb  msteps (psnoc π tdb) st =
   (let (V', st') = msteps π st; (V'', st'') = mstep tdb st' in (V'  V'', st''))"
  by transfer (auto simp: msteps0_snoc split: list.splits prod.splits if_splits)

definition monitor where
  "monitor φ π = msteps_stateless π (minit_safe φ)"

lemma Suc_length_conv_snoc: "(Suc n = length xs) = (y ys. xs = ys @ [y]  length ys = n)"
  by (cases xs rule: rev_cases) auto

lemma (in monitorable_mfotl) wf_mstate_msteps: "wf_mstate φ π R st  mem_restr R v  π  π' 
  X = msteps (pdrop (plen π) π') st  wf_mstate φ π' R (snd X) 
  ((i, v)  fst X) = ((i, v)  M π' - M π)"
proof (induct "plen π' - plen π" arbitrary: X st π π')
  case 0
  from 0(1,4,5) have "π = π'"  "X = ({}, st)"
    by (transfer; auto)+
  with 0(2) show ?case by simp
next
  case (Suc x)
  from Suc(2,5) obtain π'' tdb where "x = plen π'' - plen π"  "π  π''"
    "π' = psnoc π'' tdb" "pdrop (plen π) (psnoc π'' tdb) = psnoc (pdrop (plen π) π'') tdb"
    "last_ts (pdrop (plen π) π'')  snd tdb" "last_ts π''  snd tdb"
    "π''  psnoc π'' tdb"
  proof (atomize_elim, transfer, elim exE, goal_cases prefix)
    case (prefix _ _ π' _ π_tdb)
    then show ?case
    proof (cases π_tdb rule: rev_cases)
      case (snoc π tdb)
      with prefix show ?thesis
        by (intro bexI[of _ "π' @ π"] exI[of _ tdb])
          (force simp: sorted_append append_eq_Cons_conv split: list.splits if_splits)+
    qed simp
  qed
  with Suc(1)[OF this(1) Suc.prems(1,2) this(2) refl] Suc.prems show ?case
    unfolding msteps_msteps_stateless[symmetric]
    by (auto simp: msteps_psnoc split_beta mstep_mverdicts
      dest: mono_monitor[THEN set_mp, rotated] intro!: wf_mstate_mstep)
qed

lemma (in monitorable_mfotl) wf_mstate_msteps_stateless:
  assumes "wf_mstate φ π R st" "mem_restr R v" "π  π'"
  shows "(i, v)  msteps_stateless (pdrop (plen π) π') st  (i, v)  M π' - M π"
  using wf_mstate_msteps[OF assms refl] unfolding msteps_msteps_stateless by simp

lemma (in monitorable_mfotl) wf_mstate_msteps_stateless_UNIV: "wf_mstate φ π UNIV st  π  π' 
  msteps_stateless (pdrop (plen π) π') st = M π' - M π"
  by (auto dest: wf_mstate_msteps_stateless[OF _ mem_restr_UNIV])

lemma (in monitorable_mfotl) mverdicts_Nil: "M pnil = {}"
  by (simp add: M_def pprogress_eq)

lemma wf_mstate_minit_safe: "mmonitorable φ  wf_mstate φ pnil R (minit_safe φ)"
  using wf_mstate_minit minit_safe_minit mmonitorable_def by metis

lemma (in monitorable_mfotl) monitor_mverdicts: "monitor φ π = M π"
  unfolding monitor_def using monitorable
  by (subst wf_mstate_msteps_stateless_UNIV[OF wf_mstate_minit_safe, simplified])
    (auto simp: mmonitorable_def mverdicts_Nil)

subsection ‹Collected correctness results›

context monitorable_mfotl
begin

text ‹We summarize the main results proved above.
\begin{enumerate}
\item The term @{term M} describes semantically the monitor's expected behaviour:
\begin{itemize}
\item @{thm[source] mono_monitor}: @{thm mono_monitor[no_vars]}
\item @{thm[source] sound_monitor}: @{thm sound_monitor[no_vars]}
\item @{thm[source] complete_monitor}: @{thm complete_monitor[no_vars]}
\item @{thm[source] sliceable_M}: @{thm sliceable_M[no_vars]}
\end{itemize}
\item The executable monitor's online interface @{term minit_safe} and @{term mstep}
  preserves the invariant @{term wf_mstate} and produces the the verdicts according
  to @{term M}:
\begin{itemize}
\item @{thm[source] wf_mstate_minit_safe}: @{thm wf_mstate_minit_safe[no_vars]}
\item @{thm[source] wf_mstate_mstep}: @{thm wf_mstate_mstep[no_vars]}
\item @{thm[source] mstep_mverdicts}: @{thm mstep_mverdicts[no_vars]}
\end{itemize}
\item The executable monitor's offline interface @{term monitor} implements @{term M}:
\begin{itemize}
\item @{thm[source] monitor_mverdicts}: @{thm monitor_mverdicts[no_vars]}
\end{itemize}
\end{enumerate}
›

end

(*<*)
end
(*>*)