Theory TD_warrow

section ‹Warrowing TD›

text‹In this theory, we first prove the partial correctness of the warrowing TD and later, with
  additional assumptions, its equivalence with the TD with widening and narrowing in phases. The
  warrowing TD extends the vanilla TD by dynamically tracking potential warrowing points.
  The warrowing operator is applied at warrowing points in function @{term iterate} to
  accelerate fixpoint iteration. Compared to the vanilla TD, the warrowing TD is no longer
  guaranteed to return partial solutions. Instead, computed assignments are only partial
  post-solutions to the given system of equations.›

theory TD_warrow
  imports Basics TD_wn_phases
begin

text‹We first use a locale to specify the context for the definitions. Later, extensions of this
  locale are used to specify further assumptions for the proofs.›

locale TD_warrow_defs =
  fixes T :: "('x,'d::order_bot) eqsT"
  fixes widening :: "'d ⇒ 'd ⇒ 'd" (infixl "∇" 65)
    and narrowing :: "'d ⇒ 'd ⇒ 'd" (infixl "Δ" 70)
begin

subsection ‹The Warrowing Operator›

text‹The warrowing is defined as a dynamic operator that dispatches to widening or narrowing based
  on the current relation of the old value @{term a} and the new value @{term b}. For non-monotonic
  equation systems, the warrowing solver may switch between widening and narrowing phases multiple
  times before reaching a fixpoint---or even never terminate.›

definition warrowing :: "'d ⇒ 'd ⇒ 'd" (infixl "∇Δ" 65)
  where "warrowing a b = (if b ≤ a then a Δ b else a ∇ b)"


subsection‹Definition of the Solver Algorithm›

text‹As the TD with widening/narrowing phases, TD with warrowing uses a set @{term point} to
  dynamically track unknowns at which to apply warrowing. In case a transitive self-dependence of
  an unknown is detected in function @{term query}, the solver marks the unknown as point.
  The warrowing operator is applied all unknowns in points in the function @{term iterate}.›

function (domintros)
    query :: "'x ⇒ 'x ⇒ ('x,'d) state ⇒ 'd × ('x,'d) state" and
  iterate :: "'x ⇒ ('x,'d) state ⇒ 'd × ('x,'d) state" and
     eval :: "'x ⇒ ('x,'d) strategy_tree ⇒ ('x,'d) state ⇒ 'd × ('x,'d) state" where
  "query y x state = (
    let (xd, state) =
      if x ∈ called state then
        (mlup (σ state) x, state ⦇point := insert x (point state)⦈)
      else
        iterate x (state ⦇called := insert x (called state)⦈)
    in (xd, state ⦇infl := fminsert (infl state) x y⦈))"
| "iterate x state = (
    if x ∉ stabl state then
      let pointx = x ∈ point state in
      let (xd, state) = eval x (T x) (state ⦇stabl := insert x (stabl state)⦈) in
      let d_new = if ¬ pointx then xd else mlup (σ state) x ∇Δ xd in
      if d_new = mlup (σ state) x then
        (d_new, state ⦇called := called state - {x}, point := (point state) - {x}⦈)
      else
        let (infl', stabl') = destab x (infl state) (stabl state) in
        iterate x (state ⦇infl := infl', stabl := stabl', σ := (σ state)(x ↦ d_new)⦈)
    else
      (mlup (σ state) x, state ⦇called := called state - {x}, point := (point state) - {x}⦈))"
| "eval x t state = (case t of
      Answer d ⇒ (d, state)
    | Query y g ⇒ (let (yd, state) = query x y state in eval x (g yd) state))"
  by pat_completeness auto

definition solve :: "'x ⇒ ('x, 'd) map × 'x set" where
  "solve x = (
    let state = ⦇called = {}, σ = Map.empty, infl = fmempty, stabl = {}, point = {}⦈ in
    let (d, state) = iterate x (state ⦇ called := insert x (called state) ⦈) in
    (σ state, stabl state))"

definition query_dom where
  "query_dom y x state = query_iterate_eval_dom (Inl (y, x, state))"
declare query_dom_def [simp]
definition iterate_dom where
  "iterate_dom x state = query_iterate_eval_dom (Inr (Inl (x, state)))"
declare iterate_dom_def [simp]
definition eval_dom where
  "eval_dom x t state = query_iterate_eval_dom (Inr (Inr (x, t, state)))"
declare eval_dom_def [simp]

definition solve_dom where
  "solve_dom x =
    iterate_dom x ⦇called = {x}, σ = Map.empty, infl = fmempty, stabl = {}, point = {}⦈"

lemmas dom_defs = query_dom_def iterate_dom_def eval_dom_def


subsection ‹Refinement of Auto-Generated Rules›

lemmas query_iterate_eval_pinduct[consumes 1, case_names Query Iterate Eval]
  = query_iterate_eval.pinduct(1)[
      folded query_dom_def iterate_dom_def eval_dom_def,
      of y x state for y x state
    ]
    query_iterate_eval.pinduct(2)[
      folded query_dom_def iterate_dom_def eval_dom_def,
      of x state for x state
    ]
    query_iterate_eval.pinduct(3)[
      folded query_dom_def iterate_dom_def eval_dom_def,
      of x t state for x t state
    ]

lemmas iterate_pinduct[consumes 1, case_names Iterate]
  = query_iterate_eval_pinduct(2)[where ?P="λy x state. True"
    and ?R="λx t state. True", simplified (no_asm_use),
    folded query_dom_def iterate_dom_def eval_dom_def]

declare query.psimps[simp] iterate.psimps[simp] eval.psimps[simp]


subsection ‹Domain Lemmas›

lemma dom_backwards_pinduct:
  shows "query_dom y x state
    ⟹ x ∉ (called state) ⟹ iterate_dom x (state ⦇called := insert x (called state)⦈)"
  and "iterate_dom x state
    ⟹ x ∉ (stabl state) ⟹ (eval_dom x (T x) (state ⦇stabl := insert x (stabl state)⦈) ∧
        ((xd, state1) = eval x (T x) (state ⦇stabl := insert x (stabl state)⦈)
          ⟶ d_new = (if x ∉ (point state) then xd else mlup (σ state1) x ∇Δ xd)
          ⟶ mlup (σ state1) x ≠ d_new
          ⟶ (infl2, stabl2) = destab x (infl state1) (stabl state1) ⟶
          iterate_dom x (state1 ⦇infl := infl2, stabl := stabl2, σ := (σ state1)(x ↦ d_new)⦈)))"
  and "eval_dom x (Query y g) state
    ⟹ (query_dom x y state ∧
        ((yd, state') = query x y state ⟶
          eval_dom x (g yd) state'))"
proof (induction y x state and x state and x "Query y g" state
    arbitrary: and xd state1 d_new infl2 stabl2 and y g yd state'
    rule: query_iterate_eval_pinduct)
  case (Query y x state)
  show ?case
    apply (rule query_iterate_eval.domintros(2)[folded dom_defs])
    using Query.hyps(2) Query.prems by auto
next
  case (Iterate x state)
  show ?case apply (intro impI conjI)
  subgoal
    apply (rule query_iterate_eval.domintros(3)[folded dom_defs])
    using Iterate.hyps(2)[OF Iterate.prems] by fastforce+
  subgoal
    apply (rule query_iterate_eval.domintros(2)[folded dom_defs])
    using Iterate.hyps(3)[OF Iterate.prems, folded dom_defs] by (fastforce split: prod.splits)+
  done
next
  case (Eval x state)
  then show ?case using query_iterate_eval.domintros(1,3) by simp
qed


subsection ‹Case Rules›

lemma iterate_continue_fixpoint_cases[consumes 3]:
  assumes "iterate_dom x state"
    and "(xd, state') = iterate x state"
  obtains (Stable) "x ∈ (stabl state)"
    and "xd = mlup (σ state) x"
    and "state' = state ⦇called := called state - {x}, point := (point state) - {x}⦈"
  | (Fixpoint) state1
  where "x ∉ (stabl state)" and "x ∉ (point state)"
    and "eval_dom x (T x) (state ⦇stabl := insert x (stabl state)⦈)"
    and "(xd, state1) = eval x (T x) (state ⦇stabl := insert x (stabl state)⦈)"
    and "mlup (σ state') x = xd"
    and "state' = state1 ⦇called := called state1 - {x}, point := (point state1) - {x}⦈"
  | (WN_Fixpoint) xd1 state1
  where "x ∉ (stabl state)" and "x ∈ (point state)"
    and "eval_dom x (T x) (state ⦇stabl := insert x (stabl state)⦈)"
    and "(xd1, state1) = eval x (T x) (state ⦇stabl := insert x (stabl state)⦈)"
    and "xd = mlup (σ state') x ∇Δ xd1"
    and "mlup (σ state') x = xd"
    and "state' = state1 ⦇called := called state1 - {x}, point := (point state1) - {x}⦈"
  | (Continue) xd1 state1 d_new infl2 stabl2
  where "x ∉ (stabl state)"
    and "eval_dom x (T x) (state ⦇stabl := insert x (stabl state)⦈)"
    and "(xd1, state1) = eval x (T x) (state ⦇stabl := insert x (stabl state)⦈)"
    and "d_new = (if x ∉ (point state) then xd1 else mlup (σ state1) x ∇Δ xd1)"
    and "d_new ≠ mlup (σ state1) x"
    and "(infl2, stabl2) = destab x (infl state1) (stabl state1)"
    and "iterate_dom x (state1 ⦇infl := infl2, stabl := stabl2, σ := (σ state1)(x ↦ d_new)⦈)"
    and "(xd, state') =
          iterate x (state1 ⦇infl := infl2, stabl := stabl2, σ := (σ state1)(x ↦ d_new)⦈)"
proof(cases "x ∈ (stabl state)" rule: case_split[case_names Stable Unstable])
  case Stable
  then show ?thesis using that(1) assms(1,2) by auto
next
  case Unstable
  then have sldom: "eval_dom x (T x) (state ⦇stabl := insert x (stabl state)⦈)"
    using assms(1) dom_backwards_pinduct(2)
    by simp
  then obtain xd1 state1
    where slapp: "eval x (T x) (state ⦇stabl := insert x (stabl state)⦈) = (xd1, state1)"
    by (cases "eval x (T x) (state ⦇stabl := insert x (stabl state)⦈)") auto
  then obtain d_new
    where d_new: "d_new = (if x ∉ (point state) then xd1 else mlup (σ state1) x ∇Δ xd1)"
    by blast
  show ?thesis
  proof (cases "mlup (σ state1) x = d_new" rule: case_split[case_names Fixpoint Continue])
    case Fixpoint
    then show ?thesis
      using Unstable sldom slapp d_new assms that(2,3)
      by (cases "x ∈ point state") auto
  next
    case Continue
    obtain infl2 stabl2 where destab: "destab x (infl state1) (stabl state1) = (infl2, stabl2)"
      by (cases "destab x (infl state1) (stabl state1)")
    then have dom:
        "iterate_dom x (state1 ⦇infl := infl2, stabl := stabl2, σ := (σ state1)(x ↦ d_new)⦈)"
      using Unstable Continue slapp d_new assms(1) dom_backwards_pinduct(2) by auto
    then show ?thesis
      using Unstable Continue sldom slapp d_new assms destab that(4)
      by (cases "x ∈ (point state)") (auto simp add: Let_def)
  qed
qed

lemma query_iterate_lookup_cases_basic[consumes 2]:
  assumes "query_dom y x state"
    and "(xd, state') = query y x state"
  obtains (Iterate) state1
  where "x ∉ (called state)"
    and "iterate_dom x (state ⦇called := insert x (called state)⦈)"
    and "(xd, state1) = iterate x (state ⦇called := insert x (called state)⦈)"
    and "state' = state1 ⦇infl := fminsert (infl state1) x y⦈"
  | (Lookup) "x ∈ (called state)"
    and "xd = mlup (σ state) x"
    and "state' = state ⦇infl := fminsert (infl state) x y, point := insert x (point state)⦈"
  using assms that dom_backwards_pinduct(1)
  by (cases "x ∈ (called state)") (auto split!: prod.splits)

lemma eval_query_answer_cases_basic[consumes 2]:
  assumes "eval_dom x t state"
    and "(xd, state') = eval x t state"
  obtains (Query) y g yd state1
  where "t = Query y g"
    and "query_dom x y state"
    and "(yd, state1) = query x y state"
    and "eval_dom x (g yd) state1"
    and "(xd, state') = eval x (g yd) state1"
  | (Answer) "t = Answer xd"
    and "state' = state"
  using assms dom_backwards_pinduct(3) that
  by (cases t; auto split: prod.splits)

lemma c_same:
  shows
    "query_dom y x state ⟹ (xd, state') = query y x state ⟹ called state' = called state"
    "iterate_dom x state ⟹ (xd, state') = iterate x state ⟹ called state' = called state - {x}"
    "eval_dom x t state ⟹ (xd, state') = eval x t state ⟹ called state' = called state"
proof (induction y x state and x state and x t state
       arbitrary: xd state' and xd state' and xd state'
       rule: query_iterate_eval_pinduct)
  case (Query x y state)
  show ?case using Query(1,3)
  proof (cases rule: query_iterate_lookup_cases_basic)
    case (Iterate state1)
    then show ?thesis using Query(2)[of xd state1] by simp
  next
    case Lookup
    then show ?thesis by fastforce
  qed
next
  case (Iterate x state)
  show ?case using Iterate(1,4)
  proof (cases rule: iterate_continue_fixpoint_cases)
    case Stable
    then show ?thesis by simp
  next
    case Fixpoint
    then show ?thesis using Iterate.IH(2) by simp
  next
    case (WN_Fixpoint xd1 state1)
    then show ?thesis using Iterate.IH(2) by simp
  next
    case (Continue xd1 state1 d_new infl2 stabl2)
    then show ?thesis
      using Iterate.IH(2)[OF Continue(1) _ Continue(3)]
        Iterate.IH(3)[OF Continue(1) _ Continue(3) _ Continue(4,5) _ Continue(6),
                      simplified, OF Continue(8)]
      by simp
  qed
next
  case (Eval x t state)
  show ?case using Eval(1, 4)
  proof (cases rule: eval_query_answer_cases_basic)
    case (Query y g yd state1)
    then show ?thesis
      using Eval.IH(2)[OF Query(1,3)] Eval.IH(3)[OF Query(1,3) _ Query(5), simplified] by simp
  qed simp
qed

lemma iterate_fmlookup:
  assumes "iterate_dom x state"
    and "(xd, state') = iterate x state"
  shows "mlup (σ state') x = xd"
  using assms
proof(induction rule: iterate_pinduct)
  case Iterate
  show ?case
    using Iterate.hyps Iterate.prems
  proof(cases rule: iterate_continue_fixpoint_cases)
    case Continue
    then show ?thesis
      using Iterate.IH(1) c_same(3)[OF Continue(2,3)] Iterate(3) by fastforce
  qed simp+
qed

corollary query_fmlookup:
  assumes "query_dom y x state"
    and "(xd, state') = query y x state"
  shows "mlup (σ state') x = xd"
  using assms iterate_fmlookup dom_backwards_pinduct(1)[of y x state]
  by (auto split: prod.splits if_splits)

lemma query_iterate_lookup_cases[consumes 2]:
  assumes "query_dom y x state"
    and "(xd, state') = query y x state"
  obtains (Iterate) state1
  where "x ∉ (called state)"
    and "iterate_dom x (state ⦇called := insert x (called state)⦈)"
    and "(xd, state1) = iterate x (state ⦇called := insert x (called state)⦈)"
    and "state' = state1 ⦇infl := fminsert (infl state1) x y⦈"
    and "mlup (σ state') x = xd"
  | (Lookup) "x ∈ (called state)"
    and "xd = mlup (σ state) x"
    and "state' = state ⦇infl := fminsert (infl state) x y, point := insert x (point state)⦈"
  apply (rule query_iterate_lookup_cases_basic[OF assms])
  using iterate_fmlookup[of x "state⦇called := insert x (called state)⦈"]
  by (simp_all split: if_splits del: dom_defs)

lemma eval_query_answer_cases[consumes 2]:
  assumes "eval_dom x t state"
    and "(xd, state') = eval x t state"
  obtains (Query) y g yd state1
  where "t = Query y g"
    and "query_dom x y state"
    and "(yd, state1) = query x y state"
    and "eval_dom x (g yd) state1"
    and "(xd, state') = eval x (g yd) state1"
    and "mlup (σ state1) y = yd"
  | (Answer) "t = Answer xd"
    and "state' = state"
  apply (rule eval_query_answer_cases_basic[OF assms])
  by (auto simp: query_fmlookup[of x _ state])


subsection ‹Program Refinement for Code Generation›

text‹To derive executable code for the TD, we do a program refinement and define an
  equivalent solve function based on partial\_function with options that can be used for the code
  generation.›

datatype ('a,'b) istate = Q "'a × 'a × ('a, 'b) state"
  | I "'a × ('a, 'b) state"
  | E "'a × ('a,'b) strategy_tree × ('a, 'b) state"

partial_function (option) solve_rec_c ::
  "('x, 'd) istate ⇒ ('d × ('x, 'd) state) option"
  where
  "solve_rec_c s = (case s of Q (y,x,state) ⇒ Option.bind
      (if x ∈ (called state) then
        Some (mlup (σ state) x, state ⦇point := insert x (point state)⦈)
      else
        solve_rec_c (I (x, state ⦇called := insert x (called state)⦈)))
      (λ (xd, state). Some (xd, state ⦇infl := fminsert (infl state) x y⦈))
  | I (x,state) ⇒
      if x ∉ (stabl state) then
        let p0 = point state in Option.bind (
        solve_rec_c (E (x, (T x), state ⦇stabl := insert x (stabl state)⦈))) (λ(xd, state).
        let d_new = if x ∉ p0 then xd else mlup (σ state) x ∇Δ xd in
        if mlup (σ state) x = d_new then
          Some (mlup (σ state) x, state ⦇called := called state - {x}, point := (point state) - {x}⦈)
        else
          let (infl', stabl') = destab x (infl state) (stabl state) in
          solve_rec_c (I (x, state ⦇infl := infl', stabl := stabl', σ := (σ state)(x ↦ d_new)⦈)))
      else
        Some (mlup (σ state) x, state ⦇called := called state - {x}, point := (point state) - {x}⦈)
  | E (x,t,state) ⇒ (case t of
        Answer d ⇒ Some (d, state)
      | Query y g ⇒ (
          Option.bind (solve_rec_c (Q (x, y, state))) (λ(yd, state).
          solve_rec_c (E (x, g yd, state))))))"

definition solve_rec_c_dom where "solve_rec_c_dom p ≡ ∃σ. solve_rec_c p = Some σ" for p

declare solve_rec_c.simps[simp,code]

definition solve_c :: "'x ⇒ (('x, 'd) map × 'x set) option" where
  "solve_c x = Option.bind (solve_rec_c (I (x,
    ⦇called = {x}, σ = Map.empty, infl = fmempty, stabl = {}, point = {}⦈)))
    (λ(d, state). Some (σ state, stabl state))"

definition solve_c_dom :: "'x ⇒ bool" where "solve_c_dom x ≡ ∃σ. solve_c x = Some σ"

text‹We prove the equivalence of the refined solver function for code generation and the initial
  version used for the partial correctness proof.›

lemma query_iterate_eval_solve_rec_c_equiv:
  shows "query_dom y x state ⟹ solve_rec_c_dom (Q (y,x,state))
    ∧ query y x state = the (solve_rec_c (Q (y,x,state)))"
  and "iterate_dom x state ⟹ solve_rec_c_dom (I (x,state))
    ∧ iterate x state = the (solve_rec_c (I (x,state)))"
  and "eval_dom x t state ⟹ solve_rec_c_dom (E (x,t,state))
    ∧ eval x t state = the (solve_rec_c (E (x,t,state)))"
proof (induction y x state and x state and x t state
    rule: query_iterate_eval_pinduct)
  case (Query y x state)
  show ?case
  proof (cases "x ∈ (called state)")
    case True
    then have "solve_rec_c (Q (y, x, state)) = Some (mlup (σ state) x,
        state ⦇point := insert x (point state), infl := fminsert (infl state) x y⦈)"
      by simp
    moreover have "query y x state = (mlup (σ state) x,
        state⦇point := insert x (point state), infl := fminsert (infl state) x y⦈)"
      using query.psimps[folded dom_defs] Query(1) True by force
    ultimately show ?thesis unfolding solve_rec_c_dom_def by auto
  next
    case False
    obtain d1 state1 where
        I: "iterate x (state ⦇called := insert x (called state)⦈) = (d1, state1)"
      using prod_cases5 by fastforce
    then have J: "query y x state = (d1, state1 ⦇infl := fminsert (infl state1) x y⦈)"
      using False Query.IH(1) query.pelims[folded dom_defs] by fastforce
    then have "solve_rec_c (I (x, state ⦇called := insert x (called state)⦈)) = Some (d1, state1)"
      using Query(2) False I by (simp add: solve_rec_c_dom_def)
    then have "solve_rec_c (Q (y, x, state)) =
        Some (d1, state1 ⦇infl := fminsert (infl state1) x y⦈)"
      using False by simp
    moreover have "solve_rec_c_dom (Q (y, x, state))"
      using Query(2) False unfolding solve_rec_c_dom_def by fastforce
    ultimately show ?thesis using Query J unfolding solve_rec_c_dom_def by auto
  qed
next
  case (Iterate x state)
  show ?case
  proof (cases "x ∈ (stabl state)")
    case True
    have "iterate_dom x state ∧ iterate x state = (mlup (σ state) x,
        state ⦇called := called state - {x}, point := (point state) - {x}⦈)"
      using True iterate.psimps query_iterate_eval.domintros(2)
      unfolding iterate_dom_def
      by presburger
    then show ?thesis using True unfolding solve_rec_c_dom_def by auto
  next
    case False
    obtain p0 where "p0 = point state" by blast
    obtain d1 state1 where
        eval: "eval x (T x) (state ⦇stabl := insert x (stabl state)⦈) = (d1, state1)"
        "solve_rec_c (E (x, (T x), state ⦇stabl := insert x (stabl state)⦈)) = Some (d1, state1)"
      using Iterate(2) solve_rec_c_dom_def False by force
    define d_new where "d_new = (if x ∉ (point state) then d1 else mlup (σ state1) x ∇Δ d1)"
    show ?thesis
    proof (cases "d_new = mlup (σ state1) x")
      case True
      have "iterate x state = (d_new, state1⦇called := called state1 - {x}, point := point state1 - {x}⦈)"
        using eval iterate.psimps[folded dom_defs, OF Iterate(1)] True False d_new_def
        by (auto simp: Set.remove_eq)
      moreover have "solve_rec_c (I (x, state))
          = Some (d_new, state1⦇called := called state1 - {x}, point := point state1 - {x}⦈)"
        using eval False True d_new_def by (auto simp: Set.remove_eq)
      ultimately show ?thesis unfolding solve_rec_c_dom_def by simp
    next
      case False
      obtain infl2 stabl2 where
        destab: "(infl2, stabl2) = destab x (infl state1) (stabl state1)"
        by (cases "destab x (infl state1) (stabl state1)") auto
      let ?state2 = "state1⦇infl := infl2, stabl := stabl2, σ := (σ state1)(x ↦ d_new)⦈"
      have "solve_rec_c_dom (I (x, ?state2))"
        and "iterate x ?state2 = the (solve_rec_c (I (x, ?state2)))"
        using Iterate(3)[OF ‹x ∉ (stabl state)› _ eval(1)[symmetric] _ d_new_def False destab]
        by blast+
      moreover have "iterate x state  = iterate x ?state2"
        using eval iterate.psimps[folded dom_defs, OF Iterate(1)] False ‹x ∉ (stabl state)›
          destab d_new_def
        by (auto split: prod.split)
      moreover have "solve_rec_c (I (x, state)) = solve_rec_c (I (x, ?state2))"
        using ‹x ∉ (stabl state)› False eval(2) destab[symmetric] d_new_def
        by (auto simp add: Let_def)
      ultimately show ?thesis unfolding solve_rec_c_dom_def by auto
    qed
  qed
next
  case (Eval x t state)
  show ?case
  proof (cases t)
    case (Answer d)
    then have "eval x t state = (d, state)"
      using eval.psimps query_iterate_eval.domintros(3) dom_defs(3) by fastforce
    then show ?thesis using Eval Answer unfolding solve_rec_c_dom_def by simp
  next
    case (Query y g)
    then obtain d1 state1 where
        query: "solve_rec_c (Q (x, y, state)) = Some (d1, state1)"
          "query x y state = (d1, state1)"
      using Query Eval(2) unfolding solve_rec_c_dom_def by auto
    then have "solve_rec_c_dom (E (x, g d1, state1))"
        "eval x (g d1) state1 = the (solve_rec_c (E (x, g d1, state1)))"
      using Eval(3)[OF Query] by auto
    moreover have "eval x t state = eval x (g d1) state1"
      using Eval.IH(1) Query eval.psimps eval_dom_def query
      by fastforce
    moreover have "solve_rec_c (E (x, t, state))
        = solve_rec_c (E (x, g d1, state1))"
      using Query query solve_rec_c.simps[of "E (x,t,state)"]
      by (simp del: solve_rec_c.simps)
    ultimately show ?thesis using solve_rec_c_dom_def by force
  qed
qed

lemma solve_rec_c_query_iterate_eval_equiv:
  shows "solve_rec_c s = Some r ⟹ (case s of
        Q (x,y,state) ⇒ query_dom x y state
          ∧ query x y state = r
      | I (x,state) ⇒ iterate_dom x state
          ∧ iterate x state = r
      | E (x,t,state) ⇒ eval_dom x t state
          ∧ eval x t state = r)"
proof (induction arbitrary: s r rule: solve_rec_c.fixp_induct)
  case 1
  then show ?case using option_admissible by fast
next
  case 2
  then show ?case by simp
next
  case (3 S)
  show ?case
  proof (cases s)
    case (Q a)
    obtain y x state where "a = (y, x, state)" using prod_cases3 by blast
    have "query_dom y x state ∧ query y x state = r"
    proof (cases "x ∈ called state")
      case True
      then have "Some (mlup (σ state) x,
          state⦇infl := fminsert (infl state) x y, point := insert x (point state)⦈) = Some r"
        using 3(2) Q ‹a = (y, x, state)› by auto
      then show ?thesis using query.psimps[folded query_dom_def, of y x state]
            query_iterate_eval.domintros(1)[folded query_dom_def, of x state] True by force
    next
      case False
      then have "Option.bind (S (I (x, state ⦇called := insert x (called state)⦈))) (λ(d,state).
          Some (d, state ⦇infl := fminsert (infl state) x y⦈)) = Some r"
        using 3(2) Q ‹a = (y, x, state)› by simp
      then obtain d1 state1
        where "S (I (x, state ⦇called := insert x (called state)⦈)) = Some (d1 ,state1)"
        and "(d1, state1 ⦇infl := fminsert (infl state1) x y⦈) = r"
        by (cases "S (I (x, state ⦇called := insert x (called state)⦈))") auto
      then have "iterate_dom x (state ⦇called := insert x (called state)⦈)
          ∧ iterate x (state ⦇called := insert x (called state)⦈) = (d1, state1)"
        using 3(1) unfolding iterate_dom_def by fastforce
      then show ?thesis using False ‹(d1, state1 ⦇infl := fminsert (infl state1) x y⦈) = r›
        by (simp add: query_iterate_eval.domintros(1) False)
    qed
    then show ?thesis using Q ‹a = (y, x, state)› by simp
  next
    case (I a)
    obtain x state where "a = (x, state)" by fastforce
    show ?thesis
    proof(cases "x ∈ (stabl state)")
      case True
      then have "(mlup (σ state) x, state ⦇called := called state - {x}, point := (point state) - {x}⦈) = r"
        using I ‹a = (x, state)› 3(2) by simp
      moreover have "iterate_dom x state ∧ iterate x state = (mlup (σ state) x,
          state ⦇called := called state - {x}, point := (point state) - {x}⦈)"
        using True query_iterate_eval.domintros(2) iterate.psimps dom_defs by fastforce
      ultimately show ?thesis using I ‹a = (x, state)› by simp
    next
      case False
      obtain p0 where "p0 = point state" by blast
      with False have IH1: "Option.bind (S (E (x, T x, state ⦇stabl := insert x (stabl state)⦈)))
          (λ(d, state1).
            let d_new = if x ∉ p0 then d else mlup (σ state1) x ∇Δ d in
            if mlup (σ state1) x = d_new then
              Some (mlup (σ state1) x, state1 ⦇called := called state1 - {x}, point := (point state1) - {x}⦈)
            else let (infl2, stabl2) = destab x (infl state1) (stabl state1) in
            S (I (x, state1 ⦇infl := infl2, stabl := stabl2, σ := (σ state1)(x ↦ d_new)⦈))) =
          Some r"
        using 3(2) I ‹a = (x, state)› by simp
      then obtain d state1 d_new
        where eval_some: "S (E (x, T x, state ⦇stabl := insert x (stabl state)⦈))
          = Some (d, state1)" and
          d_new: "d_new = (if x ∉ (point state) then d else mlup (σ state1) x ∇Δ d)"
        using 3(2) I
        by (cases "S (E (x, T x, state ⦇stabl := insert x (stabl state)⦈))") auto
      then have eval: "eval_dom x (T x) (state ⦇stabl := insert x (stabl state)⦈)
          ∧ eval x (T x) (state ⦇stabl := insert x (stabl state)⦈) = (d, state1)"
        using 3(1) d_new unfolding TD_plain.eval_dom_def by force
      have "iterate_dom x state ∧ iterate x state = r"
      proof (cases "mlup (σ state1) x = d_new")
        case True
        have "(d_new, state1 ⦇called := called state1 - {x}, point := (point state1) - {x}⦈) = r"
          using IH1 eval_some True d_new ‹p0 = point state› by auto
        moreover have "iterate_dom x state"
          using query_iterate_eval.domintros(2)[folded dom_defs] False True eval d_new by fastforce
        ultimately show ?thesis
          using iterate.psimps[folded dom_defs] False True eval d_new by fastforce
      next
        case False
        obtain infl2 stabl2 where
            destab: "(infl2, stabl2) = destab x (infl state1) (stabl state1)"
          by (cases "destab x (infl state1)  (stabl state1)") auto
        let ?state2 = "state1⦇infl := infl2, stabl := stabl2, σ := (σ state1)(x ↦ d_new)⦈"
        have "S (I (x, ?state2)) = Some r"
          using IH1 False eval_some d_new destab ‹p0 = point state› by (auto split: prod.splits)
        then have iter_cont: "iterate_dom x ?state2 ∧ iterate x ?state2 = r"
          using 3(1) unfolding iterate_dom_def by fastforce
        then have "iterate_dom x state"
          using query_iterate_eval.domintros(2)[folded dom_defs, of x state] eval
            ‹x ∉ (stabl state)› False destab d_new
          by (cases "destab x (infl state1) (stabl state1)") (auto split: if_splits)
        then show ?thesis
          using iterate.psimps[folded dom_defs, of x state] ‹x ∉ (stabl state)› destab eval
            False iter_cont d_new
          by (cases "destab x (infl state1) (stabl state1)") (auto split: if_splits)
      qed
      then show ?thesis using I ‹a = (x, state)› by simp
    qed
  next
    case (E a)
    obtain x t state where "a = (x, t, state)" using prod_cases3 by blast
    then have "s = E (x, t, state)" using E by auto
    have "eval_dom x t state ∧ eval x t state = r"
    proof (cases t)
      case (Answer d)
      then have "eval_dom x t state"
        unfolding eval_dom_def using query_iterate_eval.domintros(3) by fastforce
      moreover have "eval x t state = (d, state)"
        using Answer eval.psimps[folded dom_defs, OF calculation] by auto
      moreover have "(d, state) = r"
        using 3(2) ‹s = E (x, t, state)› Answer by simp
      ultimately show ?thesis by simp
    next
      case (Query y g)
      then have A: "Option.bind (S (Q (x, y, state))) (λ(yd, state).
        S (E (x, g yd, state))) = Some r" using ‹s = E (x, t, state)› 3(2)
        by simp
      then obtain yd state1
          where S1: "S (Q (x, y, state)) = Some (yd, state1)"
          and S2: "S (E (x, g yd, state1)) = Some r"
        by (cases "S (Q (x, y, state))") auto
      then have "query_dom x y state
          ∧ query x y state = (yd, state1)"
          and "eval_dom x (g yd) state1 ∧ eval x (g yd) state1 = r"
        using 3(1)[OF S1] 3(1)[OF S2] unfolding TD_plain.dom_defs by force+
      then show ?thesis
        using query_iterate_eval.domintros(3)[folded dom_defs] eval.psimps[folded dom_defs] Query
        by fastforce
    qed
    then show ?thesis using E ‹a = (x, t, state)› by simp
  qed
qed

theorem term_equivalence: "solve_dom x ⟷ solve_c_dom x"
  using solve_rec_c_query_iterate_eval_equiv query_iterate_eval_solve_rec_c_equiv(2)[of x]
  unfolding solve_dom_def solve_c_dom_def solve_rec_c_dom_def solve_c_def
  by (cases "solve_rec_c (I (x, ⦇called = {x}, σ = Map.empty, infl = fmempty, stabl = {},
      point = {}⦈))")
     fastforce+

theorem value_equivalence: "solve_dom x ⟹ ∃σ. solve_c x = Some σ ∧ solve x = σ"
proof goal_cases
  case 1
  then obtain r where "solve_rec_c (I (x,
      ⦇called = {x}, σ = Map.empty, infl = fmempty, stabl = {}, point = {}⦈)) = Some r
    ∧ iterate x ⦇called = {x}, σ = Map.empty, infl = fmempty, stabl = {}, point = {}⦈ = r"
    using query_iterate_eval_solve_rec_c_equiv(2)[OF 1[unfolded solve_dom_def]]
    unfolding solve_rec_c_dom_def solve_dom_def
    by fastforce
  then show ?case unfolding solve_c_def solve_def by (auto split: prod.split)
qed

text‹With the equivalence of the refined version and the initial version proven, we can specify a
  the code equation.›

lemma solve_code_equation [code]:
  "solve x = (case solve_c x of Some r ⇒ r
  | None ⇒ Code.abort (STR ''Input not in domain'') (λ_. solve x))"
proof (cases "solve_dom x")
  case True
  then show ?thesis
    using solve_c_def solve_def value_equivalence by fastforce
next
  case False
  then have "solve_c x = None" using solve_c_dom_def term_equivalence by (meson option.exhaust)
  then show ?thesis by auto
qed

end

text‹Finally, we use a dedicated rewrite rule for the code generation of the solver locale.›

global_interpretation TD_warrow_Interp: TD_warrow_defs T w n for T w n
  defines TD_warrow_Interp_solve = TD_warrow_Interp.solve
  done

export_code TD_warrow_Interp_solve in SML


subsection ‹Lemmas about Warowing Operator.›

locale TD_warrow = TD_warrow_defs T widening narrowing
  for T :: "('x, 'd :: order_bot) eqsT"
    and widening :: "'d ⇒ 'd ⇒ 'd" (infixl "∇" 65)
    and narrowing :: "'d ⇒ 'd ⇒ 'd" (infixl "Δ" 70) +
  assumes widening_ge_2: "b ≤ a ∇ b"
    and narrowing_ge: "b ≤ a ⟹ b ≤ a Δ b"
begin

lemma warrowing_properties:
  "b ≤ a ∇Δ b"
  "a = a ∇Δ b ⟹ b ≤ a"
  unfolding warrowing_def
  using narrowing_ge[of b a] widening_ge_2[of b a] by (auto split: if_splits)

subsection ‹Well-formedness of Infl and Stabl›

subsubsection ‹Predicate for Well-formed Infl Map and Stable Set›

text‹For the warrowing TD, we adapt the predicate of valid solver states already used in the proof
  of the vanilla TD. Instead of demanding @{term σ} to be a partial solution of the equation
  system, it may only be a partial post-solution. Note that the composition of the set of warrowing
  points @{term point} is not relevant for the partial correctness proof, but is only crucial for
  termination.›

definition well_formed_infl_stabl where
  "well_formed_infl_stabl state ≡
    called state ⊆ stabl state
    ∧ fset (fmdom (infl state)) ⊆ stabl state
    ∧ (∀y∈stabl state - called state. ∀x ∈ dep T (σ state) y. y ∈ slookup (infl state) x)"

abbreviation "update_rel x state state' ≡
    stabl state ⊆ stabl state' ∧
    (∀u. slookup (infl state) u ⊆ slookup (infl state') u) ∧
    (∀u. (slookup (infl state') u - slookup (infl state) u) ∩ (stabl state - {x}) = {})"

lemma well_formed_infl_stabl_simp_c_stabl:
  assumes "x ∈ called state"
    and "well_formed_infl_stabl (state⦇called := called state - {x}⦈)"
  shows "well_formed_infl_stabl (state⦇stabl := insert x (stabl state)⦈)"
  using assms
proof -
  have "called state - {x} ⊆ stabl state ≡ called state ⊆ insert x (stabl state)"
    using assms(1)
    by (simp add: subset_insert_iff)
  moreover have "stabl state - (called state - {x}) ⊇ insert x (stabl state) - called state"
    using assms(1)
    by auto
  ultimately show ?thesis
    using assms(2)
    unfolding well_formed_infl_stabl_def
    by auto
qed

lemma well_formed_infl_stabl_simp_p_upd:
  assumes "well_formed_infl_stabl state"
  shows "well_formed_infl_stabl (state⦇point := p'⦈)"
  using assms unfolding well_formed_infl_stabl_def by simp


subsubsection ‹Preservation of the Well-formedness›

text‹The following lemmas show that the well-formedness of infl and stabl are preserved when
  destabilizing an unknown and updating its value in @{term σ}.›

lemma destab_upd_preserves_well_formed_infl_stabl:
  assumes "called state - {x} ⊆ stabl state"
      and "(infl2, stabl2) = destab x (infl state1) (stabl state1)"
      and "(∀x∈stabl state1 - (called state1 - {x}).
            ∀y∈dep T (σ state1) x. x ∈ slookup (infl state1) y)"
      and "fset (fmdom (infl state1)) ⊆ stabl state1"
      and "stabl state ⊆ stabl2"
      and "called state1 = called state"
    shows "well_formed_infl_stabl (state1⦇infl := infl2, stabl := stabl2,
           σ := (σ state1)(x ↦ d_new), called := called state1 - {x}⦈)"
proof -
  show ?thesis
    unfolding well_formed_infl_stabl_def
  proof(intro conjI, goal_cases)
    case 1 show ?case
      using assms(1,5,6) by simp
    case 2 show ?case
      using destab_preserves_infl_dom_stabl[OF assms(2,4)] by simp
    case 3 show ?case
      using destab_and_upd_preserves_dep_closed_in_infl[OF assms(2,3)] by simp
  qed
qed


subsubsection ‹Induction proof›

text‹The well-formedness of infl and stabl is shown by induction. The proof closely aligns with the
  equivalence proof of TD and TD\_plain.›

lemma well_formed_infl_stabl_ind:
  shows "query_dom y x state
    ⟹ (xd, state') = query y x state
    ⟹ well_formed_infl_stabl state
    ⟹ well_formed_infl_stabl state'
      ∧ (∀ξ ∈ stabl state. mlup (σ state) ξ = mlup (σ state') ξ)
      ∧ y ∈ slookup (infl state') x
      ∧ update_rel y state state'"
    and "iterate_dom x state
    ⟹ (xd, state') = iterate x state
    ⟹ x ∈ called state
    ⟹ well_formed_infl_stabl (state⦇called := called state - {x}⦈)
    ⟹ well_formed_infl_stabl (state'⦇called := called state' - {x}⦈)
      ∧ (∀ξ ∈ stabl state. mlup (σ state) ξ = mlup (σ state') ξ)
      ∧ x ∈ stabl state'
      ∧ update_rel x state state'"
    and "eval_dom x t state
    ⟹ (xd, state') = eval x t state
    ⟹ well_formed_infl_stabl state
    ⟹ well_formed_infl_stabl state'
      ∧ (∀ξ ∈ stabl state. mlup (σ state) ξ = mlup (σ state') ξ)
      ∧ (∀y∈dep_aux (σ state') t. x ∈ slookup (infl state') y)
      ∧ update_rel x state state'"
proof(induction y x state and x state and y t state
    arbitrary: xd state' and xd state' and xd state'
    rule: query_iterate_eval_pinduct)
  case (Query y x state)
  show ?case using Query.IH(1) Query.prems(1)
  proof(cases rule: query_iterate_lookup_cases)
    case (Iterate state1)
    moreover note IH = Query.IH(2)[simplified, OF Iterate(1,3) Query.prems(2)]
    ultimately show ?thesis
    proof(intro conjI, goal_cases)
      case 5
      hence "infl state' = fminsert (infl state1) x y"
        and "∀u. slookup (infl state) u ⊆ slookup (infl state1) u"
        by simp+
      then show ?case by (metis le_supI1 slookup_fminsert_other slookup_fminsert_same)
    next
      case 6
      have "∀ξ. (slookup (infl state1) ξ - slookup (infl state) ξ) ∩ (stabl state) = {}"
        using 6(2,3,6) by (cases "x ∈ (stabl state)"; simp)
      then show ?case
        by (auto simp: 6(4) intro!: TD.infl_upd_diff)
    qed (auto simp: well_formed_infl_stabl_def fminsert_def fmlookup_default_def)
  next
    case Lookup
    then show ?thesis using Query.prems(2)
      by (auto simp add: well_formed_infl_stabl_def fminsert_def fmlookup_default_def)
  qed
next
  case (Iterate x state)

  note inv = well_formed_infl_stabl_simp_c_stabl[OF Iterate.prems(2,3)]
  note IH' = Iterate.IH(2)[rotated 3, OF inv]

  show ?case using Iterate.IH(1) Iterate.prems(1)
  proof(cases rule: iterate_continue_fixpoint_cases)
    case Stable
    hence "state'⦇called := called state' - {x}⦈ = state'" by fastforce
    moreover have "well_formed_infl_stabl state'"
      using Iterate.prems(3) well_formed_infl_stabl_simp_p_upd Stable(3)
      by fast
    moreover have "state⦇called := called state - {x}, point := (point state) - {x}⦈
        = state⦇point := (point state) - {x}, called := called state - {x}⦈" by auto
    ultimately show ?thesis using Stable(1,3) by auto
  next
    case Fixpoint
    note IH = IH'[OF Fixpoint(1) _ Fixpoint(4), folded dep_def]
    then show ?thesis by (auto simp: well_formed_infl_stabl_def Fixpoint(6))
  next
    case (WN_Fixpoint xd1 state1)
    note IH = IH'[OF WN_Fixpoint(1) _ WN_Fixpoint(4), folded dep_def]
    then show ?thesis by (auto simp: well_formed_infl_stabl_def WN_Fixpoint(7))
  next
    case (Continue xd1 state1 d_new infl2 stabl2)
    note IH = IH'[OF Continue(1) refl Continue(3)]

    have infl_closed:
      "(∀x∈stabl state1 - (called state1 - {x}). ∀y∈dep T (σ state1) x. x ∈ slookup (infl state1) y)"
      using IH[unfolded well_formed_infl_stabl_def, folded dep_def] c_same(3)[OF Continue(2,3)]
      by auto

    note infl2_stabl2_def = destab_infl_stabl_relation[OF Continue(6)]
    have stabl_inc: "stabl state ⊆ stabl2"
      using Iterate.prems(3) Continue(1) TD.new_lookup_to_infl_not_stabl[of state1 state x]
        destab_infl_stabl_relation[OF Continue(6)] IH
      unfolding well_formed_infl_stabl_def
      by auto

    note c_same = c_same(3)[OF Continue(2,3), simplified]
    note xcalled1 = Iterate.prems(2)[simplified c_same[symmetric]]
    have inv: "well_formed_infl_stabl (state1⦇infl := infl2, stabl := stabl2,
        σ := (σ state1)(x ↦ d_new), called := called state1 - {x}⦈)"
      apply (rule destab_upd_preserves_well_formed_infl_stabl[OF _ Continue(6) infl_closed _
             stabl_inc])
      using Iterate.prems(3) IH c_same unfolding well_formed_infl_stabl_def by simp+

    note ih = Iterate.IH(3)[OF Continue(1) refl Continue(3) _ Continue(4,5,6) _
        Continue(8), simplified, OF xcalled1 inv]

    with IH stabl_inc show ?thesis
    proof(elim conjE, intro conjI, goal_cases)
      case 2
      have "∀ξ∈stabl state. mlup (σ state1) ξ = mlup (σ state') ξ"
        using 2(1,16) Continue(1)
        unfolding mlup_def
        by (auto simp add: fun_upd_apply split: if_splits)
      then show ?case using 2(4) by simp
    next
      case 5
      show ?case
      proof(intro allI subsetI, goal_cases)
        case (1 ξ u)
        then have "ξ ∈ stabl state"
          using Iterate.prems(3) TD.stabl_infl_empty[of ξ "stabl state" "infl state"]
          unfolding well_formed_infl_stabl_def by auto
        then have "ξ ∉ insert x (influenced_by (infl state1) x)"
          using 1(1) Continue(1) conjunct2[OF infl2_stabl2_def] stabl_inc by blast
        then show ?case
          using IH conjunct1[OF infl2_stabl2_def] 1 5(12)
          apply (auto simp add: fmlookup_default_drop_set simp del: fmdrop_set_insert)
          by blast
      qed
    next case 6
      show ?case
      proof(intro allI, goal_cases)
        case (1 ξ)
        have "slookup infl2 ξ ⊆ slookup (infl state1) ξ"
          using conjunct1[OF infl2_stabl2_def] unfolding fmlookup_default_def by auto
        moreover have "(slookup (infl state') ξ - slookup infl2 ξ) ∩ (stabl state) = {}"
          using Continue(1) 6(13) stabl_inc by (cases "x ∈ stabl2") auto
        moreover have "(slookup (infl state1) ξ - slookup (infl state) ξ) ∩ (stabl state) = {}"
          using Continue(1) 6(14) by auto
        ultimately show ?case by blast
      qed
    qed (auto split: prod.split)
  qed
next
  case (Eval x t state)
  show ?case using Eval.IH(1) Eval.prems(1)
  proof(cases rule: eval_query_answer_cases)
    case (Query y g yd state1)
    note IH = Eval.IH(2)[OF Query(1,3) Eval.prems(2)]

    note ih = Eval.IH(3)[OF Query(1,3), rotated 1, OF Query(5) conjunct1[OF IH], simplified]

    have y_stabl1: "y ∈ stabl state1"
      using IH TD.stabl_infl_empty[of y "stabl state1" "infl state1"]
      unfolding well_formed_infl_stabl_def
      by fastforce
    then have mlup: "mlup (σ state') y = yd"
      using ih query_fmlookup[OF Query(2,3)] by simp

    show ?thesis using IH ih Query(1) mlup
    proof (intro conjI, goal_cases)
      case 3
      have "x ∈ slookup (infl state') y" using IH ih y_stabl1 by blast
      then show ?case using Query(1) mlup ih by auto
    next
      case 5
      then show ?case by blast
    next
      case 6
      have "∀u. (slookup (infl state') u - slookup (infl state1) u) ∩ (stabl state1 - {x}) = {}"
        using ih by auto
      then show ?case using IH by blast
    qed auto
  next
    case Answer
    then show ?thesis by (simp add: Eval.prems(2))
  qed
qed


subsection ‹Partial Correctness›

abbreviation eq_subsumed :: "('x,'d) map ⇒ 'x set ⇒ bool" where
  "eq_subsumed sigma vars ≡ (∀x ∈ vars. eq T x sigma ≤ mlup sigma x)"

lemma destab_upd_preserves_part_post_sol:
  assumes "(infl2, stabl2) = destab x (infl state1) (stabl state1)"
    and "eq_subsumed (σ state1) (stabl state1 - called state)"
    and "∀y∈stabl state1 - (called state - {x}). ∀x∈dep T (σ state1) y. y ∈ slookup (infl state1) x"
    and "eq T x (σ state1) ≤ xd'"
  shows "eq_subsumed ((σ state1)(x ↦ xd')) (stabl2 - (called state - {x}))"
proof (intro ballI, goal_cases)
  case (1 y)
  have stabl2_def: "stabl2 = (stabl state1) - influenced_by (infl state1) x"
    using destab_infl_stabl_relation[OF assms(1)] by fast
  have x_no_dep: "∀y ∈ stabl2 - (called state - {x}). x ∉ dep T (σ state1) y"
    using destab_x_no_dep[OF assms(1,3)] by simp
  have eq_y_upd: "eq T y ((σ state1)(x ↦ xd')) = eq T y (σ state1)"
    using 1 eq_mupd_no_dep[of x T "σ state1" y] x_no_dep
    by auto
  show ?case
  proof (cases "y = x")
    case True
    then show ?thesis using assms(4) eq_y_upd unfolding mlup_def by (simp add: fun_upd_same)
  next
    case False
    then have "y ∈ stabl state1 - called state"
      using 1 stabl2_def by force
    then have "eq T y (σ state1) ≤ mlup (σ state1) y"
      using assms(2) by blast
    then show ?thesis using False eq_y_upd unfolding mlup_def by (simp add: fun_upd_other)
  qed
qed

lemma eq_subsumed_ind:
  shows "query_dom y x state
    ⟹ (xd, state') = query y x state
    ⟹ well_formed_infl_stabl state
    ⟹ eq_subsumed (σ state) ((stabl state) - (called state))
    ⟹ eq_subsumed (σ state') (stabl state' - called state)"
    and "iterate_dom x state
    ⟹ (xd, state') = iterate x state
    ⟹ x ∈ (called state)
    ⟹ well_formed_infl_stabl (state⦇called := called state - {x}⦈)
    ⟹ eq_subsumed (σ state) (stabl state - (called state - {x}))
    ⟹ eq_subsumed (σ state') (stabl state' - (called state - {x}))"
    and "eval_dom x t state
    ⟹ (xd, state') = eval x t state
    ⟹ x ∈ stabl state
    ⟹ well_formed_infl_stabl state
    ⟹ eq_subsumed (σ state) ((stabl state) - (called state))
    ⟹ eq_subsumed (σ state') (stabl state' - called state)
        ∧ traverse_rhs t (σ state') = xd"
proof(induction y x state and x state and y t state
    arbitrary: xd state' and xd state' and xd state'
    rule: query_iterate_eval_pinduct)
  case (Query y x state)
  show ?case using Query.IH(1) Query.prems(1)
  proof(cases rule: query_iterate_lookup_cases)
    case (Iterate state1)
    show ?thesis
      using Query.IH(2)[simplified, OF Iterate(1,3) Query.prems(2)] Query.prems(3)
      by (simp add: Iterate(4))
  next
    case Lookup
    then show ?thesis using Query.prems(3) by simp
  qed
next
  case (Iterate x state)

  note inv = well_formed_infl_stabl_simp_c_stabl[OF Iterate.prems(2,3)]
  have "eq_subsumed (σ state) (insert x (stabl state) - (called state))"
    using Iterate.prems(2,4) by blast
  hence part_post: "eq_subsumed (σ (state⦇stabl := insert x (stabl state)⦈)) (stabl
    (state⦇stabl := insert x (stabl state)⦈) - called (state⦇stabl := insert x (stabl state)⦈))"
    by simp
  note IH' = Iterate.IH(2)[rotated 4, OF inv part_post]

  show ?case using Iterate.IH(1) Iterate.prems(1)
  proof(cases rule: iterate_continue_fixpoint_cases)
    case Stable
    show ?thesis using Stable(3) Iterate.prems(4) by auto
  next
    case (Fixpoint state1)
    note IH = IH'[OF Fixpoint(1) _ Fixpoint(4), folded dep_def]
    then show ?thesis using Fixpoint(5,6) by auto
  next
    case (WN_Fixpoint xd1 state1)
    note IH = IH'[OF WN_Fixpoint(1) _ WN_Fixpoint(4), folded dep_def]

    have "eq T x (σ state') ≤ mlup (σ state') x"
      using WN_Fixpoint(5)[simplified WN_Fixpoint(6)[symmetric], THEN warrowing_properties(2)] IH
        WN_Fixpoint(7) unfolding eq_def by force

    with IH WN_Fixpoint(7) show ?thesis by auto
  next
    case (Continue xd1 state1 d_new infl2 stabl2)
    note IH = IH'[OF Continue(1) _ Continue(3)]
    note valid_stabl_infl_1 = well_formed_infl_stabl_ind(3)[OF Continue(2,3) inv, simplified]
    note c_c1_same = c_same(3)[OF Continue(2,3), simplified]
    hence c_c1_upd_same:
      "called (state1⦇infl := infl2, stabl := stabl2, σ := (σ state1)(x ↦ d_new)⦈) = called state"
      by force

    have valid_stabl_infl_2: "well_formed_infl_stabl (state1⦇infl := infl2, stabl := stabl2,
      σ := (σ state1)(x ↦ d_new), called := called state - {x}⦈)"
    proof -
      have infl_closed: "(∀x∈stabl state1 - (called state1 - {x}).
          ∀y∈dep T (σ state1) x. x ∈ slookup (infl state1) y)"
        using valid_stabl_infl_1[folded dep_def] c_c1_same
        unfolding well_formed_infl_stabl_def by blast
      have stabl_inc: "stabl state ⊆ stabl2"
        using Iterate.prems(3) Continue(1) TD.new_lookup_to_infl_not_stabl[of state1]
          destab_infl_stabl_relation[OF Continue(6)] valid_stabl_infl_1
        unfolding well_formed_infl_stabl_def by auto
      then show ?thesis
        using destab_upd_preserves_well_formed_infl_stabl[OF _ Continue(6) infl_closed _
              stabl_inc] Iterate.prems(3) valid_stabl_infl_1 c_same(3)[OF Continue(2,3)]
        unfolding well_formed_infl_stabl_def by auto
    qed

    have "eq T x (σ state1) ≤ d_new"
      using Continue(4) IH warrowing_properties(1) by (auto split: if_splits)
    then have inv: "eq_subsumed ((σ state1)(x ↦ d_new)) (stabl2 - (called state - {x}))"
      using destab_upd_preserves_part_post_sol[OF Continue(6), of state1 d_new] IH
        valid_stabl_infl_1 c_c1_same
      unfolding well_formed_infl_stabl_def dep_def by fastforce

    have "x ∈ called (state1⦇infl := infl2, stabl := stabl2, σ := (σ state1)(x ↦ d_new)⦈)"
      using c_c1_same Iterate.prems(2) by simp
    note ih' = Iterate.IH(3)[OF Continue(1) _ Continue (3), rotated 2, OF Continue(4-6) refl
        Continue(8) this, simplified c_c1_upd_same, OF valid_stabl_infl_2 _ refl refl]

    then show ?thesis using inv by auto
  qed
next
  case (Eval x t state)
  show ?case using Eval.IH(1) Eval.prems(1)
  proof(cases rule: eval_query_answer_cases)
    case (Query y g yd state1)
    note IH = Eval.IH(2)[OF Query(1,3) Eval.prems(3,4)]

    note valid_infl_stabl_1 = well_formed_infl_stabl_ind(1)[OF Query(2,3) Eval.prems(3)]
    then have x_stabl1: "x ∈ stabl state1" using Eval.prems(2) by fast

    note ih = Eval.IH(3)[OF Query(1,3) refl Query(5) x_stabl1 conjunct1[OF valid_infl_stabl_1]
                         IH[simplified c_same(1)[OF Query(2,3), symmetric]]]
    thm c_same(1)[OF Query(2,3)]

    have y_stabl1: "y ∈ stabl state1"
      using valid_infl_stabl_1[unfolded well_formed_infl_stabl_def]
            TD.stabl_infl_empty[of y "stabl state1" "infl state1"]
      by fastforce
    then have "mlup (σ state1) y = mlup (σ state') y"
      using well_formed_infl_stabl_ind(3)[OF Query(4,5)] valid_infl_stabl_1 x_stabl1 by simp
    then have mlup: "mlup (σ state') y = yd"
      using query_fmlookup[OF Query(2,3)] by simp

    show ?thesis using ih Query(1) mlup c_same(1)[OF Query(2,3), symmetric] by auto
  next
    case Answer
    then show ?thesis using Eval.prems(2,4) by simp
  qed
qed


text‹Since the initial solver state fulfills the valid solver state predicate, we can conclude from
  the above lemma that the warrowing TD returns a partial post-solution for the queried unknown
  @{term x} and all unknowns on which it transitively depends on.›

corollary partial_correctness:
  assumes "solve_dom x"
    and "solve x = (sigma, vars)"
  shows "part_post_solution T x sigma vars"
proof -
  obtain xd state where app: "(xd, state) =
      iterate x ⦇called = {x}, σ = Map.empty, infl = fmempty, stabl = {}, point = {}⦈"
    using assms
    unfolding solve_def
    by (cases "iterate x ⦇called = {x}, σ = Map.empty, infl = fmempty, stabl = {}, point = {}⦈") auto
  hence stabl'_def: "vars = stabl state" and σ'_def: "sigma = σ state" and c_empty: "called state = {}"
    using assms(2) c_same(2)[OF assms(1)[unfolded solve_dom_def] app]
    unfolding solve_def by (auto split: prod.splits)
  have "well_formed_infl_stabl state" "x ∈ stabl state"
    using well_formed_infl_stabl_ind(2)[OF assms(1)[unfolded solve_dom_def] app]
    unfolding well_formed_infl_stabl_def
    by auto
  then have "∀ξ∈stabl state. dep T (σ state) ξ ⊆ stabl state"
    using TD.dep_subset_stable[of "infl state" "stabl state" "called state"] c_empty
    unfolding well_formed_infl_stabl_def by auto
  then show ?thesis
    using eq_subsumed_ind(2)[OF assms(1)[unfolded solve_dom_def] app] ‹x ∈ stabl state›
    unfolding well_formed_infl_stabl_def stabl'_def σ'_def by auto
qed

end


subsection ‹With Monotonicity›

text‹In this section, we consider stronger assumptions, namely that the widening
  operator is precise and that the equation system has monotonic right-hand sides with monotonic
  dependencies. These additional assumptions allow us to prove TD\_warrow equivalent to
  TD\_wn\_phases. With the equivalence and assuming that the set of unknowns is finite, the total
  correctness of both solvers can then easily be derived, as we have already proven partial
  correctness for TD\_warrow and termination of TD\_wn\_phases.›


subsubsection ‹Construction of Precise Widening Operators›

text‹First, we show that the assumption on the precision of the widening operator can be lifted as
  a precise widening operator can be constructed from any, possibly imprecise, widening operator.›

abbreviation is_widening where
  "is_widening op ≡ (∀a b. b ≤ op a b) ∧ wf {(a, b). ∃c. a ≠ b ∧ a = op b c}"

abbreviation is_precise_widening where
  "is_precise_widening op ≡ is_widening op ∧ (∀a b. b ≤ a ⟶ op a b = a)"

definition create_precise_widening where
  "create_precise_widening op ≡ (λa b. if b ≤ a then a else op a b)"

lemma create_precise_widening:
  assumes "is_widening op"
  shows "is_precise_widening (create_precise_widening op)"
  unfolding create_precise_widening_def
  using assms
  by (auto intro: wf_subset)


subsubsection ‹Characterize Set of Post-Solution Unknowns›

text‹To prove the equivalence of both solvers, we introduce three ghost variables that are
  collected in a record of type ghost_state. The ghost variables @{term cn}, @{term post} and
  @{term pinfl} track unknowns which are being iterated with narrowing, for which a post-solution
  is already computed, and their dependencies, respectively. The set of unknowns @{term post}
  is designed to be a super set of the unknowns in @{term stabl}. Note, however,
  that it may contain more as both solvers may destabilize and keep iterating unknowns for which a
  stable value is already found to improve their values with narrowing.›

record ('x,'d) post_state =
  cn :: "'x set"
  pinfl :: "('x, 'x list) fmap"
  post :: "'x set"

locale TD_warrow_mono = TD_warrow T widening narrowing
  for T :: "('x, 'd :: order_bot) eqsT"
    and widening :: "'d ⇒ 'd ⇒ 'd" (infixl "∇" 65)
    and narrowing :: "'d ⇒ 'd ⇒ 'd" (infixl "Δ" 70) +

  assumes narrowing_le: "b ≤ a ⟹ a Δ b ≤ a"
    and widening_precise: "b ≤ a ⟹ a ∇ b = a"
begin

definition narrowing_inv :: "('x,'d) state ⇒ ('x, 'd) post_state ⇒ bool" where
  "narrowing_inv state post_state ≡
    eq_subsumed (σ state) (post post_state - (called state - cn post_state))
    ∧ cn post_state ⊆ called state
    ∧ stabl state ⊆ post post_state
    ∧ fset (fmdom (pinfl post_state)) ⊆ post post_state
    ∧ (∀y∈post post_state - (called state - cn post_state). ∀x ∈ dep T (σ state) y.
        y ∈ slookup (pinfl post_state) x)
    ∧ (∀u. slookup (infl state) u ⊆ slookup (pinfl post_state) u)"

definition update_rel_nar ::
  "'x ⇒ ('x,'d) state ⇒ ('x,'d) state ⇒ ('x, 'd) post_state ⇒ ('x, 'd) post_state ⇒ bool" where
  "update_rel_nar x state state' post_state post_state' ≡
    post post_state ⊆ post post_state' ∧
    (∀u ∈ post post_state. mlup (σ state') u ≤ mlup (σ state) u) ∧
    (∀u. slookup (pinfl post_state) u ⊆ slookup (pinfl post_state') u) ∧
    (∀u. (slookup (pinfl post_state') u - slookup (pinfl post_state) u)
      ∩ (post post_state - ({x} - cn post_state)) = {}) ∧
    cn post_state' = cn post_state"


paragraph ‹Destabilization Mechanism for Post Unknowns›

text‹We align the design of the ghost variables @{term cn}, @{term post} and @{term pinfl} with the
  implementation of the solver's data structures @{term cn}, @{term stabl} and @{term infl} to
  profit from already proven auxiliary lemmas. Unknowns are optimistically added to @{term post}
  whenever they are added to @{term stabl} and dependencies are recorded in @{term pinfl} when
  recorded in @{term infl}. The data structures differ, however, in that unknowns may be kept in
  @{term post} even if removed from @{term stabl}. In the following, we design a variant of the
  destabilization mechanism for @{term stabl} and @{term infl}. This variant is used to prune
  unknowns and entries from @{term post} and @{term pinfl} when @{term σ} no longer stores a
  (partial) post-solution for them, but explicitly avoids the removal of stable unknowns.›

inductive_set influenced_by_excl_cutoff for infl x c where
  base: "y ∉ c ⟹ fmlookup infl x = Some ys ⟹ y ∈ set ys
    ⟹ y ∈ influenced_by_excl_cutoff infl x c"
| step: "z ∈ influenced_by_excl_cutoff infl x c ⟹ y ∉ c ⟹ fmlookup infl z = Some ys
    ⟹ y ∈ set ys ⟹ y ∈ influenced_by_excl_cutoff infl x c"

lemma influenced_by_excl_cutoff_equiv:
  "influenced_by_excl_cutoff i x co = influenced_by_cutoff i x (co - {x}) - co"
proof -
  have "u ∈ influenced_by_cutoff i x (co - {x}) - co"
      if "u ∈ influenced_by_excl_cutoff i x co" for u
    using that(1)
  proof (induction rule: influenced_by_excl_cutoff.induct)
    case (base y ys)
    then show ?case by (simp add: influenced_by_cutoff.base)
  next
    case (step y z zs)
    then show ?case using influenced_by_cutoff.step by fastforce
  qed
  moreover have "u ∈ influenced_by_excl_cutoff i x co"
    if "u ∈ influenced_by_cutoff i x (co - {x})" "u ∉ co" for u
    using that
  proof (induction rule: influenced_by_cutoff.induct[consumes 1, case_names base step])
    case (base ys y)
    then show ?case by (simp add: influenced_by_excl_cutoff.base)
  next
    case (step y zs z)
    then show ?case
      by (metis Diff_iff influenced_by_excl_cutoff.base influenced_by_excl_cutoff.step singletonD)
  qed
  ultimately show ?thesis by blast
qed

definition destab_barrier :: "'x ⇒ ('x, 'd) post_state ⇒ 'x set ⇒ ('x, 'd) post_state"
  where
  "destab_barrier x post_state b = (
   let i = fmdrop_set (insert x (influenced_by_excl_cutoff (pinfl post_state) x b))
           (pinfl post_state) in
   let s = post post_state - influenced_by_excl_cutoff (pinfl post_state) x b in
   post_state⦇pinfl := i, post := s⦈)"

definition destab_post ::
  "'x ⇒ bool ⇒ ('x, 'd) post_state ⇒ 'x set ⇒ ('x, 'd) post_state" where
  "destab_post x x_truly_post post_state b =
    (if x_truly_post then post_state else destab_barrier x post_state b)"


paragraph ‹Preservation of the Invariant and Auxiliary Lemmas›

text‹In this section, we prove several auxiliary lemmas. They, e.g., help to argue that the
  restricted destabilization mechanism for post unknowns is sufficient, i.e., the resulting set
  is again closed under the dependencies and contains only unknowns for which a partial
  post-solution is already found.›

lemma lookup_in_influenced_cutoff:
  assumes "x ∉ s"
  shows "slookup i x ⊆ influenced_by_cutoff i x s"
proof(intro subsetI, goal_cases)
  case (1 y)
  then show ?case
    using influenced_by_cutoff.base[of x s i] assms
    by (cases rule: set_fmlookup_default_cases) simp
qed

lemma part_post_solution_preserved:
  assumes "is_mono_eq T"
    and "eq_subsumed (σ state1) truly_post"
    and "d ≤ mlup (σ state1) x"
    and "eq T x (σ state1) ≤ d"
  shows "eq_subsumed ((σ state1)(x↦d)) (insert x truly_post)"
proof -
  have "(σ state1)(x ↦ d) ⊑m σ state1" using assms(3) by (simp add: fun_upd_apply mlup_def)
  then have "eq T u ((σ state1)(x ↦ d)) ≤ eq T u (σ state1)" for u
    using assms(1) unfolding is_mono_eq_def by simp
  moreover have "eq T u (σ state1) ≤ mlup ((σ state1)(x ↦ d)) u"
    if "u ∈ insert x truly_post" for u
  proof (cases "u = x")
    case True
    then show ?thesis using assms(4) by (auto simp add: fun_upd_same mlup_def)
  next
    case False
    then show ?thesis using assms(2) that by (auto simp add: mlup_def fun_upd_other)
  qed
  ultimately show ?thesis using order_trans by blast
qed

lemma nar_inv_after_update_if_post:
  assumes "is_mono_eq T"
    and "mono_deps T"
    and IH: "narrowing_inv state1 post_state1"
    and post_inv: "well_formed_infl_stabl state1"
    and dep_x_in_infl1: "∀u∈dep T (σ state1) x. x ∈ slookup (infl state1) u"
    and d_geq_eq: "eq T x (σ state1) ≤ d"
    and d_leq_lookup: "d ≤ mlup (σ state1) x"
    and destab_stabl: "(infl2, stabl2) = destab x (infl state1) (stabl state1)"
  shows "narrowing_inv (state1⦇infl := infl2, stabl := stabl2, σ := (σ state1)(x ↦ d),
          called := called state1 - {x}⦈) (post_state1⦇cn := cn post_state1 - {x}⦈)"
  unfolding narrowing_inv_def
proof (intro conjI, goal_cases)

  case 1
  then show ?case
    using part_post_solution_preserved[OF assms(1) _ d_leq_lookup d_geq_eq] IH
    unfolding narrowing_inv_def by auto

  case 2
  then show ?case using IH unfolding narrowing_inv_def by auto

  case 3
  then have "stabl state1 ⊆ post post_state1" using IH unfolding narrowing_inv_def by auto
  then show ?case using destab_infl_stabl_relation[OF destab_stabl] by auto

  case 4
  show ?case using IH[unfolded narrowing_inv_def] by simp

  case 5
  have "(σ state1)(x ↦ d) ⊑m σ state1" using d_leq_lookup by (simp add: fun_upd_apply mlup_def)
  then have "dep T ((σ state1)(x ↦ d)) u ⊆ dep T (σ state1) u" for u
    using ‹mono_deps T› unfolding mono_deps_def by simp
  moreover have "∀y∈post post_state1 - (called state1 - {x} - (cn post_state1 - {x})).
      ∀x∈dep T (σ state1) y. y ∈ slookup (pinfl post_state1) x"
    using IH dep_x_in_infl1 unfolding narrowing_inv_def by blast
  ultimately show ?case by auto

  case 6
  have "slookup infl2 u ⊆ slookup (infl state1) u" for u
    using destab_infl_stabl_relation[OF destab_stabl]
    by (metis empty_iff empty_set fmlookup_default_drop_set subsetI)
  then show ?case using IH unfolding narrowing_inv_def by fastforce
qed

lemma no_dep_on_x_if_post_after_destab:
  assumes destab_stabl_res_2: "stabl2 = stabl state1 - influenced_by (infl state1) x"
    and x_not_post: "x ∉ post post_state"
    and post_inv: "well_formed_infl_stabl (state⦇called := called state - {x}⦈)"
    and nar_inv: "narrowing_inv (state⦇called := called state - {x}⦈) (post_state⦇cn := cn post_state - {x}⦈)"
    and update_rel_nar: "update_rel_nar x (state⦇stabl := insert x (stabl state)⦈) state1
          (post_state⦇post := insert x (post post_state)⦈) post_state1"
    and post_inv1: "well_formed_infl_stabl state1"
    and nar_inv1: "narrowing_inv state1 post_state1"
    and dep_x_infl1: "∀y ∈ dep T (σ state1) x. x ∈ slookup (infl state1) y"
    and cn_same: "cn post_state1 = cn post_state"
    and u_in_post1: "u ∈ post post_state1"
    and u_not_cw: "u ∉ called state1 - (cn post_state1) - {x}"
    and u_not_pinfl_cutoff_by_x:
        "u ∉ influenced_by_cutoff (pinfl post_state1) x (stabl2 - {x}) - stabl2"
  shows "x ∉ dep T (σ state1) u"
proof -
  consider "u ∈ stabl2" | "u ∉ influenced_by_cutoff (pinfl post_state1) x (stabl2 - {x})"
    using u_not_pinfl_cutoff_by_x by blast
  then show ?thesis
  proof cases
    case 1
    show ?thesis
    proof (cases "u ∈ stabl state1 - (called state1 - {x})")
      case True
      have "u ∉ influenced_by (infl state1) x" using destab_stabl_res_2 1 by auto
      then have "u ∉ slookup (infl state1) x" using lookup_in_influenced by fast
      then show ?thesis
        using post_inv1 dep_x_infl1 True unfolding well_formed_infl_stabl_def by blast
    next
      case False
      then have "u ∈ cn post_state1" using 1 destab_stabl_res_2 u_not_cw by blast
      then have "u ∈ cn post_state - {x}" using cn_same 1 False destab_stabl_res_2 by blast
      then have "u ∈ insert x (post post_state) - ({x} - cn post_state)"
        using post_inv nar_inv unfolding well_formed_infl_stabl_def narrowing_inv_def by auto
      moreover have "slookup (pinfl post_state) x = {}"
        apply (intro TD.stabl_infl_empty)
        using x_not_post nar_inv unfolding narrowing_inv_def by auto
      ultimately have "u ∉ slookup (pinfl post_state1) x"
        using update_rel_nar[unfolded update_rel_nar_def] by fastforce
      then show ?thesis
        using nar_inv1 u_in_post1 u_not_cw dep_x_infl1 unfolding narrowing_inv_def by blast
    qed
  next
    case 2
    then have "u ∉ slookup (pinfl post_state1) x"
      using lookup_in_influenced_cutoff[of x "stabl2 - {x}"]
      by blast
    then show ?thesis
      using dep_x_infl1 nar_inv1 u_in_post1 u_not_cw unfolding narrowing_inv_def by blast
  qed
qed

lemma non_post_not_influenced:
  assumes "u ∈ influenced_by (pinfl post_state1) x"
    and x_not_post: "x ∉ post post_state"
    and lookup_diff: "∀u. (slookup (pinfl post_state1) u - slookup (pinfl post_state) u)
                      ∩ (post post_state - {x}) = {}"
    and pinfl_subset_post: "fset (fmdom (pinfl post_state)) ⊆ post post_state"
  shows "u ∉ post post_state"
    using assms(1)
proof (induction rule: influenced_by.induct[consumes 1, case_names base step])
  case (base ys y)
  have "slookup (pinfl post_state) x = {}"
    using x_not_post pinfl_subset_post TD.stabl_infl_empty by simp
  then have "∀u ∈ slookup (pinfl post_state1) x. u ∉ post post_state - {x}"
    using lookup_diff by fastforce
  then have "y ∉ post post_state - {x}" using base by simp
  then show ?case using x_not_post by simp
next
  case (step y zs z)
  have "slookup (pinfl post_state) y = {}"
    using pinfl_subset_post step(4) unfolding narrowing_inv_def by (meson TD.stabl_infl_empty)
  then have "z ∈ slookup (pinfl post_state1) y - slookup (pinfl post_state) y"
    by (simp add: step.hyps(2) step.hyps(3))
  then show ?case using lookup_diff x_not_post by blast
qed

lemma nar_inv_after_destab_update_if_not_post:
  assumes x_not_post: "x ∉ post post_state"
    and x_not_cn: "x ∉ cn post_state"
    and post_inv: "well_formed_infl_stabl (state⦇called := called state - {x}⦈)"
    and nar_inv: "narrowing_inv (state⦇called := called state - {x}⦈) (post_state⦇cn := cn post_state - {x}⦈)"
    and post_inv1: "well_formed_infl_stabl state1"
    and nar_inv1: "narrowing_inv state1 post_state1"
    and update_rel: "update_rel x (state⦇stabl := insert x (stabl state)⦈) state1"
    and update_rel_nar: "update_rel_nar x (state⦇stabl := insert x (stabl state)⦈) state1
          (post_state⦇post := insert x (post post_state)⦈) post_state1"
    and destab_post: "post_state2 =
          destab_post x x_truly_post (post_state1⦇cn := cn post_state1⦈) stabl2"
    and destab_stabl: "(infl2, stabl2) = destab x (infl state1) (stabl state1)"
    and xd1_def: "eq T x (σ state1) ≤ d"
    and dep_x_infl1: "∀y ∈ dep T (σ state1) x. x ∈ slookup (infl state1) y"
    and post_inv2: "well_formed_infl_stabl (state1⦇infl := infl2, stabl := stabl2,
          σ := (σ state1)(x ↦ d), called := called state1 - {x}⦈)"
    and c_same: "called state1 = called state"
    and cn_same: "cn post_state1 = cn post_state"
    and x_not_truly_post: "¬ x_truly_post"
  shows "narrowing_inv (state1⦇infl := infl2, stabl := stabl2, σ := (σ state1)(x ↦ d),
          called := called state1 - {x}⦈) (post_state2⦇cn := cn post_state2 - {x}⦈)"
proof -
  have destab_post_res:
    "pinfl post_state2 = fmdrop_set (insert x (influenced_by_cutoff (pinfl post_state1) x
                         (stabl2 - {x}) - stabl2)) (pinfl post_state1)"
    "post post_state2 = post post_state1 -
                        (influenced_by_cutoff (pinfl post_state1) x (stabl2 - {x}) - stabl2)"
    "cn post_state2 = cn post_state1"
    using destab_post x_not_post influenced_by_excl_cutoff_equiv[of _ x stabl2] x_not_truly_post
    unfolding destab_post_def destab_barrier_def by (auto split: prod.splits)

  have destab_stabl_res:
    "infl2 = fmdrop_set (insert x (influenced_by (infl state1) x)) (infl state1)"
    "stabl2 = stabl state1 - influenced_by (infl state1) x"
    using destab_stabl destab_infl_stabl_relation[of infl2 stabl2 x] by auto

  have stabl_subset_post2: "stabl2 ⊆ post post_state2"
  proof -
    have "stabl state1 ⊆ post post_state1" using nar_inv1 unfolding narrowing_inv_def by simp
    then show ?thesis
      using destab_post_res(2) destab_stabl_res(2) by auto
  qed

  show ?thesis
    unfolding narrowing_inv_def
  proof (intro conjI, goal_cases)
    case 2
    then show ?case using destab_post_res(3) nar_inv1 unfolding narrowing_inv_def by auto

    case 3
    then show ?case using stabl_subset_post2 by auto

    case 1
    have "eq T u (σ state1) ≤ mlup (σ state1) u"
      if "u ∈ post post_state1 - (called state1 - cn post_state1)" for u
      using nar_inv1[unfolded narrowing_inv_def] that by simp
    then have "eq T u (σ state1) ≤ mlup ((σ state1)(x ↦ d)) u" if "x ≠ u"
        "u ∈ post post_state1 - (called state1 - {x} - cn post_state1)" for u
      using that by (auto simp add: fun_upd_other mlup_def)
    moreover have "eq T x (σ state1) ≤ mlup ((σ state1)(x ↦ d)) x"
      using nar_inv1 xd1_def by (auto simp add: fun_upd_same mlup_def)
    moreover have "eq T u ((σ state1)(x ↦ d)) = eq T u (σ state1)"
      if "u ∈ post post_state2 - (called state1 - {x} - cn post_state1)" for u
    proof -
      have "x ∉ dep T (σ state1) u"
        apply (intro no_dep_on_x_if_post_after_destab[OF destab_stabl_res(2) x_not_post post_inv
              nar_inv update_rel_nar post_inv1 nar_inv1 dep_x_infl1 cn_same])
        using that destab_post_res(2) by auto
      then show ?thesis using eq_mupd_no_dep by force
    qed
    ultimately show ?case using destab_post_res(2,3) by force
  next
    case 4
    have "fset (fmdom (pinfl post_state1)) ⊆ post post_state1"
      using nar_inv1 unfolding narrowing_inv_def by blast
    then show ?case
      using destab_post_res(1,2) by (auto simp add: fmlookup_dom_iff split: if_splits)
  next
    case 5
    have "∀y∈post post_state1 - (called state1 - cn post_state1 - {x}). ∀x∈dep T (σ state1) y.
        y ∈ slookup (pinfl post_state1) x"
      using nar_inv1 dep_x_infl1 unfolding narrowing_inv_def by blast
    show ?case
    proof (intro ballI, goal_cases)
      case (1 y z)
      then have y_post2: "y ∈ post post_state2"
        by simp
      have "x ∉ dep T (σ state1) y"
        apply (intro no_dep_on_x_if_post_after_destab[OF destab_stabl_res(2) _ post_inv nar_inv _
            post_inv1 nar_inv1 dep_x_infl1])
        using x_not_post update_rel_nar destab_post_res(2,3) 1(1) cn_same by auto
      then have "dep T ((σ state1)(x ↦ d)) y = dep T (σ state1) y"
        by (metis dep_eq mlup_eq_mupd_set)
      then have "z ∈ dep T (σ state1) y" using 1(2) by auto
      then have "y ∈ slookup (pinfl post_state1) z"
      proof -
        have "∀y∈post post_state1 - ((called state1 - cn post_state1) - {x}).
            ∀x∈dep T (σ state1) y. y ∈ slookup (pinfl post_state1) x"
          using nar_inv1 dep_x_infl1 unfolding narrowing_inv_def by blast
        moreover have "y ∈ post post_state1 - (called state1 - {x} - (cn post_state1 - {x}))"
          using "1"(1) destab_post_res(2,3) by simp
        ultimately show ?thesis using ‹z ∈ dep T (σ state1) y› by blast
      qed
      have "z ≠ x" using ‹z ∈ dep T (σ state1) y› ‹x ∉ dep T (σ state1) y› by auto

      have "z ∈ post post_state1"
        using ‹y ∈ slookup (pinfl post_state1) z› nar_inv1 unfolding narrowing_inv_def
        by (metis TD.stabl_infl_empty empty_iff)
      have "y ∈ post post_state1" using "1"(1) destab_post_res(2) by auto

      have "z ∉ influenced_by_cutoff (pinfl post_state1) x (stabl2 - {x}) - stabl2"
      proof (rule ccontr, goal_cases)
        case 1
        then have "z ∉ stabl2" "z ∈ influenced_by_cutoff (pinfl post_state1) x (stabl2 - {x})"
          by auto
        then have "y ∈ influenced_by_cutoff (pinfl post_state1) x (stabl2 - {x})"
          using influenced_by_cutoff.step[of z _ x "stabl2 - {x}"]
            ‹y ∈ slookup (pinfl post_state1) z›
          by (meson Diff_iff set_fmlookup_default_cases)
        then have "y ∈ stabl2"
          using destab_post_res(2) influenced_by_excl_cutoff_equiv[of _ x stabl2] y_post2
          by auto
        have "y ∉ stabl2 - (called state - {x})"
        proof (rule ccontr, goal_cases)
          case 1
          have "∀ξ∈stabl2 - (called state1 - {x}). dep T ((σ state1)(x ↦ d)) ξ ⊆ stabl2"
            apply (intro TD.dep_subset_stable[of infl2])
            using post_inv2
            unfolding well_formed_infl_stabl_def
            by simp+
          then have "dep T (σ state1) y ⊆ stabl2"
            using ‹dep T ((σ state1)(x ↦ d)) y = dep T (σ state1) y› 1 c_same by blast
          then have "z ∈ stabl2" using ‹z ∈ dep T (σ state1) y› by auto
          then show ?case using ‹z ∉ stabl2› by simp
        qed
        then have "y ∈ called state" "y ≠ x" using ‹y ∈ stabl2› by auto
        then have "y ∈ stabl state"
          using post_inv nar_inv unfolding well_formed_infl_stabl_def narrowing_inv_def by auto
        then have "y ∈ post post_state" using nar_inv unfolding narrowing_inv_def by auto
        then have "y ∈ slookup (pinfl post_state) z"
          using ‹y ∈ slookup (pinfl post_state1) z› ‹y ∈ post post_state› ‹y ≠ x› update_rel_nar
          unfolding update_rel_nar_def by auto
        then have "z ∈ post post_state"
          using nar_inv TD.stabl_infl_empty[of z "post post_state" "pinfl post_state"]
          unfolding narrowing_inv_def by force
        have "y ∈ influenced_by (pinfl post_state1) x"
          using influenced_cutoff_subset
            ‹y ∈ influenced_by_cutoff (pinfl post_state1) x (stabl2 - {x})›
          by fastforce
        have "y ∉ post post_state"
          apply (intro non_post_not_influenced[OF ‹y ∈ influenced_by (pinfl post_state1) x›
                 x_not_post])
          using nar_inv update_rel_nar unfolding narrowing_inv_def update_rel_nar_def
          by auto
        then show False using ‹y ∈ post post_state› by blast
      qed
      then have "z ∉ insert x (influenced_by_cutoff (pinfl post_state1) x (stabl2 - {x})
          - stabl2)"
        using ‹z ≠ x› by blast
      then have "slookup (pinfl post_state1) z = slookup (pinfl post_state2) z"
        using destab_post_res(1) by (metis fmlookup_default_drop_set)
      then show ?case using ‹y ∈ slookup (pinfl post_state1) z› by simp
    qed
  next
    case 6
    then show ?case
    proof (intro allI, goal_cases)
      case (1 u)
      then show ?case
      proof (cases "u = x")
        case True
        then show ?thesis using destab_post_res(1) destab_stabl_res(1)
          by (simp add: fmlookup_default_drop_set del: fmdrop_set_insert)
      next
        case False
        then show ?thesis
        proof (cases "u ∈ stabl2")
          case True
          have "slookup infl2 u ⊆ slookup (infl state1) u"
            using destab_stabl_res(1) fmlookup_default_drop_set
            by (metis empty_iff empty_set subset_iff)
          moreover have "slookup (pinfl post_state2) u = slookup (pinfl post_state1) u"
            using destab_post_res(1) True False fmlookup_default_drop_set
            by (metis DiffD2 insertE)
          ultimately show ?thesis using nar_inv1 unfolding narrowing_inv_def by force
        next
          case False
          then have "slookup infl2 u = {}"
            using TD.stabl_infl_empty post_inv2 well_formed_infl_stabl_def
                destab_preserves_infl_dom_stabl destab_stabl post_inv1
            by metis
          then show ?thesis by simp
      qed
      qed
    qed
  qed
qed

lemma post_dom_incr:
  assumes post_inv: "well_formed_infl_stabl (state⦇called := called state - {x}⦈)"
    and post_inv1: "well_formed_infl_stabl state1"
    and nar_inv: "narrowing_inv (state⦇called := called state - {x}⦈) (post_state⦇cn := cn post_state - {x}⦈)"
    and nar_inv1: "narrowing_inv state1 post_state1"
    and update_rel_nar: "update_rel_nar x (state⦇stabl := insert x (stabl state)⦈) state1
                         (post_state⦇post := insert x (post post_state)⦈) post_state1"
    and destab: "post_state2 = destab_post x x_truly_post (post_state1⦇cn := cnx⦈) stabl2"
    and x_not_truly_post: "¬ x_truly_post ⟹ x ∉ post post_state ∧ x ∉ cn post_state"
  shows "post post_state ⊆ post post_state2"
proof (cases x_truly_post)
  case True
  then show ?thesis
    using destab update_rel_nar unfolding destab_post_def update_rel_nar_def by simp
next
  case False
  then have "x ∉ cn post_state" and x_not_post: "x ∉ post post_state"
    using x_not_truly_post by auto

  have "x ∉ fset (fmdom (pinfl post_state))"
    using nar_inv x_not_post unfolding narrowing_inv_def by auto
  then have "slookup (pinfl post_state) x = {}" by (simp add: TD.stabl_infl_empty)
  then have "influenced_by (pinfl post_state) x = {}"
    by (metis influenced_by_aux UN_E empty_iff equals0I)

  have post2_sub: "post post_state ⊆ post post_state1 - {x}"
    using update_rel_nar x_not_post unfolding update_rel_nar_def by auto
  have destab_post: "post post_state2 = post post_state1 -
      (influenced_by_cutoff (pinfl post_state1) x (stabl2 - {x}) - stabl2)"
    using destab influenced_by_excl_cutoff_equiv[of _ x] False
    unfolding destab_post_def destab_barrier_def by simp

  have U: "∀u. (slookup (pinfl post_state1) u - slookup (pinfl post_state) u)
      ∩ (post post_state - {x}) = {}"
    using ‹x ∉ cn post_state› update_rel_nar unfolding update_rel_nar_def by auto
  have "u ∉ post post_state" if "u ∈ influenced_by (pinfl post_state1) x" for u
    using that
  proof (induction rule: influenced_by.induct[consumes 1, case_names base step])
    case (base ys y)
    have "∀u ∈ slookup (pinfl post_state1) x. u ∉ post post_state - {x}"
      using U ‹slookup (pinfl post_state) x = {}› by fastforce
    then have "y ∉ post post_state - {x}" using base by simp
    then show ?case using x_not_post by simp
  next
    case (step y zs z)
    have "slookup (pinfl post_state) y = {}"
      apply (intro TD.stabl_infl_empty)
      using nar_inv step(4) unfolding narrowing_inv_def by simp+
    then have "z ∈ slookup (pinfl post_state1) y - slookup (pinfl post_state) y"
      by (simp add: step.hyps(2) step.hyps(3))
    then show ?case using U x_not_post by blast
  qed

  moreover have "influenced_by_cutoff (pinfl post_state1) x (stabl2 - {x})
      ⊆ influenced_by (pinfl post_state1) x"
    by (meson influenced_cutoff_subset)

  ultimately show ?thesis using post2_sub destab_post by blast
qed

lemma inf_infl_inf_cutoff_infl_or_stabl:
  assumes "u ∈ influenced_by (infl state1) x"
    and "x ∈ stabl state1"
    and stabl2: "stabl2 = stabl1 - influenced_by (infl state1) x"
    and "well_formed_infl_stabl state1"
    and "narrowing_inv state1 post_state1"
    and "x ∉ stabl2"
  shows "u ∈ influenced_by_cutoff (pinfl post_state1) x stabl2 - stabl2"
  using assms(1)
proof (induction rule: influenced_by.induct[consumes 1, case_names base step])
  case (base ys y)
  then have "y ∈ slookup (pinfl post_state1) x"
    using assms(2,5) unfolding narrowing_inv_def by fastforce
  then have "y ∈ influenced_by_cutoff (pinfl post_state1) x stabl2" if "x ∉ stabl2"
    using lookup_in_influenced_cutoff that by fastforce
  moreover have "y ∉ stabl2"
    using influenced_by.base base.hyps(1) base.hyps(2) stabl2 assms(1) by fast
  ultimately show ?case using assms(6) by blast
next
  case (step y zs z)
  have "y ∈ stabl state1"
    using assms(4) step(2,3) unfolding well_formed_infl_stabl_def by (meson fmdomI subsetD)
  then have "z ∈ slookup (pinfl post_state1) y"
    using step(2,3) assms(5) unfolding narrowing_inv_def by fastforce

  have "y ∉ stabl2" using step(1) stabl2 by simp
  then have "y ∈ influenced_by_cutoff (pinfl post_state1) x stabl2" if "x ∉ stabl2"
    using step(4) that by blast
  then have "z ∈ influenced_by_cutoff (pinfl post_state1) x stabl2" if "x ∉ stabl2"
    using ‹y ∉ stabl2› that influenced_by_cutoff.step[of y _ x stabl2]
      ‹z ∈ slookup (pinfl post_state1) y›
    by (meson set_fmlookup_default_cases)

  moreover have "z ∉ stabl2" by (metis DiffD2 influenced_by.step stabl2 step.hyps(1-3))

  ultimately show ?case using assms(6) by blast
qed

lemma destab_post_c_unchanged:
  assumes "post_state2 = destab_post x x_truly_post post_state1 stabl2"
  shows "cn post_state2 = cn post_state1"
  using assms
  unfolding destab_post_def destab_barrier_def
  by auto

lemma c_post_after_destab:
  assumes "(infl2, stabl2) = destab x (infl state1) (stabl state1)"
    and "post_state2 = destab_post x x_truly_post (post_state1⦇cn := cnz⦈) stabl2"
    and "post post_state ⊆ post post_state2"
    and "narrowing_inv (state⦇called := called state - {x}⦈) (post_state⦇cn := cn post_state - {x}⦈)"
    and "well_formed_infl_stabl state1"
    and "narrowing_inv state1 post_state1"
    and "x ∈ stabl state1"
    and "¬ x_truly_post ⟹ x ∉ cn post_state ∧ x ∉ post post_state ∧ x ∉ cnz"
    and "x_truly_post ⟹ x ∈ cnz"
  shows "(x ∉ cn post_state2 ⟶ x ∈ post post_state2 ⟶ x ∈ stabl2)
         ∧ (x ∈ cn post_state2 ⟶ x ∈ post post_state2)"
proof (cases x_truly_post)
  case False
  then have "x ∉ cn post_state" "x ∉ post post_state" "x ∉ cnz" using assms(8) by blast+
  have "x ∉ post post_state2 - stabl2"
  proof -
    have "post_state2 = destab_barrier x (post_state1⦇cn := cnz⦈) stabl2"
      using assms(2) False unfolding destab_post_def by auto
    then have post2: "post post_state2 = post post_state1 -
        (influenced_by_cutoff (pinfl post_state1) x (stabl2 - {x}) - stabl2)"
      using influenced_by_excl_cutoff_equiv[of "pinfl post_state1" x stabl2]
      unfolding destab_barrier_def by simp
    have stabl2: "stabl2 = stabl state1 - influenced_by (infl state1) x"
      using destab_infl_stabl_relation[OF assms(1)] by simp
    have "slookup (pinfl post_state) x = {}"
      apply (intro TD.stabl_infl_empty[OF ‹x ∉ post post_state›])
      using assms(4) unfolding narrowing_inv_def by simp
    then have "influenced_by (pinfl post_state) x = {}"
      apply (subst influenced_by_aux)
      by simp
    have "x ∈ stabl state1" using assms(7) by auto
    then have "u ∈ influenced_by_cutoff (pinfl post_state1) x stabl2 - stabl2 ∨ x ∈ stabl2"
      if "u ∈ influenced_by (infl state1) x" for u
      using inf_infl_inf_cutoff_infl_or_stabl that assms(5,6) stabl2 by force
    then show ?thesis using post2 stabl2 assms(5,7) unfolding well_formed_infl_stabl_def by auto
  qed
  then show ?thesis using destab_post_c_unchanged[OF assms(2)] ‹x ∉ cnz› by auto
next
  case True
  then have "post_state2 = post_state1⦇cn := cnz⦈" using assms(2) unfolding destab_post_def by simp
  moreover have "x ∈ post post_state1" using assms(6,7) unfolding narrowing_inv_def by auto
  ultimately show ?thesis using assms(9)[OF True] by simp
qed

lemma narrow_inv_add_x_stabl_and_post:
  assumes xcalled: "x ∈ called state"
      and wn_post: "(x ∉ cn post_state ⟶ x ∉ post post_state - stabl state)
                      ∧ (x ∈ cn post_state ⟶ x ∈ post post_state)"
      and nar_inv: "narrowing_inv (state⦇called := called state - {x}⦈)
                      (post_state⦇cn := cn post_state - {x}⦈)"
    shows "narrowing_inv (state⦇stabl := insert x (stabl state)⦈)
            (post_state⦇post := insert x (post post_state)⦈)"
  using wn_post nar_inv xcalled unfolding narrowing_inv_def by auto


paragraph ‹Induction Proof›

text‹We show by induction on the computation trace that there exist ghost variables
  @{term cn}, @{term post} and @{term pinfl} that fulfill the @{term narrowing_inv}
  invariant and are updated consistently (@{term update_rel_nar}).›

lemma narrowing_inv_ind:
  assumes "is_mono_eq T"
    and "mono_deps T"
  shows "query_dom y x state
         ⟹ (xd, state') = query y x state
         ⟹ well_formed_infl_stabl state
         ⟹ narrowing_inv state post_state
         ⟹ x ∈ dep T (σ state) y
         ⟹ ∃post_state'. narrowing_inv state' post_state'
             ∧ update_rel_nar y state state' post_state post_state'"
    and "iterate_dom x state
         ⟹ (xd, state') = iterate x state
         ⟹ well_formed_infl_stabl (state⦇called := called state - {x}⦈)
         ⟹ narrowing_inv (state⦇called := called state - {x}⦈) (post_state⦇cn := cn post_state - {x}⦈)
         ⟹ x ∈ called state
         ⟹ (x ∉ cn post_state ⟶ x ∉ post post_state - stabl state)
             ∧ (x ∈ cn post_state ⟶ x ∈ post post_state)
         ⟹ ∃post_state'.
             narrowing_inv (state'⦇called := called state' - {x}⦈) post_state'
             ∧ update_rel_nar x (state⦇called := called state - {x}⦈) (state'⦇called := called state' - {x}⦈)
               (post_state⦇cn := insert x (cn post_state)⦈)
               (post_state'⦇cn := insert x (cn post_state')⦈)"
    and "eval_dom x t state
         ⟹ (xd, state') = eval x t state
         ⟹ well_formed_infl_stabl state
         ⟹ narrowing_inv state post_state
         ⟹ x ∈ called state
         ⟹ subt_for_prefix (T x) pre (σ state) = Some t
         ⟹ set pre ⊆ stabl state
         ⟹ ∃post_state'. narrowing_inv state' post_state'
             ∧ update_rel_nar x state state' post_state post_state'"
proof (induction y x state and x state and x t state
       arbitrary: xd state' post_state and xd state' post_state and xd state' post_state pre
       rule: query_iterate_eval_pinduct)
  case (Query y x state)
  show ?case using Query.IH(1) Query.prems(1)
  proof(cases rule: query_iterate_lookup_cases)
    case (Iterate state1)
    obtain c1n where
      c1n_def: "c1n = (if x ∈ post post_state then insert x (cn post_state) else (cn post_state))"
      by fastforce
    let ?post_state = "post_state⦇cn := c1n⦈"
    have "c1n - {x} = cn post_state"
      using c1n_def Iterate(1) Query.prems(3) unfolding narrowing_inv_def by auto
    have "(x ∉ c1n ⟶ x ∉ post post_state - stabl state) ∧ (x ∈ c1n ⟶ x ∈ post post_state)"
      using Iterate(1) Query.prems(3) c1n_def unfolding narrowing_inv_def by auto
    moreover have pinv: "well_formed_infl_stabl (state⦇called := called state - {x}⦈)"
      using Iterate(1) Query.prems(2,4) c1n_def by (auto split: if_splits)
    moreover have "narrowing_inv (state⦇called := called state - {x}⦈) (post_state⦇cn := c1n - {x}⦈)"
      using Iterate(1) Query.prems(3) c1n_def unfolding narrowing_inv_def by auto
    ultimately obtain post_state1 where
      IH: "narrowing_inv (state1⦇called := called state1 - {x}⦈) post_state1"
          "update_rel_nar x (state⦇called := called state - {x}⦈) (state1⦇called := called state1 - {x}⦈)
             (post_state⦇cn := insert x c1n⦈) (post_state1⦇cn := insert x (cn post_state1)⦈)"
      using Query.IH(2)[OF Iterate(1,3), of ?post_state] by force

    have pinv1: "well_formed_infl_stabl (state1⦇called := called state1 - {x}⦈)"
           "update_rel x (state⦇called := called state - {x}⦈) (state1⦇called := called state1 - {x}⦈)"
           "x ∈ stabl state1"
      using well_formed_infl_stabl_ind(2)[OF Iterate(2,3)] pinv by auto

    note c_same = c_same(2)[OF Iterate(2,3)]

    show ?thesis
    proof (intro exI[of _ "post_state1⦇pinfl := fminsert (pinfl post_state1) x y⦈"] conjI,
           goal_cases)
      case 1
      show ?case
        using IH(1) unfolding narrowing_inv_def
      proof (intro conjI, goal_cases)
        case 2
        then show ?case by (auto simp add: Iterate(4))
      next
        case 4
        have"x ∈ post post_state1" using 4 pinv1(3) unfolding narrowing_inv_def by auto
        moreover have "fset (fmdom (fminsert (pinfl post_state1) x y)) =
          fset (fmdom (pinfl post_state1)) ∪ {x}"
          using Iterate(4) unfolding fminsert_def by simp
        ultimately show ?case using Iterate(4) IH unfolding narrowing_inv_def by auto
      next
        case 5
        then show ?case by (auto simp add: Iterate(4) ‹c1n - {x} = cn post_state› slookup_fminsert)
      next
        case 6
        show ?case
        proof (intro allI, goal_cases)
        case (1 u)
        then show ?case using Iterate(3,4) 1 6
          by (cases "u = x") (auto simp add: slookup_fminsert_same slookup_fminsert_other)
      qed
      qed (auto simp add: Iterate(4))
    next
      case 2
      show ?case
        using IH unfolding update_rel_nar_def
      proof (intro conjI, goal_cases)
        case 3
        have "slookup (pinfl post_state1) v ⊆ slookup (fminsert (pinfl post_state1) x y) v" for v
          using Iterate(4) unfolding fmlookup_default_def fminsert_def by auto
        then show ?case using 3 by fastforce
      next
        case 4
        show ?case
        proof (cases "y ∉ cn post_state")
          case True
          then have "{y} - cn post_state = {y}" by blast
          moreover have "∀u. (slookup (pinfl post_state1) u - slookup (pinfl post_state) u)
              ∩ post post_state = {}"
            using 4 Iterate(1) Query.prems(4) by simp
          ultimately show ?thesis
            apply simp using TD.infl_upd_diff[of _ _ _ x y] 4 by simp
        next
          case False
          then have "y ∈ cn post_state" by auto
          have "y ∈ slookup (pinfl post_state) x"
          proof -
            have "y ∈ post post_state - (called state - cn post_state)"
              using Query.prems(2-4) False unfolding narrowing_inv_def well_formed_infl_stabl_def
              by auto
            then show ?thesis using Query.prems(3,4) unfolding narrowing_inv_def by blast
          qed
          then have "x ∈ post post_state"
            using Query.prems(3) TD.stabl_infl_empty[of x "post post_state" "pinfl post_state"]
            unfolding narrowing_inv_def by fastforce
          then have "y ∈ slookup (pinfl post_state1) x"
            using 4 ‹y ∈ slookup (pinfl post_state) x› unfolding update_rel_nar_def by auto
          then have "slookup (fminsert (pinfl post_state1) x y) u = slookup (pinfl post_state1) u"
            for u
            by (cases "u = x") (auto simp add: slookup_fminsert_same slookup_fminsert_other)
          then show ?thesis using Iterate(1) ‹y ∈ cn post_state› 4 by auto
        qed
      next
        case 5
        then have "cn post_state1 = c1n - {x}" unfolding narrowing_inv_def by auto
        then show ?case using ‹c1n - {x} = cn post_state› by simp
      qed (auto simp add: Iterate(4))
    qed
  next
    case Lookup
    then show ?thesis
    proof (intro exI[of _ "post_state⦇pinfl := fminsert (pinfl post_state) x y⦈"] conjI, goal_cases)
      case 1
      then show ?case
        using Query.prems(3) unfolding narrowing_inv_def
      proof (intro conjI, goal_cases)
        case 4
        have "x ∈ stabl state"
          using 4(1) Query.prems(2,4) unfolding well_formed_infl_stabl_def by auto
        then have "x ∈ post post_state" using 4 by auto
        then show ?case using 4 by (auto simp add: fminsert_def fmlookup_default_def)
      next
        case 5
        then show ?case by (auto simp add: fminsert_def fmlookup_default_def)
      next
        case 6
        then show ?case
        proof (intro allI, goal_cases)
          case (1 u)
          then show ?case
            by (cases "u = x") (auto simp add: slookup_fminsert_same slookup_fminsert_other)
        qed
      qed auto
    next
      case 2
      then show ?case
        unfolding update_rel_nar_def
      proof (intro conjI, goal_cases)
        case 3
        then show ?case unfolding fmlookup_default_def fminsert_def by auto
      next
        case 4
        then have "∀u. (slookup (fminsert (pinfl post_state) x y) u - slookup (pinfl post_state) u)
            ∩ (post post_state - {y}) = {}"
          by (simp add: TD.infl_upd_diff)
        then show ?case
        proof (intro allI, goal_cases)
          case (1 u)
          then show ?case
            using Query.prems(3,4) unfolding narrowing_inv_def
            by (cases "u = x") (auto simp add: slookup_fminsert_other slookup_fminsert_same)
        qed
      qed auto
    qed
  qed
next
  case (Iterate x state)
  have pinv: "well_formed_infl_stabl (state⦇stabl := insert x (stabl state)⦈)"
    using Iterate.prems(2,4) unfolding well_formed_infl_stabl_def by auto
  have part_post: "eq_subsumed (σ state) (insert x (stabl state) - (called state))"
    using Iterate.prems(3,4) unfolding narrowing_inv_def by auto
  have nar_inv: "narrowing_inv (state⦇stabl := insert x (stabl state)⦈)
      (post_state⦇post := insert x (post post_state)⦈)"
    using Iterate.prems(3-5) narrow_inv_add_x_stabl_and_post by force
  show ?case using Iterate.IH(1) Iterate.prems(1)
  proof (cases rule: iterate_continue_fixpoint_cases)
    case Stable
    then show ?thesis
      using Iterate.prems(3) unfolding narrowing_inv_def update_rel_nar_def
      apply (intro exI[of _ "post_state⦇cn := cn post_state - {x}⦈"])
      by auto
  next
    case (Fixpoint state1)
    obtain post_state' where
      IH: "narrowing_inv state1 post_state' ∧
           update_rel_nar x (state⦇stabl := insert x (stabl state)⦈) state1
            (post_state⦇post := insert x (post post_state)⦈) post_state'"
      using Iterate.IH(2)[OF Fixpoint(1) refl Fixpoint(4) pinv nar_inv, of "[]"] Iterate.prems(4)
      by auto

    note c_same = c_same(3)[OF Fixpoint(3,4)]
    have "insert x (post post_state) - ({x} - cn post_state) = post post_state"
      using Iterate.prems(5) Fixpoint(1) by blast

    have parCorr: "eq T x (σ state1) ≤ mlup (σ state1) x"
        "(∀y∈dep T (σ state1) x. x ∈ slookup (infl state1) y)"
      using well_formed_infl_stabl_ind(3)[OF Fixpoint(3,4) pinv]
        eq_subsumed_ind(3)[OF Fixpoint(3,4) _ pinv] part_post Fixpoint(5,6)
      unfolding dep_def
      by simp+

    then show ?thesis
      apply (intro exI[of _ "post_state'⦇cn := cn post_state' - {x}⦈"])
      using IH
      unfolding narrowing_inv_def update_rel_nar_def
      apply (simp add: c_same Fixpoint(5,6)
          ‹insert x (post post_state) - ({x} - cn post_state) = post post_state›)
      by blast
  next
    case (WN_Fixpoint xd1 state1)
    obtain post_state' where
      IH: "narrowing_inv state1 post_state'"
          "update_rel_nar x (state⦇stabl := insert x (stabl state)⦈) state1
            (post_state⦇post := insert x (post post_state)⦈) post_state'"
      using Iterate(2)[OF WN_Fixpoint(1) refl WN_Fixpoint(4) pinv nar_inv, of "[]"]
        Iterate.prems(4)
      by auto

    note c_same = c_same(3)[OF WN_Fixpoint(3,4)]
    have insert_post_simp: "insert x (post post_state) - ({x} - cn post_state) = post post_state"
      using Iterate.prems(5) WN_Fixpoint(1) by blast


    note well_inv1 = well_formed_infl_stabl_ind(3)[OF WN_Fixpoint(3,4) pinv]
    have parCorr: "traverse_rhs (T x) (σ state1) = xd1"
      using well_inv1 eq_subsumed_ind(3)[OF WN_Fixpoint(3,4) _ pinv] part_post
      by simp+
    then have "traverse_rhs (T x) (σ state1) ≤ mlup (σ state') x"
      using WN_Fixpoint(5,6) warrowing_properties(1) by metis
    moreover have "∀y∈dep T (σ state1) x. x ∈ slookup (pinfl post_state') y"
      using well_inv1 IH unfolding narrowing_inv_def update_rel_nar_def dep_def by force

    ultimately show ?thesis
      apply (intro exI[of _ "post_state'⦇cn := cn post_state' - {x}⦈"])
      using IH
      unfolding narrowing_inv_def update_rel_nar_def
      by (auto simp add: WN_Fixpoint(7) c_same insert_post_simp)
  next
    case (Continue xd1 state1 d_new infl2 stabl2)
    obtain post_state1 where
      IH1: "narrowing_inv state1 post_state1"
        "update_rel_nar x (state⦇stabl := insert x (stabl state)⦈) state1
          (post_state⦇post := insert x (post post_state)⦈) post_state1"
      using Iterate(2)[OF Continue(1) refl Continue(3) pinv nar_inv, of "[]"] Iterate.prems(4)
      by auto

    have "eq_subsumed (σ state) (insert x (stabl state) - (called state))"
      using Iterate.prems(3,4) unfolding narrowing_inv_def by auto
    then have parCorr: "well_formed_infl_stabl state1"
          "update_rel x (state⦇stabl := insert x (stabl state)⦈) state1"
          "eq T x (σ state1) = xd1"
          "(∀y∈dep_aux (σ state1) (T x). x ∈ slookup (infl state1) y)"
          "x ∈ stabl state1"
      using well_formed_infl_stabl_ind(3)[OF Continue(2,3) pinv]
        eq_subsumed_ind(3)[OF Continue(2,3) _ pinv] by force+

    have xcalled1: "x ∈ called state1" and c_same: "called state1 = called state"
      using Iterate.prems(4) c_same(3)[OF Continue(2,3)] by simp+

    have stabl_incr: "stabl state ⊆ stabl2"
    proof -
      have "(slookup (infl state1) ξ - slookup (infl state) ξ) ∩ (stabl state) = {}" for ξ
        using Iterate.prems(3) Continue(1) parCorr by auto
      then show ?thesis
        using Iterate.prems(2) Continue(1) destab_infl_stabl_relation[OF Continue(6)]
          TD.new_lookup_to_infl_not_stabl[of state1 state x] parCorr
        unfolding well_formed_infl_stabl_def by auto
    qed

    have pinv2: "well_formed_infl_stabl (state1⦇infl := infl2, stabl := stabl2,
      σ := (σ state1)(x ↦ d_new), called := called state1 - {x}⦈)"
    proof -
      have "eq T x (σ state1) ≤ d_new" using Continue(4) parCorr warrowing_properties(1) by auto
      then show ?thesis
        using parCorr Iterate.prems(2,5) stabl_incr c_same
        apply (intro destab_upd_preserves_well_formed_infl_stabl[OF _ Continue(6), of state])
        unfolding well_formed_infl_stabl_def eq_def dep_def
        apply simp_all
        by fastforce
    qed

    have x_in_cn_iff_in_post: "(x ∈ cn post_state) = (x ∈ post post_state)"
      using Iterate.prems(5) Continue(1) by blast

    define x_truly_post where "x_truly_post ≡ x ∈ cn post_state ∨
                                              x ∈ point state ∧ xd1 ≤ mlup (σ state1) x"
    define cnx where "cnx ≡ (if x_truly_post then insert x (cn post_state1) else cn post_state1)"

    obtain post_state2 where destab_post: "post_state2 =
        destab_post x x_truly_post (post_state1⦇cn := cnx⦈) stabl2"
      by (auto split: prod.split)

    have post_incr: "post post_state ⊆ post post_state2"
      apply (intro post_dom_incr[OF Iterate.prems(2) parCorr(1) Iterate.prems(3) IH1(1,2)
             destab_post])
      using x_truly_post_def x_in_cn_iff_in_post by auto

    have cn_post: "(x ∉ cn post_state2 ⟶ x ∈ post post_state2 ⟶ x ∈ stabl2)
          ∧ (x ∈ cn post_state2 ⟶ x ∈ post post_state2)"
      apply (intro c_post_after_destab[OF Continue(6) destab_post post_incr Iterate.prems(3)
            parCorr(1) IH1(1) parCorr(5)])
      subgoal
        using x_in_cn_iff_in_post IH1(2) unfolding cnx_def x_truly_post_def update_rel_nar_def
        by simp
      subgoal unfolding cnx_def by simp
      done

    have nar_inv2: "narrowing_inv (state1⦇infl := infl2, stabl := stabl2,
        σ := (σ state1)(x ↦ d_new), called := called state1 - {x}⦈)
      (post_state2⦇cn := cn post_state2 - {x}⦈)"
    proof (cases x_truly_post)
      case True
      have "x ∈ post post_state1 - (called state1 - cn post_state1)"
        if "x ∈ cn post_state"
        using IH1(2) that c_same unfolding update_rel_nar_def by simp
      then have "xd1 ≤ mlup (σ state1) x"
        using IH1(1) True parCorr(3) unfolding narrowing_inv_def x_truly_post_def by auto
      have "eq T x (σ state1) ≤ d_new"
        using Continue(4) True parCorr warrowing_properties(1) by auto
      moreover have "d_new ≤ mlup (σ state1) x"
        using Continue(4) ‹xd1 ≤ mlup (σ state1) x› narrowing_le unfolding warrowing_def by auto
      moreover have "post_state2 = post_state1⦇cn := cnx⦈"
        using destab_post True unfolding destab_post_def by simp
      ultimately show ?thesis
        by (auto intro: nar_inv_after_update_if_post[OF assms(1,2) IH1(1)
              parCorr(1,4)[folded dep_def] _ _ Continue(6)] simp add: cnx_def True)
    next
      case False
      then have "cnx = cn post_state1" using cnx_def by auto
      have "eq T x (σ state1) ≤ d_new"
        using Continue(4) False parCorr warrowing_properties(1) by auto
      moreover have "x ∉ cn post_state" "x ∉ post post_state"
        using False x_in_cn_iff_in_post unfolding x_truly_post_def by auto
      ultimately show ?thesis
        using nar_inv_after_destab_update_if_not_post[OF _ _ Iterate.prems(2,3) parCorr(1)
            IH1(1) parCorr(2) IH1(2) destab_post[simplified ‹cnx = cn post_state1›] Continue(6) _
            parCorr(4)[folded dep_def] pinv2 c_same _ False] IH1(2)
        unfolding update_rel_nar_def
        by auto
    qed

    obtain post_state' where IH2:
        "narrowing_inv (state'⦇called := called state' - {x}⦈) post_state'"
        "update_rel_nar x (state1⦇infl := infl2, stabl := stabl2, σ := (σ state1)(x ↦ d_new),
          called := called state1 - {x}⦈) (state'⦇called := called state' - {x}⦈)
          (post_state2⦇cn := insert x (cn post_state2)⦈)
          (post_state'⦇cn := insert x (cn post_state')⦈)"
      using Iterate.IH(3)[OF Continue(1) refl Continue(3) _ Continue(4-6) _ Continue(8),
          simplified, OF pinv2 nar_inv2 xcalled1 cn_post]
      by blast

    then show ?thesis
    proof (intro exI[of _ post_state'] conjI, goal_cases)
      case 1
      then show ?case by simp
    next
      case 2
      then show ?case
        unfolding update_rel_nar_def
      proof (intro conjI, goal_cases)
        case 1
        then show ?case using post_incr by (auto split: if_splits)
      next
        case 2
        then have "∀u∈post post_state. mlup (σ state') u ≤ mlup ((σ state1)(x ↦ d_new)) u"
          using post_incr by (auto split: if_splits)
        moreover have "∀u∈post post_state. mlup (σ state1) u ≤ mlup (σ state) u"
          using IH1 unfolding update_rel_nar_def by auto
        moreover have "mlup ((σ state1)(x ↦ d_new)) u ≤ mlup (σ state1) u"
          if "u ∈ post post_state" for u
        proof (cases "u = x")
          case True
          then have "x ∉ called state1 - cn post_state1"
            using Continue(1) Iterate.prems(5) that c_same IH1(2)
            unfolding update_rel_nar_def by auto
          then have "x ∈ post post_state1 - (called state1 - cn post_state1)"
            using that IH1 unfolding update_rel_nar_def by auto
          then have "xd1 ≤ mlup (σ state1) x" using IH1 parCorr unfolding narrowing_inv_def by auto
          then have "d_new ≤ mlup (σ state1) x"
            using Continue(4) narrowing_le unfolding warrowing_def by auto
          then show ?thesis using True by (auto simp add: fun_upd_same mlup_def)
        next
          case False
          then show ?thesis by (auto simp add: fun_upd_other mlup_def)
        qed
        ultimately show ?case by fastforce
      next
        case 3
        show ?case
        proof(intro allI subsetI, goal_cases)
          case (1 ξ u)
          then have "ξ ∈ post post_state"
            using TD.stabl_infl_empty[of _ _ "pinfl post_state"] Iterate.prems(3)
            unfolding narrowing_inv_def
            by auto
          then show ?case
          proof (cases x_truly_post)
            case True
            then have "post_state2 = post_state1⦇cn := cnx⦈"
              using destab_post unfolding destab_post_def by auto
            moreover have "slookup (pinfl post_state) ξ ⊆ slookup (pinfl post_state1) ξ"
              "ξ ∈ post post_state1"
              using ‹ξ ∈ post post_state› IH1 unfolding update_rel_nar_def by auto
            moreover have "slookup (pinfl post_state2) ξ ⊆ slookup (pinfl post_state') ξ"
              using ‹ξ ∈ post post_state1› ‹post_state2 = post_state1⦇cn := cnx⦈› 3
              unfolding update_rel_nar_def by auto
            ultimately show ?thesis using 1(1) by auto
          next
            case False
            then have "x ∉ cn post_state" unfolding x_truly_post_def by simp
            then have "x ∉ post post_state" using x_in_cn_iff_in_post by simp
            have "u ∈ slookup (pinfl post_state1) ξ"
              using IH1 1 unfolding update_rel_nar_def by auto
            have destab_post: "post_state2 = destab_barrier x (post_state1⦇cn := cnx⦈) stabl2"
              using destab_post False unfolding destab_post_def by auto
            have "ξ ≠ x" using ‹ξ ∈ post post_state› ‹x ∉ post post_state› by blast
            have "ξ ∈ post post_state2" using ‹ξ ∈ post post_state› post_incr by blast
            then have "ξ ∉ insert x (influenced_by_excl_cutoff (pinfl post_state1) x stabl2)"
              using destab_post ‹ξ ∈ post post_state› ‹ξ ≠ x›
              unfolding destab_barrier_def by auto
            then have "slookup (pinfl post_state1) ξ = slookup (pinfl post_state2) ξ"
              using destab_post unfolding destab_barrier_def
              by (auto simp add: fmlookup_default_drop_set simp del: fmdrop_set_insert)
            then have "u ∈ slookup (pinfl post_state2) ξ"
              using ‹u ∈ slookup (pinfl post_state1) ξ› by auto
            then show ?thesis using 1(1) 3 by auto
          qed
        qed
      next
        case 4
        have "∀u. slookup (pinfl post_state2) u ⊆ slookup (pinfl post_state1) u"
        proof (cases x_truly_post)
          case True
          then show ?thesis using destab_post unfolding destab_post_def by auto
        next
          case False
          have "pinfl post_state2 = fmdrop_set (insert x
              (influenced_by_excl_cutoff (pinfl post_state1) x stabl2)) (pinfl post_state1)"
            using destab_post False unfolding destab_post_def destab_barrier_def by auto
          then show ?thesis
            by (metis Orderings.order_eq_iff empty_set empty_subsetI fmlookup_default_drop_set)
        qed
        moreover have "∀u. (slookup (pinfl post_state1) u - slookup (pinfl post_state) u)
          ∩ (post post_state) = {}"
        proof -
          have "∀u. (slookup (pinfl post_state1) u - slookup (pinfl post_state) u)
              ∩ (insert x (post post_state) - ({x} - (cn post_state))) = {}"
            using IH1 Continue(1) unfolding update_rel_nar_def by auto
          then show ?thesis using Iterate.prems(5) Continue(1) by blast
        qed
        moreover have "∀u. (slookup (pinfl post_state') u - slookup (pinfl post_state2) u)
            ∩ (post post_state2) = {}"
          using 4 cnx_def unfolding update_rel_nar_def by auto
        moreover have "post post_state ⊆ post post_state2" using post_incr by auto
        ultimately show ?case by fastforce
      next
        case 5
        then show ?case
          using destab_post_c_unchanged[OF destab_post] cnx_def IH1(2)
          unfolding update_rel_nar_def by simp
      qed
    qed
  qed
next
  case (Eval x t state)
  show ?case using Eval.IH(1)Eval.prems(1)
  proof (cases rule: eval_query_answer_cases)
    case (Query y g yd state1)
    have y_dep: "y ∈ dep T (σ state) x"
      using Eval.prems(5) Query(1) subt_for_prefix_implies_subt subt_implies_dep
      unfolding dep_def by fast
    then obtain post_state1 where IH1: "narrowing_inv state1 post_state1"
        "update_rel_nar x state state1 post_state post_state1"
      using Eval(2)[OF Query(1,3) Eval.prems(2-3)] by blast
    have parCorr: "well_formed_infl_stabl state1"
        "∀ξ∈stabl state. mlup (σ state) ξ = mlup (σ state1) ξ"
        "x ∈ slookup (infl state1) y"
        "stabl state ⊆ stabl state1"
        "∀u∈stabl state. slookup (infl state) u ⊆ slookup (infl state1) u"
        "∀u. (slookup (infl state1) u - slookup (infl state) u) ∩ (stabl state - {x}) = {}"
      using well_formed_infl_stabl_ind(1)[OF Query(2,3)] Eval.prems(2,6) by auto

    have "subt_for_prefix (T x) (pre @ [y]) (σ state1) = Some (g yd)"
    proof -
      have "∀u∈set pre. mlup (σ state) u = mlup (σ state1) u" using parCorr Eval.prems(6) by auto
      then have "subt_for_prefix (T x) pre (σ state1) = Some t"
        using Eval.prems(5) subt_for_prefix_same by metis
      moreover have "subt_for_prefix t [y] (σ state1) = Some (g yd)"
        using Query(1) query_fmlookup[OF Query(2,3)] by auto
      ultimately show ?thesis using subt_for_prefix_transitive by blast
    qed
    moreover have "set (pre @ [y]) ⊆ stabl state1"
    proof -
      have "y ∈ stabl state1"
        using parCorr TD.stabl_infl_empty[of y "stabl state1" "infl state1"]
        unfolding well_formed_infl_stabl_def
        by fastforce
      then show ?thesis using Eval.prems(6) parCorr by auto
    qed
    ultimately obtain post_state' where
       IH2: "narrowing_inv state' post_state'"
            "update_rel_nar x state1 state' post_state1 post_state'"
      using Eval(3)[OF Query(1,3) refl Query(5) parCorr(1) IH1(1)] Eval.prems(4)
        c_same(1)[OF Query(2,3)]
      by blast
    then have "update_rel_nar x state state' post_state post_state'"
      using IH1 unfolding update_rel_nar_def
    proof (intro conjI, goal_cases)
      case 1
      then show ?case by (simp add: subset_iff)
    next
      case 2
      then show ?case by (meson order_trans subsetD)
    next
      case 3
      then show ?case by (meson dual_order.trans subsetD)
    next
      case 4
      then show ?case
      proof (cases "x ∉ cn post_state")
        case True
        then have A: "∀u. (slookup (pinfl post_state1) u - slookup (pinfl post_state) u)
            ∩ (post post_state - {x}) = {}" and
          B: "∀u. (slookup (pinfl post_state') u - slookup (pinfl post_state1) u)
            ∩ (post post_state1 - {x}) = {}" using 4(2,4) by blast+
        show ?thesis using TD.infl_diff_eval_step[OF _ B A] 4(4) True by auto
      next
        case False
        then have A: "∀u. (slookup (pinfl post_state1) u - slookup (pinfl post_state) u)
              ∩ (post post_state) = {}" and
          B: "∀u. (slookup (pinfl post_state') u - slookup (pinfl post_state1) u)
              ∩ (post post_state1) = {}"
          using 4(2,4) by auto
        then show ?thesis
        proof(intro allI, goal_cases)
          case (1 ξ)
          then have "((slookup (pinfl post_state') ξ - slookup (pinfl post_state1) ξ)
              ∪ (slookup (pinfl post_state1) ξ - slookup (pinfl post_state) ξ))
              ∩ (post post_state) = {}"
            using 4(4) False by blast
          then show ?case by blast
        qed
      qed
    next
      case 5
      then show ?case by simp
    qed
    then show ?thesis using IH2(1) by auto
  next
    case Answer
    then show ?thesis using Eval.prems(3) unfolding update_rel_nar_def by fastforce
  qed
qed



subsubsection ‹Equivalence with Phase Solver for Monotonicity›

text‹For equation systems with monotonic right-hand sides and monotonic dependencies, the warrowing
  solver is equivalent to the TD with widening and narrowing phases when used with a precise
  widening operator. We prove this by relying heavily on the invariants that have been shown to
  hold for the ghost variables @{term cn}, @{term post} and @{term pinfl} in the previous
  subsection. Termination of TD\_warrow and the partial correctness of TD\_wn\_phases then follow
  immediately.›

interpretation TD_wn_phases: TD_wn_phases.TD_wn_phases T "(∇)" "(Δ)"
  done

lemma phase_widen_narrow_incr:
  assumes "d_new = (if x ∉ point state then xd1 else
                    if wn = Widening then mlup (σ state1) x ∇ xd1 else mlup (σ state1) x Δ xd1)"
      and "wn = Narrowing ⟶ x ∈ cn post_state1"
      and "well_formed_infl_stabl state1"
      and "narrowing_inv state1 post_state1"
      and "x ∈ post post_state1"
      and "eq T x (σ state1) = xd1"
    shows "eq T x (σ state1) ≤ d_new"
proof (cases "x ∈ point state")
  case True
  show ?thesis
  proof (cases wn)
    case Widening
    have "d_new = mlup (σ state1) x ∇ xd1" using assms(1) Widening True by simp
    then have "xd1 ≤ d_new" using widening_ge_2 by auto
    then show ?thesis using assms(6) by simp
  next
    case Narrowing
    then have "x ∈ cn post_state1" using assms(2) by fastforce
    then have "x ∈ post post_state1 - (called state1 - cn post_state1)" using assms(3,5) by auto
    then have "xd1 ≤ mlup (σ state1) x" using assms(4,6) unfolding narrowing_inv_def by auto
    then show ?thesis using assms(1,6) True Narrowing narrowing_ge[of xd1 "mlup (σ state1) x"] by auto
  qed
next
  case False
  then show ?thesis using assms(1,4,6) unfolding eq_def by auto
qed

lemma equiv_wn_solver_ind_1:
  assumes "is_mono_eq T"
    and "mono_deps T"
  shows "TD_wn_phases.query_dom y x state
        ⟹ (xd, state') = TD_wn_phases.query y x state
        ⟹ well_formed_infl_stabl state
        ⟹ narrowing_inv state post_state
        ⟹ x ∈ dep T (σ state)y
        ⟹ query_dom y x state
            ∧ (xd, state') = query y x state"
    and "TD_wn_phases.iterate_dom x wn state
        ⟹ (xd, state') = TD_wn_phases.iterate x wn state
        ⟹ well_formed_infl_stabl (state⦇called := called state - {x}⦈)
        ⟹ narrowing_inv (state⦇called := called state - {x}⦈) (post_state⦇cn := cn post_state - {x}⦈)
        ⟹ x ∈ called state
        ⟹ (x ∉ cn post_state ⟶ x ∉ post post_state - stabl state)
            ∧ (x ∈ cn post_state ⟶ x ∈ post post_state)
        ⟹ (wn = Narrowing) ⟶ (x ∈ cn post_state)
        ⟹ iterate_dom x state
            ∧ (xd, state') = iterate x state"
    and "TD_wn_phases.eval_dom x t state
        ⟹ (xd, state') = TD_wn_phases.eval x t state
        ⟹ well_formed_infl_stabl state
        ⟹ narrowing_inv state post_state
        ⟹ x ∈ called state
        ⟹ subt_for_prefix (T x) pre (σ state) = Some t
        ⟹ set pre ⊆ stabl state
        ⟹ eval_dom x t state
            ∧ (xd, state') = eval x t state"
proof(induction y x state and x wn state and x t state
      arbitrary: post_state xd state' and post_state xd state' and post_state xd state' pre
      rule: TD_wn_phases.query_iterate_eval_pinduct)
  case (Query y x state)
  show ?case using Query.IH(1) Query.prems(1)
  proof(cases rule: TD_wn_phases.query_iterate_lookup_cases)
    case (Iterate state1)
    obtain c1n where
      c1_def: "c1n = (if x ∈ post post_state then insert x (cn post_state) else cn post_state)"
      by fastforce
    have "(x ∉ c1n ⟶ x ∉ post post_state - stabl state)
        ∧ (x ∈ c1n ⟶ x ∈ post post_state)"
      using c1_def Query.prems(3) Iterate(1) unfolding narrowing_inv_def by auto
    moreover have "well_formed_infl_stabl (state⦇called := insert x (called state) - {x}⦈)"
      using Iterate(1) Query.prems(2) by auto
    moreover have
        "narrowing_inv (state⦇called := insert x (called state) - {x}⦈) (post_state⦇cn := c1n - {x}⦈)"
      using Iterate(1) Query.prems(3) c1_def unfolding narrowing_inv_def by auto
    ultimately have IH: "iterate_dom x (state ⦇called := insert x (called state)⦈)"
      "(xd, state1) = iterate x (state ⦇called := insert x (called state)⦈)"
      using Query.IH(2)[OF Iterate(1,3), of "post_state⦇cn := c1n⦈"] by auto
    then have "query_dom y x state"
      using query_iterate_eval.domintros(1)[of x state] Query.prems(4) Iterate(1,4)
      by (auto split: if_splits)
    then show ?thesis
      using query.psimps[folded dom_defs] Iterate(1,4) IH(2) Query.prems(4)
      by (auto split: prod.splits if_splits)
  next
    case Lookup
    then show ?thesis using query_iterate_eval.domintros(1)[of x state] Query.prems(4) by auto
  qed
next
  case (Iterate x wn state)
  have xcalled: "x ∈ called state" using Iterate.prems(4,5) by auto
  have winv: "well_formed_infl_stabl (state⦇stabl := insert x (stabl state)⦈)"
    using Iterate.prems(2,4,5) unfolding well_formed_infl_stabl_def by auto
  have pinv: "eq_subsumed (σ (state⦇stabl := insert x (stabl state)⦈))
      (stabl (state⦇stabl := insert x (stabl state)⦈) - called (state⦇stabl := insert x (stabl state)⦈))"
    using Iterate.prems(3,4) unfolding narrowing_inv_def by auto
  have nar_inv: "narrowing_inv (state⦇stabl := insert x (stabl state)⦈)
      (post_state⦇post := insert x (post post_state)⦈)"
    using narrow_inv_add_x_stabl_and_post[OF Iterate.prems(4,5,3)] by auto
  show ?case using Iterate.IH(1) Iterate.prems(1)
  proof(cases rule: TD_wn_phases.iterate_continue_fixpoint_cases)
    case Stable
    then show ?thesis using query_iterate_eval.domintros(2)[of x state, folded dom_defs] by auto
  next
    case (Fixpoint state1)
    have IH1: "eval_dom x (T x) (state ⦇stabl := insert x (stabl state)⦈)"
      "(xd, state1) = eval x (T x) (state ⦇stabl := insert x (stabl state)⦈)"
      using Iterate.IH(2)[OF Fixpoint(1) refl Fixpoint(4) winv nar_inv, where ?pre1 = "[]"]
        Iterate.prems(4)
      by auto
    have "iterate_dom x state"
      using query_iterate_eval.domintros(2)[of x state, folded dom_defs] Fixpoint(2,5,6) IH1
        query_iterate_eval.domintros(2)[of x state]
      by (cases "eval x (T x) (state ⦇stabl := insert x (stabl state)⦈)") auto
    then show ?thesis
      using IH1 Fixpoint(1,2,5,6)
      by (cases "eval x (T x) (state ⦇stabl := insert x (stabl state)⦈)") simp
  next
    case (W_Fixpoint xd1 state1 infl2 stabl2)
    have IH1: "eval_dom x (T x) (state ⦇stabl := insert x (stabl state)⦈)"
      "(xd1, state1) = eval x (T x) (state ⦇stabl := insert x (stabl state)⦈)"
      using Iterate.IH(2)[OF W_Fixpoint(1) refl W_Fixpoint(5) winv nar_inv, where ?pre1 = "[]"]
        Iterate.prems(4)
      by auto

    note part_correct = eq_subsumed_ind(3)[OF IH1 _ winv pinv, simplified]
    note wellformed_stabl = well_formed_infl_stabl_ind(3)[OF IH1 winv, simplified]
    note c_same = c_same(3)[OF IH1]
    obtain post_state1 where narInv: "narrowing_inv state1 post_state1"
      "update_rel_nar x (state ⦇stabl := insert x (stabl state)⦈) state1
        (post_state ⦇post := insert x (post post_state)⦈) post_state1"
      using narrowing_inv_ind(3)[OF assms(1,2) IH1 winv nar_inv, of "[]"] Iterate.prems(4-5)
      by auto

    have stabl_incr: "stabl state ⊆ stabl2"
    proof -
      have "(slookup (infl state1) ξ - slookup (infl state) ξ) ∩ (stabl state) = {}" for ξ
        using Iterate.prems(3) W_Fixpoint(1) wellformed_stabl
        by auto
      then show ?thesis
        using Iterate.prems(2) W_Fixpoint(1) TD.new_lookup_to_infl_not_stabl[of state1 state x]
          destab_infl_stabl_relation[OF W_Fixpoint(8)] wellformed_stabl
        unfolding well_formed_infl_stabl_def by auto
    qed

    let ?state2 = "state1⦇infl := infl2, stabl := stabl2,
       σ := (σ state1)(x ↦ mlup (σ state1) x Δ xd1)⦈"
    let ?post_state2 = "post_state1⦇cn := insert x (cn post_state1)⦈"

    have xd1_smaller: "xd1 ≤ mlup (σ state1) x"
      using wellformed_stabl W_Fixpoint(6) widening_ge_2 by metis
    have sigma_narrow_smaller: "(σ state1)(x ↦ mlup (σ state1) x Δ xd1) ⊑m σ state1"
    proof -
      have "mlup (σ state1) x Δ xd1 ≤ mlup (σ state1) x" using narrowing_le xd1_smaller by simp
      then show ?thesis unfolding mlup_def by (simp add: fun_upd_apply)
    qed
    have "x ∈ post post_state1" using narInv unfolding update_rel_nar_def by simp
    have A: "(x ∉ insert x (cn post_state1) ⟶ x ∈ post post_state1 ⟶ x ∈ stabl2)
        ∧ (x ∈ insert x (cn post_state1) ⟶ x ∈ post post_state1)"
      using ‹x ∈ post post_state1› by simp
    have w_inv2: "well_formed_infl_stabl (?state2⦇called := called state1 - {x}⦈)"
    proof -
      have "∀x∈stabl state1 - (called state1 - {x}). ∀y∈dep T (σ state1) x. x ∈ slookup (infl state1) y"
        using wellformed_stabl unfolding well_formed_infl_stabl_def dep_def by auto
      moreover have "eq T x (σ state1) ≤ mlup (σ state1) x Δ xd1"
        by (metis eq_def narrowing_ge xd1_smaller part_correct)
      ultimately show ?thesis
        apply (intro destab_upd_preserves_well_formed_infl_stabl[OF _ W_Fixpoint(8) _ _ stabl_incr])
        using wellformed_stabl Iterate.prems(2) c_same
        unfolding well_formed_infl_stabl_def eq_def by auto
    qed
    have nar_inv2:
      "narrowing_inv (?state2⦇called := called state1 - {x}⦈) (post_state1⦇cn := cn post_state1 - {x}⦈)"
    proof -
      have "eq T x (σ state1) ≤ mlup (σ state1) x Δ xd1"
        by (metis eq_def narrowing_ge part_correct xd1_smaller)
      moreover have "mlup (σ state1) x Δ xd1 ≤ mlup (σ state1) x"
        using xd1_smaller by (simp add: narrowing_le)
      moreover have "narrowing_inv state1 post_state1"
        using narrow_inv_add_x_stabl_and_post ‹x ∈ post post_state1› narInv(1)
        unfolding narrowing_inv_def by blast
      ultimately show ?thesis
        apply (intro nar_inv_after_update_if_post[OF assms(1,2)])
        using W_Fixpoint(8) wellformed_stabl Iterate.prems(5) unfolding destab_post_def dep_def
        by simp_all
    qed

    have IH2: "iterate_dom x ?state2" "(xd, state') = iterate x ?state2"
      using Iterate.IH(3)[OF W_Fixpoint(1) refl W_Fixpoint(5) _ _ W_Fixpoint(6) _ refl
          W_Fixpoint(7,8) _ W_Fixpoint(10), of "post_state1⦇cn := insert x (cn post_state1)⦈",
          simplified, OF _ w_inv2 nar_inv2] W_Fixpoint(2-3)
          ‹x ∈ post post_state1› Iterate.prems(4) c_same
      unfolding iterate_dom_def by auto

    have war_is_nar: "mlup (σ state1) x ∇Δ xd1 = mlup (σ state1) x Δ xd1"
      using xd1_smaller unfolding warrowing_def by auto
    then have "iterate_dom x state"
      using W_Fixpoint(1-3,7,8) IH1 IH2(1) query_iterate_eval.domintros(2)[of x state]
      by (cases "eval x (T x) (state ⦇stabl := insert x (stabl state)⦈)",
          cases "destab x (infl state1) (stabl state1)", cases wn) auto
    then show ?thesis using iterate.psimps W_Fixpoint(1,2,3,7,8) IH1(2) IH2(2) war_is_nar
      by (cases "eval x (T x) (state ⦇stabl := insert x (stabl state)⦈)",
          cases "destab x (infl state1) (stabl state1)") simp
  next
    case (N_Fixpoint xd1 state1)
    have IH1: "eval_dom x (T x) (state ⦇stabl := insert x (stabl state)⦈)"
      "(xd1, state1) = eval x (T x) (state ⦇stabl := insert x (stabl state)⦈)"
      using Iterate.IH(2)[OF N_Fixpoint(1) refl N_Fixpoint(5) winv nar_inv, where ?pre1 = "[]"]
        Iterate.prems(4)
      by auto

    note part_correct = eq_subsumed_ind(3)[OF IH1 _ winv pinv, simplified]
    note wellformed_stabl = well_formed_infl_stabl_ind(3)[OF IH1 winv, simplified]
    obtain post_state1 where narInv: "narrowing_inv state1 post_state1"
      "update_rel_nar x (state⦇stabl := insert x (stabl state)⦈) state1
        (post_state⦇post := insert x (post post_state)⦈) post_state1"
      using narrowing_inv_ind(3)[OF assms(1,2) IH1 winv nar_inv, of "[]"] Iterate.prems(4)
      by auto
    note c_same = c_same(3)[OF IH1]

    have "xd1 ≤ mlup (σ state') x"
    proof (cases wn)
      case Widening
      then show ?thesis using N_Fixpoint(3) widening_ge_2[of xd1 "mlup (σ state') x"] by auto
    next
      case Narrowing
      then have "x ∈ post post_state1 - (called state1 - cn post_state1)"
        using Iterate.prems(5,6) narInv(2) c_same unfolding update_rel_nar_def by auto
      then have "eq T x (σ state1) ≤ mlup (σ state1) x"
        using narInv(1)  unfolding narrowing_inv_def by simp
      then show ?thesis
        using conjunct2[OF part_correct, symmetric] N_Fixpoint(8) by simp
    qed
    then have war_fix: "mlup (σ state') x = mlup (σ state') x ∇Δ xd1"
      using N_Fixpoint(6,7) unfolding warrowing_def by metis
    have "iterate_dom x state"
      using query_iterate_eval.domintros(2)[of x state] IH1 N_Fixpoint(2,8) war_fix
      by (cases "eval x (T x) (state ⦇stabl := insert x (stabl state)⦈)") simp
    then show ?thesis
      using iterate.psimps[of x state] IH1 N_Fixpoint(1-3,6-8) war_fix
      by (cases "eval x (T x) (state ⦇stabl := insert x (stabl state)⦈)") simp
  next
    case (Continue xd1 state1 d_new infl2 stabl2)
    have IH1: "eval_dom x (T x) (state ⦇stabl := insert x (stabl state)⦈)"
      "(xd1, state1) = eval x (T x) (state ⦇stabl := insert x (stabl state)⦈)"
      using Iterate.IH(2)[OF Continue(1) refl Continue(3) winv nar_inv, where ?pre1 = "[]"]
        Iterate.prems(4-6)
      by auto

    note c_same = c_same(3)[OF IH1]
    note part_correct = eq_subsumed_ind(3)[OF IH1 _ winv pinv, simplified]
    note wellformed_stabl = well_formed_infl_stabl_ind(3)[OF IH1 winv, simplified]
    obtain post_state1 where narInv: "narrowing_inv state1 post_state1"
      "update_rel_nar x (state ⦇stabl := insert x (stabl state)⦈) state1
        (post_state ⦇post := insert x (post post_state)⦈) post_state1"
      using narrowing_inv_ind(3)[OF assms(1,2) IH1 winv nar_inv, of "[]"] Iterate.prems(4-6)
      by auto

    have stabl_incr: "stabl state ⊆ stabl2"
    proof -
      have "(slookup (infl state1) ξ - slookup (infl state) ξ) ∩ (stabl state) = {}" for ξ
        using Iterate.prems(3) Continue(1) wellformed_stabl
        by auto
      then show ?thesis
        using Iterate.prems(2) Continue(1) TD.new_lookup_to_infl_not_stabl[of state1 _ x]
          destab_infl_stabl_relation[OF Continue(6)] wellformed_stabl
        unfolding well_formed_infl_stabl_def by auto
    qed

    let ?state2 = "state1⦇infl := infl2, stabl := stabl2, σ := (σ state1)(x ↦ d_new)⦈"

    let ?x_truly_post = "x ∈ cn post_state"
    have x_cn_iff_post: "(x ∈ cn post_state) = (x ∈ post post_state)"
      using Iterate.prems(5) Continue(1) by auto
    obtain post_state2 where destab_post:
        "post_state2 = destab_post x ?x_truly_post post_state1 stabl2"
      by (cases "destab_post x ?x_truly_post post_state1 stabl2") fastforce

    have post_incr: "post post_state ⊆ post post_state2"
      apply (intro post_dom_incr[OF Iterate.prems(2) conjunct1[OF wellformed_stabl]
            Iterate.prems(3) narInv(1,2), of _ ?x_truly_post "cn post_state1"])
      using destab_post x_cn_iff_post
      by simp+

    have winv2: "well_formed_infl_stabl (?state2⦇called := called state1 - {x}⦈)"
    proof -
      have "x ∈ post post_state1"
        using wellformed_stabl narInv(1) unfolding narrowing_inv_def by blast
      then have "eq T x (σ state1) ≤ d_new"
        apply (intro phase_widen_narrow_incr[OF Continue(4) _ conjunct1[OF wellformed_stabl]
              narInv(1)])
        using Iterate.prems(6) narInv(2) conjunct2[OF part_correct, folded eq_def]
        unfolding update_rel_nar_def
        by simp_all
      then show ?thesis
        apply (intro destab_upd_preserves_well_formed_infl_stabl[OF _ Continue(6) _ _ stabl_incr])
        using Iterate.prems(2) wellformed_stabl c_same
        unfolding well_formed_infl_stabl_def dep_def
        by auto
    qed
    have nar_inv2:
      "narrowing_inv (?state2⦇called := called state1 - {x}⦈) (post_state2⦇cn := cn post_state2 - {x}⦈)"
    proof (cases ?x_truly_post)
      case True
      then have "xd1 ≤ mlup (σ state1) x"
        using IH1 part_correct narInv unfolding narrowing_inv_def update_rel_nar_def by auto
      then have "eq T x (σ state1) ≤ d_new"
        using Continue(4) True widening_precise narrowing_ge part_correct
        unfolding eq_def by (cases wn) auto
      moreover have "d_new ≤ mlup (σ state1) x"
        using ‹xd1 ≤ mlup (σ state1) x› Continue(4) widening_precise narrowing_le by auto
      ultimately show ?thesis
        using nar_inv_after_update_if_post[OF assms(1,2)] Continue(6) wellformed_stabl True
          destab_post narInv(1)
        unfolding dep_def destab_post_def by auto
    next
      case False
      then have "x ∉ post post_state" using x_cn_iff_post by simp
      have "x ∈ post post_state1"
        using wellformed_stabl narInv(1) unfolding narrowing_inv_def by blast
      then have "eq T x (σ state1) ≤ d_new"
        apply (intro phase_widen_narrow_incr[OF Continue(4) _ conjunct1[OF wellformed_stabl]
              narInv(1)])
        using narInv(2) Iterate.prems(6) part_correct
        unfolding update_rel_nar_def eq_def by auto
      moreover have "x ∉ post post_state" using False x_cn_iff_post by fastforce
      ultimately show ?thesis
        apply (intro nar_inv_after_destab_update_if_not_post[OF _ False Iterate.prems(2,3)
              conjunct1[OF wellformed_stabl] narInv(1) _ narInv(2) _ Continue(6) _ _ winv2 _ _
              False])
        using destab_post wellformed_stabl Continue(6)
        unfolding dep_def
        apply simp_all
        using c_same narInv(2)
        unfolding update_rel_nar_def
        by simp_all
    qed

    have "(x ∉ cn post_state2 ⟶ x ∈ post post_state2 ⟶ x ∈ stabl2)
      ∧ (x ∈ cn post_state2 ⟶ x ∈ post post_state2)"
    proof -
      have "x ∈ stabl state1" "x ∈ post post_state1" "cn post_state1 = cn post_state"
        using wellformed_stabl narInv IH1 xcalled
        unfolding well_formed_infl_stabl_def update_rel_nar_def by auto
      then show ?thesis
        apply (intro c_post_after_destab[OF Continue(6) _ post_incr Iterate.prems(3)
            conjunct1[OF wellformed_stabl] narInv(1), of "x ∈ cn post_state" "cn post_state1"])
        using destab_post x_cn_iff_post by fastforce+
    qed
    then have IH2: "iterate_dom x ?state2" "(xd, state') = iterate x ?state2"
      using Iterate.IH(4)[OF Continue(1) refl Continue(3) refl Continue(4,5,6) refl Continue(8),
          where ?post_state1=post_state2]
        winv2 nar_inv2 destab_post_c_unchanged[OF destab_post] narInv(2) c_same Iterate.prems(4,6)
      unfolding update_rel_nar_def
      by simp_all

    have d_new_war: "d_new = (if x ∉ (point state) then xd1 else mlup (σ state1) x ∇Δ xd1)"
      using Continue(4)
    proof (cases wn)
      case Widening
      then show ?thesis using Continue(4,5) warrowing_def widening_precise by force
    next
      case Narrowing
      then have "x ∈ cn post_state - (called state - cn post_state)" using Iterate.prems(4-6) by auto
      then have "x ∈ post post_state1 - (called state1 - cn post_state1)"
        using wellformed_stabl narInv(1,2) c_same
        unfolding narrowing_inv_def update_rel_nar_def by auto
      then have "xd1 ≤ mlup (σ state1) x"
        using part_correct narInv unfolding narrowing_inv_def by auto
      then show ?thesis using Continue(4) Narrowing unfolding warrowing_def by auto
    qed
    have "iterate_dom x state"
    proof (cases "x ∈ point state")
      case True
      show ?thesis
        using True Continue(1,5,6) IH1 IH2(1) query_iterate_eval.domintros(2)[of x state]
          d_new_war
        by (cases "eval x (T x) (state ⦇stabl := insert x (stabl state)⦈)", cases
          "destab x (infl state1) (stabl state1)") (auto split: if_splits simp del: eval.psimps)
    next
      case False
      then show ?thesis
        using Continue(1,4,5,6) IH1 IH2(1) query_iterate_eval.domintros(2)[of x state]
        by (cases "eval x (T x) (state ⦇stabl := insert x (stabl state)⦈)", cases
          "destab x (infl state1) (stabl state1)") (auto split: if_splits)
    qed
    then show ?thesis
      using iterate.psimps[folded dom_defs] Continue(1,5-6) IH1(2) IH2(2) d_new_war
      by (cases "eval x (T x) (state ⦇stabl := insert x (stabl state)⦈)", cases
          "destab x (infl state1) (stabl state1)") auto
  qed
next
  case (Eval x t state)
  show ?case using Eval.IH(1) Eval.prems(1)
  proof(cases rule: TD_wn_phases.eval_query_answer_cases)
    case (Query y g yd state1)
    have y_dep: "y ∈ dep T (σ state)x"
      using Eval.prems(5) Query(1) subt_for_prefix_implies_subt subt_implies_dep
      unfolding dep_def by fast
    then have IH1: "query_dom x y state"
      "(yd, state1) = query x y state"
      using Eval.IH(2)[OF Query(1,3)] Eval.prems(2-6) by auto

    note c_same = c_same(1)[OF IH1]
    note wellformed_stabl = well_formed_infl_stabl_ind(1)[OF IH1 Eval.prems(2)]
    obtain post_state1 where narInv: "narrowing_inv state1 post_state1
      ∧ update_rel_nar x state state1 post_state post_state1"
      using narrowing_inv_ind(1)[OF assms(1,2) IH1 Eval.prems(2,3) y_dep] by auto

    have "x ∈ stabl state1"
      using Eval.prems(4) wellformed_stabl c_same unfolding well_formed_infl_stabl_def by auto
    have "subt_for_prefix (T x) pre (σ state1) = Some t"
      apply (subst subt_for_prefix_same)
      using Eval.prems(5,6) wellformed_stabl
      by auto
    moreover have "subt_for_prefix t [y] (σ state1) = Some (g yd)"
      using wellformed_stabl query_fmlookup[OF IH1] Query(1) by simp
    ultimately have F1: "subt_for_prefix (T x) (pre @ [y]) (σ state1) = Some (g yd)"
      using subt_for_prefix_transitive by blast
    have "y ∈ stabl state1"
      using wellformed_stabl TD.stabl_infl_empty unfolding well_formed_infl_stabl_def
      by (metis empty_iff)
    then have F2: "set (pre @ [y]) ⊆ stabl state1"
      using ‹set pre ⊆ stabl state› wellformed_stabl by auto

    have IH2: "eval_dom x (g yd) state1"
      "(xd, state') = eval x (g yd) state1"
      using Eval.IH(3)[OF Query(1,3) _ Query(5)] Eval.prems(4) c_same wellformed_stabl narInv
        ‹x ∈ stabl state1› F1 F2
      by auto
    have "eval_dom x t state"
      apply (rule query_iterate_eval.domintros(3)[folded dom_defs])
      using Query(1) IH1 IH2(1)
      by (auto split: prod.splits)
    then show ?thesis
      using eval.psimps[folded dom_defs] Query(1) IH1(2) IH2(2) by (auto split: prod.splits)
  next
    case Answer
    then show ?thesis using query_iterate_eval.domintros(3)[of t] by simp
  qed
qed

lemma equiv_wn_solver_ind_2:
  assumes "is_mono_eq T"
    and "mono_deps T"
  shows "query_dom y x state
        ⟹ (xd, state') = query y x state
        ⟹ well_formed_infl_stabl state
        ⟹ narrowing_inv state post_state
        ⟹ x ∈ dep T (σ state)y
        ⟹ TD_wn_phases.query_dom y x state
            ∧ (xd, state') = TD_wn_phases.query y x state"
    and "iterate_dom x state
        ⟹ (xd, state') = iterate x state
        ⟹ well_formed_infl_stabl (state⦇called := called state - {x}⦈)
        ⟹ narrowing_inv (state⦇called := called state - {x}⦈) (post_state⦇cn := cn post_state - {x}⦈)
        ⟹ x ∈ called state
        ⟹ (x ∉ cn post_state ⟶ x ∉ post post_state - stabl state)
            ∧ (x ∈ cn post_state ⟶ x ∈ post post_state)
        ⟹ wn = Narrowing ⟶ x ∈ cn post_state
        ⟹ TD_wn_phases.iterate_dom x wn state
            ∧ (xd, state') = TD_wn_phases.iterate x wn state"
    and "eval_dom x t state
        ⟹ (xd, state') = eval x t state
        ⟹ well_formed_infl_stabl state
        ⟹ narrowing_inv state post_state
        ⟹ x ∈ called state
        ⟹ subt_for_prefix (T x) pre (σ state) = Some t
        ⟹ set pre ⊆ stabl state
        ⟹ TD_wn_phases.eval_dom x t state
            ∧ (xd, state') = TD_wn_phases.eval x t state"
proof(induction y x state and x state and y t state
      arbitrary: post_state xd state' and wn post_state xd state' and post_state xd state' pre
      rule: query_iterate_eval_pinduct)
  case (Query y x state)
  show ?case using Query.IH(1) Query.prems(1)
  proof(cases rule: query_iterate_lookup_cases)
    case (Iterate state1)
    obtain c1n where c1_def:
      "c1n = (if x ∈ post post_state then insert x (cn post_state) else cn post_state)"
      by fastforce
    have "c1n ⊆ insert x (called state)" using c1_def Query.prems(3) unfolding narrowing_inv_def by auto
    have "(x ∉ c1n ⟶ x ∈ post post_state ⟶ x ∈ stabl state) ∧
        (x ∈ c1n ⟶ x ∈ post post_state)"
      using c1_def Query.prems(3) Iterate(1) unfolding narrowing_inv_def by auto
    moreover have "well_formed_infl_stabl (state⦇called := insert x (called state) - {x}⦈)"
      using Iterate(1) Query.prems(2) by auto
    moreover have "narrowing_inv (state⦇called := insert x (called state) - {x}⦈)
        (post_state⦇cn := c1n - {x}⦈)"
      using Iterate(1) Query.prems(3) c1_def unfolding narrowing_inv_def by auto
    ultimately have IH: "TD_wn_phases.iterate_dom x Widening (state⦇called := insert x (called state)⦈)"
      "(xd, state1) = TD_wn_phases.iterate x Widening (state⦇called := insert x (called state)⦈)"
      using Query.IH(2)[OF Iterate(1,3), of "post_state⦇cn := c1n⦈" Widening] by simp+
    then show ?thesis
      using TD_wn_phases.query_iterate_eval.domintros(1)[of x state] Iterate(1,4)
      by (auto split: prod.splits)
  next
    case Lookup
    then show ?thesis using TD_wn_phases.query_iterate_eval.domintros(1)[of x state] by auto
  qed
next
  case (Iterate x state)
  have winv: "well_formed_infl_stabl (state⦇stabl := insert x (stabl state)⦈)"
    using Iterate.prems(2,4,5) unfolding well_formed_infl_stabl_def by auto
  have pinv: "eq_subsumed (σ (state⦇stabl := insert x (stabl state)⦈))
     (stabl (state⦇stabl := insert x (stabl state)⦈) - called (state⦇stabl := insert x (stabl state)⦈))"
    using Iterate.prems(3,4) unfolding narrowing_inv_def by auto
  have nar_inv: "narrowing_inv (state⦇stabl := insert x (stabl state)⦈)
      (post_state⦇post := insert x (post post_state)⦈)"
    using narrow_inv_add_x_stabl_and_post[OF Iterate.prems(4,5,3)] by auto
  show ?case using Iterate.IH(1) Iterate.prems(1)
  proof(cases rule: iterate_continue_fixpoint_cases)
    case Stable
    then show ?thesis
      using TD_wn_phases.query_iterate_eval.domintros(2)[of x state] by fastforce
  next
    case (Fixpoint state1)
    have IH1: "TD_wn_phases.eval_dom x (T x) (state⦇stabl := insert x (stabl state)⦈)"
      "(xd, state1) = TD_wn_phases.eval x (T x) (state⦇stabl := insert x (stabl state)⦈)"
      using Iterate.IH(2)[OF Fixpoint(1) refl Fixpoint(4) winv nar_inv, where ?pre1 = "[]"]
        Iterate.prems(4)
      by auto
    have "TD_wn_phases.iterate_dom x wn state"
      using Fixpoint(1,2,5,6) IH1 TD_wn_phases.query_iterate_eval.domintros(2)[of x state wn]
      by (cases "TD_wn_phases.eval x (T x) (state⦇stabl := insert x (stabl state)⦈)") auto
    then show ?thesis
      using IH1 Fixpoint(1,2,5,6)
      by (cases "TD_wn_phases.eval x (T x) (state⦇stabl := insert x (stabl state)⦈)") auto
  next
    case (WN_Fixpoint xd1 state1)
    have IH1: "TD_wn_phases.eval_dom x (T x) (state⦇stabl := insert x (stabl state)⦈)"
      "(xd1, state1) = TD_wn_phases.eval x (T x) (state⦇stabl := insert x (stabl state)⦈)"
      using Iterate.IH(2)[OF WN_Fixpoint(1) refl WN_Fixpoint(4) winv nar_inv, where ?pre1 = "[]"]
        Iterate.prems(4)
      by auto

    note part_correct = eq_subsumed_ind(3)[OF WN_Fixpoint(3,4) _ winv pinv, simplified]
    note wellformed_stabl = well_formed_infl_stabl_ind(3)[OF WN_Fixpoint(3,4) winv, simplified]
    obtain post_state1 where narInv: "narrowing_inv state1 post_state1"
      "update_rel_nar x (state⦇stabl := insert x (stabl state)⦈) state1
        (post_state⦇post := insert x (post post_state)⦈) post_state1"
      using narrowing_inv_ind(3)[OF assms(1,2) WN_Fixpoint(3,4) winv nar_inv, of "[]"]
        Iterate.prems(4-5) by auto

    have "xd1 ≤ mlup (σ state') x" using WN_Fixpoint(5,6) warrowing_properties(2) by blast
    then have w_fix: "mlup (σ state') x ∇ xd1 = mlup (σ state') x"
      using widening_precise by simp
    have n_fix: "mlup (σ state') x Δ xd1 = mlup (σ state') x"
      using WN_Fixpoint(5,6) ‹xd1 ≤ mlup (σ state') x› unfolding warrowing_def by simp
    have "TD_wn_phases.iterate_dom x wn state"
      using WN_Fixpoint(1-3,6,7) IH1 w_fix n_fix
        TD_wn_phases.query_iterate_eval.domintros(2)[of x state]
      by (cases "TD_wn_phases.eval x (T x) (state⦇stabl := insert x (stabl state)⦈)") simp
    then show ?thesis
      using TD_wn_phases.iterate.psimps[of x Widening state]
        IH1(2) WN_Fixpoint(1-2,6-7) w_fix n_fix
      by (cases "TD_wn_phases.eval x (T x) (state⦇stabl := insert x (stabl state)⦈)") simp
  next
    case (Continue xd1 state1 d_new infl2 stabl2)
    have IH1: "TD_wn_phases.eval_dom x (T x) (state⦇stabl := insert x (stabl state)⦈)"
      "(xd1, state1) = TD_wn_phases.eval x (T x) (state⦇stabl := insert x (stabl state)⦈)"
      using Iterate.IH(2)[OF Continue(1) refl Continue(3) winv nar_inv, where ?pre1 = "[]"]
        Iterate.prems(4)
      by auto

    note wellformed_stabl = well_formed_infl_stabl_ind(3)[OF Continue(2,3) winv, simplified]
    note part_correct = eq_subsumed_ind(3)[OF Continue(2,3) _ winv pinv, simplified]
    obtain post_state1 where narInv: "narrowing_inv state1 post_state1"
      "update_rel_nar x (state⦇stabl := insert x (stabl state)⦈) state1
        (post_state⦇post := insert x (post post_state)⦈) post_state1"
      using narrowing_inv_ind(3)[OF assms(1,2) Continue(2,3) winv nar_inv, of "[]"]
        Iterate.prems(4)
      by auto

    have xcalled1: "x ∈ called state1" and c_same: "called state1 = called state"
      using Iterate.prems(4) c_same(3)[OF Continue(2,3)] by simp+

    have stabl_incr: "stabl state ⊆ stabl2"
    proof -
      have "(slookup (infl state1) ξ - slookup (infl state) ξ) ∩ (stabl state) = {}" for ξ
        using Iterate.prems(3) Continue(1) wellformed_stabl by auto
      then show ?thesis
        using Iterate.prems(2) Continue(1) destab_infl_stabl_relation[OF Continue(6)]
          TD.new_lookup_to_infl_not_stabl[of state1 state x]
          wellformed_stabl
        unfolding well_formed_infl_stabl_def by auto
    qed

    let ?state2 = "state1⦇infl := infl2, stabl := stabl2, σ := (σ state1)(x ↦ d_new)⦈"

    have pinv2: "well_formed_infl_stabl (?state2⦇called := called state1 - {x}⦈)"
    proof -
      have "eq T x (σ state1) ≤ d_new"
        using Continue(4) part_correct warrowing_properties(1) by auto
      then show ?thesis
        using wellformed_stabl Iterate.prems(2,5) stabl_incr c_same
        apply (intro destab_upd_preserves_well_formed_infl_stabl[OF _ Continue(6), of state])
        unfolding well_formed_infl_stabl_def eq_def dep_def
        apply simp_all
        by fastforce
    qed

    have x_in_cn_iff_in_post: "(x ∈ cn post_state) = (x ∈ post post_state)"
      using Iterate.prems(5) Continue(1) by blast

    define x_truly_post where "x_truly_post ≡ x ∈ cn post_state ∨
                                              x ∈ point state ∧ xd1 ≤ mlup (σ state1) x"
    define cnx where "cnx ≡ (if x_truly_post then insert x (cn post_state1) else cn post_state1)"

    obtain post_state2 where destab_post: "post_state2 =
        destab_post x x_truly_post (post_state1⦇cn := cnx⦈) stabl2"
      by (auto split: prod.split)

    have post_incr: "post post_state ⊆ post post_state2"
      apply (intro post_dom_incr[OF Iterate.prems(2) conjunct1[OF wellformed_stabl]
             Iterate.prems(3) narInv(1,2) destab_post])
      using x_truly_post_def x_in_cn_iff_in_post by auto

    have cn_post: "(x ∉ cn post_state2 ⟶ x ∈ post post_state2 ⟶ x ∈ stabl2)
          ∧ (x ∈ cn post_state2 ⟶ x ∈ post post_state2)"
      apply (intro c_post_after_destab[OF Continue(6) destab_post post_incr Iterate.prems(3)
            conjunct1[OF wellformed_stabl] narInv(1)])
      using x_in_cn_iff_in_post narInv(2) wellformed_stabl
      unfolding cnx_def x_truly_post_def update_rel_nar_def
      by simp+

    have nar_inv2: "narrowing_inv (?state2⦇called := called state1 - {x}⦈)
      (post_state2⦇cn := cn post_state2 - {x}⦈)"
    proof (cases x_truly_post)
      case True
      have "x ∈ post post_state1 - (called state1 - cn post_state1)"
        if "x ∈ cn post_state"
        using narInv(2) that c_same unfolding update_rel_nar_def by simp
      then have "xd1 ≤ mlup (σ state1) x"
        using narInv(1) True part_correct unfolding narrowing_inv_def x_truly_post_def by auto
      have "eq T x (σ state1) ≤ d_new"
        using Continue(4) True part_correct warrowing_properties(1) by auto
      moreover have "d_new ≤ mlup (σ state1) x"
        using Continue(4) ‹xd1 ≤ mlup (σ state1) x› narrowing_le unfolding warrowing_def by auto
      ultimately have "narrowing_inv (?state2⦇called := called state1 - {x}⦈)
          (post_state1⦇cn := cn post_state1 - {x}⦈)"
        apply (intro nar_inv_after_update_if_post[OF assms(1,2) narInv(1)
              conjunct1[OF wellformed_stabl] _ _ _ Continue(6)])
        using wellformed_stabl destab_post True cnx_def
        unfolding dep_def
        by simp_all
      then show ?thesis using destab_post True cnx_def unfolding destab_post_def by auto
    next
      case False
      then have "cnx = cn post_state1" using cnx_def by auto
      have "eq T x (σ state1) ≤ d_new"
        using Continue(4) False part_correct warrowing_properties(1) by auto
      moreover have "x ∉ cn post_state" "x ∉ post post_state"
        using False x_in_cn_iff_in_post unfolding x_truly_post_def by auto
      ultimately show ?thesis
        using nar_inv_after_destab_update_if_not_post[OF _ _ Iterate.prems(2,3) _
            narInv(1) _ narInv(2) destab_post[simplified ‹cnx = cn post_state1›] Continue(6) _
            _ pinv2 c_same _ False] narInv(2) wellformed_stabl[folded dep_def]
        unfolding update_rel_nar_def
        by auto
    qed

    then show ?thesis
    proof (cases "x ∉ point state ∨ ¬ xd1 ≤ mlup (σ state1) x"
           rule: case_split[case_names Not_Post Post])
      case Not_Post

      have "wn = Narrowing ⟶ x ∈ cn post_state2"
        using Iterate.prems(6) destab_post
        unfolding cnx_def destab_post_def x_truly_post_def
        by simp
      then have IH2:
          "TD_wn_phases.iterate_dom x wn ?state2"
          "(xd, state') = TD_wn_phases.iterate x wn ?state2"
        using Iterate.IH(3)[OF Continue(1) refl Continue(3) _ Continue(4-6) _ Continue(8)]
          pinv2 nar_inv2 xcalled1 cn_post
        by simp+

      have "x ∉ point state ∨ wn = Widening"
        using Not_Post narInv part_correct Iterate.prems(6) x_in_cn_iff_in_post
        unfolding narrowing_inv_def update_rel_nar_def
        by (cases wn) auto

      then have iterate_dom: "TD_wn_phases.iterate_dom x wn state"
        using Continue(1,4-6) IH1 IH2(1) Not_Post
          TD_wn_phases.query_iterate_eval.domintros(2)[of x state wn]
        unfolding warrowing_def
        by (cases "x ∈ point state";
            cases "TD_wn_phases.eval x (T x) (state⦇stabl := insert x (stabl state)⦈)",
            cases "destab x (infl state1) (stabl state1)") (auto split: if_splits)

      then show ?thesis
        using TD_wn_phases.iterate.psimps[folded TD_wn_phases.dom_defs, OF iterate_dom]
          Continue(1,4-6) IH1(2) IH2(2) Not_Post ‹x ∉ point state ∨ wn = Widening›
        unfolding warrowing_def
        by (cases "TD_wn_phases.eval x (T x) (state⦇stabl := insert x (stabl state)⦈)",
            cases "destab x (infl state1) (stabl state1)") (auto split: if_splits)
    next
      case Post
      have "x ∈ post post_state1" using narInv unfolding update_rel_nar_def by simp

      have "x ∈ cn post_state2"
        using destab_post_c_unchanged[OF destab_post] Post
        unfolding cnx_def x_truly_post_def
        by (auto split: if_splits)
      then have IH2:
        "TD_wn_phases.iterate_dom x phase ?state2"
        "(xd, state') = TD_wn_phases.iterate x phase ?state2" for phase
      using Iterate.IH(3)[OF Continue(1) refl Continue(3) _ Continue(4-6) _ Continue(8)]
        pinv2 nar_inv2 xcalled1 cn_post
      by simp+

      have "TD_wn_phases.iterate_dom x wn state"
        using TD_wn_phases.query_iterate_eval.domintros(2)[folded TD_wn_phases.dom_defs,
              of x state wn] IH1 IH2 Continue(4,6) Post widening_precise
        unfolding warrowing_def
        by (cases "TD_wn_phases.eval x (T x) (state⦇stabl := insert x (stabl state)⦈)",
            cases "destab x (infl state1) (stabl state1)") auto

      then show ?thesis
        using Continue(1,4,5,6) Post IH1(2) widening_precise IH2(2)
        unfolding warrowing_def
        by (cases "TD_wn_phases.eval x (T x) (state⦇stabl := insert x (stabl state)⦈)",
            cases "destab x (infl state1) (stabl state1)") auto
    qed
  qed
next
  case (Eval x t state)
  show ?case using Eval.IH(1) Eval.prems(1)
  proof(cases rule: eval_query_answer_cases)
    case (Query y g yd state1)
    have y_dep: "y ∈ dep T (σ state)x"
      using Eval.prems(5) Query(1) subt_for_prefix_implies_subt dep_def subt_implies_dep by fast
    then have IH1: "TD_wn_phases.query_dom x y state"
      "(yd, state1) = TD_wn_phases.query x y state"
      using Eval.IH(2)[OF Query(1,3)] Eval.prems(2-6) by auto

    note c_same = c_same(1)[OF Query(2,3)]
    note wellformed_stabl = well_formed_infl_stabl_ind(1)[OF Query(2,3) Eval.prems(2)]
    obtain post_state1 where narInv: "narrowing_inv state1 post_state1
      ∧ update_rel_nar x state state1 post_state post_state1"
      using narrowing_inv_ind(1)[OF assms(1,2) Query(2,3) Eval.prems(2,3) y_dep] by auto

    have "x ∈ stabl state1"
      using Eval.prems(4) wellformed_stabl c_same unfolding well_formed_infl_stabl_def by fast
    have "subt_for_prefix (T x) pre (σ state1) = Some t"
      apply (subst subt_for_prefix_same)
      using Eval.prems(5,6) wellformed_stabl
      by auto
    moreover have "subt_for_prefix t [y] (σ state1) = Some (g yd)"
      using wellformed_stabl query_fmlookup[OF Query(2,3)] Query(1) by simp
    ultimately have F1: "subt_for_prefix (T x) (pre @ [y]) (σ state1) = Some (g yd)"
      using subt_for_prefix_transitive by blast
    have "y ∈ stabl state1"
      using wellformed_stabl TD.stabl_infl_empty unfolding well_formed_infl_stabl_def
      by (metis empty_iff)
    then have F2: "set (pre @ [y]) ⊆ stabl state1"
      using ‹set pre ⊆ stabl state› wellformed_stabl by auto

    have IH2: "TD_wn_phases.eval_dom x (g yd) state1"
      "(xd, state') = TD_wn_phases.eval x (g yd) state1"
      using Eval.IH(3)[OF Query(1,3) _ Query(5)] Eval.prems(4) c_same wellformed_stabl narInv
        ‹x ∈ stabl state1› F1 F2 by auto
    have "TD_wn_phases.eval_dom x t state"
      apply (rule TD_wn_phases.query_iterate_eval.domintros(3)[folded TD_wn_phases.dom_defs])
      using Query(1) IH1 IH2 by (auto split: prod.splits)
    then show ?thesis
      using eval.psimps[folded dom_defs] Query(1) IH1(2) IH2(2) by (auto split: prod.splits)
  next
    case Answer
    then show ?thesis
      using TD_wn_phases.query_iterate_eval.domintros(3)[of t] by simp
  qed
qed

corollary TD_wn_phases_TD_warrow_equivalence:
  assumes "is_mono_eq T"
      and "mono_deps T"
    shows "TD_wn_phases.solve_dom x ∧ TD_wn_phases.solve x = (sigma, vars)
           ⟷ solve_dom x ∧ solve x = (sigma, vars)"
proof
  assume solve: "TD_wn_phases.solve_dom x ∧ TD_wn_phases.solve x = (sigma, vars)"
  obtain xd state where "(xd, state) = TD_wn_phases.iterate x Widening
      ⦇called = {x}, σ = Map.empty, infl = fmempty, stabl = {}, point = {}⦈"
      and vars_sigma: "vars = stabl state" "sigma = σ state"
    using solve unfolding TD_wn_phases.solve_def by (auto split: prod.splits)
  then have "iterate_dom x ⦇called = {x}, σ = Map.empty, infl = fmempty, stabl = {}, point = {}⦈"
    "(xd, state) = iterate x ⦇called = {x}, σ = Map.empty, infl = fmempty, stabl = {}, point = {}⦈"
    using equiv_wn_solver_ind_1(2)[OF assms(1-2) conjunct1[OF solve,
          unfolded TD_wn_phases.solve_dom_def], of xd state "⦇cn = {}, pinfl = fmempty, post = {}⦈"]
    unfolding well_formed_infl_stabl_def narrowing_inv_def
    by auto
  then show "solve_dom x ∧ solve x = (sigma, vars)"
    using vars_sigma unfolding solve_dom_def solve_def by (auto split: prod.splits)
next
  assume solve: "solve_dom x ∧ solve x = (sigma, vars)"
  obtain xd state where "(xd, state) =
      iterate x ⦇called = {x}, σ = Map.empty, infl = fmempty, stabl = {}, point = {}⦈"
    and vars_sigma: "vars = stabl state" "sigma = σ state"
    using solve unfolding solve_def by (auto split: prod.splits)
  then have "TD_wn_phases.iterate_dom x Widening
      ⦇called = {x}, σ = Map.empty, infl = fmempty, stabl = {}, point = {}⦈"
    "(xd, state) = TD_wn_phases.iterate x Widening
      ⦇called = {x}, σ = Map.empty, infl = fmempty, stabl = {}, point = {}⦈"
    using equiv_wn_solver_ind_2(2)[OF assms(1-2) conjunct1[OF solve, unfolded solve_dom_def],
        of xd state "⦇cn = {}, pinfl = fmempty, post = {}⦈" Widening]
    unfolding well_formed_infl_stabl_def narrowing_inv_def
    by auto
  then show "TD_wn_phases.solve_dom x ∧ TD_wn_phases.solve x = (sigma, vars)"
    using vars_sigma unfolding TD_wn_phases.solve_dom_def TD_wn_phases.solve_def
    by (auto split: prod.splits)
qed

end


subsubsection ‹Termination of Warrowing TD›

locale TD_warrow_mono_term = TD_warrow_mono T widening narrowing
  for T :: "('x, 'd :: order_bot) eqsT"
    and widening :: "'d ⇒ 'd ⇒ 'd" (infixl "∇" 65)
    and narrowing :: "'d ⇒ 'd ⇒ 'd" (infixl "Δ" 70) +

  fixes widening_chains narrowing_chains :: "('d × 'd) set"
  defines widening_chains: "widening_chains ≡ {(x,y). ∃a. x ≠ y ∧ x = y ∇ a}"
    and narrowing_chains: "narrowing_chains ≡ {(x,y). ∃a. x ≠ y ∧ x = y Δ a}"
  assumes widening_finite: "wf widening_chains"
    and narrowing_finite: "wf narrowing_chains"

    and finite_vars: "finite (UNIV :: 'x set)"
begin

interpretation TD_wn_phases_term: TD_wn_phases.TD_wn_phases_term "(∇)" "(Δ)"
  using widening_finite narrowing_finite finite_vars
  unfolding TD_wn_phases_term_def widening_chains
    narrowing_chains
  by auto

corollary TD_warrow_terminating:
  assumes "is_mono_eq T"
      and "mono_deps T"
    shows"solve_dom x"
proof -
  have "TD_wn_phases_term.solve_dom x" by (simp add: TD_wn_phases_term.solve_termination)
  then show ?thesis using TD_wn_phases_TD_warrow_equivalence assms(1,2) by (meson old.prod.exhaust)
qed

subsubsection ‹Correctness of Phase TD›

corollary TD_wn_phases_partial_correctness:
  assumes "is_mono_eq T"
      and "mono_deps T"
      and "TD_wn_phases_term.solve x = (sigma, vars)"
    shows "part_post_solution T x sigma vars"
proof -
  have "solve_dom x" "solve x = (sigma, vars)"
    using TD_wn_phases_TD_warrow_equivalence TD_wn_phases_term.solve_termination assms
    by auto
  then show ?thesis using partial_correctness by auto
qed

end

end