Theory CDCL_W_Covering_Models

theory CDCL_W_Covering_Models
  imports CDCL_W_Optimal_Model
begin

section Covering Models

text I am only interested in the extension of CDCL to find covering mdoels, not in the required
subsequent extraction of the minimal covering models.

type_synonym 'v cov = 'v literal multiset multiset

lemma true_clss_cls_in_susbsuming:
  C' ⊆# C  C'  N  N ⊨p C
  by (metis subset_mset.le_iff_add true_clss_cls_in true_clss_cls_mono_r)

locale covering_models =
  fixes
    ρ :: 'v  bool
begin

definition model_is_dominated :: 'v literal multiset  'v literal multiset  bool where
model_is_dominated M M' 
  filter_mset (λL. is_pos L  ρ (atm_of L)) M ⊆# filter_mset (λL. is_pos L  ρ (atm_of L)) M'

lemma model_is_dominated_refl: model_is_dominated I I
  by (auto simp: model_is_dominated_def)

lemma model_is_dominated_trans:
  model_is_dominated I J  model_is_dominated J K  model_is_dominated I K
  by (auto simp: model_is_dominated_def)

definition is_dominating :: 'v literal multiset multiset  'v literal multiset  bool where
  is_dominating  I  (M∈#. J. I ⊆# J  model_is_dominated J M)

lemma
  is_dominating_in:
    I ∈#   is_dominating  I and
  is_dominating_mono:
    is_dominating  I  set_mset   set_mset ℳ'  is_dominating ℳ' I and
  is_dominating_mono_model:
    is_dominating  I  I' ⊆# I  is_dominating  I'
  using multiset_filter_mono[of I' I λL.  is_pos L  ρ (atm_of L)]
  by (auto 5 5 simp: is_dominating_def model_is_dominated_def
    dest!: multi_member_split)

lemma is_dominating_add_mset:
  is_dominating (add_mset x ) I 
   is_dominating  I  (J. I ⊆# J   model_is_dominated J x)
  by (auto simp: is_dominating_def)

definition is_improving_int
  :: ('v, 'v clause) ann_lits  ('v, 'v clause) ann_lits  'v clauses  'v cov  bool
where
is_improving_int M M' N  
  M = M'  (I ∈# . ¬model_is_dominated (lit_of `# mset M) I) 
  total_over_m (lits_of_l M) (set_mset N) 
  lit_of `# mset M  simple_clss (atms_of_mm N) 
  lit_of `# mset M ∉#  
  M ⊨asm N 
  no_dup M


text This criteria is a bit more general than Weidenbach's version.
abbreviation conflicting_clauses_ent where
  conflicting_clauses_ent N  
     {#pNeg {#L ∈# x. ρ (atm_of L)#}.
        x ∈# filter_mset (λx. is_dominating  x  atms_of x = atms_of_mm N)
            (mset_set (simple_clss (atms_of_mm N)))#}+ N

definition conflicting_clauses
  :: 'v clauses  'v cov  'v clauses
where
  conflicting_clauses N  =
    {#C ∈# mset_set (simple_clss (atms_of_mm N)).
      conflicting_clauses_ent N  ⊨pm C#}

lemma conflicting_clauses_insert:
  assumes M  simple_clss (atms_of_mm N) and atms_of M = atms_of_mm N
  shows pNeg M ∈# conflicting_clauses N (add_mset M w)
  using assms true_clss_cls_in_susbsuming[of pNeg {#L ∈# M. ρ (atm_of L)#}
    pNeg M set_mset (conflicting_clauses_ent N (add_mset M w))]
    is_dominating_in
  by (auto simp: conflicting_clauses_def simple_clss_finite
    pNeg_def image_mset_subseteq_mono)

lemma is_dominating_in_conflicting_clauses:
  assumes is_dominating  I and
    atm: atms_of_s (set_mset I) = atms_of_mm N and
    set_mset I ⊨m N and
    consistent_interp (set_mset I) and
    ¬tautology I and
    distinct_mset I
  shows
    pNeg I ∈# conflicting_clauses N 
proof -
  have simpI: I  simple_clss (atms_of_mm N)
    using assms by (auto simp: simple_clss_def atms_of_s_def atms_of_def)
  obtain I' J where J ∈#  and model_is_dominated I' J and I ⊆# I'
    using assms(1) unfolding is_dominating_def
    by auto
  then have I  {x  simple_clss (atms_of_mm N).
         (is_dominating A x  (Ja. x ⊆# Ja  model_is_dominated Ja J)) 
         atms_of x = atms_of_mm N}
    using assms(1) atm
    by (auto simp: conflicting_clauses_def simple_clss_finite simpI atms_of_def
        pNeg_mono true_clss_cls_in_susbsuming is_dominating_add_mset atms_of_s_def
      dest!: multi_member_split)
  then show ?thesis
    using assms(1)
    by (auto simp: conflicting_clauses_def simple_clss_finite simpI
        pNeg_mono  is_dominating_add_mset
      dest!: multi_member_split
      intro!: true_clss_cls_in_susbsuming[of (λx. pNeg {#L ∈# x. ρ (atm_of L)#}) I])
qed

end

locale conflict_driven_clause_learningW_covering_models =
  conflict_driven_clause_learningW
    state_eq
    state
    ― ‹functions for the state:
      ― ‹access functions:
    trail init_clss learned_clss conflicting
      ― ‹changing state:
    cons_trail tl_trail add_learned_cls remove_cls
    update_conflicting
      ― ‹get state:
    init_state +
  covering_models ρ
  for
    state_eq :: 'st  'st  bool (infix  50) and
    state :: "'st  ('v, 'v clause) ann_lits × 'v clauses × 'v clauses × 'v clause option ×
      'v cov × 'b" and
    trail :: 'st  ('v, 'v clause) ann_lits and
    init_clss :: 'st  'v clauses and
    learned_clss :: 'st  'v clauses and
    conflicting :: 'st  'v clause option and

    cons_trail :: ('v, 'v clause) ann_lit  'st  'st and
    tl_trail :: 'st  'st and
    add_learned_cls :: 'v clause  'st  'st and
    remove_cls :: 'v clause  'st  'st and
    update_conflicting :: 'v clause option  'st  'st and
    init_state :: 'v clauses  'st and
    ρ :: 'v  bool  +
  fixes
    update_additional_info :: 'v cov × 'b  'st  'st
  assumes
    update_additional_info:
      state S = (M, N, U, C, )  state (update_additional_info K' S) = (M, N, U, C, K') and
    weight_init_state:
      N :: 'v clauses. fst (additional_info (init_state N)) = {#}
begin

definition update_weight_information :: ('v, 'v clause) ann_lits  'st  'st where
  update_weight_information M S =
    update_additional_info (add_mset (lit_of `# mset M) (fst (additional_info S)), snd (additional_info S)) S

lemma
  trail_update_additional_info[simp]: trail (update_additional_info w S) = trail S and
  init_clss_update_additional_info[simp]:
    init_clss (update_additional_info w S) = init_clss S and
  learned_clss_update_additional_info[simp]:
    learned_clss (update_additional_info w S) = learned_clss S and
  backtrack_lvl_update_additional_info[simp]:
    backtrack_lvl (update_additional_info w S) = backtrack_lvl S and
  conflicting_update_additional_info[simp]:
    conflicting (update_additional_info w S) = conflicting S and
  clauses_update_additional_info[simp]:
    clauses (update_additional_info w S) = clauses S
  using update_additional_info[of S] unfolding clauses_def
  by (subst (asm) state_prop; subst (asm) state_prop; auto; fail)+

lemma
  trail_update_weight_information[simp]:
    trail (update_weight_information w S) = trail S and
  init_clss_update_weight_information[simp]:
    init_clss (update_weight_information w S) = init_clss S and
  learned_clss_update_weight_information[simp]:
    learned_clss (update_weight_information w S) = learned_clss S and
  backtrack_lvl_update_weight_information[simp]:
    backtrack_lvl (update_weight_information w S) = backtrack_lvl S and
  conflicting_update_weight_information[simp]:
    conflicting (update_weight_information w S) = conflicting S and
  clauses_update_weight_information[simp]:
    clauses (update_weight_information w S) = clauses S
  using update_additional_info[of S] unfolding update_weight_information_def by auto

definition covering :: 'st  'v cov where
  covering S = fst (additional_info S)

lemma
  additional_info_update_additional_info[simp]:
  additional_info (update_additional_info w S) = w
  unfolding additional_info_def using update_additional_info[of S]
  by (cases state S; auto; fail)+

lemma
  covering_cons_trail2[simp]: covering (cons_trail L S) = covering S and
  clss_tl_trail2[simp]: covering (tl_trail S) = covering S and
  covering_add_learned_cls_unfolded:
    covering (add_learned_cls U S) = covering S
    and
  covering_update_conflicting2[simp]: covering (update_conflicting D S) = covering S and
  covering_remove_cls2[simp]:
    covering (remove_cls C S) = covering S and
  covering_add_learned_cls2[simp]:
    covering (add_learned_cls C S) = covering S and
  covering_update_covering_information2[simp]:
    covering (update_weight_information M S) = add_mset (lit_of `# mset M) (covering S)
  by (auto simp: update_weight_information_def covering_def)



sublocale conflict_driven_clause_learningW where
  state_eq = state_eq and
  state = state and
  trail = trail and
  init_clss = init_clss and
  learned_clss = learned_clss and
  conflicting = conflicting and
  cons_trail = cons_trail and
  tl_trail = tl_trail and
  add_learned_cls = add_learned_cls and
  remove_cls = remove_cls and
  update_conflicting = update_conflicting and
  init_state = init_state
  by unfold_locales

sublocale conflict_driven_clause_learning_with_adding_init_clause_bnbW_no_state
  where
    state = state and
    trail = trail and
    init_clss = init_clss and
    learned_clss = learned_clss and
    conflicting = conflicting and
    cons_trail = cons_trail and
    tl_trail = tl_trail and
    add_learned_cls = add_learned_cls and
    remove_cls = remove_cls and
    update_conflicting = update_conflicting and
    init_state = init_state and
    weight = covering and
    update_weight_information = update_weight_information and
    is_improving_int = is_improving_int and
    conflicting_clauses = conflicting_clauses
  by unfold_locales

lemma state_additional_info2':
  state S = (trail S, init_clss S, learned_clss S, conflicting S, covering S, additional_info' S)
  unfolding additional_info'_def by (cases state S; auto simp: state_prop covering_def)

lemma state_update_weight_information:
  state S = (M, N, U, C, w, other) 
    w'. state (update_weight_information T S) = (M, N, U, C, w', other)
  unfolding update_weight_information_def by (cases state S; auto simp: state_prop covering_def)


lemma conflicting_clss_incl_init_clss:
  atms_of_mm (conflicting_clss S)  atms_of_mm (init_clss S)
  unfolding conflicting_clss_def conflicting_clauses_def
  apply (auto simp: simple_clss_finite)
  by (auto simp: simple_clss_def atms_of_ms_def split: if_splits)

lemma conflict_clss_update_weight_no_alien:
  atms_of_mm (conflicting_clss (update_weight_information M S))
     atms_of_mm (init_clss S)
  by (auto simp: conflicting_clss_def conflicting_clauses_def atms_of_ms_def
      cdclW_restart_mset_state simple_clss_finite
    dest: simple_clssE)


lemma distinct_mset_mset_conflicting_clss2: distinct_mset_mset (conflicting_clss S)
  unfolding conflicting_clss_def conflicting_clauses_def distinct_mset_set_def
  apply (auto simp: simple_clss_finite)
  by (auto simp: simple_clss_def)


lemma total_over_m_atms_incl:
  assumes total_over_m M (set_mset N)
  shows
    x  atms_of_mm N  x  atms_of_s M
  by (meson assms contra_subsetD total_over_m_alt_def)

lemma negate_ann_lits_simple_clss_iff[iff]:
  negate_ann_lits M  simple_clss N  lit_of `# mset M  simple_clss N
  unfolding negate_ann_lits_def
  by (subst uminus_simple_clss_iff[symmetric]) auto

lemma conflicting_clss_update_weight_information_in2:
  assumes is_improving M M' S
  shows negate_ann_lits M' ∈# conflicting_clss (update_weight_information M' S)
proof -
  have
    [simp]: M' = M and
    I∈#covering S. ¬ model_is_dominated (lit_of `# mset M) I and
    tot: total_over_m (lits_of_l M) (set_mset (init_clss S)) and
    simpI: lit_of `# mset M  simple_clss (atms_of_mm (init_clss S)) and
    lit_of `# mset M ∉# covering S and
    no_dup M and
    M ⊨asm init_clss S
    using assms unfolding is_improving_int_def by auto
  have pNeg {#L ∈# lit_of `# mset M. ρ (atm_of L)#}
      (λx. pNeg {#L ∈# x. ρ (atm_of L)#}) `
       {x  simple_clss (atms_of_mm (init_clss S)).
        is_dominating (add_mset (lit_of `# mset M) (covering S)) x}
    using is_dominating_in[of lit_of `# mset M add_mset (lit_of `# mset M) (covering S)]
    by (auto simp: simple_clss_finite multiset_filter_mono2 pNeg_mono
      conflicting_clauses_def conflicting_clss_def is_improving_int_def
      simpI)
  moreover have atms_of (lit_of `# mset M) = atms_of_mm (init_clss S)
    using tot simpI
    by (auto simp: simple_clss_finite multiset_filter_mono2 pNeg_mono
      conflicting_clauses_def conflicting_clss_def is_improving_int_def
      total_over_m_alt_def atms_of_s_def lits_of_def image_image atms_of_def
      simple_clss_def)
  ultimately have (x. x  simple_clss (atms_of_mm (init_clss S)) 
          is_dominating (add_mset (lit_of `# mset M) (covering S)) x 
          atms_of x = atms_of_mm (init_clss S) 
          pNeg {#L ∈# lit_of `# mset M. ρ (atm_of L)#} =
          pNeg {#L ∈# x. ρ (atm_of L)#})
    by (auto intro: exI[of _ lit_of `# mset M] simp add: simpI is_dominating_in)
  then show ?thesis
    using is_dominating_in
     true_clss_cls_in_susbsuming[of pNeg {#L ∈# lit_of `# mset M. ρ (atm_of L)#}
    pNeg (lit_of `# mset M) set_mset (conflicting_clauses_ent
      (init_clss S) (covering (update_weight_information M' S)))]
    by (auto simp: simple_clss_finite multiset_filter_mono2 simpI
      conflicting_clauses_def conflicting_clss_def pNeg_mono
        negate_ann_lits_pNeg_lit_of image_iff image_mset_subseteq_mono)
qed

lemma is_improving_conflicting_clss_update_weight_information: is_improving M M' S 
       conflicting_clss S ⊆# conflicting_clss (update_weight_information M' S)
  by (auto simp: is_improving_int_def conflicting_clss_def conflicting_clauses_def
      simp: multiset_filter_mono2 le_less true_clss_cls_tautology_iff simple_clss_finite
        is_dominating_add_mset filter_disj_eq image_Un
      intro!: image_mset_subseteq_mono
      intro: true_clss_cls_subsetI
      dest: simple_clssE
      split: enat.splits)

sublocale stateW_no_state
  where
    state = state and
    trail = trail and
    init_clss = init_clss and
    learned_clss = learned_clss and
    conflicting = conflicting and
    cons_trail = cons_trail and
    tl_trail = tl_trail and
    add_learned_cls = add_learned_cls and
    remove_cls = remove_cls and
    update_conflicting = update_conflicting and
    init_state = init_state
  by unfold_locales

sublocale stateW_no_state where
  state_eq = state_eq and
  state = state and
  trail = trail and
  init_clss = init_clss and
  learned_clss = learned_clss and
  conflicting = conflicting and
  cons_trail = cons_trail and
  tl_trail = tl_trail and
  add_learned_cls = add_learned_cls and
  remove_cls = remove_cls and
  update_conflicting = update_conflicting and
  init_state = init_state
  by unfold_locales

sublocale conflict_driven_clause_learningW where
  state_eq = state_eq and
  state = state and
  trail = trail and
  init_clss = init_clss and
  learned_clss = learned_clss and
  conflicting = conflicting and
  cons_trail = cons_trail and
  tl_trail = tl_trail and
  add_learned_cls = add_learned_cls and
  remove_cls = remove_cls and
  update_conflicting = update_conflicting and
  init_state = init_state
  by unfold_locales

sublocale conflict_driven_clause_learning_with_adding_init_clause_bnbW_ops
  where
    state = state and
    trail = trail and
    init_clss = init_clss and
    learned_clss = learned_clss and
    conflicting = conflicting and
    cons_trail = cons_trail and
    tl_trail = tl_trail and
    add_learned_cls = add_learned_cls and
    remove_cls = remove_cls and
    update_conflicting = update_conflicting and
    init_state = init_state and
    weight = covering and
    update_weight_information = update_weight_information and
    is_improving_int = is_improving_int and
    conflicting_clauses = conflicting_clauses
  apply unfold_locales
  subgoal by (rule state_additional_info2')
  subgoal by (rule state_update_weight_information)
  subgoal by (rule conflicting_clss_incl_init_clss)
  subgoal by (rule distinct_mset_mset_conflicting_clss2)
  subgoal by (rule is_improving_conflicting_clss_update_weight_information)
  subgoal by (rule conflicting_clss_update_weight_information_in2)
  done

definition covering_simple_clss where
  covering_simple_clss N S  (set_mset (covering S)  simple_clss (atms_of_mm N)) 
     distinct_mset (covering S) 
     (M ∈# covering S. total_over_m (set_mset M) (set_mset N))

lemma [simp]: covering (init_state N) = {#}
  by (simp add: covering_def weight_init_state)

lemma covering_simple_clss N (init_state N)
  by (auto simp: covering_simple_clss_def)

lemma cdcl_bnb_covering_simple_clss:
  cdcl_bnb S T  init_clss S = N  covering_simple_clss N S  covering_simple_clss N T
  by (auto simp: cdcl_bnb.simps covering_simple_clss_def is_improving_int_def
      model_is_dominated_refl ocdclW_o.simps cdcl_bnb_bj.simps
      lits_of_def
    elim!: rulesE improveE conflict_optE obacktrackE
    dest!: multi_member_split[of _ covering S])

lemma rtranclp_cdcl_bnb_covering_simple_clss:
  cdcl_bnb** S T  init_clss S = N  covering_simple_clss N S  covering_simple_clss N T
  by (induction rule: rtranclp_induct)
    (auto simp: cdcl_bnb_covering_simple_clss simp: rtranclp_cdcl_bnb_no_more_init_clss
      cdcl_bnb_no_more_init_clss)


lemma wf_cdcl_bnb_fixed:
   wf {(T, S). cdclW_restart_mset.cdclW_all_struct_inv (abs_state S)  cdcl_bnb S T
        covering_simple_clss N S  init_clss S = N}
  apply (rule wf_cdcl_bnb_with_additional_inv[of
     covering_simple_clss N
     N id {(T, S). (T, S)  {(ℳ', ).  ⊂# ℳ'  distinct_mset ℳ'
        set_mset ℳ'  simple_clss (atms_of_mm N)}}])
  subgoal
    by (auto simp: improvep.simps is_improving_int_def covering_simple_clss_def
         add_mset_eq_add_mset  model_is_dominated_refl
      dest!: multi_member_split)
  subgoal
    apply (rule wf_bounded_set[of _ λ_. simple_clss (atms_of_mm N) set_mset])
    apply (auto simp: distinct_mset_subset_iff_remdups[symmetric] simple_clss_finite
      simp flip: remdups_mset_def)
    by (metis distinct_mset_mono distinct_mset_set_mset_ident)
  subgoal
    by (rule cdcl_bnb_covering_simple_clss)
  done

lemma can_always_improve:
  assumes
    ent: trail S ⊨asm clauses S and
    total: total_over_m (lits_of_l (trail S)) (set_mset (clauses S)) and
    n_s: no_step conflict_opt S and
    confl: conflicting S = None and
    all_struct: cdclW_restart_mset.cdclW_all_struct_inv (abs_state S)
  shows Ex (improvep S)
proof -
  have cdclW_restart_mset.cdclW_M_level_inv (abs_state S) and
    alien: cdclW_restart_mset.no_strange_atm (abs_state S)
    using all_struct
    unfolding cdclW_restart_mset.cdclW_all_struct_inv_def
    by fast+
  then have n_d: no_dup (trail S)
    unfolding cdclW_restart_mset.cdclW_M_level_inv_def
    by auto
  have [simp]:
    atms_of_mm (CDCL_W_Abstract_State.init_clss (abs_state S)) = atms_of_mm (init_clss S)
    unfolding abs_state_def init_clss.simps
    by auto
  let ?M = (lit_of `# mset (trail S))
  have trail_simple: ?M  simple_clss (atms_of_mm (init_clss S))
    using n_d alien
    by (auto simp: simple_clss_def cdclW_restart_mset.no_strange_atm_def
        lits_of_def image_image atms_of_def
      dest: distinct_consistent_interp no_dup_not_tautology
        no_dup_distinct)
  then have [simp]: atms_of ?M = atms_of_mm (init_clss S)
    using total
    by (auto simp: total_over_m_alt_def simple_clss_def atms_of_def image_image
      lits_of_def atms_of_s_def clauses_def)
  then have K: is_dominating (covering S) ?M  pNeg {#L ∈# lit_of `# mset (trail S). ρ (atm_of L)#}
          (λx. pNeg {#L ∈# x. ρ (atm_of L)#}) `
           {x  simple_clss (atms_of_mm (init_clss S)).
            is_dominating (covering S) x 
            atms_of x = atms_of_mm (init_clss S)}
    by (auto simp: image_iff trail_simple
      intro!: exI[of _ lit_of `# mset (trail S)])
  have H: I ∈# covering S 
        model_is_dominated ?M I 
	pNeg {#L ∈# ?M. ρ (atm_of L)#}
      (λx. pNeg {#L ∈# x. ρ (atm_of L)#}) `
       {x  simple_clss (atms_of_mm (init_clss S)).
        is_dominating (covering S) x} for I
    using is_dominating_in[of lit_of `# mset M add_mset (lit_of `# mset M) (covering S)]
      trail_simple
    by (auto 5 5 simp: simple_clss_finite multiset_filter_mono2 pNeg_mono
          conflicting_clauses_def conflicting_clss_def is_improving_int_def
          is_dominating_add_mset filter_disj_eq image_Un
        dest!: multi_member_split)
  have I ∈# covering S 
        model_is_dominated ?M I  False for I
    using n_s confl H[of I] K
     true_clss_cls_in_susbsuming[of pNeg {#L ∈# ?M. ρ (atm_of L)#}
    pNeg ?M set_mset (conflicting_clauses_ent
      (init_clss S) (covering S))]
    by (auto simp: conflict_opt.simps simple_clss_finite
        conflicting_clss_def conflicting_clauses_def is_dominating_def
	is_dominating_add_mset filter_disj_eq image_Un pNeg_mono
	multiset_filter_mono2 negate_ann_lits_pNeg_lit_of
      intro: trail_simple)
  moreover have False if lit_of `# mset (trail S) ∈# covering S
    using n_s confl that trail_simple by (auto simp: conflict_opt.simps
      conflicting_clauses_insert conflicting_clss_def simple_clss_finite
      negate_ann_lits_pNeg_lit_of
      dest!: multi_member_split)
  ultimately have imp: is_improving (trail S) (trail S) S
    unfolding is_improving_int_def
    using assms trail_simple n_d by (auto simp: clauses_def)
  show ?thesis
    by (rule exI) (rule improvep.intros[OF imp confl state_eq_ref])
qed

lemma exists_model_with_true_lit_entails_conflicting:
  assumes
    L_I: Pos L  I and
    L: ρ L and
    L_in: L  atms_of_mm (init_clss S) and
    ent: I ⊨m init_clss S and
    cons: consistent_interp I and
    total: total_over_m I (set_mset N) and
    no_L: ¬(J∈# covering S. Pos L ∈# J) and
    cov: covering_simple_clss N S and
    NS: atms_of_mm N = atms_of_mm (init_clss S)
  shows I ⊨m conflicting_clss S and
    I ⊨m CDCL_W_Abstract_State.init_clss (abs_state S)
proof -
  show I ⊨m conflicting_clss S
    unfolding conflicting_clss_def conflicting_clauses_def
      set_mset_filter true_cls_mset_def
  proof
    fix C
    assume C  {a. a ∈# mset_set (simple_clss (atms_of_mm (init_clss S))) 
                {#pNeg {#L ∈# x. ρ (atm_of L)#}.
                x ∈# {#x ∈# mset_set (simple_clss (atms_of_mm (init_clss S))).
                        is_dominating (covering S) x 
                        atms_of x = atms_of_mm (init_clss S)#}#} +
                init_clss S ⊨pm
                a}
    then have simp_C: C  simple_clss (atms_of_mm (init_clss S)) and
      ent_C: (λx. pNeg {#L ∈# x. ρ (atm_of L)#}) `
           {x  simple_clss (atms_of_mm (init_clss S)). is_dominating (covering S) x 
	     atms_of x = atms_of_mm (init_clss S)} 
          set_mset (init_clss S) ⊨p C
      by (auto simp: simple_clss_finite)
    have tot_I2: total_over_m I
         ((λx. pNeg {#L ∈# x. ρ (atm_of L)#}) `
          {x  simple_clss (atms_of_mm (init_clss S)).
           is_dominating (covering S) x 
           atms_of x = atms_of_mm (init_clss S)} 
          set_mset (init_clss S) 
          {C})  total_over_m I (set_mset N) for I
      using simp_C  NS[symmetric]
      by (auto simp: total_over_m_def total_over_set_def
          simple_clss_def atms_of_ms_def atms_of_def pNeg_def
	dest!: multi_member_split)
    have I ⊨s (λx. pNeg {#L ∈# x. ρ (atm_of L)#}) `
           {x  simple_clss (atms_of_mm (init_clss S)). is_dominating (covering S) x 
	     atms_of x = atms_of_mm (init_clss S)}
      unfolding NS[symmetric]
        total_over_m_alt_def true_clss_def
    proof
      fix D
      assume D  (λx. pNeg {#L ∈# x. ρ (atm_of L)#}) `
            {x  simple_clss (atms_of_mm N). is_dominating (covering S) x 
	     atms_of x = atms_of_mm N}
      then obtain x where
        D: D = pNeg {#L ∈# x. ρ (atm_of L)#} and
        x: x  simple_clss (atms_of_mm N) and
        dom: is_dominating (covering S) x and
	tot_x: atms_of x = atms_of_mm N
        by auto
      then have L  atms_of x
        using cov L_in no_L
	unfolding NS[symmetric]
        by (auto simp: true_clss_def is_dominating_def model_is_dominated_def
	    covering_simple_clss_def atms_of_def pNeg_def image_image
	    total_over_m_alt_def atms_of_s_def
          dest!: multi_member_split)
      then have Neg L ∈# x
        using no_L dom L unfolding atm_iff_pos_or_neg_lit
	by (auto simp: is_dominating_def model_is_dominated_def insert_subset_eq_iff
	  dest!: multi_member_split)
      then have Pos L ∈# D
        using L
        by (auto simp: pNeg_def image_image D image_iff
          dest!: multi_member_split)
      then show I  D
        using L_I by (auto dest: multi_member_split)
    qed
    then show I  C
      using total cons ent_C ent
      unfolding true_clss_cls_def tot_I2
      by auto
  qed
  then show I_S: I ⊨m CDCL_W_Abstract_State.init_clss (abs_state S)
    using ent
    by (auto simp: abs_state_def init_clss.simps)
qed

lemma exists_model_with_true_lit_still_model:
  assumes
    L_I: Pos L  I and
    L: ρ L and
    L_in: L  atms_of_mm (init_clss S) and
    ent: I ⊨m init_clss S and
    cons: consistent_interp I and
    total: total_over_m I (set_mset N) and
    cdcl: cdcl_bnb S T and
    no_L_T: ¬(J∈# covering T. Pos L ∈# J) and
    cov: covering_simple_clss N S and
    NS: atms_of_mm N = atms_of_mm (init_clss S)
  shows I ⊨m CDCL_W_Abstract_State.init_clss (abs_state T)
proof -
  have no_L: ¬(J∈# covering S. Pos L ∈# J)
    using cdcl no_L_T
    by (cases) (auto elim!: rulesE improveE conflict_optE obacktrackE
      simp: ocdclW_o.simps cdcl_bnb_bj.simps)
  have I_S: I ⊨m CDCL_W_Abstract_State.init_clss (abs_state S)
    by (rule exists_model_with_true_lit_entails_conflicting[OF assms(1-6) no_L assms(9) NS])
  have I_T': I ⊨m conflicting_clss (update_weight_information M' S)
    if T: T  update_weight_information M' S for M'
    unfolding conflicting_clss_def conflicting_clauses_def
      set_mset_filter true_cls_mset_def
  proof
    let ?T = update_weight_information M' S
    fix C
    assume C  {a. a ∈# mset_set (simple_clss (atms_of_mm (init_clss ?T))) 
                {#pNeg {#L ∈# x. ρ (atm_of L)#}.
                x ∈# {#x ∈# mset_set (simple_clss (atms_of_mm (init_clss ?T))).
                        is_dominating (covering ?T) x 
                        atms_of x = atms_of_mm (init_clss ?T)#}#} +
                init_clss ?T ⊨pm
                a}
    then have simp_C: C  simple_clss (atms_of_mm (init_clss ?T)) and
      ent_C: (λx. pNeg {#L ∈# x. ρ (atm_of L)#}) `
           {x  simple_clss (atms_of_mm (init_clss ?T)). is_dominating (covering ?T) x 
	     atms_of x = atms_of_mm (init_clss ?T)} 
          set_mset (init_clss ?T) ⊨p C
      by (auto simp: simple_clss_finite)
    have tot_I2: total_over_m I
         ((λx. pNeg {#L ∈# x. ρ (atm_of L)#}) `
          {x  simple_clss (atms_of_mm (init_clss ?T)).
           is_dominating (covering ?T) x 
           atms_of x = atms_of_mm (init_clss ?T)} 
          set_mset (init_clss ?T) 
          {C})  total_over_m I (set_mset N) for I
      using simp_C  NS[symmetric]
      by (auto simp: total_over_m_def total_over_set_def
          simple_clss_def atms_of_ms_def atms_of_def pNeg_def
	dest!: multi_member_split)
    have H: atms_of_mm (init_clss (update_weight_information M' S)) = atms_of_mm N
      by (auto simp: NS)
    have I ⊨s (λx. pNeg {#L ∈# x. ρ (atm_of L)#}) `
           {x  simple_clss (atms_of_mm (init_clss ?T)). is_dominating (covering ?T) x 
	     atms_of x = atms_of_mm (init_clss ?T)}
      unfolding NS[symmetric] H
        total_over_m_alt_def true_clss_def
    proof
      fix D
      assume D  (λx. pNeg {#L ∈# x. ρ (atm_of L)#}) `
            {x  simple_clss (atms_of_mm N). is_dominating (covering ?T) x 
	     atms_of x = atms_of_mm N}
      then obtain x where
        D: D = pNeg {#L ∈# x. ρ (atm_of L)#} and
        x: x  simple_clss (atms_of_mm N) and
        dom: is_dominating (covering ?T) x and
	tot_x: atms_of x = atms_of_mm N
        by auto
      then have L  atms_of x
        using cov L_in no_L
	unfolding NS[symmetric]
        by (auto simp: true_clss_def is_dominating_def model_is_dominated_def
	    covering_simple_clss_def atms_of_def pNeg_def image_image
	    total_over_m_alt_def atms_of_s_def
          dest!: multi_member_split)
      then have Neg L ∈# x
        using no_L_T dom L T unfolding atm_iff_pos_or_neg_lit
	by (auto simp: is_dominating_def model_is_dominated_def insert_subset_eq_iff
	  dest!: multi_member_split)
      then have Pos L ∈# D
        using L
        by (auto simp: pNeg_def image_image D image_iff
          dest!: multi_member_split)
      then show I  D
        using L_I by (auto dest: multi_member_split)
    qed
    then show I  C
      using total cons ent_C ent
      unfolding true_clss_cls_def tot_I2
      by auto
  qed
  show ?thesis
    using cdcl
  proof (cases)
    case cdcl_conflict
    then show ?thesis using I_S by (auto elim!: conflictE)
  next
    case cdcl_propagate
    then show ?thesis using I_S by (auto elim!: rulesE)
  next
    case cdcl_improve
    show ?thesis
      using I_S cdcl_improve I_T'
      by (auto simp: abs_state_def init_clss.simps
        elim!: improveE)
  next
    case cdcl_conflict_opt
    then show ?thesis using I_S by (auto elim!: conflict_optE)
  next
    case cdcl_other'
    then show ?thesis using I_S by (auto elim!: rulesE obacktrackE simp: ocdclW_o.simps cdcl_bnb_bj.simps)
  qed
qed

lemma rtranclp_exists_model_with_true_lit_still_model:
  assumes
    L_I: Pos L  I and
    L: ρ L and
    L_in: L  atms_of_mm (init_clss S) and
    ent: I ⊨m init_clss S and
    cons: consistent_interp I and
    total: total_over_m I (set_mset N) and
    cdcl: cdcl_bnb** S T and
    cov: covering_simple_clss N S and
    N = init_clss S
  shows I ⊨m CDCL_W_Abstract_State.init_clss (abs_state T)  (J∈# covering T. Pos L ∈# J)
  using cdcl assms
  apply (induction rule: rtranclp_induct)
  subgoal using exists_model_with_true_lit_entails_conflicting[of L I S N]
    by auto
  subgoal for T U
    apply (rule disjCI)
    apply (rule exists_model_with_true_lit_still_model[OF L_I L _ _ cons total, of T U])
    by (auto dest: rtranclp_cdcl_bnb_no_more_init_clss
      intro: rtranclp_cdcl_bnb_covering_simple_clss cdcl_bnb_covering_simple_clss)
  done

lemma is_dominating_nil[simp]: ¬is_dominating {#} x
  by (auto simp: is_dominating_def)

lemma atms_of_conflicting_clss_init_state:
  atms_of_mm (conflicting_clss (init_state N))  atms_of_mm N
  by (auto simp: conflicting_clss_def conflicting_clauses_def
    atms_of_ms_def simple_clss_finite
    dest!: simple_clssE)

lemma no_step_cdcl_bnb_stgy_empty_conflict2:
  assumes
    n_s: no_step cdcl_bnb S and
    all_struct: cdclW_restart_mset.cdclW_all_struct_inv (abs_state S) and
    stgy_inv: cdcl_bnb_stgy_inv S
  shows conflicting S = Some {#}
  by (rule no_step_cdcl_bnb_stgy_empty_conflict[OF can_always_improve assms])


theorem cdclcm_correctness:
  assumes
    full: full cdcl_bnb_stgy (init_state N) T and
    dist: distinct_mset_mset N
  shows
    Pos L  I  ρ L  L  atms_of_mm N  total_over_m I (set_mset N)  consistent_interp I  I ⊨m N 
      J ∈# covering T. Pos L ∈# J
proof -
  let ?S = init_state N
  have ns: no_step cdcl_bnb_stgy T and
    st: cdcl_bnb_stgy** ?S T and
    st': cdcl_bnb** ?S T
    using full unfolding full_def by (auto intro: rtranclp_cdcl_bnb_stgy_cdcl_bnb)
  have ns': no_step cdcl_bnb T
    by (meson cdcl_bnb.cases cdcl_bnb_stgy.simps no_confl_prop_impr.elims(3) ns)

  have distinct_mset C if C ∈# N for C
    using dist that by (auto simp: distinct_mset_set_def dest: multi_member_split)
  then have dist: distinct_mset_mset (N)
    by (auto simp: distinct_mset_set_def)
  then have [simp]: cdclW_restart_mset.cdclW_all_struct_inv ([], N, {#}, None)
    unfolding init_state.simps[symmetric]
    by (auto simp: cdclW_restart_mset.cdclW_all_struct_inv_def)
  have [iff]: cdcl_bnb_struct_invs ?S
    using atms_of_conflicting_clss_init_state[of N]
    by (auto simp: cdcl_bnb_struct_invs_def)
  have stgy_inv: cdcl_bnb_stgy_inv ?S
    by (auto simp: cdcl_bnb_stgy_inv_def conflict_is_false_with_level_def)
  have ent: cdclW_restart_mset.cdclW_learned_clauses_entailed_by_init (abs_state ?S)
    by (auto simp: cdclW_restart_mset.cdclW_learned_clauses_entailed_by_init_def)
  have all_struct: cdclW_restart_mset.cdclW_all_struct_inv (abs_state (init_state N))
    unfolding CDCL_W_Abstract_State.init_state.simps abs_state_def
    by (auto simp: cdclW_restart_mset.cdclW_all_struct_inv_def dist
      cdclW_restart_mset.no_strange_atm_def cdclW_restart_mset_state
      cdclW_restart_mset.cdclW_M_level_inv_def
      cdclW_restart_mset.distinct_cdclW_state_def
      cdclW_restart_mset.cdclW_conflicting_def distinct_mset_mset_conflicting_clss
      cdclW_restart_mset.cdclW_learned_clause_alt_def)
  have cdcl: cdcl_bnb** ?S T
    using st rtranclp_cdcl_bnb_stgy_cdcl_bnb unfolding full_def by blast
  have cov: covering_simple_clss N ?S
    by (auto simp: covering_simple_clss_def)

  have struct_T: cdclW_restart_mset.cdclW_all_struct_inv (abs_state T)
    using rtranclp_cdcl_bnb_stgy_all_struct_inv[OF st' all_struct] .
  have stgy_T: cdcl_bnb_stgy_inv T
    using rtranclp_cdcl_bnb_stgy_stgy_inv[OF st all_struct stgy_inv] .
  have confl: conflicting T = Some {#}
    using no_step_cdcl_bnb_stgy_empty_conflict2[OF ns' struct_T stgy_T] .
  have tot_I: total_over_m I (set_mset (clauses T + conflicting_clss T)) 
    total_over_m I (set_mset (init_clss T + conflicting_clss T)) for I
    using struct_T atms_of_conflicting_clss[of T]
    unfolding cdclW_restart_mset.cdclW_all_struct_inv_def
      cdclW_restart_mset.cdclW_learned_clause_alt_def satisfiable_def
      cdclW_restart_mset.no_strange_atm_def
    by (auto simp: clauses_def satisfiable_def total_over_m_alt_def
      abs_state_def cdclW_restart_mset_state
      cdclW_restart_mset.clauses_def)
  have unsatisfiable (set_mset (clauses T + conflicting_clss T))
    using full_cdcl_bnb_stgy_unsat[OF _ full all_struct _ stgy_inv]
    by (auto simp: can_always_improve)
  have cdclW_restart_mset.cdclW_learned_clauses_entailed_by_init
     (abs_state T)
    using rtranclp_cdcl_bnb_cdclW_learned_clauses_entailed_by_init[OF st' ent all_struct] .
  then have init_clss T + conflicting_clss T ⊨pm {#}
    using struct_T confl
    unfolding cdclW_restart_mset.cdclW_all_struct_inv_def
      cdclW_restart_mset.cdclW_learned_clause_alt_def
      cdclW_restart_mset.no_strange_atm_def tot_I
      cdclW_restart_mset.cdclW_learned_clauses_entailed_by_init_def
    by (auto simp: clauses_def abs_state_def cdclW_restart_mset_state
      cdclW_restart_mset.clauses_def
      satisfiable_def dest: true_clss_clss_left_right)
  then have unsat: unsatisfiable (set_mset (init_clss T + conflicting_clss T))
    by (auto simp: clauses_def true_clss_cls_def
      satisfiable_def)

  assume
    L_I: Pos L  I and
    L: ρ L and
    L_N: L  atms_of_mm N and
    tot_I: total_over_m I (set_mset N) and
    cons: consistent_interp I and
    I_N: I ⊨m N
  show Multiset.Bex (covering T) ((∈#) (Pos L))
    using rtranclp_exists_model_with_true_lit_still_model[OF L_I L _ _ _ _ cdcl, of N] L_N
      I_N tot_I cons cov unsat
    by (auto simp: abs_state_def cdclW_restart_mset_state)
qed

end


text Now we instantiate the previous with termλ_. True: This means that we aim at making
all variables that appears at least ones true.

global_interpretation cover_all_vars: covering_models λ_. True
  .

context conflict_driven_clause_learningW_covering_models
begin

interpretation cover_all_vars: conflict_driven_clause_learningW_covering_models where
    ρ = λ_::'v. True and
    state = state and
    trail = trail and
    init_clss = init_clss and
    learned_clss = learned_clss and
    conflicting = conflicting and
    cons_trail = cons_trail and
    tl_trail = tl_trail and
    add_learned_cls = add_learned_cls and
    remove_cls = remove_cls and
    update_conflicting = update_conflicting and
    init_state = init_state
  by standard

lemma
  cover_all_vars.model_is_dominated M M' 
    filter_mset (λL. is_pos L) M ⊆# filter_mset (λL. is_pos L) M'
  unfolding cover_all_vars.model_is_dominated_def
  by auto

lemma
  cover_all_vars.conflicting_clauses N  =
    {# C ∈# (mset_set (simple_clss (atms_of_mm N))).
        (pNeg `
        {a. a ∈# mset_set (simple_clss (atms_of_mm N)) 
            (M∈#. J. a ⊆# J  cover_all_vars.model_is_dominated J M) 
            atms_of a = atms_of_mm N} 
        set_mset N) ⊨p C#}
  unfolding cover_all_vars.conflicting_clauses_def
    cover_all_vars.is_dominating_def
  by auto

theorem cdclcm_correctness_all_vars: (* \htmllink{cdclcm-correctness}*)
  assumes
    full: full cover_all_vars.cdcl_bnb_stgy (init_state N) T and
    dist: distinct_mset_mset N
  shows
    Pos L  I  L  atms_of_mm N  total_over_m I (set_mset N)  consistent_interp I  I ⊨m N 
      J ∈# covering T. Pos L ∈# J
  using cover_all_vars.cdclcm_correctness[OF assms]
  by blast

end

end