Theory CDCL_WNOT

theory CDCL_WNOT
imports CDCL_W_Termination CDCL_NOT
theory CDCL_WNOT
imports CDCL_W_Termination CDCL_NOT
begin

section ‹Link between Weidenbach's and NOT's CDCL›
subsection ‹Inclusion of the states›
declare upt.simps(2)[simp del]
sledgehammer_params[verbose]

context cdclW
begin

lemma backtrack_levE:
  "backtrack S S' ⟹ cdclW_M_level_inv S ⟹
  (⋀D L K M1 M2.
    (Decided K (Suc (get_maximum_level (trail S) D)) # M1, M2)
      ∈ set (get_all_decided_decomposition (trail S)) ⟹
    get_level (trail S) L = get_maximum_level (trail S) (D + {#L#})  ⟹
    undefined_lit M1 L ⟹
    S' ∼ cons_trail (Propagated L (D + {#L#}))
      (reduce_trail_to M1 (add_learned_cls (D + {#L#})
        (update_backtrack_lvl (get_maximum_level (trail S) D) (update_conflicting None S)))) ⟹
    backtrack_lvl S = get_maximum_level (trail S) (D + {#L#}) ⟹
    conflicting S = Some (D + {#L#}) ⟹ P) ⟹
  P"
  using assms by (induction rule: backtrack_induction_lev2) metis

lemma backtrack_no_cdclW_bj:
  assumes cdcl: "cdclW_bj T U" and inv: "cdclW_M_level_inv V"
  shows "¬backtrack V T"
  using cdcl inv
  apply (induction rule: cdclW_bj.induct)
    apply (elim skipE, force elim!: backtrack_levE[OF _ inv] simp: cdclW_M_level_inv_def)
   apply (elim resolveE, force elim!: backtrack_levE[OF _ inv] simp: cdclW_M_level_inv_def)
  apply standard
  apply (elim backtrack_levE[OF _ inv], elim backtrackE)
  apply (force simp del: state_simp simp add: state_eq_conflicting cdclW_M_level_inv_decomp)
  done
 (*  by (force elim!: backtrack_levE[OF _ inv] simp: cdclW_M_level_inv_def) works too,
 but is much slower (6s vs less than 1s)*)

abbreviation skip_or_resolve :: "'st ⇒ 'st ⇒ bool" where
"skip_or_resolve ≡ (λS T. skip S T ∨ resolve S T)"

lemma rtranclp_cdclW_bj_skip_or_resolve_backtrack:
  assumes "cdclW_bj** S U" and inv: "cdclW_M_level_inv S"
  shows "skip_or_resolve** S U ∨ (∃T. skip_or_resolve** S T ∧ backtrack T U)"
  using assms
proof (induction)
  case base
  then show ?case by simp
next
  case (step U V) note st = this(1) and bj = this(2) and IH = this(3)[OF this(4)]
  consider
      (SU) "S = U"
    | (SUp) "cdclW_bj++ S U"
    using st unfolding rtranclp_unfold by blast
  then show ?case
    proof cases
      case SUp
      have "⋀T. skip_or_resolve** S T ⟹ cdclW** S T"
        using mono_rtranclp[of skip_or_resolve cdclW] other by blast
      then have "skip_or_resolve** S U"
        using bj IH inv backtrack_no_cdclW_bj rtranclp_cdclW_consistent_inv[OF _ inv] by meson
      then show ?thesis
        using bj by (metis (no_types, lifting) cdclW_bj.cases rtranclp.simps)
    next
      case SU
      then show ?thesis
        using bj by (metis (no_types, lifting) cdclW_bj.cases rtranclp.simps)
    qed
qed

lemma rtranclp_skip_or_resolve_rtranclp_cdclW:
  "skip_or_resolve** S T ⟹ cdclW** S T"
  by (induction rule: rtranclp_induct) (auto dest!: cdclW_bj.intros cdclW.intros cdclW_o.intros)

definition backjump_l_cond :: "'v clause ⇒ 'v clause ⇒ 'v literal ⇒ 'st ⇒ bool" where
"backjump_l_cond ≡ λC C' L' S. True"

definition invNOT :: "'st ⇒ bool" where
"invNOT ≡ λS. no_dup (trail S)"

declare invNOT_def[simp]
end

fun convert_ann_literal_from_W where
"convert_ann_literal_from_W (Propagated L _) = Propagated L ()" |
"convert_ann_literal_from_W (Decided L _) = Decided L ()"

abbreviation convert_trail_from_W ::
  "('v,  'lvl, 'a) ann_literal list
    ⇒ ('v, unit, unit) ann_literal list"  where
"convert_trail_from_W ≡ map convert_ann_literal_from_W"

lemma lits_of_convert_trail_from_W[simp]:
  "lits_of (convert_trail_from_W M) = lits_of M"
  by (induction rule: ann_literal_list_induct) simp_all

lemma lit_of_convert_trail_from_W[simp]:
  "lit_of (convert_ann_literal_from_W L) = lit_of L"
  by (cases L) auto

lemma no_dup_convert_from_W[simp]:
  "no_dup (convert_trail_from_W M) ⟷ no_dup M"
  by (auto simp: comp_def)

lemma convert_trail_from_W_true_annots[simp]:
  "convert_trail_from_W M ⊨as C ⟷ M ⊨as C"
  by (auto simp: true_annots_true_cls)

lemma defined_lit_convert_trail_from_W[simp]:
  "defined_lit (convert_trail_from_W S) L ⟷ defined_lit S L"
  by (auto simp: defined_lit_map image_comp)

text ‹The values @{term "0::nat"} and @{term "{#}"} are dummy values.›
fun convert_ann_literal_from_NOT
  :: "('a, 'e, 'b) ann_literal ⇒ ('a, nat, 'a literal multiset) ann_literal"  where
"convert_ann_literal_from_NOT (Propagated L _) = Propagated L {#}" |
"convert_ann_literal_from_NOT (Decided L _) = Decided L 0"

abbreviation convert_trail_from_NOT where
"convert_trail_from_NOT ≡ map convert_ann_literal_from_NOT"

lemma undefined_lit_convert_trail_from_NOT[simp]:
  "undefined_lit (convert_trail_from_NOT F) L ⟷ undefined_lit F L"
  by (induction F rule: ann_literal_list_induct) (auto simp: defined_lit_map)

lemma lits_of_convert_trail_from_NOT:
  "lits_of (convert_trail_from_NOT F) = lits_of F"
  by (induction F rule: ann_literal_list_induct) auto

lemma convert_trail_from_W_from_NOT[simp]:
  "convert_trail_from_W (convert_trail_from_NOT M) = M"
  by (induction rule: ann_literal_list_induct) auto

lemma convert_trail_from_W_convert_lit_from_NOT[simp]:
  "convert_ann_literal_from_W (convert_ann_literal_from_NOT L) = L"
  by (cases L) auto

abbreviation trailNOT where
"trailNOT S ≡ convert_trail_from_W (fst S)"

lemma undefined_lit_convert_trail_from_W[iff]:
  "undefined_lit (convert_trail_from_W M) L ⟷ undefined_lit M L"
  by (auto simp: defined_lit_map image_comp)

lemma lit_of_convert_ann_literal_from_NOT[iff]:
  "lit_of (convert_ann_literal_from_NOT L) = lit_of L"
  by (cases L) auto

sublocale stateW  dpll_state
  "λS. convert_trail_from_W (trail S)"
  clauses
  "λL S. cons_trail (convert_ann_literal_from_NOT L) S"
  "λS. tl_trail S"
  "λC S. add_learned_cls C S"
  "λC S. remove_cls C S"
  by unfold_locales (auto simp: map_tl o_def)

context stateW
begin
declare state_simpNOT[simp del]
end

sublocale cdclW  cdclNOT_merge_bj_learn_ops
  "λS. convert_trail_from_W (trail S)"
  clauses
  "λL S. cons_trail (convert_ann_literal_from_NOT L) S"
  "λS. tl_trail S"
  "λC S. add_learned_cls C S"
  "λC S. remove_cls C S"
  (* propagate conditions: *)"λ_ _. True"
  (* backjump conditions: *) "λ_ S. conflicting S = None"
  "λC C' L' S. backjump_l_cond C C' L' S  ∧ distinct_mset (C' + {#L'#}) ∧ ¬tautology (C' + {#L'#})"
  by unfold_locales

sublocale cdclW  cdclNOT_merge_bj_learn_proxy
  "λS. convert_trail_from_W (trail S)"
  clauses
  "λL S. cons_trail (convert_ann_literal_from_NOT L) S"
  "λS. tl_trail S"
  "λC S. add_learned_cls C S"
  "λC S. remove_cls C S"
  "λ_ _. True"
  "λ_ S. conflicting S = None" backjump_l_cond invNOT
proof (unfold_locales, goal_cases)
  case 2
  then show ?case using cdclNOT_merged_bj_learn_no_dup_inv by (auto simp: comp_def)
next
  case (1 C' S C F' K F L)
  moreover
    let ?C' = "remdups_mset C'"
    have "L ∉# C'"
      using ‹F ⊨as CNot C'› ‹undefined_lit F L› Decided_Propagated_in_iff_in_lits_of
      in_CNot_implies_uminus(2) by blast
    then have "distinct_mset (?C' + {#L#})"
      by (metis count_mset_set(3) distinct_mset_remdups_mset distinct_mset_single_add
        less_irrefl_nat mem_set_mset_iff remdups_mset_def)
  moreover
    have "no_dup F"
      using ‹invNOT S› ‹convert_trail_from_W (trail S) = F' @ Decided K () # F›
      unfolding invNOT_def
      by (smt comp_apply distinct.simps(2) distinct_append list.simps(9) map_append
        no_dup_convert_from_W)
    then have "consistent_interp (lits_of F)"
      using distinctconsistent_interp by blast
    then have "¬ tautology (C')"
      using ‹F ⊨as CNot C'› consistent_CNot_not_tautology true_annots_true_cls by blast
    then have "¬ tautology (?C' + {#L#})"
      using ‹F ⊨as CNot C'› ‹undefined_lit F L› by (metis  CNot_remdups_mset
        Decided_Propagated_in_iff_in_lits_of add.commute in_CNot_uminus tautology_add_single
        tautology_remdups_mset true_annot_singleton true_annots_def)
  show ?case
    proof -
      have f2: "no_dup (convert_trail_from_W (trail S))"
        using ‹invNOT S› unfolding invNOT_def by (simp add: o_def)
      have f3: "atm_of L ∈ atms_of_msu (clauses S)
        ∪ atm_of ` lits_of (convert_trail_from_W (trail S))"
        using ‹convert_trail_from_W (trail S) = F' @ Decided K () # F›
        ‹atm_of L ∈ atms_of_msu (clauses S) ∪ atm_of ` lits_of (F' @ Decided K () # F)› by auto
      have f4: "clauses S ⊨pm remdups_mset C' + {#L#}"
        by (metis (no_types) ‹L ∉# C'› ‹clauses S ⊨pm C' + {#L#}› remdups_mset_singleton_sum(2)
          true_clss_cls_remdups_mset union_commute)
      have "F ⊨as CNot (remdups_mset C')"
        by (simp add: ‹F ⊨as CNot C'›)
      then show ?thesis
        using f4 f3 f2 ‹¬ tautology (remdups_mset C' + {#L#})›
        backjump_l.intros[OF  _ f2] calculation(2-5,9)
        state_eqNOT_ref unfolding backjump_l_cond_def by blast
    qed
qed

sublocale cdclW  cdclNOT_merge_bj_learn_proxy2
  "λS. convert_trail_from_W (trail S)"
  clauses
  "λL S. cons_trail (convert_ann_literal_from_NOT L) S"
  "λS. tl_trail S"
  "λC S. add_learned_cls C S"
  "λC S. remove_cls C S" "λ_ _. True"  invNOT
  "λ_ S. conflicting S = None" backjump_l_cond
  by unfold_locales

sublocale cdclW  cdclNOT_merge_bj_learn
  "λS. convert_trail_from_W (trail S)"
  clauses
  "λL S. cons_trail (convert_ann_literal_from_NOT L) S"
  "λS. tl_trail S"
  "λC S. add_learned_cls C S"
  "λC S. remove_cls C S" "λ_ _. True"  invNOT
  "λ_ S. conflicting S = None" backjump_l_cond
  apply unfold_locales
   using dpll_bj_no_dup apply (simp add: comp_def)
  using cdclNOT_no_dup by (auto simp add: comp_def cdclNOT.simps)

context cdclW
begin
text ‹Notations are lost while proving locale inclusion:›
notation state_eqNOT (infix "∼NOT" 50)

subsection ‹Additional Lemmas between NOT and W states›
lemma trailW_eq_reduce_trail_toNOT_eq:
  "trail S = trail T ⟹ trail (reduce_trail_toNOT F S) = trail (reduce_trail_toNOT F T)"
proof (induction F S arbitrary: T rule: reduce_trail_toNOT.induct)
  case (1 F S T) note IH = this(1) and tr = this(2)
  then have "[] = convert_trail_from_W (trail S)
    ∨ length F = length (convert_trail_from_W (trail S))
    ∨ trail (reduce_trail_toNOT F (tl_trail S)) = trail (reduce_trail_toNOT F (tl_trail T))"
    using IH by (metis (no_types) trail_tl_trail)
  then show "trail (reduce_trail_toNOT F S) = trail (reduce_trail_toNOT F T)"
    using tr by (metis (no_types) reduce_trail_toNOT.elims)
qed

lemma trail_reduce_trail_toNOT_add_learned_cls:
"no_dup (trail S) ⟹
  trail (reduce_trail_toNOT M (add_learned_cls D S)) = trail (reduce_trail_toNOT M S)"
 by (rule trailW_eq_reduce_trail_toNOT_eq) simp

lemma reduce_trail_toNOT_reduce_trail_convert:
  "reduce_trail_toNOT C S = reduce_trail_to (convert_trail_from_NOT C) S"
  apply (induction C S rule: reduce_trail_toNOT.induct)
  apply (subst reduce_trail_toNOT.simps, subst reduce_trail_to.simps)
  by auto

lemma reduce_trail_to_length:
  "length M = length M' ⟹ reduce_trail_to M S = reduce_trail_to M' S"
  apply (induction M S arbitrary:  rule: reduce_trail_to.induct)
  apply (rename_tac F S; case_tac "trail S ≠ [] "; case_tac "length (trail S) ≠ length M'")
  by (simp_all add: reduce_trail_to_length_ne)

subsection ‹More lemmas conflict--propagate and backjumping›
subsubsection ‹Termination›

lemma cdclW_cp_normalized_element_all_inv:
  assumes inv: "cdclW_all_struct_inv S"
  obtains T where "full cdclW_cp S T"
  using assms cdclW_cp_normalized_element unfolding cdclW_all_struct_inv_def by blast
thm backtrackE

lemma cdclW_bj_measure:
  assumes "cdclW_bj S T" and "cdclW_M_level_inv S"
  shows "length (trail S) + (if conflicting S = None then 0 else 1)
    > length (trail T) +  (if conflicting T = None then 0 else 1)"
  using assms by (induction rule: cdclW_bj.induct)
  (force dest:arg_cong[of _ _ length]
    intro: get_all_decided_decomposition_exists_prepend
    elim!: backtrack_levE
    simp: cdclW_M_level_inv_def)+

lemma wf_cdclW_bj:
  "wf {(b,a). cdclW_bj a b ∧ cdclW_M_level_inv a}"
  apply (rule wfP_if_measure[of "λ_. True"
      _ "λT. length (trail T) + (if conflicting T = None then 0 else 1)", simplified])
  using cdclW_bj_measure by blast

lemma cdclW_bj_exists_normal_form:
  assumes lev: "cdclW_M_level_inv S"
  shows "∃T. full cdclW_bj S T"
proof -
  obtain T where T: "full (λa b. cdclW_bj a b ∧ cdclW_M_level_inv a) S T"
    using wf_exists_normal_form_full[OF wf_cdclW_bj] by auto
  then have "cdclW_bj** S T"
     by (auto dest: rtranclp_and_rtranclp_left simp: full_def)
  moreover
    then have "cdclW** S T"
      using mono_rtranclp[of cdclW_bj cdclW] cdclW.simps by blast
    then have "cdclW_M_level_inv T"
      using rtranclp_cdclW_consistent_inv lev by auto
  ultimately show ?thesis using T unfolding full_def by auto
qed

lemma rtranclp_skip_state_decomp:
  assumes "skip** S T" and "no_dup (trail S)"
  shows
    "∃M. trail S = M @ trail T ∧ (∀m∈set M. ¬is_decided m)" and
    "T ∼ delete_trail_and_rebuild (trail T) S"
  using assms by (induction rule: rtranclp_induct)
  (auto simp del: state_simp simp: state_eq_def state_access_simp)

subsubsection ‹More backjumping›
paragraph ‹Backjumping after skipping or jump directly›
lemma rtranclp_skip_backtrack_backtrack:
  assumes
    "skip** S T" and
    "backtrack T W" and
    "cdclW_all_struct_inv S"
  shows "backtrack S W"
  using assms
proof induction
  case base
  then show ?case by simp
next
  case (step T V) note st = this(1) and skip = this(2) and IH = this(3) and bt = this(4) and
    inv = this(5)
  have "skip** S V"
    using st skip by auto
  then have "cdclW_all_struct_inv V"
    using rtranclp_mono[of skip cdclW] assms(3) rtranclp_cdclW_all_struct_inv_inv mono_rtranclp
    by (auto dest!: bj other cdclW_bj.skip)
  then have "cdclW_M_level_inv V"
    unfolding cdclW_all_struct_inv_def by auto
  then obtain N k M1 M2 K D L U i where
    V: "state V = (trail V, N, U, k, Some (D + {#L#}))" and
    W: "state W = (Propagated L (D + {#L#}) # M1, N, {#D + {#L#}#} + U,
      get_maximum_level (trail V) D, None)" and
    decomp: "(Decided K (Suc i) # M1, M2)
      ∈ set (get_all_decided_decomposition (trail V))" and
    "k = get_maximum_level (trail V) (D + {#L#})" and
    lev_L: "get_level (trail V) L = k" and
    undef: "undefined_lit M1 L" and
    "W ∼ cons_trail (Propagated L (D + {#L#}))
      (reduce_trail_to M1 (add_learned_cls (D + {#L#})
        (update_backtrack_lvl (get_maximum_level (trail V) D) (update_conflicting None V))))"and
    lev_l_D: "backtrack_lvl V = get_maximum_level (trail V) (D + {#L#})" and
    "conflicting V = Some (D + {#L#})" and
    i: "i = get_maximum_level (trail V) D"
    using bt by (elim backtrack_levE)
    (auto simp: cdclW_M_level_inv_decomp state_eq_def simp del: state_simp)+
  let ?D = "(D + {#L#})"
  obtain L' C' where
    T: "state T = (Propagated L' C' # trail V, N, U, k, Some ?D)" and
    "V ∼ tl_trail T" and
    "-L' ∉# ?D" and
    "?D ≠ {#}"
    using skip V by force

  let ?M =  "Propagated L' C' # trail V"
  have "cdclW** S T" using bj cdclW_bj.skip mono_rtranclp[of skip cdclW S T] other st by meson
  then have inv': "cdclW_all_struct_inv T"
    using rtranclp_cdclW_all_struct_inv_inv inv by blast
  have M_lev: "cdclW_M_level_inv T" using inv' unfolding cdclW_all_struct_inv_def by auto
  then have n_d': "no_dup ?M"
    using T unfolding cdclW_M_level_inv_def by auto

  have "k > 0"
    using decomp M_lev T V unfolding cdclW_M_level_inv_def by auto
  then have "atm_of L ∈ atm_of ` lits_of (trail V)"
    using lev_L get_rev_level_ge_0_atm_of_in V by fastforce
  then have L_L': "atm_of L ≠ atm_of L'"
    using n_d' unfolding lits_of_def by auto
  have L'_M: "atm_of L' ∉ atm_of ` lits_of (trail V)"
    using n_d' unfolding lits_of_def by auto
  have "?M ⊨as CNot ?D"
    using inv' T unfolding cdclW_conflicting_def cdclW_all_struct_inv_def by auto
  then have "L' ∉# ?D"
    using L_L' L'_M unfolding true_annots_def by (auto simp add: true_annot_def true_cls_def
      atm_of_in_atm_of_set_iff_in_set_or_uminus_in_set Ball_mset_def
      split: split_if_asm)
  have [simp]: "trail (reduce_trail_to M1 T) = M1"
    by (metis (mono_tags, lifting) One_nat_def Pair_inject T ‹V ∼ tl_trail T› decomp
      diff_less in_get_all_decided_decomposition_trail_update_trail length_greater_0_conv
      length_tl lessI list.distinct(1) reduce_trail_to_length_ne state_eq_trail
      trail_reduce_trail_to_length_le trail_tl_trail)
  have "skip** S V"
    using st skip by auto
  have "no_dup (trail S)"
    using inv unfolding cdclW_all_struct_inv_def cdclW_M_level_inv_def by auto
  then have [simp]: "init_clss S = N" and [simp]: "learned_clss S = U"
    using rtranclp_skip_state_decomp[OF ‹skip** S V›] V
    by (auto simp del: state_simp simp: state_eq_def state_access_simp)
  then have W_S: "W ∼ cons_trail (Propagated L (D + {#L#})) (reduce_trail_to M1
  (add_learned_cls (D + {#L#}) (update_backtrack_lvl i (update_conflicting None T))))"
    using W i T undef M_lev by (auto simp del: state_simp simp: state_eq_def cdclW_M_level_inv_def)

  obtain M2' where
    "(Decided K (i+1) # M1, M2') ∈ set (get_all_decided_decomposition ?M)"
    using decomp V by (cases "hd (get_all_decided_decomposition (trail V))",
      cases "get_all_decided_decomposition (trail V)") auto
  moreover
    from L_L' have "get_level ?M L = k"
      using lev_L ‹-L' ∉# ?D› V  by (auto split: split_if_asm)
  moreover
    have "atm_of L' ∉ atms_of D"
      using ‹L' ∉# ?D› ‹-L' ∉# ?D› by (simp add: atm_of_in_atm_of_set_iff_in_set_or_uminus_in_set
        atms_of_def)
    then have "get_level ?M L = get_maximum_level ?M (D+{#L#})"
      using lev_l_D[symmetric] L_L' V lev_L by simp
  moreover have "i = get_maximum_level ?M D"
    using i ‹atm_of L' ∉ atms_of D› by auto
  moreover

  ultimately have "backtrack T W"
    using T(1) W_S by blast
  then show ?thesis using IH inv by blast
qed

lemma fst_get_all_decided_decomposition_prepend_not_decided:
  assumes "∀m∈set MS. ¬ is_decided m"
  shows "set (map fst (get_all_decided_decomposition M))
    = set (map fst (get_all_decided_decomposition (MS @ M)))"
    using assms apply (induction MS rule: ann_literal_list_induct)
    apply auto[2]
    by (rename_tac L m xs; case_tac "get_all_decided_decomposition (xs @ M)") simp_all

text ‹See also @{thm rtranclp_skip_backtrack_backtrack}›
lemma rtranclp_skip_backtrack_backtrack_end:
  assumes
    skip: "skip** S T" and
    bt: "backtrack S W" and
    inv: "cdclW_all_struct_inv S"
  shows "backtrack T W"
  using assms
proof -
  have M_lev: "cdclW_M_level_inv S "
    using bt inv unfolding cdclW_all_struct_inv_def by (auto elim!: backtrack_levE)
  then obtain k M M1 M2 K i D L N U where
    S: "state S = (M, N, U, k, Some (D + {#L#}))" and
    W: "state W = (Propagated L (D + {#L#}) # M1, N, {#D + {#L#}#} + U, get_maximum_level M D,
      None)" and
    decomp: "(Decided K (i+1) # M1, M2) ∈ set (get_all_decided_decomposition M)" and
    lev_l: "get_level M L = k" and
    lev_l_D: "get_level M L = get_maximum_level M (D+{#L#})" and
    i: "i = get_maximum_level M D" and
    undef: "undefined_lit M1 L"
    using bt by (elim backtrack_levE)
    (simp_all add: cdclW_M_level_inv_decomp state_eq_def del: state_simp)
  let ?D = "(D + {#L#})"

  have [simp]: "no_dup (trail S)"
    using M_lev by (auto simp: cdclW_M_level_inv_decomp)
  have "cdclW_all_struct_inv T"
    using mono_rtranclp[of skip cdclW] by (smt bj cdclW_bj.skip inv local.skip  other
      rtranclp_cdclW_all_struct_inv_inv)
  then have [simp]: "no_dup (trail T)"
    unfolding cdclW_all_struct_inv_def cdclW_M_level_inv_def by auto
  (* MT is a proxy to allow auto to unfold T*)
  obtain MS MT where M: "M = MS @ MT" and MT: "MT = trail T" and nm: "∀m∈set MS. ¬is_decided m"
    using rtranclp_skip_state_decomp(1)[OF skip] S M_lev by auto
  have T: "state T = (MT, N, U, k, Some ?D)"
    using MT rtranclp_skip_state_decomp(2)[of S T] skip S
    by (auto simp del: state_simp simp: state_eq_def state_access_simp)

  have "cdclW_all_struct_inv T"
    apply (rule rtranclp_cdclW_all_struct_inv_inv[OF _ inv])
    using bj cdclW_bj.skip local.skip other rtranclp_mono[of skip cdclW] by blast
  then have "MT ⊨as CNot ?D"
    unfolding cdclW_all_struct_inv_def cdclW_conflicting_def using T by blast
  have "∀L∈#?D. atm_of L ∈ atm_of ` lits_of MT"
    proof -
      have f1: "⋀l. ¬ MT ⊨a {#- l#} ∨ atm_of l ∈ atm_of ` lits_of MT"
        by (simp add: atm_of_in_atm_of_set_iff_in_set_or_uminus_in_set in_lit_of_true_annot
          lits_of_def)
      have "⋀l. l ∉# D ∨ - l ∈ lits_of MT"
        using ‹MT ⊨as CNot (D + {#L#})› multi_member_split by fastforce
      then show ?thesis
        using f1 by (meson ‹MT ⊨as CNot (D + {#L#})› ball_msetI true_annots_CNot_all_atms_defined)
    qed
  moreover have "no_dup M"
    using inv S unfolding cdclW_all_struct_inv_def cdclW_M_level_inv_def by auto
  ultimately have "∀L∈#?D. atm_of L ∉ atm_of ` lits_of MS"
    unfolding M unfolding lits_of_def by auto
  then have H: "⋀L. L∈#?D ⟹ get_level M L  = get_level MT L"
    unfolding M by (fastforce simp: lits_of_def)
  have [simp]: "get_maximum_level M ?D = get_maximum_level MT ?D"
    by (metis ‹MT ⊨as CNot (D + {#L#})›  M nm ball_msetI true_annots_CNot_all_atms_defined
      get_maximum_level_skip_un_decided_not_present)

  have lev_l': "get_level MT L = k"
    using lev_l by (auto simp: H)
  have [simp]: "trail (reduce_trail_to M1 T) = M1"
    using T decomp M nm by (smt MT append_assoc beginning_not_decided_invert
      get_all_decided_decomposition_exists_prepend reduce_trail_to_trail_tl_trail_decomp)
  have W: "W ∼ cons_trail (Propagated L (D + {#L#})) (reduce_trail_to M1
    (add_learned_cls (D + {#L#}) (update_backtrack_lvl i (update_conflicting None T))))"
    using W T i decomp undef by (auto simp del: state_simp simp: state_eq_def)

  have lev_l_D': "get_level MT L = get_maximum_level MT (D+{#L#})"
    using lev_l_D by (auto simp: H)
  have [simp]: "get_maximum_level M D = get_maximum_level MT D"
    proof -
      have "⋀ms m. ¬ (ms::('v, nat, 'v literal multiset) ann_literal list) ⊨as CNot m
          ∨ (∀l∈#m. atm_of l ∈ atm_of ` lits_of ms)"
        by (simp add: atm_of_in_atm_of_set_iff_in_set_or_uminus_in_set in_CNot_implies_uminus(2))
      then have "∀l∈#D. atm_of l ∈ atm_of ` lits_of MT"
        using ‹MT ⊨as CNot (D + {#L#})› by auto
      then show ?thesis
        by (metis M get_maximum_level_skip_un_decided_not_present nm)
    qed
  then have i': "i = get_maximum_level MT D"
    using i by auto
  have "Decided K (i + 1) # M1 ∈ set (map fst (get_all_decided_decomposition M))"
    using Set.imageI[OF decomp, of fst] by auto
  then have "Decided K (i + 1) # M1 ∈ set (map fst (get_all_decided_decomposition MT))"
    using fst_get_all_decided_decomposition_prepend_not_decided[OF nm] unfolding M  by auto
  then obtain M2' where decomp':"(Decided K (i+1) # M1, M2') ∈ set (get_all_decided_decomposition MT)"
    by auto
  then show "backtrack T W"
    using backtrack.intros[OF T decomp' lev_l'] lev_l_D' i' W by force
qed

lemma cdclW_bj_decomp_resolve_skip_and_bj:
  assumes "cdclW_bj** S T" and inv: "cdclW_M_level_inv S"
  shows "(skip_or_resolve** S T
    ∨ (∃U. skip_or_resolve** S U ∧ backtrack U T))"
  using assms
proof induction
  case base
  then show ?case by simp
next
  case (step T U) note st = this(1) and bj = this(2) and IH = this(3)
  have IH: "skip_or_resolve** S T"
    proof -
      { assume "(∃U. skip_or_resolve** S U ∧ backtrack U T)"
        then obtain V where
          bt: "backtrack V T" and
          "skip_or_resolve** S V"
          by blast
        have "cdclW** S V"
          using ‹skip_or_resolve** S V› rtranclp_skip_or_resolve_rtranclp_cdclW by blast
        then have "cdclW_M_level_inv V" and "cdclW_M_level_inv S"
          using rtranclp_cdclW_consistent_inv inv by blast+
        with bj bt have False using backtrack_no_cdclW_bj by simp
      }
      then show ?thesis using IH inv by blast
    qed
  show ?case
    using bj
    proof (cases rule: cdclW_bj.cases)
      case backtrack
      then show ?thesis using IH by blast
    qed (metis (no_types, lifting) IH rtranclp.simps)+
qed

lemma resolve_skip_deterministic:
  "resolve S T ⟹ skip S U ⟹ False"
  by fastforce

lemma backtrack_unique:
  assumes
    bt_T: "backtrack S T" and
    bt_U: "backtrack S U" and
    inv: "cdclW_all_struct_inv S"
  shows "T ∼ U"
proof -
  have lev: "cdclW_M_level_inv S"
    using inv unfolding cdclW_all_struct_inv_def by auto
  then obtain M N U' k D L i K M1 M2 where
    S: "state S = (M, N, U', k, Some (D + {#L#}))" and
    decomp: "(Decided K (i+1) # M1, M2) ∈ set (get_all_decided_decomposition M)" and
    "get_level M L = k" and
    "get_level M L = get_maximum_level M (D+{#L#})" and
    "get_maximum_level M D = i" and
    T: "state T = (Propagated L ( (D+{#L#})) # M1 , N, {#D + {#L#}#} + U', i, None)" and
    undef: "undefined_lit M1 L"
    using bt_T by (elim backtrack_levE)
    (force simp: cdclW_M_level_inv_def state_eq_def simp del: state_simp)+

  obtain  D' L' i' K' M1' M2' where
    S': "state S = (M, N, U', k, Some (D' + {#L'#}))" and
    decomp': "(Decided K' (i'+1) # M1', M2') ∈ set (get_all_decided_decomposition M)" and
    "get_level M L' = k" and
    "get_level M L' = get_maximum_level M (D'+{#L'#})" and
    "get_maximum_level M D' = i'" and
    U: "state U = (Propagated L' (D'+{#L'#}) # M1', N, {#D' + {#L'#}#} +U', i', None)" and
    undef: "undefined_lit M1' L'"
    using bt_U lev S by (elim backtrack_levE)
    (force simp: cdclW_M_level_inv_def  state_eq_def simp del: state_simp)+
  obtain c where M: "M = c @ M2 @ Decided K (i + 1) # M1"
    using decomp by auto
  obtain c' where M': "M = c' @ M2' @ Decided K' (i' + 1) # M1'"
    using decomp' by auto
  have decided: "get_all_levels_of_decided M = rev [1..<1+k]"
    using inv S unfolding cdclW_all_struct_inv_def cdclW_M_level_inv_def by auto
  then have "i < k"
    unfolding M
    by (force simp add: rev_swap[symmetric] dest!: arg_cong[of _ _ set])

  have [simp]: "L = L'"
    proof (rule ccontr)
      assume "¬ ?thesis"
      then have "L' ∈# D"
        using S unfolding S' by (fastforce simp: multiset_eq_iff split: split_if_asm)
      then have "get_maximum_level M D ≥ k"
        using ‹get_level M L' = k› get_maximum_level_ge_get_level by blast
      then show False using ‹get_maximum_level M D = i› ‹i < k› by auto
    qed
  then have [simp]: "D = D'"
    using S S' by auto
  have [simp]: "i=i'" using ‹get_maximum_level M D' = i'› ‹get_maximum_level M D = i› by auto

  text ‹Automation in a step later...›
  have H: "⋀a A B. insert a A = B ⟹ a : B"
    by blast
  have "get_all_levels_of_decided (c@M2) = rev [i+2..<1+k]" and
    "get_all_levels_of_decided (c'@M2') = rev [i+2..<1+k]"
    using decided unfolding M
    using decided unfolding M'
    unfolding rev_swap[symmetric] by (auto dest: append_cons_eq_upt_length_i_end)
  from arg_cong[OF this(1), of set] arg_cong[OF this(2), of set]
  have
    "dropWhile (λL. ¬is_decided L ∨ level_of L ≠ Suc i) (c @ M2) = []" and
    "dropWhile (λL. ¬is_decided L ∨ level_of L ≠ Suc i) (c' @ M2') = []"
      unfolding dropWhile_eq_Nil_conv Ball_def
      by (intro allI; rename_tac x; case_tac x; auto dest!: H simp add: in_set_conv_decomp)+

  then have "M1 = M1'"
    using arg_cong[OF M, of "dropWhile (λL. ¬is_decided L ∨ level_of L ≠ Suc i)"]
    unfolding M' by auto
  then show ?thesis using T U by (auto simp del: state_simp simp: state_eq_def)
qed

lemma if_can_apply_backtrack_no_more_resolve:
  assumes
    skip: "skip** S U" and
    bt: "backtrack S T" and
    inv: "cdclW_all_struct_inv S"
  shows "¬resolve U V"
proof (rule ccontr)
  assume resolve: "¬¬resolve U V"

  obtain L C M N U' k D where
    U: "state U = (Propagated L ( (C + {#L#})) # M, N, U', k, Some (D + {#-L#}))"and
    "get_maximum_level (Propagated L (C + {#L#}) # M) D = k" and
    "state V = (M, N, U', k, Some (D #∪ C))"
    using resolve by auto
  have "cdclW_all_struct_inv U"
    using mono_rtranclp[of skip cdclW] by (meson bj cdclW_bj.skip inv local.skip other
      rtranclp_cdclW_all_struct_inv_inv)
  then have [iff]: "no_dup (trail S)" "cdclW_M_level_inv S" and [iff]: "no_dup (trail U)"
    using inv unfolding cdclW_all_struct_inv_def cdclW_M_level_inv_def by blast+
  then have
    S: "init_clss S = N"
       "learned_clss S = U'"
       "backtrack_lvl S = k"
       "conflicting S = Some (D + {#-L#})"
    using rtranclp_skip_state_decomp(2)[OF skip] U
    by (auto simp del: state_simp simp: state_eq_def state_access_simp)
  obtain M0 where
    tr_S: "trail S = M0 @ trail U" and
    nm: "∀m∈set M0. ¬is_decided m"
    using rtranclp_skip_state_decomp[OF skip] by blast

  obtain M' D' L' i K M1 M2 where
    S': "state S = (M', N, U', k, Some (D' + {#L'#}))"  and
    decomp: "(Decided K (i+1) # M1, M2) ∈ set (get_all_decided_decomposition M')" and
    "get_level M' L' = k" and
    "get_level M' L' = get_maximum_level M' (D'+{#L'#})" and
    "get_maximum_level M' D' = i" and
    undef: "undefined_lit M1 L'" and
    T: "state T = (Propagated L' (D'+{#L'#}) # M1 , N, {#D' + {#L'#}#}+U', i, None)"
    using bt by (elim backtrack_levE) (fastforce simp: S state_eq_def simp del:state_simp)+
  obtain c where M: "M' = c @ M2 @ Decided K (i + 1) # M1"
    using get_all_decided_decomposition_exists_prepend[OF decomp] by auto
  have decided: "get_all_levels_of_decided M' = rev [1..<1+k]"
    using inv S' unfolding cdclW_all_struct_inv_def cdclW_M_level_inv_def by auto
  then have "i < k"
    unfolding M by (force simp add: rev_swap[symmetric] dest!: arg_cong[of _ _ set])

  have DD': "D' + {#L'#} = D + {#-L#}"
    using S S' by auto
  have [simp]: "L' = -L"
    proof (rule ccontr)
      assume "¬ ?thesis"
      then have "-L ∈# D'"
        using DD' by (metis add_diff_cancel_right' diff_single_trivial diff_union_swap
          multi_self_add_other_not_self)
      moreover
        have M': "M' = M0 @ Propagated L ( (C + {#L#})) # M"
          using tr_S U S S' by (auto simp: lits_of_def)
        have "no_dup M'"
           using inv U S' unfolding cdclW_all_struct_inv_def cdclW_M_level_inv_def by auto
        have atm_L_notin_M: "atm_of L ∉ atm_of ` (lits_of M)"
          using ‹no_dup M'› M' U S S' by (auto simp: lits_of_def)
        have "get_all_levels_of_decided M' = rev [1..<1+k]"
          using inv U S' unfolding cdclW_all_struct_inv_def cdclW_M_level_inv_def by auto
        then have "get_all_levels_of_decided M = rev [1..<1+k]"
          using nm M' S' U by (simp add: get_all_levels_of_decided_no_decided)
        then have get_lev_L:
          "get_level(Propagated L (C + {#L#}) # M) L = k"
          using get_level_get_rev_level_get_all_levels_of_decided[OF atm_L_notin_M,
            of "[Propagated L ((C + {#L#}))]"] by simp
        have "atm_of L ∉ atm_of ` (lits_of (rev M0))"
          using ‹no_dup M'› M' U S' by (auto simp: lits_of_def)
        then have "get_level M' L = k"
          using get_rev_level_notin_end[of L "rev M0"
            "rev M @ Propagated L (C + {#L#}) # []" 0]
          using tr_S get_lev_L M' U S' by (simp add:nm lits_of_def)
      ultimately have "get_maximum_level M' D' ≥ k"
        by (metis get_maximum_level_ge_get_level get_rev_level_uminus)
      then show False
        using ‹i < k› unfolding ‹get_maximum_level M' D' = i› by auto
    qed
  have [simp]: "D = D'" using DD' by auto
  have "cdclW** S U"
    using bj cdclW_bj.skip local.skip mono_rtranclp[of skip cdclW S U] other by meson
  then have "cdclW_all_struct_inv U"
    using inv rtranclp_cdclW_all_struct_inv_inv by blast
  then have "Propagated L ( (C + {#L#})) # M ⊨as CNot (D' + {#L'#})"
    using cdclW_all_struct_inv_def cdclW_conflicting_def U by auto
  then have "∀L'∈#D. atm_of L' ∈ atm_of ` lits_of (Propagated L ( (C + {#L#})) # M)"
    by (metis CNot_plus CNot_singleton Un_insert_right ‹D = D'› true_annots_insert ball_msetI
      atm_of_in_atm_of_set_iff_in_set_or_uminus_in_set  in_CNot_implies_uminus(2)
      sup_bot.comm_neutral)
  then have "get_maximum_level M' D = k"
     using tr_S nm U S'
       get_maximum_level_skip_un_decided_not_present[of D "
         Propagated L (C + {#L#}) # M" M0]
     unfolding  ‹get_maximum_level (Propagated L (C + {#L#}) # M) D = k›
     unfolding ‹D = D'›
     by simp
  then show False
    using ‹get_maximum_level M' D' = i› ‹i < k› by auto
qed

lemma if_can_apply_resolve_no_more_backtrack:
  assumes
    skip: "skip** S U" and
    resolve: "resolve S T" and
    inv: "cdclW_all_struct_inv S"
  shows "¬backtrack U V"
  using assms
  by (meson if_can_apply_backtrack_no_more_resolve rtranclp.rtrancl_refl
    rtranclp_skip_backtrack_backtrack)

lemma if_can_apply_backtrack_skip_or_resolve_is_skip:
  assumes
    bt: "backtrack S T" and
    skip: "skip_or_resolve** S U" and
    inv: "cdclW_all_struct_inv S"
  shows "skip** S U"
  using assms(2,3,1)
  by induction (simp_all add: if_can_apply_backtrack_no_more_resolve)

lemma cdclW_bj_bj_decomp:
  assumes "cdclW_bj** S W" and "cdclW_all_struct_inv S"
  shows
    "(∃T U V. (λS T. skip_or_resolve S T ∧ no_step backtrack S)** S T
        ∧ (λT U. resolve T U ∧ no_step backtrack T) T U
        ∧ skip** U V  ∧ backtrack V W)
    ∨ (∃T U. (λS T. skip_or_resolve S T ∧ no_step backtrack S)** S T
        ∧ (λT U. resolve T U ∧ no_step backtrack T) T U ∧ skip** U W)
    ∨ (∃T. skip** S T  ∧ backtrack T W)
    ∨ skip** S W" (is "?RB S W ∨ ?R S W ∨ ?SB S W ∨ ?S S W")
  using assms
proof induction
  case base
  then show ?case by simp
next
  case (step W X) note st = this(1) and bj = this(2) and IH = this(3)[OF this(4)] and inv = this(4)

  have "¬?RB S W" and "¬?SB S W"
    proof (clarify, goal_cases)
      case (1 T U V)
      have "skip_or_resolve** S T"
        using 1(1) by (auto dest!: rtranclp_and_rtranclp_left)
      then show "False"
        by (metis (no_types, lifting) "1"(2) "1"(4) "1"(5) backtrack_no_cdclW_bj
          cdclW_all_struct_inv_def cdclW_all_struct_inv_inv cdclW_o.bj local.bj other
          resolve rtranclp_cdclW_all_struct_inv_inv rtranclp_skip_backtrack_backtrack
          rtranclp_skip_or_resolve_rtranclp_cdclW step.prems)
    next
      case 2
      then show ?case by (meson assms(2) cdclW_all_struct_inv_def backtrack_no_cdclW_bj
        local.bj rtranclp_skip_backtrack_backtrack)
    qed
  then have IH: "?R S W ∨ ?S S W" using IH by blast

  have "cdclW** S W" by (metis cdclW_o.bj mono_rtranclp other st)
  then have inv_W: "cdclW_all_struct_inv W" by (simp add: rtranclp_cdclW_all_struct_inv_inv
    step.prems)
  consider
      (BT) X' where "backtrack W X'"
    | (skip) "no_step backtrack W" and "skip W X"
    | (resolve) "no_step backtrack W" and "resolve W X"
    using bj cdclW_bj.cases by meson
  then show ?case
    proof cases
      case (BT X')
      then consider
          (bt) "backtrack W X"
        | (sk) "skip W X"
        using bj if_can_apply_backtrack_no_more_resolve[of W W X' X] inv_W cdclW_bj.cases by fast
      then show ?thesis
        proof cases
          case bt
          then show ?thesis using IH by auto
        next
          case sk
          then show ?thesis using IH by (meson rtranclp_trans r_into_rtranclp)
        qed
    next
      case skip
      then show ?thesis using IH  by (meson rtranclp.rtrancl_into_rtrancl)
    next
      case resolve note no_bt = this(1) and res = this(2)
      consider
          (RS) T U where
            "(λS T. skip_or_resolve S T ∧ no_step backtrack S)** S T" and
            "resolve T U" and
            "no_step backtrack T" and
            "skip** U W"
        | (S)  "skip** S W"
        using IH by auto
      then show ?thesis
        proof cases
          case (RS T U)
          have "cdclW** S T"
            using  RS(1) cdclW_bj.resolve cdclW_o.bj  other skip
            mono_rtranclp[of " (λS T. skip_or_resolve S T ∧ no_step backtrack S)" cdclW S T]
            by meson
          then have "cdclW_all_struct_inv U"
            by (meson RS(2) cdclW_all_struct_inv_inv cdclW_bj.resolve cdclW_o.bj other
              rtranclp_cdclW_all_struct_inv_inv step.prems)
          { fix U'
            assume "skip** U U'" and "skip** U' W"
            have "cdclW_all_struct_inv U'"
              using ‹cdclW_all_struct_inv U› ‹skip** U U'› rtranclp_cdclW_all_struct_inv_inv
                 cdclW_o.bj rtranclp_mono[of skip cdclW] other skip by blast
            then have "no_step backtrack U'"
              using if_can_apply_backtrack_no_more_resolve[OF ‹skip** U' W› ] res by blast
          }
          with ‹skip** U W›
          have "(λS T. skip_or_resolve S T ∧ no_step backtrack S)** U W"
             proof induction
               case base
               then show ?case by simp
             next
               case (step V W) note st = this(1) and skip = this(2) and IH = this(3) and H = this(4)
               have "⋀U'. skip** U' V ⟹ skip** U' W"
                 using skip by auto
               then have "(λS T. skip_or_resolve S T ∧ no_step backtrack S)** U V"
                 using IH H by blast
               moreover have "(λS T. skip_or_resolve S T ∧ no_step backtrack S)** V W"
                 (* adding the ** here makes the ?case easier to find *)
                 by (simp add: local.skip r_into_rtranclp st step.prems)
               ultimately show ?case by simp
             qed
          then show ?thesis
            proof -
              have f1: "∀p pa pb pc. ¬ p (pa) pb ∨ ¬ p** pb pc ∨ p** pa pc"
                by (meson converse_rtranclp_into_rtranclp)
              have "skip_or_resolve T U ∧ no_step backtrack T"
                using RS(2) RS(3) by force
              then have "(λp pa. skip_or_resolve p pa ∧ no_step backtrack p)** T W"
                proof -
                  have "(∃vr19 vr16 vr17 vr18. vr19 (vr16::'st) vr17 ∧ vr19** vr17 vr18
                       ∧ ¬ vr19** vr16 vr18)
                    ∨ ¬ (skip_or_resolve T U ∧ no_step backtrack T)
                    ∨ ¬ (λuu uua. skip_or_resolve uu uua ∧ no_step backtrack uu)** U W
                    ∨ (λuu uua. skip_or_resolve uu uua ∧ no_step backtrack uu)** T W"
                    by force
                  then show ?thesis
                    by (metis (no_types) ‹(λS T. skip_or_resolve S T ∧ no_step backtrack S)** U W›
                      ‹skip_or_resolve T U ∧ no_step backtrack T› f1)
                qed
              then have "(λp pa. skip_or_resolve p pa ∧ no_step backtrack p)** S W"
                using RS(1) by force
              then show ?thesis
                using no_bt res by blast
            qed
        next
          case S
          { fix U'
            assume "skip** S U'" and "skip** U' W"
            then have "cdclW** S U'"
              using mono_rtranclp[of skip cdclW S U'] by (simp add: cdclW_o.bj other skip)
            then have "cdclW_all_struct_inv U'"
              by (metis (no_types, hide_lams) ‹cdclW_all_struct_inv S› 
                rtranclp_cdclW_all_struct_inv_inv)
            then have "no_step backtrack U'"
              using if_can_apply_backtrack_no_more_resolve[OF ‹skip** U' W› ] res by blast
          }
          with S
          have "(λS T. skip_or_resolve S T ∧ no_step backtrack S)** S W"
             proof induction
               case base
               then show ?case by simp
             next
               case (step V W) note st = this(1) and skip = this(2) and IH = this(3) and H = this(4)
               have "⋀U'. skip** U' V ⟹ skip** U' W"
                 using skip by auto
               then have "(λS T. skip_or_resolve S T ∧ no_step backtrack S)** S V"
                 using IH H by blast
               moreover have "(λS T. skip_or_resolve S T ∧ no_step backtrack S)** V W"
                 (* adding the ** here makes the ?case easier to find *)
                 by (simp add: local.skip r_into_rtranclp st step.prems)
               ultimately show ?case by simp
             qed
          then show ?thesis using res no_bt by blast
        qed
    qed
qed

text ‹The case distinction is needed, since @{term "T ∼ V"} does not imply that @{term "R** T V"}.›
lemma cdclW_bj_strongly_confluent:
   assumes
     "cdclW_bj** S V" and
     "cdclW_bj** S T" and
     n_s: "no_step cdclW_bj V" and
     inv: "cdclW_all_struct_inv S"
   shows "T ∼ V ∨ cdclW_bj** T V"
   using assms(2)
proof induction
  case base
  then show ?case by (simp add: assms(1))
next
  case (step T U) note st = this(1) and s_o_r = this(2) and IH = this(3)
  have "cdclW** S T"
    using st mono_rtranclp[of cdclW_bj cdclW] other by blast
  then have lev_T: "cdclW_M_level_inv T"
    using inv rtranclp_cdclW_consistent_inv[of S T]
    unfolding cdclW_all_struct_inv_def by auto

  consider
       (TV) "T ∼ V"
     | (bj_TV) "cdclW_bj** T V"
    using IH by blast
  then show ?case
    proof cases
      case TV
      have "no_step cdclW_bj T"
        using ‹cdclW_M_level_inv T› n_s cdclW_bj_state_eq_compatible[of T _ V] TV by auto
      then show ?thesis
        using s_o_r by auto
    next
      case bj_TV
      then obtain U' where
        T_U': "cdclW_bj T U'" and
        "cdclW_bj** U' V"
        using IH n_s s_o_r by (metis rtranclp_unfold tranclpD)
      have "cdclW** S T"
        by (metis (no_types, hide_lams) bj mono_rtranclp[of cdclW_bj cdclW] other st)
      then have inv_T: "cdclW_all_struct_inv T"
        by (metis (no_types, hide_lams) inv rtranclp_cdclW_all_struct_inv_inv)

      have lev_U: "cdclW_M_level_inv U"
        using s_o_r cdclW_consistent_inv lev_T other by blast
      show ?thesis
        using s_o_r
        proof cases
          case backtrack
          then obtain V0 where "skip** T V0" and "backtrack V0 V"
            using IH if_can_apply_backtrack_skip_or_resolve_is_skip[OF backtrack _ inv_T]
             cdclW_bj_decomp_resolve_skip_and_bj
             by (meson bj_TV cdclW_bj.backtrack inv_T lev_T n_s
               rtranclp_skip_backtrack_backtrack_end)
          then have "cdclW_bj** T V0" and "cdclW_bj V0 V"
            using rtranclp_mono[of skip cdclW_bj] by blast+
          then show ?thesis
            using ‹backtrack V0 V› ‹skip** T V0› backtrack_unique inv_T local.backtrack
            rtranclp_skip_backtrack_backtrack by auto
        next
          case resolve
          then have "U ∼ U'"
            by (meson T_U' cdclW_bj.simps if_can_apply_backtrack_no_more_resolve inv_T
              resolve_skip_deterministic resolve_unique rtranclp.rtrancl_refl)
          then show ?thesis
            using ‹cdclW_bj** U' V› unfolding rtranclp_unfold
            by (meson T_U' bj cdclW_consistent_inv lev_T other state_eq_ref state_eq_sym
              tranclp_cdclW_bj_state_eq_compatible)
        next
          case skip
          consider
              (sk)  "skip T U'"
            | (bt)  "backtrack T U'"
            using T_U' by (meson cdclW_bj.cases local.skip resolve_skip_deterministic)
          then show ?thesis
            proof cases
              case sk
              then show ?thesis
                using ‹cdclW_bj** U' V› unfolding rtranclp_unfold
                by (meson T_U' bj cdclW_all_inv(3) cdclW_all_struct_inv_def inv_T local.skip other
                  tranclp_cdclW_bj_state_eq_compatible skip_unique state_eq_ref)
            next
              case bt
              have "skip++ T U"
                using local.skip by blast
              then show ?thesis
                using bt by (metis ‹cdclW_bj** U' V› backtrack inv_T tranclp_unfold_begin
                  rtranclp_skip_backtrack_backtrack_end tranclp_into_rtranclp)
            qed
        qed
    qed
qed


lemma cdclW_bj_unique_normal_form:
  assumes
    ST: "cdclW_bj** S T" and SU: "cdclW_bj** S U" and
    n_s_U: "no_step cdclW_bj U" and
    n_s_T: "no_step cdclW_bj T" and
    inv: "cdclW_all_struct_inv S"
  shows "T ∼ U"
proof -
  have "T ∼ U ∨ cdclW_bj** T U"
    using ST SU cdclW_bj_strongly_confluent inv n_s_U by blast
  then show ?thesis
    by (metis (no_types) n_s_T rtranclp_unfold state_eq_ref tranclp_unfold_begin)
qed

lemma full_cdclW_bj_unique_normal_form:
 assumes "full cdclW_bj S T" and "full cdclW_bj S U" and
   inv: "cdclW_all_struct_inv S"
 shows "T ∼ U"
   using cdclW_bj_unique_normal_form assms unfolding full_def by blast

subsection ‹CDCL FW›
inductive cdclW_merge_restart :: "'st ⇒ 'st ⇒ bool" where
fw_r_propagate: "propagate S S' ⟹ cdclW_merge_restart S S'" |
fw_r_conflict: "conflict S T ⟹ full cdclW_bj T U ⟹ cdclW_merge_restart S U" |
fw_r_decide: "decide S S' ⟹ cdclW_merge_restart S S'"|
fw_r_rf: "cdclW_rf S S' ⟹ cdclW_merge_restart S S'"

lemma cdclW_merge_restart_cdclW:
  assumes "cdclW_merge_restart S T"
  shows "cdclW** S T"
  using assms
proof induction
  case (fw_r_conflict S T U) note confl = this(1) and bj = this(2)
  have "cdclW S T" using confl by (simp add: cdclW.intros r_into_rtranclp)
  moreover
    have "cdclW_bj** T U" using bj unfolding full_def by auto
    then have "cdclW** T U" by (metis cdclW_o.bj mono_rtranclp other)
  ultimately show ?case by auto
qed (simp_all add: cdclW_o.intros cdclW.intros r_into_rtranclp)

lemma cdclW_merge_restart_conflicting_true_or_no_step:
  assumes "cdclW_merge_restart S T"
  shows "conflicting T = None ∨ no_step cdclW T"
  using assms
proof induction
  case (fw_r_conflict S T U) note confl = this(1) and n_s = this(2)
  { fix D V
    assume "cdclW U V" and "conflicting U = Some D"
    then have False
      using n_s unfolding full_def
      by (induction rule: cdclW_all_rules_induct) (auto dest!: cdclW_bj.intros )
  }
  then show ?case by (cases "conflicting U") fastforce+
qed (auto simp add: cdclW_rf.simps)

inductive cdclW_merge :: "'st ⇒ 'st ⇒ bool" where
fw_propagate: "propagate S S' ⟹ cdclW_merge S S'" |
fw_conflict: "conflict S T ⟹ full cdclW_bj T U ⟹ cdclW_merge S U" |
fw_decide: "decide S S' ⟹ cdclW_merge S S'"|
fw_forget: "forget S S' ⟹ cdclW_merge S S'"

lemma cdclW_merge_cdclW_merge_restart:
  "cdclW_merge S T ⟹ cdclW_merge_restart S T"
  by (meson cdclW_merge.cases cdclW_merge_restart.simps forget)

lemma rtranclp_cdclW_merge_tranclp_cdclW_merge_restart:
  "cdclW_merge** S T ⟹ cdclW_merge_restart** S T"
  using rtranclp_mono[of cdclW_merge cdclW_merge_restart] cdclW_merge_cdclW_merge_restart by blast

lemma cdclW_merge_rtranclp_cdclW:
  "cdclW_merge S T ⟹ cdclW** S T"
  using cdclW_merge_cdclW_merge_restart cdclW_merge_restart_cdclW by blast

lemma rtranclp_cdclW_merge_rtranclp_cdclW:
  "cdclW_merge** S T ⟹ cdclW** S T"
  using rtranclp_mono[of cdclW_merge "cdclW**"] cdclW_merge_rtranclp_cdclW by auto

lemma cdclW_merge_is_cdclNOT_merged_bj_learn:
  assumes
    inv: "cdclW_all_struct_inv S" and
    cdclW:"cdclW_merge S T"
  shows "cdclNOT_merged_bj_learn S T
    ∨ (no_step cdclW_merge T ∧ conflicting T ≠ None)"
  using cdclW inv
proof induction
  case (fw_propagate S T) note propa = this(1)
  then obtain M N U k L C where
    H: "state S = (M, N, U, k, None)" and
    CL: "C + {#L#} ∈# clauses S" and
    M_C: "M ⊨as CNot C" and
    undef: "undefined_lit (trail S) L" and
    T: "T ∼ cons_trail (Propagated L (C + {#L#})) S"
    using propa by auto
  have "propagateNOT S T"
    apply (rule propagateNOT.propagateNOT[of _ C L])
    using H CL T undef M_C by (auto simp: state_eqNOT_def state_eq_def clauses_def
      simp del: state_simp)
  then show ?case
    using cdclNOT_merged_bj_learn.intros(2) by blast
next
  case (fw_decide S T) note dec = this(1) and inv = this(2)
  then obtain L where
    undef_L: "undefined_lit (trail S) L" and
    atm_L: "atm_of L ∈ atms_of_msu (init_clss S)" and
    T: "T ∼ cons_trail (Decided L (Suc (backtrack_lvl S)))
      (update_backtrack_lvl (Suc (backtrack_lvl S)) S)"
    by auto
  have "decideNOT S T"
    apply (rule decideNOT.decideNOT)
       using undef_L apply simp
     using atm_L inv unfolding cdclW_all_struct_inv_def no_strange_atm_def clauses_def apply auto[]
    using T undef_L unfolding state_eq_def state_eqNOT_def by (auto simp: clauses_def)
  then show ?case using cdclNOT_merged_bj_learn_decideNOT by blast
next
  case (fw_forget S T) note rf =this(1) and inv = this(2)
  then obtain M N C U k where
     S: "state S = (M, N, {#C#} + U, k, None)" and
     "¬ M ⊨asm clauses S" and
     "C ∉ set (get_all_mark_of_propagated (trail S))" and
     C_init: "C ∉# init_clss S" and
     C_le: "C ∈# learned_clss S" and
     T: "T ∼ remove_cls C S"
    by auto
  have "init_clss S ⊨pm C"
    using inv C_le unfolding cdclW_all_struct_inv_def cdclW_learned_clause_def
    by (meson mem_set_mset_iff true_clss_clss_in_imp_true_clss_cls)
  then have S_C: "clauses S - replicate_mset (count (clauses S) C) C ⊨pm C"
    using C_init C_le unfolding clauses_def by (simp add: Un_Diff)
  moreover have H: "init_clss S + (learned_clss S - replicate_mset (count (learned_clss S) C) C)
    = init_clss S + learned_clss S - replicate_mset (count (learned_clss S) C) C"
    using C_le C_init by (metis clauses_def clauses_remove_cls diff_zero gr0I
      init_clss_remove_cls learned_clss_remove_cls plus_multiset.rep_eq replicate_mset_0
      semiring_normalization_rules(5))
  have "forgetNOT S T"
    apply (rule forgetNOT.forgetNOT)
       using S_C apply blast
      using S apply simp
     using ‹C ∈# learned_clss S› apply (simp add: clauses_def)
    using T C_le C_init by (auto
      simp: state_eq_def Un_Diff state_eqNOT_def clauses_def ac_simps H
      simp del: state_simp)
  then show ?case using cdclNOT_merged_bj_learn_forgetNOT by blast
next
  case (fw_conflict S T U) note confl = this(1) and bj = this(2) and inv = this(3)
  obtain CS where
    confl_T: "conflicting T = Some CS" and
    CS: "CS ∈# clauses S" and
    tr_S_CS: "trail S ⊨as CNot CS"
    using confl by auto
  have "cdclW_all_struct_inv T"
    using cdclW.simps cdclW_all_struct_inv_inv confl inv by blast
  then have "cdclW_M_level_inv T"
    unfolding cdclW_all_struct_inv_def by auto
  then consider
      (no_bt) "skip_or_resolve** T U"
    | (bt) T' where "skip_or_resolve** T T'" and "backtrack T' U"
    using bj rtranclp_cdclW_bj_skip_or_resolve_backtrack unfolding full_def by meson
  then show ?case
    proof cases
      case no_bt
      then have "conflicting U ≠ None"
        using confl by (induction rule: rtranclp_induct) auto
      moreover then have "no_step cdclW_merge U"
        by (auto simp: cdclW_merge.simps)
      ultimately show ?thesis by blast
    next
      case bt note s_or_r = this(1) and bt = this(2)
      have "cdclW** T T'"
        using s_or_r mono_rtranclp[of skip_or_resolve cdclW] rtranclp_skip_or_resolve_rtranclp_cdclW
        by blast
      then have "cdclW_M_level_inv T'"
        using rtranclp_cdclW_consistent_inv ‹cdclW_M_level_inv T› by blast
      then obtain M1 M2 i D L K where
        confl_T': "conflicting T' = Some (D + {#L#})" and
        M1_M2:"(Decided K (i+1) # M1, M2) ∈ set (get_all_decided_decomposition (trail T'))" and
        "get_level (trail T') L = backtrack_lvl T'" and
        "get_level (trail T') L = get_maximum_level (trail T') (D+{#L#})" and
        "get_maximum_level (trail T') D = i" and
        undef_L: "undefined_lit M1 L" and
        U: "U ∼ cons_trail (Propagated L (D+{#L#}))
                 (reduce_trail_to M1
                      (add_learned_cls (D + {#L#})
                         (update_backtrack_lvl i
                            (update_conflicting None T'))))"
        using bt by (auto elim: backtrack_levE)
      have [simp]: "clauses S = clauses T"
        using confl by auto
      have [simp]: "clauses T = clauses T'"
        using s_or_r
        proof (induction)
          case base
          then show ?case by simp
        next
          case (step U V) note st = this(1) and s_o_r = this(2) and IH = this(3)
          have "clauses U = clauses V"
            using s_o_r by auto
          then show ?case using IH by auto
        qed
      have inv_T: "cdclW_all_struct_inv T"
        by (meson cdclW_cp.simps confl inv r_into_rtranclp rtranclp_cdclW_all_struct_inv_inv
          rtranclp_cdclW_cp_rtranclp_cdclW)
      have "cdclW** T T'"
        using rtranclp_skip_or_resolve_rtranclp_cdclW s_or_r by blast
      have inv_T': "cdclW_all_struct_inv T'"
        using ‹cdclW** T T'› inv_T rtranclp_cdclW_all_struct_inv_inv by blast
      have inv_U: "cdclW_all_struct_inv U"
        using cdclW_merge_restart_cdclW confl fw_r_conflict inv local.bj
        rtranclp_cdclW_all_struct_inv_inv by blast

      have [simp]: "init_clss S = init_clss T'"
        using ‹cdclW** T T'› cdclW_init_clss confl cdclW_all_struct_inv_def conflict inv
        by (metis ‹cdclW_M_level_inv T› rtranclp_cdclW_init_clss)
      then have atm_L: "atm_of L ∈ atms_of_msu (clauses S)"
        using inv_T' confl_T' unfolding cdclW_all_struct_inv_def no_strange_atm_def clauses_def
        by auto
      obtain M where tr_T: "trail T = M @ trail T'"
        using s_or_r by (induction rule: rtranclp_induct) auto
      obtain M' where
        tr_T': "trail T' = M' @  Decided K (i+1) # tl (trail U)" and
        tr_U: "trail U = Propagated L (D + {#L#}) # tl (trail U)"
        using U M1_M2 undef_L inv_T' unfolding cdclW_all_struct_inv_def cdclW_M_level_inv_def
        by fastforce
      def M''  "M @ M'"
        have tr_T: "trail S = M'' @  Decided K (i+1) # tl (trail U)"
        using tr_T tr_T' confl unfolding M''_def by auto
      have "init_clss T' + learned_clss S ⊨pm D + {#L#}"
        using inv_T' confl_T' unfolding cdclW_all_struct_inv_def cdclW_learned_clause_def clauses_def
        by simp
      have "reduce_trail_to (convert_trail_from_NOT (convert_trail_from_W M1)) S =
        reduce_trail_to M1 S"
        by (rule reduce_trail_to_length) simp
      moreover have "trail (reduce_trail_to M1 S) = M1"
        apply (rule reduce_trail_to_skip_beginning[of _ "M @ _ @ M2 @ [Decided K (Suc i)]"])
        using confl M1_M2 ‹trail T = M @ trail T'›
          apply (auto dest!: get_all_decided_decomposition_exists_prepend
            elim!: conflictE)
          by (rule sym) auto
      ultimately have [simp]: "trail (reduce_trail_toNOT (convert_trail_from_W M1) S) = M1"
        using M1_M2 confl by (auto simp add: reduce_trail_toNOT_reduce_trail_convert)
      have "every_mark_is_a_conflict U"
        using inv_U unfolding cdclW_all_struct_inv_def cdclW_conflicting_def by simp
      then have "tl (trail U) ⊨as CNot D"
        by (metis add_diff_cancel_left' append_self_conv2 tr_U union_commute)
      have "backjump_l S U"
        apply (rule backjump_l[of _ _ _ _ _ L])
                 using tr_T apply simp
                using inv unfolding cdclW_all_struct_inv_def cdclW_M_level_inv_def
                apply (simp add: comp_def)
               using U M1_M2 confl undef_L M1_M2 inv_T' inv unfolding cdclW_all_struct_inv_def
               cdclW_M_level_inv_def apply (auto simp: state_eqNOT_def
                 trail_reduce_trail_toNOT_add_learned_cls)[]
              using CS apply simp
             using tr_S_CS apply simp

            using U undef_L M1_M2  inv_T' inv unfolding cdclW_all_struct_inv_def
            cdclW_M_level_inv_def apply auto[]
           using undef_L atm_L apply (simp add: trail_reduce_trail_toNOT_add_learned_cls)
          using ‹init_clss T' + learned_clss S ⊨pm D + {#L#}› unfolding clauses_def apply simp
         apply (metis ‹tl (trail U) ⊨as CNot D› convert_trail_from_W_true_annots)
        using  inv_T' inv_U U confl_T' undef_L M1_M2 unfolding cdclW_all_struct_inv_def
        distinct_cdclW_state_def by (simp add: cdclW_M_level_inv_decomp backjump_l_cond_def)
      then show ?thesis using cdclNOT_merged_bj_learn_backjump_l by fast
    qed
qed

abbreviation cdclNOT_restart where
"cdclNOT_restart ≡ restart_ops.cdclNOT_raw_restart cdclNOT restart"

lemma cdclW_merge_restart_is_cdclNOT_merged_bj_learn_restart_no_step:
  assumes
    inv: "cdclW_all_struct_inv S" and
    cdclW:"cdclW_merge_restart S T"
  shows "cdclNOT_restart** S T ∨ (no_step cdclW_merge T ∧ conflicting T ≠ None)"
proof -
  consider
      (fw) "cdclW_merge S T"
    | (fw_r) "restart S T"
    using cdclW by (meson cdclW_merge_restart.simps cdclW_rf.cases fw_conflict fw_decide fw_forget
      fw_propagate)
  then show ?thesis
    proof cases
      case fw
      then have IH: "cdclNOT_merged_bj_learn S T ∨ (no_step cdclW_merge T ∧ conflicting T ≠ None)"
        using inv cdclW_merge_is_cdclNOT_merged_bj_learn by blast
      have invS: "invNOT S"
        using inv unfolding cdclW_all_struct_inv_def cdclW_M_level_inv_def by auto
      have ff2: "cdclNOT++ S T ⟶ cdclNOT** S T"
          by (meson tranclp_into_rtranclp)
      have ff3: "no_dup (convert_trail_from_W (trail S))"
        using invS by (simp add: comp_def)
      have "cdclNOT ≤ cdclNOT_restart"
        by (auto simp: restart_ops.cdclNOT_raw_restart.simps)
      then show ?thesis
        using ff3 ff2 IH cdclNOT_merged_bj_learn_is_tranclp_cdclNOT
        rtranclp_mono[of cdclNOT cdclNOT_restart] invS predicate2D by blast
    next
      case fw_r
      then show ?thesis by (blast intro: restart_ops.cdclNOT_raw_restart.intros)
    qed
qed

abbreviation μFW :: "'st ⇒ nat" where
FW S ≡ (if no_step cdclW_merge S then 0 else 1+μCDCL'_merged (set_mset (init_clss S)) S)"

lemma cdclW_merge_μFW_decreasing:
  assumes
    inv: "cdclW_all_struct_inv S" and
    fw: "cdclW_merge S T"
  shows FW T < μFW S"
proof -
  let ?A = "init_clss S"
  have atm_clauses: "atms_of_msu (clauses S) ⊆ atms_of_msu ?A"
    using inv unfolding cdclW_all_struct_inv_def no_strange_atm_def clauses_def by auto
  have atm_trail: "atm_of ` lits_of (trail S) ⊆ atms_of_msu ?A"
    using inv unfolding cdclW_all_struct_inv_def no_strange_atm_def clauses_def by auto
  have n_d: "no_dup (trail S)"
    using inv unfolding cdclW_all_struct_inv_def by (auto simp: cdclW_M_level_inv_decomp)
  have [simp]: "¬ no_step cdclW_merge S"
    using fw by auto
  have [simp]: "init_clss S = init_clss T"
    using cdclW_merge_restart_cdclW[of S T] inv rtranclp_cdclW_init_clss
    unfolding cdclW_all_struct_inv_def
    by (meson cdclW_merge.simps cdclW_merge_restart.simps  cdclW_rf.simps fw)
  consider
      (merged) "cdclNOT_merged_bj_learn S T"
    | (n_s) "no_step cdclW_merge T"
    using cdclW_merge_is_cdclNOT_merged_bj_learn inv fw by blast
  then show ?thesis
    proof cases
      case merged
      then show ?thesis
        using cdclNOT_decreasing_measure'[OF _ _ atm_clauses] atm_trail n_d
        by (auto split: split_if simp: comp_def)
    next
      case n_s
      then show ?thesis by simp
    qed
qed

lemma wf_cdclW_merge: "wf {(T, S). cdclW_all_struct_inv S ∧ cdclW_merge S T}"
  apply (rule wfP_if_measure[of _ _ FW"])
  using cdclW_merge_μFW_decreasing by blast

lemma cdclW_all_struct_inv_tranclp_cdclW_merge_tranclp_cdclW_merge_cdclW_all_struct_inv:
  assumes
    inv: "cdclW_all_struct_inv b"
    "cdclW_merge++ b a"
  shows "(λS T. cdclW_all_struct_inv S ∧ cdclW_merge S T)++ b a"
  using assms(2)
proof induction
  case base
  then show ?case using inv by auto
next
  case (step c d) note st =this(1) and fw = this(2) and IH = this(3)
  have "cdclW_all_struct_inv c"
    using tranclp_into_rtranclp[OF st] cdclW_merge_rtranclp_cdclW
    assms(1) rtranclp_cdclW_all_struct_inv_inv rtranclp_mono[of cdclW_merge "cdclW**"] by fastforce
  then have "(λS T. cdclW_all_struct_inv S ∧ cdclW_merge S T)++ c d"
    using fw by auto
  then show ?case using IH by auto
qed

lemma wf_tranclp_cdclW_merge: "wf {(T, S). cdclW_all_struct_inv S ∧ cdclW_merge++ S T}"
  using wf_trancl[OF wf_cdclW_merge]
  apply (rule wf_subset)
  by (auto simp: trancl_set_tranclp
    cdclW_all_struct_inv_tranclp_cdclW_merge_tranclp_cdclW_merge_cdclW_all_struct_inv)

lemma backtrack_is_full1_cdclW_bj:
  assumes bt: "backtrack S T" and inv: "cdclW_M_level_inv S"
  shows "full1 cdclW_bj S T"
proof -
  have "no_step cdclW_bj T"
    using bt inv backtrack_no_cdclW_bj by blast
  moreover have "cdclW_bj++ S T"
    using bt by auto
  ultimately show ?thesis unfolding full1_def by blast
qed

lemma rtrancl_cdclW_conflicting_true_cdclW_merge_restart:
  assumes "cdclW** S V" and inv: "cdclW_M_level_inv S" and "conflicting S = None"
  shows "(cdclW_merge_restart** S V ∧ conflicting V = None)
    ∨ (∃T U. cdclW_merge_restart** S T ∧ conflicting V ≠ None ∧ conflict T U ∧ cdclW_bj** U V)"
  using assms
proof induction
  case base
  then show ?case by simp
next
  case (step U V) note st = this(1) and cdclW = this(2) and IH = this(3)[OF this(4-)] and
    confl[simp] = this(5) and inv = this(4)
  from cdclW
  show ?case
    proof (cases)
      case propagate
      moreover then have "conflicting U = None"
        by auto
      moreover have "conflicting V = None"
        using propagate by auto
      ultimately show ?thesis using IH cdclW_merge_restart.fw_r_propagate[of U V] by auto
    next
      case conflict
      moreover then have "conflicting U = None"
        by auto
      moreover have "conflicting V ≠ None"
        using conflict by auto
      ultimately show ?thesis using IH by auto
    next
      case other
      then show ?thesis
        proof cases
          case decide
          moreover then have "conflicting U = None"
            by auto
          ultimately show ?thesis using IH cdclW_merge_restart.fw_r_decide[of U V] by auto
        next
          case bj
          moreover {
            assume "skip_or_resolve U V"
            have f1: "cdclW_bj++ U V"
              by (simp add: local.bj tranclp.r_into_trancl)
            obtain T T' :: 'st where
              f2: "cdclW_merge_restart** S U
                ∨ cdclW_merge_restart** S T ∧ conflicting U ≠ None
                  ∧ conflict T T' ∧ cdclW_bj** T' U"
              using IH confl by blast
            then have ?thesis
              proof -
                have "conflicting V ≠ None ∧ conflicting U ≠ None"
                  using ‹skip_or_resolve U V› by auto
                then show ?thesis
                  by (metis (no_types) IH f1 rtranclp_trans tranclp_into_rtranclp)
              qed
          }
          moreover {
            assume "backtrack U V"
            then have "conflicting U ≠ None" by auto
            then obtain T T' where
              "cdclW_merge_restart** S T" and
              "conflicting U ≠ None" and
              "conflict T T'" and
              "cdclW_bj** T' U"
              using IH confl by meson
            have invU: "cdclW_M_level_inv U"
              using inv rtranclp_cdclW_consistent_inv step.hyps(1) by blast
            then have "conflicting V = None"
              using ‹backtrack U V› inv by (auto elim: backtrack_levE
                simp: cdclW_M_level_inv_decomp)
            have "full cdclW_bj T' V"
              apply (rule rtranclp_fullI[of cdclW_bj T' U V])
                using ‹cdclW_bj** T' U› apply fast
              using ‹backtrack U V› backtrack_is_full1_cdclW_bj invU unfolding full1_def full_def
              by blast
            then have ?thesis
              using cdclW_merge_restart.fw_r_conflict[of T T' V] ‹conflict T T'›
              ‹cdclW_merge_restart** S T› ‹conflicting V = None› by auto
          }
          ultimately show ?thesis by (auto simp: cdclW_bj.simps)
      qed
    next
      case rf
      moreover then have "conflicting U = None" and "conflicting V = None"
        by (auto simp: cdclW_rf.simps)
      ultimately show ?thesis using IH cdclW_merge_restart.fw_r_rf[of U V] by auto
    qed
qed

lemma no_step_cdclW_no_step_cdclW_merge_restart: "no_step cdclW S ⟹ no_step cdclW_merge_restart S"
  by (auto simp: cdclW.simps cdclW_merge_restart.simps cdclW_o.simps cdclW_bj.simps)

lemma no_step_cdclW_merge_restart_no_step_cdclW:
  assumes
    "conflicting S = None" and
    "cdclW_M_level_inv S" and
    "no_step cdclW_merge_restart S"
  shows "no_step cdclW S"
proof -
  { fix S'
    assume "conflict S S'"
    then have "cdclW S S'" using cdclW.conflict by auto
    then have "cdclW_M_level_inv S'"
      using assms(2) cdclW_consistent_inv by blast
    then obtain S'' where "full cdclW_bj S' S''"
      using cdclW_bj_exists_normal_form[of S'] by auto
    then have False
      using ‹conflict S S'› assms(3) fw_r_conflict by blast
  }
  then show ?thesis
    using assms unfolding cdclW.simps cdclW_merge_restart.simps cdclW_o.simps cdclW_bj.simps
    by fastforce
qed

lemma rtranclp_cdclW_merge_restart_no_step_cdclW_bj:
  assumes
    "cdclW_merge_restart** S T" and
    "conflicting S = None"
  shows "no_step cdclW_bj T"
  using assms
  apply (induction rule: rtranclp_induct)
   apply  (fastforce simp: cdclW_bj.simps cdclW_rf.simps cdclW_merge_restart.simps full_def)
  apply (fastforce simp: cdclW_bj.simps cdclW_rf.simps cdclW_merge_restart.simps full_def)
  (* SLOW ~15s *)
  done

text ‹If @{term "conflicting  S ≠ None"}, we cannot say anything.

  Remark that this theorem does  not say anything about well-foundedness: even if you know that one
  relation is well-founded, it only states that the normal forms are shared.
  ›
lemma conflicting_true_full_cdclW_iff_full_cdclW_merge:
  assumes confl: "conflicting  S = None" and lev: "cdclW_M_level_inv S"
  shows "full cdclW S V ⟷ full cdclW_merge_restart S V"
proof
  assume full: "full cdclW_merge_restart S V"
  then have st: "cdclW** S V"
    using rtranclp_mono[of cdclW_merge_restart "cdclW**"] cdclW_merge_restart_cdclW
    unfolding full_def by auto

  have n_s: "no_step cdclW_merge_restart V"
    using full unfolding full_def by auto
  have n_s_bj: "no_step cdclW_bj V"
    using rtranclp_cdclW_merge_restart_no_step_cdclW_bj confl full unfolding full_def by auto
  have "⋀S'. conflict V S' ⟹ cdclW_M_level_inv S'"
    using cdclW.conflict cdclW_consistent_inv lev rtranclp_cdclW_consistent_inv st by blast
  then have "⋀S'. conflict V S' ⟹ False"
    using n_s n_s_bj cdclW_bj_exists_normal_form cdclW_merge_restart.simps by meson
  then have n_s_cdclW: "no_step cdclW V"
    using n_s n_s_bj by (auto simp: cdclW.simps cdclW_o.simps cdclW_merge_restart.simps)
  then show "full cdclW S V" using st unfolding full_def by auto
next
  assume full: "full cdclW S V"
  have "no_step cdclW_merge_restart V"
    using full no_step_cdclW_no_step_cdclW_merge_restart unfolding full_def by blast
  moreover
    consider
        (fw) "cdclW_merge_restart** S V" and "conflicting V = None"
      | (bj) T U where
        "cdclW_merge_restart** S T" and
        "conflicting V ≠ None" and
        "conflict T U" and
        "cdclW_bj** U V"
      using full rtrancl_cdclW_conflicting_true_cdclW_merge_restart confl lev unfolding full_def
      by meson
    then have "cdclW_merge_restart** S V"
      proof cases
        case fw
        then show ?thesis by fast
      next
        case (bj T U)
        have "no_step cdclW_bj V"
          using full unfolding full_def by (meson cdclW_o.bj other)
        then have "full cdclW_bj U V"
          using ‹ cdclW_bj** U V› unfolding full_def by auto
        then have "cdclW_merge_restart T V"
          using ‹conflict T U› cdclW_merge_restart.fw_r_conflict by blast
        then show ?thesis using ‹cdclW_merge_restart** S T› by auto
      qed
  ultimately show "full cdclW_merge_restart S V" unfolding full_def by fast
qed

lemma init_state_true_full_cdclW_iff_full_cdclW_merge:
  shows "full cdclW (init_state N) V ⟷ full cdclW_merge_restart (init_state N) V"
  by (rule conflicting_true_full_cdclW_iff_full_cdclW_merge) auto

subsection ‹FW with strategy›
subsubsection ‹The intermediate step›
inductive cdclW_s' :: "'st ⇒ 'st ⇒ bool" where
conflict': "full1 cdclW_cp S S' ⟹ cdclW_s' S S'" |
decide': "decide S S' ⟹ no_step cdclW_cp S ⟹ full cdclW_cp S' S'' ⟹ cdclW_s' S S''" |
bj': "full1 cdclW_bj S S' ⟹ no_step cdclW_cp S ⟹ full cdclW_cp S' S'' ⟹ cdclW_s' S S''"

inductive_cases cdclW_s'E: "cdclW_s' S T"

lemma rtranclp_cdclW_bj_full1_cdclp_cdclW_stgy:
  "cdclW_bj** S S' ⟹ full cdclW_cp S' S'' ⟹ cdclW_stgy** S S''"
proof (induction rule: converse_rtranclp_induct)
  case base
  then show ?case by (metis cdclW_stgy.conflict' full_unfold rtranclp.simps)
next
  case (step T U) note st =this(2) and bj = this(1) and IH = this(3)[OF this(4)]
  have "no_step cdclW_cp T"
    using bj by (auto simp add: cdclW_bj.simps)
  consider
      (U) "U = S'"
    | (U') U' where "cdclW_bj U U'" and "cdclW_bj** U' S'"
    using st by (metis converse_rtranclpE)
  then show ?case
    proof cases
      case U
      then show ?thesis
        using ‹no_step cdclW_cp T› cdclW_o.bj local.bj other' step.prems by (meson r_into_rtranclp)
    next
      case U' note U' = this(1)
      have "no_step cdclW_cp U"
        using U' by (fastforce simp: cdclW_cp.simps cdclW_bj.simps)
      then have "full cdclW_cp U U"
        by (simp add: full_unfold)
      then have "cdclW_stgy T U"
        using ‹no_step cdclW_cp T› cdclW_stgy.simps local.bj cdclW_o.bj by meson
      then show ?thesis using IH by auto
    qed
qed

lemma cdclW_s'_is_rtranclp_cdclW_stgy:
  "cdclW_s' S T ⟹ cdclW_stgy** S T"
  apply (induction rule: cdclW_s'.induct)
    apply (auto intro: cdclW_stgy.intros)[]
   apply (meson decide other' r_into_rtranclp)
  by (metis full1_def rtranclp_cdclW_bj_full1_cdclp_cdclW_stgy tranclp_into_rtranclp)

lemma cdclW_cp_cdclW_bj_bissimulation:
  assumes
    "full cdclW_cp T U" and
    "cdclW_bj** T T'" and
    "cdclW_all_struct_inv T" and
    "no_step cdclW_bj T'"
  shows "full cdclW_cp T' U
    ∨ (∃U' U''. full cdclW_cp T' U'' ∧ full1 cdclW_bj U U' ∧ full cdclW_cp U' U'' ∧ cdclW_s'** U U'')"
  using assms(2,1,3,4)
proof (induction rule: rtranclp_induct)
  case base
  then show ?case by blast
next
  case (step T' T'') note st = this(1) and bj = this(2) and IH = this(3)[OF this(4,5)] and
    full = this(4) and inv = this(5)
  have "cdclW** T T''"
    by (metis (no_types, lifting) cdclW_o.bj local.bj mono_rtranclp[of cdclW_bj cdclW T T''] other
      st rtranclp.rtrancl_into_rtrancl)
  then have inv_T'': "cdclW_all_struct_inv T''"
    using inv rtranclp_cdclW_all_struct_inv_inv by blast
  have "cdclW_bj++ T T''"
    using local.bj st by auto
  have "full1 cdclW_bj T T''"
    by (metis ‹cdclW_bj++ T T''› full1_def step.prems(3))
  then have "T = U"
    proof -
      obtain Z where "cdclW_bj T Z"
          by (meson tranclpD ‹cdclW_bj++ T T''›)
      { assume "cdclW_cp++ T U"
        then obtain Z' where "cdclW_cp T Z'"
          by (meson tranclpD)
        then have False
          using ‹cdclW_bj T Z› by (fastforce simp: cdclW_bj.simps cdclW_cp.simps)
      }
      then show ?thesis
        using full unfolding full_def rtranclp_unfold by blast
    qed
  obtain U'' where "full cdclW_cp T'' U''"
    using cdclW_cp_normalized_element_all_inv inv_T'' by blast
  moreover then have "cdclW_stgy** U U''"
    by (metis ‹T = U› ‹cdclW_bj++ T T''› rtranclp_cdclW_bj_full1_cdclp_cdclW_stgy rtranclp_unfold)
  moreover have "cdclW_s'** U U''"
    proof -
      obtain ss :: "'st ⇒ 'st" where
        f1: "∀x2. (∃v3. cdclW_cp x2 v3) = cdclW_cp x2 (ss x2)"
        by moura
      have "¬ cdclW_cp U (ss U)"
        by (meson full full_def)
      then show ?thesis
        using f1 by (metis (no_types) ‹T = U› ‹full1 cdclW_bj T T''› bj' calculation(1)
          r_into_rtranclp)
    qed
  ultimately show ?case
    using ‹full1 cdclW_bj T T''› ‹full cdclW_cp T'' U''› unfolding ‹T = U› by blast
qed

lemma cdclW_cp_cdclW_bj_bissimulation':
  assumes
    "full cdclW_cp T U" and
    "cdclW_bj** T T'" and
    "cdclW_all_struct_inv T" and
    "no_step cdclW_bj T'"
  shows "full cdclW_cp T' U
    ∨ (∃U'. full1 cdclW_bj U U' ∧ (∀U''. full cdclW_cp U' U'' ⟶ full cdclW_cp T' U''
      ∧ cdclW_s'** U U''))"
  using assms(2,1,3,4)
proof (induction rule: rtranclp_induct)
  case base
  then show ?case by blast
next
  case (step T' T'') note st = this(1) and bj = this(2) and IH = this(3)[OF this(4,5)] and
    full = this(4) and inv = this(5)
  have "cdclW** T T''"
    by (metis (no_types, lifting) cdclW_o.bj local.bj mono_rtranclp[of cdclW_bj cdclW T T''] other st
      rtranclp.rtrancl_into_rtrancl)
  then have inv_T'': "cdclW_all_struct_inv T''"
    using inv rtranclp_cdclW_all_struct_inv_inv by blast
  have "cdclW_bj++ T T''"
    using local.bj st by auto
  have "full1 cdclW_bj T T''"
    by (metis ‹cdclW_bj++ T T''› full1_def step.prems(3))
  then have "T = U"
    proof -
      obtain Z where "cdclW_bj T Z"
        by (meson tranclpD ‹cdclW_bj++ T T''›)
      { assume "cdclW_cp++ T U"
        then obtain Z' where "cdclW_cp T Z'"
          by (meson tranclpD)
        then have False
          using ‹cdclW_bj T Z› by (fastforce simp: cdclW_bj.simps cdclW_cp.simps)
      }
      then show ?thesis
        using full unfolding full_def rtranclp_unfold by blast
    qed
  { fix U''
    assume "full cdclW_cp T'' U''"
    moreover then have "cdclW_stgy** U U''"
      by (metis ‹T = U› ‹cdclW_bj++ T T''› rtranclp_cdclW_bj_full1_cdclp_cdclW_stgy rtranclp_unfold)
    moreover have "cdclW_s'** U U''"
      proof -
        obtain ss :: "'st ⇒ 'st" where
          f1: "∀x2. (∃v3. cdclW_cp x2 v3) = cdclW_cp x2 (ss x2)"
          by moura
        have "¬ cdclW_cp U (ss U)"
          by (meson assms(1) full_def)
        then show ?thesis
          using f1 by (metis (no_types) ‹T = U› ‹full1 cdclW_bj T T''› bj' calculation(1)
            r_into_rtranclp)
      qed
    ultimately have "full1 cdclW_bj U T''" and " cdclW_s'** T'' U''"
      using ‹full1 cdclW_bj T T''› ‹full cdclW_cp T'' U''› unfolding ‹T = U›
        apply blast
      by (metis ‹full cdclW_cp T'' U''› cdclW_s'.simps full_unfold rtranclp.simps)
    }
  then show ?case
    using ‹full1 cdclW_bj T T''› full bj' unfolding ‹T = U› full_def by (metis r_into_rtranclp)
qed

lemma cdclW_stgy_cdclW_s'_connected:
  assumes "cdclW_stgy S U" and "cdclW_all_struct_inv S"
  shows "cdclW_s' S U
    ∨ (∃U'. full1 cdclW_bj U U' ∧ (∀U''. full cdclW_cp U' U'' ⟶ cdclW_s' S U'' ))"
  using assms
proof (induction rule: cdclW_stgy.induct)
  case (conflict' T)
  then have "cdclW_s' S T"
    using cdclW_s'.conflict' by blast
  then show ?case
    by blast
next
  case (other' T U) note o = this(1) and n_s = this(2) and full = this(3) and inv = this(4)
  show ?case
    using o
    proof cases
      case decide
      then show ?thesis using cdclW_s'.simps full n_s by blast
    next
      case bj
      have inv_T: "cdclW_all_struct_inv T"
        using cdclW_all_struct_inv_inv o other other'.prems by blast
      consider
          (cp) "full cdclW_cp T U" and "no_step cdclW_bj T"
        | (fbj) T' where "full1 cdclW_bj T T'"
        apply (cases "no_step cdclW_bj T")
         using full apply blast
        using cdclW_bj_exists_normal_form[of T] inv_T unfolding cdclW_all_struct_inv_def
        by (metis full_unfold)
      then show ?thesis
        proof cases
          case cp
          then show ?thesis
            proof -
              obtain ss :: "'st ⇒ 'st" where
                f1: "∀s sa sb. (¬ full1 cdclW_bj s sa ∨ cdclW_cp s (ss s) ∨ ¬ full cdclW_cp sa sb)
                  ∨ cdclW_s' s sb"
                using bj' by moura
              have "full1 cdclW_bj S T"
                by (simp add: cp(2) full1_def local.bj tranclp.r_into_trancl)
              then show ?thesis
                using f1 full n_s by blast
            qed
        next
          case (fbj U')
          then have "full1 cdclW_bj S U'"
            using bj unfolding full1_def by auto
          moreover have "no_step cdclW_cp S"
            using n_s by blast
          moreover have "T = U"
            using full fbj unfolding full1_def full_def rtranclp_unfold
            by (force dest!: tranclpD simp:cdclW_bj.simps)
          ultimately show ?thesis using cdclW_s'.bj'[of S U'] using fbj by blast
        qed
    qed
qed

lemma cdclW_stgy_cdclW_s'_connected':
  assumes "cdclW_stgy S U" and "cdclW_all_struct_inv S"
  shows "cdclW_s' S U
    ∨ (∃U' U''. cdclW_s' S U'' ∧ full1 cdclW_bj U U' ∧ full cdclW_cp U' U'')"
  using assms
proof (induction rule: cdclW_stgy.induct)
  case (conflict' T)
  then have "cdclW_s' S T"
    using cdclW_s'.conflict' by blast
  then show ?case
    by blast
next
  case (other' T U) note o = this(1) and n_s = this(2) and full = this(3) and inv = this(4)
  show ?case
    using o
    proof cases
      case decide
      then show ?thesis using cdclW_s'.simps full n_s by blast
    next
      case bj
      have "cdclW_all_struct_inv T"
        using cdclW_all_struct_inv_inv o other other'.prems by blast
      then obtain T' where T': "full cdclW_bj T T'"
        using cdclW_bj_exists_normal_form unfolding full_def cdclW_all_struct_inv_def by metis
      then have "full cdclW_bj S T'"
        proof -
          have f1: "cdclW_bj** T T' ∧ no_step cdclW_bj T'"
            by (metis (no_types) T' full_def)
          then have "cdclW_bj** S T'"
            by (meson converse_rtranclp_into_rtranclp local.bj)
          then show ?thesis
            using f1 by (simp add: full_def)
        qed
      have "cdclW_bj** T T'"
        using T' unfolding full_def by simp
      have "cdclW_all_struct_inv T"
        using cdclW_all_struct_inv_inv o other other'.prems by blast
      then consider
          (T'U) "full cdclW_cp T' U"
        | (U) U' U'' where
            "full cdclW_cp T' U''" and
            "full1 cdclW_bj U U'" and
            "full cdclW_cp U' U''" and
            "cdclW_s'** U U''"
        using cdclW_cp_cdclW_bj_bissimulation[OF full ‹cdclW_bj** T T'›] T' unfolding full_def
        by blast
      then show ?thesis by (metis T' cdclW_s'.simps full_fullI local.bj n_s)
    qed
qed

lemma cdclW_stgy_cdclW_s'_no_step:
  assumes "cdclW_stgy S U" and "cdclW_all_struct_inv S" and "no_step cdclW_bj U"
  shows "cdclW_s' S U"
  using cdclW_stgy_cdclW_s'_connected[OF assms(1,2)] assms(3)
  by (metis (no_types, lifting) full1_def tranclpD)

lemma rtranclp_cdclW_stgy_connected_to_rtranclp_cdclW_s':
  assumes "cdclW_stgy** S U" and inv: "cdclW_M_level_inv S"
  shows "cdclW_s'** S U ∨ (∃T. cdclW_s'** S T ∧ cdclW_bj++ T U ∧ conflicting U ≠ None)"
  using assms(1)
proof induction
  case base
  then show ?case by simp
next
  case (step T V) note st = this(1) and o = this(2) and IH = this(3)
  from o show ?case
    proof cases
      case conflict'
      then have f2: "cdclW_s' T V"
        using cdclW_s'.conflict' by blast
      obtain ss :: 'st where
        f3: "S = T ∨ cdclW_stgy** S ss ∧ cdclW_stgy ss T"
        by (metis (full_types) rtranclp.simps st)
      obtain ssa :: 'st where
        "cdclW_cp T ssa"
        using conflict' by (metis (no_types) full1_def tranclpD)
      then have "S = T"
        using f3 by (metis (no_types) cdclW_stgy.simps full_def full1_def)
      then show ?thesis
        using f2 by blast
    next
      case (other' U) note o = this(1) and n_s = this(2) and full = this(3)
      then show ?thesis
        using o
        proof (cases rule: cdclW_o_rule_cases)
          case decide
          then have "cdclW_s'** S T"
            using IH by auto
          then show ?thesis
            by (meson decide decide' full n_s rtranclp.rtrancl_into_rtrancl)
        next
          case backtrack
          consider
              (s') "cdclW_s'** S T"
            | (bj) S' where "cdclW_s'** S S'" and "cdclW_bj++ S' T" and "conflicting T ≠ None"
            using IH by blast
          then show ?thesis
            proof cases
              case s'
              moreover
                have "cdclW_M_level_inv T"
                  using inv local.step(1) rtranclp_cdclW_stgy_consistent_inv by auto
                then have "full1 cdclW_bj T U"
                  using backtrack_is_full1_cdclW_bj backtrack by blast
                then have "cdclW_s' T V"
                 using full bj' n_s by blast
              ultimately show ?thesis by auto
            next
              case (bj S') note S_S' = this(1) and bj_T = this(2)
              have "no_step cdclW_cp S'"
                using bj_T by (fastforce simp: cdclW_cp.simps cdclW_bj.simps dest!: tranclpD)
              moreover
                have " cdclW_M_level_inv T"
                  using inv local.step(1) rtranclp_cdclW_stgy_consistent_inv by auto
                then have "full1 cdclW_bj T U"
                  using backtrack_is_full1_cdclW_bj backtrack by blast
                then have "full1 cdclW_bj S' U"
                  using bj_T unfolding full1_def by fastforce
              ultimately have "cdclW_s' S' V" using full by (simp add: bj')
              then show ?thesis using S_S' by auto
            qed
        next
          case skip
          then have [simp]: "U = V"
            using full converse_rtranclpE unfolding full_def by fastforce

          consider
              (s') "cdclW_s'** S T"
            | (bj) S' where "cdclW_s'** S S'" and "cdclW_bj++ S' T" and "conflicting T ≠ None"
            using IH by blast
          then show ?thesis
            proof cases
              case s'
              have "cdclW_bj++ T V"
                using skip by force
              moreover have "conflicting V ≠ None"
                using skip by auto
              ultimately show ?thesis using s' by auto
            next
              case (bj S') note S_S' = this(1) and bj_T = this(2)
              have "cdclW_bj++ S' V"
                using skip bj_T by (metis ‹U = V› cdclW_bj.skip tranclp.simps)

              moreover have "conflicting V ≠ None"
                using skip by auto
              ultimately show ?thesis using S_S' by auto
            qed
        next
          case resolve
          then have [simp]: "U = V"
            using full converse_rtranclpE unfolding full_def by fastforce
          consider
              (s') "cdclW_s'** S T"
            | (bj) S' where "cdclW_s'** S S'" and "cdclW_bj++ S' T" and "conflicting T ≠ None"
            using IH by blast
          then show ?thesis
            proof cases
              case s'
              have "cdclW_bj++ T V"
                using resolve by force
              moreover have "conflicting V ≠ None"
                using resolve by auto
              ultimately show ?thesis using s' by auto
            next
              case (bj S') note S_S' = this(1) and bj_T = this(2)
              have "cdclW_bj++ S' V"
                using resolve  bj_T by (metis ‹U = V› cdclW_bj.resolve tranclp.simps)
              moreover have "conflicting V ≠ None"
                using resolve by auto
              ultimately show ?thesis using S_S' by auto
            qed
        qed
    qed
qed

lemma n_step_cdclW_stgy_iff_no_step_cdclW_cl_cdclW_o:
  assumes inv: "cdclW_all_struct_inv S"
  shows "no_step cdclW_s' S ⟷ no_step cdclW_cp S ∧ no_step cdclW_o S" (is "?S' S ⟷ ?C S ∧ ?O S")
proof
  assume "?C S ∧ ?O S"
  then show "?S' S"
    by (auto simp: cdclW_s'.simps full1_def tranclp_unfold_begin)
next
  assume n_s: "?S' S"
  have "?C S"
    proof (rule ccontr)
      assume "¬ ?thesis"
      then obtain S' where "cdclW_cp S S'"
        by auto
      then obtain T where "full1 cdclW_cp S T"
        using cdclW_cp_normalized_element_all_inv inv by (metis (no_types, lifting) full_unfold)
      then show False using n_s cdclW_s'.conflict' by blast
    qed
  moreover have "?O S"
    proof (rule ccontr)
      assume "¬ ?thesis"
      then obtain S' where "cdclW_o S S'"
        by auto
      then obtain T where "full1 cdclW_cp S' T"
        using cdclW_cp_normalized_element_all_inv inv
        by (meson cdclW_all_struct_inv_def n_s
          cdclW_stgy_cdclW_s'_connected' cdclW_then_exists_cdclW_stgy_step )
      then show False using n_s by (meson ‹cdclW_o S S'› cdclW_all_struct_inv_def
        cdclW_stgy_cdclW_s'_connected' cdclW_then_exists_cdclW_stgy_step inv)
    qed
  ultimately show "?C S ∧ ?O S" by auto
qed

lemma cdclW_s'_tranclp_cdclW:
   "cdclW_s' S S' ⟹ cdclW++ S S'"
proof (induct rule: cdclW_s'.induct)
  case conflict'
  then show ?case
    by (simp add: full1_def tranclp_cdclW_cp_tranclp_cdclW)
next
  case decide'
  then show ?case
    using cdclW_stgy.simps cdclW_stgy_tranclp_cdclW by (meson cdclW_o.simps)
next
  case (bj' Sa S'a S'') note a2 = this(1) and a1 = this(2) and n_s = this(3)
  obtain ss :: "'st ⇒ 'st ⇒ ('st ⇒ 'st ⇒ bool) ⇒ 'st" where
    "∀x0 x1 x2. (∃v3. x2 x1 v3 ∧ x2** v3 x0) = (x2 x1 (ss x0 x1 x2) ∧ x2** (ss x0 x1 x2) x0)"
    by moura
  then have f3: "∀p s sa. ¬ p++ s sa ∨ p s (ss sa s p) ∧ p** (ss sa s p) sa"
    by (metis (full_types) tranclpD)
  have "cdclW_bj++ Sa S'a ∧ no_step cdclW_bj S'a"
    using a2 by (simp add: full1_def)
  then have "cdclW_bj Sa (ss S'a Sa cdclW_bj) ∧ cdclW_bj** (ss S'a Sa cdclW_bj) S'a"
    using f3 by auto
  then show "cdclW++ Sa S''"
    using a1 n_s by (meson bj other rtranclp_cdclW_bj_full1_cdclp_cdclW_stgy
      rtranclp_cdclW_stgy_rtranclp_cdclW rtranclp_into_tranclp2)
qed

lemma tranclp_cdclW_s'_tranclp_cdclW:
  "cdclW_s'++ S S' ⟹ cdclW++ S S'"
  apply (induct rule: tranclp.induct)
   using cdclW_s'_tranclp_cdclW apply blast
  by (meson cdclW_s'_tranclp_cdclW tranclp_trans)

lemma rtranclp_cdclW_s'_rtranclp_cdclW:
   "cdclW_s'** S S' ⟹ cdclW** S S'"
  using rtranclp_unfold[of cdclW_s' S S'] tranclp_cdclW_s'_tranclp_cdclW[of S S'] by auto

lemma full_cdclW_stgy_iff_full_cdclW_s':
  assumes inv: "cdclW_all_struct_inv S"
  shows "full cdclW_stgy S T ⟷ full cdclW_s' S T" (is "?S ⟷ ?S'")
proof
  assume ?S'
  then have "cdclW** S T"
    using rtranclp_cdclW_s'_rtranclp_cdclW[of S T] unfolding full_def by blast
  then have inv': "cdclW_all_struct_inv T"
    using rtranclp_cdclW_all_struct_inv_inv inv by blast
  have "cdclW_stgy** S T"
    using ‹?S'› unfolding full_def
      using cdclW_s'_is_rtranclp_cdclW_stgy rtranclp_mono[of cdclW_s' "cdclW_stgy**"] by auto
  then show ?S
    using ‹?S'› inv' cdclW_stgy_cdclW_s'_connected' unfolding full_def by blast
next
  assume ?S
  then have inv_T:"cdclW_all_struct_inv T"
    by (metis assms full_def rtranclp_cdclW_all_struct_inv_inv rtranclp_cdclW_stgy_rtranclp_cdclW)

  consider
      (s')  "cdclW_s'** S T"
    | (st) S' where "cdclW_s'** S S'" and "cdclW_bj++ S' T" and "conflicting T ≠ None"
    using rtranclp_cdclW_stgy_connected_to_rtranclp_cdclW_s'[of S T] inv ‹?S›
    unfolding full_def  cdclW_all_struct_inv_def
    by blast
  then show ?S'
    proof cases
      case s'
      then show ?thesis
        by (metis ‹full cdclW_stgy S T› inv_T cdclW_all_struct_inv_def cdclW_s'.simps
          cdclW_stgy.conflict'  cdclW_then_exists_cdclW_stgy_step full_def
          n_step_cdclW_stgy_iff_no_step_cdclW_cl_cdclW_o)
    next
      case (st S')
      have "full cdclW_cp T T"
        using option_full_cdclW_cp st(3) by blast
      moreover
        have n_s: "no_step cdclW_bj T"
          by (metis ‹full cdclW_stgy S T› bj inv_T cdclW_all_struct_inv_def
            cdclW_then_exists_cdclW_stgy_step full_def)
        then have "full1 cdclW_bj S' T"
          using st(2) unfolding full1_def by blast
      moreover have "no_step cdclW_cp S'"
        using st(2) by (fastforce dest!: tranclpD simp: cdclW_cp.simps cdclW_bj.simps)
      ultimately have "cdclW_s' S' T"
        using cdclW_s'.bj'[of S' T T] by blast
      then have "cdclW_s'** S T"
        using st(1) by auto
      moreover have "no_step cdclW_s' T"
        using inv_T by (metis ‹full cdclW_cp T T› ‹full cdclW_stgy S T› cdclW_all_struct_inv_def
          cdclW_then_exists_cdclW_stgy_step full_def n_step_cdclW_stgy_iff_no_step_cdclW_cl_cdclW_o)
      ultimately show ?thesis
        unfolding full_def by blast
    qed
qed

lemma conflict_step_cdclW_stgy_step:
  assumes
    "conflict S T"
    "cdclW_all_struct_inv S"
  shows "∃T. cdclW_stgy S T"
proof -
  obtain U where "full cdclW_cp S U"
    using cdclW_cp_normalized_element_all_inv assms by blast
  then have "full1 cdclW_cp S U"
    by (metis cdclW_cp.conflict' assms(1) full_unfold)
  then show ?thesis using cdclW_stgy.conflict' by blast
qed

lemma decide_step_cdclW_stgy_step:
  assumes
    "decide S T"
    "cdclW_all_struct_inv S"
  shows "∃T. cdclW_stgy S T"
proof -
  obtain U where "full cdclW_cp T U"
    using cdclW_cp_normalized_element_all_inv by (meson assms(1) assms(2) cdclW_all_struct_inv_inv
      cdclW_cp_normalized_element_all_inv decide other)
  then show ?thesis
    by (metis assms cdclW_cp_normalized_element_all_inv cdclW_stgy.conflict' decide full_unfold
      other')
qed

lemma rtranclp_cdclW_cp_conflicting_Some:
  "cdclW_cp** S T ⟹ conflicting S = Some D ⟹ S = T"
  using rtranclpD tranclpD by fastforce

inductive cdclW_merge_cp :: "'st ⇒ 'st ⇒ bool" where
conflict'[intro]: "conflict S T ⟹ full cdclW_bj T U ⟹ cdclW_merge_cp S U" |
propagate'[intro]: "propagate++ S S' ⟹ cdclW_merge_cp S S'"

lemma cdclW_merge_restart_cases[consumes 1, case_names conflict propagate]:
  assumes
    "cdclW_merge_cp S U" and
    "⋀T. conflict S T ⟹ full cdclW_bj T U ⟹ P" and
    "propagate++ S U ⟹ P"
  shows "P"
  using assms unfolding cdclW_merge_cp.simps by auto

lemma cdclW_merge_cp_tranclp_cdclW_merge:
  "cdclW_merge_cp S T ⟹ cdclW_merge++ S T"
  apply (induction rule: cdclW_merge_cp.induct)
    using cdclW_merge.simps apply auto[1]
  using tranclp_mono[of propagate cdclW_merge] fw_propagate by blast

lemma rtranclp_cdclW_merge_cp_rtranclp_cdclW:
  "cdclW_merge_cp** S T ⟹ cdclW** S T"
 apply (induction rule: rtranclp_induct)
  apply simp
 unfolding cdclW_merge_cp.simps by (meson cdclW_merge_restart_cdclW fw_r_conflict
   rtranclp_propagate_is_rtranclp_cdclW rtranclp_trans tranclp_into_rtranclp)

lemma full1_cdclW_bj_no_step_cdclW_bj:
  "full1 cdclW_bj S T ⟹ no_step cdclW_cp S"
  by (metis rtranclp_unfold cdclW_cp_conflicting_not_empty option.exhaust full1_def
    rtranclp_cdclW_merge_restart_no_step_cdclW_bj tranclpD)

inductive cdclW_s'_without_decide where
conflict'_without_decide[intro]: "full1 cdclW_cp S S' ⟹ cdclW_s'_without_decide S S'" |
bj'_without_decide[intro]: "full1 cdclW_bj S S' ⟹ no_step cdclW_cp S ⟹ full cdclW_cp S' S''
      ⟹ cdclW_s'_without_decide S S''"

lemma rtranclp_cdclW_s'_without_decide_rtranclp_cdclW:
  "cdclW_s'_without_decide** S T ⟹ cdclW** S T"
  apply (induction rule: rtranclp_induct)
    apply simp
  by (meson cdclW_s'.simps cdclW_s'_tranclp_cdclW cdclW_s'_without_decide.simps
    rtranclp_tranclp_tranclp tranclp_into_rtranclp)

lemma rtranclp_cdclW_s'_without_decide_rtranclp_cdclW_s':
  "cdclW_s'_without_decide** S T ⟹ cdclW_s'** S T"
proof (induction rule: rtranclp_induct)
  case base
  then show ?case by simp
next
  case (step y z) note a2 = this(2) and a1 = this(3)
  have "cdclW_s' y z"
    using a2 by (metis (no_types) bj' cdclW_s'.conflict' cdclW_s'_without_decide.cases)
  then show "cdclW_s'** S z"
    using a1 by (meson r_into_rtranclp rtranclp_trans)
qed

lemma rtranclp_cdclW_merge_cp_is_rtranclp_cdclW_s'_without_decide:
  assumes
    "cdclW_merge_cp** S V"
    "conflicting S = None"
  shows
    "(cdclW_s'_without_decide** S V)
    ∨ (∃T. cdclW_s'_without_decide** S T ∧ propagate++ T V)
    ∨ (∃T U. cdclW_s'_without_decide** S T ∧ full1 cdclW_bj T U ∧ propagate** U V)"
  using assms
proof (induction rule: rtranclp_induct)
  case base
  then show ?case by simp
next
  case (step U V) note st = this(1) and cp = this(2) and IH = this(3)[OF this(4)]
  from cp show ?case
    proof (cases rule: cdclW_merge_restart_cases)
      case propagate
      then show ?thesis using IH by (meson rtranclp_tranclp_tranclp tranclp_into_rtranclp)
    next
      case (conflict U') note confl = this(1) and bj = this(2)
      have full1_U_U': "full1 cdclW_cp U U'"
        by (simp add: conflict_is_full1_cdclW_cp local.conflict(1))
      consider
          (s') "cdclW_s'_without_decide** S U"
        | (propa) T' where "cdclW_s'_without_decide** S T'" and "propagate++ T' U"
        | (bj_prop) T' T'' where
            "cdclW_s'_without_decide** S T' " and
            "full1 cdclW_bj T' T''" and
            "propagate** T'' U"
        using IH by blast
      then show ?thesis
        proof cases
          case s'
          have "cdclW_s'_without_decide U U'"
           using full1_U_U' conflict'_without_decide by blast
          then have "cdclW_s'_without_decide** S U'"
            using  ‹cdclW_s'_without_decide** S U› by auto
          moreover have "U' = V ∨ full1 cdclW_bj U' V"
            using bj by (meson full_unfold)
          ultimately show ?thesis by blast
        next
          case propa note s' = this(1) and T'_U = this(2)
          have "full1 cdclW_cp T' U'"
            using rtranclp_mono[of propagate cdclW_cp] T'_U cdclW_cp.propagate' full1_U_U'
            rtranclp_full1I[of cdclW_cp T'] by (metis (full_types) predicate2D predicate2I
              tranclp_into_rtranclp)
          have "cdclW_s'_without_decide** S U'"
            using ‹full1 cdclW_cp T' U'› conflict'_without_decide s' by force
          have "full1 cdclW_bj U' V ∨ V = U'"
            by (metis (lifting) full_unfold local.bj)
          then show ?thesis
            using ‹cdclW_s'_without_decide** S U'› by blast
        next
          case bj_prop note s' = this(1) and bj_T' = this(2) and T''_U = this(3)
          have "no_step cdclW_cp T'"
            using bj_T' full1_cdclW_bj_no_step_cdclW_bj by blast
          moreover have "full1 cdclW_cp T'' U'"
            using rtranclp_mono[of propagate cdclW_cp] T''_U cdclW_cp.propagate' full1_U_U'
            rtranclp_full1I[of cdclW_cp T''] by blast
          ultimately have "cdclW_s'_without_decide T' U'"
            using bj'_without_decide[of T' T'' U'] bj_T' by (simp add: full_unfold)
          then have "cdclW_s'_without_decide** S U'"
            using s' rtranclp.intros(2)[of _ S T' U'] by blast
          then show ?thesis
            by (metis full_unfold local.bj rtranclp.rtrancl_refl)
        qed
    qed
qed


lemma rtranclp_cdclW_s'_without_decide_is_rtranclp_cdclW_merge_cp:
  assumes
    "cdclW_s'_without_decide** S V" and
    confl: "conflicting S = None"
  shows
    "(cdclW_merge_cp** S V ∧ conflicting V = None)
    ∨ (cdclW_merge_cp** S V ∧ conflicting V ≠ None ∧ no_step cdclW_cp V ∧ no_step cdclW_bj V)
    ∨ (∃T. cdclW_merge_cp** S T ∧ conflict T V)"
  using assms(1)
proof (induction)
  case base
  then show ?case using confl by auto
next
  case (step U V) note st = this(1) and s = this(2) and IH = this(3)
  from s show ?case
    proof (cases rule: cdclW_s'_without_decide.cases)
      case conflict'_without_decide
      then have rt: "cdclW_cp++ U V"  unfolding full1_def by fast
      then have "conflicting U = None"
        using tranclp_cdclW_cp_propagate_with_conflict_or_not[of U V]
        conflict by (auto dest!: tranclpD simp: rtranclp_unfold)
      then have "cdclW_merge_cp** S U" using IH by auto
      consider
          (propa) "propagate++ U V"
         | (confl') "conflict U V"
         | (propa_confl') U' where "propagate++ U U'" "conflict U' V"
        using tranclp_cdclW_cp_propagate_with_conflict_or_not[OF rt] unfolding rtranclp_unfold
        by fastforce
      then show ?thesis
        proof cases
          case propa
          then have "cdclW_merge_cp U V"
            by auto
          moreover have "conflicting V = None"
            using propa unfolding tranclp_unfold_end by auto
          ultimately show ?thesis using ‹cdclW_merge_cp** S U› by force
        next
          case confl'
          then show ?thesis using ‹cdclW_merge_cp** S U› by auto
        next
          case propa_confl' note propa = this(1) and confl' = this(2)
          then have "cdclW_merge_cp U U'" by auto
          then have "cdclW_merge_cp** S U'" using ‹cdclW_merge_cp** S U› by auto
          then show ?thesis using ‹cdclW_merge_cp** S U› confl' by auto
        qed
    next
      case (bj'_without_decide U') note full_bj = this(1) and cp = this(3)
      then have "conflicting U ≠ None"
        using full_bj unfolding full1_def by (fastforce dest!: tranclpD simp: cdclW_bj.simps)
      with IH obtain T where
        S_T: "cdclW_merge_cp** S T" and T_U: "conflict T U"
        using full_bj unfolding full1_def by (blast dest: tranclpD)
      then have "cdclW_merge_cp T U'"
        using cdclW_merge_cp.conflict'[of T U U'] full_bj by (simp add: full_unfold)
      then have S_U': "cdclW_merge_cp** S U'" using S_T by auto
      consider
          (n_s) "U' = V"
         | (propa) "propagate++ U' V"
         | (confl') "conflict U' V"
         | (propa_confl') U'' where "propagate++ U' U''" "conflict U'' V"
        using tranclp_cdclW_cp_propagate_with_conflict_or_not cp
        unfolding rtranclp_unfold full_def by metis
      then show ?thesis
        proof cases
          case propa
          then have "cdclW_merge_cp U' V" by auto
          moreover have "conflicting V = None"
            using propa  unfolding tranclp_unfold_end by auto
          ultimately show ?thesis using S_U' by force
        next
          case confl'
          then show ?thesis using S_U' by auto
        next
          case propa_confl' note propa = this(1) and confl = this(2)
          have "cdclW_merge_cp U' U''" using propa by auto
          then show ?thesis using S_U' confl by (meson rtranclp.rtrancl_into_rtrancl)
        next
          case n_s
          then show ?thesis
            using S_U' apply (cases "conflicting V = None")
             using full_bj apply simp
            by (metis cp full_def full_unfold full_bj)
        qed
    qed
qed

lemma no_step_cdclW_s'_no_ste_cdclW_merge_cp:
  assumes
    "cdclW_all_struct_inv S"
    "conflicting S = None"
    "no_step cdclW_s' S"
  shows "no_step cdclW_merge_cp S"
  using assms apply (auto simp: cdclW_s'.simps cdclW_merge_cp.simps)
    using conflict_is_full1_cdclW_cp apply blast
  using cdclW_cp_normalized_element_all_inv cdclW_cp.propagate' by (metis cdclW_cp.propagate'
    full_unfold tranclpD)

text ‹The @{term "no_step decide S"} is needed, since @{term "cdclW_merge_cp"} is
  @{term "cdclW_s'"} without @{term decide}.›
lemma conflicting_true_no_step_cdclW_merge_cp_no_step_s'_without_decide:
  assumes
    confl: "conflicting S = None" and
    inv: "cdclW_M_level_inv S" and
    n_s: "no_step cdclW_merge_cp S"
  shows "no_step cdclW_s'_without_decide S"
proof (rule ccontr)
  assume "¬ no_step cdclW_s'_without_decide S"
  then obtain T where
    cdclW: "cdclW_s'_without_decide S T"
    by auto
  then have inv_T: "cdclW_M_level_inv T"
    using rtranclp_cdclW_s'_without_decide_rtranclp_cdclW[of S T]
    rtranclp_cdclW_consistent_inv inv by blast
  from cdclW show False
    proof cases
      case conflict'_without_decide
      have "no_step propagate S"
        using n_s by blast
      then have "conflict S T"
        using local.conflict' tranclp_cdclW_cp_propagate_with_conflict_or_not[of S T]
        unfolding full1_def by (metis full1_def local.conflict'_without_decide rtranclp_unfold
          tranclp_unfold_begin)
      moreover
        then obtain T' where "full cdclW_bj T T'"
          using cdclW_bj_exists_normal_form inv_T by blast
      ultimately show False using cdclW_merge_cp.conflict' n_s by meson
    next
      case (bj'_without_decide S')
      then show ?thesis
        using confl unfolding full1_def by (fastforce simp: cdclW_bj.simps dest: tranclpD)
    qed
qed

lemma conflicting_true_no_step_s'_without_decide_no_step_cdclW_merge_cp:
  assumes
    inv: "cdclW_all_struct_inv S" and
    n_s: "no_step cdclW_s'_without_decide S"
  shows "no_step cdclW_merge_cp S"
proof (rule ccontr)
  assume "¬ ?thesis"
  then obtain T where "cdclW_merge_cp S T"
    by auto
  then show False
    proof cases
      case (conflict' S')
      then show False using n_s conflict'_without_decide conflict_is_full1_cdclW_cp by blast
    next
      case propagate'
      moreover
        have "cdclW_all_struct_inv T"
          using inv by (meson local.propagate' rtranclp_cdclW_all_struct_inv_inv
            rtranclp_propagate_is_rtranclp_cdclW tranclp_into_rtranclp)
        then obtain U where "full cdclW_cp T U"
          using cdclW_cp_normalized_element_all_inv by auto
      ultimately have "full1 cdclW_cp S U"
        using tranclp_full_full1I[of cdclW_cp S T U] cdclW_cp.propagate'
        tranclp_mono[of propagate cdclW_cp] by blast
      then show False using conflict'_without_decide n_s by blast
    qed
qed

lemma no_step_cdclW_merge_cp_no_step_cdclW_cp:
  "no_step cdclW_merge_cp S ⟹ cdclW_M_level_inv S ⟹ no_step cdclW_cp S"
  using cdclW_bj_exists_normal_form cdclW_consistent_inv[OF cdclW.conflict, of S]
  by (metis cdclW_cp.cases cdclW_merge_cp.simps tranclp.intros(1))

lemma conflicting_not_true_rtranclp_cdclW_merge_cp_no_step_cdclW_bj:
  assumes
    "conflicting S = None" and
    "cdclW_merge_cp** S T"
  shows "no_step cdclW_bj T"
  using assms(2,1) by (induction)
  (fastforce simp: cdclW_merge_cp.simps full_def tranclp_unfold_end cdclW_bj.simps)+

lemma conflicting_true_full_cdclW_merge_cp_iff_full_cdclW_s'_without_decode:
  assumes
    confl: "conflicting S = None" and
    inv: "cdclW_all_struct_inv S"
  shows
    "full cdclW_merge_cp S V ⟷ full cdclW_s'_without_decide S V" (is "?fw ⟷ ?s'")
proof
  assume ?fw
  then have st: "cdclW_merge_cp** S V" and n_s: "no_step cdclW_merge_cp V"
    unfolding full_def by blast+
  have inv_V: "cdclW_all_struct_inv V"
    using rtranclp_cdclW_merge_cp_rtranclp_cdclW[of S V] ‹?fw› unfolding full_def
    by (simp add: inv rtranclp_cdclW_all_struct_inv_inv)
  consider
      (s') "cdclW_s'_without_decide** S V"
    | (propa) T where "cdclW_s'_without_decide** S T" and "propagate++ T V"
    | (bj) T U where "cdclW_s'_without_decide** S T" and "full1 cdclW_bj T U" and "propagate** U V"
    using rtranclp_cdclW_merge_cp_is_rtranclp_cdclW_s'_without_decide confl st n_s by metis
  then have "cdclW_s'_without_decide** S V"
    proof cases
      case s'
      then show ?thesis .
    next
      case propa note s' = this(1) and propa = this(2)
      have "no_step cdclW_cp V"
        using no_step_cdclW_merge_cp_no_step_cdclW_cp n_s inv_V
        unfolding cdclW_all_struct_inv_def by blast
      then have "full1 cdclW_cp T V"
        using propa tranclp_mono[of propagate cdclW_cp] "cdclW_cp.propagate'" unfolding full1_def
        by blast
      then have "cdclW_s'_without_decide T V"
        using conflict'_without_decide by blast
      then show ?thesis using s' by auto
    next
      case bj note s' = this(1) and bj = this(2) and propa = this(3)
      have "no_step cdclW_cp V"
        using no_step_cdclW_merge_cp_no_step_cdclW_cp n_s inv_V
        unfolding cdclW_all_struct_inv_def by blast
      then have "full cdclW_cp U V"
        using propa rtranclp_mono[of propagate cdclW_cp] cdclW_cp.propagate' unfolding full_def
        by blast
      moreover have "no_step cdclW_cp T"
        using bj unfolding full1_def by (fastforce dest!: tranclpD simp:cdclW_bj.simps)
      ultimately have "cdclW_s'_without_decide T V"
        using bj'_without_decide[of T U V] bj by blast
      then show ?thesis using s' by auto
    qed
  moreover have "no_step cdclW_s'_without_decide V"
    proof (cases "conflicting V = None")
      case False
      { fix ss :: 'st
        have ff1: "∀s sa. ¬ cdclW_s' s sa ∨ full1 cdclW_cp s sa
          ∨ (∃sb. decide s sb ∧ no_step cdclW_cp s ∧ full cdclW_cp sb sa)
          ∨ (∃sb. full1 cdclW_bj s sb ∧ no_step cdclW_cp s ∧ full cdclW_cp sb sa)"
          by (metis cdclW_s'.cases)
        have ff2: "(∀p s sa. ¬ full1 p (s::'st) sa ∨ p++ s sa ∧ no_step p sa)
          ∧ (∀p s sa. (¬ p++ (s::'st) sa ∨ (∃s. p sa s)) ∨ full1 p s sa)"
          by (meson full1_def)
        obtain ssa :: "('st ⇒ 'st ⇒ bool) ⇒ 'st ⇒ 'st ⇒ 'st" where
          ff3: "∀p s sa. ¬ p++ s sa ∨ p s (ssa p s sa) ∧ p** (ssa p s sa) sa"
          by (metis (no_types) tranclpD)
        then have a3: "¬ cdclW_cp++ V ss"
          using False by (metis option_full_cdclW_cp full_def)
        have "⋀s. ¬ cdclW_bj++ V s"
          using ff3 False by (metis confl st
            conflicting_not_true_rtranclp_cdclW_merge_cp_no_step_cdclW_bj)
        then have "¬ cdclW_s'_without_decide V ss"
          using ff1 a3 ff2 by (metis cdclW_s'_without_decide.cases)
      }
      then show ?thesis
        by fastforce
      next
        case True
        then show ?thesis
          using conflicting_true_no_step_cdclW_merge_cp_no_step_s'_without_decide n_s inv_V
          unfolding cdclW_all_struct_inv_def by blast
    qed
  ultimately show ?s' unfolding full_def by blast
next
  assume s': ?s'
  then have st: "cdclW_s'_without_decide** S V" and n_s: "no_step cdclW_s'_without_decide V"
    unfolding full_def by auto
  then have "cdclW** S V"
    using rtranclp_cdclW_s'_without_decide_rtranclp_cdclW st by blast
  then have inv_V: "cdclW_all_struct_inv V" using inv rtranclp_cdclW_all_struct_inv_inv by blast
  then have n_s_cp_V: "no_step cdclW_cp V"
    using cdclW_cp_normalized_element_all_inv[of V] full_fullI[of cdclW_cp V] n_s
    conflict'_without_decide conflicting_true_no_step_s'_without_decide_no_step_cdclW_merge_cp
    no_step_cdclW_merge_cp_no_step_cdclW_cp
    unfolding cdclW_all_struct_inv_def by presburger
  have n_s_bj: "no_step cdclW_bj V"
    proof (rule ccontr)
      assume "¬ ?thesis"
      then obtain W where W: "cdclW_bj V W" by blast
      have "cdclW_all_struct_inv W"
        using W cdclW.simps cdclW_all_struct_inv_inv inv_V by blast
      then obtain W' where "full1 cdclW_bj V W'"
        using cdclW_bj_exists_normal_form[of W] full_fullI[of cdclW_bj V W]  W
        unfolding cdclW_all_struct_inv_def
        by blast
      moreover
        then have "cdclW++ V W'"
          using tranclp_mono[of cdclW_bj cdclW] cdclW.other cdclW_o.bj unfolding full1_def by blast
        then have "cdclW_all_struct_inv W'"
          by (meson inv_V rtranclp_cdclW_all_struct_inv_inv tranclp_into_rtranclp)
        then obtain X where "full cdclW_cp W' X"
          using cdclW_cp_normalized_element_all_inv by blast
      ultimately show False
        using bj'_without_decide n_s_cp_V n_s by blast
    qed
  from s' consider
      (cp_true) "cdclW_merge_cp** S V" and "conflicting V = None"
    | (cp_false) "cdclW_merge_cp** S V" and "conflicting V ≠ None" and "no_step cdclW_cp V" and
         "no_step cdclW_bj V"
    | (cp_confl) T where "cdclW_merge_cp** S T" "conflict T V"
    using rtranclp_cdclW_s'_without_decide_is_rtranclp_cdclW_merge_cp[of S V] confl
    unfolding full_def by meson
  then have "cdclW_merge_cp** S V"
    proof cases
      case cp_confl note S_T = this(1) and conf_V = this(2)
      have "full cdclW_bj V V"
        using conf_V n_s_bj unfolding full_def by fast
      then have "cdclW_merge_cp T V"
        using cdclW_merge_cp.conflict' conf_V by auto
      then show ?thesis using S_T by auto
    qed fast+
  moreover
    then have "cdclW** S V" using rtranclp_cdclW_merge_cp_rtranclp_cdclW by blast
    then have "cdclW_all_struct_inv V"
      using inv rtranclp_cdclW_all_struct_inv_inv by blast
    then have "no_step cdclW_merge_cp V"
      using conflicting_true_no_step_s'_without_decide_no_step_cdclW_merge_cp s'
      unfolding full_def by blast
  ultimately show ?fw unfolding full_def by auto
qed

lemma conflicting_true_full1_cdclW_merge_cp_iff_full1_cdclW_s'_without_decode:
  assumes
    confl: "conflicting S = None" and
    inv: "cdclW_all_struct_inv S"
  shows
    "full1 cdclW_merge_cp S V ⟷ full1 cdclW_s'_without_decide S V"
proof -
  have "full cdclW_merge_cp S V = full cdclW_s'_without_decide S V"
    using confl conflicting_true_full_cdclW_merge_cp_iff_full_cdclW_s'_without_decode inv
    by blast
  then show ?thesis unfolding full_unfold full1_def
    by (metis (mono_tags) tranclp_unfold_begin)
qed

lemma conflicting_true_full1_cdclW_merge_cp_imp_full1_cdclW_s'_without_decode:
  assumes
    fw: "full1 cdclW_merge_cp S V" and
    inv: "cdclW_all_struct_inv S"
  shows
    "full1 cdclW_s'_without_decide S V"
proof -
  have "conflicting S = None"
    using fw unfolding full1_def by (auto dest!: tranclpD simp: cdclW_merge_cp.simps)
  then show ?thesis
    using conflicting_true_full1_cdclW_merge_cp_iff_full1_cdclW_s'_without_decode fw inv by blast
qed

inductive cdclW_merge_stgy where
fw_s_cp[intro]: "full1 cdclW_merge_cp S T ⟹ cdclW_merge_stgy S T" |
fw_s_decide[intro]: "decide S T ⟹ no_step cdclW_merge_cp S ⟹ full cdclW_merge_cp T U
  ⟹  cdclW_merge_stgy S U"

lemma cdclW_merge_stgy_tranclp_cdclW_merge:
  assumes fw: "cdclW_merge_stgy S T"
  shows "cdclW_merge++ S T"
proof -
  { fix S T
    assume "full1 cdclW_merge_cp S T"
    then have "cdclW_merge++ S T"
      using tranclp_mono[of cdclW_merge_cp "cdclW_merge++"] cdclW_merge_cp_tranclp_cdclW_merge
      unfolding full1_def
      by auto
  } note full1_cdclW_merge_cp_cdclW_merge = this
  show ?thesis
    using fw
    apply (induction rule: cdclW_merge_stgy.induct)
      using full1_cdclW_merge_cp_cdclW_merge apply simp
    unfolding full_unfold by (auto dest!: full1_cdclW_merge_cp_cdclW_merge fw_decide)
qed

lemma rtranclp_cdclW_merge_stgy_rtranclp_cdclW_merge:
  assumes fw: "cdclW_merge_stgy** S T"
  shows "cdclW_merge** S T"
  using fw cdclW_merge_stgy_tranclp_cdclW_merge rtranclp_mono[of cdclW_merge_stgy "cdclW_merge++"]
  unfolding tranclp_rtranclp_rtranclp by blast

lemma cdclW_merge_stgy_rtranclp_cdclW:
  "cdclW_merge_stgy S T ⟹ cdclW** S T"
  apply (induction rule: cdclW_merge_stgy.induct)
    using rtranclp_cdclW_merge_cp_rtranclp_cdclW unfolding full1_def
    apply (simp add: tranclp_into_rtranclp)
  using rtranclp_cdclW_merge_cp_rtranclp_cdclW cdclW_o.decide cdclW.other unfolding full_def
  by (meson r_into_rtranclp rtranclp_trans)

lemma rtranclp_cdclW_merge_stgy_rtranclp_cdclW:
  "cdclW_merge_stgy** S T ⟹ cdclW** S T"
  using rtranclp_mono[of cdclW_merge_stgy "cdclW**"] cdclW_merge_stgy_rtranclp_cdclW by auto

lemma cdclW_merge_stgy_cases[consumes 1, case_names fw_s_cp fw_s_decide]:
  assumes
    "cdclW_merge_stgy S U"
    "full1 cdclW_merge_cp S U ⟹ P"
    "⋀T. decide S T ⟹ no_step cdclW_merge_cp S ⟹ full cdclW_merge_cp T U ⟹ P"
  shows "P"
  using assms by (auto simp: cdclW_merge_stgy.simps)

inductive cdclW_s'_w :: "'st ⇒ 'st ⇒ bool" where
conflict': "full1 cdclW_s'_without_decide S S' ⟹ cdclW_s'_w S S'" |
decide': "decide S S' ⟹ no_step cdclW_s'_without_decide S ⟹ full cdclW_s'_without_decide S' S''
  ⟹ cdclW_s'_w S S''"

lemma cdclW_s'_w_rtranclp_cdclW:
  "cdclW_s'_w S T ⟹ cdclW** S T"
  apply (induction rule: cdclW_s'_w.induct)
    using rtranclp_cdclW_s'_without_decide_rtranclp_cdclW unfolding full1_def
    apply (simp add: tranclp_into_rtranclp)
  using rtranclp_cdclW_s'_without_decide_rtranclp_cdclW unfolding full_def
  by (meson decide other rtranclp_into_tranclp2 tranclp_into_rtranclp)

lemma rtranclp_cdclW_s'_w_rtranclp_cdclW:
  "cdclW_s'_w** S T ⟹ cdclW** S T"
  using rtranclp_mono[of cdclW_s'_w "cdclW**"] cdclW_s'_w_rtranclp_cdclW by auto

lemma no_step_cdclW_cp_no_step_cdclW_s'_without_decide:
  assumes "no_step cdclW_cp S" and "conflicting S = None" and inv: "cdclW_M_level_inv S"
  shows "no_step cdclW_s'_without_decide S"
  by (metis assms cdclW_cp.conflict' cdclW_cp.propagate' cdclW_merge_restart_cases tranclpD
    conflicting_true_no_step_cdclW_merge_cp_no_step_s'_without_decide)

lemma no_step_cdclW_cp_no_step_cdclW_merge_restart:
  assumes "no_step cdclW_cp S" and "conflicting S = None"
  shows "no_step cdclW_merge_cp S"
  by (metis assms(1) cdclW_cp.conflict' cdclW_cp.propagate' cdclW_merge_restart_cases tranclpD)
lemma after_cdclW_s'_without_decide_no_step_cdclW_cp:
  assumes "cdclW_s'_without_decide S T"
  shows "no_step cdclW_cp T"
  using assms by (induction rule: cdclW_s'_without_decide.induct) (auto simp: full1_def full_def)

lemma no_step_cdclW_s'_without_decide_no_step_cdclW_cp:
  "cdclW_all_struct_inv S ⟹ no_step cdclW_s'_without_decide S ⟹ no_step cdclW_cp S"
  by (simp add: conflicting_true_no_step_s'_without_decide_no_step_cdclW_merge_cp
    no_step_cdclW_merge_cp_no_step_cdclW_cp cdclW_all_struct_inv_def)

lemma after_cdclW_s'_w_no_step_cdclW_cp:
  assumes "cdclW_s'_w S T" and "cdclW_all_struct_inv S"
  shows "no_step cdclW_cp T"
  using assms
proof (induction rule: cdclW_s'_w.induct)
  case conflict'
  then show ?case
    by (auto simp: full1_def tranclp_unfold_end after_cdclW_s'_without_decide_no_step_cdclW_cp)
next
  case (decide' S T U)
  moreover
    then have "cdclW** S U"
      using rtranclp_cdclW_s'_without_decide_rtranclp_cdclW[of T U] cdclW.other[of S T]
      cdclW_o.decide unfolding full_def by auto
    then have "cdclW_all_struct_inv U"
      using decide'.prems rtranclp_cdclW_all_struct_inv_inv by blast
  ultimately show ?case
    using no_step_cdclW_s'_without_decide_no_step_cdclW_cp unfolding full_def by blast
qed

lemma rtranclp_cdclW_s'_w_no_step_cdclW_cp_or_eq:
  assumes "cdclW_s'_w** S T" and "cdclW_all_struct_inv S"
  shows "S = T ∨ no_step cdclW_cp T"
  using assms
proof (induction rule: rtranclp_induct)
  case base
  then show ?case by simp
next
  case (step T U)
  moreover have "cdclW_all_struct_inv T"
    using rtranclp_cdclW_s'_w_rtranclp_cdclW[of S U] assms(2) rtranclp_cdclW_all_struct_inv_inv
    rtranclp_cdclW_s'_w_rtranclp_cdclW step.hyps(1) by blast
  ultimately show ?case using after_cdclW_s'_w_no_step_cdclW_cp by fast
qed

lemma rtranclp_cdclW_merge_stgy'_no_step_cdclW_cp_or_eq:
  assumes "cdclW_merge_stgy** S T" and inv: "cdclW_all_struct_inv S"
  shows "S = T ∨ no_step cdclW_cp T"
  using assms
proof (induction rule: rtranclp_induct)
  case base
  then show ?case by simp
next
  case (step T U)
  moreover have "cdclW_all_struct_inv T"
    using rtranclp_cdclW_merge_stgy_rtranclp_cdclW[of S U] assms(2) rtranclp_cdclW_all_struct_inv_inv
    rtranclp_cdclW_s'_w_rtranclp_cdclW step.hyps(1)
    by (meson rtranclp_cdclW_merge_stgy_rtranclp_cdclW)
  ultimately show ?case
    using after_cdclW_s'_w_no_step_cdclW_cp inv unfolding cdclW_all_struct_inv_def
    by (metis cdclW_all_struct_inv_def cdclW_merge_stgy.simps full1_def full_def
      no_step_cdclW_merge_cp_no_step_cdclW_cp rtranclp_cdclW_all_struct_inv_inv
      rtranclp_cdclW_merge_stgy_rtranclp_cdclW tranclp.intros(1) tranclp_into_rtranclp)
qed

lemma no_step_cdclW_s'_without_decide_no_step_cdclW_bj:
  assumes "no_step cdclW_s'_without_decide S" and inv: "cdclW_all_struct_inv S"
  shows "no_step cdclW_bj S"
proof (rule ccontr)
  assume "¬ ?thesis"
  then obtain T where S_T: "cdclW_bj S T"
    by auto
  have "cdclW_all_struct_inv T"
    using S_T cdclW_all_struct_inv_inv inv other by blast
  then obtain T' where "full1 cdclW_bj S T'"
    using cdclW_bj_exists_normal_form[of T] full_fullI S_T  unfolding cdclW_all_struct_inv_def
    by metis
  moreover
    then have "cdclW** S T'"
      using rtranclp_mono[of cdclW_bj cdclW] cdclW.other cdclW_o.bj tranclp_into_rtranclp[of cdclW_bj]
      unfolding full1_def by (metis (full_types) predicate2D predicate2I)
    then have "cdclW_all_struct_inv T'"
      using inv  rtranclp_cdclW_all_struct_inv_inv by blast
    then obtain U where "full cdclW_cp T' U"
      using cdclW_cp_normalized_element_all_inv by blast
  moreover have "no_step cdclW_cp S"
    using S_T by (auto simp: cdclW_bj.simps)
  ultimately show False
  using assms cdclW_s'_without_decide.intros(2)[of S T' U] by fast
qed

lemma cdclW_s'_w_no_step_cdclW_bj:
  assumes "cdclW_s'_w S T" and "cdclW_all_struct_inv S"
  shows "no_step cdclW_bj T"
  using assms apply induction
    using rtranclp_cdclW_s'_without_decide_rtranclp_cdclW rtranclp_cdclW_all_struct_inv_inv
    no_step_cdclW_s'_without_decide_no_step_cdclW_bj unfolding full1_def
    apply (meson tranclp_into_rtranclp)
  using rtranclp_cdclW_s'_without_decide_rtranclp_cdclW rtranclp_cdclW_all_struct_inv_inv
    no_step_cdclW_s'_without_decide_no_step_cdclW_bj unfolding full_def
  by (meson cdclW_merge_restart_cdclW fw_r_decide)

lemma rtranclp_cdclW_s'_w_no_step_cdclW_bj_or_eq:
  assumes "cdclW_s'_w** S T" and "cdclW_all_struct_inv S"
  shows "S = T ∨ no_step cdclW_bj T"
  using assms apply induction
    apply simp
  using rtranclp_cdclW_s'_w_rtranclp_cdclW rtranclp_cdclW_all_struct_inv_inv
    cdclW_s'_w_no_step_cdclW_bj by meson

lemma rtranclp_cdclW_s'_no_step_cdclW_s'_without_decide_decomp_into_cdclW_merge:
  assumes
    "cdclW_s'** R V" and
    "conflicting R = None" and
    inv: "cdclW_all_struct_inv R"
  shows "(cdclW_merge_stgy** R V ∧ conflicting V = None)
  ∨ (cdclW_merge_stgy** R V ∧ conflicting V ≠ None ∧ no_step cdclW_bj V)
  ∨ (∃S T U. cdclW_merge_stgy** R S ∧ no_step cdclW_merge_cp S ∧ decide S T
    ∧ cdclW_merge_cp** T U ∧ conflict U V)
  ∨ (∃S T. cdclW_merge_stgy** R S ∧ no_step cdclW_merge_cp S ∧ decide S T
    ∧ cdclW_merge_cp** T V
      ∧ conflicting V = None)
  ∨ (cdclW_merge_cp** R V ∧ conflicting V = None)
  ∨ (∃U. cdclW_merge_cp** R U ∧ conflict U V)"
  using assms(1,2)
proof induction
  case base
  then show ?case by simp
next
  case (step V W) note st = this(1) and s' = this(2) and IH = this(3)[OF this(4)] and
    n_s_R = this(4)
  from s'
  show ?case
    proof cases
      case conflict'
      consider
          (s') "cdclW_merge_stgy** R V"
        | (dec_confl) S T U where "cdclW_merge_stgy** R S" and "no_step cdclW_merge_cp S" and
            "decide S T" and "cdclW_merge_cp** T U" and "conflict U V"
        | (dec) S T where "cdclW_merge_stgy** R S" and "no_step cdclW_merge_cp S" and "decide S T"
            and "cdclW_merge_cp** T V" and "conflicting V = None"
        | (cp) "cdclW_merge_cp** R V"
        | (cp_confl) U where "cdclW_merge_cp** R U" and "conflict U V"
        using IH by meson
      then show ?thesis
        proof cases
        next
          case s'
          then have "R = V"
            by (metis full1_def inv local.conflict' tranclp_unfold_begin
              rtranclp_cdclW_merge_stgy'_no_step_cdclW_cp_or_eq)
          consider
              (V_W) "V = W"
            | (propa) "propagate++ V W" and "conflicting W = None"
            | (propa_confl) V' where "propagate** V V'" and "conflict V' W"
            using tranclp_cdclW_cp_propagate_with_conflict_or_not[of V W] conflict'
            unfolding full_unfold full1_def by meson
          then show ?thesis
            proof cases
              case V_W
              then show ?thesis using ‹R = V› n_s_R by simp
            next
              case propa
              then show ?thesis using ‹R = V› by auto
            next
              case propa_confl
              moreover
                then have "cdclW_merge_cp** V V'"
                  by (metis rtranclp_unfold cdclW_merge_cp.propagate' r_into_rtranclp)
              ultimately show ?thesis using s' ‹R = V› by blast
            qed
        next
          case dec_confl note _ = this(5)
          then have False using conflict' unfolding full1_def by (auto dest!: tranclpD)
          then show ?thesis by fast
        next
          case dec note T_V = this(4)
          consider
              (propa) "propagate++ V W" and "conflicting W = None"
            | (propa_confl) V' where "propagate** V V'" and "conflict V' W"
            using tranclp_cdclW_cp_propagate_with_conflict_or_not[of V W] conflict'
            unfolding full1_def by meson
          then show ?thesis (* too many levels of case distinction *)
            proof cases
              case propa
              then show ?thesis
                by (meson T_V cdclW_merge_cp.propagate' dec rtranclp.rtrancl_into_rtrancl)
            next
              case propa_confl
              then have "cdclW_merge_cp** T V'"
                using T_V by (metis rtranclp_unfold cdclW_merge_cp.propagate' rtranclp.simps)
              then show ?thesis using dec propa_confl(2) by metis
            qed
        next
          case cp
          consider
              (propa) "propagate++ V W" and "conflicting W = None"
            | (propa_confl) V' where "propagate** V V'" and "conflict V' W"
            using tranclp_cdclW_cp_propagate_with_conflict_or_not[of V W] conflict'
            unfolding full1_def by meson
          then show ?thesis
            proof cases
              case propa
              then show ?thesis by (meson cdclW_merge_cp.propagate' cp rtranclp.rtrancl_into_rtrancl)
            next
              case propa_confl
              then show ?thesis
                using propa_confl(2) by (metis rtranclp_unfold cdclW_merge_cp.propagate'
                  cp rtranclp.rtrancl_into_rtrancl)
            qed
        next
          case cp_confl
          then show ?thesis using conflict' unfolding full1_def by (fastforce dest!: tranclpD)
        qed
    next
      case (decide' V')
      then have conf_V: "conflicting V = None"
        by auto
      consider
         (s') "cdclW_merge_stgy** R V"
        | (dec_confl) S T U where "cdclW_merge_stgy** R S" and "no_step cdclW_merge_cp S" and
            "decide S T" and "cdclW_merge_cp** T U" and "conflict U V"
        | (dec) S T where "cdclW_merge_stgy** R S" and "no_step cdclW_merge_cp S" and "decide S T"
             and "cdclW_merge_cp** T V" and "conflicting V = None"
        | (cp) "cdclW_merge_cp** R V"
        | (cp_confl) U where "cdclW_merge_cp** R U" and "conflict U V"
        using IH by meson
      then show ?thesis
        proof cases
          case s'
          have confl_V': "conflicting V' = None" using decide'(1) by auto
          have full: "full1 cdclW_cp V' W ∨ (V' = W ∧ no_step cdclW_cp W)"
            using decide'(3) unfolding full_unfold by blast
          consider
              (V'_W) "V' = W"
            | (propa) "propagate++ V' W" and "conflicting W = None"
            | (propa_confl) V'' where "propagate** V' V''" and "conflict V'' W"
            using tranclp_cdclW_cp_propagate_with_conflict_or_not[of V W] decide'
            by (metis ‹full1 cdclW_cp V' W ∨ V' = W ∧ no_step cdclW_cp W› full1_def
              tranclp_cdclW_cp_propagate_with_conflict_or_not)
          then show ?thesis (* too many levels of case distinction *)
            proof cases
              case V'_W
              then show ?thesis
                using confl_V' local.decide'(1,2) s' conf_V
                no_step_cdclW_cp_no_step_cdclW_merge_restart[of V] by blast
            next
              case propa
              then show ?thesis using local.decide'(1,2) s' by (metis cdclW_merge_cp.simps conf_V
                no_step_cdclW_cp_no_step_cdclW_merge_restart r_into_rtranclp)
            next
              case propa_confl
              then have "cdclW_merge_cp** V' V''"
                by (metis rtranclp_unfold cdclW_merge_cp.propagate' r_into_rtranclp)
              then show ?thesis
                using local.decide'(1,2) propa_confl(2) s' conf_V
                no_step_cdclW_cp_no_step_cdclW_merge_restart
                by metis
            qed
        next
          case (dec) note s' = this(1) and dec = this(2) and cp = this(3) and ns_cp_T = this(4)
          have "full cdclW_merge_cp T V"
            unfolding full_def by (simp add: conf_V local.decide'(2)
              no_step_cdclW_cp_no_step_cdclW_merge_restart ns_cp_T)
          moreover have "no_step cdclW_merge_cp V"
             by (simp add: conf_V local.decide'(2) no_step_cdclW_cp_no_step_cdclW_merge_restart)
          moreover have "no_step cdclW_merge_cp S"
            by (metis dec)
          ultimately have "cdclW_merge_stgy S V"
            using cp by blast
          then have "cdclW_merge_stgy** R V" using s' by auto
          consider
              (V'_W) "V' = W"
            | (propa) "propagate++ V' W" and "conflicting W = None"
            | (propa_confl) V'' where "propagate** V' V''" and "conflict V'' W"
            using tranclp_cdclW_cp_propagate_with_conflict_or_not[of V' W] decide'
            unfolding full_unfold full1_def by meson
          then show ?thesis (* too many levels of case distinction *)
            proof cases
              case V'_W
              moreover have "conflicting V' = None"
                using decide'(1) by auto
              ultimately show ?thesis
                using ‹cdclW_merge_stgy** R V› decide' ‹no_step cdclW_merge_cp V› by blast
            next
              case propa
              moreover then have "cdclW_merge_cp V' W"
                by auto
              ultimately show ?thesis
                using ‹cdclW_merge_stgy** R V› decide' ‹no_step cdclW_merge_cp V›
                by (meson r_into_rtranclp)
            next
              case propa_confl
              moreover then have "cdclW_merge_cp** V' V''"
                by (metis cdclW_merge_cp.propagate' rtranclp_unfold tranclp_unfold_end)
              ultimately show ?thesis using ‹cdclW_merge_stgy** R V› decide'
                ‹no_step cdclW_merge_cp V› by (meson r_into_rtranclp)
            qed
        next
          case cp
          have "no_step cdclW_merge_cp V"
            using conf_V local.decide'(2) no_step_cdclW_cp_no_step_cdclW_merge_restart by blast
          then have "full cdclW_merge_cp R V"
            unfolding full_def using cp by fast
          then have "cdclW_merge_stgy** R V"
            unfolding full_unfold by auto
          have "full1 cdclW_cp V' W ∨ (V' = W ∧ no_step cdclW_cp W)"
            using decide'(3) unfolding full_unfold by blast

          consider
              (V'_W) "V' = W"
            | (propa) "propagate++ V' W" and "conflicting W = None"
            | (propa_confl) V'' where "propagate** V' V''" and "conflict V'' W"
            using tranclp_cdclW_cp_propagate_with_conflict_or_not[of V' W] decide'
            unfolding full_unfold full1_def by meson
          then show ?thesis (* too many levels of case distinction *)
          (* copy paste. copy paste, copy paste *)
            proof cases
              case V'_W
              moreover have "conflicting V' = None"
                using decide'(1) by auto
              ultimately show ?thesis
                using ‹cdclW_merge_stgy** R V› decide'  ‹no_step cdclW_merge_cp V› by blast
            next
              case propa
              moreover then have "cdclW_merge_cp V' W"
                by auto
              ultimately show ?thesis using ‹cdclW_merge_stgy** R V› decide'
                ‹no_step cdclW_merge_cp V› by (meson r_into_rtranclp)
            next
              case propa_confl
              moreover then have "cdclW_merge_cp** V' V''"
                by (metis cdclW_merge_cp.propagate' rtranclp_unfold tranclp_unfold_end)
              ultimately show ?thesis using ‹cdclW_merge_stgy** R V› decide'
                ‹no_step cdclW_merge_cp V› by (meson r_into_rtranclp)
            qed
        next
          case (dec_confl) (* Oh! a simple case *)
          show ?thesis using conf_V dec_confl(5) by auto
        next
          case cp_confl
          then show ?thesis using decide' apply - by (intro HOL.disjI2) fastforce
      qed
    next
      case (bj' V')
      then have "¬no_step cdclW_bj V "
        by (auto dest: tranclpD simp: full1_def)
      then consider
         (s') "cdclW_merge_stgy** R V" and "conflicting V = None"
        | (dec_confl) S T U where "cdclW_merge_stgy** R S" and "no_step cdclW_merge_cp S" and
            "decide S T" and "cdclW_merge_cp** T U" and "conflict U V"
        | (dec) S T where "cdclW_merge_stgy** R S" and "no_step cdclW_merge_cp S" and "decide S T"
            and "cdclW_merge_cp** T V" and "conflicting V = None"
        | (cp) "cdclW_merge_cp** R V" and "conflicting V = None"
        | (cp_confl) U where "cdclW_merge_cp** R U" and "conflict U V"
        using IH by meson
      then show ?thesis
        proof cases
          case s' note _ =this(2)
          then have False
            using bj'(1) unfolding full1_def by (force dest!: tranclpD simp: cdclW_bj.simps)
          then show ?thesis by fast
        next
          case dec note _ = this(5)
          then have False
            using bj'(1) unfolding full1_def by (force dest!: tranclpD simp: cdclW_bj.simps)
          then show ?thesis by fast
        next
          case dec_confl
          then have "cdclW_merge_cp U V'"
            using bj' cdclW_merge_cp.intros(1)[of U V V'] by (simp add: full_unfold)
          then have "cdclW_merge_cp** T V'"
            using dec_confl(4) by simp
          consider
              (V'_W) "V' = W"
            | (propa) "propagate++ V' W" and "conflicting W = None"
            | (propa_confl) V'' where "propagate** V' V''" and "conflict V'' W"
            using tranclp_cdclW_cp_propagate_with_conflict_or_not[of V' W] bj'(3)
            unfolding full_unfold full1_def by meson
          then show ?thesis (* too many levels of case distinction *)
            proof cases
              case V'_W
              then have "no_step cdclW_cp V'"
                using bj'(3) unfolding full_def by auto
              then have "no_step cdclW_merge_cp V'"
                by (metis cdclW_cp.propagate' cdclW_merge_cp.cases tranclpD
                  no_step_cdclW_cp_no_conflict_no_propagate(1) )
              then have "full1 cdclW_merge_cp T V'"
                unfolding full1_def using ‹cdclW_merge_cp U V'› dec_confl(4) by auto
              then have "full  cdclW_merge_cp T V'"
                by (simp add: full_unfold)
              then have "cdclW_merge_stgy S V'"
                using dec_confl(3) cdclW_merge_stgy.fw_s_decide ‹no_step cdclW_merge_cp S› by blast
              then have "cdclW_merge_stgy** R V'"
                using ‹cdclW_merge_stgy** R S› by auto
              show ?thesis
                proof cases
                  assume "conflicting W = None"
                  then show ?thesis using ‹cdclW_merge_stgy** R V'› ‹V' = W› by auto
                next
                  assume "conflicting W ≠ None"
                  then show ?thesis
                    using ‹cdclW_merge_stgy** R V'› ‹V' = W› by (metis ‹cdclW_merge_cp U V'›
                      conflicting_not_true_rtranclp_cdclW_merge_cp_no_step_cdclW_bj dec_confl(5)
                      r_into_rtranclp conflictE)
                qed
            next
              case propa
              moreover then have "cdclW_merge_cp V' W"
                by auto
              ultimately show ?thesis using decide' by (meson ‹cdclW_merge_cp** T V'› dec_confl(1-3)
                rtranclp.rtrancl_into_rtrancl)
            next
              case propa_confl
              moreover then have "cdclW_merge_cp** V' V''"
                by (metis cdclW_merge_cp.propagate' rtranclp_unfold tranclp_unfold_end)
              ultimately show ?thesis by (meson ‹cdclW_merge_cp** T V'› dec_confl(1-3) rtranclp_trans)
            qed
        next
          case cp note _ = this(2)
          then show ?thesis using bj'(1)  ‹¬ no_step cdclW_bj V›
            conflicting_not_true_rtranclp_cdclW_merge_cp_no_step_cdclW_bj by auto
        next
          case cp_confl
          then have "cdclW_merge_cp U V'" by (simp add: cdclW_merge_cp.conflict' full_unfold
            local.bj'(1))
          consider
              (V'_W) "V' = W"
            | (propa) "propagate++ V' W" and "conflicting W = None"
            | (propa_confl) V'' where "propagate** V' V''" and "conflict V'' W"
            using tranclp_cdclW_cp_propagate_with_conflict_or_not[of V' W] bj'
            unfolding full_unfold full1_def by meson
          then show ?thesis (* too many levels of case distinction *)
          (* copy paste. copy paste, copy paste *)
            proof cases
              case V'_W
              show ?thesis
                proof cases
                  assume "conflicting V' = None"
                  then show ?thesis
                    using V'_W ‹cdclW_merge_cp U V'› cp_confl(1) by force
                next
                  assume confl: "conflicting V' ≠ None"
                  then have "no_step cdclW_merge_stgy V'"
                    by (fastforce simp: cdclW_merge_stgy.simps full1_def full_def
                      cdclW_merge_cp.simps dest!: tranclpD)
                  have "no_step cdclW_merge_cp V'"
                    using confl by (auto simp: full1_def full_def cdclW_merge_cp.simps
                    dest!: tranclpD)
                  moreover have "cdclW_merge_cp U W"
                    using V'_W ‹cdclW_merge_cp U V'› by blast
                  ultimately have "full1 cdclW_merge_cp R V'"
                    using cp_confl(1) V'_W unfolding full1_def by auto
                  then have "cdclW_merge_stgy R V'"
                    by auto
                  moreover have "no_step cdclW_merge_stgy V'"
                    using confl ‹no_step cdclW_merge_cp V'› by (auto simp: cdclW_merge_stgy.simps
                      full1_def dest!: tranclpD)
                  ultimately have "cdclW_merge_stgy** R V'" by auto
                  show ?thesis by (metis V'_W ‹cdclW_merge_cp U V'› ‹cdclW_merge_stgy** R V'›
                    conflicting_not_true_rtranclp_cdclW_merge_cp_no_step_cdclW_bj cp_confl(1)
                    rtranclp.rtrancl_into_rtrancl step.prems)
                qed
            next
              case propa
              moreover then have "cdclW_merge_cp V' W"
                by auto
              ultimately show ?thesis using ‹cdclW_merge_cp U V'› cp_confl(1) by force
            next
              case propa_confl
              moreover then have "cdclW_merge_cp** V' V''"
                by (metis cdclW_merge_cp.propagate' rtranclp_unfold tranclp_unfold_end)
              ultimately show ?thesis
                using ‹cdclW_merge_cp U V'› cp_confl(1) by (metis rtranclp.rtrancl_into_rtrancl
                  rtranclp_trans)
            qed
        qed
    qed
qed

lemma decide_rtranclp_cdclW_s'_rtranclp_cdclW_s':
  assumes
    dec: "decide S T" and
    "cdclW_s'** T U" and
    n_s_S: "no_step cdclW_cp S" and
    "no_step cdclW_cp U"
  shows "cdclW_s'** S U"
  using assms(2,4)
proof induction
  case (step U V) note st =this(1) and s' = this(2) and IH = this(3) and n_s = this(4)
  consider
      (TU) "T = U"
    | (s'_st) T' where "cdclW_s' T T'" and "cdclW_s'** T' U"
    using st[unfolded rtranclp_unfold] by (auto dest!: tranclpD)
  then show ?case
    proof cases
      case TU
      then show ?thesis
        proof -
          assume a1: "T = U"
          then have f2: "cdclW_s' T V"
            using s' by force
          obtain ss :: 'st where
            "cdclW_s'** S T ∨ cdclW_cp T ss"
            using a1 step.IH by blast
          then show ?thesis
            using f2 by (metis (full_types) cdclW_s'.decide' cdclW_s'E dec full1_is_full n_s_S
              rtranclp_unfold tranclp_unfold_end)
        qed
    next
      case (s'_st T') note s'_T' = this(1) and st = this(2)
      have "cdclW_s'** S T'"
        using s'_T'
        proof cases
          case conflict'
          then have "cdclW_s' S T'"
             using dec cdclW_s'.decide' n_s_S by (simp add: full_unfold)
          then show ?thesis
             using st by auto
        next
          case (decide' T'')
          then have "cdclW_s' S T"
             using dec cdclW_s'.decide' n_s_S by (simp add: full_unfold)
          then show ?thesis using decide' s'_T' by auto
        next
          case bj'
          then have False
            using dec unfolding full1_def by (fastforce dest!: tranclpD simp: cdclW_bj.simps)
          then show ?thesis by fast
        qed
      then show ?thesis using s' st by auto
    qed
next
  case base
  then have "full cdclW_cp T T"
    by (simp add: full_unfold)
  then show ?case
    using cdclW_s'.simps dec n_s_S by auto
qed

lemma rtranclp_cdclW_merge_stgy_rtranclp_cdclW_s':
  assumes
    "cdclW_merge_stgy** R V" and
    inv: "cdclW_all_struct_inv R"
  shows "cdclW_s'** R V"
  using assms(1)
proof induction
  case base
  then show ?case by simp
next
  case (step S T) note st = this(1) and fw = this(2) and IH = this(3)
  have "cdclW_all_struct_inv S"
    using inv rtranclp_cdclW_all_struct_inv_inv rtranclp_cdclW_merge_stgy_rtranclp_cdclW st by blast
  from fw show ?case
    proof (cases rule: cdclW_merge_stgy_cases)
      case fw_s_cp
      then show ?thesis
        proof -
          assume a1: "full1 cdclW_merge_cp S T"
          obtain ss :: "('st ⇒ 'st ⇒ bool) ⇒ 'st ⇒ 'st" where
            f2: "⋀p s sa pa sb sc sd pb se sf. (¬ full1 p (s::'st) sa ∨ p++ s sa)
              ∧ (¬ pa (sb::'st) sc ∨ ¬ full1 pa sd sb) ∧ (¬ pb++ se sf ∨ pb sf (ss pb sf)
              ∨ full1 pb se sf)"
            by (metis (no_types) full1_def)
          then have f3: "cdclW_merge_cp++ S T"
            using a1 by auto
          obtain ssa :: "('st ⇒ 'st ⇒ bool) ⇒ 'st ⇒ 'st ⇒ 'st" where
            f4: "⋀p s sa. ¬ p++ s sa ∨ p s (ssa p s sa)"
            by (meson tranclp_unfold_begin)
          then have f5: "⋀s. ¬ full1 cdclW_merge_cp s S"
            using f3 f2 by (metis (full_types))
          have "⋀s. ¬ full cdclW_merge_cp s S"
            using f4 f3 by (meson full_def)
          then have "S = R"
            using f5 by (metis (no_types) cdclW_merge_stgy.simps rtranclp_unfold st
              tranclp_unfold_end)
          then show ?thesis
            using f2 a1 by (metis (no_types) ‹cdclW_all_struct_inv S›
              conflicting_true_full1_cdclW_merge_cp_imp_full1_cdclW_s'_without_decode
              rtranclp_cdclW_s'_without_decide_rtranclp_cdclW_s' rtranclp_unfold)
        qed
    next
      case (fw_s_decide S') note dec = this(1) and n_S = this(2) and full = this(3)
      moreover then have "conflicting S' = None"
        by auto
      ultimately have "full cdclW_s'_without_decide S' T"
        by (meson ‹cdclW_all_struct_inv S› cdclW_merge_restart_cdclW fw_r_decide
          rtranclp_cdclW_all_struct_inv_inv
          conflicting_true_full_cdclW_merge_cp_iff_full_cdclW_s'_without_decode)
      then have a1: "cdclW_s'** S' T"
        unfolding full_def by (metis (full_types)rtranclp_cdclW_s'_without_decide_rtranclp_cdclW_s')
      have "cdclW_merge_stgy** S T"
        using fw by blast
      then have "cdclW_s'** S T"
        using decide_rtranclp_cdclW_s'_rtranclp_cdclW_s' a1 by (metis ‹cdclW_all_struct_inv S› dec
          n_S no_step_cdclW_merge_cp_no_step_cdclW_cp cdclW_all_struct_inv_def
          rtranclp_cdclW_merge_stgy'_no_step_cdclW_cp_or_eq)
      then show ?thesis using IH by auto
    qed
qed

lemma rtranclp_cdclW_merge_stgy_distinct_mset_clauses:
  assumes invR: "cdclW_all_struct_inv R" and
  st: "cdclW_merge_stgy** R S" and
  dist: "distinct_mset (clauses R)" and
  R: "trail R = []"
  shows "distinct_mset (clauses S)"
  using rtranclp_cdclW_stgy_distinct_mset_clauses[OF invR _ dist R]
  invR st rtranclp_mono[of cdclW_s' "cdclW_stgy**"] cdclW_s'_is_rtranclp_cdclW_stgy
  by (auto dest!: cdclW_s'_is_rtranclp_cdclW_stgy rtranclp_cdclW_merge_stgy_rtranclp_cdclW_s')

lemma no_step_cdclW_s'_no_step_cdclW_merge_stgy:
  assumes
    inv: "cdclW_all_struct_inv R" and s': "no_step cdclW_s' R"
  shows "no_step cdclW_merge_stgy R"
proof -
  { fix ss :: 'st
    obtain ssa :: "'st ⇒ 'st ⇒ 'st" where
      ff1: "⋀s sa. ¬ cdclW_merge_stgy s sa ∨ full1 cdclW_merge_cp s sa ∨ decide s (ssa s sa)"
      using cdclW_merge_stgy.cases by moura
    obtain ssb :: "('st ⇒ 'st ⇒ bool) ⇒ 'st ⇒ 'st ⇒ 'st" where
      ff2: "⋀p s sa. ¬ p++ s sa ∨ p s (ssb p s sa)"
      by (meson tranclp_unfold_begin)
    obtain ssc :: "'st ⇒ 'st" where
      ff3: "⋀s sa sb. (¬ cdclW_all_struct_inv s ∨ ¬ cdclW_cp s sa ∨ cdclW_s' s (ssc s))
        ∧ (¬ cdclW_all_struct_inv s ∨ ¬ cdclW_o s sb ∨ cdclW_s' s (ssc s))"
      using n_step_cdclW_stgy_iff_no_step_cdclW_cl_cdclW_o by moura
    then have ff4: "⋀s. ¬ cdclW_o R s"
      using s' inv by blast
    have ff5: "⋀s. ¬ cdclW_cp++ R s"
      using ff3 ff2 s' by (metis inv)
    have "⋀s. ¬ cdclW_bj++ R s"
      using ff4 ff2 by (metis bj)
    then have "⋀s. ¬ cdclW_s'_without_decide R s"
      using ff5 by (simp add: cdclW_s'_without_decide.simps full1_def)
    then have "¬ cdclW_s'_without_decide++ R ss"
      using ff2 by blast
    then have "¬ cdclW_merge_stgy R ss"
      using ff4 ff1 by (metis (full_types)  decide full1_def inv
        conflicting_true_full1_cdclW_merge_cp_imp_full1_cdclW_s'_without_decode) }
  then show ?thesis
    by fastforce
qed

lemma wf_cdclW_merge_cp:
  "wf{(T, S). cdclW_all_struct_inv S ∧ cdclW_merge_cp S T}"
  using wf_tranclp_cdclW_merge by (rule wf_subset) (auto simp: cdclW_merge_cp_tranclp_cdclW_merge)

lemma wf_cdclW_merge_stgy:
  "wf{(T, S). cdclW_all_struct_inv S ∧ cdclW_merge_stgy S T}"
  using wf_tranclp_cdclW_merge by (rule wf_subset)
  (auto simp add: cdclW_merge_stgy_tranclp_cdclW_merge)

lemma cdclW_merge_cp_obtain_normal_form:
  assumes inv: "cdclW_all_struct_inv R"
  obtains S where "full cdclW_merge_cp R S"
proof -
  obtain S where "full (λS T. cdclW_all_struct_inv S ∧ cdclW_merge_cp S T) R S"
    using wf_exists_normal_form_full[OF wf_cdclW_merge_cp] by blast
  then have
    st: "(λS T. cdclW_all_struct_inv S ∧ cdclW_merge_cp S T)** R S" and
    n_s: "no_step (λS T. cdclW_all_struct_inv S ∧ cdclW_merge_cp S T) S"
    unfolding full_def by blast+
  have "cdclW_merge_cp** R S"
    using st by induction auto
  moreover
    have "cdclW_all_struct_inv S"
      using st inv
      apply (induction rule: rtranclp_induct)
        apply simp
      by (meson r_into_rtranclp rtranclp_cdclW_all_struct_inv_inv
        rtranclp_cdclW_merge_cp_rtranclp_cdclW)
    then have "no_step cdclW_merge_cp S"
      using n_s by auto
  ultimately show ?thesis
    using that unfolding full_def by blast
qed

lemma no_step_cdclW_merge_stgy_no_step_cdclW_s':
  assumes
    inv: "cdclW_all_struct_inv R" and
    confl: "conflicting R = None" and
    n_s: "no_step cdclW_merge_stgy R"
  shows "no_step cdclW_s' R"
proof (rule ccontr)
  assume "¬ ?thesis"
  then obtain S where "cdclW_s' R S" by auto
  then show False
    proof cases
      case conflict'
      then obtain S' where "full1 cdclW_merge_cp R S'"
        by (metis (full_types) cdclW_merge_cp_obtain_normal_form cdclW_s'_without_decide.simps confl
          conflicting_true_no_step_cdclW_merge_cp_no_step_s'_without_decide full_def full_unfold inv
          cdclW_all_struct_inv_def)
      then show False using n_s by blast
    next
      case (decide' R')
      then have "cdclW_all_struct_inv R'"
        using inv cdclW_all_struct_inv_inv cdclW.other cdclW_o.decide by meson
      then obtain R'' where "full cdclW_merge_cp R' R''"
        using cdclW_merge_cp_obtain_normal_form by blast
      moreover have "no_step cdclW_merge_cp R"
        by (simp add: confl local.decide'(2) no_step_cdclW_cp_no_step_cdclW_merge_restart)
      ultimately show False using n_s cdclW_merge_stgy.intros local.decide'(1) by blast
    next
      case (bj' R')
      then show False
        using confl no_step_cdclW_cp_no_step_cdclW_s'_without_decide inv
        unfolding cdclW_all_struct_inv_def by blast
    qed
qed

lemma rtranclp_cdclW_merge_cp_no_step_cdclW_bj:
  assumes "conflicting R = None" and "cdclW_merge_cp** R S"
  shows "no_step cdclW_bj S"
  using assms conflicting_not_true_rtranclp_cdclW_merge_cp_no_step_cdclW_bj by blast

lemma rtranclp_cdclW_merge_stgy_no_step_cdclW_bj:
  assumes confl: "conflicting R = None" and "cdclW_merge_stgy** R S"
  shows "no_step cdclW_bj S"
  using assms(2)
proof induction
  case base
  then show ?case
    using confl by (auto simp: cdclW_bj.simps)[]
next
  case (step S T) note st = this(1) and fw = this(2) and IH = this(3)
  have confl_S: "conflicting S = None"
    using fw apply cases
    by (auto simp: full1_def cdclW_merge_cp.simps dest!: tranclpD)
  from fw show ?case
    proof cases
      case fw_s_cp
      then show ?thesis
        using rtranclp_cdclW_merge_cp_no_step_cdclW_bj confl_S
        by (simp add: full1_def tranclp_into_rtranclp)
    next
      case (fw_s_decide S')
      moreover then have "conflicting S' = None" by auto
      ultimately show ?thesis
        using conflicting_not_true_rtranclp_cdclW_merge_cp_no_step_cdclW_bj
        unfolding full_def by meson
    qed
qed

lemma full_cdclW_s'_full_cdclW_merge_restart:
  assumes
    "conflicting R = None" and
    inv: "cdclW_all_struct_inv R"
  shows "full cdclW_s' R V ⟷ full cdclW_merge_stgy R V" (is "?s' ⟷ ?fw")
proof
  assume ?s'
  then have "cdclW_s'** R V" unfolding full_def by blast
  have "cdclW_all_struct_inv V"
    using ‹cdclW_s'** R V› inv rtranclp_cdclW_all_struct_inv_inv rtranclp_cdclW_s'_rtranclp_cdclW
    by blast
  then have n_s: "no_step cdclW_merge_stgy V"
    using no_step_cdclW_s'_no_step_cdclW_merge_stgy by (meson ‹full cdclW_s' R V› full_def)
  have n_s_bj: "no_step cdclW_bj V"
    by (metis ‹cdclW_all_struct_inv V› ‹full cdclW_s' R V› bj full_def
      n_step_cdclW_stgy_iff_no_step_cdclW_cl_cdclW_o)
  have n_s_cp: "no_step cdclW_merge_cp V"
    proof -
      { fix ss :: 'st
        obtain ssa :: "'st ⇒ 'st" where
          ff1: "∀s. ¬ cdclW_all_struct_inv s ∨ cdclW_s'_without_decide s (ssa s)
            ∨ no_step cdclW_merge_cp s"
          using conflicting_true_no_step_s'_without_decide_no_step_cdclW_merge_cp by moura
        have "(∀p s sa. ¬ full p (s::'st) sa ∨ p** s sa ∧ no_step p sa)" and
          "(∀p s sa. (¬ p** (s::'st) sa ∨ (∃s. p sa s)) ∨ full p s sa)"
          by (meson full_def)+
        then have "¬ cdclW_merge_cp V ss"
          using ff1 by (metis (no_types) ‹cdclW_all_struct_inv V› ‹full cdclW_s' R V› cdclW_s'.simps
            cdclW_s'_without_decide.cases) }
      then show ?thesis
        by blast
    qed
  consider
      (fw_no_confl) "cdclW_merge_stgy** R V" and "conflicting V = None"
    | (fw_confl) "cdclW_merge_stgy** R V" and "conflicting V ≠ None" and "no_step cdclW_bj V"
    | (fw_dec_confl) S T U where "cdclW_merge_stgy** R S" and "no_step cdclW_merge_cp S" and
        "decide S T" and "cdclW_merge_cp** T U" and "conflict U V"
    | (fw_dec_no_confl) S T where "cdclW_merge_stgy** R S" and "no_step cdclW_merge_cp S" and
        "decide S T" and "cdclW_merge_cp** T V" and "conflicting V = None"
    | (cp_no_confl) "cdclW_merge_cp** R V" and "conflicting V = None"
    | (cp_confl) U where "cdclW_merge_cp** R U" and "conflict U V"
    using rtranclp_cdclW_s'_no_step_cdclW_s'_without_decide_decomp_into_cdclW_merge[OF
      ‹cdclW_s'** R V› assms] by auto
  then show ?fw
    proof cases
      case fw_no_confl
      then show ?thesis using n_s unfolding full_def by blast
    next
      case fw_confl
      then show ?thesis using n_s unfolding full_def by blast
    next
      case fw_dec_confl
      have "cdclW_merge_cp U V"
        using n_s_bj by (metis cdclW_merge_cp.simps full_unfold fw_dec_confl(5))
      then have "full1 cdclW_merge_cp T V"
        unfolding full1_def by (metis fw_dec_confl(4) n_s_cp tranclp_unfold_end)
      then have "cdclW_merge_stgy S V" using ‹decide S T› ‹no_step cdclW_merge_cp S› by auto
      then show ?thesis using n_s ‹ cdclW_merge_stgy** R S› unfolding full_def by auto
    next
      case fw_dec_no_confl
      then have "full cdclW_merge_cp T V"
        using n_s_cp unfolding full_def by blast
      then have "cdclW_merge_stgy S V" using ‹decide S T› ‹no_step cdclW_merge_cp S› by auto
      then show ?thesis using n_s ‹ cdclW_merge_stgy** R S› unfolding full_def by auto
    next
      case cp_no_confl
      then have "full cdclW_merge_cp R V"
        by (simp add: full_def n_s_cp)
      then have "R = V ∨ cdclW_merge_stgy++ R V"
        by (metis (no_types) full_unfold fw_s_cp rtranclp_unfold tranclp_unfold_end)
      then show ?thesis
        by (simp add: full_def n_s rtranclp_unfold)
    next
      case cp_confl
      have "full cdclW_bj V V"
        using n_s_bj unfolding full_def by blast
      then have "full1 cdclW_merge_cp R V"
        unfolding full1_def by (meson cdclW_merge_cp.conflict' cp_confl(1,2) n_s_cp
          rtranclp_into_tranclp1)
      then show ?thesis using n_s unfolding full_def by auto
    qed
next
  assume ?fw
  then have "cdclW** R V" using rtranclp_mono[of cdclW_merge_stgy "cdclW**"]
    cdclW_merge_stgy_rtranclp_cdclW unfolding full_def by auto
  then have inv': "cdclW_all_struct_inv V" using inv rtranclp_cdclW_all_struct_inv_inv by blast
  have "cdclW_s'** R V"
    using ‹?fw› by (simp add: full_def inv rtranclp_cdclW_merge_stgy_rtranclp_cdclW_s')
  moreover have "no_step cdclW_s' V"
    proof cases
      assume "conflicting V = None"
      then show ?thesis
        by (metis inv' ‹full cdclW_merge_stgy R V› full_def
          no_step_cdclW_merge_stgy_no_step_cdclW_s')
    next
      assume confl_V: "conflicting V ≠ None"
      then have "no_step cdclW_bj V"
      using rtranclp_cdclW_merge_stgy_no_step_cdclW_bj by (meson ‹full cdclW_merge_stgy R V›
        assms(1) full_def)
      then show ?thesis using confl_V by (fastforce simp: cdclW_s'.simps full1_def cdclW_cp.simps
        dest!: tranclpD)
    qed
  ultimately show ?s' unfolding full_def by blast
qed

lemma full_cdclW_stgy_full_cdclW_merge:
  assumes
    "conflicting R = None" and
    inv: "cdclW_all_struct_inv R"
  shows "full cdclW_stgy R V ⟷ full cdclW_merge_stgy R V"
  by (simp add: assms(1) full_cdclW_s'_full_cdclW_merge_restart full_cdclW_stgy_iff_full_cdclW_s'
    inv)

lemma full_cdclW_merge_stgy_final_state_conclusive':
  fixes S' :: "'st"
  assumes full: "full cdclW_merge_stgy (init_state N) S'"
  and no_d: "distinct_mset_mset N"
  shows "(conflicting S' = Some {#} ∧ unsatisfiable (set_mset N))
    ∨ (conflicting S' = None ∧ trail S' ⊨asm N ∧ satisfiable (set_mset N))"
proof -
  have "cdclW_all_struct_inv (init_state N)"
    using no_d unfolding cdclW_all_struct_inv_def by auto
  moreover have "conflicting (init_state N) = None"
    by auto
  ultimately show ?thesis
    by (simp add: full full_cdclW_stgy_final_state_conclusive_from_init_state
      full_cdclW_stgy_full_cdclW_merge no_d)
qed

end

subsection ‹Adding Restarts›
locale cdclW_restart =
  cdclW trail init_clss learned_clss backtrack_lvl conflicting cons_trail tl_trail
   add_init_cls
   add_learned_cls remove_cls update_backtrack_lvl update_conflicting init_state
   restart_state
  for
    trail :: "'st ⇒ ('v, nat, 'v clause) ann_literals" and
    init_clss :: "'st ⇒ 'v clauses" and
    learned_clss :: "'st ⇒ 'v clauses" and
    backtrack_lvl :: "'st ⇒ nat" and
    conflicting :: "'st ⇒'v clause option" and

    cons_trail :: "('v, nat, 'v clause) ann_literal ⇒ 'st ⇒ 'st" and
    tl_trail :: "'st ⇒ 'st" and
    add_init_cls :: "'v clause ⇒ 'st ⇒ 'st" and
    add_learned_cls remove_cls :: "'v clause ⇒ 'st ⇒ 'st" and
    update_backtrack_lvl :: "nat ⇒ 'st ⇒ 'st" and
    update_conflicting :: "'v clause option ⇒ 'st ⇒ 'st" and

    init_state :: "'v clauses ⇒ 'st" and
    restart_state :: "'st ⇒ 'st" +
  fixes f :: "nat ⇒ nat"
  assumes f: "unbounded f"
begin
text ‹The condition of the differences of cardinality has to be strict.
  Otherwise, you could be in a strange state, where nothing remains to do, but a restart is done.
  See the proof of well-foundedness.›
inductive cdclW_merge_with_restart where
restart_step:
  "(cdclW_merge_stgy^^(card (set_mset (learned_clss T)) - card (set_mset (learned_clss S)))) S T
  ⟹ card (set_mset (learned_clss T)) - card (set_mset (learned_clss S)) > f n
  ⟹ restart T U ⟹ cdclW_merge_with_restart (S, n) (U, Suc n)" |
restart_full: "full1 cdclW_merge_stgy S T ⟹ cdclW_merge_with_restart (S, n) (T, Suc n)"

lemma "cdclW_merge_with_restart S T ⟹ cdclW_merge_restart** (fst S) (fst T)"
  by (induction rule: cdclW_merge_with_restart.induct)
  (auto dest!: relpowp_imp_rtranclp cdclW_merge_stgy_tranclp_cdclW_merge tranclp_into_rtranclp
     rtranclp_cdclW_merge_stgy_rtranclp_cdclW_merge rtranclp_cdclW_merge_tranclp_cdclW_merge_restart
     fw_r_rf cdclW_rf.restart
    simp: full1_def)

lemma cdclW_merge_with_restart_rtranclp_cdclW:
  "cdclW_merge_with_restart S T ⟹ cdclW** (fst S) (fst T)"
  by (induction rule: cdclW_merge_with_restart.induct)
  (auto dest!: relpowp_imp_rtranclp rtranclp_cdclW_merge_stgy_rtranclp_cdclW cdclW.rf
    cdclW_rf.restart tranclp_into_rtranclp simp: full1_def)

lemma cdclW_merge_with_restart_increasing_number:
  "cdclW_merge_with_restart S T ⟹ snd T = 1 + snd S"
  by (induction rule: cdclW_merge_with_restart.induct) auto

lemma "full1 cdclW_merge_stgy S T ⟹ cdclW_merge_with_restart (S, n) (T, Suc n)"
  using restart_full by blast

lemma cdclW_all_struct_inv_learned_clss_bound:
  assumes inv: "cdclW_all_struct_inv S"
  shows "set_mset (learned_clss S) ⊆ simple_clss (atms_of_msu (init_clss S))"
proof
  fix C
  assume C: "C ∈ set_mset (learned_clss S)"
  have "distinct_mset C"
    using C inv unfolding cdclW_all_struct_inv_def distinct_cdclW_state_def distinct_mset_set_def
    by auto
  moreover have "¬tautology C"
    using C inv unfolding cdclW_all_struct_inv_def cdclW_learned_clause_def by auto
  moreover
    have "atms_of C ⊆ atms_of_msu (learned_clss S)"
      using C by auto
    then have "atms_of C ⊆ atms_of_msu (init_clss S)"
    using inv  unfolding cdclW_all_struct_inv_def no_strange_atm_def by force
  moreover have "finite (atms_of_msu (init_clss S))"
    using inv unfolding cdclW_all_struct_inv_def by auto
  ultimately show "C ∈ simple_clss (atms_of_msu (init_clss S))"
    using distinct_mset_not_tautology_implies_in_simple_clss simple_clss_mono
    by blast
qed

lemma cdclW_merge_with_restart_init_clss:
  "cdclW_merge_with_restart S T ⟹ cdclW_M_level_inv (fst S) ⟹
  init_clss (fst S) = init_clss (fst T)"
  using cdclW_merge_with_restart_rtranclp_cdclW rtranclp_cdclW_init_clss by blast

lemma
  "wf {(T, S). cdclW_all_struct_inv (fst S) ∧ cdclW_merge_with_restart S T}"
proof (rule ccontr)
  assume "¬ ?thesis"
    then obtain g where
    g: "⋀i. cdclW_merge_with_restart (g i) (g (Suc i))" and
    inv: "⋀i. cdclW_all_struct_inv (fst (g i))"
    unfolding wf_iff_no_infinite_down_chain by fast
  { fix i
    have "init_clss (fst (g i)) = init_clss (fst (g 0))"
      apply (induction i)
        apply simp
      using g inv unfolding cdclW_all_struct_inv_def by (metis cdclW_merge_with_restart_init_clss)
    } note init_g = this
  let ?S = "g 0"
  have "finite (atms_of_msu (init_clss (fst ?S)))"
    using inv unfolding cdclW_all_struct_inv_def by auto
  have snd_g: "⋀i. snd (g i) = i + snd (g 0)"
    apply (induct_tac i)
      apply simp
    by (metis Suc_eq_plus1_left add_Suc cdclW_merge_with_restart_increasing_number g)
  then have snd_g_0: "⋀i. i > 0 ⟹ snd (g i) = i + snd (g 0)"
    by blast
  have unbounded_f_g: "unbounded (λi. f (snd (g i)))"
    using f unfolding bounded_def by (metis add.commute f less_or_eq_imp_le snd_g
      not_bounded_nat_exists_larger not_le le_iff_add)

  obtain k where
    f_g_k: "f (snd (g k)) > card (simple_clss (atms_of_msu (init_clss (fst ?S))))" and
    "k > card (simple_clss (atms_of_msu (init_clss (fst ?S))))"
    using not_bounded_nat_exists_larger[OF unbounded_f_g] by blast
  text ‹The following does not hold anymore with the non-strict version of
    cardinality in the definition.›
  { fix i
    assume "no_step cdclW_merge_stgy (fst (g i))"
    with g[of i]
    have False
      proof (induction rule: cdclW_merge_with_restart.induct)
        case (restart_step T S n) note H = this(1) and c = this(2) and n_s = this(4)
        obtain S' where "cdclW_merge_stgy S S'"
          using H c by (metis gr_implies_not0 relpowp_E2)
        then show False using n_s by auto
      next
        case (restart_full S T)
        then show False unfolding full1_def by (auto dest: tranclpD)
      qed
    } note H = this
  obtain m T where
    m: "m = card (set_mset (learned_clss T)) - card (set_mset (learned_clss (fst (g k))))" and
    "m > f (snd (g k))" and
    "restart T (fst (g (k+1)))" and
    cdclW_merge_stgy: "(cdclW_merge_stgy ^^ m) (fst (g k)) T"
    using g[of k] H[of "Suc k"] by (force simp: cdclW_merge_with_restart.simps full1_def)
  have "cdclW_merge_stgy** (fst (g k)) T"
    using cdclW_merge_stgy relpowp_imp_rtranclp by metis
  then have "cdclW_all_struct_inv T"
    using inv[of k]  rtranclp_cdclW_all_struct_inv_inv rtranclp_cdclW_merge_stgy_rtranclp_cdclW
    by blast
  moreover have "card (set_mset (learned_clss T)) - card (set_mset (learned_clss (fst (g k))))
      > card (simple_clss (atms_of_msu (init_clss (fst ?S))))"
      unfolding m[symmetric] using ‹m > f (snd (g k))› f_g_k by linarith
    then have "card (set_mset (learned_clss T))
      > card (simple_clss (atms_of_msu (init_clss (fst ?S))))"
      by linarith
  moreover
    have "init_clss (fst (g k)) = init_clss T"
      using ‹cdclW_merge_stgy** (fst (g k)) T› rtranclp_cdclW_merge_stgy_rtranclp_cdclW
      rtranclp_cdclW_init_clss inv unfolding cdclW_all_struct_inv_def by blast
    then have "init_clss (fst ?S) = init_clss T"
      using init_g[of k] by auto
  ultimately show False
    using cdclW_all_struct_inv_learned_clss_bound
    by (simp add: ‹finite (atms_of_msu (init_clss (fst (g 0))))› simple_clss_finite
      card_mono leD)
qed

lemma cdclW_merge_with_restart_distinct_mset_clauses:
  assumes invR: "cdclW_all_struct_inv (fst R)" and
  st: "cdclW_merge_with_restart R S" and
  dist: "distinct_mset (clauses (fst R))" and
  R: "trail (fst R) = []"
  shows "distinct_mset (clauses (fst S))"
  using assms(2,1,3,4)
proof (induction)
  case (restart_full S T)
  then show ?case using rtranclp_cdclW_merge_stgy_distinct_mset_clauses[of S T] unfolding full1_def
    by (auto dest: tranclp_into_rtranclp)
next
  case (restart_step T S n U)
  then have "distinct_mset (clauses T)"
    using rtranclp_cdclW_merge_stgy_distinct_mset_clauses[of S T] unfolding full1_def
    by (auto dest: relpowp_imp_rtranclp)
  then show ?case using ‹restart T U› by (metis clauses_restart distinct_mset_union fstI
    mset_le_exists_conv restart.cases state_eq_clauses)
qed

inductive cdclW_with_restart where
restart_step:
  "(cdclW_stgy^^(card (set_mset (learned_clss T)) - card (set_mset (learned_clss S)))) S T ⟹
     card (set_mset (learned_clss T)) - card (set_mset (learned_clss S)) > f n ⟹
     restart T U ⟹
   cdclW_with_restart (S, n) (U, Suc n)" |
restart_full: "full1 cdclW_stgy S T ⟹ cdclW_with_restart (S, n) (T, Suc n)"

lemma cdclW_with_restart_rtranclp_cdclW:
  "cdclW_with_restart S T ⟹ cdclW** (fst S) (fst T)"
  apply (induction rule: cdclW_with_restart.induct)
  by (auto dest!: relpowp_imp_rtranclp  tranclp_into_rtranclp fw_r_rf
     cdclW_rf.restart rtranclp_cdclW_stgy_rtranclp_cdclW cdclW_merge_restart_cdclW
    simp: full1_def)

lemma cdclW_with_restart_increasing_number:
  "cdclW_with_restart S T ⟹ snd T = 1 + snd S"
  by (induction rule: cdclW_with_restart.induct) auto

lemma "full1 cdclW_stgy S T ⟹ cdclW_with_restart (S, n) (T, Suc n)"
  using restart_full by blast

lemma cdclW_with_restart_init_clss:
  "cdclW_with_restart S T ⟹  cdclW_M_level_inv (fst S) ⟹ init_clss (fst S) = init_clss (fst T)"
  using cdclW_with_restart_rtranclp_cdclW rtranclp_cdclW_init_clss by blast

lemma
  "wf {(T, S). cdclW_all_struct_inv (fst S) ∧ cdclW_with_restart S T}"
proof (rule ccontr)
  assume "¬ ?thesis"
    then obtain g where
    g: "⋀i. cdclW_with_restart (g i) (g (Suc i))" and
    inv: "⋀i. cdclW_all_struct_inv (fst (g i))"
    unfolding wf_iff_no_infinite_down_chain by fast
  { fix i
    have "init_clss (fst (g i)) = init_clss (fst (g 0))"
      apply (induction i)
        apply simp
      using g inv unfolding cdclW_all_struct_inv_def by (metis cdclW_with_restart_init_clss)
    } note init_g = this
  let ?S = "g 0"
  have "finite (atms_of_msu (init_clss (fst ?S)))"
    using inv unfolding cdclW_all_struct_inv_def by auto
  have snd_g: "⋀i. snd (g i) = i + snd (g 0)"
    apply (induct_tac i)
      apply simp
    by (metis Suc_eq_plus1_left add_Suc cdclW_with_restart_increasing_number g)
  then have snd_g_0: "⋀i. i > 0 ⟹ snd (g i) = i + snd (g 0)"
    by blast
  have unbounded_f_g: "unbounded (λi. f (snd (g i)))"
    using f unfolding bounded_def by (metis add.commute f less_or_eq_imp_le snd_g
      not_bounded_nat_exists_larger not_le le_iff_add)

  obtain k where
    f_g_k: "f (snd (g k)) > card (simple_clss (atms_of_msu (init_clss (fst ?S))))" and
    "k > card (simple_clss (atms_of_msu (init_clss (fst ?S))))"
    using not_bounded_nat_exists_larger[OF unbounded_f_g] by blast
  text ‹The following does not hold anymore with the non-strict version of
    cardinality in the definition.›
  { fix i
    assume "no_step cdclW_stgy (fst (g i))"
    with g[of i]
    have False
      proof (induction rule: cdclW_with_restart.induct)
        case (restart_step T S n) note H = this(1) and c = this(2) and n_s = this(4)
        obtain S' where "cdclW_stgy S S'"
          using H c by (metis gr_implies_not0 relpowp_E2)
        then show False using n_s by auto
      next
        case (restart_full S T)
        then show False unfolding full1_def by (auto dest: tranclpD)
      qed
    } note H = this
  obtain m T where
    m: "m = card (set_mset (learned_clss T)) - card (set_mset (learned_clss (fst (g k))))" and
    "m > f (snd (g k))" and
    "restart T (fst (g (k+1)))" and
    cdclW_merge_stgy: "(cdclW_stgy ^^ m) (fst (g k)) T"
    using g[of k] H[of "Suc k"] by (force simp: cdclW_with_restart.simps full1_def)
  have "cdclW_stgy** (fst (g k)) T"
    using cdclW_merge_stgy relpowp_imp_rtranclp by metis
  then have "cdclW_all_struct_inv T"
    using inv[of k]  rtranclp_cdclW_all_struct_inv_inv rtranclp_cdclW_stgy_rtranclp_cdclW by blast
  moreover have "card (set_mset (learned_clss T)) - card (set_mset (learned_clss (fst (g k))))
      > card (simple_clss (atms_of_msu (init_clss (fst ?S))))"
      unfolding m[symmetric] using ‹m > f (snd (g k))› f_g_k by linarith
    then have "card (set_mset (learned_clss T))
      > card (simple_clss (atms_of_msu (init_clss (fst ?S))))"
      by linarith
  moreover
    have "init_clss (fst (g k)) = init_clss T"
      using ‹cdclW_stgy** (fst (g k)) T› rtranclp_cdclW_stgy_rtranclp_cdclW rtranclp_cdclW_init_clss
      inv unfolding cdclW_all_struct_inv_def
      by blast
    then have "init_clss (fst ?S) = init_clss T"
      using init_g[of k] by auto
  ultimately show False
    using cdclW_all_struct_inv_learned_clss_bound
    by (simp add: ‹finite (atms_of_msu (init_clss (fst (g 0))))› simple_clss_finite
      card_mono leD)
qed

lemma cdclW_with_restart_distinct_mset_clauses:
  assumes invR: "cdclW_all_struct_inv (fst R)" and
  st: "cdclW_with_restart R S" and
  dist: "distinct_mset (clauses (fst R))" and
  R: "trail (fst R) = []"
  shows "distinct_mset (clauses (fst S))"
  using assms(2,1,3,4)
proof (induction)
  case (restart_full S T)
  then show ?case using rtranclp_cdclW_stgy_distinct_mset_clauses[of S T] unfolding full1_def
    by (auto dest: tranclp_into_rtranclp)
next
  case (restart_step T S n U)
  then have "distinct_mset (clauses T)" using rtranclp_cdclW_stgy_distinct_mset_clauses[of S T]
    unfolding full1_def by (auto dest: relpowp_imp_rtranclp)
  then show ?case using ‹restart T U› by (metis clauses_restart distinct_mset_union fstI
    mset_le_exists_conv restart.cases state_eq_clauses)
qed
end

locale luby_sequence =
  fixes ur :: nat (*unit run*)
  assumes "ur > 0"
begin

lemma exists_luby_decomp:
  fixes i ::nat
  shows "∃k::nat. (2 ^ (k - 1) ≤ i ∧ i < 2 ^ k - 1) ∨ i = 2 ^ k - 1"
proof (induction i)
  case 0
  then show ?case
    by (rule exI[of _ 0], simp)
next
  case (Suc n)
  then obtain k where "2 ^ (k - 1) ≤ n ∧ n < 2 ^ k - 1 ∨ n = 2 ^ k - 1"
    by blast
  then consider
      (st_interv) "2 ^ (k - 1) ≤ n" and  "n ≤ 2 ^ k - 2"
    | (end_interv) "2 ^ (k - 1) ≤ n" and "n = 2 ^ k - 2"
    | (pow2) "n = 2 ^ k - 1"
    by linarith
  then show ?case
    proof cases
      case st_interv
      then show ?thesis apply - apply (rule exI[of _ k])
        by (metis (no_types, lifting) One_nat_def Suc_diff_Suc Suc_lessI
          ‹2 ^ (k - 1) ≤ n ∧ n < 2 ^ k - 1 ∨ n = 2 ^ k - 1› diff_self_eq_0
          dual_order.trans le_SucI le_imp_less_Suc numeral_2_eq_2 one_le_numeral
          one_le_power zero_less_numeral zero_less_power)
    next
      case end_interv
      then show ?thesis apply - apply (rule exI[of _ k]) by auto
    next
      case pow2
      then show ?thesis apply - apply (rule exI[of _ "k+1"]) by auto
    qed
qed

text ‹Luby sequences are defined by:
   ▪ @{term "(2::nat)^(k::nat)- 1"}, if @{term "i = 2^k - 1"}
   ▪ @{term "luby_sequence_core (i - (2::nat)^(k - 1) + 1)"}, if @{term "2^(k - 1) ≤ i"} and
   @{term "i ≤ 2^k - 1"}

Then the sequence is then scaled by a constant unit run (called @{term ur} here), strictly positive.
›
function luby_sequence_core :: "nat ⇒ nat" where
"luby_sequence_core i =
  (if ∃k. i = 2^k - 1
  then 2^((SOME k. i = 2^k - 1) - 1)
  else luby_sequence_core (i - 2^((SOME k. 2^(k-1)≤ i ∧ i < 2^k - 1) - 1) + 1))"
by auto
termination
proof (relation "less_than", goal_cases)
  case 1
  then show ?case by auto
next
  case (2 i)
  let ?k = "(SOME k. 2 ^ (k - 1) ≤ i ∧ i < 2 ^ k - 1)"
  have "2 ^ (?k - 1) ≤ i ∧ i < 2 ^ ?k - 1"
    apply (rule someI_ex)
    using "2" exists_luby_decomp by blast
  then show ?case
    (* sledgehammer *)
    proof -
      have "∀n na. ¬ (1::nat) ≤ n ∨ 1 ≤ n ^ na"
        by (meson one_le_power)
      then have f1: "(1::nat) ≤ 2 ^ (?k - 1)"
        using one_le_numeral by blast
      have f2: "i - 2 ^ (?k - 1) + 2 ^ (?k - 1) = i"
        using ‹2 ^ (?k - 1) ≤ i ∧ i < 2 ^ ?k - 1› le_add_diff_inverse2 by blast
      have f3: "2 ^ ?k - 1 ≠ Suc 0"
        using f1 ‹2 ^ (?k - 1) ≤ i ∧ i < 2 ^ ?k - 1› by linarith
      have "2 ^ ?k - (1::nat) ≠ 0"
        using ‹2 ^ (?k - 1) ≤ i ∧ i < 2 ^ ?k - 1› gr_implies_not0 by blast
      then have f4: "2 ^ ?k ≠ (1::nat)"
        by linarith
      have f5: "∀n na. if na = 0 then (n::nat) ^ na = 1 else n ^ na = n * n ^ (na - 1)"
        by (simp add: power_eq_if)
      then have "?k ≠ 0"
        using f4 by meson
      then have "2 ^ (?k - 1) ≠ Suc 0"
        using f5 f3 by presburger
      then have "Suc 0 < 2 ^ (?k - 1)"
        using f1 by linarith
      then show ?thesis
        using f2 less_than_iff by presburger
    qed
qed

declare luby_sequence_core.simps[simp del]

lemma two_pover_n_eq_two_power_n'_eq:
  assumes H: "(2::nat) ^ (k::nat) - 1 = 2 ^ k' - 1"
  shows "k' = k"
proof -
  have "(2::nat) ^ (k::nat) = 2 ^ k'"
    using H by (metis One_nat_def Suc_pred zero_less_numeral zero_less_power)
  then show ?thesis by simp
qed

lemma luby_sequence_core_two_power_minus_one:
  "luby_sequence_core (2^k - 1) = 2^(k-1)" (is "?L = ?K")
proof -
  have decomp: "∃ka. 2 ^ k - 1 = 2 ^ ka - 1"
    by auto
  have "?L = 2^((SOME k'. (2::nat)^k - 1 = 2^k' - 1) - 1)"
    apply (subst luby_sequence_core.simps, subst decomp)
    by simp
  moreover have "(SOME k'. (2::nat)^k - 1 = 2^k' - 1) = k"
    apply (rule some_equality)
      apply simp
      using two_pover_n_eq_two_power_n'_eq by blast
  ultimately show ?thesis by presburger
qed

lemma different_luby_decomposition_false:
  assumes
    H: "2 ^ (k - Suc 0) ≤ i" and
    k': "i < 2 ^ k' - Suc 0" and
    k_k': "k > k'"
  shows "False"
proof -
  have "2 ^ k' - Suc 0 < 2 ^ (k - Suc 0)"
    using k_k' less_eq_Suc_le by auto
  then show ?thesis
    using H k' by linarith
qed

lemma luby_sequence_core_not_two_power_minus_one:
  assumes
    k_i: "2 ^ (k - 1) ≤ i" and
    i_k: "i < 2^ k - 1"
  shows "luby_sequence_core i = luby_sequence_core (i - 2 ^ (k - 1) + 1)"
proof -
  have H: "¬ (∃ka. i = 2 ^ ka - 1)"
    proof (rule ccontr)
      assume "¬ ?thesis"
      then obtain k'::nat where k': "i = 2 ^ k' - 1" by blast
      have "(2::nat) ^ k' - 1 < 2 ^ k - 1"
        using i_k unfolding k' .
      then have "(2::nat) ^ k' < 2 ^ k"
        by linarith
      then have "k' < k"
        by simp
      have "2 ^ (k - 1) ≤ 2 ^ k' - (1::nat)"
        using k_i unfolding k' .
      then have "(2::nat) ^ (k-1) < 2 ^ k'"
        by (metis Suc_diff_1 not_le not_less_eq zero_less_numeral zero_less_power)
      then have "k-1 < k'"
        by simp

      show False using ‹k' < k› ‹k-1 < k'› by linarith
    qed
  have "⋀k k'. 2 ^ (k - Suc 0) ≤ i ⟹ i < 2 ^ k - Suc 0 ⟹ 2 ^ (k' - Suc 0) ≤ i ⟹
    i < 2 ^ k' - Suc 0 ⟹ k = k'"
    by (meson different_luby_decomposition_false linorder_neqE_nat)
  then have k: "(SOME k. 2 ^ (k - Suc 0) ≤ i ∧ i < 2 ^ k - Suc 0) = k"
    using k_i i_k by auto
  show ?thesis
    apply (subst luby_sequence_core.simps[of i], subst H)
    by (simp add: k)
qed

lemma unbounded_luby_sequence_core: "unbounded luby_sequence_core"
  unfolding bounded_def
proof
  assume "∃b. ∀n. luby_sequence_core n ≤ b"
  then obtain b where b: "⋀n. luby_sequence_core n ≤ b"
    by metis
  have "luby_sequence_core (2^(b+1) - 1) = 2^b"
    using luby_sequence_core_two_power_minus_one[of "b+1"] by simp
  moreover have "(2::nat)^b > b"
    by (induction b) auto
  ultimately show False using b[of "2^(b+1) - 1"] by linarith
qed

abbreviation luby_sequence :: "nat ⇒ nat" where
"luby_sequence n ≡  ur * luby_sequence_core n"

lemma bounded_luby_sequence: "unbounded luby_sequence"
  using bounded_const_product[of ur] luby_sequence_axioms
  luby_sequence_def unbounded_luby_sequence_core by blast

lemma luby_sequence_core_0: "luby_sequence_core 0 = 1"
proof -
  have 0: "(0::nat) = 2^0-1"
    by auto
  show ?thesis
    by (subst 0, subst luby_sequence_core_two_power_minus_one) simp
qed

lemma "luby_sequence_core n ≥ 1"
proof (induction n rule: nat_less_induct_case)
  case 0
  then show ?case by (simp add: luby_sequence_core_0)
next
  case (Suc n) note IH = this

  consider
      (interv) k where "2 ^ (k - 1) ≤ Suc n" and "Suc n < 2 ^ k - 1"
    | (pow2)  k where "Suc n = 2 ^ k - Suc 0"
    using exists_luby_decomp[of "Suc n"] by auto

  then show ?case
     proof cases
       case pow2
       show ?thesis
         using luby_sequence_core_two_power_minus_one pow2 by auto
     next
       case interv
       have n: "Suc n - 2 ^ (k - 1) + 1 < Suc n"
         by (metis Suc_1 Suc_eq_plus1 add.commute add_diff_cancel_left' add_less_mono1 gr0I
           interv(1) interv(2) le_add_diff_inverse2 less_Suc_eq not_le power_0 power_one_right
           power_strict_increasing_iff)
       show ?thesis
         apply (subst luby_sequence_core_not_two_power_minus_one[OF interv])
         using IH n by auto
     qed
qed
end

locale luby_sequence_restart =
  luby_sequence ur +
  cdclW trail init_clss learned_clss backtrack_lvl conflicting cons_trail tl_trail
    add_init_cls
    add_learned_cls remove_cls update_backtrack_lvl update_conflicting init_state
    restart_state
  for
    ur :: nat and
    trail :: "'st ⇒ ('v, nat, 'v clause) ann_literals" and
    init_clss :: "'st ⇒ 'v clauses" and
    learned_clss :: "'st ⇒ 'v clauses" and
    backtrack_lvl :: "'st ⇒ nat" and
    conflicting :: "'st ⇒'v clause option" and
    cons_trail :: "('v, nat, 'v clause) ann_literal ⇒ 'st ⇒ 'st" and
    tl_trail :: "'st ⇒ 'st" and
    add_init_cls :: "'v clause ⇒ 'st ⇒ 'st" and
    add_learned_cls remove_cls :: "'v clause ⇒ 'st ⇒ 'st" and
    update_backtrack_lvl :: "nat ⇒ 'st ⇒ 'st" and
    update_conflicting :: "'v clause option ⇒ 'st ⇒ 'st" and

    init_state :: "'v clauses ⇒ 'st" and
    restart_state :: "'st ⇒ 'st"
begin

sublocale cdclW_restart _ _ _ _ _ _ _ _ _ _ _ _ _ _ luby_sequence
  apply unfold_locales
  using bounded_luby_sequence by blast

end

end