Theory Watched_Literals_Watch_List_Reduce

theory Watched_Literals_Watch_List_Reduce
  imports Watched_Literals_List_Simp Watched_Literals_List_Reduce Watched_Literals_Watch_List
    Watched_Literals_Watch_List_Restart
begin
no_notation funcset (infixr "" 60)

lemma GC_remap_all_init_atmsD:
  GC_remap (N, x, m) (N', x', m') 
    all_init_atms N NE + all_init_atms m NE  = all_init_atms N' NE  + all_init_atms m' NE
  by (induction rule: GC_remap.induct[split_format(complete)])
    (auto simp: all_init_atms_def all_init_lits_def init_clss_l_fmdrop_if
       init_clss_l_fmupd_if image_mset_remove1_mset_if
    simp del: all_init_atms_def[symmetric]
    simp flip: image_mset_union all_lits_of_mm_add_mset all_lits_of_mm_union)

lemma rtranclp_GC_remap_all_init_atmsD:
  GC_remap** (N, x, m) (N', x', m') 
    all_init_atms N NE + all_init_atms m NE  = all_init_atms N' NE  + all_init_atms m' NE
  by (induction rule: rtranclp_induct[of r (_, _, _) (_, _, _), split_format(complete), of for r])
    (auto dest: GC_remap_all_init_atmsD)

lemma rtranclp_GC_remap_all_init_atms:
  GC_remap** (x1a, Map.empty, fmempty) (fmempty, m, x1ad) 
    all_init_atms x1ad NE = all_init_atms x1a NE
  by (auto dest!: rtranclp_GC_remap_all_init_atmsD[of _ _ _ _ _ _ NE])

lemma GC_remap_all_init_lits:
  GC_remap (N, m, new) (N', m', new') 
    all_init_lits N NE + all_init_lits new NE = all_init_lits N' NE + all_init_lits new' NE
  by (induction rule: GC_remap.induct[split_format(complete)])
    (case_tac irred N C ; auto simp: all_init_lits_def init_clss_l_fmupd_if image_mset_remove1_mset_if
    simp flip: all_lits_of_mm_union)

lemma rtranclp_GC_remap_all_init_lits:
  GC_remap** (N, m, new) (N', m', new') 
  all_init_lits N NE + all_init_lits new NE = all_init_lits N' NE + all_init_lits new' NE
  by (induction rule: rtranclp_induct[of r (_, _, _) (_, _, _), split_format(complete), of for r])
    (auto dest: GC_remap_all_init_lits)

lemma subsumed_clauses_alt_def:
  subsumed_clauses S = subsumed_init_clauses S + subsumed_learned_clauses S
  by (cases S) auto

definition drop_clause_add_move_init_wl :: 'v twl_st_wl  nat  'v twl_st_wl where
  drop_clause_add_move_init_wl = (λ(M, N, D, NE0, UE, NEk, UEk, NS, US, N0, U0, Q, W) C.
     (M, fmdrop C N, D, add_mset (mset (N  C)) NE0, UE, NEk, UEk, NS, {#}, N0, U0, Q, W))

definition drop_clause_wl :: 'v twl_st_wl  nat  'v twl_st_wl where
  drop_clause_wl = (λ(M, N, D, NE0, UE, NS, US, N0, U0, Q, W) C.
     (M, fmdrop C N, D, NE0, UE, NS, {#}, N0, U0, Q, W))

lemma reduce_dom_clauses_fmdrop:
  reduce_dom_clauses N0 N  reduce_dom_clauses N0 (fmdrop C N)
  using distinct_mset_dom[of N]
  by (auto simp: reduce_dom_clauses_def distinct_mset_remove1_All)

lemma correct_watching_fmdrop:
  assumes
    irred: ¬ irred N C and
    C: C ∈# dom_m N and
    correct_watching' (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W) and
    C2: length (N  C)  2 and
    blit: literals_are_ℒin' (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W)
  shows correct_watching' (M, fmdrop C N, D, NE, {#}, NEk, UEk, NS, {#}, N0, {#}, Q, W) and
     literals_are_ℒin'  (M, fmdrop C N, D, NE, {#}, NEk, UEk, NS, {#}, N0, {#}, Q, W)
proof -
  let ?S = (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W)
  have
    Hdist: L i K b. L∈#all_init_lits_of_wl ?S 
       distinct_watched (W L) and
    H1: L i K b. L∈#all_init_lits_of_wl ?S 
       (i, K, b)∈#mset (W L)  i ∈# dom_m N  K  set (N  i)  K  L 
         correctly_marked_as_binary N (i, K, b) and
    H1': L i K b. L∈#all_init_lits_of_wl ?S 
       (i, K, b)∈#mset (W L)  b   i ∈# dom_m N and
    H2: L. L∈# all_init_lits_of_wl ?S 
       {#i ∈# fst `# mset (W L). i ∈# dom_m N#} =
       {#C ∈# dom_m (get_clauses_l (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, {#}, {#})).
        L  set (watched_l (get_clauses_l (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, {#}, {#})  C))#}
    using assms
    unfolding correct_watching'.simps clause_to_update_def
    by fast+
  have 1: {#Ca ∈# dom_m (fmdrop C N). L  set (watched_l (fmdrop C N  Ca))#} =
    {#Ca ∈# dom_m (fmdrop C N). L  set (watched_l (N  Ca))#} for L
    apply (rule filter_mset_cong2)
      using distinct_mset_dom[of N] C irred
    by (auto simp: image_mset_remove1_mset_if clause_to_update_def image_filter_replicate_mset
      distinct_mset_remove1_All filter_mset_neq_cond dest: all_lits_of_mm_diffD
        dest: multi_member_split)
  have 2: remove1_mset C {#Ca ∈# dom_m N. L  set (watched_l (N  Ca))#} =
     removeAll_mset C {#Ca ∈# dom_m N. L  set (watched_l (N  Ca))#} for L
    apply (rule distinct_mset_remove1_All)
    using distinct_mset_dom[of N]
    by (auto intro: distinct_mset_filter)
  have [simp]: filter_mset (λi. i  C  i ∈# (dom_m N)) A  =
    removeAll_mset C (filter_mset (λi. i ∈# dom_m N) A) for A
    by (induction A)
      (auto simp: distinct_mset_remove1_All distinct_mset_dom)
  show  correct_watching' (M, fmdrop C N, D, NE, {#}, NEk, UEk, NS, {#}, N0, {#}, Q, W)
    unfolding correct_watching'.simps clause_to_update_def
    apply (intro conjI impI ballI)
    subgoal for L using Hdist[of L] distinct_mset_dom[of N]
        H1[of L fst iK fst (snd iK) snd (snd iK)] C irred
	H1'[of L fst iK fst (snd iK) snd (snd iK)]
      apply (auto simp: image_mset_remove1_mset_if clause_to_update_def image_filter_replicate_mset
      distinct_mset_remove1_All filter_mset_neq_cond correctly_marked_as_binary.simps dest: all_lits_of_mm_diffD
        dest: multi_member_split)
      done
    subgoal for L iK
      using distinct_mset_dom[of N] H1[of L fst iK fst (snd iK) snd (snd iK)] C irred
        H1'[of L fst iK fst (snd iK) snd (snd iK)]
      apply (auto simp: image_mset_remove1_mset_if clause_to_update_def image_filter_replicate_mset
      distinct_mset_remove1_All filter_mset_neq_cond correctly_marked_as_binary.simps dest: all_lits_of_mm_diffD
        dest: multi_member_split)
      done
    subgoal for L iK
       using distinct_mset_dom[of N] H1[of L fst iK fst (snd iK) snd (snd iK)] C irred
        H1'[of L fst iK fst (snd iK) snd (snd iK)] C2
      apply (auto simp: image_mset_remove1_mset_if clause_to_update_def image_filter_replicate_mset
      distinct_mset_remove1_All filter_mset_neq_cond correctly_marked_as_binary.simps dest: all_lits_of_mm_diffD
        dest: multi_member_split)
      done
    subgoal for L
      using C irred apply -
      unfolding get_clauses_l.simps
      apply (subst 1)
      by (auto 5 1  simp: image_mset_remove1_mset_if clause_to_update_def image_filter_replicate_mset
        distinct_mset_remove1_All filter_mset_neq_cond 2 H2 dest: all_lits_of_mm_diffD
        dest: multi_member_split)
    done
  have [dest!]: x ∈# all_learned_lits_of_wl ([], fmdrop C N, D, NE, {#}, NEk, UEk, NS, {#}, N0, {#}, Q, W) 
    x ∈# all_learned_lits_of_wl ([], N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W) for x
    using assms(1,2)
    by (auto dest: all_lits_of_mm_diffD simp: all_learned_lits_of_wl_def all_lits_of_mm_union
      image_mset_remove1_mset_if)

  show literals_are_ℒin'  (M, fmdrop C N, D, NE, {#}, NEk, UEk, NS, {#}, N0, {#}, Q, W)
     using assms by (auto simp: blits_in_ℒin'_def image_mset_remove1_mset_if literals_are_ℒin'_def
         all_init_lits_def all_lits_of_mm_union
       dest: multi_member_split all_lits_of_mm_diffD)
qed

lemma correct_watching'_fmdrop:
  assumes
    irred: ¬ irred N C and
    C: C ∈# dom_m N and
    correct_watching' (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W) and
    literals_are_ℒin'  (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W)
  shows correct_watching'_nobin (M, fmdrop C N, D, NE, UE, NEk, UEk, NS, {#}, N0, U0, Q, W)and
    literals_are_ℒin'  (M, fmdrop C N, D, NE, UE, NEk, UEk, NS, {#}, N0, U0, Q, W)
proof -
  let ?S = (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W)
  let ?ℒ = all_init_lits_of_wl ?S
  have
    Hdist: L i K b. L∈#?ℒ 
       distinct_watched (W L) and
    H1: L i K b. L∈#?ℒ 
       (i, K, b)∈#mset (W L)  i ∈# dom_m N  K  set (N  i)  K  L  correctly_marked_as_binary N (i, K, b) and
    H2: L. L∈#?ℒ 
       {#i ∈# fst `# mset (W L). i ∈# dom_m N#} =
       {#C ∈# dom_m (get_clauses_l (M', N, D, NE, UE, NEk, UEk, NS, US,N0, U0,  {#}, {#})).
        L  set (watched_l (get_clauses_l (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, {#}, {#})  C))#}
    using assms
    unfolding correct_watching'.simps clause_to_update_def
    by fast+
  have 1: {#Ca ∈# dom_m (fmdrop C N). L  set (watched_l (fmdrop C N  Ca))#} =
    {#Ca ∈# dom_m (fmdrop C N). L  set (watched_l (N  Ca))#} for L
    apply (rule filter_mset_cong2)
      using distinct_mset_dom[of N] C irred
    by (auto simp: image_mset_remove1_mset_if clause_to_update_def image_filter_replicate_mset
      distinct_mset_remove1_All filter_mset_neq_cond dest: all_lits_of_mm_diffD
        dest: multi_member_split)
  have 2: remove1_mset C {#Ca ∈# dom_m N. L  set (watched_l (N  Ca))#} =
     removeAll_mset C {#Ca ∈# dom_m N. L  set (watched_l (N  Ca))#} for L
    apply (rule distinct_mset_remove1_All)
    using distinct_mset_dom[of N]
    by (auto intro: distinct_mset_filter)
  have [simp]: filter_mset (λi. i  C  i ∈# dom_m N) A  =
    removeAll_mset C (filter_mset (λi. i ∈# dom_m N) A) for A
    by (induction A)
      (auto simp: distinct_mset_remove1_All distinct_mset_dom)
  show  correct_watching'_nobin (M, fmdrop C N, D, NE, UE, NEk, UEk, NS, {#}, N0, U0, Q, W)
    unfolding correct_watching'_nobin.simps clause_to_update_def
    apply (intro conjI impI ballI)
    subgoal for L using Hdist[of L] distinct_mset_dom[of N]
        H1[of L fst iK fst (snd iK) snd (snd iK)] C irred
      apply (auto simp: image_mset_remove1_mset_if clause_to_update_def image_filter_replicate_mset
      distinct_mset_remove1_All filter_mset_neq_cond correctly_marked_as_binary.simps dest: all_lits_of_mm_diffD
        dest: multi_member_split)
      done
    subgoal for L iK
      using distinct_mset_dom[of N] H1[of L fst iK fst (snd iK) snd (snd iK)] C irred
      apply (auto simp: image_mset_remove1_mset_if clause_to_update_def image_filter_replicate_mset
      distinct_mset_remove1_All filter_mset_neq_cond correctly_marked_as_binary.simps dest: all_lits_of_mm_diffD
        dest: multi_member_split)
      done
    subgoal for L
      using C irred apply -
      unfolding get_clauses_l.simps
      apply (subst 1)
      by (auto 5 1  simp: image_mset_remove1_mset_if clause_to_update_def image_filter_replicate_mset
        distinct_mset_remove1_All filter_mset_neq_cond 2 H2 dest: all_lits_of_mm_diffD
        dest: multi_member_split)
    done
  have [dest!]: x ∈# all_learned_lits_of_wl ([], fmdrop C N, D, NE, UE, NEk, UEk, NS, {#}, N0, U0, Q, W) 
           x ∈# all_learned_lits_of_wl ([], N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W) for x
    using assms
    by (auto dest: all_lits_of_mm_diffD simp: all_learned_lits_of_wl_def
      all_lits_of_mm_union image_mset_remove1_mset_if)
  show literals_are_ℒin'  (M, fmdrop C N, D, NE, UE, NEk, UEk, NS, {#}, N0, U0, Q, W)
    using assms by (auto simp: blits_in_ℒin'_def image_mset_remove1_mset_if literals_are_ℒin'_def
         all_init_lits_def all_lits_of_mm_union
       dest: multi_member_split all_lits_of_mm_diffD)
qed

lemma all_init_lits_of_wl_fmdrop_addNEk[simp]:
  irred N C  C ∈# dom_m N 
  (all_init_lits_of_wl (M, fmdrop C N, D, NE, UE, add_mset (mset (N  C)) NEk, UEk, NS, US, N0, U0, Q, W)) =
  (all_init_lits_of_wl (M, N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W))
  using distinct_mset_dom[of N]
  by (auto simp: all_init_lits_of_wl_def ran_m_def dest!: multi_member_split
    intro!: arg_cong[of _ _ all_lits_of_mm]
    intro!: filter_mset_cong2 image_mset_cong2)

lemma correct_watching'_fmdrop':
  assumes
    irred: irred N C and
    C: C ∈# dom_m N and
    correct_watching'_nobin (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W)and
    literals_are_ℒin' (M', N, D, NE, UE, NEk, UEk, NS, US,  N0, U0, Q, W)
  shows correct_watching'_nobin (M, fmdrop C N, D, NE, UE, add_mset (mset (N  C)) NEk, UEk, NS, {#}, N0, U0, Q, W) and
    literals_are_ℒin' (M, fmdrop C N, D, NE, UE, add_mset (mset (N  C)) NEk, UEk, NS, {#}, N0, U0, Q, W)
proof -
  let ?S = (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W)
  let ?ℒ = all_init_lits_of_wl ?S
  have
    Hdist: L. L∈#?ℒ 
       distinct_watched (W L) and
    H1: L i K b. L∈#?ℒ 
       (i, K, b)∈#mset (W L)  i ∈# dom_m N 
          K  set (N  i)  K  L  correctly_marked_as_binary N (i, K, b) and
    H2: L. L∈#?ℒ 
       {#i ∈# fst `# mset (W L). i ∈# dom_m N#} =
       {#C ∈# dom_m (get_clauses_l (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, {#}, {#})).
        L  set (watched_l (get_clauses_l (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, {#}, {#})  C))#}
    using assms
    unfolding correct_watching'_nobin.simps clause_to_update_def
    by blast+
  have 1: {#Ca ∈# dom_m (fmdrop C N). L  set (watched_l (fmdrop C N  Ca))#} =
    {#Ca ∈# dom_m (fmdrop C N). L  set (watched_l (N  Ca))#} for L
    apply (rule filter_mset_cong2)
      using distinct_mset_dom[of N] H1[of L fst iK snd iK] C irred
    by (auto simp: image_mset_remove1_mset_if clause_to_update_def image_filter_replicate_mset
      distinct_mset_remove1_All filter_mset_neq_cond dest: all_lits_of_mm_diffD
        dest: multi_member_split)
  have 2: remove1_mset C {#Ca ∈# dom_m N. L  set (watched_l (N  Ca))#} =
     removeAll_mset C {#Ca ∈# dom_m N. L  set (watched_l (N  Ca))#} for L
    apply (rule distinct_mset_remove1_All)
    using distinct_mset_dom[of N]
    by (auto intro: distinct_mset_filter)
  have [simp]: filter_mset (λi. i  C  i ∈# (dom_m N)) A  =
    removeAll_mset C (filter_mset (λi. i ∈# dom_m N) A) for A
    by (induction A)
      (auto simp: distinct_mset_remove1_All distinct_mset_dom)
  show correct_watching'_nobin (M, fmdrop C N, D, NE, UE, add_mset (mset (N  C)) NEk, UEk, NS, {#}, N0, U0, Q, W)
    unfolding correct_watching'_nobin.simps clause_to_update_def
    apply (intro conjI impI ballI)
    subgoal for L
      using distinct_mset_dom[of N] H1[of L fst iK fst (snd iK) snd (snd iK)] C irred
        Hdist[of L] irred C
      apply (auto simp: image_mset_remove1_mset_if clause_to_update_def image_filter_replicate_mset
      distinct_mset_remove1_All filter_mset_neq_cond correctly_marked_as_binary.simps dest: all_lits_of_mm_diffD
        dest: multi_member_split)
      done
    subgoal for L iK
      using distinct_mset_dom[of N] H1[of L fst iK fst (snd iK) snd (snd iK)] C irred
      apply (auto simp: image_mset_remove1_mset_if clause_to_update_def image_filter_replicate_mset
      distinct_mset_remove1_All filter_mset_neq_cond correctly_marked_as_binary.simps dest: all_lits_of_mm_diffD
        dest: multi_member_split)
      done
    subgoal for L
      using C irred apply -
      unfolding get_clauses_l.simps
      apply (subst 1)
      by (auto 5 1  simp: image_mset_remove1_mset_if clause_to_update_def image_filter_replicate_mset
        distinct_mset_remove1_All filter_mset_neq_cond 2 H2 dest: all_lits_of_mm_diffD
        dest: multi_member_split)
    done
  have [dest!]: x ∈# all_learned_lits_of_wl ([], N, D, NE, UE, add_mset (mset (N  C)) NEk, UEk, NS, {#}, N0, U0, Q, W) 
           x ∈# all_learned_lits_of_wl ([], N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W) for x
    using assms
    by (auto dest: all_lits_of_mm_diffD simp: all_learned_lits_of_wl_def
      all_lits_of_mm_union image_mset_remove1_mset_if)
  have (N  C, irred N C) ∈# (init_clss_l N)
    using assms by (auto simp: ran_m_def dest!: multi_member_split) (metis prod.collapse)
  from multi_member_split[OF this]
  show literals_are_ℒin' (M, fmdrop C N, D, NE, UE, add_mset (mset (N  C)) NEk, UEk, NS, {#}, N0, U0, Q, W)
    using distinct_mset_dom[of N]
    using assms by (auto simp: blits_in_ℒin'_def image_mset_remove1_mset_if all_lits_of_mm_add_mset
          all_lits_of_mm_union literals_are_ℒin'_def all_init_lits_def
       dest: multi_member_split all_lits_of_mm_diffD)
qed


lemma correct_watching'_fmdrop'':
  assumes
    irred: ¬irred N C and
    C: C ∈# dom_m N and
    correct_watching'_nobin (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W) and
    literals_are_ℒin' (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W)
  shows correct_watching'_nobin (M, fmdrop C N, D, NE, UE, NEk, add_mset (mset (N  C)) UEk, NS, {#}, N0, U0, Q, W) and
    literals_are_ℒin' (M, fmdrop C N, D, NE, UE, NEk, add_mset (mset (N  C)) UEk, NS, {#},  N0, U0, Q, W)
proof -
  let ?S = (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W)
  let ?ℒ = all_init_lits_of_wl ?S
  have
    Hdist: L. L∈#?ℒ 
       distinct_watched (W L) and
    H1: L i K b. L∈#?ℒ 
       (i, K, b)∈#mset (W L)  i ∈# dom_m N  K  set (N  i)  K  L  correctly_marked_as_binary N (i, K, b) and
    H2: L. L∈#?ℒ 
       {#i ∈# fst `# mset (W L). i ∈# dom_m N#} =
       {#C ∈# dom_m (get_clauses_l (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, {#}, {#})).
        L  set (watched_l (get_clauses_l (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, {#}, {#})  C))#}
    using assms
    unfolding correct_watching'_nobin.simps clause_to_update_def
    by blast+
  have 1: {#Ca ∈# dom_m (fmdrop C N). L  set (watched_l (fmdrop C N  Ca))#} =
    {#Ca ∈# dom_m (fmdrop C N). L  set (watched_l (N  Ca))#} for L
    apply (rule filter_mset_cong2)
      using distinct_mset_dom[of N] H1[of L fst iK snd iK] C irred
    by (auto simp: image_mset_remove1_mset_if clause_to_update_def image_filter_replicate_mset
      distinct_mset_remove1_All filter_mset_neq_cond dest: all_lits_of_mm_diffD
        dest: multi_member_split)
  have 2: remove1_mset C {#Ca ∈# dom_m N. L  set (watched_l (N  Ca))#} =
     removeAll_mset C {#Ca ∈# dom_m N. L  set (watched_l (N  Ca))#} for L
    apply (rule distinct_mset_remove1_All)
    using distinct_mset_dom[of N]
    by (auto intro: distinct_mset_filter)
  have [simp]: filter_mset (λi. i  C  i ∈# dom_m N) A  =
    removeAll_mset C (filter_mset (λi. i ∈# dom_m N) A) for A
    by (induction A)
      (auto simp: distinct_mset_remove1_All distinct_mset_dom)
  show  correct_watching'_nobin (M, fmdrop C N, D, NE, UE, NEk, add_mset (mset (N  C)) UEk, NS, {#}, N0, U0, Q, W)
    unfolding correct_watching'_nobin.simps clause_to_update_def
    apply (intro conjI impI ballI)
    subgoal for L
      using distinct_mset_dom[of N] H1[of L fst iK fst (snd iK) snd (snd iK)] C irred
        Hdist[of L] assms
      apply (auto simp: image_mset_remove1_mset_if clause_to_update_def image_filter_replicate_mset
      distinct_mset_remove1_All filter_mset_neq_cond correctly_marked_as_binary.simps dest: all_lits_of_mm_diffD
        dest: multi_member_split)
      done
    subgoal for L iK
      using distinct_mset_dom[of N] H1[of L fst iK fst (snd iK) snd (snd iK)] C irred
      apply (auto simp: image_mset_remove1_mset_if clause_to_update_def image_filter_replicate_mset
      distinct_mset_remove1_All filter_mset_neq_cond correctly_marked_as_binary.simps dest: all_lits_of_mm_diffD
        dest: multi_member_split)
      done
    subgoal for L
      using C irred apply -
      unfolding get_clauses_l.simps
      apply (subst 1)
      by (auto 5 1  simp: image_mset_remove1_mset_if clause_to_update_def image_filter_replicate_mset
        distinct_mset_remove1_All filter_mset_neq_cond 2 H2 dest: all_lits_of_mm_diffD
        dest: multi_member_split)
    done

  have [dest!]: x ∈# all_learned_lits_of_wl ([], fmdrop C N, D, NE, UE, NEk, add_mset (mset (N  C)) UEk, NS, {#}, N0, U0, Q, W) 
           x ∈# all_learned_lits_of_wl ([], N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W) for x
    using assms
    by (auto dest: all_lits_of_mm_diffD simp: all_learned_lits_of_wl_def
      all_lits_of_mm_union image_mset_remove1_mset_if)
  have (N  C, irred N C) ∈# (learned_clss_l N)
    using assms by (auto simp: ran_m_def dest!: multi_member_split) (metis prod.collapse)
  from multi_member_split[OF this]
  show literals_are_ℒin' (M, fmdrop C N, D, NE, UE, NEk, add_mset (mset (N  C)) UEk, NS, {#}, N0, U0, Q, W)
    using distinct_mset_dom[of N]
    using assms by (auto simp: blits_in_ℒin'_def image_mset_remove1_mset_if all_lits_of_mm_add_mset
          all_lits_of_mm_union literals_are_ℒin'_def all_init_lits_def
      dest: multi_member_split all_lits_of_mm_diffD)
qed

definition remove_one_annot_true_clause_one_imp_wl_pre where
  remove_one_annot_true_clause_one_imp_wl_pre i T 
     (T'. (T, T')  state_wl_l None 
       remove_one_annot_true_clause_one_imp_pre i T' 
       correct_watching'_nobin T  literals_are_ℒin' T)

definition replace_annot_wl_pre :: 'v literal  nat  'v twl_st_wl  bool where
replace_annot_wl_pre L C S 
  (S'. (S, S')  state_wl_l None  L ∈# all_init_lits_of_wl S 
    replace_annot_l_pre L C S'  literals_are_ℒin' S 
    correct_watching'_nobin S)

definition replace_annot_wl :: 'v literal  nat  'v twl_st_wl  'v twl_st_wl nres where
  replace_annot_wl L C =
    (λ(M, N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W). do {
      ASSERT(replace_annot_wl_pre L C (M, N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W));
      RES {(M', N, D, NE, {#}, NEk, UEk, NS, {#}, N0, {#}, Q, W)| M'.
       (M2 M1 C. M = M2 @ Propagated L C # M1  M' = M2 @ Propagated L 0 # M1)}
   })

lemma replace_annot_l_pre_replace_annot_wl_pre: (((L, C), S), (L', C'), S')
     Id ×f nat_rel ×f
      {(S, T).
       (S, T)  state_wl_l None 
       correct_watching'_nobin S  literals_are_ℒin' S} 
    replace_annot_l_pre L' C' S' 
    replace_annot_wl_pre L C S
    unfolding replace_annot_wl_pre_def replace_annot_l_pre_alt_def
    unfolding replace_annot_l_pre_def[symmetric]
    by (rule exI[of _ S'])
      (auto simp add: ac_simps all_init_lits_of_wl_def)

lemma all_learned_lits_of_wl_all_init_lits_of_wlD[intro]:
  set_mset (all_learned_lits_of_wl (M, ab, ac, ad, ae, NEk, UEk, af, ag, ah, ai, aj, ba))
        set_mset (all_init_lits_of_wl (M, ab, ac, ad, {#}, NEk, {#}, af, {#}, ah, {#}, aj, ba)) 
       x ∈# all_learned_lits_of_wl (M, ab, ac, ad, {#}, NEk, UEk, af, {#}, ah, {#}, aj, ba) 
       x ∈# all_init_lits_of_wl (M, ab, ac, ad, {#}, NEk, {#}, af, {#}, ah, {#}, aj, ba)
  by (auto simp: all_learned_lits_of_wl_def all_init_lits_of_wl_def
    all_lits_of_mm_union)

lemma replace_annot_wl_replace_annot_l:
  (uncurry2 replace_annot_wl, uncurry2 replace_annot_l) 
    Id ×f nat_rel ×f {(S, T). (S, T)  state_wl_l None  correct_watching'_nobin S 
        literals_are_ℒin' S} f
    {(S, T). (S, T)  state_wl_l None  correct_watching'_nobin S 
        literals_are_ℒin' S}nres_rel
    unfolding replace_annot_wl_def replace_annot_l_def uncurry_def
    apply (intro frefI nres_relI)
    apply clarify
    apply refine_rcg
    subgoal for a b aa ab ac ad ae af ba ag bb ah ai aj ak al am bc
      by (force intro!: replace_annot_l_pre_replace_annot_wl_pre)
    subgoal
      by (rule RES_refine)
       (force simp: state_wl_l_def literals_are_ℒin'_def ac_simps
          all_lits_of_mm_union
        correct_watching'_nobin.simps clause_to_update_def blits_in_ℒin'_def)
    done

definition remove_and_add_cls_wl :: nat  'v twl_st_wl  'v twl_st_wl nres where
  remove_and_add_cls_wl C =
    (λ(M, N, D, NE, UE, NEk, UEk, NS, US, Q, W). do {
       ASSERT(C ∈# dom_m N);
        RETURN (M, fmdrop C N, D, NE, UE,
         (if irred N C then add_mset (mset (NC)) else id) NEk,
	 (if ¬irred N C then add_mset (mset (NC)) else id) UEk, NS, {#}, Q, W)
    })

definition remove_one_annot_true_clause_one_imp_wl
  :: nat  'v twl_st_wl  (nat × 'v twl_st_wl) nres
where
remove_one_annot_true_clause_one_imp_wl = (λi S. do {
      ASSERT(remove_one_annot_true_clause_one_imp_wl_pre i S);
      ASSERT(is_proped (rev (get_trail_wl S) ! i));
      (L, C)  SPEC(λ(L, C). (rev (get_trail_wl S))!i = Propagated L C);
      ASSERT(Propagated L C  set (get_trail_wl S));
      ASSERT(L ∈# all_init_lits_of_wl S);
      if C = 0 then RETURN (i+1, S)
      else do {
        ASSERT(C ∈# dom_m (get_clauses_wl S));
	S  replace_annot_wl L C S;
	S  remove_and_add_cls_wl C S;
        RETURN (i+1, S)
      }
  })

lemma
  assumes
      x2_T: (x2, T)  state_wl_l b and
      struct: twl_struct_invs U and
      T_U: (T, U)  twl_st_l b'
  shows
    literals_are_ℒin_literals_are_ℒin_trail_init:
      literals_are_in_ℒin_trail (all_init_atms_st x2) (get_trail_wl x2)
     (is ?trail)
proof -
  have
    alien: cdclW_restart_mset.no_strange_atm (stateW_of U) and
    confl: cdclW_restart_mset.cdclW_conflicting (stateW_of U) and
    M_lev: cdclW_restart_mset.cdclW_M_level_inv (stateW_of U) and
    dist: cdclW_restart_mset.distinct_cdclW_state (stateW_of U)
   using struct unfolding twl_struct_invs_def cdclW_restart_mset.cdclW_all_struct_inv_def
        pcdcl_all_struct_invs_def stateW_of_def
   by fast+

  show lits_trail: literals_are_in_ℒin_trail (all_init_atms_st x2) (get_trail_wl x2)
    using alien x2_T T_U unfolding is_ℒall_def
      literals_are_in_ℒin_trail_def cdclW_restart_mset.no_strange_atm_def
      literals_are_ℒin_def all_init_lits_of_wl_def all_atms_def all_all_init_atms
    by
     (auto 5 2
        simp del: all_clss_l_ran_m union_filter_mset_complement
        simp: twl_st twl_st_l twl_st_wl all_lits_of_mm_union lits_of_def
        convert_lits_l_def image_image in_all_lits_of_mm_ain_atms_of_iff
        get_unit_clauses_wl_alt_def all_all_init_atms all_init_lits_def)
qed

lemma remove_one_annot_true_clause_one_imp_wl_remove_one_annot_true_clause_one_imp:
    (uncurry remove_one_annot_true_clause_one_imp_wl, uncurry remove_one_annot_true_clause_one_imp)
     nat_rel ×f  {(S, T). (S, T)  state_wl_l None  correct_watching'_nobin S  literals_are_ℒin' S} f
      nat_rel ×f {(S, T). (S, T)  state_wl_l None  correct_watching'_nobin S  literals_are_ℒin' S}nres_rel
    (is _  _ ×f ?A f _)
proof -

  have [refine0]: remove_and_add_cls_wl C S  ?A (remove_and_add_cls_l C' S')
    if (C, C')  Id and (S, S')  ?A
      for C C' S S'
    using that unfolding remove_and_add_cls_l_def remove_and_add_cls_wl_def
    by refine_rcg
     (auto intro!: RES_refine simp: state_wl_l_def
       intro: correct_watching'_fmdrop correct_watching'_fmdrop''
          correct_watching'_fmdrop')

  show ?thesis
    unfolding remove_one_annot_true_clause_one_imp_wl_def remove_one_annot_true_clause_one_imp_def
      uncurry_def
    apply (intro frefI nres_relI)
    apply (refine_vcg replace_annot_wl_replace_annot_l[THEN fref_to_Down_curry2])
    subgoal for x y unfolding remove_one_annot_true_clause_one_imp_wl_pre_def
      by (rule exI[of _ snd y]) auto
    subgoal by (simp add: state_wl_l_def)
    subgoal by (simp add: state_wl_l_def)
    subgoal by (simp add: state_wl_l_def)
    subgoal for x y x1 x2 x1a x2a xa x' x1b x2b x1c x2c
      unfolding remove_one_annot_true_clause_one_imp_wl_pre_def
       remove_one_annot_true_clause_one_imp_pre_def
      apply normalize_goal+

      subgoal for U S T
        using literals_are_ℒin_literals_are_ℒin_trail_init[of x2a U None T None]
        by (auto simp add: literals_are_in_ℒin_trail_def lits_of_def image_image
          all_all_init_atms)
       done
    subgoal by simp
    subgoal by (simp add: state_wl_l_def)
    subgoal by (simp add: state_wl_l_def)
    subgoal by (simp add: state_wl_l_def)
    subgoal by simp
    subgoal by (simp add: state_wl_l_def)
    done
qed

definition remove_one_annot_true_clause_imp_wl_inv where
  remove_one_annot_true_clause_imp_wl_inv S = (λ(i, T).
     (S' T'. (S, S')  state_wl_l None  (T, T')  state_wl_l None 
       correct_watching'_nobin S  correct_watching'_nobin T  literals_are_ℒin' S 
       literals_are_ℒin' T 
       remove_one_annot_true_clause_imp_inv S' (i, T')))

definition remove_all_learned_subsumed_clauses_wl :: 'v twl_st_wl  ('v twl_st_wl) nres where
remove_all_learned_subsumed_clauses_wl = (λ(M, N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W).
   RETURN (M, N, D, NE, {#}, NEk, UEk, NS, {#}, N0, {#}, Q, W))

definition remove_one_annot_true_clause_imp_wl :: 'v twl_st_wl  ('v twl_st_wl) nres
where
remove_one_annot_true_clause_imp_wl = (λS. do {
    k  SPEC(λk. (M1 M2 K. (Decided K # M1, M2)  set (get_all_ann_decomposition (get_trail_wl S)) 
        count_decided M1 = 0  k = length M1)
       (count_decided (get_trail_wl S) = 0  k = length (get_trail_wl S)));
    start  SPEC (λi. i  k  (j < i. is_proped (rev (get_trail_wl S) ! j)  mark_of (rev (get_trail_wl S) ! j) = 0));
    (i, T)  WHILETremove_one_annot_true_clause_imp_wl_inv S(λ(i, S). i < k)
      (λ(i, S). remove_one_annot_true_clause_one_imp_wl i S)
      (start, S);
    ASSERT (remove_one_annot_true_clause_imp_wl_inv S (i, T));
    remove_all_learned_subsumed_clauses_wl T
  })

lemma remove_all_learned_subsumed_clauses_wl_remove_all_learned_subsumed_clauses:
  (remove_all_learned_subsumed_clauses_wl, remove_all_learned_subsumed_clauses)
    {(S, T). (S, T)  state_wl_l None  correct_watching'_nobin S  literals_are_ℒin' S} f
      {(S, T). (S, T)  state_wl_l None  correct_watching'_nobin S  literals_are_ℒin' S}nres_rel
  apply (auto intro!: frefI nres_relI
    simp: remove_all_learned_subsumed_clauses_wl_def remove_all_learned_subsumed_clauses_def
      literals_are_ℒin'_def correct_watching'_nobin.simps state_wl_l_def all_init_learned_lits_simps_Q
    clause_to_update_def all_lits_of_mm_union blits_in_ℒin'_def)
  by (meson basic_trans_rules(31) in_all_learned_lits_of_wl_addUS)

lemma remove_one_annot_true_clause_imp_wl_remove_one_annot_true_clause_imp:
  (remove_one_annot_true_clause_imp_wl, remove_one_annot_true_clause_imp)
     {(S, T). (S, T)  state_wl_l None  correct_watching'_nobin S  literals_are_ℒin' S} f
      {(S, T). (S, T)  state_wl_l None  correct_watching'_nobin S  literals_are_ℒin' S}nres_rel
proof -
  show ?thesis
    unfolding remove_one_annot_true_clause_imp_wl_def remove_one_annot_true_clause_imp_def
      uncurry_def
    apply (intro frefI nres_relI)
    apply (refine_vcg
      WHILEIT_refine[where
         R = nat_rel ×f {(S, T).  (S, T)  state_wl_l None  correct_watching'_nobin S 
            literals_are_ℒin' S}]
      remove_one_annot_true_clause_one_imp_wl_remove_one_annot_true_clause_one_imp[THEN
        fref_to_Down_curry]
      remove_all_learned_subsumed_clauses_wl_remove_all_learned_subsumed_clauses[THEN
        fref_to_Down])
    subgoal by force
    subgoal by auto
    subgoal by force
    subgoal by force
    subgoal by force
    subgoal for x y k ka xa start start' x'
      unfolding remove_one_annot_true_clause_imp_wl_inv_def
      apply (subst case_prod_beta)
      apply (rule_tac x=y in exI)
      apply (rule_tac x=snd x' in exI)
      apply (subst (asm)(23) surjective_pairing)
      apply (subst (asm)(28) surjective_pairing)
      unfolding prod_rel_iff by simp
    subgoal by auto
    subgoal by auto
    subgoal for x y k ka xa start start' x'
      unfolding remove_one_annot_true_clause_imp_wl_inv_def
      apply (subst case_prod_beta)
      apply (rule_tac x=y in exI)
      apply (rule_tac x=snd x' in exI)
      apply (subst (asm)(23) surjective_pairing)
      apply (subst (asm)(28) surjective_pairing)
      unfolding prod_rel_iff by simp
    subgoal by auto
    done
qed

definition collect_valid_indices_wl :: 'v twl_st_wl  nat list nres where
  collect_valid_indices_wl S = SPEC (λN. True)

definition mark_to_delete_clauses_wl_inv
  :: 'v twl_st_wl  nat list  nat × 'v twl_st_wl× nat list   bool
where
  mark_to_delete_clauses_wl_inv = (λS xs0 (i, T, xs).
     S' T'. (S, S')  state_wl_l None  (T, T')  state_wl_l None 
      mark_to_delete_clauses_l_inv S' xs0 (i, T', xs) 
      correct_watching' S literals_are_ℒin' S  literals_are_ℒin' T)

definition mark_to_delete_clauses_wl_pre :: 'v twl_st_wl  bool
where
  mark_to_delete_clauses_wl_pre S 
   (T. (S, T)  state_wl_l None  mark_to_delete_clauses_l_pre T  literals_are_ℒin' S)

definition mark_garbage_wl:: nat  'v twl_st_wl  'v twl_st_wl  where
  mark_garbage_wl = (λC (M, N, D, NE, UE, NEk, UEk, NS, US, N0, U0, WS, Q).
    (M, fmdrop C N, D, NE, {#}, NEk, UEk, NS, {#}, N0, {#}, WS, Q))

definition mark_to_delete_clauses_wl :: 'v twl_st_wl  'v twl_st_wl nres where
mark_to_delete_clauses_wl  = (λS. do {
    ASSERT(mark_to_delete_clauses_wl_pre S);
    xs  collect_valid_indices_wl S;
    l  SPEC(λ_:: nat. True);
    (_, S, _)  WHILETmark_to_delete_clauses_wl_inv S xs(λ(i, S, xs). i < length xs)
      (λ(i, T, xs). do {
        if(xs!i ∉# dom_m (get_clauses_wl T)) then RETURN (i, T, delete_index_and_swap xs i)
        else do {
          ASSERT(0 < length (get_clauses_wl T(xs!i)));
	  ASSERT (get_clauses_wl T  (xs ! i) ! 0 ∈# all (all_init_atms_st T));
          can_del  SPEC(λb. b 
             (Propagated (get_clauses_wl T(xs!i)!0) (xs!i)  set (get_trail_wl T)) 
              ¬irred (get_clauses_wl T) (xs!i)  length (get_clauses_wl T  (xs!i))  2);
          ASSERT(i < length xs);
          if can_del
          then
            RETURN (i, mark_garbage_wl (xs!i) T, delete_index_and_swap xs i)
          else
            RETURN (i+1, T, xs)
       }
      })
      (l, S, xs);
    remove_all_learned_subsumed_clauses_wl S
  })

lemma mark_to_delete_clauses_wl_invD1:
  assumes mark_to_delete_clauses_wl_inv S xs (i, T, ys) and
    C ∈# dom_m (get_clauses_wl T) and
    0 < length (get_clauses_wl T  C)
  shows
    get_clauses_wl T  C ! 0 ∈# all (all_init_atms_st T)
proof -
  have literals_are_ℒin' T
    using assms unfolding mark_to_delete_clauses_wl_inv_def by blast
  then have get_clauses_wl T  C ! 0 ∈# all_init_lits_of_wl T
    using nth_in_all_lits_stI[of C T 0]
    using assms(2,3) by (auto simp del: nth_in_all_lits_stI
      simp: all_lits_st_init_learned  literals_are_ℒin'_def)
  then show ?thesis
    by (simp add: all_all_init_atms)
qed

lemma remove_all_learned_subsumed_clauses_wl_remove_all_learned_subsumed_clauses2:
  (remove_all_learned_subsumed_clauses_wl, remove_all_learned_subsumed_clauses)
    {(S, T). (S, T)  state_wl_l None  correct_watching' S  literals_are_ℒin' S} f
      {(S, T). (S, T)  state_wl_l None  correct_watching' S  literals_are_ℒin' S}nres_rel
  by (auto intro!: frefI nres_relI
    simp: remove_all_learned_subsumed_clauses_wl_def remove_all_learned_subsumed_clauses_def
      literals_are_ℒin'_def correct_watching'.simps state_wl_l_def all_init_learned_lits_simps_Q
    clause_to_update_def all_lits_of_mm_union blits_in_ℒin'_def)
    (meson basic_trans_rules(31) in_all_learned_lits_of_wl_addUS)

lemma mark_to_delete_clauses_wl_mark_to_delete_clauses_l:
  (mark_to_delete_clauses_wl, mark_to_delete_clauses_l)
     {(S, T). (S, T)  state_wl_l None  correct_watching' S  literals_are_ℒin' S} f
      {(S, T). (S, T)  state_wl_l None  correct_watching' S  literals_are_ℒin' S}nres_rel
proof -
  have [refine0]: collect_valid_indices_wl S    Id  (collect_valid_indices S')
    if (S, S')  {(S, T).  (S, T)  state_wl_l None  correct_watching' S 
           mark_to_delete_clauses_wl_pre S}
    for S S'
    using that by (auto simp: collect_valid_indices_wl_def collect_valid_indices_def)
  have if_inv: (if A then RETURN P else RETURN Q) = RETURN (if A then P else Q) for A P Q
    by auto
  have Ball_range[simp]: (xrange f  range g. P x)(x. P (f x)  P (g x)) for P f g
    by auto
  show ?thesis
    unfolding mark_to_delete_clauses_wl_def mark_to_delete_clauses_l_def
      uncurry_def
    apply (intro frefI nres_relI)
    apply (refine_vcg
      WHILEIT_refine[where
         R = {((i, S, xs), (j, T, ys)). i = j  (S, T)  state_wl_l None  correct_watching' S 
             xs = ys  literals_are_ℒin' S}]
      remove_one_annot_true_clause_one_imp_wl_remove_one_annot_true_clause_one_imp[THEN
        fref_to_Down_curry]
      remove_all_learned_subsumed_clauses_wl_remove_all_learned_subsumed_clauses2[THEN
        fref_to_Down])
    subgoal unfolding mark_to_delete_clauses_wl_pre_def by blast
    subgoal by auto
    subgoal by (auto simp: state_wl_l_def)
    subgoal unfolding mark_to_delete_clauses_wl_inv_def by fast
    subgoal by auto
    subgoal by (force simp: state_wl_l_def)
    subgoal by auto
    subgoal by (force simp: state_wl_l_def)
    subgoal for x y xs xsa l to_keep xa x' x1 x2 x1a x2a x1b x2b x1c x2c
      by (auto simp: mark_to_delete_clauses_wl_invD1)
    subgoal by (auto simp: state_wl_l_def can_delete_def)
    subgoal by auto
    subgoal by (force simp: state_wl_l_def)
    subgoal
      by (auto simp: state_wl_l_def correct_watching_fmdrop mark_garbage_wl_def
          mark_garbage_l_def ac_simps
        split: prod.splits)
    subgoal by (auto simp: state_wl_l_def)
    subgoal by (auto simp: state_wl_l_def)
    done
qed

text 
  This is only a specification and must be implemented. There are two ways to do so:
   clean the watch lists and then iterate over all clauses to rebuild them.
   iterate over the watch list and check whether the clause index is in the domain or not.

  It is not clear which is faster (but option 1 requires only 1 memory access per clause instead of
  two). The first option is implemented in SPASS-SAT. The latter version (partly) in cadical.

definition rewatch_clauses :: 'v twl_st_wl  'v twl_st_wl nres where
  rewatch_clauses = (λ(M, N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W).
  SPEC(λ(M', N', D', NE', UE',  NEk', UEk', NS', US', N0', U0', Q', W').
     (M, N, D, NE, UE,  NEk, UEk, NS, US, N0, U0, Q) = (M', N', D', NE', UE', NEk', UEk', NS', US', N0', U0', Q') 
    correct_watching (M, N', D, NE, UE, NEk', UEk', NS', US', N0', U0', Q, W')))

definition mark_to_delete_clauses_wl_post where
  mark_to_delete_clauses_wl_post S T 
     (S' T'. (S, S')  state_wl_l None  (T, T')  state_wl_l None  blits_in_ℒin S 
       mark_to_delete_clauses_l_post S' T'  correct_watching S  blits_in_ℒin T 
       correct_watching T  get_unkept_learned_clss_wl T = {#}  
       get_subsumed_learned_clauses_wl T = {#}  get_learned_clauses0_wl T = {#})

definition cdcl_twl_full_restart_wl_prog :: 'v twl_st_wl  'v twl_st_wl nres where
cdcl_twl_full_restart_wl_prog S = do {
    ASSERT(mark_to_delete_clauses_wl_pre S);
    T  mark_to_delete_clauses_wl S;
    ASSERT(mark_to_delete_clauses_wl_post S T);
    RETURN T
  }


lemma correct_watching_correct_watching: correct_watching S  correct_watching' S
  by (cases S, auto simp only: correct_watching.simps correct_watching'.simps all_lits_st_init_learned
    image_mset_union)

lemma (in -) [twl_st_l, simp]:
 (Sa, x)  twl_st_l None  get_all_learned_clss x =  mset `# (get_learned_clss_l Sa) + get_unit_learned_clss_l Sa + get_subsumed_learned_clauses_l Sa + get_learned_clauses0_l Sa
  by (cases Sa; cases x) (auto simp: twl_st_l_def get_learned_clss_l_def mset_take_mset_drop_mset')

lemma cdcl_twl_full_restart_wl_prog_final_rel:
  assumes
    S_Sa: (S, Sa)  {(S, T). (S, T)  state_wl_l None  correct_watching' S  blits_in_ℒin S} and
    pre_Sa: mark_to_delete_clauses_l_pre Sa and
    pre_S: mark_to_delete_clauses_wl_pre S and
    T_Ta: (T, Ta)  {(S, T). (S, T)  state_wl_l None  correct_watching' S  literals_are_ℒin' S} and
    pre_l: mark_to_delete_clauses_l_post Sa Ta
  shows mark_to_delete_clauses_wl_post S T
proof -
  obtain x where
    Sa_x: (Sa, x)  twl_st_l None and
    st: remove_one_annot_true_clause** Sa Ta and
    list_invs: twl_list_invs Sa and
    struct: twl_struct_invs x and
    confl: get_conflict_l Sa = None and
    upd: clauses_to_update_l Sa = {#} and
    empty:
       get_unkept_learned_clss_l Ta = {#}
      get_subsumed_learned_clauses_l Ta = {#}
      get_learned_clauses0_l Ta = {#}
    using pre_l
    unfolding mark_to_delete_clauses_l_post_def by blast

  have corr_S: correct_watching' S and corr_T: correct_watching' T and
    blits_S: blits_in_ℒin S and
    blits_T: literals_are_ℒin' T and
    S_Sa: (S, Sa)  state_wl_l None and
    T_Ta: (T, Ta)  state_wl_l None
    using S_Sa T_Ta by auto

  have set_mset (all_init_lits_of_wl S) = set_mset (all_lits_st S)
    using literals_are_ℒin'_literals_are_ℒin_iff(4)[OF S_Sa Sa_x struct] .

  then have corr_S': correct_watching S
    using corr_S
    by (cases S; simp only: correct_watching'.simps correct_watching.simps)
  obtain y where
    cdcl_twl_restart_l** Sa Ta and
    Ta_y: (Ta, y)  twl_st_l None  and
    cdcl_twl_restart** x y and
    struct: twl_struct_invs y
    using rtranclp_remove_one_annot_true_clause_cdcl_twl_restart_l2[OF st list_invs confl upd Sa_x
      struct]
    by blast

  have eq: set_mset (all_init_lits_of_wl T) = set_mset (all_lits_st T)
    using literals_are_ℒin'_literals_are_ℒin_iff(4)[OF T_Ta Ta_y struct] .

  then have corr_T': correct_watching T
    using corr_T
    by (cases T; simp only: correct_watching'.simps correct_watching.simps)

  have blits_in_ℒin T
    using blits_T eq
    unfolding blits_in_ℒin_def blits_in_ℒin'_def all_lits_def literals_are_ℒin'_def
       all_init_lits_def
    by (auto dest: multi_member_split simp: ac_simps)
  moreover have get_unkept_learned_clss_wl T = {#} 
    get_subsumed_learned_clauses_wl T = {#} 
    get_learned_clauses0_wl T = {#}
    using empty T_Ta by simp
   ultimately show ?thesis
    using S_Sa T_Ta corr_T' corr_S' pre_l blits_S
    unfolding mark_to_delete_clauses_wl_post_def
    by blast
qed

lemma cdcl_twl_full_restart_wl_prog_final_rel':
  assumes
    S_Sa: (S, Sa)  {(S, T). (S, T)  state_wl_l None  correct_watching S  blits_in_ℒin S} and
    pre_Sa: mark_to_delete_clauses_l_pre Sa and
    pre_S: mark_to_delete_clauses_wl_pre S and
    T_Ta: (T, Ta)  {(S, T). (S, T)  state_wl_l None  correct_watching' S  literals_are_ℒin' S} and
    pre_l: mark_to_delete_clauses_l_post Sa Ta
  shows mark_to_delete_clauses_wl_post S T
proof -
  obtain x where
    Sa_x: (Sa, x)  twl_st_l None and
    st: remove_one_annot_true_clause** Sa Ta and
    list_invs: twl_list_invs Sa and
    struct: twl_struct_invs x and
    confl: get_conflict_l Sa = None and
    upd: clauses_to_update_l Sa = {#} and
    empty:
       get_unkept_learned_clss_l Ta = {#}
      get_subsumed_learned_clauses_l Ta = {#}
      get_learned_clauses0_l Ta = {#}
    using pre_l
    unfolding mark_to_delete_clauses_l_post_def by blast

  have corr_S: correct_watching S and corr_T: correct_watching' T and
    blits_T: literals_are_ℒin' T and
    blits_S: blits_in_ℒin S and
    S_Sa: (S, Sa)  state_wl_l None and
    T_Ta: (T, Ta)  state_wl_l None
    using S_Sa T_Ta by auto
  have corr_S: correct_watching' S
    using correct_watching_correct_watching[OF corr_S] .
  have set_mset (all_init_lits_of_wl S) = set_mset (all_lits_st S)
    using literals_are_ℒin'_literals_are_ℒin_iff(4)[OF S_Sa Sa_x struct] .
  then have corr_S': correct_watching S
    using corr_S
    by (cases S; simp only: correct_watching'.simps correct_watching.simps)
  obtain y where
    cdcl_twl_restart_l** Sa Ta and
    Ta_y: (Ta, y)  twl_st_l None  and
    cdcl_twl_restart** x y and
    struct: twl_struct_invs y
    using rtranclp_remove_one_annot_true_clause_cdcl_twl_restart_l2[OF st list_invs confl upd Sa_x
      struct]
    by blast


  have eq: set_mset (all_init_lits_of_wl T) = set_mset (all_lits_st T)
    using literals_are_ℒin'_literals_are_ℒin_iff(4)[OF T_Ta Ta_y struct] .

  then have corr_T': correct_watching T
    using corr_T
    by (cases T; simp only: correct_watching'.simps correct_watching.simps)

  have blits_in_ℒin T
    using blits_T eq
    unfolding blits_in_ℒin_def blits_in_ℒin'_def all_lits_def literals_are_ℒin'_def
         all_init_lits_def
    by (auto dest: multi_member_split simp: ac_simps)
  moreover have get_unkept_learned_clss_wl T = {#} 
    get_subsumed_learned_clauses_wl T = {#} 
    get_learned_clauses0_wl T = {#}
    using empty T_Ta by simp
  ultimately show ?thesis
    using S_Sa T_Ta corr_T' corr_S' pre_l blits_S
    unfolding mark_to_delete_clauses_wl_post_def apply -
    apply (rule exI[of _ Sa])
    apply (rule exI[of _ Ta])
    by blast
qed


lemma mark_to_delete_clauses_l_pre_blits_in_ℒin':
  assumes
    S_Sa: (S, Sa)  {(S, T). (S, T)  state_wl_l None  correct_watching S  blits_in_ℒin S} and
    pre_Sa: mark_to_delete_clauses_l_pre Sa
  shows literals_are_ℒin' S
proof -
  obtain x where
    Sa_x: (Sa, x)  twl_st_l None and
    list_invs: twl_list_invs Sa and
    struct: twl_struct_invs x
    using pre_Sa
    unfolding mark_to_delete_clauses_l_pre_def by blast

  have corr_S: correct_watching S and
    blits_S: blits_in_ℒin S and
    S_Sa: (S, Sa)  state_wl_l None
    using S_Sa by auto
  have corr_S: correct_watching' S
    using correct_watching_correct_watching[OF corr_S] .
  have eq: set_mset (all_init_lits_of_wl S) = set_mset (all_lits_st S)
    using literals_are_ℒin'_literals_are_ℒin_iff(4)[OF S_Sa Sa_x struct] .

  then have corr_S': correct_watching S
    using corr_S
    by (cases S; simp only: correct_watching'.simps correct_watching.simps)

  have literals_are_ℒin' S
    using blits_S eq
    unfolding blits_in_ℒin_def blits_in_ℒin'_def all_lits_def literals_are_ℒin'_def
      all_init_lits_def all_lits_st_init_learned[of S] by auto
  then show ?thesis
    using S_Sa corr_S' blits_S
    unfolding mark_to_delete_clauses_wl_post_def
    by blast
qed

lemma cdcl_twl_full_restart_wl_prog_cdcl_full_twl_restart_l_prog:
  (cdcl_twl_full_restart_wl_prog, cdcl_twl_full_restart_l_prog)
     {(S, T). (S, T)  state_wl_l None  correct_watching S  blits_in_ℒin S} f
      {(S, T). (S, T)  state_wl_l None  correct_watching S  blits_in_ℒin S}nres_rel
  unfolding cdcl_twl_full_restart_wl_prog_def cdcl_twl_full_restart_l_prog_def
    rewatch_clauses_def
  apply (intro frefI nres_relI)
  apply (refine_vcg
     mark_to_delete_clauses_wl_mark_to_delete_clauses_l[THEN fref_to_Down]
     remove_one_annot_true_clause_imp_wl_remove_one_annot_true_clause_imp[THEN fref_to_Down])
  subgoal unfolding mark_to_delete_clauses_wl_pre_def
   by (blast intro: correct_watching_correct_watching mark_to_delete_clauses_l_pre_blits_in_ℒin')
  subgoal unfolding mark_to_delete_clauses_wl_pre_def by (blast intro: correct_watching_correct_watching)
  subgoal
    by (rule cdcl_twl_full_restart_wl_prog_final_rel')
  subgoal by (auto simp: state_wl_l_def mark_to_delete_clauses_wl_post_def)
  done


datatype restart_type =
  NO_RESTART |
  GC |
  RESTART |
  INPROCESS

context twl_restart_ops
begin

definition (in twl_restart_ops) restart_required_wl  :: 'v twl_st_wl  nat  nat  nat  restart_type nres where
restart_required_wl S last_GC last_Restart n =  do {
  ASSERT(size (get_all_learned_clss_wl S)  last_GC);
  ASSERT(size (get_all_learned_clss_wl S)  last_Restart);
  SPEC (λb.
  (b = GC  f n < size (get_all_learned_clss_wl S) - last_GC) 
  (b = INPROCESS  f n < size (get_all_learned_clss_wl S) - last_GC) 
  (b = RESTART  last_Restart < size (get_all_learned_clss_wl S)))}

definition (in twl_restart_ops) cdcl_twl_stgy_restart_abs_wl_inv
   :: 'v twl_st_wl  bool × 'v twl_st_wl × nat × nat × nat  bool where
  cdcl_twl_stgy_restart_abs_wl_inv S0 = (λ(brk, T, last_GC, last_Restart, n).
    (S0' T'.
       (S0, S0')  state_wl_l None 
       (T, T')  state_wl_l None 
       cdcl_twl_stgy_restart_abs_l_inv S0' (brk, T', last_GC, last_Restart, n) 
       (¬brk  correct_watching T)))
end


definition (in -) cdcl_GC_clauses_pre_wl :: 'v twl_st_wl  bool where
cdcl_GC_clauses_pre_wl S  (
  T. (S, T)  state_wl_l None 
    no_lost_clause_in_WL S 
    literals_are_ℒin' S 
    cdcl_GC_clauses_pre T
  )

definition cdcl_GC_clauses_wl :: 'v twl_st_wl  'v twl_st_wl nres where
cdcl_GC_clauses_wl = (λ(M, N, D, NE, UE, NEk, UEk, NS, US, N0, U0, WS, Q). do {
  ASSERT(cdcl_GC_clauses_pre_wl (M, N, D, NE, UE, NEk, UEk, NS, US, N0, U0, WS, Q));
  let b = True;
  if b then do {
    (N', _)  SPEC (λ(N'', m). GC_remap** (N, Map.empty, fmempty) (fmempty, m, N'') 
      0 ∉# dom_m N'');
    Q  SPEC(λQ. correct_watching' (M, N', D, NE, UE, NEk, UEk, NS, US, N0, U0, WS, Q) literals_are_ℒin' (M, N', D, NE, UE, NEk, UEk, NS, US, N0, U0, WS, Q));
    RETURN (M, N', D, NE, {#}, NEk, UEk, NS, {#}, N0, {#}, WS, Q)
  }
  else RETURN (M, N, D, NE, {#}, NEk, UEk, NS, {#}, N0, {#}, WS, Q)})

lemma cdcl_GC_clauses_wl_cdcl_GC_clauses:
  (cdcl_GC_clauses_wl, cdcl_GC_clauses)  {(S::'v twl_st_wl, S').
       (S, S')  state_wl_l None  no_lost_clause_in_WL S  literals_are_ℒin' S} f {(S::'v twl_st_wl, S').
  (S, S')  state_wl_l None  correct_watching' S  literals_are_ℒin' S 
    get_unkept_learned_clss_wl S = {#} 
    get_subsumed_learned_clauses_wl S = {#} 
    get_learned_clauses0_wl S = {#}}nres_rel
  unfolding cdcl_GC_clauses_wl_def cdcl_GC_clauses_def
  apply (intro frefI nres_relI)
  apply refine_vcg
  subgoal unfolding cdcl_GC_clauses_pre_wl_def by blast
  subgoal by (auto simp: state_wl_l_def)
  subgoal by (auto simp: state_wl_l_def)
  subgoal by auto
  subgoal for x y x1 x2 x1a x2a x1b x2b x1c x2c x1d x2d x1e x2e x1f x2f x1g x2g x1h
       x2h x1i x2i x1j x2j x1k x2k b xa x' x1l x2l x1m x2m Q
    by (auto simp: state_wl_l_def blits_in_ℒin'_def literals_are_ℒin'_empty
      dest: literals_are_ℒin'_empty(6-))
  subgoal by auto
  done

definition mark_to_delete_clauses_GC_wl_inv
  :: 'v twl_st_wl  nat list  nat × 'v twl_st_wl× nat list   bool
where
  mark_to_delete_clauses_GC_wl_inv = (λS xs0 (i, T, xs).
     S' T'. (S, S')  state_wl_l None  (T, T')  state_wl_l None 
      mark_to_delete_clauses_l_inv S' xs0 (i, T', xs) 
      no_lost_clause_in_WL S  literals_are_ℒin' S  literals_are_ℒin' T)

lemma mark_to_delete_clauses_GC_wl_inv_alt_def:
  mark_to_delete_clauses_GC_wl_inv = (λS xs0 (i, T, xs).
     S' T'. (S, S')  state_wl_l None  (T, T')  state_wl_l None 
     mark_to_delete_clauses_l_inv S' xs0 (i, T', xs) 
     set (get_all_mark_of_propagated (get_trail_wl T))  set (get_all_mark_of_propagated (get_trail_wl S))  {0}  
      no_lost_clause_in_WL S  literals_are_ℒin' S  literals_are_ℒin' T)
   unfolding mark_to_delete_clauses_GC_wl_inv_def case_prod_beta
   apply (intro  impI iffI allI ext; normalize_goal+)
   subgoal for S xs0 p x xa
     by (rule_tac x=x in exI, rule_tac x=xa in exI)
      (auto simp: mark_to_delete_clauses_l_inv_def
       dest!: rtranclp_remove_one_annot_true_clause_get_all_mark_of_propagated)
   subgoal for S xs0 p x xa
     by (rule_tac x=x in exI, rule_tac x=xa in exI) auto
   done

definition mark_to_delete_clauses_GC_wl_pre :: 'v twl_st_wl  bool
  where
  mark_to_delete_clauses_GC_wl_pre S 
  (T. (S, T)  state_wl_l None  mark_to_delete_clauses_l_GC_pre T 
    literals_are_ℒin' S)

lemma mark_to_delete_clause_GC_wl_pre_alt_def:
  mark_to_delete_clauses_GC_wl_pre S 
  (T. (S, T)  state_wl_l None  mark_to_delete_clauses_l_GC_pre T 
    literals_are_ℒin' S   set (get_all_mark_of_propagated (get_trail_wl S))  {0})
  unfolding mark_to_delete_clauses_GC_wl_pre_def
  apply (rule iffI impI conjI; normalize_goal+)
  subgoal for T
    by (rule exI[of _ T]) (auto simp: mark_to_delete_clauses_l_GC_pre_def)
  subgoal for T
    by (rule exI[of _ T]) (auto simp: mark_to_delete_clauses_l_GC_pre_def)
  done

text 
  Unlike the @{thm[source] mark_to_delete_clauses_wl_def}, this version is only used for garbage
  collection. Hence, there are a few differences.

definition mark_to_delete_clauses_GC_wl :: 'v twl_st_wl  'v twl_st_wl nres where
mark_to_delete_clauses_GC_wl = (λS. do {
    ASSERT(mark_to_delete_clauses_GC_wl_pre S);
    xs  collect_valid_indices_wl S;
    l  SPEC(λ_:: nat. True);
    (_, S, _)  WHILETmark_to_delete_clauses_GC_wl_inv S xs(λ(i, S, xs). i < length xs)
      (λ(i, T, xs). do {
        if(xs!i ∉# dom_m (get_clauses_wl T)) then RETURN (i, T, delete_index_and_swap xs i)
        else do {
          ASSERT(0 < length (get_clauses_wl T(xs!i)));
	  ASSERT (get_clauses_wl T  (xs ! i) ! 0 ∈# all (all_init_atms_st T));
          can_del  SPEC(λb. b 
              ¬irred (get_clauses_wl T) (xs!i)  length (get_clauses_wl T  (xs!i))  2);
          ASSERT(i < length xs);
          if can_del
          then
            RETURN (i, mark_garbage_wl (xs!i) T, delete_index_and_swap xs i)
          else
            RETURN (i+1, T, xs)
       }
      })
      (l, S, xs);
    remove_all_learned_subsumed_clauses_wl S
  })

lemma mark_to_delete_clauses_GC_wl_invD1:
  assumes mark_to_delete_clauses_GC_wl_inv S xs (i, T, ys) and
    C ∈# dom_m (get_clauses_wl T) and
    0 < length (get_clauses_wl T  C)
  shows
    get_clauses_wl T  C ! 0 ∈# all (all_init_atms_st T)
proof -
  have get_clauses_wl T  C ! 0 ∈# all_lits_st T
    using assms(2,3) by auto
  moreover have literals_are_ℒin' T
    using assms unfolding mark_to_delete_clauses_GC_wl_inv_def by blast
  ultimately show ?thesis
    unfolding all_lits_st_init_learned all_all_init_atms literals_are_ℒin'_def
    by auto
qed

lemma no_lost_clause_in_WL_drop_irrel[simp]:
  ¬irred a C 
  no_lost_clause_in_WL (x1d, a, aa, ab, ac, NEk, UEk, ad, US, af, ag, ah, b) 
  no_lost_clause_in_WL (x1d, fmdrop C a, aa, ab, {#}, NEk, UEk, ad, {#}, af, {#}, ah, b)
  by (auto simp: no_lost_clause_in_WL_def all_init_lits_of_wl_def
    dest: in_diffD)

lemma literals_are_ℒin'_drop_irrel:
  assumes
    irred: ¬ irred N C and
    literals_are_ℒin'  (M', N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W)
  shows
    literals_are_ℒin'  (M, fmdrop C N, D, NE, {#}, NEk, UEk, NS, {#}, N0, {#}, Q, W)
  using assms
  by (cases C ∈# dom_m N)
    (auto simp: literals_are_ℒin'_def blits_in_ℒin'_def
      all_learned_lits_of_wl_def image_mset_remove1_mset_if all_lits_of_mm_union
      all_init_lits_of_wl_def learned_clss_l_l_fmdrop ran_m_fmdrop_notin
      split: if_splits
      dest!: all_lits_of_mm_diffD)

lemma remove_all_learned_subsumed_clauses_wl_remove_all_learned_subsumed_clauses3:
  (remove_all_learned_subsumed_clauses_wl, remove_all_learned_subsumed_clauses)
   {(S, T). (S, T)  state_wl_l None  no_lost_clause_in_WL S  literals_are_ℒin' S} f
  {(S, T). (S, T)  state_wl_l None  no_lost_clause_in_WL S  literals_are_ℒin' S}nres_rel
  by (auto intro!: frefI nres_relI
    simp: remove_all_learned_subsumed_clauses_wl_def remove_all_learned_subsumed_clauses_def
    literals_are_ℒin'_def correct_watching'.simps state_wl_l_def
    all_init_lits_of_wl_def all_learned_lits_of_wl_def
    no_lost_clause_in_WL_def
    clause_to_update_def all_lits_of_mm_union blits_in_ℒin'_def)

lemma mark_to_delete_clauses_wl_mark_to_delete_clauses_l2:
  (mark_to_delete_clauses_GC_wl, mark_to_delete_clauses_l)
   {(S, T). (S, T)  state_wl_l None  no_lost_clause_in_WL S  literals_are_ℒin' S 
    set (get_all_mark_of_propagated (get_trail_wl S))  {0}} f
  {(S, T). (S, T)  state_wl_l None  no_lost_clause_in_WL S  literals_are_ℒin' S}nres_rel
proof -
  have [refine0]: collect_valid_indices_wl S    Id (collect_valid_indices S')
    if (S, S')  {(S, T).  (S, T)  state_wl_l None  no_lost_clause_in_WL S 
           mark_to_delete_clauses_GC_wl_pre S}
    for S S'
    using that by (auto simp: collect_valid_indices_wl_def collect_valid_indices_def)
  have if_inv: (if A then RETURN P else RETURN Q) = RETURN (if A then P else Q) for A P Q
    by auto
  have Ball_range[simp]: (xrange f  range g. P x)(x. P (f x)  P (g x)) for P f g
    by auto
  show ?thesis
    unfolding mark_to_delete_clauses_GC_wl_def mark_to_delete_clauses_l_def
      uncurry_def
    apply (intro frefI nres_relI)
    apply (refine_vcg
      WHILEIT_refine[where
      R = {((i, S, xs), (j, T, ys)). i = j  (S, T)  state_wl_l None  no_lost_clause_in_WL S 
             xs = ys  literals_are_ℒin' S}]
      remove_one_annot_true_clause_one_imp_wl_remove_one_annot_true_clause_one_imp[THEN fref_to_Down_curry]
      remove_all_learned_subsumed_clauses_wl_remove_all_learned_subsumed_clauses3[THEN fref_to_Down])
    subgoal for x y
      unfolding mark_to_delete_clauses_GC_wl_pre_def mark_to_delete_clauses_l_GC_pre_def
        mark_to_delete_clauses_l_pre_def
      apply normalize_goal+
      apply (rule_tac x=y in exI)
      by fastforce
    subgoal by auto
    subgoal by (auto simp: state_wl_l_def)
    subgoal unfolding mark_to_delete_clauses_GC_wl_inv_def by fast
    subgoal by auto
    subgoal by (force simp: state_wl_l_def)
    subgoal by auto
    subgoal by (force simp: state_wl_l_def)
    subgoal for x y xs xsa l to_keep xa x' x1 x2 x1a x2a x1b x2b x1c x2c
      by (auto simp: mark_to_delete_clauses_GC_wl_invD1)
    subgoal by (auto simp: state_wl_l_def can_delete_def
      mark_to_delete_clauses_GC_wl_inv_alt_def
      dest!: split_list)
    subgoal by auto
    subgoal by (force simp: state_wl_l_def)
    subgoal
      by (auto simp: state_wl_l_def correct_watching_fmdrop mark_garbage_wl_def
          mark_garbage_l_def
        literals_are_ℒin'_drop_irrel
        split: prod.splits)
    subgoal by (auto simp: state_wl_l_def)
    subgoal by (auto simp: ac_simps)
    done
qed

lemma correct_watching'_nobin_clauses_pointed_to:
  assumes
    xa_xb: (xa, xb)  state_wl_l None and
    corr: correct_watching'_nobin xa and
    pre: cdcl_GC_clauses_pre xb and
    L: literals_are_ℒin' xa
  shows set_mset (dom_m (get_clauses_wl xa))
          clauses_pointed_to
            (Neg ` set_mset (all_init_atms_st xa) 
             Pos ` set_mset (all_init_atms_st xa))
            (get_watched_wl xa)
        (is ?G1 is _  ?A) and
    no_lost_clause_in_WL xa (is ?G2)
proof -
  let ?𝒜 = all_init_atms (get_clauses_wl xa) (get_unit_init_clss_wl xa)
  show ?G1
  proof
    fix C
    assume C: C ∈# dom_m (get_clauses_wl xa)
    obtain M N D NE UE NEk UEk NS US N0 U0 Q W where
      xa: xa = (M, N, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, W)
      by (cases xa)
    obtain x where
      xb_x: (xb, x)  twl_st_l None and
      twl_list_invs xb and
      struct_invs: twl_struct_invs x and
      get_conflict_l xb = None and
      clauses_to_update_l xb = {#} and
      count_decided (get_trail_l xb) = 0 and
      Lset (get_trail_l xb). mark_of L = 0
      using pre unfolding cdcl_GC_clauses_pre_def by fast
    have twl_st_inv x
      using xb_x C struct_invs
      by (auto simp: twl_struct_invs_def
        cdclW_restart_mset.cdclW_all_struct_inv_def)
    then have le0: get_clauses_wl xa  C  []
      using xb_x C xa_xb
      by (cases x; cases irred N C)
        (auto simp: twl_struct_invs_def twl_st_inv.simps
          twl_st_l_def state_wl_l_def xa ran_m_def conj_disj_distribR
          Collect_disj_eq Collect_conv_if
        dest!: multi_member_split)
    then have le: N  C ! 0  set (watched_l (N  C))
      by (cases N  C) (auto simp: xa)
    have eq: set_mset (all (all_init_atms N NE)) =
          set_mset (all_lits_of_mm (mset `# init_clss_lf N + NE))
       by (auto simp del: all_init_atms_def[symmetric]
          simp: all_init_atms_def xa all_atm_of_all_lits_of_mm[symmetric]
            all_init_lits_def)

    have H: get_clauses_wl xa  C ! 0 ∈# all_init_lits_of_wl xa
      using L C le0 apply -
      unfolding all_init_atms_def[symmetric] all_init_lits_def[symmetric]
      apply (subst literals_are_ℒin'_literals_are_ℒin_iff(4)[OF xa_xb xb_x struct_invs])
      apply (cases N  C; auto simp: literals_are_ℒin_def all_lits_def ran_m_def eq
            all_lits_of_mm_add_mset is_ℒall_def xa all_lits_of_m_add_mset
            all_all_atms_all_lits all_lits_st_def
          dest!: multi_member_split)
      done
    moreover {
      have {#i ∈# fst `# mset (W (N  C ! 0)). i ∈# dom_m N#} =
             add_mset C {#Ca ∈# remove1_mset C (dom_m N). N  C ! 0  set (watched_l (N  Ca))#}
        using corr H C le unfolding xa
        by (auto simp: clauses_pointed_to_def correct_watching'_nobin.simps xa
          simp flip: all_init_atms_def all_init_lits_def all_init_atms_alt_def
            all_init_lits_alt_def
          simp: clause_to_update_def
          simp del: all_init_atms_def[symmetric]
          dest!: multi_member_split)
      from arg_cong[OF this, of set_mset] have C  fst ` set (W (N  C ! 0))
        using corr H C le unfolding xa
        by (auto simp: clauses_pointed_to_def correct_watching'.simps xa
          simp: all_init_atms_def all_init_lits_def clause_to_update_def
          simp del: all_init_atms_def[symmetric]
          dest!: multi_member_split) }
    ultimately show C  ?A
      by (cases N  C ! 0)
        (auto simp: clauses_pointed_to_def correct_watching'.simps xa
          simp flip: all_init_lits_def all_init_atms_alt_def
            all_init_lits_alt_def 
          simp: clause_to_update_def all_init_atms_st_def all_init_lits_of_wl_def all_init_atms_def
          simp del: all_init_atms_def[symmetric]
        dest!: multi_member_split)
  qed
  moreover have set_mset (all_init_lits_of_wl xa) =
    Neg ` set_mset (all_init_atms_st xa)  Pos ` set_mset (all_init_atms_st xa)
    unfolding all_init_lits_of_wl_def
      all_lits_of_mm_def all_init_atms_st_def all_init_atms_def
    by (auto simp: all_init_atms_def all_init_lits_def all_lits_of_mm_def image_image
      image_Un
      simp del: all_init_atms_def[symmetric])
  moreover have distinct_watched (watched_by xa (Pos L))
    distinct_watched (watched_by xa (Neg L))
    if L ∈# all_init_atms_st xa for L
    using that corr
    by (cases xa;
      auto simp: correct_watching'_nobin.simps all_init_lits_of_wl_def all_init_atms_def
      all_lits_of_mm_union all_init_lits_def all_init_atms_st_def literal.atm_of_def
      in_all_lits_of_mm_uminus_iff[symmetric, of Pos _]
      simp del: all_init_atms_def[symmetric]
      split: literal.splits; fail)+
  ultimately show ?G2
    unfolding no_lost_clause_in_WL_def
    by (auto simp del: all_init_atms_def[symmetric]) 
qed

definition cdcl_GC_clauses_prog_copy_wl_entry
  :: 'v clauses_l  'v watched  'v literal 
  'v clauses_l  ('v clauses_l × 'v clauses_l) nres
  where
  cdcl_GC_clauses_prog_copy_wl_entry = (λN W A N'. do {
    let le = length W;
    (i, N, N')  WHILET
      (λ(i, N, N'). i < le)
      (λ(i, N, N'). do {
        ASSERT(i < length W);
        let C = fst (W ! i);
        if C ∈# dom_m N then do {
           D  SPEC(λD. D ∉# dom_m N'  D  0);
           RETURN (i+1, fmdrop C N, fmupd D (N  C, irred N C) N')
        } else RETURN (i+1, N, N')
       }) (0, N, N');
    RETURN (N, N')
   })
 
lemma cdcl_GC_clauses_prog_copy_wl_entry:
  fixes A :: 'v literal and WS :: 'v literal  'v watched
  defines [simp]: W  WS A
  assumes ran m0  set_mset (dom_m N0') 
	  (Ldom m0. L ∉# (dom_m N0)) 
	  set_mset (dom_m N0)  clauses_pointed_to (set_mset 𝒜) WS 
          0 ∉# dom_m N0'
  shows
    cdcl_GC_clauses_prog_copy_wl_entry N0 W A N0' 
      SPEC(λ(N, N'). (m. GC_remap** (N0, m0, N0') (N, m, N') 
	  ran m  set_mset (dom_m N') 
	  (Ldom m. L ∉# (dom_m N)) 
	  set_mset (dom_m N)  clauses_pointed_to (set_mset (remove1_mset A 𝒜)) WS) 
	  (L  set W. fst L ∉# dom_m N) 
          0 ∉# dom_m N')
proof -
  have [simp]:
    x ∈# remove1_mset a (dom_m aaa)  x  a  x ∈# dom_m aaa for x a aaa
    using distinct_mset_dom[of aaa]
    by (cases a ∈# dom_m aaa)
      (auto dest!: multi_member_split simp: add_mset_eq_add_mset)

  show ?thesis
    unfolding cdcl_GC_clauses_prog_copy_wl_entry_def
    apply (refine_vcg
      WHILET_rule[where I = λ(i, N, N'). m. GC_remap** (N0, m0, N0') (N, m, N') 
	  ran m  set_mset (dom_m N') 
	  (Ldom m. L ∉# (dom_m N)) 
	  set_mset (dom_m N)  clauses_pointed_to (set_mset (remove1_mset A 𝒜)) WS 
	    (fst) ` set (drop i W) 
	  (L  set (take i W). fst L ∉# dom_m N) 
          0 ∉# dom_m N' and
	R = measure (λ(i, N, N'). length W -i)])
    subgoal by auto
    subgoal
      using assms
      by (cases A ∈# 𝒜) (auto dest!: multi_member_split)
    subgoal by auto
    subgoal for s aa ba aaa baa x x1 x2 x1a x2a
      apply clarify
      apply (subgoal_tac (m'. GC_remap (aaa, m, baa) (fmdrop (fst (W ! aa)) aaa, m',
		fmupd x (the (fmlookup aaa (fst (W ! aa)))) baa) 
	  ran m'  set_mset (dom_m (fmupd x (the (fmlookup aaa (fst (W ! aa)))) baa)) 
    (Ldom m'. L ∉# (dom_m (fmdrop (fst (W ! aa)) aaa)))) 
	  set_mset (dom_m (fmdrop (fst (W ! aa)) aaa)) 
	    clauses_pointed_to (set_mset (remove1_mset A 𝒜)) WS 
	     fst ` set (drop (Suc aa) W) 
	  (L  set (take (Suc aa) W). fst L ∉# dom_m (fmdrop (fst (W ! aa)) aaa)))
      apply (auto intro: rtranclp.rtrancl_into_rtrancl)[]
      apply (auto simp: GC_remap.simps Cons_nth_drop_Suc[symmetric]
          take_Suc_conv_app_nth
        dest: multi_member_split)
      apply (rule_tac x= m(fst (W ! aa)  x) in exI)
      apply (intro conjI)
      apply (rule_tac x=x in exI)
        apply (rule_tac x= fst (W ! aa) in exI)
        apply (force dest: rtranclp_GC_remap_ran_m_no_lost)
       apply auto
      by (smt basic_trans_rules(31) fun_upd_apply mem_Collect_eq option.simps(1) ran_def)
    subgoal by auto
    subgoal by (auto 5 5 simp: GC_remap.simps Cons_nth_drop_Suc[symmetric]
          take_Suc_conv_app_nth
        dest: multi_member_split)
    subgoal by auto
    subgoal by auto
    subgoal by auto
    subgoal by auto
    done
qed

definition cdcl_GC_clauses_prog_single_wl
  :: 'v clauses_l  ('v literal  'v watched)  'v 
         'v clauses_l  ('v clauses_l × 'v clauses_l × ('v literal  'v watched)) nres
where
cdcl_GC_clauses_prog_single_wl = (λN WS A N'. do {
    L  RES {Pos A, Neg A};
    (N, N')  cdcl_GC_clauses_prog_copy_wl_entry N (WS L) L N';
    let WS = WS(L := []);
    (N, N')  cdcl_GC_clauses_prog_copy_wl_entry N (WS (-L)) (-L) N';
    let WS = WS(-L := []);
    RETURN (N, N', WS)
  })

lemma cdcl_GC_clauses_prog_single_wl_removed:
  Lset (W (Pos A)). fst L ∉# dom_m aaa 
       Lset (W (Neg A)). fst L ∉# dom_m a 
       GC_remap** (aaa, ma, baa) (a, mb, b) 
       set_mset (dom_m a)  clauses_pointed_to (set_mset (negs 𝒜 + poss 𝒜 - {#Neg A, Pos A#})) W 
       xa ∈# dom_m a 
       xa  clauses_pointed_to (Neg ` set_mset (remove1_mset A 𝒜)  Pos ` set_mset (remove1_mset A 𝒜))
              (W(Pos A := [], Neg A := []))
  Lset (W (Neg A)). fst L ∉# dom_m aaa 
       Lset (W (Pos A)). fst L ∉# dom_m a 
       GC_remap** (aaa, ma, baa) (a, mb, b) 
       set_mset (dom_m a)  clauses_pointed_to (set_mset (negs 𝒜 + poss 𝒜 - {#Pos A, Neg A#})) W 
       xa ∈# dom_m a 
       xa  clauses_pointed_to
              (Neg ` set_mset (remove1_mset A 𝒜)  Pos ` set_mset (remove1_mset A 𝒜))
              (W(Neg A := [], Pos A := []))
  supply poss_remove_Pos[simp] negs_remove_Neg[simp]
  by (case_tac [!] A ∈# 𝒜)
    (fastforce simp: clauses_pointed_to_def
      dest!: multi_member_split
      dest: rtranclp_GC_remap_ran_m_no_lost)+

lemma cdcl_GC_clauses_prog_single_wl:
  fixes A :: 'v and WS :: 'v literal  'v watched and
    N0 :: 'v clauses_l
  assumes ran m  set_mset (dom_m N0') 
	  (Ldom m. L ∉# (dom_m N0)) 
	  set_mset (dom_m N0) 
	    clauses_pointed_to (set_mset (negs 𝒜 + poss 𝒜)) W 
          0 ∉# dom_m N0'
  shows
    cdcl_GC_clauses_prog_single_wl N0 W A N0' 
      SPEC(λ(N, N', WS'). m'. GC_remap** (N0, m, N0') (N, m', N') 
	  ran m'  set_mset (dom_m N') 
	  (Ldom m'. L ∉# dom_m N) 
	  WS' (Pos A) = []  WS' (Neg A) = [] 
	  (L. L  Pos A  L  Neg A  W L = WS' L) 
	  set_mset (dom_m N) 
	    clauses_pointed_to
	      (set_mset (negs (remove1_mset A 𝒜) + poss (remove1_mset A 𝒜))) WS' 
          0 ∉# dom_m N'
	  )
proof -
  have [simp]: A ∉# 𝒜  negs 𝒜 + poss 𝒜 - {#Neg A, Pos A#} =
   negs 𝒜 + poss 𝒜
    by (induction 𝒜) auto
  have [simp]: A ∉# 𝒜  negs 𝒜 + poss 𝒜 - {#Pos A, Neg A#} =
   negs 𝒜 + poss 𝒜
    by (induction 𝒜)  auto
  show ?thesis
    unfolding cdcl_GC_clauses_prog_single_wl_def
    apply (refine_vcg)
    subgoal for x (*TODO proof*)
      apply (rule order_trans, rule cdcl_GC_clauses_prog_copy_wl_entry[of _ _ _
            negs 𝒜 + poss 𝒜])
       apply(solves use assms in auto)
      apply (rule RES_rule)
      apply (refine_vcg)
      apply clarify
      subgoal for aa ba aaa baa ma
        apply (rule order_trans,
            rule cdcl_GC_clauses_prog_copy_wl_entry[of ma _ _
              remove1_mset x (negs 𝒜 + poss 𝒜)])
         apply (solves auto simp: clauses_pointed_to_remove1_if)[]
        unfolding Let_def
        apply (rule RES_rule)
        apply clarsimp
        apply (simp add: eq_commute[of Neg _]
            uminus_lit_swap clauses_pointed_to_remove1_if)
        apply auto
         apply (rule_tac x=mb in exI)
         apply (auto dest!:
            simp: clauses_pointed_to_remove1_if
            clauses_pointed_to_remove1_if2
            clauses_pointed_to_remove1_if2_eq)
         apply (subst (asm) clauses_pointed_to_remove1_if2_eq)
          apply (force dest: rtranclp_GC_remap_ran_m_no_lost)
         apply (auto intro!: cdcl_GC_clauses_prog_single_wl_removed)[]
         apply (rule_tac x=mb in exI)
         apply (auto dest: multi_member_split[of A]
            simp: clauses_pointed_to_remove1_if
            clauses_pointed_to_remove1_if2
            clauses_pointed_to_remove1_if2_eq)
         apply (subst (asm) clauses_pointed_to_remove1_if2_eq)
          apply (force dest: rtranclp_GC_remap_ran_m_no_lost)
        apply (auto intro!: cdcl_GC_clauses_prog_single_wl_removed)[]
        done
    done
    done
qed


definition (in -)cdcl_GC_clauses_prog_wl_inv
  :: 'v multiset  'v clauses_l 
    'v multiset × ('v clauses_l × 'v clauses_l × ('v literal  'v watched))  bool
where
cdcl_GC_clauses_prog_wl_inv 𝒜 N0 = (λ(, (N, N', WS)).  ⊆# 𝒜 
  (A  set_mset 𝒜 - set_mset . (WS (Pos A) = [])  WS (Neg A) = []) 
  0 ∉# dom_m N' 
  (m. GC_remap** (N0, (λ_. None), fmempty) (N, m, N')
      ran m  set_mset (dom_m N') 
      (Ldom m. L ∉# dom_m N) 
      set_mset (dom_m N)  clauses_pointed_to (Neg ` set_mset   Pos ` set_mset ) WS))

definition cdcl_GC_clauses_prog_wl :: 'v twl_st_wl  'v twl_st_wl nres where
  cdcl_GC_clauses_prog_wl = (λ(M, N0, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, WS). do {
    ASSERT(cdcl_GC_clauses_pre_wl (M, N0, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, WS));
    𝒜  SPEC(λ𝒜. set_mset 𝒜 = set_mset (all_init_atms_st (M, N0, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, WS)));
    (_, (N, N', WS))  WHILETcdcl_GC_clauses_prog_wl_inv 𝒜 N0(λ(, _).   {#})
      (λ(, (N, N', WS)). do {
        ASSERT(  {#});
        A  SPEC (λA. A ∈# );
        (N, N', WS)  cdcl_GC_clauses_prog_single_wl N WS A N';
        RETURN (remove1_mset A , (N, N', WS))
      })
      (𝒜, (N0, fmempty, WS));
    RETURN (M, N', D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, WS)
  })

lemma no_lost_clause_in_WL_no_lost_clause_in_WL0D:
  no_lost_clause_in_WL S  no_lost_clause_in_WL0 S
  by (auto simp: no_lost_clause_in_WL_def no_lost_clause_in_WL0_def)

lemma no_lost_clause_in_WL_alt_def:
  no_lost_clause_in_WL0 (M, N0, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, WS) 
  set_mset (dom_m N0)  clauses_pointed_to
  (Neg ` set_mset (all_init_atms N0 (NE+NEk+NS+N0))  Pos ` set_mset (all_init_atms N0 (NE+NEk+NS+N0))) WS
proof -
  have [simp]: set_mset (all_init_lits_of_wl ([], N0, D, NE, {#}, NEk, {#}, NS, {#}, N0, {#}, Q, WS)) =
    (Neg ` set_mset (all_init_atms N0 (NE + NEk+ NS + N0))  Pos ` set_mset (all_init_atms N0 (NE + NEk + NS + N0)))
    unfolding all_init_lits_of_wl_def all_init_atms_def  image_image
      all_lits_of_mm_def all_init_lits_def set_image_mset image_mset_union
      sum_mset.union image_Un
    by (auto simp add: image_image image_Un)
  show ?thesis
    unfolding no_lost_clause_in_WL0_def
    by auto
qed

lemma cdcl_GC_clauses_prog_wl:
  assumes ((M, N0, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, WS), S)  state_wl_l None 
    no_lost_clause_in_WL (M, N0, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, WS) 
    cdcl_GC_clauses_pre S 
    literals_are_ℒin' (M, N0, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, WS)
  shows
    cdcl_GC_clauses_prog_wl (M, N0, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, WS) 
      (SPEC(λ(M', N', D', NE', UE', NEk', UEk', NS', US', N0', U0', Q', WS').
         (M', D', NE', UE', NEk', UEk', NS', US', N0', U0', Q') = (M, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q) 
         (m. GC_remap** (N0, (λ_. None), fmempty) (fmempty, m, N')) 
         0 ∉# dom_m N'  (L ∈# all_init_lits N0 (NE+NEk+NS+N0). WS' L = [])))
proof -
  show ?thesis
    supply[[goals_limit=1]]
    unfolding cdcl_GC_clauses_prog_wl_def
    apply (refine_vcg
      WHILEIT_rule[where R = measure (λ(𝒜::'v multiset, (_::'v clauses_l, _ ::'v clauses_l,
          _:: 'v literal  'v watched)). size 𝒜)])
    subgoal
      using assms
      unfolding cdcl_GC_clauses_pre_wl_def 
      by blast
    subgoal by auto
    subgoal using assms
      no_lost_clause_in_WL_no_lost_clause_in_WL0D[of (M, N0, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, WS), unfolded no_lost_clause_in_WL_alt_def]
      unfolding cdcl_GC_clauses_prog_wl_inv_def
      by (auto simp: all_init_atms_st_def)
    subgoal by auto
    subgoal for a b aa ba ab bb ac bc ad bd ae be af bf ag bg ah bh ai bi aj bj ak bk x s al bl am
        bm an bn xa
      unfolding cdcl_GC_clauses_prog_wl_inv_def
      apply clarify
      apply (rule order_trans,
         rule_tac m=m and 𝒜=al in cdcl_GC_clauses_prog_single_wl)
      subgoal by (auto simp: all_init_atms_st_def)
      subgoal
        apply (rule RES_rule)
        apply clarify
        apply (rule RETURN_rule)
        apply clarify
        apply (intro conjI)
             apply (solves auto)
            apply (solves auto dest!: multi_member_split)
           apply (solves auto)
          apply (rule_tac x=m' in exI)
          apply (solves auto)[]
         apply (simp_all add: size_Diff1_less)[]
        done
      done
    subgoal
      unfolding cdcl_GC_clauses_prog_wl_inv_def
      by auto
    subgoal
      unfolding cdcl_GC_clauses_prog_wl_inv_def
      by auto
    subgoal
      unfolding cdcl_GC_clauses_prog_wl_inv_def
      by auto
    subgoal
      unfolding cdcl_GC_clauses_prog_wl_inv_def
      by (intro ballI, rename_tac L, case_tac L)
       (auto simp: in_all_lits_of_mm_ain_atms_of_iff all_init_atms_def all_init_atms_st_def
          simp del: all_init_atms_def[symmetric]
          dest!: multi_member_split)
  done
qed


lemma cdcl_GC_clauses_prog_wl2:
  assumes ((M, N0, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, WS), S)  state_wl_l None 
    no_lost_clause_in_WL (M, N0, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, WS) 
    cdcl_GC_clauses_pre S 
    literals_are_ℒin' (M, N0, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, WS)
  N0 = N0'
  shows
    cdcl_GC_clauses_prog_wl (M, N0, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q, WS)   Id
      (SPEC(λ(M', N', D', NE', UE', NEk', UEk', NS', US', N0', U0', Q', WS').
         (M', D', NE', UE', NEk', UEk', NS', US', N0', U0', Q') = (M, D, NE, UE, NEk, UEk, NS, US, N0, U0, Q) 
         (m. GC_remap** (N0', (λ_. None), fmempty) (fmempty, m, N')) 
         0 ∉# dom_m N'  (L ∈# all_init_lits N0 (NE+NEk+NS+N0). WS' L = [])))
proof -
  show ?thesis
    unfolding N0 = N0'[symmetric]
    apply (rule order_trans[OF cdcl_GC_clauses_prog_wl[OF assms(1)]])
    apply (rule RES_refine)
    apply (fastforce dest: rtranclp_GC_remap_all_init_lits)
    done
qed

end