Theory Watched_Literals_Clauses

theory Watched_Literals_Clauses
imports More_Sepref.WB_More_Refinement_List Watched_Literals_Transition_System
begin

type_synonym 'v clause_l = 'v literal list
type_synonym 'v clauses_l = (nat, ('v clause_l × bool)) fmap

abbreviation watched_l :: 'a clause_l  'a clause_l where
  watched_l l  take 2 l

abbreviation unwatched_l :: 'a clause_l  'a clause_l  where
  unwatched_l l  drop 2 l

fun twl_clause_of :: 'a clause_l  'a clause twl_clause where
  twl_clause_of l = TWL_Clause (mset (watched_l l)) (mset (unwatched_l l))

abbreviation clause_in :: 'v clauses_l  nat  'v clause_l (infix "" 101) where
  N  i  fst (the (fmlookup N i))

abbreviation clause_upd :: 'v clauses_l  nat  'v clause_l  'v clauses_l  where
  clause_upd N i C  fmupd i (C, snd (the (fmlookup N i))) N

text Taken from termfun_upd.
nonterminal updclsss and updclss

syntax
  "_updclss" :: "'a clauses_l  'a  updclss"             ("(2_ / _)")
  ""         :: "updbind  updbinds"             ("_")
  "_updclsss":: "updclss  updclsss  updclsss" ("_,/ _")
  "_Updateclss"  :: "'a  updclss  'a"            ("_/'((_)')" [1000, 0] 900)

translations
  "_Updateclss f (_updclsss b bs)"  "_Updateclss (_Updateclss f b) bs"
  "f(x  y)"  "CONST clause_upd f x y"


abbreviation ran_mf :: 'v clauses_l  'v clause_l multiset where
  ran_mf N  fst `# ran_m N

abbreviation learned_clss_l :: 'v clauses_l  ('v clause_l × bool) multiset where
  learned_clss_l N  {#C ∈# ran_m N. ¬snd C#}

abbreviation learned_clss_lf :: 'v clauses_l  'v clause_l multiset where
  learned_clss_lf N  fst `# learned_clss_l N

abbreviation init_clss_l :: 'v clauses_l  ('v clause_l × bool) multiset where
  init_clss_l N  {#C ∈# ran_m N. snd C#}

abbreviation init_clss_lf :: 'v clauses_l  'v clause_l multiset where
  init_clss_lf N  fst `# init_clss_l N

abbreviation all_clss_l :: 'v clauses_l  ('v clause_l × bool) multiset where
  all_clss_l N  init_clss_l N + learned_clss_l N

lemma all_clss_l_ran_m[simp]:
  all_clss_l N = ran_m N
  by (metis multiset_partition)

abbreviation all_clss_lf :: 'v clauses_l  'v clause_l multiset where
  all_clss_lf N  init_clss_lf N + learned_clss_lf N

lemma all_clss_lf_ran_m: all_clss_lf N = fst `# ran_m N
  by (metis (no_types) image_mset_union multiset_partition)

abbreviation irred :: 'v clauses_l  nat  bool where
  irred N C  snd (the (fmlookup N C))

definition irred' where irred' = irred

lemma ran_m_ran: fset_mset (ran_m N) = fmran N
  unfolding ran_m_def ran_def
  apply (auto simp: fmlookup_ran_iff dom_m_def elim!: fmdomE)
   apply (metis fmdomE notin_fset option.sel)
  by (metis (no_types, lifting) fmdomI fmember.rep_eq image_iff option.sel)

lemma ran_m_clause_upd:
  assumes
    NC: C ∈# dom_m N
  shows ran_m (N(C  C')) =
         add_mset (C', irred N C) (remove1_mset (N  C, irred N C) (ran_m N))
proof -
  define N' where
    N' = fmdrop C N
  have N_N': dom_m N = add_mset C (dom_m N')
    using NC unfolding N'_def by auto
  have C ∉# dom_m N'
    using NC distinct_mset_dom[of N] unfolding N_N' by auto
  then show ?thesis
    by (auto simp: N_N' ran_m_def mset_set.insert_remove image_mset_remove1_mset_if
      intro!: image_mset_cong)
qed

lemma ran_m_mapsto_upd:
  assumes
    NC: C ∈# dom_m N
  shows ran_m (fmupd C C' N) =
         add_mset C' (remove1_mset (N  C, irred N C) (ran_m N))
proof -
  define N' where
    N' = fmdrop C N
  have N_N': dom_m N = add_mset C (dom_m N')
    using NC unfolding N'_def by auto
  have C ∉# dom_m N'
    using NC distinct_mset_dom[of N] unfolding N_N' by auto
  then show ?thesis
    by (auto simp: N_N' ran_m_def mset_set.insert_remove image_mset_remove1_mset_if
      intro!: image_mset_cong)
qed

lemma ran_m_mapsto_upd_notin:
  assumes
    NC: C ∉# dom_m N
  shows ran_m (fmupd C C' N) = add_mset C' (ran_m N)
  using NC
  by (auto simp: ran_m_def mset_set.insert_remove image_mset_remove1_mset_if
      intro!: image_mset_cong split: if_splits)

lemma learned_clss_l_update[simp]:
  bh ∈# dom_m ax  size (learned_clss_l (ax(bh  C))) = size (learned_clss_l ax)
  by (auto simp: ran_m_clause_upd size_Diff_singleton_if dest!: multi_member_split)
     (auto simp: ran_m_def)

lemma Ball_ran_m_dom:
  (x∈#ran_m N. P (fst x))  (x∈#dom_m N. P (N  x))
  by (auto simp: ran_m_def)

lemma Ball_ran_m_dom_struct_wf:
  (x∈#ran_m N. struct_wf_twl_cls (twl_clause_of (fst x))) 
     (x∈# dom_m N. struct_wf_twl_cls (twl_clause_of (N  x)))
  by (rule Ball_ran_m_dom)

lemma init_clss_lf_fmdrop[simp]:
  irred N C  C ∈# dom_m N  init_clss_lf (fmdrop C N) = remove1_mset (NC) (init_clss_lf N)
  using distinct_mset_dom[of N]
  by (auto simp: ran_m_def image_mset_If_eq_notin[of C _ the] dest!: multi_member_split)

lemma init_clss_lf_fmdrop_irrelev[simp]:
  ¬irred N C  init_clss_lf (fmdrop C N) = init_clss_lf N
  using distinct_mset_dom[of N]
  apply (cases C ∈# dom_m N)
  by (auto simp: ran_m_def image_mset_If_eq_notin[of C _ the] dest!: multi_member_split)

lemma learned_clss_lf_lf_fmdrop[simp]:
  ¬irred N C  C ∈# dom_m N  learned_clss_lf (fmdrop C N) = remove1_mset (NC) (learned_clss_lf N)
  using distinct_mset_dom[of N]
  apply (cases C ∈# dom_m N)
  by (auto simp: ran_m_def image_mset_If_eq_notin[of C _ the] dest!: multi_member_split)

lemma learned_clss_l_l_fmdrop: ¬ irred N C  C ∈# dom_m N 
  learned_clss_l (fmdrop C N) = remove1_mset (the (fmlookup N C)) (learned_clss_l N)
  using distinct_mset_dom[of N]
  apply (cases C ∈# dom_m N)
  by (auto simp: ran_m_def image_mset_If_eq_notin[of C _ the] dest!: multi_member_split)

lemma learned_clss_lf_lf_fmdrop_irrelev[simp]:
  irred N C  learned_clss_lf (fmdrop C N) = learned_clss_lf N
  using distinct_mset_dom[of N]
  apply (cases C ∈# dom_m N)
  by (auto simp: ran_m_def image_mset_If_eq_notin[of C _ the] dest!: multi_member_split)

lemma ran_mf_lf_fmdrop[simp]:
  C ∈# dom_m N   ran_mf (fmdrop C N) = remove1_mset (NC) (ran_mf N)
  using distinct_mset_dom[of N]
  by (auto simp: ran_m_def image_mset_If_eq_notin[of C _ λx. fst (the x)] dest!: multi_member_split)

lemma ran_mf_lf_fmdrop_notin[simp]:
  C ∉# dom_m N   ran_mf (fmdrop C N) = ran_mf N
  using distinct_mset_dom[of N]
  by (auto simp: ran_m_def image_mset_If_eq_notin[of C _ λx. fst (the x)] dest!: multi_member_split)

lemma lookup_None_notin_dom_m[simp]:
  fmlookup N i = None  i ∉# dom_m N
  by (auto simp: dom_m_def fmlookup_dom_iff fmember.rep_eq[symmetric])

text While it is tempting to mark the two following theorems as [simp], this would break more
  simplifications since termran_mf is only an abbreviation for termran_m.

lemma ran_m_fmdrop:
  C ∈# dom_m N   ran_m (fmdrop C N) = remove1_mset (N  C, irred N C) (ran_m N)
  using distinct_mset_dom[of N]
  by (cases fmlookup N C)
    (auto simp: ran_m_def image_mset_If_eq_notin[of C _ λx. fst (the x)]
     dest!: multi_member_split
    intro!: filter_mset_cong2 image_mset_cong2)

lemma ran_m_fmdrop_notin:
  C ∉# dom_m N  ran_m (fmdrop C N) = ran_m N
  using distinct_mset_dom[of N]
  by (auto simp: ran_m_def image_mset_If_eq_notin[of C _ λx. fst (the x)]
    dest!: multi_member_split
    intro!: filter_mset_cong2 image_mset_cong2)

lemma init_clss_l_fmdrop_irrelev:
  ¬irred N C  init_clss_l (fmdrop C N) = init_clss_l N
  using distinct_mset_dom[of N]
  apply (cases C ∈# dom_m N)
  by (auto simp: ran_m_def image_mset_If_eq_notin[of C _ the] dest!: multi_member_split)

lemma init_clss_l_fmdrop:
  irred N C  C ∈# dom_m N  init_clss_l (fmdrop C N) = remove1_mset (the (fmlookup N C)) (init_clss_l N)
  using distinct_mset_dom[of N]
  by (auto simp: ran_m_def image_mset_If_eq_notin[of C _ the] dest!: multi_member_split)

lemma ran_m_lf_fmdrop:
  C ∈# dom_m N  ran_m (fmdrop C N) = remove1_mset (the (fmlookup N C)) (ran_m N)
  using distinct_mset_dom[of N]
  by (auto simp: ran_m_def image_mset_If_eq_notin[of C _ λx. fst (the x)] dest!: multi_member_split
    intro!: image_mset_cong)
lemma set_clauses_simp[simp]:
  f ` {a. a ∈# ran_m N  ¬ snd a}  f ` {a. a ∈# ran_m N  snd a}  A =
   f ` {a. a ∈# ran_m N}  A
  by auto

lemma init_clss_l_clause_upd:
  C ∈# dom_m N  irred N C 
    init_clss_l (N(C  C')) =
     add_mset (C', irred N C) (remove1_mset (N  C, irred N C) (init_clss_l N))
  by (auto simp: ran_m_mapsto_upd)

lemma init_clss_l_mapsto_upd:
  C ∈# dom_m N  irred N C 
   init_clss_l (fmupd C (C', True) N) =
     add_mset (C', irred N C) (remove1_mset (N  C, irred N C) (init_clss_l N))
  by (auto simp: ran_m_mapsto_upd)

lemma learned_clss_l_mapsto_upd:
  C ∈# dom_m N  ¬irred N C 
   learned_clss_l (fmupd C (C', False) N) =
      add_mset (C', irred N C) (remove1_mset (N  C, irred N C) (learned_clss_l N))
  by (auto simp: ran_m_mapsto_upd)

lemma init_clss_l_mapsto_upd_irrel: C ∈# dom_m N  ¬irred N C 
  init_clss_l (fmupd C (C', False) N) = init_clss_l N
  by (auto simp: ran_m_mapsto_upd)

lemma init_clss_l_mapsto_upd_irrel_notin: C ∉# dom_m N 
  init_clss_l (fmupd C (C', False) N) = init_clss_l N
  by (auto simp: ran_m_mapsto_upd_notin)

lemma learned_clss_l_mapsto_upd_irrel: C ∈# dom_m N  irred N C 
  learned_clss_l (fmupd C (C', True) N) = learned_clss_l N
  by (auto simp: ran_m_mapsto_upd)

lemma learned_clss_l_mapsto_upd_notin: C ∉# dom_m N 
  learned_clss_l (fmupd C  (C', False) N) = add_mset (C', False) (learned_clss_l N)
  by (auto simp: ran_m_mapsto_upd_notin)

lemma in_ran_mf_clause_inI[intro]:
  C ∈# dom_m N  i = irred N C  (N  C, i) ∈# ran_m N
  by (auto simp: ran_m_def dom_m_def)

lemma init_clss_l_mapsto_upd_notin:
  C ∉# dom_m N  init_clss_l (fmupd C (C', True) N) =
     add_mset (C', True) (init_clss_l N)
  by (auto simp: ran_m_mapsto_upd_notin)

lemma learned_clss_l_mapsto_upd_notin_irrelev: C ∉# dom_m N 
  learned_clss_l (fmupd C  (C', True) N) = learned_clss_l N
  by (auto simp: ran_m_mapsto_upd_notin)

lemma clause_twl_clause_of:  clause (twl_clause_of C) = mset C for C
    by (cases C; cases tl C) auto

lemma learned_clss_l_l_fmdrop_irrelev: irred N C 
  learned_clss_l (fmdrop C N) = learned_clss_l N
  using distinct_mset_dom[of N]
  apply (cases C ∈# dom_m N)
  by (auto simp: ran_m_def image_mset_If_eq_notin[of C _ the] dest!: multi_member_split)

lemma init_clss_l_fmdrop_if:
  C ∈# dom_m N  init_clss_l (fmdrop C N) = (if irred N C then remove1_mset (the (fmlookup N C)) (init_clss_l N)
    else init_clss_l N)
  by (auto simp: init_clss_l_fmdrop init_clss_l_fmdrop_irrelev)

lemma init_clss_l_fmupd_if:
  C' ∉# dom_m new  init_clss_l (fmupd C' D new) = (if snd D then add_mset D (init_clss_l new) else init_clss_l new)
  by (cases D) (auto simp: init_clss_l_mapsto_upd_irrel_notin init_clss_l_mapsto_upd_notin)

lemma learned_clss_l_fmdrop_if:
  C ∈# dom_m N  learned_clss_l (fmdrop C N) = (if ¬irred N C then remove1_mset (the (fmlookup N C)) (learned_clss_l N)
    else learned_clss_l N)
  by (auto simp: learned_clss_l_l_fmdrop learned_clss_l_l_fmdrop_irrelev)

lemma learned_clss_l_fmupd_if:
  C' ∉# dom_m new  learned_clss_l (fmupd C' D new) = (if ¬snd D then add_mset D (learned_clss_l new) else learned_clss_l new)
  by (cases D) (auto simp: learned_clss_l_mapsto_upd_notin_irrelev
    learned_clss_l_mapsto_upd_notin)



definition op_clauses_at :: 'v clauses_l  nat  nat  'v literal where
op_clauses_at N C i = N  C ! i

definition mop_clauses_at :: 'v clauses_l  nat  nat  'v literal nres where
mop_clauses_at N C i = do {
   ASSERT(C ∈# dom_m N);
   ASSERT(i < length (N  C));
   RETURN (N  C ! i)
}

lemma mop_clauses_at:
   (uncurry2 mop_clauses_at, uncurry2 (RETURN ooo op_clauses_at)) 
   [λ((N, C), i). C ∈# dom_m N  i < length (N  C)]f
   Id ×f Id ×f Id  Idnres_rel
  by (auto simp: mop_clauses_at_def op_clauses_at_def intro!: frefI nres_relI)

definition mop_clauses_swap :: 'v clauses_l  nat  nat  nat  'v clauses_l nres where
mop_clauses_swap N C i j = do {
   ASSERT(C ∈# dom_m N);
   ASSERT(i < length (N  C));
   ASSERT(j < length (N  C));
   RETURN (N(C  (swap (N  C) i j)))
}

definition op_clauses_swap :: 'v clauses_l  nat  nat  nat  'v clauses_l where
op_clauses_swap N C i j = (N(C  (swap (N  C) i j)))

lemma mop_clauses_swap:
   (uncurry3 mop_clauses_swap, uncurry3 (RETURN oooo op_clauses_swap)) 
   [λ(((N, C), i), j). C ∈# dom_m N  i < length (N  C)  j < length (N  C)]f
   Id ×f Id ×f Id ×f Id  Idnres_rel
  by (auto simp: mop_clauses_swap_def op_clauses_swap_def intro!: frefI nres_relI)


lemma mop_clauses_at_itself:
  (uncurry2 mop_clauses_at, uncurry2 mop_clauses_at)  Id ×f Id ×f Id f Idnres_rel
  by (auto intro!: frefI nres_relI)

lemma mop_clauses_at_itself_spec:
  ((N, C, i), (N', C', i'))  Id 
     mop_clauses_at N C i   {(L, L'). L = L'  L = N  C ! i} (mop_clauses_at N' C' i')
  by (auto intro!: frefI nres_relI ASSERT_refine_right simp: mop_clauses_at_def)

lemma mop_clauses_at_itself_spec2:
  ((N, C, i), (N', C', i'))  Id 
     mop_clauses_at N C i   {(L, L'). L = L'  L = N  C ! i  C ∈# dom_m N  i < length (N  C)}
      (mop_clauses_at N' C' i')
  by (auto intro!: frefI nres_relI ASSERT_refine_right simp: mop_clauses_at_def)

lemma mop_clauses_at_op_clauses_at_spec2:
  ((N, C, i), (N', C', i'))  Id  C ∈# dom_m N  i < length (N  C) 
     mop_clauses_at N C i   {(L, L'). L = L'  L = N  C ! i}
      (RETURN (op_clauses_at N' C' i'))
  by (auto intro!: frefI nres_relI ASSERT_refine_right
   simp: mop_clauses_at_def op_clauses_at_def)

lemma mop_clauses_swap_itself:
  (uncurry3 mop_clauses_swap, uncurry3 mop_clauses_swap)  Id ×f Id ×f Id ×f Id f Idnres_rel
  by (auto intro!: frefI nres_relI)

lemma mop_clauses_swap_itself_spec:
  ((N, C, i, j), (N', C', i', j'))  Id 
     mop_clauses_swap N C i j   {(L, L'). L = L'  L = op_clauses_swap N' C' i' j'  C' ∈# dom_m N} (mop_clauses_swap N' C' i' j')
  by (auto intro!: frefI nres_relI ASSERT_refine_right simp: mop_clauses_swap_def
    op_clauses_swap_def)

lemma mop_clauses_swap_itself_spec2:
  ((N, C, i, j), (N', C', i', j'))  Id 
     mop_clauses_swap N C i j   {(L, L'). L = L'  L = op_clauses_swap N' C' i' j'  C' ∈# dom_m N 
       i < length (N  C)  j < length (N  C)} (mop_clauses_swap N' C' i' j')
  by (auto intro!: frefI nres_relI ASSERT_refine_right simp: mop_clauses_swap_def
    op_clauses_swap_def)


end