Theory Approximate_Model_Counting.ApproxMCCore
section ‹ ApproxMCCore definitions ›
text ‹
This section defines the ApproxMCCore locale and various failure events to be used in its probabilistic analysis.
The definitions closely follow Section 4.2 of Chakraborty et al.~\cite{DBLP:conf/ijcai/ChakrabortyMV16}.
Some non-probabilistic properties of the events are proved, most notably, the event inclusions of Lemma 3~\cite{DBLP:conf/ijcai/ChakrabortyMV16}.
Note that ``events'' here refer to subsets of hash functions.
›
theory ApproxMCCore imports
ApproxMCPreliminaries
begin
type_synonym 'a assg = "'a ⇀ bool"
definition restr :: "'a set ⇒ ('a ⇒ bool) ⇒ 'a assg"
where "restr S w = (λx. if x ∈ S then Some (w x) else None)"
lemma restrict_eq_mono:
assumes "x ⊆ y"
assumes "f |` y = g |` y"
shows "f |` x = g |` x"
using assms
by (metis Map.restrict_restrict inf.absorb_iff2)
definition proj :: "'a set ⇒ ('a ⇒ bool) set ⇒ 'a assg set"
where "proj S W = restr S ` W"
lemma card_proj:
assumes "finite S"
shows "finite (proj S W)" "card (proj S W) ≤ 2 ^ card S"
proof -
have *: "proj S W ⊆ {w. dom w = S}"
unfolding proj_def restr_def
by (auto split: if_splits)
also have 1: "{w. dom w = S} = {w. dom w = S ∧ ran w ⊆ {True,False}}"
by auto
have f: "finite {w. dom w = S ∧ ran w ⊆ {True,False}}"
by (simp add: assms finite_set_of_finite_maps)
thus "finite (proj S W)"
using * 1
by (metis finite_subset)
have 2:"card {w. dom w = S ∧ ran w ⊆ {True,False}} = (card {True,False}) ^ card S"
apply (intro card_dom_ran)
using assms by auto
show "card (proj S W) ≤ 2 ^ card S"
using * 1 2
by (metis (no_types, lifting) f card.empty card_insert_disjoint card_mono finite.emptyI finite.insertI insert_absorb insert_not_empty numeral_2_eq_2 singleton_insert_inj_eq)
qed
lemma proj_mono:
assumes "x ⊆ y"
shows "proj w x ⊆ proj w y"
unfolding proj_def
using assms by blast
definition aslice :: "nat ⇒ nat assg ⇒ nat assg"
where "aslice i a = a |` {..<i}"
lemma aslice_eq:
assumes "i ≥ n"
assumes "dom a = {..<n}"
shows "aslice i a = aslice n a"
using assms
unfolding aslice_def restrict_map_def dom_def
by fastforce
definition hslice :: "nat ⇒
('a assg ⇒ nat assg) ⇒ ('a assg ⇒ nat assg)"
where "hslice i h = aslice i ∘ h"
locale ApproxMCCore =
fixes W :: "('a ⇒ bool) set"
fixes S :: "'a set"
fixes ε :: "real"
fixes α :: "nat assg"
fixes thresh :: "nat"
assumes α: "dom α = {0..<card S - 1}"
assumes ε: "ε > 0"
assumes thresh:
"thresh > 4"
"card (proj S W) ≥ thresh"
assumes S: "finite S"
begin
lemma finite_proj_S:
shows "finite (proj S W)"
using S by (auto intro!: card_proj)
definition μ :: "nat ⇒ real"
where "μ i = card (proj S W) / 2 ^ i"
definition card_slice ::"
('a assg ⇒ nat assg) ⇒
nat ⇒ nat"
where "card_slice h i =
card (proj S W ∩ {w. hslice i h w = aslice i α})"
lemma card_slice_anti_mono:
assumes "i ≤ j"
shows "card_slice h j ≤ card_slice h i"
proof -
have *: "{..<i} ⊆ {..<j}" using assms by auto
have "{w. hslice j h w = aslice j α}
⊆ {w. hslice i h w = aslice i α}"
by (auto intro: restrict_eq_mono[OF *] simp add: hslice_def aslice_def)
thus ?thesis
unfolding card_slice_def
apply (intro card_mono)
subgoal using finite_proj_S by blast
by (auto intro!: proj_mono)
qed
lemma hslice_eq:
assumes "n ≤ i"
assumes "⋀w. dom (h w) = {..<n}"
shows "hslice i h = hslice n h"
using assms aslice_eq
unfolding hslice_def by auto
lemma card_slice_lim:
assumes "card S - 1 ≤ i"
assumes "⋀w. dom (h w) = {..<(card S - 1)}"
shows "card_slice h i = card_slice h (card S - 1)"
unfolding card_slice_def
apply(subst aslice_eq[OF assms(1)])
subgoal using α by auto
apply(subst hslice_eq[OF assms(1)])
using assms by auto
definition T :: "nat ⇒
('a assg ⇒ nat assg) set"
where "T i = {h. card_slice h i < thresh}"
lemma T_mono:
assumes "i ≤ j"
shows "T i ⊆ T j"
unfolding T_def
using card_slice_anti_mono[OF assms]
dual_order.strict_trans2
of_nat_mono
by blast
lemma μ_anti_mono:
assumes "i ≤ j"
shows "μ i ≥ μ j"
proof -
have "2^ i ≤ (2::real) ^ j"
by (simp add: assms)
then show ?thesis unfolding μ_def
by (simp add: frac_le)
qed
lemma card_proj_witnesses:
"card (proj S W) > 0"
using thresh by linarith
lemma μ_strict_anti_mono:
assumes "i < j"
shows "μ i > μ j"
proof -
have "2^ i < (2::real) ^ j"
by (simp add: assms)
then show ?thesis unfolding μ_def
using card_proj_witnesses
by (simp add: frac_less2)
qed
lemma μ_gt_zero:
shows "μ i > 0"
unfolding μ_def
using card_proj_witnesses
by auto
definition L :: "nat ⇒
('a assg ⇒ nat assg) set"
where "
L i =
{h. real (card_slice h i) < μ i / (1 + ε)}"
definition U :: "nat ⇒
('a assg ⇒ nat assg) set"
where "
U i =
{h. real (card_slice h i) ≥ μ i * (1 + ε / (1 + ε))}"
definition approxcore :: "
('a assg ⇒ nat assg) ⇒
nat × nat"
where "
approxcore h =
(case List.find
(λi. h ∈ T i) [1..<card S] of
None ⇒ (2 ^ card S, 1)
| Some m ⇒
(2 ^ m, card_slice h m))"
definition approxcore_fail :: "
('a assg ⇒ nat assg) set"
where "approxcore_fail =
{h.
let (cells,sols) = approxcore h in
cells * sols ∉
{ card (proj S W) / (1 + ε) ..
(1 + ε::real) * card (proj S W)}
}"
lemma T0_empty:
shows "T 0 = {}"
unfolding T_def card_slice_def
hslice_def aslice_def
using thresh(2) by auto
lemma L0_empty:
shows "L 0 = {}"
proof -
have "0 < ε ⟹
real (card (proj S W))
< real (card (proj S W)) / (1 + ε) ⟹
False"
by (smt (z3) card_proj_witnesses divide_minus1 frac_less2 nonzero_minus_divide_right of_nat_0_less_iff)
thus ?thesis
unfolding L_def card_slice_def
hslice_def aslice_def μ_def
using ε by clarsimp
qed
lemma U0_empty:
shows "U 0 = {}"
proof -
have *: "(1 + ε / (1 + ε)) > 1"
using ε by auto
have **: "U 0 = {}"
unfolding U_def card_slice_def
hslice_def aslice_def μ_def
using *
by (simp add: card_proj_witnesses)
thus ?thesis using ** by auto
qed
lemma real_divide_pos_left:
assumes "(0::real) < a"
assumes "a * b < c"
shows "b < c / a"
using assms
by (simp add: mult.commute mult_imp_less_div_pos)
lemma real_divide_pos_right:
assumes "a > (0::real)"
assumes "b < a * c"
shows "b / a < c"
using assms
by (simp add: mult.commute mult_imp_div_pos_less)
lemma failure_imp:
shows "approxcore_fail ⊆
(⋃i∈{1..<card S}.
(T i - T (i-1)) ∩ (L i ∪ U i)) ∪
-T (card S - 1)"
proof standard
fix h
assume "h ∈ approxcore_fail"
then obtain cells sols where
h: "approxcore h = (cells, sols)"
"cells * sols ∉
{ card (proj S W) / (1 + ε) ..
(1 + ε::real) * card (proj S W)}" (is "_ ∉ {?lower..?upper}")
unfolding approxcore_fail_def
by auto
have "List.find (λi. h ∈ T i) [1..<card S] = None ∨
List.find (λi. h ∈ T i) [1..<card S] ≠ None" by auto
moreover {
assume "List.find (λi. h ∈ T i) [1..<card S] = None"
then have "h ∉ T (card S - 1)"
unfolding find_None_iff
by (metis T0_empty atLeastLessThan_iff diff_is_0_eq' diff_less empty_iff gr_zeroI leI less_one not_less_zero set_upt)
}
moreover {
assume "List.find (λi. h ∈ T i) [1..<card S] ≠ None"
then obtain m where
findm: "List.find (λi. h ∈ T i) [1..<card S] = Some m" by auto
then have
m: "1 ≤ m" "m < card S"
"h ∈ T m"
"∀i. 1 ≤ i ∧ i < m ⟶ h ∉ T i"
unfolding find_Some_iff
using less_Suc_eq_0_disj by auto
then have 1: "h ∉ T (m - 1)"
by (metis T0_empty bot_nat_0.not_eq_extremum diff_is_0_eq diff_less empty_iff less_one)
have "2 ^ m * card_slice h m < ?lower ∨
2 ^ m * card_slice h m > ?upper"
using h unfolding approxcore_def findm by auto
moreover {
assume "2 ^ m * card_slice h m < ?lower"
then have "card_slice h m < ?lower / 2 ^ m"
using real_divide_pos_left
by (metis numeral_power_eq_of_nat_cancel_iff of_nat_mult zero_less_numeral zero_less_power)
then have "h ∈ L m" unfolding L_def
by (simp add: μ_def mult.commute)
}
moreover {
assume *: "?upper < 2 ^ m * card_slice h m"
have "1 / (1 + ε) < 1"
using ε divide_less_eq_1 by fastforce
then have "ε / (1 + ε) < ε"
using ε
by (metis (no_types, opaque_lifting) add_cancel_left_right div_by_1 divide_divide_eq_left divide_less_eq_1_pos mult.commute nonzero_divide_mult_cancel_left)
then have "card (proj S W) * (1 + ε / (1 + ε)) ≤ ?upper"
using linorder_not_less not_less_iff_gr_or_eq by fastforce
then have "(card (proj S W) * (1 + ε / (1 + ε))) / 2 ^ m < card_slice h m"
apply (intro real_divide_pos_right)
using * by auto
then have "h ∈ U m" unfolding U_def
by (simp add: μ_def)
}
ultimately have "h ∈ L m ∨ h ∈ U m" by blast
then have "∀m∈{Suc 0..<card S}.
h ∈ T m ⟶
h ∈ T (m - Suc 0) ∨
h ∉ L m ∧ h ∉ U m ⟹
h ∈ T (card S - Suc 0) ⟹ False"
using m 1 by auto
}
ultimately show
"h ∈ (⋃i∈{1..<card S}.
(T i - T (i - 1)) ∩ (L i ∪ U i)) ∪
- T (card S - 1)"
by auto
qed
lemma smallest_nat_exists:
assumes "P i" "¬P (0::nat)"
obtains m where "m ≤ i" "P m" "¬P (m-1)"
using assms
proof (induction i)
case 0
then show ?case by auto
next
case (Suc i)
then show ?case
by (metis diff_Suc_1 le_Suc_eq)
qed
lemma mstar_non_zero:
shows "¬ μ 0 * (1 + ε / (1 + ε)) ≤ thresh"
proof -
have "μ 0 ≥ thresh"
unfolding μ_def
by (auto simp add: thresh(2))
thus ?thesis
by (smt (verit, best) ε μ_gt_zero divide_pos_pos mult_le_cancel_left2)
qed
lemma real_div_less:
assumes "c > 0"
assumes "a ≤ b * (c::nat)"
shows "real a / real c ≤ b"
by (metis assms(1) assms(2) divide_le_eq of_nat_0_less_iff of_nat_mono of_nat_mult)
lemma mstar_exists:
obtains m where
"μ (m - 1) * (1 + ε / (1 + ε)) > thresh"
"μ m * (1 + ε / (1 + ε)) ≤ thresh"
"m ≤ card S - 1"
proof -
have e1:"1 + ε / (1 + ε) > 1"
by (simp add: ε add_nonneg_pos)
have e2:"1 + ε / (1 + ε) < 2"
by (simp add: ε add_nonneg_pos)
have "thresh ≥ (4::real)"
using thresh(1) by linarith
then have up:"thresh / (1 + ε / (1 + ε)) > 2"
by (smt (verit) e1 e2 field_sum_of_halves frac_less2)
have "card (proj S W) ≤ 2 * 2 ^ (card S - Suc 0)"
by (metis One_nat_def S Suc_diff_Suc card.empty card_gt_0_iff card_proj(2) diff_zero less_one order_less_le_trans plus_1_eq_Suc power_0 power_Suc0_right power_add thresh(1) thresh(2) zero_neq_numeral)
then have low:"μ (card S - 1) ≤ 2"
unfolding μ_def
using real_div_less
by (smt (verit) Num.of_nat_simps(2) Num.of_nat_simps(4) Suc_1 nat_zero_less_power_iff numeral_nat(7) of_nat_power plus_1_eq_Suc pos2)
have pi: "μ (card S - 1) * (1 + ε / (1 + ε)) ≤ thresh"
using up low
by (smt (verit, ccfv_SIG) divide_le_eq e1)
from smallest_nat_exists[OF pi mstar_non_zero]
show ?thesis
by (metis linorder_not_less that)
qed
definition mstar :: "nat"
where "mstar = (@m.
μ (m - 1) * (1 + ε / (1 + ε)) > thresh ∧
μ m * (1 + ε / (1 + ε)) ≤ thresh ∧
m ≤ card S - 1)"
lemma mstar_prop:
shows
"μ (mstar - 1) * (1 + ε / (1 + ε)) > thresh"
"μ mstar * (1 + ε / (1 + ε)) ≤ thresh"
"mstar ≤ card S - 1"
unfolding mstar_def
by (smt (verit) some_eq_ex mstar_exists)+
lemma O1_lem:
assumes "i ≤ m"
shows "(T i - T (i-1)) ∩ (L i ∪ U i) ⊆ T m"
using T_mono assms by blast
lemma O1:
shows "(⋃i∈{1..mstar-3}.
(T i - T (i-1)) ∩ (L i ∪ U i)) ⊆ T (mstar-3)"
using T_mono by force
lemma T_anti_mono_neg:
assumes "i ≤ j"
shows "- T j ⊆ - T i"
by (simp add: Diff_mono T_mono assms)
lemma O2_lem:
assumes "mstar < i"
shows "(T i - T (i-1)) ∩ (L i ∪ U i) ⊆ -T mstar"
proof -
have "(T i - T (i-1)) ∩ (L i ∪ U i) ⊆ -T (i-1)"
by blast
thus ?thesis
by (smt (verit) T_mono ApproxMCCore_axioms One_nat_def Suc_diff_Suc Suc_le_eq assms compl_mono diff_is_0_eq' diff_less_mono leI minus_nat.diff_0 subset_trans)
qed
lemma O2:
shows "(⋃i∈{mstar..<card S}.
(T i - T (i-1)) ∩ (L i ∪ U i)) ∪
-T (card S - 1) ⊆ L mstar ∪ U mstar"
proof -
have 0: "(⋃i∈{mstar..<card S}.
(T i - T (i-1)) ∩ (L i ∪ U i)) ⊆
(T mstar - T (mstar-1)) ∩ (L mstar ∪ U mstar) ∪
(⋃i∈{mstar+1..<card S}.
(T i - T (i-1)) ∩ (L i ∪ U i))"
apply (intro subsetI)
apply clarsimp
by (metis Suc_le_eq atLeastLessThan_iff basic_trans_rules(18))
have 1: "(⋃i∈{mstar+1..<card S}.
(T i - T (i-1)) ∩ (L i ∪ U i)) ⊆ -T mstar"
apply clarsimp
by (metis (no_types, lifting) ApproxMCCore.T_mono ApproxMCCore_axioms One_nat_def diff_Suc_1 diff_le_mono subsetD)
have 2: "-T (card S - 1) ⊆ - T mstar"
using T_anti_mono_neg mstar_prop(3) by presburger
have "thresh ≥ μ mstar * (1 + ε / (1 + ε))"
using mstar_prop(2) thresh by linarith
then have *: "- T mstar ⊆ U mstar"
unfolding T_def U_def
by auto
have "(⋃i∈{mstar..<card S}.
(T i - T (i-1)) ∩ (L i ∪ U i)) ∪
-T (card S - 1) ⊆
((T mstar - T (mstar-1)) ∩ (L mstar ∪ U mstar)) ∪ -T mstar"
using 0 1 2 by (smt (z3) Un_iff subset_iff)
moreover have "... ⊆ L mstar ∪ U mstar"
using *
by blast
ultimately show ?thesis by auto
qed
lemma O3:
assumes "i ≤ mstar - 1"
shows "(T i - T (i-1)) ∩ (L i ∪ U i) ⊆ L i"
proof -
have *: "μ i * (1 + ε / (1 + ε)) > thresh"
by (smt (verit, ccfv_SIG) ε μ_anti_mono assms divide_nonneg_nonneg mstar_prop(1) mult_right_mono)
have "x ∈ T i ∧ x ∈ U i ⟹ False" for x
unfolding T_def U_def
using * by auto
thus ?thesis
by blast
qed
lemma union_split_lem:
assumes x: "x ∈ (⋃i∈{1..<n::nat}. P i)"
shows "x ∈ (⋃i∈{1..m-3}. P i) ∪
P (m-2) ∪
P (m-1) ∪
(⋃i∈{m..<n}. P i)"
proof -
obtain i where i: "i ∈ {1..<n}"
"x ∈ P i" using x by auto
have "i ∈ {1..m-3} ∨ i = m-2 ∨ i = m-1 ∨ i ∈ {m..<n}"
using i(1)
by auto
thus ?thesis using i
by blast
qed
lemma union_split:
"(⋃i∈{1..<n::nat}. P i) ⊆
(⋃i∈{1..m-3}. P i) ∪
P (m-2) ∪
P (m-1) ∪
(⋃i∈{m..<n}. P i)"
using union_split_lem
by (metis subsetI)
lemma failure_bound:
shows "approxcore_fail ⊆
T (mstar-3) ∪
L (mstar-2) ∪
L (mstar-1) ∪
(L mstar ∪ U mstar)"
proof -
have *: "approxcore_fail ⊆
(⋃i∈{1..<card S}.
(T i - T (i-1)) ∩ (L i ∪ U i)) ∪ -T (card S - 1)" (is "_ ⊆ (⋃i∈{1..<card S}. ?P i) ∪ _")
using failure_imp .
moreover have "... ⊆
(⋃i∈{1..mstar - 3}. ?P i) ∪
?P (mstar - 2) ∪
?P (mstar - 1) ∪
((⋃i∈{mstar..<card S}. ?P i) ∪ -T (card S - 1))"
using
union_split[of "λi. ?P i" "card S" "mstar"]
by blast
moreover have "... ⊆
T (mstar - 3) ∪
L (mstar - 2) ∪
L (mstar - 1) ∪
(L mstar ∪ U mstar)
"
using O1 O2 O3
by (metis (no_types, lifting) One_nat_def Un_mono diff_Suc_eq_diff_pred diff_le_self nat_1_add_1 plus_1_eq_Suc)
ultimately show ?thesis
by (meson order_trans)
qed
end
end