theory CDCL_WNOT imports CDCL_NOT CDCL_W_Merge begin section ‹Link between Weidenbach's and NOT's CDCL› subsection ‹Inclusion of the states› declare upt.simps(2)[simp del] fun convert_ann_lit_from_W where "convert_ann_lit_from_W (Propagated L _) = Propagated L ()" | "convert_ann_lit_from_W (Decided L) = Decided L" abbreviation convert_trail_from_W :: "('v, 'mark) ann_lits ⇒ ('v, unit) ann_lits" where "convert_trail_from_W ≡ map convert_ann_lit_from_W" lemma lits_of_l_convert_trail_from_W[simp]: "lits_of_l (convert_trail_from_W M) = lits_of_l M" by (induction rule: ann_lit_list_induct) simp_all lemma lit_of_convert_trail_from_W[simp]: "lit_of (convert_ann_lit_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 no_dup_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 image_image lits_of_def) lemma defined_lit_convert_trail_from_W[simp]: "defined_lit (convert_trail_from_W S) = defined_lit S" by (auto simp: defined_lit_map image_comp intro!: ext) lemma is_decided_convert_trail_from_W[simp]: ‹is_decided (convert_ann_lit_from_W L) = is_decided L› by (cases L) auto lemma count_decided_conver_Trail_from_W[simp]: ‹count_decided (convert_trail_from_W M) = count_decided M› unfolding count_decided_def by (auto simp: comp_def) text ‹The values @{term "0::nat"} and @{term "{#}"} are dummy values.› consts dummy_cls :: 'cls fun convert_ann_lit_from_NOT :: "('v, 'mark) ann_lit ⇒ ('v, 'cls) ann_lit" where "convert_ann_lit_from_NOT (Propagated L _) = Propagated L dummy_cls" | "convert_ann_lit_from_NOT (Decided L) = Decided L" abbreviation convert_trail_from_NOT where "convert_trail_from_NOT ≡ map convert_ann_lit_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_lit_list_induct) (auto simp: defined_lit_map) lemma lits_of_l_convert_trail_from_NOT: "lits_of_l (convert_trail_from_NOT F) = lits_of_l F" by (induction F rule: ann_lit_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_lit_list_induct) auto lemma convert_trail_from_W_convert_lit_from_NOT[simp]: "convert_ann_lit_from_W (convert_ann_lit_from_NOT L) = L" by (cases L) auto abbreviation trail⇩N⇩O⇩T where "trail⇩N⇩O⇩T 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_lit_from_NOT[iff]: "lit_of (convert_ann_lit_from_NOT L) = lit_of L" by (cases L) auto sublocale state⇩W ⊆ dpll_state_ops where trail = "λS. convert_trail_from_W (trail S)" and clauses⇩N⇩O⇩T = clauses and prepend_trail = "λL S. cons_trail (convert_ann_lit_from_NOT L) S" and tl_trail = "λS. tl_trail S" and add_cls⇩N⇩O⇩T = "λC S. add_learned_cls C S" and remove_cls⇩N⇩O⇩T = "λC S. remove_cls C S" by unfold_locales sublocale state⇩W ⊆ dpll_state where trail = "λS. convert_trail_from_W (trail S)" and clauses⇩N⇩O⇩T = clauses and prepend_trail = "λL S. cons_trail (convert_ann_lit_from_NOT L) S" and tl_trail = "λS. tl_trail S" and add_cls⇩N⇩O⇩T = "λC S. add_learned_cls C S" and remove_cls⇩N⇩O⇩T = "λC S. remove_cls C S" by unfold_locales (auto simp: map_tl o_def) context state⇩W begin declare state_simp⇩N⇩O⇩T[simp del] end subsection ‹Inclusion of Weidendenbch's CDCL without Strategy› sublocale conflict_driven_clause_learning⇩W ⊆ cdcl⇩N⇩O⇩T_merge_bj_learn_ops where trail = "λS. convert_trail_from_W (trail S)" and clauses⇩N⇩O⇩T = clauses and prepend_trail = "λL S. cons_trail (convert_ann_lit_from_NOT L) S" and tl_trail = "λS. tl_trail S" and add_cls⇩N⇩O⇩T = "λC S. add_learned_cls C S" and remove_cls⇩N⇩O⇩T = "λC S. remove_cls C S" and decide_conds = "λ_ _. True" and propagate_conds = "λ_ _ _. True" and forget_conds = "λ_ S. conflicting S = None" and backjump_l_cond = "λC C' L' S T. backjump_l_cond C C' L' S T ∧ distinct_mset C' ∧ L' ∉# C' ∧ ¬tautology (add_mset L' C')" by unfold_locales sublocale conflict_driven_clause_learning⇩W ⊆ cdcl⇩N⇩O⇩T_merge_bj_learn_proxy where trail = "λS. convert_trail_from_W (trail S)" and clauses⇩N⇩O⇩T = clauses and prepend_trail = "λL S. cons_trail (convert_ann_lit_from_NOT L) S" and tl_trail = "λS. tl_trail S" and add_cls⇩N⇩O⇩T = "λC S. add_learned_cls C S" and remove_cls⇩N⇩O⇩T = "λC S. remove_cls C S" and decide_conds = "λ_ _. True" and propagate_conds = "λ_ _ _. True" and forget_conds = "λ_ S. conflicting S = None" and backjump_l_cond = backjump_l_cond and inv = inv⇩N⇩O⇩T by unfold_locales sublocale conflict_driven_clause_learning⇩W ⊆ cdcl⇩N⇩O⇩T_merge_bj_learn where trail = "λS. convert_trail_from_W (trail S)" and clauses⇩N⇩O⇩T = clauses and prepend_trail = "λL S. cons_trail (convert_ann_lit_from_NOT L) S" and tl_trail = "λS. tl_trail S" and add_cls⇩N⇩O⇩T = "λC S. add_learned_cls C S" and remove_cls⇩N⇩O⇩T = "λC S. remove_cls C S" and decide_conds = "λ_ _. True" and propagate_conds = "λ_ _ _. True" and forget_conds = "λ_ S. conflicting S = None" and backjump_l_cond = backjump_l_cond and inv = inv⇩N⇩O⇩T proof (unfold_locales, goal_cases) case 2 then show ?case using cdcl⇩N⇩O⇩T_merged_bj_learn_no_dup_inv by (auto simp: comp_def) next case (1 C' S C F' K F L) let ?C' = "remdups_mset C'" have "L ∉# C'" using ‹F ⊨as CNot C'› ‹undefined_lit F L› Decided_Propagated_in_iff_in_lits_of_l in_CNot_implies_uminus(2) by fast then have dist: "distinct_mset ?C'" "L ∉# C'" by simp_all have "no_dup F" using ‹inv⇩N⇩O⇩T S› ‹convert_trail_from_W (trail S) = F' @ Decided K # F› unfolding inv⇩N⇩O⇩T_def by (metis no_dup_appendD no_dup_cons no_dup_convert_from_W) then have "consistent_interp (lits_of_l F)" using distinct_consistent_interp by blast then have "¬ tautology C'" using ‹F ⊨as CNot C'› consistent_CNot_not_tautology true_annots_true_cls by blast then have taut: "¬ tautology (add_mset L ?C')" using ‹F ⊨as CNot C'› ‹undefined_lit F L› by (metis CNot_remdups_mset Decided_Propagated_in_iff_in_lits_of_l in_CNot_uminus tautology_add_mset tautology_remdups_mset true_annot_singleton true_annots_def) have f2: "no_dup (convert_trail_from_W (trail S))" using ‹inv⇩N⇩O⇩T S› unfolding inv⇩N⇩O⇩T_def by (simp add: o_def) have f3: "atm_of L ∈ atms_of_mm (clauses S) ∪ atm_of ` lits_of_l (convert_trail_from_W (trail S))" using ‹convert_trail_from_W (trail S) = F' @ Decided K # F› ‹atm_of L ∈ atms_of_mm (clauses S) ∪ atm_of ` lits_of_l (F' @ Decided K # F)› by auto have f4: "clauses S ⊨pm add_mset L ?C'" by (metis "1"(7) dist(2) remdups_mset_singleton_sum true_clss_cls_remdups_mset) have "F ⊨as CNot ?C'" by (simp add: ‹F ⊨as CNot C'›) have "Ex (backjump_l S)" apply standard apply (rule backjump_l.intros[of _ _ _ _ _ L "add_mset L ?C'" _ ?C']) using f4 f3 f2 ‹¬ tautology (add_mset L ?C')› 1 taut dist ‹F ⊨as CNot (remdups_mset C')› state_eq⇩N⇩O⇩T_ref unfolding backjump_l_cond_def set_mset_remdups_mset by blast+ then show ?case by blast next case (3 L S) then show "∃T. decide⇩N⇩O⇩T S T ∨ propagate⇩N⇩O⇩T S T ∨ backjump_l S T" using decide⇩N⇩O⇩T.intros[of S L] by auto qed context conflict_driven_clause_learning⇩W begin text ‹Notations are lost while proving locale inclusion:› notation state_eq⇩N⇩O⇩T (infix "∼⇩N⇩O⇩T" 50) subsection ‹Additional Lemmas between NOT and W states› lemma trail⇩W_eq_reduce_trail_to⇩N⇩O⇩T_eq: "trail S = trail T ⟹ trail (reduce_trail_to⇩N⇩O⇩T F S) = trail (reduce_trail_to⇩N⇩O⇩T F T)" proof (induction F S arbitrary: T rule: reduce_trail_to⇩N⇩O⇩T.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_to⇩N⇩O⇩T F (tl_trail S)) = trail (reduce_trail_to⇩N⇩O⇩T F (tl_trail T))" using IH by (metis (no_types) trail_tl_trail) then show "trail (reduce_trail_to⇩N⇩O⇩T F S) = trail (reduce_trail_to⇩N⇩O⇩T F T)" using tr by (metis (no_types) reduce_trail_to⇩N⇩O⇩T.elims) qed lemma trail_reduce_trail_to⇩N⇩O⇩T_add_learned_cls: "no_dup (trail S) ⟹ trail (reduce_trail_to⇩N⇩O⇩T M (add_learned_cls D S)) = trail (reduce_trail_to⇩N⇩O⇩T M S)" by (rule trail⇩W_eq_reduce_trail_to⇩N⇩O⇩T_eq) simp lemma reduce_trail_to⇩N⇩O⇩T_reduce_trail_convert: "reduce_trail_to⇩N⇩O⇩T C S = reduce_trail_to (convert_trail_from_NOT C) S" apply (induction C S rule: reduce_trail_to⇩N⇩O⇩T.induct) apply (subst reduce_trail_to⇩N⇩O⇩T.simps, subst reduce_trail_to.simps) by auto lemma reduce_trail_to_map[simp]: "reduce_trail_to (map f M) S = reduce_trail_to M S" by (rule reduce_trail_to_length) simp lemma reduce_trail_to⇩N⇩O⇩T_map[simp]: "reduce_trail_to⇩N⇩O⇩T (map f M) S = reduce_trail_to⇩N⇩O⇩T M S" by (rule reduce_trail_to⇩N⇩O⇩T_length) simp lemma skip_or_resolve_state_change: assumes "skip_or_resolve⇧*⇧* S T" shows "∃M. trail S = M @ trail T ∧ (∀m ∈ set M. ¬is_decided m)" "clauses S = clauses T" "backtrack_lvl S = backtrack_lvl T" "init_clss S = init_clss T" "learned_clss S = learned_clss T" using assms proof (induction rule: rtranclp_induct) case base case 1 show ?case by simp case 2 show ?case by simp case 3 show ?case by simp case 4 show ?case by simp case 5 show ?case by simp next case (step T U) note st = this(1) and s_o_r = this(2) and IH = this(3) and IH' = this(3-) case 2 show ?case using IH' s_o_r by (auto elim!: rulesE simp: skip_or_resolve.simps) case 3 show ?case using IH' s_o_r by (cases ‹trail T›) (auto elim!: rulesE simp: skip_or_resolve.simps) case 1 show ?case using s_o_r IH by (cases "trail T") (auto elim!: rulesE simp: skip_or_resolve.simps) case 4 show ?case using s_o_r IH' by (cases "trail T") (auto elim!: rulesE simp: skip_or_resolve.simps) case 5 show ?case using s_o_r IH' by (cases "trail T") (auto elim!: rulesE simp: skip_or_resolve.simps) qed subsection ‹Inclusion of Weidenbach's CDCL in NOT's CDCL› text ‹This lemma shows the inclusion of Weidenbach's CDCL @{const cdcl⇩W_merge} (with merging) in NOT's @{const cdcl⇩N⇩O⇩T_merged_bj_learn}.› lemma cdcl⇩W_merge_is_cdcl⇩N⇩O⇩T_merged_bj_learn: assumes inv: "cdcl⇩W_all_struct_inv S" and cdcl⇩W_restart: "cdcl⇩W_merge S T" shows "cdcl⇩N⇩O⇩T_merged_bj_learn S T ∨ (no_step cdcl⇩W_merge T ∧ conflicting T ≠ None)" using cdcl⇩W_restart inv proof induction case (fw_propagate S T) note propa = this(1) then obtain M N U L C where H: "state_butlast S = (M, N, U, None)" and CL: "C + {#L#} ∈# clauses S" and M_C: "M ⊨as CNot C" and undef: "undefined_lit (trail S) L" and T: "state_butlast T = (Propagated L (C + {#L#}) # M, N, U, None)" by (auto elim: propagate_high_levelE) have "propagate⇩N⇩O⇩T S T" using H CL T undef M_C by (auto simp: state_eq⇩N⇩O⇩T_def clauses_def simp del: state_simp) then show ?case using cdcl⇩N⇩O⇩T_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_mm (init_clss S)" and T: "T ∼ cons_trail (Decided L) S" by (auto elim: decideE) have "decide⇩N⇩O⇩T S T" apply (rule decide⇩N⇩O⇩T.decide⇩N⇩O⇩T) using undef_L apply (simp; fail) using atm_L inv apply (auto simp: cdcl⇩W_all_struct_inv_def no_strange_atm_def clauses_def; fail) using T undef_L unfolding state_eq⇩N⇩O⇩T_def by (auto simp: clauses_def) then show ?case using cdcl⇩N⇩O⇩T_merged_bj_learn_decide⇩N⇩O⇩T by blast next case (fw_forget S T) note rf = this(1) and inv = this(2) then obtain C where S: "conflicting S = None" and C_le: "C ∈# learned_clss S" and "¬(trail S) ⊨asm clauses S" and "C ∉ set (get_all_mark_of_propagated (trail S))" and C_init: "C ∉# init_clss S" and T: "T ∼ remove_cls C S" and S_C: ‹removeAll_mset C (clauses S) ⊨pm C› by (auto elim: forgetE) have "forget⇩N⇩O⇩T S T" apply (rule forget⇩N⇩O⇩T.forget⇩N⇩O⇩T) using S_C apply blast using S apply simp using C_init C_le apply (simp add: clauses_def) using T C_le C_init by (auto simp: Un_Diff state_eq⇩N⇩O⇩T_def clauses_def ac_simps) then show ?case using cdcl⇩N⇩O⇩T_merged_bj_learn_forget⇩N⇩O⇩T by blast next case (fw_conflict S T U) note confl = this(1) and bj = this(2) and inv = this(3) obtain C⇩S CT where confl_T: "conflicting T = Some CT" and CT: "CT = C⇩S" and C⇩S: "C⇩S ∈# clauses S" and tr_S_C⇩S: "trail S ⊨as CNot C⇩S" using confl by (elim conflictE) auto have inv_T: "cdcl⇩W_all_struct_inv T" using cdcl⇩W_restart.simps cdcl⇩W_all_struct_inv_inv confl inv by blast then have "cdcl⇩W_M_level_inv T" unfolding cdcl⇩W_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_cdcl⇩W_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 simp: skip_or_resolve.simps elim!: rulesE) moreover then have "no_step cdcl⇩W_merge U" by (auto simp: cdcl⇩W_merge.simps elim: rulesE) ultimately show ?thesis by blast next case bt note s_or_r = this(1) and bt = this(2) have "cdcl⇩W_restart⇧*⇧* T T'" using s_or_r mono_rtranclp[of skip_or_resolve cdcl⇩W_restart] rtranclp_skip_or_resolve_rtranclp_cdcl⇩W_restart by blast then have "cdcl⇩W_M_level_inv T'" using rtranclp_cdcl⇩W_restart_consistent_inv ‹cdcl⇩W_M_level_inv T› by blast then obtain M1 M2 i D L K D' where confl_T': "conflicting T' = Some (add_mset L D)" and M1_M2:"(Decided K # M1, M2) ∈ set (get_all_ann_decomposition (trail T'))" and "get_level (trail T') K = i+1" "get_level (trail T') L = backtrack_lvl T'" and "get_level (trail T') L = get_maximum_level (trail T') (add_mset L D')" and "get_maximum_level (trail T') D' = i" and U: "U ∼ cons_trail (Propagated L (add_mset L D')) (reduce_trail_to M1 (add_learned_cls (add_mset L D') (update_conflicting None T')))" and D_D': ‹D' ⊆# D› and T'_L_D': ‹clauses T' ⊨pm add_mset L D'› using bt by (auto elim: backtrackE) let ?D' = ‹add_mset L D'› have [simp]: "clauses S = clauses T" using confl by (auto elim: rulesE) 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 simp: skip_or_resolve.simps elim: rulesE) then show ?case using IH by auto qed have "cdcl⇩W_restart⇧*⇧* T T'" using rtranclp_skip_or_resolve_rtranclp_cdcl⇩W_restart s_or_r by blast have inv_T': "cdcl⇩W_all_struct_inv T'" using ‹cdcl⇩W_restart⇧*⇧* T T'› inv_T rtranclp_cdcl⇩W_all_struct_inv_inv by blast have inv_U: "cdcl⇩W_all_struct_inv U" using cdcl⇩W_merge_restart_cdcl⇩W_restart confl fw_r_conflict inv local.bj rtranclp_cdcl⇩W_all_struct_inv_inv by blast have [simp]: "init_clss S = init_clss T'" using ‹cdcl⇩W_restart⇧*⇧* T T'› cdcl⇩W_restart_init_clss confl cdcl⇩W_all_struct_inv_def conflict inv by (metis rtranclp_cdcl⇩W_restart_init_clss) then have atm_L: "atm_of L ∈ atms_of_mm (clauses S)" using inv_T' confl_T' unfolding cdcl⇩W_all_struct_inv_def no_strange_atm_def clauses_def by (simp add: atms_of_def image_subset_iff) obtain M where tr_T: "trail T = M @ trail T'" using s_or_r skip_or_resolve_state_change by meson obtain M' where tr_T': "trail T' = M' @ Decided K # tl (trail U)" and tr_U: "trail U = Propagated L ?D' # tl (trail U)" using U M1_M2 inv_T' unfolding cdcl⇩W_all_struct_inv_def cdcl⇩W_M_level_inv_def by fastforce define M'' where "M'' ≡ M @ M'" have tr_T: "trail S = M'' @ Decided K # tl (trail U)" using tr_T tr_T' confl unfolding M''_def by (auto elim: rulesE) have "init_clss T' + learned_clss S ⊨pm ?D'" using inv_T' confl_T' ‹clauses S = clauses T› ‹clauses T = clauses T'› T'_L_D' unfolding cdcl⇩W_all_struct_inv_def cdcl⇩W_learned_clause_alt_def clauses_def by auto 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]"]) using confl M1_M2 ‹trail T = M @ trail T'› apply (auto dest!: get_all_ann_decomposition_exists_prepend elim!: conflictE) by (rule sym) auto ultimately have [simp]: "trail (reduce_trail_to⇩N⇩O⇩T M1 S) = M1" using M1_M2 confl by (subst reduce_trail_to⇩N⇩O⇩T_reduce_trail_convert) (auto simp: comp_def elim: rulesE) have "every_mark_is_a_conflict U" using inv_U unfolding cdcl⇩W_all_struct_inv_def cdcl⇩W_conflicting_def by simp then have U_D: "tl (trail U) ⊨as CNot D'" by (subst tr_U, subst (asm) tr_U) fastforce have undef_L: "undefined_lit (tl (trail U)) L" using U M1_M2 inv_U unfolding cdcl⇩W_all_struct_inv_def cdcl⇩W_M_level_inv_def by (auto simp: lits_of_def defined_lit_map) have "backjump_l S U" apply (rule backjump_l[of _ _ _ _ _ L ?D' _ "D'"]) using tr_T apply (simp; fail) using U M1_M2 confl M1_M2 inv_T' inv unfolding cdcl⇩W_all_struct_inv_def cdcl⇩W_M_level_inv_def apply (auto simp: state_eq⇩N⇩O⇩T_def trail_reduce_trail_to⇩N⇩O⇩T_add_learned_cls; fail)[] using C⇩S apply (auto; fail)[] using tr_S_C⇩S apply (simp; fail) using undef_L apply (auto; fail)[] using atm_L apply (simp add: trail_reduce_trail_to⇩N⇩O⇩T_add_learned_cls; fail) using ‹init_clss T' + learned_clss S ⊨pm ?D'› unfolding clauses_def apply (simp; fail) apply (simp; fail) apply (metis U_D convert_trail_from_W_true_annots) using inv_T' inv_U U confl_T' undef_L M1_M2 unfolding cdcl⇩W_all_struct_inv_def distinct_cdcl⇩W_state_def by (auto simp: cdcl⇩W_M_level_inv_decomp backjump_l_cond_def dest: multi_member_split) then show ?thesis using cdcl⇩N⇩O⇩T_merged_bj_learn_backjump_l by fast qed qed abbreviation cdcl⇩N⇩O⇩T_restart where "cdcl⇩N⇩O⇩T_restart ≡ restart_ops.cdcl⇩N⇩O⇩T_raw_restart cdcl⇩N⇩O⇩T restart" lemma cdcl⇩W_merge_restart_is_cdcl⇩N⇩O⇩T_merged_bj_learn_restart_no_step: assumes inv: "cdcl⇩W_all_struct_inv S" and cdcl⇩W_restart:"cdcl⇩W_merge_restart S T" shows "cdcl⇩N⇩O⇩T_restart⇧*⇧* S T ∨ (no_step cdcl⇩W_merge T ∧ conflicting T ≠ None)" proof - consider (fw) "cdcl⇩W_merge S T" | (fw_r) "restart S T" using cdcl⇩W_restart by (meson cdcl⇩W_merge_restart.simps cdcl⇩W_rf.cases fw_conflict fw_decide fw_forget fw_propagate) then show ?thesis proof cases case fw then have IH: "cdcl⇩N⇩O⇩T_merged_bj_learn S T ∨ (no_step cdcl⇩W_merge T ∧ conflicting T ≠ None)" using inv cdcl⇩W_merge_is_cdcl⇩N⇩O⇩T_merged_bj_learn by blast have invS: "inv⇩N⇩O⇩T S" using inv unfolding cdcl⇩W_all_struct_inv_def cdcl⇩W_M_level_inv_def by auto have ff2: "cdcl⇩N⇩O⇩T⇧+⇧+ S T ⟶ cdcl⇩N⇩O⇩T⇧*⇧* 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 "cdcl⇩N⇩O⇩T ≤ cdcl⇩N⇩O⇩T_restart" by (auto simp: restart_ops.cdcl⇩N⇩O⇩T_raw_restart.simps) then show ?thesis using ff3 ff2 IH cdcl⇩N⇩O⇩T_merged_bj_learn_is_tranclp_cdcl⇩N⇩O⇩T rtranclp_mono[of cdcl⇩N⇩O⇩T cdcl⇩N⇩O⇩T_restart] invS predicate2D by blast next case fw_r then show ?thesis by (blast intro: restart_ops.cdcl⇩N⇩O⇩T_raw_restart.intros) qed qed abbreviation μ⇩F⇩W :: "'st ⇒ nat" where "μ⇩F⇩W S ≡ (if no_step cdcl⇩W_merge S then 0 else 1+μ⇩C⇩D⇩C⇩L'_merged (set_mset (init_clss S)) S)" lemma cdcl⇩W_merge_μ⇩F⇩W_decreasing: assumes inv: "cdcl⇩W_all_struct_inv S" and fw: "cdcl⇩W_merge S T" shows "μ⇩F⇩W T < μ⇩F⇩W S" proof - let ?A = "init_clss S" have atm_clauses: "atms_of_mm (clauses S) ⊆ atms_of_mm ?A" using inv unfolding cdcl⇩W_all_struct_inv_def no_strange_atm_def clauses_def by auto have atm_trail: "atm_of ` lits_of_l (trail S) ⊆ atms_of_mm ?A" using inv unfolding cdcl⇩W_all_struct_inv_def no_strange_atm_def clauses_def by auto have n_d: "no_dup (trail S)" using inv unfolding cdcl⇩W_all_struct_inv_def by (auto simp: cdcl⇩W_M_level_inv_decomp) have [simp]: "¬ no_step cdcl⇩W_merge S" using fw by auto have [simp]: "init_clss S = init_clss T" using cdcl⇩W_merge_restart_cdcl⇩W_restart[of S T] inv rtranclp_cdcl⇩W_restart_init_clss unfolding cdcl⇩W_all_struct_inv_def by (meson cdcl⇩W_merge.simps cdcl⇩W_merge_restart.simps cdcl⇩W_rf.simps fw) consider (merged) "cdcl⇩N⇩O⇩T_merged_bj_learn S T" | (n_s) "no_step cdcl⇩W_merge T" using cdcl⇩W_merge_is_cdcl⇩N⇩O⇩T_merged_bj_learn inv fw by blast then show ?thesis proof cases case merged then show ?thesis using cdcl⇩N⇩O⇩T_decreasing_measure'[OF _ _ atm_clauses, of T] atm_trail n_d by (auto split: if_split simp: comp_def image_image lits_of_def) next case n_s then show ?thesis by simp qed qed lemma wf_cdcl⇩W_merge: "wf {(T, S). cdcl⇩W_all_struct_inv S ∧ cdcl⇩W_merge S T}" apply (rule wfP_if_measure[of _ _ "μ⇩F⇩W"]) using cdcl⇩W_merge_μ⇩F⇩W_decreasing by blast lemma tranclp_cdcl⇩W_merge_cdcl⇩W_merge_trancl: "{(T, S). cdcl⇩W_all_struct_inv S ∧ cdcl⇩W_merge⇧+⇧+ S T} ⊆ {(T, S). cdcl⇩W_all_struct_inv S ∧ cdcl⇩W_merge S T}⇧+" proof - have "(T, S) ∈ {(T, S). cdcl⇩W_all_struct_inv S ∧ cdcl⇩W_merge S T}⇧+" if inv: "cdcl⇩W_all_struct_inv S" and "cdcl⇩W_merge⇧+⇧+ S T" for S T :: 'st using that(2) proof (induction rule: tranclp_induct) case base then show ?case using inv by auto next case (step T U) note st = this(1) and s = this(2) and IH = this(3) have "cdcl⇩W_all_struct_inv T" using st by (meson inv rtranclp_cdcl⇩W_all_struct_inv_inv rtranclp_cdcl⇩W_merge_rtranclp_cdcl⇩W_restart tranclp_into_rtranclp) then have "(U, T) ∈ {(T, S). cdcl⇩W_all_struct_inv S ∧ cdcl⇩W_merge S T}⇧+" using s by auto then show ?case using IH by auto qed then show ?thesis by auto qed lemma wf_tranclp_cdcl⇩W_merge: "wf {(T, S). cdcl⇩W_all_struct_inv S ∧ cdcl⇩W_merge⇧+⇧+ S T}" apply (rule wf_subset) apply (rule wf_trancl) using wf_cdcl⇩W_merge apply simp using tranclp_cdcl⇩W_merge_cdcl⇩W_merge_trancl by simp lemma wf_cdcl⇩W_bj_all_struct: "wf {(T, S). cdcl⇩W_all_struct_inv S ∧ cdcl⇩W_bj S T}" apply (rule wfP_if_measure[of "λ_. True" _ "λT. length (trail T) + (if conflicting T = None then 0 else 1)", simplified]) using cdcl⇩W_bj_measure by (simp add: cdcl⇩W_all_struct_inv_def) lemma cdcl⇩W_conflicting_true_cdcl⇩W_merge_restart: assumes "cdcl⇩W S V" and confl: "conflicting S = None" shows "(cdcl⇩W_merge S V ∧ conflicting V = None) ∨ (conflicting V ≠ None ∧ conflict S V)" using assms proof (induction rule: cdcl⇩W.induct) case W_propagate then show ?case by (auto intro: cdcl⇩W_merge.intros elim: rulesE) next case (W_conflict S') then show ?case by (auto intro: cdcl⇩W_merge.intros elim: rulesE) next case W_other then show ?case proof cases case decide then show ?thesis by (auto intro: cdcl⇩W_merge.intros elim: rulesE) next case bj then show ?thesis using confl by (auto simp: cdcl⇩W_bj.simps elim: rulesE) qed qed lemma trancl_cdcl⇩W_conflicting_true_cdcl⇩W_merge_restart: assumes "cdcl⇩W⇧+⇧+ S V" and inv: "cdcl⇩W_M_level_inv S" and "conflicting S = None" shows "(cdcl⇩W_merge⇧+⇧+ S V ∧ conflicting V = None) ∨ (∃T U. cdcl⇩W_merge⇧*⇧* S T ∧ conflicting V ≠ None ∧ conflict T U ∧ cdcl⇩W_bj⇧*⇧* U V)" using assms proof induction case base then show ?case using cdcl⇩W_conflicting_true_cdcl⇩W_merge_restart by blast next case (step U V) note st = this(1) and cdcl⇩W = this(2) and IH = this(3)[OF this(4-)] and confl[simp] = this(5) and inv = this(4) from cdcl⇩W show ?case proof (cases) case W_propagate moreover have "conflicting U = None" and "conflicting V = None" using W_propagate by (auto elim: propagateE) ultimately show ?thesis using IH cdcl⇩W_merge.fw_propagate[of U V] by auto next case W_conflict moreover have confl_U: "conflicting U = None" and confl_V: "conflicting V ≠ None" using W_conflict by (auto elim!: conflictE) moreover have "cdcl⇩W_merge⇧*⇧* S U" using IH confl_U by auto ultimately show ?thesis using IH by auto next case W_other then show ?thesis proof cases case decide then show ?thesis using IH cdcl⇩W_merge.fw_decide[of U V] by (auto elim: decideE) next case bj then consider (s_or_r) "skip_or_resolve U V" | (bt) "backtrack U V" by (auto simp: cdcl⇩W_bj.simps) then show ?thesis proof cases case s_or_r have f1: "cdcl⇩W_bj⇧+⇧+ U V" by (simp add: local.bj tranclp.r_into_trancl) obtain T T' :: 'st where f2: "cdcl⇩W_merge⇧+⇧+ S U ∨ cdcl⇩W_merge⇧*⇧* S T ∧ conflicting U ≠ None ∧ conflict T T' ∧ cdcl⇩W_bj⇧*⇧* T' U" using IH confl by (meson bj rtranclp.intros(1) rtranclp_cdcl⇩W_merge_restart_no_step_cdcl⇩W_bj rtranclp_cdcl⇩W_merge_tranclp_cdcl⇩W_merge_restart) have "conflicting V ≠ None ∧ conflicting U ≠ None" using ‹skip_or_resolve U V› by (auto simp: skip_or_resolve.simps elim!: skipE resolveE) then show ?thesis by (metis (full_types) IH f1 rtranclp_trans tranclp_into_rtranclp) next case bt then have "conflicting U ≠ None" by (auto elim: backtrackE) then obtain T T' where "cdcl⇩W_merge⇧*⇧* S T" and "conflicting U ≠ None" and "conflict T T'" and "cdcl⇩W_bj⇧*⇧* T' U" using IH confl by (meson bj rtranclp.intros(1) rtranclp_cdcl⇩W_merge_restart_no_step_cdcl⇩W_bj rtranclp_cdcl⇩W_merge_tranclp_cdcl⇩W_merge_restart) have invU: "cdcl⇩W_M_level_inv U" using inv rtranclp_cdcl⇩W_restart_consistent_inv step.hyps(1) by (meson ‹cdcl⇩W_bj⇧*⇧* T' U› ‹cdcl⇩W_merge⇧*⇧* S T› ‹conflict T T'› cdcl⇩W_restart_consistent_inv conflict rtranclp_cdcl⇩W_bj_rtranclp_cdcl⇩W_restart rtranclp_cdcl⇩W_merge_rtranclp_cdcl⇩W_restart) then have "conflicting V = None" using ‹backtrack U V› inv by (auto elim: backtrackE simp: cdcl⇩W_M_level_inv_decomp) have "full cdcl⇩W_bj T' V" apply (rule rtranclp_fullI[of cdcl⇩W_bj T' U V]) using ‹cdcl⇩W_bj⇧*⇧* T' U› apply fast using ‹backtrack U V› backtrack_is_full1_cdcl⇩W_bj invU unfolding full1_def full_def by blast then show ?thesis using cdcl⇩W_merge.fw_conflict[of T T' V] ‹conflict T T'› ‹cdcl⇩W_merge⇧*⇧* S T› ‹conflicting V = None› by auto qed qed qed qed lemma wf_cdcl⇩W: "wf {(T, S). cdcl⇩W_all_struct_inv S ∧ cdcl⇩W S T}" unfolding wf_iff_no_infinite_down_chain proof clarify fix f :: "nat ⇒ 'st" assume "∀i. (f (Suc i), f i) ∈ {(T, S). cdcl⇩W_all_struct_inv S ∧ cdcl⇩W S T}" then have f: "⋀i. (f (Suc i), f i) ∈ {(T, S). cdcl⇩W_all_struct_inv S ∧ cdcl⇩W S T}" by blast { fix f :: "nat ⇒ 'st" assume f: "(f (Suc i), f i) ∈ {(T, S). cdcl⇩W_all_struct_inv S ∧ cdcl⇩W S T}" and confl: "conflicting (f i) ≠ None" for i have "(f (Suc i), f i) ∈ {(T, S). cdcl⇩W_all_struct_inv S ∧ cdcl⇩W_bj S T}" for i using f[of i] confl[of i] by (auto simp: cdcl⇩W.simps cdcl⇩W_o.simps cdcl⇩W_rf.simps elim!: rulesE) then have False using wf_cdcl⇩W_bj_all_struct unfolding wf_iff_no_infinite_down_chain by blast } note no_infinite_conflict = this have st: "cdcl⇩W⇧+⇧+ (f i) (f (Suc (i+j)))" for i j :: nat proof (induction j) case 0 then show ?case using f by auto next case (Suc j) then show ?case using f [of "i+j+1"] by auto qed have st: "i < j ⟹ cdcl⇩W⇧+⇧+ (f i) (f j)" for i j :: nat using st[of i "j - i - 1"] by auto obtain i⇩b where i⇩b: "conflicting (f i⇩b) = None" using f no_infinite_conflict by blast define i⇩0 where i⇩0: "i⇩0 = Max {i⇩0. ∀i < i⇩0. conflicting (f i) ≠ None}" have "finite {i⇩0. ∀i < i⇩0. conflicting (f i) ≠ None}" proof - have "{i⇩0. ∀i < i⇩0. conflicting (f i) ≠ None} ⊆ {0..i⇩b}" using i⇩b by (metis (mono_tags, lifting) atLeast0AtMost atMost_iff mem_Collect_eq not_le subsetI) then show ?thesis by (simp add: finite_subset) qed moreover have "{i⇩0. ∀i < i⇩0. conflicting (f i) ≠ None} ≠ {}" by auto ultimately have "i⇩0 ∈ {i⇩0. ∀i < i⇩0. conflicting (f i) ≠ None}" using Max_in[of "{i⇩0. ∀i<i⇩0. conflicting (f i) ≠ None}"] unfolding i⇩0 by fast then have confl_i⇩0: "conflicting (f i⇩0) = None" proof - have f1: "∀n<i⇩0. conflicting (f n) ≠ None" using ‹i⇩0 ∈ {i⇩0. ∀i<i⇩0. conflicting (f i) ≠ None}› by blast have "Suc i⇩0 ∉ {n. ∀na<n. conflicting (f na) ≠ None}" by (metis (lifting) Max_ge ‹finite {i⇩0. ∀i<i⇩0. conflicting (f i) ≠ None}› i⇩0 lessI not_le) then have "∃n<Suc i⇩0. conflicting (f n) = None" by fastforce then show "conflicting (f i⇩0) = None" using f1 by (metis le_less less_Suc_eq_le) qed have "∀i < i⇩0. conflicting (f i) ≠ None" using ‹i⇩0 ∈ {i⇩0. ∀i < i⇩0. conflicting (f i) ≠ None}› by blast have not_conflicting_none: False if confl: "∀x>i. conflicting (f x) = None" for i :: nat proof - let ?f = "λj. f (i + j+1)" have "cdcl⇩W_merge (?f j) (?f (Suc j))" for j :: nat using f[of "i+j+1"] confl that by (auto dest!: cdcl⇩W_conflicting_true_cdcl⇩W_merge_restart) then have "(?f (Suc j), ?f j) ∈ {(T, S). cdcl⇩W_all_struct_inv S ∧ cdcl⇩W_merge S T}" for j :: nat using f[of "i+j+1"] by auto then show False using wf_cdcl⇩W_merge unfolding wf_iff_no_infinite_down_chain by fast qed have not_conflicting: False if confl: "∀x>i. conflicting (f x) ≠ None" for i :: nat proof - let ?f = "λj. f (Suc (i + j))" have confl: "conflicting (f x) ≠ None" if "x > i" for x :: nat using confl that by auto have [iff]: "¬propagate (?f j) S" "¬decide (?f j) S" "¬conflict (?f j) S" for j :: nat and S :: 'st using confl[of "i+j+1"] by (auto elim!: rulesE) have [iff]: "¬ backtrack (f (Suc (i + j))) (f (Suc (Suc (i + j))))" for j :: nat using confl[of "i+j+2"] by (auto elim!: rulesE) have "cdcl⇩W_bj (?f j) (?f (Suc j))" for j :: nat using f[of "i+j+1"] confl that by (auto simp: cdcl⇩W.simps cdcl⇩W_o.simps elim: rulesE) then have "(?f (Suc j), ?f j) ∈ {(T, S). cdcl⇩W_all_struct_inv S ∧ cdcl⇩W_bj S T}" for j :: nat using f[of "i+j+1"] by auto then show False using wf_cdcl⇩W_bj_all_struct unfolding wf_iff_no_infinite_down_chain by fast qed then have [simp]: "∃x>i. conflicting (f x) = None" for i :: nat by meson have "{j. j > i ∧ conflicting (f j) ≠ None} ≠ {}" for i :: nat using not_conflicting_none by (rule ccontr) auto define g where g: "g = rec_nat i⇩0 (λ_ i. LEAST j. j > i ∧ conflicting (f j) = None)" have g_0: "g 0 = i⇩0" unfolding g by auto have g_Suc: "g (Suc i) = (LEAST j. j > g i ∧ conflicting (f j) = None)" for i unfolding g by auto have g_prop:"g (Suc i) > g i ∧ conflicting (f (g (Suc i))) = None" for i proof (cases i) case 0 then show ?thesis using LeastI_ex[of "λj. j > i⇩0 ∧ conflicting (f j) = None"] by (auto simp: g)[] next case (Suc i') then show ?thesis apply (subst g_Suc, subst g_Suc) using LeastI_ex[of "λj. j > g (Suc i') ∧ conflicting (f j) = None"] by auto qed then have g_increasing: "g (Suc i) > g i" for i :: nat by simp have confl_f_G[simp]: "conflicting (f (g i)) = None" for i :: nat by (cases i) (auto simp: g_prop g_0 confl_i⇩0) have [simp]: "cdcl⇩W_M_level_inv (f i)" "cdcl⇩W_all_struct_inv (f i)" for i :: nat using f[of i] by (auto simp: cdcl⇩W_all_struct_inv_def) let ?fg = "λi. (f (g i))" have "∀i < Suc j. (f (g (Suc i)), f (g i)) ∈ {(T, S). cdcl⇩W_all_struct_inv S ∧ cdcl⇩W_merge⇧+⇧+ S T}" for j :: nat proof (induction j) case 0 have "cdcl⇩W⇧+⇧+ (?fg 0) (?fg 1)" using g_increasing[of 0] by (simp add: st) then show ?case by (auto dest!: trancl_cdcl⇩W_conflicting_true_cdcl⇩W_merge_restart) next case (Suc j) note IH = this(1) let ?i = "g (Suc j)" let ?j = "g (Suc (Suc j))" have "conflicting (f ?i) = None" by auto moreover have "cdcl⇩W_all_struct_inv (f ?i)" by auto ultimately have "cdcl⇩W⇧+⇧+ (f ?i) (f ?j)" using g_increasing by (simp add: st) then have "cdcl⇩W_merge⇧+⇧+ (f ?i) (f ?j)" by (auto dest!: trancl_cdcl⇩W_conflicting_true_cdcl⇩W_merge_restart) then show ?case using IH not_less_less_Suc_eq by auto qed then have "∀i. (f (g (Suc i)), f (g i)) ∈ {(T, S). cdcl⇩W_all_struct_inv S ∧ cdcl⇩W_merge⇧+⇧+ S T}" by blast then show False using wf_tranclp_cdcl⇩W_merge unfolding wf_iff_no_infinite_down_chain by fast qed lemma wf_cdcl⇩W_stgy: ‹wf {(T, S). cdcl⇩W_all_struct_inv S ∧ cdcl⇩W_stgy S T}› by (rule wf_subset[OF wf_cdcl⇩W]) (auto dest: cdcl⇩W_stgy_cdcl⇩W) end subsection ‹Inclusion of Weidendenbch's CDCL with Strategy› context conflict_driven_clause_learning⇩W begin abbreviation propagate_conds where "propagate_conds ≡ λ_. propagate" abbreviation (input) decide_conds where "decide_conds S T ≡ decide S T ∧ no_step conflict S ∧ no_step propagate S" abbreviation backjump_l_conds_stgy :: "'v clause ⇒ 'v clause ⇒ 'v literal ⇒ 'st ⇒ 'st ⇒ bool" where "backjump_l_conds_stgy C C' L S V ≡ (∃T U. conflict S T ∧ full skip_or_resolve T U ∧ conflicting T = Some C ∧ mark_of (hd_trail V) = add_mset L C' ∧ backtrack U V)" abbreviation inv⇩N⇩O⇩T_stgy where "inv⇩N⇩O⇩T_stgy S ≡ conflicting S = None ∧ cdcl⇩W_all_struct_inv S ∧ no_smaller_propa S ∧ cdcl⇩W_stgy_invariant S ∧ propagated_clauses_clauses S" interpretation cdcl⇩W_with_strategy: cdcl⇩N⇩O⇩T_merge_bj_learn_ops where trail = "λS. convert_trail_from_W (trail S)" and clauses⇩N⇩O⇩T = clauses and prepend_trail = "λL S. cons_trail (convert_ann_lit_from_NOT L) S" and tl_trail = "λS. tl_trail S" and add_cls⇩N⇩O⇩T = "λC S. add_learned_cls C S" and remove_cls⇩N⇩O⇩T = "λC S. remove_cls C S" and decide_conds = decide_conds and propagate_conds = propagate_conds and forget_conds = "λ_ _. False" and backjump_l_cond = "λC C' L' S T. backjump_l_conds_stgy C C' L' S T ∧ distinct_mset C' ∧ L' ∉# C' ∧ ¬tautology (add_mset L' C')" by unfold_locales interpretation cdcl⇩W_with_strategy: cdcl⇩N⇩O⇩T_merge_bj_learn_proxy where trail = "λS. convert_trail_from_W (trail S)" and clauses⇩N⇩O⇩T = clauses and prepend_trail = "λL S. cons_trail (convert_ann_lit_from_NOT L) S" and tl_trail = "λS. tl_trail S" and add_cls⇩N⇩O⇩T = "λC S. add_learned_cls C S" and remove_cls⇩N⇩O⇩T = "λC S. remove_cls C S" and decide_conds = decide_conds and propagate_conds = propagate_conds and forget_conds = "λ_ _. False" and backjump_l_cond = backjump_l_conds_stgy and inv = inv⇩N⇩O⇩T_stgy by unfold_locales lemma cdcl⇩W_with_strategy_cdcl⇩N⇩O⇩T_merged_bj_learn_conflict: assumes "cdcl⇩W_with_strategy.cdcl⇩N⇩O⇩T_merged_bj_learn S T" "conflicting S = None" shows "conflicting T = None" using assms apply (cases rule: cdcl⇩W_with_strategy.cdcl⇩N⇩O⇩T_merged_bj_learn.cases; elim cdcl⇩W_with_strategy.forget⇩N⇩O⇩TE cdcl⇩W_with_strategy.propagate⇩N⇩O⇩TE cdcl⇩W_with_strategy.decide⇩N⇩O⇩TE rulesE cdcl⇩W_with_strategy.backjump_lE backjumpE) apply (auto elim!: rulesE simp: comp_def) done lemma cdcl⇩W_with_strategy_no_forget⇩N⇩O⇩T[iff]: "cdcl⇩W_with_strategy.forget⇩N⇩O⇩T S T ⟷ False" by (auto elim: cdcl⇩W_with_strategy.forget⇩N⇩O⇩TE) lemma cdcl⇩W_with_strategy_cdcl⇩N⇩O⇩T_merged_bj_learn_cdcl⇩W_stgy: assumes "cdcl⇩W_with_strategy.cdcl⇩N⇩O⇩T_merged_bj_learn S V" shows "cdcl⇩W_stgy⇧*⇧* S V" using assms proof (cases rule: cdcl⇩W_with_strategy.cdcl⇩N⇩O⇩T_merged_bj_learn.cases) case cdcl⇩N⇩O⇩T_merged_bj_learn_decide⇩N⇩O⇩T then show ?thesis apply (elim cdcl⇩W_with_strategy.decide⇩N⇩O⇩TE) using cdcl⇩W_stgy.other'[of S V] cdcl⇩W_o.decide[of S V] by blast next case cdcl⇩N⇩O⇩T_merged_bj_learn_propagate⇩N⇩O⇩T then show ?thesis using cdcl⇩W_stgy.propagate' by (blast elim: cdcl⇩W_with_strategy.propagate⇩N⇩O⇩TE) next case cdcl⇩N⇩O⇩T_merged_bj_learn_forget⇩N⇩O⇩T then show ?thesis by blast next case cdcl⇩N⇩O⇩T_merged_bj_learn_backjump_l then obtain T U where confl: "conflict S T" and full: "full skip_or_resolve T U" and bt: "backtrack U V" by (elim cdcl⇩W_with_strategy.backjump_lE) blast have "cdcl⇩W_bj⇧*⇧* T U" using full mono_rtranclp[of skip_or_resolve cdcl⇩W_bj] unfolding full_def by (blast elim: skip_or_resolve.cases) moreover have "cdcl⇩W_bj U V" and "no_step cdcl⇩W_bj V" using bt by (auto dest: backtrack_no_cdcl⇩W_bj) ultimately have "full1 cdcl⇩W_bj T V" unfolding full1_def by auto then have "cdcl⇩W_stgy⇧*⇧* T V" using cdcl⇩W_s'.bj'[of T V] cdcl⇩W_s'_is_rtranclp_cdcl⇩W_stgy[of T V] by blast then show ?thesis using confl cdcl⇩W_stgy.conflict'[of S T] by auto qed lemma rtranclp_transition_function: ‹R⇧*⇧* a b ⟹ ∃f j. (∀i<j. R (f i) (f (Suc i))) ∧ f 0 = a ∧ f j = b› proof (induction rule: rtranclp_induct) case base then show ?case by auto next case (step b c) note st = this(1) and R = this(2) and IH = this(3) from IH obtain f j where i: ‹∀i<j. R (f i) (f (Suc i))› and a: ‹f 0 = a› and b: ‹f j = b› by auto let ?f = ‹f(Suc j := c)› have i: ‹∀i<Suc j. R (?f i) (?f (Suc i))› and a: ‹?f 0 = a› and b: ‹?f (Suc j) = c› using i a b R by auto then show ?case by blast qed lemma cdcl⇩W_bj_cdcl⇩W_stgy: ‹cdcl⇩W_bj S T ⟹ cdcl⇩W_stgy S T› by (rule cdcl⇩W_stgy.other') (auto simp: cdcl⇩W_bj.simps cdcl⇩W_o.simps elim!: rulesE) lemma cdcl⇩W_restart_propagated_clauses_clauses: ‹cdcl⇩W_restart S T ⟹ propagated_clauses_clauses S ⟹ propagated_clauses_clauses T› by (induction rule: cdcl⇩W_restart_all_induct) (auto simp: propagated_clauses_clauses_def in_get_all_mark_of_propagated_in_trail simp: state_prop) lemma rtranclp_cdcl⇩W_restart_propagated_clauses_clauses: ‹cdcl⇩W_restart⇧*⇧* S T ⟹ propagated_clauses_clauses S ⟹ propagated_clauses_clauses T› by (induction rule: rtranclp_induct) (auto simp: cdcl⇩W_restart_propagated_clauses_clauses) lemma rtranclp_cdcl⇩W_stgy_propagated_clauses_clauses: ‹cdcl⇩W_stgy⇧*⇧* S T ⟹ propagated_clauses_clauses S ⟹ propagated_clauses_clauses T› using rtranclp_cdcl⇩W_restart_propagated_clauses_clauses[of S T] rtranclp_cdcl⇩W_stgy_rtranclp_cdcl⇩W_restart by blast lemma conflicting_clause_bt_lvl_gt_0_backjump: assumes inv: ‹inv⇩N⇩O⇩T_stgy S› and C: ‹C ∈# clauses S› and tr_C: ‹trail S ⊨as CNot C› and bt: ‹backtrack_lvl S > 0› shows ‹∃ T U V. conflict S T ∧ full skip_or_resolve T U ∧ backtrack U V› proof - let ?T = "update_conflicting (Some C) S" have confl_S_T: "conflict S ?T" using C tr_C inv by (auto intro!: conflict_rule) have count: "count_decided (trail S) > 0" using inv bt unfolding cdcl⇩W_stgy_invariant_def cdcl⇩W_all_struct_inv_def cdcl⇩W_M_level_inv_def by auto have ‹(∃K M'. trail S = M' @ Decided K # M) ⟹ D ∈# clauses S ⟹ ¬ M ⊨as CNot D› for M D using inv C tr_C unfolding cdcl⇩W_stgy_invariant_def no_smaller_confl_def by auto from this[OF _ C ] have C_ne: ‹C ≠ {#}› using tr_C bt count by (fastforce simp: filter_empty_conv in_set_conv_decomp count_decided_def elim!: is_decided_ex_Decided) obtain U where U: ‹full skip_or_resolve ?T U› by (meson wf_exists_normal_form_full wf_skip_or_resolve) then have s_o_r: "skip_or_resolve⇧*⇧* ?T U" unfolding full_def by blast then obtain C' where C': ‹conflicting U = Some C'› by (induction rule: rtranclp_induct) (auto simp: skip_or_resolve.simps elim: rulesE) have ‹cdcl⇩W_stgy⇧*⇧* ?T U› using s_o_r by induction (auto simp: skip_or_resolve.simps dest!: cdcl⇩W_bj.intros cdcl⇩W_bj_cdcl⇩W_stgy) then have ‹cdcl⇩W_stgy⇧*⇧* S U› using confl_S_T by (auto dest!: cdcl⇩W_stgy.intros) then have inv_U: ‹cdcl⇩W_all_struct_inv U› and no_smaller_U: ‹no_smaller_propa U› and inv_stgy_U: ‹cdcl⇩W_stgy_invariant U› using inv rtranclp_cdcl⇩W_stgy_cdcl⇩W_all_struct_inv rtranclp_cdcl⇩W_stgy_no_smaller_propa rtranclp_cdcl⇩W_stgy_cdcl⇩W_stgy_invariant by blast+ show ?thesis proof (cases C') case (add L D) then obtain V where ‹cdcl⇩W_stgy U V› using conflicting_no_false_can_do_step[of U C'] C' inv_U inv_stgy_U unfolding cdcl⇩W_all_struct_inv_def cdcl⇩W_stgy_invariant_def by (auto simp del: conflict_is_false_with_level_def) then have ‹backtrack U V› using C' U unfolding full_def by (auto simp: cdcl⇩W_stgy.simps cdcl⇩W_o.simps cdcl⇩W_bj.simps elim: rulesE) then show ?thesis using U confl_S_T by blast next case [simp]: empty obtain f j where f_s_o_r: ‹i<j ⟹ skip_or_resolve (f i) (f (Suc i))› and f_0: ‹f 0 = ?T› and f_j: ‹f j = U› for i using rtranclp_transition_function[OF s_o_r] by blast have j_0: ‹j ≠ 0› using C' f_j C_ne f_0 by (cases j) auto have bt_lvl_f_l: ‹backtrack_lvl (f k) = backtrack_lvl (f 0)› if ‹k ≤ j› for k using that proof (induction k) case 0 then show ?case by (simp add: f_0) next case (Suc k) then have ‹backtrack_lvl (f (Suc k)) = backtrack_lvl (f k)› apply (cases ‹k < j›; cases ‹trail (f k)›) using f_s_o_r[of k] apply (auto simp: skip_or_resolve.simps elim!: rulesE)[2] by (auto simp: skip_or_resolve.simps elim!: rulesE simp del: local.state_simp) then show ?case using f_s_o_r[of k] Suc by simp qed have st_f: ‹cdcl⇩W_stgy⇧*⇧* ?T (f k)› if ‹k < j› for k using that proof (induction k) case 0 then show ?case by (simp add: f_0) next case (Suc k) then show ?case apply (cases ‹k < j›) using f_s_o_r[of k] apply (auto simp: skip_or_resolve.simps dest!: cdcl⇩W_bj.intros cdcl⇩W_bj_cdcl⇩W_stgy)[] using f_s_o_r[of "j - 1"] j_0 by (simp del: local.state_simp) qed note st_f_T = this(1) have st_f_s_k: ‹cdcl⇩W_stgy⇧*⇧* S (f k)› if ‹k < j› for k using confl_S_T that st_f_T[of k] by (auto dest!: cdcl⇩W_stgy.intros) have f_confl: "conflicting (f k) ≠ None" if ‹k ≤ j› for k using that f_s_o_r[of k] f_j C' by (auto simp: skip_or_resolve.simps le_eq_less_or_eq elim!: rulesE) have ‹size (the (conflicting (f j))) = 0› using f_j C' by simp moreover have ‹size (the (conflicting (f 0))) > 0› using C_ne f_0 by (cases C) auto then have ‹∃x∈set [0..<Suc j]. 0 < size (the (conflicting (f x)))› by force ultimately obtain ys l zs where ‹[0..<Suc j] = ys @ l # zs› and ‹0 < size (the (conflicting (f l)))› and ‹∀z∈set zs. ¬ 0 < size (the (conflicting (f z)))› using split_list_last_prop[of "[0..<Suc j]" "λi. size (the (conflicting (f i))) > 0"] by blast moreover have ‹l < j› by (metis C' Suc_le_lessD ‹C' = {#}› append1_eq_conv append_cons_eq_upt_length_i_end calculation(1) calculation(2) f_j le_eq_less_or_eq neq0_conv option.sel size_eq_0_iff_empty upt_Suc) ultimately have ‹size (the (conflicting (f (Suc l)))) = 0› by (metis (no_types, hide_lams) ‹size (the (conflicting (f j))) = 0› append1_eq_conv append_cons_eq_upt_length_i_end less_eq_nat.simps(1) list.exhaust list.set_intros(1) neq0_conv upt_Suc upt_eq_Cons_conv) then have confl_Suc_l: ‹conflicting (f (Suc l)) = Some {#}› using f_confl[of "Suc l"] ‹l < j› by (cases ‹conflicting (f (Suc l))›) auto let ?T' = ‹f l› let ?T'' = ‹f (Suc l)› have res: ‹resolve ?T' ?T''› using confl_Suc_l ‹0 < size (the (conflicting (f l)))› f_s_o_r[of l] ‹l < j› by (auto simp: skip_or_resolve.simps elim: rulesE) then have confl_T': ‹size (the (conflicting (f l))) = 1› using confl_Suc_l by (auto elim!: rulesE simp: Diff_eq_empty_iff_mset subset_eq_mset_single_iff) then have "size (mark_of (hd (trail ?T'))) = 1" and hd_t'_dec:"¬is_decided (hd (trail ?T'))" and tr_T'_ne: ‹trail ?T' ≠ []› using res C' confl_Suc_l by (auto elim!: resolveE simp: Diff_eq_empty_iff_mset subset_eq_mset_single_iff) then obtain L where L: "mark_of (hd (trail ?T')) = {#L#}" by (cases "hd (trail ?T')"; cases "mark_of (hd (trail ?T'))") auto have inv_f_l: ‹cdcl⇩W_all_struct_inv (f l)› and no_smaller_f_l: ‹no_smaller_propa (f l)› and inv_stgy_f_l: ‹cdcl⇩W_stgy_invariant (f l)› and propa_cls_f_l: ‹propagated_clauses_clauses (f l)› using inv st_f_s_k[OF ‹l < j›] rtranclp_cdcl⇩W_stgy_cdcl⇩W_all_struct_inv[of S "f l"] rtranclp_cdcl⇩W_stgy_no_smaller_propa[of S "f l"] rtranclp_cdcl⇩W_stgy_cdcl⇩W_stgy_invariant[of S "f l"] rtranclp_cdcl⇩W_stgy_propagated_clauses_clauses by blast+ have hd_T': ‹hd (trail ?T') = Propagated L {#L#}› using inv_f_l L tr_T'_ne hd_t'_dec unfolding cdcl⇩W_all_struct_inv_def cdcl⇩W_conflicting_def by (cases "trail ?T'"; cases "(hd (trail ?T'))") force+ let ?D = "mark_of (hd (trail ?T'))" have ‹get_level (trail (f l)) L = 0› using propagate_single_literal_clause_get_level_is_0[of "f l" L] propa_cls_f_l no_smaller_f_l hd_T' inv_f_l unfolding cdcl⇩W_all_struct_inv_def cdcl⇩W_M_level_inv_def by (cases ‹trail (f l)›) auto then have ‹count_decided (trail ?T') = 0› using hd_T' by (cases ‹trail (f l)›) auto then have ‹backtrack_lvl ?T' = 0› using inv_f_l unfolding cdcl⇩W_all_struct_inv_def cdcl⇩W_M_level_inv_def by auto then show ?thesis using bt bt_lvl_f_l[of l] ‹l < j› confl_S_T by (auto simp: f_0 elim: rulesE) qed qed lemma conflict_full_skip_or_resolve_backtrack_backjump_l: assumes conf: ‹conflict S T› and full: ‹full skip_or_resolve T U› and bt: ‹backtrack U V› and inv: ‹cdcl⇩W_all_struct_inv S› shows ‹cdcl⇩W_with_strategy.backjump_l S V› proof - have inv_U: ‹cdcl⇩W_all_struct_inv U› by (metis cdcl⇩W_stgy.conflict' cdcl⇩W_stgy_cdcl⇩W_all_struct_inv conf full full_def inv rtranclp_cdcl⇩W_all_struct_inv_inv rtranclp_skip_or_resolve_rtranclp_cdcl⇩W_restart) then have inv_V: ‹cdcl⇩W_all_struct_inv V› by (metis backtrack bt cdcl⇩W_bj_cdcl⇩W_stgy cdcl⇩W_stgy_cdcl⇩W_all_struct_inv) obtain C where C_S: ‹C ∈# clauses S› and S_Not_C: ‹trail S ⊨as CNot C› and tr_T_S: ‹trail T = trail S› and T: ‹T ∼ update_conflicting (Some C) S› and clss_T_S: ‹clauses T = clauses S› using conf by (auto elim: rulesE) have s_o_r: ‹skip_or_resolve⇧*⇧* T U› using full unfolding full_def by blast then have ‹∃M. trail T = M @ trail U› and bt_T_U: ‹backtrack_lvl T = backtrack_lvl U› and bt_lvl_T_U: ‹backtrack_lvl T = backtrack_lvl U› and clss_T_U: ‹clauses T = clauses U› and init_T_U: ‹init_clss T = init_clss U› and learned_T_U: ‹learned_clss T = learned_clss U› using skip_or_resolve_state_change[of T U] by blast+ then obtain M where M: ‹trail T = M @ trail U› by blast obtain D D' :: "'v clause" and K L :: "'v literal" and M1 M2 :: "('v, 'v clause) ann_lit list" and i :: nat where confl_D: "conflicting U = Some (add_mset L D)" and decomp: "(Decided K # M1, M2) ∈ set (get_all_ann_decomposition (trail U))" and lev_L_U: "get_level (trail U) L = backtrack_lvl U" and max_D_L_U: "get_level (trail U) L = get_maximum_level (trail U) (add_mset L D')" and i: "get_maximum_level (trail U) D' ≡ i" and lev_K_U: "get_level (trail U) K = i + 1" and V: "V ∼ cons_trail (Propagated L (add_mset L D')) (reduce_trail_to M1 (add_learned_cls (add_mset L D') (update_conflicting None U)))" and U_L_D': ‹clauses U ⊨pm add_mset L D'› and D_D': ‹D' ⊆# D› using bt by (auto elim!: rulesE) let ?D' = ‹add_mset L D'› obtain M' where M': ‹trail U = M' @ M2 @ Decided K # M1› using decomp by auto have ‹clauses V = {#?D'#} + clauses U› using V by auto moreover have ‹trail V = (Propagated L ?D') # trail (reduce_trail_to M1 U)› using V T M tr_T_S[symmetric] M' clss_T_U[symmetric] unfolding state_eq⇩N⇩O⇩T_def by (auto simp del: state_simp dest!: state_simp(1)) ultimately have V': ‹V ∼⇩N⇩O⇩T cons_trail (Propagated L dummy_cls) (reduce_trail_to⇩N⇩O⇩T M1 (add_learned_cls ?D' S))› using V T M tr_T_S[symmetric] M' clss_T_U[symmetric] unfolding state_eq⇩N⇩O⇩T_def by (auto simp del: state_simp simp: trail_reduce_trail_to⇩N⇩O⇩T_drop drop_map drop_tl clss_T_S) have ‹no_dup (trail V)› using inv_V V unfolding cdcl⇩W_all_struct_inv_def cdcl⇩W_M_level_inv_def by blast then have undef_L: ‹undefined_lit M1 L› using V decomp by (auto simp: defined_lit_map) have ‹atm_of L ∈ atms_of_mm (init_clss V)› using inv_V V decomp unfolding cdcl⇩W_all_struct_inv_def no_strange_atm_def by auto moreover have init_clss_VU_S: ‹init_clss V = init_clss S› ‹init_clss U = init_clss S›‹learned_clss U = learned_clss S› using T V init_T_U learned_T_U by auto ultimately have atm_L: ‹atm_of L ∈ atms_of_mm (clauses S)› by (auto simp: clauses_def) have ‹distinct_mset ?D'› and ‹¬ tautology ?D'› using inv_U confl_D decomp D_D' unfolding cdcl⇩W_all_struct_inv_def distinct_cdcl⇩W_state_def apply simp_all using inv_V V not_tautology_mono[OF D_D'] distinct_mset_mono[OF D_D'] unfolding cdcl⇩W_all_struct_inv_def apply (auto simp add: tautology_add_mset) done have ‹L ∉# D'› using ‹distinct_mset ?D'› by (auto simp: not_in_iff) have bj: ‹backjump_l_conds_stgy C D' L S V› apply (rule exI[of _ T], rule exI[of _ U]) using ‹distinct_mset ?D'› ‹¬ tautology ?D'› conf full bt confl_D ‹L ∉# D'› V T by (auto) have M1_D': "M1 ⊨as CNot D'" using backtrack_M1_CNot_D'[of U D' ‹i› K M1 M2 L ‹add_mset L D› V ‹Propagated L (add_mset L D')›] inv_U confl_D decomp lev_L_U max_D_L_U i lev_K_U V U_L_D' D_D' unfolding cdcl⇩W_all_struct_inv_def cdcl⇩W_conflicting_def cdcl⇩W_M_level_inv_def by (auto simp: subset_mset_trans_add_mset) show ?thesis apply (rule cdcl⇩W_with_strategy.backjump_l.intros[of S _ K "convert_trail_from_W M1" _ L _ C D']) apply (simp add: tr_T_S[symmetric] M' M; fail) using V' apply (simp; fail) using C_S apply (simp; fail) using S_Not_C apply (simp; fail) using undef_L apply (simp; fail) using atm_L apply (simp; fail) using U_L_D' init_clss_VU_S apply (simp add: clauses_def; fail) apply (simp; fail) using M1_D' apply (simp; fail) using bj ‹distinct_mset ?D'› ‹¬ tautology ?D'› by auto qed lemma is_decided_o_convert_ann_lit_from_W[simp]: ‹is_decided o convert_ann_lit_from_W = is_decided› apply (rule ext) apply (rename_tac x, case_tac x) apply (auto simp: comp_def) done lemma cdcl⇩W_with_strategy_propagate⇩N⇩O⇩T_propagate_iff[iff]: ‹cdcl⇩W_with_strategy.propagate⇩N⇩O⇩T S T ⟷ propagate S T› (is "?NOT ⟷ ?W") proof (rule iffI) assume ?NOT then show ?W by auto next assume ?W then obtain E L where ‹conflicting S = None› and E: ‹E ∈# clauses S› and LE: ‹L ∈# E› and tr_E: ‹trail S ⊨as CNot (remove1_mset L E)› and undef: ‹undefined_lit (trail S) L› and T: ‹T ∼ cons_trail (Propagated L E) S› by (auto elim!: propagateE) show ?NOT apply (rule cdcl⇩W_with_strategy.propagate⇩N⇩O⇩T[of L ‹remove1_mset L E›]) using LE E apply (simp; fail) using tr_E apply (simp; fail) using undef apply (simp; fail) using ‹?W› apply (simp; fail) using T by (simp add: state_eq⇩N⇩O⇩T_def clauses_def) qed interpretation cdcl⇩W_with_strategy: cdcl⇩N⇩O⇩T_merge_bj_learn where trail = "λS. convert_trail_from_W (trail S)" and clauses⇩N⇩O⇩T = clauses and prepend_trail = "λL S. cons_trail (convert_ann_lit_from_NOT L) S" and tl_trail = "λS. tl_trail S" and add_cls⇩N⇩O⇩T = "λC S. add_learned_cls C S" and remove_cls⇩N⇩O⇩T = "λC S. remove_cls C S" and decide_conds = decide_conds and propagate_conds = propagate_conds and forget_conds = "λ_ _. False" and backjump_l_cond = backjump_l_conds_stgy and inv = inv⇩N⇩O⇩T_stgy proof (unfold_locales, goal_cases) case (2 S T) then show ?case using cdcl⇩W_with_strategy_cdcl⇩N⇩O⇩T_merged_bj_learn_cdcl⇩W_stgy[of S T] cdcl⇩W_with_strategy_cdcl⇩N⇩O⇩T_merged_bj_learn_conflict[of S T] rtranclp_cdcl⇩W_stgy_cdcl⇩W_all_struct_inv rtranclp_cdcl⇩W_stgy_no_smaller_propa rtranclp_cdcl⇩W_stgy_cdcl⇩W_stgy_invariant rtranclp_cdcl⇩W_stgy_propagated_clauses_clauses by blast next case (1 C' S C F' K F L) have ‹count_decided (convert_trail_from_W (trail S)) > 0› unfolding ‹convert_trail_from_W (trail S) = F' @ Decided K # F› by simp then have ‹count_decided (trail S) > 0› by simp then have ‹backtrack_lvl S > 0› using ‹inv⇩N⇩O⇩T_stgy S› unfolding cdcl⇩W_all_struct_inv_def cdcl⇩W_M_level_inv_def by auto have "∃T U V. conflict S T ∧ full skip_or_resolve T U ∧ backtrack U V" apply (rule conflicting_clause_bt_lvl_gt_0_backjump) using ‹inv⇩N⇩O⇩T_stgy S› apply (auto; fail)[] using ‹C ∈# clauses S› apply (simp; fail) using ‹convert_trail_from_W (trail S) ⊨as CNot C› apply (simp; fail) using ‹backtrack_lvl S > 0› by (simp; fail) then show ?case using conflict_full_skip_or_resolve_backtrack_backjump_l ‹inv⇩N⇩O⇩T_stgy S› by blast next case (3 L S) note atm = this(1,2) and inv = this(3) and sat = this(4) moreover have ‹Ex(cdcl⇩W_with_strategy.backjump_l S)› if ‹conflict S T› for T proof - have ‹∃C. C ∈# clauses S ∧ trail S ⊨as CNot C› using that by (auto elim: rulesE) then obtain C where ‹C ∈# clauses S› and ‹trail S ⊨as CNot C› by blast have ‹backtrack_lvl S > 0› proof (rule ccontr) assume ‹¬ ?thesis› then have ‹backtrack_lvl S = 0› by simp then have ‹count_decided (trail S) = 0› using inv unfolding cdcl⇩W_all_struct_inv_def cdcl⇩W_M_level_inv_def by simp then have ‹get_all_ann_decomposition (trail S) = [([], trail S)]› by (auto simp: filter_empty_conv no_decision_get_all_ann_decomposition count_decided_0_iff) then have ‹set_mset (clauses S) ⊨ps unmark_l (trail S)› using 3(3) unfolding cdcl⇩W_all_struct_inv_def by auto obtain I where consistent: ‹consistent_interp I› and I_S: ‹I ⊨m clauses S› and tot: ‹total_over_m I (set_mset (clauses S))› using sat by (auto simp: satisfiable_def) have ‹total_over_m I (set_mset (clauses S)) ∧ total_over_m I (unmark_l (trail S))› using tot inv unfolding cdcl⇩W_all_struct_inv_def no_strange_atm_def by (auto simp: clauses_def total_over_set_def total_over_m_def) then have ‹I ⊨s unmark_l (trail S)› using ‹set_mset (clauses S) ⊨ps unmark_l (trail S)› consistent I_S unfolding true_clss_clss_def clauses_def by auto have ‹I ⊨s CNot C› by (meson ‹trail S ⊨as CNot C› ‹I ⊨s unmark_l (trail S)› set_mp true_annots_true_cls true_cls_def true_clss_def true_clss_singleton_lit_of_implies_incl true_lit_def) moreover have ‹I ⊨ C› using ‹C ∈# clauses S› and ‹I ⊨m clauses S› unfolding true_cls_mset_def by auto ultimately show False using consistent consistent_CNot_not by blast qed then show ?thesis using conflicting_clause_bt_lvl_gt_0_backjump[of S C] conflict_full_skip_or_resolve_backtrack_backjump_l[of S] ‹C ∈# clauses S› ‹trail S ⊨as CNot C› inv by fast qed moreover { have atm: ‹atms_of_mm (clauses S) = atms_of_mm (init_clss S)› using 3(3) unfolding cdcl⇩W_all_struct_inv_def no_strange_atm_def by (auto simp: clauses_def) have ‹decide S (cons_trail (Decided L) S)› apply (rule decide_rule) using 3 by (auto simp: atm) } moreover have ‹cons_trail (Decided L) S ∼⇩N⇩O⇩T cons_trail (Decided L) S› by (simp add: state_eq⇩N⇩O⇩T_def del: state_simp) ultimately show "∃T. cdcl⇩W_with_strategy.decide⇩N⇩O⇩T S T ∨ cdcl⇩W_with_strategy.propagate⇩N⇩O⇩T S T ∨ cdcl⇩W_with_strategy.backjump_l S T" using cdcl⇩W_with_strategy.decide⇩N⇩O⇩T.intros[of S L "cons_trail (Decided L) S"] by auto qed thm cdcl⇩W_with_strategy.full_cdcl⇩N⇩O⇩T_merged_bj_learn_final_state end end