diff --git a/thys/Approximation_Algorithms/Approx_BP_Hoare.thy b/thys/Approximation_Algorithms/Approx_BP_Hoare.thy new file mode 100755 --- /dev/null +++ b/thys/Approximation_Algorithms/Approx_BP_Hoare.thy @@ -0,0 +1,1706 @@ +section \Bin Packing\ + +theory Approx_BP_Hoare + imports Complex_Main "HOL-Hoare.Hoare_Logic" "HOL-Library.Disjoint_Sets" +begin + +text \The algorithm and proofs are based on the work by Berghammer and Reuter @{cite BerghammerR03}.\ + +subsection \Formalization of a Correct Bin Packing\ + +text \Definition of the unary operator \\\\\ from the article. + \B\ will only be wrapped into a set if it is non-empty.\ +definition wrap :: "'a set \ 'a set set" where + "wrap B = (if B = {} then {} else {B})" + +lemma wrap_card: + "card (wrap B) \ 1" + unfolding wrap_def by auto + +text \If \M\ and \N\ are pairwise disjoint with \V\ and not yet contained in V, + then the union of \M\ and \N\ is also pairwise disjoint with \V\.\ +lemma pairwise_disjnt_Un: + assumes "pairwise disjnt ({M} \ {N} \ V)" "M \ V" "N \ V" + shows "pairwise disjnt ({M \ N} \ V)" + using assms unfolding pairwise_def by auto + +text \A Bin Packing Problem is defined like in the article:\ +locale BinPacking = + fixes U :: "'a set" \ \A finite, non-empty set of objects\ + and w :: "'a \ real" \ \A mapping from objects to their respective weights (positive real numbers)\ + and c :: nat \ \The maximum capacity of a bin (a natural number)\ + and S :: "'a set" \ \The set of \small\ objects (weight no larger than \1/2\ of \c\)\ + and L :: "'a set" \ \The set of \large\ objects (weight larger than \1/2\ of \c\)\ + assumes weight: "\u \ U. 0 < w(u) \ w(u) \ c" + and U_Finite: "finite U" + and U_NE: "U \ {}" + and S_def: "S = {u \ U. w(u) \ c / 2}" + and L_def: "L = U - S" +begin + +text \In the article, this is defined as \w\ as well. However, to avoid ambiguity, + we will abbreviate the weight of a bin as \W\.\ +abbreviation W :: "'a set \ real" where + "W B \ (\u \ B. w(u))" + +text \\P\ constitutes as a correct bin packing if \P\ is a partition of \U\ + (as defined in @{thm [source] partition_on_def}) and the weights of + the bins do not exceed their maximum capacity \c\.\ +definition bp :: "'a set set \ bool" where + "bp P \ partition_on U P \ (\B \ P. W(B) \ c)" + +lemma bpE: + assumes "bp P" + shows "pairwise disjnt P" "{} \ P" "\P = U" "\B \ P. W(B) \ c" + using assms unfolding bp_def partition_on_def by blast+ + +lemma bpI: + assumes "pairwise disjnt P" "{} \ P" "\P = U" "\B \ P. W(B) \ c" + shows "bp P" + using assms unfolding bp_def partition_on_def by blast + +text \Although we assume the \S\ and \L\ sets as given, manually obtaining them from \U\ is trivial + and can be achieved in linear time. Proposed by the article @{cite "BerghammerR03"}.\ +lemma S_L_set_generation: +"VARS S L W u + {True} + S := {}; L := {}; W := U; + WHILE W \ {} + INV {W \ U \ S = {v \ U - W. w(v) \ c / 2} \ L = {v \ U - W. w(v) > c / 2}} DO + u := (SOME u. u \ W); + IF 2 * w(u) \ c + THEN S := S \ {u} + ELSE L := L \ {u} FI; + W := W - {u} + OD + {S = {v \ U. w(v) \ c / 2} \ L = {v \ U. w(v) > c / 2}}" + by vcg (auto simp: some_in_eq) + +subsection \The Proposed Approximation Algorithm\ + +subsubsection \Functional Correctness\ + +text \According to the article, \inv\<^sub>1\ holds if \P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V}\ + is a correct solution for the bin packing problem @{cite BerghammerR03}. However, various + assumptions made in the article seem to suggest that more information is demanded from this + invariant and, indeed, mere correctness (as defined in @{thm [source] bp_def}) does not appear to suffice. + To amend this, four additional conjuncts have been added to this invariant, whose necessity + will be explained in the following proofs. It should be noted that there may be other (shorter) ways to amend this invariant. + This approach, however, makes for rather straight-forward proofs, as these conjuncts can be utilized and proved in relatively few steps.\ +definition inv\<^sub>1 :: "'a set set \ 'a set set \ 'a set \ 'a set \ 'a set \ bool" where + "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V \ bp (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V}) \ \A correct solution to the bin packing problem\ + \ \(P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2) = U - V \ \The partial solution does not contain objects that have not yet been assigned\ + \ B\<^sub>1 \ (P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2) \ \\B\<^sub>1\ is distinct from all the other bins\ + \ B\<^sub>2 \ (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2) \ \\B\<^sub>2\ is distinct from all the other bins\ + \ (P\<^sub>1 \ wrap B\<^sub>1) \ (P\<^sub>2 \ wrap B\<^sub>2) = {} \ \The first and second partial solutions are disjoint from each other.\" +(* +lemma "partition_on U (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V}) \ u \ V \ +partition_on U (P\<^sub>1 \ wrap (insert u B\<^sub>1) \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ (V-{u})})" + nitpick*) +lemma inv\<^sub>1E: + assumes "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" + shows "bp (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V})" + and "\(P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2) = U - V" + and "B\<^sub>1 \ (P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2)" + and "B\<^sub>2 \ (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2)" + and "(P\<^sub>1 \ wrap B\<^sub>1) \ (P\<^sub>2 \ wrap B\<^sub>2) = {}" + using assms unfolding inv\<^sub>1_def by auto + +lemma inv\<^sub>1I: + assumes "bp (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V})" + and "\(P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2) = U - V" + and "B\<^sub>1 \ (P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2)" + and "B\<^sub>2 \ (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2)" + and "(P\<^sub>1 \ wrap B\<^sub>1) \ (P\<^sub>2 \ wrap B\<^sub>2) = {}" + shows "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" + using assms unfolding inv\<^sub>1_def by blast + +lemma wrap_Un [simp]: "wrap (M \ {x}) = {M \ {x}}" unfolding wrap_def by simp +lemma wrap_empty [simp]: "wrap {} = {}" unfolding wrap_def by simp +lemma wrap_not_empty [simp]: "M \ {} \ wrap M = {M}" unfolding wrap_def by simp + +text \If \inv\<^sub>1\ holds for the current partial solution, and the weight of an object \u \ V\ added to \B\<^sub>1\ does + not exceed its capacity, then \inv\<^sub>1\ also holds if \B\<^sub>1\ and \{u}\ are replaced by \B\<^sub>1 \ {u}\.\ +lemma inv\<^sub>1_stepA: + assumes "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" "u \ V" "W(B\<^sub>1) + w(u) \ c" + shows "inv\<^sub>1 P\<^sub>1 P\<^sub>2 (B\<^sub>1 \ {u}) B\<^sub>2 (V - {u})" +proof - + note invrules = inv\<^sub>1E[OF assms(1)] and bprules = bpE[OF invrules(1)] + + text \In the proof for \Theorem 3.2\ of the article it is erroneously argued that + if \P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V}\ is a partition of \U\, + then the same holds if \B\<^sub>1\ is replaced by \B\<^sub>1 \ {u}\. + This is, however, not necessarily the case if \B\<^sub>1\ or \{u}\ are already contained in the partial solution. + Suppose \P\<^sub>1\ contains the non-empty bin \B\<^sub>1\, then \P\<^sub>1 \ wrap B\<^sub>1\ would still be pairwise disjoint, provided \P\<^sub>1\ was pairwise disjoint before, as the union simply ignores the duplicate \B\<^sub>1\. Now, if the algorithm modifies \B\<^sub>1\ by adding an element from \V\ such that \B\<^sub>1\ becomes some non-empty \B\<^sub>1'\ with \B\<^sub>1 \ B\<^sub>1' \ \\ and \B\<^sub>1' \ P\<^sub>1\, one can see that this property would no longer be preserved. + To avoid such a situation, we will use the first additional conjunct in \inv\<^sub>1\ to ensure that \{u}\ + is not yet contained in the partial solution, and the second additional conjunct to ensure that \B\<^sub>1\ + is not yet contained in the partial solution.\ + + \ \Rule 1: Pairwise Disjoint\ + have NOTIN: "\M \ P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}. u \ M" + using invrules(2) assms(2) by blast + have "{{v} |v. v \ V} = {{u}} \ {{v} |v. v \ V - {u}}" + using assms(2) by blast + then have "pairwise disjnt (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ ({{u}} \ {{v} |v. v \ V - {u}}))" + using bprules(1) assms(2) by simp + then have "pairwise disjnt (wrap B\<^sub>1 \ {{u}} \ P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}})" by (simp add: Un_commute) + then have assm: "pairwise disjnt (wrap B\<^sub>1 \ {{u}} \ (P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}))" by (simp add: Un_assoc) + have "pairwise disjnt ({B\<^sub>1 \ {u}} \ (P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}))" + proof (cases \B\<^sub>1 = {}\) + case True with assm show ?thesis by simp + next + case False + with assm have assm: "pairwise disjnt ({B\<^sub>1} \ {{u}} \ (P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}))" by simp + from NOTIN have "{u} \ P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}" by blast + from pairwise_disjnt_Un[OF assm _ this] invrules(2,3) show ?thesis + using False by auto + qed + then have 1: "pairwise disjnt (P\<^sub>1 \ wrap (B\<^sub>1 \ {u}) \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}})" + unfolding wrap_Un by simp + + \ \Rule 2: No empty sets\ + from bprules(2) have 2: "{} \ P\<^sub>1 \ wrap (B\<^sub>1 \ {u}) \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}" + unfolding wrap_def by simp + + \ \Rule 3: Union preserved\ + from bprules(3) have "\ (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{u}} \ {{v} |v. v \ V - {u}}) = U" + using assms(2) by blast + then have 3: "\ (P\<^sub>1 \ wrap (B\<^sub>1 \ {u}) \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}) = U" + unfolding wrap_def by force + + \ \Rule 4: Weights below capacity\ + have "0 < w u" using weight assms(2) bprules(3) by blast + have "finite B\<^sub>1" using bprules(3) U_Finite by (cases \B\<^sub>1 = {}\) auto + then have "W (B\<^sub>1 \ {u}) \ W B\<^sub>1 + w u" using \0 < w u\ by (cases \u \ B\<^sub>1\) (auto simp: insert_absorb) + also have "... \ c" using assms(3) . + finally have "W (B\<^sub>1 \ {u}) \ c" . + then have "\B \ wrap (B\<^sub>1 \ {u}). W B \ c" unfolding wrap_Un by blast + moreover have "\B\P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}. W B \ c" + using bprules(4) by blast + ultimately have 4: "\B\P\<^sub>1 \ wrap (B\<^sub>1 \ {u}) \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}. W B \ c" by blast + from bpI[OF 1 2 3 4] have 1: "bp (P\<^sub>1 \ wrap (B\<^sub>1 \ {u}) \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}})" . + + \ \Auxiliary information is preserved\ + have "u \ U" using assms(2) bprules(3) by blast + then have R: "U - (V - {u}) = U - V \ {u}" by blast + have L: "\ (P\<^sub>1 \ wrap (B\<^sub>1 \ {u}) \ P\<^sub>2 \ wrap B\<^sub>2) = \ (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2) \ {u}" + unfolding wrap_def using NOTIN by auto + have 2: "\ (P\<^sub>1 \ wrap (B\<^sub>1 \ {u}) \ P\<^sub>2 \ wrap B\<^sub>2) = U - (V - {u})" + unfolding L R invrules(2) .. + have 3: "B\<^sub>1 \ {u} \ P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2" + using NOTIN by auto + have 4: "B\<^sub>2 \ P\<^sub>1 \ wrap (B\<^sub>1 \ {u}) \ P\<^sub>2" + using invrules(4) NOTIN unfolding wrap_def by fastforce + have 5: "(P\<^sub>1 \ wrap (B\<^sub>1 \ {u})) \ (P\<^sub>2 \ wrap B\<^sub>2) = {}" + using invrules(5) NOTIN unfolding wrap_Un by auto + + from inv\<^sub>1I[OF 1 2 3 4 5] show ?thesis . +qed + +text \If \inv\<^sub>1\ holds for the current partial solution, and the weight of an object \u \ V\ added to \B\<^sub>2\ does + not exceed its capacity, then \inv\<^sub>1\ also holds if \B\<^sub>2\ and \{u}\ are replaced by \B\<^sub>2 \ {u}\.\ +lemma inv\<^sub>1_stepB: + assumes "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" "u \ V" "W B\<^sub>2 + w u \ c" + shows "inv\<^sub>1 (P\<^sub>1 \ wrap B\<^sub>1) P\<^sub>2 {} (B\<^sub>2 \ {u}) (V - {u})" +proof - + note invrules = inv\<^sub>1E[OF assms(1)] and bprules = bpE[OF invrules(1)] + +text \The argumentation here is similar to the one in @{thm [source] inv\<^sub>1_stepA} with + \B\<^sub>1\ replaced with \B\<^sub>2\ and using the first and third additional conjuncts of \inv\<^sub>1\ + to amend the issue, instead of the first and second.\ + \ \Rule 1: Pairwise Disjoint\ + have NOTIN: "\M \ P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}. u \ M" + using invrules(2) assms(2) by blast + have "{{v} |v. v \ V} = {{u}} \ {{v} |v. v \ V - {u}}" + using assms(2) by blast + then have "pairwise disjnt (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{u}} \ {{v} |v. v \ V - {u}})" + using bprules(1) assms(2) by simp + then have assm: "pairwise disjnt (wrap B\<^sub>2 \ {{u}} \ (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ {{v} |v. v \ V - {u}}))" + by (simp add: Un_assoc Un_commute) + have "pairwise disjnt ({B\<^sub>2 \ {u}} \ (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ {{v} |v. v \ V - {u}}))" + proof (cases \B\<^sub>2 = {}\) + case True with assm show ?thesis by simp + next + case False + with assm have assm: "pairwise disjnt ({B\<^sub>2} \ {{u}} \ (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ {{v} |v. v \ V - {u}}))" by simp + from NOTIN have "{u} \ P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ {{v} |v. v \ V - {u}}" by blast + from pairwise_disjnt_Un[OF assm _ this] invrules(2,4) show ?thesis + using False by auto + qed + then have 1: "pairwise disjnt (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ P\<^sub>2 \ wrap (B\<^sub>2 \ {u}) \ {{v} |v. v \ V - {u}})" + unfolding wrap_Un by simp + + \ \Rule 2: No empty sets\ + from bprules(2) have 2: "{} \ P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ P\<^sub>2 \ wrap (B\<^sub>2 \ {u}) \ {{v} |v. v \ V - {u}}" + unfolding wrap_def by simp + + \ \Rule 3: Union preserved\ + from bprules(3) have "\ (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{u}} \ {{v} |v. v \ V - {u}}) = U" + using assms(2) by blast + then have 3: "\ (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ P\<^sub>2 \ wrap (B\<^sub>2 \ {u}) \ {{v} |v. v \ V - {u}}) = U" + unfolding wrap_def by force + + \ \Rule 4: Weights below capacity\ + have "0 < w u" using weight assms(2) bprules(3) by blast + have "finite B\<^sub>2" using bprules(3) U_Finite by (cases \B\<^sub>2 = {}\) auto + then have "W (B\<^sub>2 \ {u}) \ W B\<^sub>2 + w u" using \0 < w u\ by (cases \u \ B\<^sub>2\) (auto simp: insert_absorb) + also have "... \ c" using assms(3) . + finally have "W (B\<^sub>2 \ {u}) \ c" . + then have "\B \ wrap (B\<^sub>2 \ {u}). W B \ c" unfolding wrap_Un by blast + moreover have "\B\P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ {{v} |v. v \ V - {u}}. W B \ c" + using bprules(4) by blast + ultimately have 4: "\B\P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ P\<^sub>2 \ wrap (B\<^sub>2 \ {u}) \ {{v} |v. v \ V - {u}}. W B \ c" + by auto + from bpI[OF 1 2 3 4] have 1: "bp (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ P\<^sub>2 \ wrap (B\<^sub>2 \ {u}) \ {{v} |v. v \ V - {u}})" . + + \ \Auxiliary information is preserved\ + have "u \ U" using assms(2) bprules(3) by blast + then have R: "U - (V - {u}) = U - V \ {u}" by blast + have L: "\ (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ P\<^sub>2 \ wrap (B\<^sub>2 \ {u})) = \ (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ P\<^sub>2 \ wrap B\<^sub>2) \ {u}" + unfolding wrap_def using NOTIN by auto + have 2: "\ (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ P\<^sub>2 \ wrap (B\<^sub>2 \ {u})) = U - (V - {u})" + unfolding L R using invrules(2) by simp + have 3: "{} \ P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap (B\<^sub>2 \ {u})" + using bpE(2)[OF 1] by simp + have 4: "B\<^sub>2 \ {u} \ P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ P\<^sub>2" + using NOTIN by auto + have 5: "(P\<^sub>1 \ wrap B\<^sub>1 \ wrap {}) \ (P\<^sub>2 \ wrap (B\<^sub>2 \ {u})) = {}" + using invrules(5) NOTIN unfolding wrap_empty wrap_Un by auto + + from inv\<^sub>1I[OF 1 2 3 4 5] show ?thesis . +qed + +text \If \inv\<^sub>1\ holds for the current partial solution, then \inv\<^sub>1\ also holds if \B\<^sub>1\ and \B\<^sub>2\ are + added to \P\<^sub>1\ and \P\<^sub>2\ respectively, \B\<^sub>1\ is emptied and \B\<^sub>2\ initialized with \u \ V\.\ +lemma inv\<^sub>1_stepC: + assumes "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" "u \ V" + shows "inv\<^sub>1 (P\<^sub>1 \ wrap B\<^sub>1) (P\<^sub>2 \ wrap B\<^sub>2) {} {u} (V - {u})" +proof - + note invrules = inv\<^sub>1E[OF assms(1)] + \ \Rule 1-4: Correct Bin Packing\ + have "P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ (P\<^sub>2 \ wrap B\<^sub>2) \ wrap {u} \ {{v} |v. v \ V - {u}} + = P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{u}} \ {{v} |v. v \ V - {u}}" + by (metis (no_types, lifting) Un_assoc Un_empty_right insert_not_empty wrap_empty wrap_not_empty) + also have "... = P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V}" + using assms(2) by auto + finally have EQ: "P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ (P\<^sub>2 \ wrap B\<^sub>2) \ wrap {u} \ {{v} |v. v \ V - {u}} + = P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V}" . + from invrules(1) have 1: "bp (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ (P\<^sub>2 \ wrap B\<^sub>2) \ wrap {u} \ {{v} |v. v \ V - {u}})" + unfolding EQ . + + \ \Auxiliary information is preserved\ + have NOTIN: "\M \ P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}. u \ M" + using invrules(2) assms(2) by blast + have "u \ U" using assms(2) bpE(3)[OF invrules(1)] by blast + then have R: "U - (V - {u}) = U - V \ {u}" by blast + have L: "\ (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ (P\<^sub>2 \ wrap B\<^sub>2) \ wrap {u}) = \ (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ (P\<^sub>2 \ wrap B\<^sub>2)) \ {u}" + unfolding wrap_def using NOTIN by auto + have 2: "\ (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ (P\<^sub>2 \ wrap B\<^sub>2) \ wrap {u}) = U - (V - {u})" + unfolding L R using invrules(2) by auto + have 3: "{} \ P\<^sub>1 \ wrap B\<^sub>1 \ (P\<^sub>2 \ wrap B\<^sub>2) \ wrap {u}" + using bpE(2)[OF 1] by simp + have 4: "{u} \ P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ (P\<^sub>2 \ wrap B\<^sub>2)" + using NOTIN by auto + have 5: "(P\<^sub>1 \ wrap B\<^sub>1 \ wrap {}) \ (P\<^sub>2 \ wrap B\<^sub>2 \ wrap {u}) = {}" + using invrules(5) NOTIN unfolding wrap_def by force + + from inv\<^sub>1I[OF 1 2 3 4 5] show ?thesis . +qed + +text \A simplified version of the bin packing algorithm proposed in the article. + It serves as an introduction into the approach taken, and, while it does not provide the desired + approximation factor, it does ensure that \P\ is a correct solution of the bin packing problem.\ +lemma simple_bp_correct: +"VARS P P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V u + {True} + P\<^sub>1 := {}; P\<^sub>2 := {}; B\<^sub>1 := {}; B\<^sub>2 := {}; V := U; + WHILE V \ S \ {} INV {inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V} DO + u := (SOME u. u \ V); V := V - {u}; + IF W(B\<^sub>1) + w(u) \ c + THEN B\<^sub>1 := B\<^sub>1 \ {u} + ELSE IF W(B\<^sub>2) + w(u) \ c + THEN B\<^sub>2 := B\<^sub>2 \ {u} + ELSE P\<^sub>2 := P\<^sub>2 \ wrap B\<^sub>2; B\<^sub>2 := {u} FI; + P\<^sub>1 := P\<^sub>1 \ wrap B\<^sub>1; B\<^sub>1 := {} FI + OD; + P := P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} | v. v \ V} + {bp P}" +proof (vcg, goal_cases) + case (1 P P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V u) + show ?case + unfolding bp_def partition_on_def pairwise_def wrap_def inv\<^sub>1_def + using weight by auto +next + case (2 P P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V u) + then have INV: "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" .. + from 2 have "V \ {}" by blast + then have IN: "(SOME u. u \ V) \ V" by (simp add: some_in_eq) + from inv\<^sub>1_stepA[OF INV IN] inv\<^sub>1_stepB[OF INV IN] inv\<^sub>1_stepC[OF INV IN] + show ?case by blast +next + case (3 P P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V u) + then show ?case unfolding inv\<^sub>1_def by blast +qed + +subsubsection \Lower Bounds for the Bin Packing Problem\ + +lemma bp_bins_finite [simp]: + assumes "bp P" + shows "\B \ P. finite B" + using bpE(3)[OF assms] U_Finite by (meson Sup_upper finite_subset) + +lemma bp_sol_finite [simp]: + assumes "bp P" + shows "finite P" + using bpE(3)[OF assms] U_Finite by (simp add: finite_UnionD) + +text \If \P\ is a solution of the bin packing problem, then no bin in \P\ may contain more than + one large object.\ +lemma only_one_L_per_bin: + assumes "bp P" "B \ P" + shows "\x \ B. \y \ B. x \ y \ x \ L \ y \ L" +proof (rule ccontr, simp) + assume "\x\B. \y\B. x \ y \ x \ L \ y \ L" + then obtain x y where *: "x \ B" "y \ B" "x \ y" "x \ L" "y \ L" by blast + then have "c < w x + w y" using L_def S_def by force + have "finite B" using assms by simp + have "y \ B - {x}" using *(2,3) by blast + have "W B = W (B - {x}) + w x" + using *(1) \finite B\ by (simp add: sum.remove) + also have "... = W (B - {x} - {y}) + w x + w y" + using \y \ B - {x}\ \finite B\ by (simp add: sum.remove) + finally have *: "W B = W (B - {x} - {y}) + w x + w y" . + have "\u \ B. 0 < w u" using bpE(3)[OF assms(1)] assms(2) weight by blast + then have "0 \ W (B - {x} - {y})" by (smt DiffD1 sum_nonneg) + with * have "c < W B" using \c < w x + w y\ by simp + then show False using bpE(4)[OF assms(1)] assms(2) by fastforce +qed + +text \If \P\ is a solution of the bin packing problem, then the amount of large objects + is a lower bound for the amount of bins in P.\ +lemma L_lower_bound_card: + assumes "bp P" + shows "card L \ card P" +proof - + have "\x \ L. \B \ P. x \ B" + using bpE(3)[OF assms] L_def by blast + then obtain f where f_def: "\u \ L. u \ f u \ f u \ P" by metis + then have "inj_on f L" + unfolding inj_on_def using only_one_L_per_bin[OF assms] by blast + then have card_eq: "card L = card (f ` L)" by (simp add: card_image) + have "f ` L \ P" using f_def by blast + moreover have "finite P" using assms by simp + ultimately have "card (f ` L) \ card P" by (simp add: card_mono) + then show ?thesis unfolding card_eq . +qed + +text \If \P\ is a solution of the bin packing problem, then the amount of bins of a subset of P + in which every bin contains a large object is a lower bound on the amount of large objects.\ +lemma subset_bp_card: + assumes "bp P" "M \ P" "\B \ M. B \ L \ {}" + shows "card M \ card L" +proof - + have "\B \ M. \u \ L. u \ B" using assms(3) by fast + then have "\f. \B \ M. f B \ L \ f B \ B" by metis + then obtain f where f_def: "\B \ M. f B \ L \ f B \ B" .. + have "inj_on f M" + proof (rule ccontr) + assume "\ inj_on f M" + then have "\x \ M. \y \ M. x \ y \ f x = f y" unfolding inj_on_def by blast + then obtain x y where *: "x \ M" "y \ M" "x \ y" "f x = f y" by blast + then have "\u. u \ x \ u \ y" using f_def by metis + then have "x \ y \ {}" by blast + moreover have "pairwise disjnt M" using pairwise_subset[OF bpE(1)[OF assms(1)] assms(2)] . + ultimately show False using * unfolding pairwise_def disjnt_def by simp + qed + moreover have "finite L" using L_def U_Finite by blast + moreover have "f ` M \ L" using f_def by blast + ultimately show ?thesis using card_inj_on_le by blast +qed + +text \If \P\ is a correct solution of the bin packing problem, \inv\<^sub>1\ holds for the partial solution, + and every bin in \P\<^sub>1 \ wrap B\<^sub>1\ contains a large object, then the amount of bins in + \P\<^sub>1 \ wrap B\<^sub>1 \ {{v} |v. v \ V \ L}\ is a lower bound for the amount of bins in \P\.\ +lemma L_bins_lower_bound_card: + assumes "bp P" "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" "\B \ P\<^sub>1 \ wrap B\<^sub>1. B \ L \ {}" + shows "card (P\<^sub>1 \ wrap B\<^sub>1 \ {{v} |v. v \ V \ L}) \ card P" +proof - + note invrules = inv\<^sub>1E[OF assms(2)] + have "\B \ {{v} |v. v \ V \ L}. B \ L \ {}" by blast + with assms(3) have + "P\<^sub>1 \ wrap B\<^sub>1 \ {{v} |v. v \ V \ L} \ P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V}" + "\B \ P\<^sub>1 \ wrap B\<^sub>1 \ {{v} |v. v \ V \ L}. B \ L \ {}" by blast+ + from subset_bp_card[OF invrules(1) this] show ?thesis + using L_lower_bound_card[OF assms(1)] by linarith +qed + +text \If \P\ is a correct solution of the bin packing problem, then the sum of the weights of the + objects is equal to the sum of the weights of the bins in \P\.\ +lemma sum_Un_eq_sum_sum: + assumes "bp P" + shows "(\u \ U. w u) = (\B \ P. W B)" +proof - + have FINITE: "\B \ P. finite B" using assms by simp + have DISJNT: "\A \ P. \B \ P. A \ B \ A \ B = {}" + using bpE(1)[OF assms] unfolding pairwise_def disjnt_def . + have "(\u \ (\P). w u) = (\B \ P. W B)" + using sum.Union_disjoint[OF FINITE DISJNT] by auto + then show ?thesis unfolding bpE(3)[OF assms] . +qed + +text \If \P\ is a correct solution of the bin packing problem, then the sum of the weights of the items + is a lower bound of amount of bins in \P\ multiplied by their maximum capacity.\ +lemma sum_lower_bound_card: + assumes "bp P" + shows "(\u \ U. w u) \ c * card P" +proof - + have *: "\B \ P. 0 < W B \ W B \ c" + using bpE(2-4)[OF assms] weight by (metis UnionI assms bp_bins_finite sum_pos) + have "(\u \ U. w u) = (\B \ P. W B)" + using sum_Un_eq_sum_sum[OF assms] . + also have "... \ (\B \ P. c)" using sum_mono * by fastforce + also have "... = c * card P" by simp + finally show ?thesis . +qed + +lemma bp_NE: + assumes "bp P" + shows "P \ {}" + using U_NE bpE(3)[OF assms] by blast + +lemma sum_Un_ge: + fixes f :: "_ \ real" + assumes "finite M" "finite N" "\B \ M \ N. 0 < f B" + shows "sum f M \ sum f (M \ N)" +proof - + have "0 \ sum f N - sum f (M \ N)" + using assms by (smt DiffD1 inf.cobounded2 UnCI sum_mono2) + then have "sum f M \ sum f M + sum f N - sum f (M \ N)" + by simp + also have "... = sum f (M \ N)" + using sum_Un[OF assms(1,2), symmetric] . + finally show ?thesis . +qed + +text \If \bij_exists\ holds, one can obtain a function which is bijective between the bins in \P\ +and the objects in \V\ such that an object returned by the function would cause the bin to +exceed its capacity.\ +definition bij_exists :: "'a set set \ 'a set \ bool" where + "bij_exists P V = (\f. bij_betw f P V \ (\B \ P. W B + w (f B) > c))" + +text \If \P\ is a functionally correct solution of the bin packing problem, \inv\<^sub>1\ holds for the +partial solution, and such a bijective function exists between the bins in \P\<^sub>1\ and the objects in +@{term "P\<^sub>2 \ wrap B\<^sub>2"}, the following strict lower bound can be shown:\ +lemma P\<^sub>1_lower_bound_card: + assumes "bp P" "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" "bij_exists P\<^sub>1 (\(P\<^sub>2 \ wrap B\<^sub>2))" + shows "card P\<^sub>1 + 1 \ card P" +proof (cases \P\<^sub>1 = {}\) + case True + have "finite P" using assms(1) by simp + then have "1 \ card P" using bp_NE[OF assms(1)] + by (metis Nat.add_0_right Suc_diff_1 Suc_le_mono card_gt_0_iff le0 mult_Suc_right nat_mult_1) + then show ?thesis unfolding True by simp +next + note invrules = inv\<^sub>1E[OF assms(2)] + case False + obtain f where f_def: "bij_betw f P\<^sub>1 (\(P\<^sub>2 \ wrap B\<^sub>2))" "\B \ P\<^sub>1. W B + w (f B) > c" + using assms(3) unfolding bij_exists_def by blast + have FINITE: "finite P\<^sub>1" "finite (P\<^sub>2 \ wrap B\<^sub>2)" "finite (P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2)" "finite (wrap B\<^sub>1 \ {{v} |v. v \ V})" + using inv\<^sub>1E(1)[OF assms(2)] bp_sol_finite by blast+ + + have F: "\B \ P\<^sub>2 \ wrap B\<^sub>2. finite B" using invrules(1) by simp + have D: "\A \ P\<^sub>2 \ wrap B\<^sub>2. \B \ P\<^sub>2 \ wrap B\<^sub>2. A \ B \ A \ B = {}" + using bpE(1)[OF invrules(1)] unfolding pairwise_def disjnt_def by auto + have sum_eq: "W (\ (P\<^sub>2 \ wrap B\<^sub>2)) = (\B \ P\<^sub>2 \ wrap B\<^sub>2. W B)" + using sum.Union_disjoint[OF F D] by auto + + have "\B\P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V}. 0 < W B" + using bpE(2,3)[OF invrules(1)] weight by (metis (no_types, lifting) UnionI bp_bins_finite invrules(1) sum_pos) + then have "(\B \ P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2. W B) \ (\B \ P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ (wrap B\<^sub>1 \ {{v} |v. v \ V}). W B)" + using sum_Un_ge[OF FINITE(3,4), of W] by blast + also have "... = (\B \ P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V}. W B)" by (smt Un_assoc Un_commute) + also have "... = W U" using sum_Un_eq_sum_sum[OF invrules(1), symmetric] . + finally have *: "(\B \ P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2. W B) \ W U" . + + \ \This follows from the fourth and final additional conjunct of \inv\<^sub>1\ and is necessary to combine the sums of the bins + of the two partial solutions. This does not inherently follow from the union being a correct solution, + as this need not be the case if \P\<^sub>1\ and \P\<^sub>2 \ wrap B\<^sub>2\ happened to be equal.\ + have DISJNT: "P\<^sub>1 \ (P\<^sub>2 \ wrap B\<^sub>2) = {}" using invrules(5) by blast + + \ \This part of the proof is based on the proof on page 72 of the article @{cite BerghammerR03}.\ + have "c * card P\<^sub>1 = (\B \ P\<^sub>1. c)" by simp + also have "... < (\B \ P\<^sub>1. W B + w (f B))" + using f_def(2) sum_strict_mono[OF FINITE(1) False] by fastforce + also have "... = (\B \ P\<^sub>1. W B) + (\B \ P\<^sub>1. w (f B))" + by (simp add: Groups_Big.comm_monoid_add_class.sum.distrib) + also have "... = (\B \ P\<^sub>1. W B) + W (\ (P\<^sub>2 \ wrap B\<^sub>2))" unfolding sum.reindex_bij_betw[OF f_def(1), of w] .. + also have "... = (\B \ P\<^sub>1. W B) + (\B \ P\<^sub>2 \ wrap B\<^sub>2. W B)" unfolding sum_eq .. + also have "... = (\B \ P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2. W B)" using sum.union_disjoint[OF FINITE(1,2) DISJNT, of W] by (simp add: Un_assoc) + also have "... \ (\u \ U. w u)" using * . + also have "... \ c * card P" using sum_lower_bound_card[OF assms(1)] . + finally show ?thesis by (meson discrete nat_mult_less_cancel_disj of_nat_less_imp_less) +qed + +text \As @{thm wrap_card} holds, it follows that the amount of bins in \P\<^sub>1 \ wrap B\<^sub>1\ + are a lower bound for the amount of bins in \P\.\ +lemma P\<^sub>1_B\<^sub>1_lower_bound_card: + assumes "bp P" "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" "bij_exists P\<^sub>1 (\(P\<^sub>2 \ wrap B\<^sub>2))" + shows "card (P\<^sub>1 \ wrap B\<^sub>1) \ card P" +proof - + have "card (P\<^sub>1 \ wrap B\<^sub>1) \ card P\<^sub>1 + card (wrap B\<^sub>1)" + using card_Un_le by blast + also have "... \ card P\<^sub>1 + 1" using wrap_card by simp + also have "... \ card P" using P\<^sub>1_lower_bound_card[OF assms] . + finally show ?thesis . +qed + +text \If \inv\<^sub>1\ holds, there are at most half as many bins in \P\<^sub>2\ as there are objects in \P\<^sub>2\, and we can again + obtain a bijective function between the bins in \P\<^sub>1\ and the objects of the second partial solution, + then the amount of bins in the second partial solution are a strict lower bound for half the bins of + the first partial solution.\ +lemma P\<^sub>2_B\<^sub>2_lower_bound_P\<^sub>1: + assumes "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" "2 * card P\<^sub>2 \ card (\P\<^sub>2)" "bij_exists P\<^sub>1 (\(P\<^sub>2 \ wrap B\<^sub>2))" + shows "2 * card (P\<^sub>2 \ wrap B\<^sub>2) \ card P\<^sub>1 + 1" +proof - + note invrules = inv\<^sub>1E[OF assms(1)] and bprules = bpE[OF invrules(1)] + + have "pairwise disjnt (P\<^sub>2 \ wrap B\<^sub>2)" + using bprules(1) pairwise_subset by blast + moreover have "B\<^sub>2 \ P\<^sub>2" using invrules(4) by simp + ultimately have DISJNT: "\P\<^sub>2 \ B\<^sub>2 = {}" + by (auto, metis (no_types, hide_lams) sup_bot.right_neutral Un_insert_right disjnt_iff mk_disjoint_insert pairwise_insert wrap_Un) + + have "finite (\P\<^sub>2)" using U_Finite bprules(3) by auto + have "finite B\<^sub>2" using bp_bins_finite[OF invrules(1)] wrap_not_empty by blast + have "finite P\<^sub>2" "finite (wrap B\<^sub>2)" using bp_sol_finite[OF invrules(1)] by blast+ + have DISJNT2: "P\<^sub>2 \ wrap B\<^sub>2 = {}" unfolding wrap_def using \B\<^sub>2 \ P\<^sub>2\ by auto + have "card (wrap B\<^sub>2) \ card B\<^sub>2" + proof (cases \B\<^sub>2 = {}\) + case False + then have "1 \ card B\<^sub>2" by (simp add: leI \finite B\<^sub>2\) + then show ?thesis using wrap_card[of B\<^sub>2] by linarith + qed simp + + \ \This part of the proof is based on the proof on page 73 of the article @{cite BerghammerR03}.\ + from assms(2) have "2 * card P\<^sub>2 + 2 * card (wrap B\<^sub>2) \ card (\P\<^sub>2) + card (wrap B\<^sub>2) + 1" + using wrap_card[of B\<^sub>2] by linarith + then have "2 * (card P\<^sub>2 + card (wrap B\<^sub>2)) \ card (\P\<^sub>2) + card B\<^sub>2 + 1" + using \card (wrap B\<^sub>2) \ card B\<^sub>2\ by simp + then have "2 * (card (P\<^sub>2 \ wrap B\<^sub>2)) \ card (\P\<^sub>2 \ B\<^sub>2) + 1" + using card_Un_disjoint[OF \finite (\P\<^sub>2)\ \finite B\<^sub>2\ DISJNT] + and card_Un_disjoint[OF \finite P\<^sub>2\ \finite (wrap B\<^sub>2)\ DISJNT2] by argo + then have "2 * (card (P\<^sub>2 \ wrap B\<^sub>2)) \ card (\(P\<^sub>2 \ wrap B\<^sub>2)) + 1" + by (cases \B\<^sub>2 = {}\) (auto simp: Un_commute) + then show "2 * (card (P\<^sub>2 \ wrap B\<^sub>2)) \ card P\<^sub>1 + 1" + using assms(3) bij_betw_same_card unfolding bij_exists_def by metis +qed + +subsubsection \Proving the Approximation Factor\ + +text \We define \inv\<^sub>2\ as it is defined in the article. + These conjuncts allow us to prove the desired approximation factor.\ +definition inv\<^sub>2 :: "'a set set \ 'a set set \ 'a set \ 'a set \ 'a set \ bool" where + "inv\<^sub>2 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V \ inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V \ \\inv\<^sub>1\ holds for the partial solution\ + \ (V \ L \ {} \ (\B \ P\<^sub>1 \ wrap B\<^sub>1. B \ L \ {})) \ \If there are still large objects left, then every bin of the first partial solution must contain a large object\ + \ bij_exists P\<^sub>1 (\(P\<^sub>2 \ wrap B\<^sub>2)) \ \There exists a bijective function between the bins of the first partial solution and the objects of the second one\ + \ (2 * card P\<^sub>2 \ card (\P\<^sub>2)) \ \There are at most twice as many bins in \P\<^sub>2\ as there are objects in \P\<^sub>2\\" + +lemma inv\<^sub>2E: + assumes "inv\<^sub>2 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" + shows "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" + and "V \ L \ {} \ \B \ P\<^sub>1 \ wrap B\<^sub>1. B \ L \ {}" + and "bij_exists P\<^sub>1 (\(P\<^sub>2 \ wrap B\<^sub>2))" + and "2 * card P\<^sub>2 \ card (\P\<^sub>2)" + using assms unfolding inv\<^sub>2_def by blast+ + +lemma inv\<^sub>2I: + assumes "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" + and "V \ L \ {} \ \B \ P\<^sub>1 \ wrap B\<^sub>1. B \ L \ {}" + and "bij_exists P\<^sub>1 (\(P\<^sub>2 \ wrap B\<^sub>2))" + and "2 * card P\<^sub>2 \ card (\P\<^sub>2)" + shows "inv\<^sub>2 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" + using assms unfolding inv\<^sub>2_def by blast + +text \If \P\ is a correct solution of the bin packing problem, \inv\<^sub>2\ holds for the partial solution, + and there are no more small objects left to be distributed, then the amount of bins of the partial solution + is no larger than \3 / 2\ of the amount of bins in \P\. This proof strongly follows the proof in + \Theorem 4.1\ of the article @{cite BerghammerR03}.\ +lemma bin_packing_lower_bound_card: + assumes "V \ S = {}" "inv\<^sub>2 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" "bp P" + shows "card (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V}) \ 3 / 2 * card P" +proof (cases \V = {}\) + note invrules = inv\<^sub>2E[OF assms(2)] + case True + then have "card (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V}) + = card (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2)" by simp + also have "... \ card (P\<^sub>1 \ wrap B\<^sub>1) + card (P\<^sub>2 \ wrap B\<^sub>2)" + using card_Un_le[of \P\<^sub>1 \ wrap B\<^sub>1\] by (simp add: Un_assoc) + also have "... \ card P + card (P\<^sub>2 \ wrap B\<^sub>2)" + using P\<^sub>1_B\<^sub>1_lower_bound_card[OF assms(3) invrules(1,3)] by simp + also have "... \ card P + card P / 2" + using P\<^sub>2_B\<^sub>2_lower_bound_P\<^sub>1[OF invrules(1,4,3)] + and P\<^sub>1_lower_bound_card[OF assms(3) invrules(1,3)] by linarith + finally show ?thesis by linarith +next + note invrules = inv\<^sub>2E[OF assms(2)] + case False + have "U = S \ L" using S_def L_def by blast + then have *: "V = V \ L" + using bpE(3)[OF inv\<^sub>1E(1)[OF invrules(1)]] + and assms(1) by blast + with False have NE: "V \ L \ {}" by simp + have "card (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V}) + = card (P\<^sub>1 \ wrap B\<^sub>1 \ {{v} |v. v \ V \ L} \ P\<^sub>2 \ wrap B\<^sub>2)" + using * by (simp add: Un_commute Un_assoc) + also have "... \ card (P\<^sub>1 \ wrap B\<^sub>1 \ {{v} |v. v \ V \ L}) + card (P\<^sub>2 \ wrap B\<^sub>2)" + using card_Un_le[of \P\<^sub>1 \ wrap B\<^sub>1 \ {{v} |v. v \ V \ L}\] by (simp add: Un_assoc) + also have "... \ card P + card (P\<^sub>2 \ wrap B\<^sub>2)" + using L_bins_lower_bound_card[OF assms(3) invrules(1) invrules(2)[OF NE]] by linarith + also have "... \ card P + card P / 2" + using P\<^sub>2_B\<^sub>2_lower_bound_P\<^sub>1[OF invrules(1,4,3)] + and P\<^sub>1_lower_bound_card[OF assms(3) invrules(1,3)] by linarith + finally show ?thesis by linarith +qed + +text \We define \inv\<^sub>3\ as it is defined in the article. + This final conjunct allows us to prove that the invariant will be maintained by the algorithm.\ +definition inv\<^sub>3 :: "'a set set \ 'a set set \ 'a set \ 'a set \ 'a set \ bool" where + "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V \ inv\<^sub>2 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V \ B\<^sub>2 \ S" + +lemma inv\<^sub>3E: + assumes "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" + shows "inv\<^sub>2 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" and "B\<^sub>2 \ S" + using assms unfolding inv\<^sub>3_def by blast+ + +lemma inv\<^sub>3I: + assumes "inv\<^sub>2 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" and "B\<^sub>2 \ S" + shows "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" + using assms unfolding inv\<^sub>3_def by blast + +lemma loop_init: + "inv\<^sub>3 {} {} {} {} U" +proof - + have *: "inv\<^sub>1 {} {} {} {} U" + unfolding bp_def partition_on_def pairwise_def wrap_def inv\<^sub>1_def + using weight by auto + have "bij_exists {} (\ ({} \ wrap {}))" + using bij_betwI' unfolding bij_exists_def by fastforce + from inv\<^sub>2I[OF * _ this] have "inv\<^sub>2 {} {} {} {} U" by auto + from inv\<^sub>3I[OF this] show ?thesis by blast +qed + +text \If \B\<^sub>1\ is empty and there are no large objects left, then \inv\<^sub>3\ will be maintained + if \B\<^sub>1\ is initialized with \u \ V \ S\.\ +lemma loop_stepA: + assumes "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" "B\<^sub>1 = {}" "V \ L = {}" "u \ V \ S" + shows "inv\<^sub>3 P\<^sub>1 P\<^sub>2 {u} B\<^sub>2 (V - {u})" +proof - + note invrules = inv\<^sub>2E[OF inv\<^sub>3E(1)[OF assms(1)]] + have WEIGHT: "W B\<^sub>1 + w u \ c" using S_def assms(2,4) by simp + from assms(4) have "u \ V" by blast + from inv\<^sub>1_stepA[OF invrules(1) this WEIGHT] assms(2) have 1: "inv\<^sub>1 P\<^sub>1 P\<^sub>2 {u} B\<^sub>2 (V - {u})" by simp + have 2: "(V - {u}) \ L \ {} \ \B\P\<^sub>1 \ wrap {u}. B \ L \ {}" using assms(3) by blast + from inv\<^sub>2I[OF 1 2] invrules have "inv\<^sub>2 P\<^sub>1 P\<^sub>2 {u} B\<^sub>2 (V - {u})" by blast + from inv\<^sub>3I[OF this] show ?thesis using inv\<^sub>3E(2)[OF assms(1)] . +qed + +text \If \B\<^sub>1\ is empty and there are large objects left, then \inv\<^sub>3\ will be maintained + if \B\<^sub>1\ is initialized with \u \ V \ L\.\ +lemma loop_stepB: + assumes "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" "B\<^sub>1 = {}" "u \ V \ L" + shows "inv\<^sub>3 P\<^sub>1 P\<^sub>2 {u} B\<^sub>2 (V - {u})" +proof - + note invrules = inv\<^sub>2E[OF inv\<^sub>3E(1)[OF assms(1)]] + have WEIGHT: "W B\<^sub>1 + w u \ c" using L_def weight assms(2,3) by simp + from assms(3) have "u \ V" by blast + from inv\<^sub>1_stepA[OF invrules(1) this WEIGHT] assms(2) have 1: "inv\<^sub>1 P\<^sub>1 P\<^sub>2 {u} B\<^sub>2 (V - {u})" by simp + have "\B\P\<^sub>1. B \ L \ {}" using assms(3) invrules(2) by blast + then have 2: "(V - {u}) \ L \ {} \ \B\P\<^sub>1 \ wrap {u}. B \ L \ {}" + using assms(3) by (metis Int_iff UnE empty_iff insertE singletonI wrap_not_empty) + from inv\<^sub>2I[OF 1 2] invrules have "inv\<^sub>2 P\<^sub>1 P\<^sub>2 {u} B\<^sub>2 (V - {u})" by blast + from inv\<^sub>3I[OF this] show ?thesis using inv\<^sub>3E(2)[OF assms(1)] . +qed + +text \If \B\<^sub>1\ is not empty and \u \ V \ S\ does not exceed its maximum capacity, then \inv\<^sub>3\ + will be maintained if \B\<^sub>1\ and \{u}\ are replaced with \B\<^sub>1 \ {u}\.\ +lemma loop_stepC: + assumes "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" "B\<^sub>1 \ {}" "u \ V \ S" "W B\<^sub>1 + w(u) \ c" + shows "inv\<^sub>3 P\<^sub>1 P\<^sub>2 (B\<^sub>1 \ {u}) B\<^sub>2 (V - {u})" +proof - + note invrules = inv\<^sub>2E[OF inv\<^sub>3E(1)[OF assms(1)]] + from assms(3) have "u \ V" by blast + from inv\<^sub>1_stepA[OF invrules(1) this assms(4)] have 1: "inv\<^sub>1 P\<^sub>1 P\<^sub>2 (B\<^sub>1 \ {u}) B\<^sub>2 (V - {u})" . + have "(V - {u}) \ L \ {} \ \B\P\<^sub>1 \ wrap B\<^sub>1. B \ L \ {}" using invrules(2) by blast + then have 2: "(V - {u}) \ L \ {} \ \B\P\<^sub>1 \ wrap (B\<^sub>1 \ {u}). B \ L \ {}" + by (metis Int_commute Un_empty_right Un_insert_right assms(2) disjoint_insert(2) insert_iff wrap_not_empty) + from inv\<^sub>2I[OF 1 2] invrules have "inv\<^sub>2 P\<^sub>1 P\<^sub>2 (B\<^sub>1 \ {u}) B\<^sub>2 (V - {u})" by blast + from inv\<^sub>3I[OF this] show ?thesis using inv\<^sub>3E(2)[OF assms(1)] . +qed + +text \If \B\<^sub>1\ is not empty and \u \ V \ S\ does exceed its maximum capacity but not the capacity of \B\<^sub>2\, + then \inv\<^sub>3\ will be maintained if \B\<^sub>1\ is added to \P\<^sub>1\ and emptied, and \B\<^sub>2\ and \{u}\ are replaced with \B\<^sub>2 \ {u}\.\ +lemma loop_stepD: + assumes "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" "B\<^sub>1 \ {}" "u \ V \ S" "W B\<^sub>1 + w(u) > c" "W B\<^sub>2 + w(u) \ c" + shows "inv\<^sub>3 (P\<^sub>1 \ wrap B\<^sub>1) P\<^sub>2 {} (B\<^sub>2 \ {u}) (V - {u})" +proof - + note invrules = inv\<^sub>2E[OF inv\<^sub>3E(1)[OF assms(1)]] + from assms(3) have "u \ V" by blast + from inv\<^sub>1_stepB[OF invrules(1) this assms(5)] have 1: "inv\<^sub>1 (P\<^sub>1 \ wrap B\<^sub>1) P\<^sub>2 {} (B\<^sub>2 \ {u}) (V - {u})" . + + have 2: "(V - {u}) \ L \ {} \ \B\P\<^sub>1 \ wrap B\<^sub>1 \ wrap {}. B \ L \ {}" + using invrules(2) unfolding wrap_empty by blast + + from invrules(3) obtain f where f_def: "bij_betw f P\<^sub>1 (\ (P\<^sub>2 \ wrap B\<^sub>2))" "\B\P\<^sub>1. c < W B + w (f B)" unfolding bij_exists_def by blast + have "B\<^sub>1 \ P\<^sub>1" using inv\<^sub>1E(3)[OF invrules(1)] by blast + have "u \ (\ (P\<^sub>2 \ wrap B\<^sub>2))" using inv\<^sub>1E(2)[OF invrules(1)] assms(3) by blast + then have "(\ (P\<^sub>2 \ wrap (B\<^sub>2 \ {u}))) = (\ (P\<^sub>2 \ wrap B\<^sub>2 \ {{u}}))" + by (metis Sup_empty Un_assoc Union_Un_distrib ccpo_Sup_singleton wrap_empty wrap_not_empty) + also have "... = (\ (P\<^sub>2 \ wrap B\<^sub>2)) \ {u}" by simp + finally have UN: "(\ (P\<^sub>2 \ wrap (B\<^sub>2 \ {u}))) = (\ (P\<^sub>2 \ wrap B\<^sub>2)) \ {u}" . + have "wrap B\<^sub>1 = {B\<^sub>1}" using wrap_not_empty[of B\<^sub>1] assms(2) by simp + let ?f = "f (B\<^sub>1 := u)" + have BIJ: "bij_betw ?f (P\<^sub>1 \ wrap B\<^sub>1) (\ (P\<^sub>2 \ wrap (B\<^sub>2 \ {u})))" + unfolding wrap_empty \wrap B\<^sub>1 = {B\<^sub>1}\ UN using f_def(1) \B\<^sub>1 \ P\<^sub>1\ \u \ (\ (P\<^sub>2 \ wrap B\<^sub>2))\ + by (metis (no_types, lifting) bij_betw_cong fun_upd_other fun_upd_same notIn_Un_bij_betw3) + have "c < W B\<^sub>1 + w (?f B\<^sub>1)" using assms(4) by simp + then have "(\B\P\<^sub>1 \ wrap B\<^sub>1. c < W B + w (?f B))" + unfolding \wrap B\<^sub>1 = {B\<^sub>1}\ using f_def(2) by simp + with BIJ have "bij_betw ?f (P\<^sub>1 \ wrap B\<^sub>1) (\ (P\<^sub>2 \ wrap (B\<^sub>2 \ {u}))) + \ (\B\P\<^sub>1 \ wrap B\<^sub>1. c < W B + w (?f B))" by blast + then have 3: "bij_exists (P\<^sub>1 \ wrap B\<^sub>1) (\ (P\<^sub>2 \ wrap (B\<^sub>2 \ {u})))" + unfolding bij_exists_def by blast + from inv\<^sub>2I[OF 1 2 3] have "inv\<^sub>2 (P\<^sub>1 \ wrap B\<^sub>1) P\<^sub>2 {} (B\<^sub>2 \ {u}) (V - {u})" using invrules(4) by blast + + from inv\<^sub>3I[OF this] show ?thesis using inv\<^sub>3E(2)[OF assms(1)] assms(3) by blast +qed + +text \If the maximum capacity of \B\<^sub>2\ is exceeded by \u \ V \ S\, + then \B\<^sub>2\ must contain at least two objects.\ +lemma B\<^sub>2_at_least_two_objects: + assumes "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" "u \ V \ S" "W B\<^sub>2 + w(u) > c" + shows "2 \ card B\<^sub>2" +proof (rule ccontr, simp add: not_le) + have FINITE: "finite B\<^sub>2" using inv\<^sub>1E(1)[OF inv\<^sub>2E(1)[OF inv\<^sub>3E(1)[OF assms(1)]]] + by (metis (no_types, lifting) Finite_Set.finite.simps U_Finite Union_Un_distrib bpE(3) ccpo_Sup_singleton finite_Un wrap_not_empty) + assume "card B\<^sub>2 < 2" + then consider (0) "card B\<^sub>2 = 0" | (1) "card B\<^sub>2 = 1" by linarith + then show False proof cases + case 0 then have "B\<^sub>2 = {}" using FINITE by simp + then show ?thesis using assms(2,3) S_def by simp + next + case 1 then obtain v where "B\<^sub>2 = {v}" + using card_1_singletonE by auto + with inv\<^sub>3E(2)[OF assms(1)] have "2 * w v \ c" using S_def by simp + moreover from \B\<^sub>2 = {v}\ have "W B\<^sub>2 = w v" by simp + ultimately show ?thesis using assms(2,3) S_def by simp + qed +qed + +text \If \B\<^sub>1\ is not empty and \u \ V \ S\ exceeds the maximum capacity of both \B\<^sub>1\ and \B\<^sub>2\, + then \inv\<^sub>3\ will be maintained if \B\<^sub>1\ and \B\<^sub>2\ are added to \P\<^sub>1\ and \P\<^sub>2\ respectively, + emptied, and \B\<^sub>2\ initialized with \u\.\ +lemma loop_stepE: + assumes "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" "B\<^sub>1 \ {}" "u \ V \ S" "W B\<^sub>1 + w(u) > c" "W B\<^sub>2 + w(u) > c" + shows "inv\<^sub>3 (P\<^sub>1 \ wrap B\<^sub>1) (P\<^sub>2 \ wrap B\<^sub>2) {} {u} (V - {u})" +proof - + note invrules = inv\<^sub>2E[OF inv\<^sub>3E(1)[OF assms(1)]] + from assms(3) have "u \ V" by blast + from inv\<^sub>1_stepC[OF invrules(1) this] have 1: "inv\<^sub>1 (P\<^sub>1 \ wrap B\<^sub>1) (P\<^sub>2 \ wrap B\<^sub>2) {} {u} (V - {u})" . + + have 2: "(V - {u}) \ L \ {} \ \B\P\<^sub>1 \ wrap B\<^sub>1 \ wrap {}. B \ L \ {}" + using invrules(2) unfolding wrap_empty by blast + + from invrules(3) obtain f where f_def: "bij_betw f P\<^sub>1 (\ (P\<^sub>2 \ wrap B\<^sub>2))" "\B\P\<^sub>1. c < W B + w (f B)" unfolding bij_exists_def by blast + have "B\<^sub>1 \ P\<^sub>1" using inv\<^sub>1E(3)[OF invrules(1)] by blast + have "u \ (\ (P\<^sub>2 \ wrap B\<^sub>2))" using inv\<^sub>1E(2)[OF invrules(1)] assms(3) by blast + have "(\ (P\<^sub>2 \ wrap B\<^sub>2 \ wrap {u})) = (\ (P\<^sub>2 \ wrap B\<^sub>2 \ {{u}}))" unfolding wrap_def by simp + also have "... = (\ (P\<^sub>2 \ wrap B\<^sub>2)) \ {u}" by simp + finally have UN: "(\ (P\<^sub>2 \ wrap B\<^sub>2 \ wrap {u})) = (\ (P\<^sub>2 \ wrap B\<^sub>2)) \ {u}" . + have "wrap B\<^sub>1 = {B\<^sub>1}" using wrap_not_empty[of B\<^sub>1] assms(2) by simp + let ?f = "f (B\<^sub>1 := u)" + have BIJ: "bij_betw ?f (P\<^sub>1 \ wrap B\<^sub>1) (\ (P\<^sub>2 \ wrap B\<^sub>2 \ wrap {u}))" + unfolding wrap_empty \wrap B\<^sub>1 = {B\<^sub>1}\ UN using f_def(1) \B\<^sub>1 \ P\<^sub>1\ \u \ (\ (P\<^sub>2 \ wrap B\<^sub>2))\ + by (metis (no_types, lifting) bij_betw_cong fun_upd_other fun_upd_same notIn_Un_bij_betw3) + have "c < W B\<^sub>1 + w (?f B\<^sub>1)" using assms(4) by simp + then have "(\B\P\<^sub>1 \ wrap B\<^sub>1. c < W B + w (?f B))" + unfolding \wrap B\<^sub>1 = {B\<^sub>1}\ using f_def(2) by simp + with BIJ have "bij_betw ?f (P\<^sub>1 \ wrap B\<^sub>1) (\ (P\<^sub>2 \ wrap B\<^sub>2 \ wrap {u})) + \ (\B\P\<^sub>1 \ wrap B\<^sub>1. c < W B + w (?f B))" by blast + then have 3: "bij_exists (P\<^sub>1 \ wrap B\<^sub>1) (\ (P\<^sub>2 \ wrap B\<^sub>2 \ wrap {u}))" + unfolding bij_exists_def by blast + + have 4: "2 * card (P\<^sub>2 \ wrap B\<^sub>2) \ card (\ (P\<^sub>2 \ wrap B\<^sub>2))" + proof - + note bprules = bpE[OF inv\<^sub>1E(1)[OF invrules(1)]] + have "pairwise disjnt (P\<^sub>2 \ wrap B\<^sub>2)" + using bprules(1) pairwise_subset by blast + moreover have "B\<^sub>2 \ P\<^sub>2" using inv\<^sub>1E(4)[OF invrules(1)] by simp + ultimately have DISJNT: "\P\<^sub>2 \ B\<^sub>2 = {}" + by (auto, metis (no_types, hide_lams) sup_bot.right_neutral Un_insert_right disjnt_iff mk_disjoint_insert pairwise_insert wrap_Un) + have "finite (\P\<^sub>2)" using U_Finite bprules(3) by auto + have "finite B\<^sub>2" using inv\<^sub>1E(1)[OF invrules(1)] bp_bins_finite wrap_not_empty by blast + + have "2 * card (P\<^sub>2 \ wrap B\<^sub>2) \ 2 * (card P\<^sub>2 + card (wrap B\<^sub>2))" + using card_Un_le[of P\<^sub>2 \wrap B\<^sub>2\] by simp + also have "... \ 2 * card P\<^sub>2 + 2" using wrap_card by auto + also have "... \ card (\ P\<^sub>2) + 2" using invrules(4) by simp + also have "... \ card (\ P\<^sub>2) + card B\<^sub>2" using B\<^sub>2_at_least_two_objects[OF assms(1,3,5)] by simp + also have "... = card (\ (P\<^sub>2 \ {B\<^sub>2}))" using DISJNT card_Un_disjoint[OF \finite (\P\<^sub>2)\ \finite B\<^sub>2\] by (simp add: Un_commute) + also have "... = card (\ (P\<^sub>2 \ wrap B\<^sub>2))" by (cases \B\<^sub>2 = {}\) auto + finally show ?thesis . + qed + from inv\<^sub>2I[OF 1 2 3 4] have "inv\<^sub>2 (P\<^sub>1 \ wrap B\<^sub>1) (P\<^sub>2 \ wrap B\<^sub>2) {} {u} (V - {u})" . + + from inv\<^sub>3I[OF this] show ?thesis using assms(3) by blast +qed + +text \The bin packing algorithm as it is proposed in the article @{cite BerghammerR03}. + \P\ will not only be a correct solution of the bin packing problem, but the amount of bins + will be a lower bound for \3 / 2\ of the amount of bins of any correct solution \Q\, and thus + guarantee an approximation factor of \3 / 2\ for the optimum.\ +lemma bp_approx: +"VARS P P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V u + {True} + P\<^sub>1 := {}; P\<^sub>2 := {}; B\<^sub>1 := {}; B\<^sub>2 := {}; V := U; + WHILE V \ S \ {} INV {inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V} DO + IF B\<^sub>1 \ {} + THEN u := (SOME u. u \ V \ S) + ELSE IF V \ L \ {} + THEN u := (SOME u. u \ V \ L) + ELSE u := (SOME u. u \ V \ S) FI FI; + V := V - {u}; + IF W(B\<^sub>1) + w(u) \ c + THEN B\<^sub>1 := B\<^sub>1 \ {u} + ELSE IF W(B\<^sub>2) + w(u) \ c + THEN B\<^sub>2 := B\<^sub>2 \ {u} + ELSE P\<^sub>2 := P\<^sub>2 \ wrap B\<^sub>2; B\<^sub>2 := {u} FI; + P\<^sub>1 := P\<^sub>1 \ wrap B\<^sub>1; B\<^sub>1 := {} FI + OD; + P := P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} | v. v \ V} + {bp P \ (\Q. bp Q \ card P \ 3 / 2 * card Q)}" +proof (vcg, goal_cases) +case (1 P P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V u) + then show ?case by (simp add: loop_init) +next + case (2 P P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V u) + then have INV: "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" .. + let ?s = "SOME u. u \ V \ S" + let ?l = "SOME u. u \ V \ L" + have LIN: "V \ L \ {} \ ?l \ V \ L" using some_in_eq by metis + then have LWEIGHT: "V \ L \ {} \ w ?l \ c" using L_def weight by blast + from 2 have "V \ S \ {}" .. + then have IN: "?s \ V \ S" using some_in_eq by metis + then have "w ?s \ c" using S_def by simp + + then show ?case + using LWEIGHT loop_stepA[OF INV _ _ IN] loop_stepB[OF INV _ LIN] loop_stepC[OF INV _ IN] + and loop_stepD[OF INV _ IN] loop_stepE[OF INV _ IN] by (cases \B\<^sub>1 = {}\, cases \V \ L = {}\) auto +next + case (3 P P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V u) + then have INV: "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" and EMPTY: "V \ S = {}" by blast+ + from inv\<^sub>1E(1)[OF inv\<^sub>2E(1)[OF inv\<^sub>3E(1)[OF INV]]] and bin_packing_lower_bound_card[OF EMPTY inv\<^sub>3E(1)[OF INV]] + show ?case by blast +qed + +end (* BinPacking *) + +subsection \The Full Linear Time Version of the Proposed Algorithm\ + +text \Finally, we prove the Algorithm proposed on page 78 of the article @{cite BerghammerR03}. + This version generates the S and L sets beforehand and uses them directly to calculate the solution, + thus removing the need for intersection operations, and ensuring linear time if we can + perform \insertion, removal, and selection of an element, the union of two sets, + and the emptiness test in constant time\ @{cite BerghammerR03}.\ + +locale BinPacking_Complete = + fixes U :: "'a set" \ \A finite, non-empty set of objects\ + and w :: "'a \ real" \ \A mapping from objects to their respective weights (positive real numbers)\ + and c :: nat \ \The maximum capacity of a bin (as a natural number)\ + assumes weight: "\u \ U. 0 < w(u) \ w(u) \ c" + and U_Finite: "finite U" + and U_NE: "U \ {}" +begin + +text \The correctness proofs will be identical to the ones of the simplified algorithm.\ + +abbreviation W :: "'a set \ real" where + "W B \ (\u \ B. w(u))" + +definition bp :: "'a set set \ bool" where + "bp P \ partition_on U P \ (\B \ P. W(B) \ c)" + +lemma bpE: + assumes "bp P" + shows "pairwise disjnt P" "{} \ P" "\P = U" "\B \ P. W(B) \ c" + using assms unfolding bp_def partition_on_def by blast+ + +lemma bpI: + assumes "pairwise disjnt P" "{} \ P" "\P = U" "\B \ P. W(B) \ c" + shows "bp P" + using assms unfolding bp_def partition_on_def by blast + +definition inv\<^sub>1 :: "'a set set \ 'a set set \ 'a set \ 'a set \ 'a set \ bool" where + "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V \ bp (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V}) \ \A correct solution to the bin packing problem\ + \ \(P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2) = U - V \ \The partial solution does not contain objects that have not yet been assigned\ + \ B\<^sub>1 \ (P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2) \ \\B\<^sub>1\ is distinct from all the other bins\ + \ B\<^sub>2 \ (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2) \ \\B\<^sub>2\ is distinct from all the other bins\ + \ (P\<^sub>1 \ wrap B\<^sub>1) \ (P\<^sub>2 \ wrap B\<^sub>2) = {} \ \The first and second partial solutions are disjoint from each other.\" + +lemma inv\<^sub>1E: + assumes "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" + shows "bp (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V})" + and "\(P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2) = U - V" + and "B\<^sub>1 \ (P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2)" + and "B\<^sub>2 \ (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2)" + and "(P\<^sub>1 \ wrap B\<^sub>1) \ (P\<^sub>2 \ wrap B\<^sub>2) = {}" + using assms unfolding inv\<^sub>1_def by auto + +lemma inv\<^sub>1I: + assumes "bp (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V})" + and "\(P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2) = U - V" + and "B\<^sub>1 \ (P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2)" + and "B\<^sub>2 \ (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2)" + and "(P\<^sub>1 \ wrap B\<^sub>1) \ (P\<^sub>2 \ wrap B\<^sub>2) = {}" + shows "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" + using assms unfolding inv\<^sub>1_def by blast + +lemma wrap_Un [simp]: "wrap (M \ {x}) = {M \ {x}}" unfolding wrap_def by simp +lemma wrap_empty [simp]: "wrap {} = {}" unfolding wrap_def by simp +lemma wrap_not_empty [simp]: "M \ {} \ wrap M = {M}" unfolding wrap_def by simp + +lemma inv\<^sub>1_stepA: + assumes "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" "u \ V" "W(B\<^sub>1) + w(u) \ c" + shows "inv\<^sub>1 P\<^sub>1 P\<^sub>2 (B\<^sub>1 \ {u}) B\<^sub>2 (V - {u})" +proof - + note invrules = inv\<^sub>1E[OF assms(1)] and bprules = bpE[OF invrules(1)] + + \ \Rule 1: Pairwise Disjoint\ + have NOTIN: "\M \ P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}. u \ M" + using invrules(2) assms(2) by blast + have "{{v} |v. v \ V} = {{u}} \ {{v} |v. v \ V - {u}}" + using assms(2) by blast + then have "pairwise disjnt (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ ({{u}} \ {{v} |v. v \ V - {u}}))" + using bprules(1) assms(2) by simp + then have "pairwise disjnt (wrap B\<^sub>1 \ {{u}} \ P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}})" by (simp add: Un_commute) + then have assm: "pairwise disjnt (wrap B\<^sub>1 \ {{u}} \ (P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}))" by (simp add: Un_assoc) + have "pairwise disjnt ({B\<^sub>1 \ {u}} \ (P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}))" + proof (cases \B\<^sub>1 = {}\) + case True with assm show ?thesis by simp + next + case False + with assm have assm: "pairwise disjnt ({B\<^sub>1} \ {{u}} \ (P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}))" by simp + from NOTIN have "{u} \ P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}" by blast + from pairwise_disjnt_Un[OF assm _ this] invrules(2,3) show ?thesis + using False by auto + qed + then have 1: "pairwise disjnt (P\<^sub>1 \ wrap (B\<^sub>1 \ {u}) \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}})" + unfolding wrap_Un by simp + + \ \Rule 2: No empty sets\ + from bprules(2) have 2: "{} \ P\<^sub>1 \ wrap (B\<^sub>1 \ {u}) \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}" + unfolding wrap_def by simp + + \ \Rule 3: Union preserved\ + from bprules(3) have "\ (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{u}} \ {{v} |v. v \ V - {u}}) = U" + using assms(2) by blast + then have 3: "\ (P\<^sub>1 \ wrap (B\<^sub>1 \ {u}) \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}) = U" + unfolding wrap_def by force + + \ \Rule 4: Weights below capacity\ + have "0 < w u" using weight assms(2) bprules(3) by blast + have "finite B\<^sub>1" using bprules(3) U_Finite by (cases \B\<^sub>1 = {}\) auto + then have "W (B\<^sub>1 \ {u}) \ W B\<^sub>1 + w u" using \0 < w u\ by (cases \u \ B\<^sub>1\) (auto simp: insert_absorb) + also have "... \ c" using assms(3) . + finally have "W (B\<^sub>1 \ {u}) \ c" . + then have "\B \ wrap (B\<^sub>1 \ {u}). W B \ c" unfolding wrap_Un by blast + moreover have "\B\P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}. W B \ c" + using bprules(4) by blast + ultimately have 4: "\B\P\<^sub>1 \ wrap (B\<^sub>1 \ {u}) \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}. W B \ c" by blast + from bpI[OF 1 2 3 4] have 1: "bp (P\<^sub>1 \ wrap (B\<^sub>1 \ {u}) \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}})" . + + \ \Auxiliary information is preserved\ + have "u \ U" using assms(2) bprules(3) by blast + then have R: "U - (V - {u}) = U - V \ {u}" by blast + have L: "\ (P\<^sub>1 \ wrap (B\<^sub>1 \ {u}) \ P\<^sub>2 \ wrap B\<^sub>2) = \ (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2) \ {u}" + unfolding wrap_def using NOTIN by auto + have 2: "\ (P\<^sub>1 \ wrap (B\<^sub>1 \ {u}) \ P\<^sub>2 \ wrap B\<^sub>2) = U - (V - {u})" + unfolding L R invrules(2) .. + have 3: "B\<^sub>1 \ {u} \ P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2" + using NOTIN by auto + have 4: "B\<^sub>2 \ P\<^sub>1 \ wrap (B\<^sub>1 \ {u}) \ P\<^sub>2" + using invrules(4) NOTIN unfolding wrap_def by fastforce + have 5: "(P\<^sub>1 \ wrap (B\<^sub>1 \ {u})) \ (P\<^sub>2 \ wrap B\<^sub>2) = {}" + using invrules(5) NOTIN unfolding wrap_Un by auto + + from inv\<^sub>1I[OF 1 2 3 4 5] show ?thesis . +qed + +lemma inv\<^sub>1_stepB: + assumes "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" "u \ V" "W B\<^sub>2 + w u \ c" + shows "inv\<^sub>1 (P\<^sub>1 \ wrap B\<^sub>1) P\<^sub>2 {} (B\<^sub>2 \ {u}) (V - {u})" +proof - + note invrules = inv\<^sub>1E[OF assms(1)] and bprules = bpE[OF invrules(1)] + + have NOTIN: "\M \ P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}. u \ M" + using invrules(2) assms(2) by blast + have "{{v} |v. v \ V} = {{u}} \ {{v} |v. v \ V - {u}}" + using assms(2) by blast + then have "pairwise disjnt (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{u}} \ {{v} |v. v \ V - {u}})" + using bprules(1) assms(2) by simp + then have assm: "pairwise disjnt (wrap B\<^sub>2 \ {{u}} \ (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ {{v} |v. v \ V - {u}}))" + by (simp add: Un_assoc Un_commute) + have "pairwise disjnt ({B\<^sub>2 \ {u}} \ (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ {{v} |v. v \ V - {u}}))" + proof (cases \B\<^sub>2 = {}\) + case True with assm show ?thesis by simp + next + case False + with assm have assm: "pairwise disjnt ({B\<^sub>2} \ {{u}} \ (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ {{v} |v. v \ V - {u}}))" by simp + from NOTIN have "{u} \ P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ {{v} |v. v \ V - {u}}" by blast + from pairwise_disjnt_Un[OF assm _ this] invrules(2,4) show ?thesis + using False by auto + qed + then have 1: "pairwise disjnt (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ P\<^sub>2 \ wrap (B\<^sub>2 \ {u}) \ {{v} |v. v \ V - {u}})" + unfolding wrap_Un by simp + + \ \Rule 2: No empty sets\ + from bprules(2) have 2: "{} \ P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ P\<^sub>2 \ wrap (B\<^sub>2 \ {u}) \ {{v} |v. v \ V - {u}}" + unfolding wrap_def by simp + + \ \Rule 3: Union preserved\ + from bprules(3) have "\ (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{u}} \ {{v} |v. v \ V - {u}}) = U" + using assms(2) by blast + then have 3: "\ (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ P\<^sub>2 \ wrap (B\<^sub>2 \ {u}) \ {{v} |v. v \ V - {u}}) = U" + unfolding wrap_def by force + + \ \Rule 4: Weights below capacity\ + have "0 < w u" using weight assms(2) bprules(3) by blast + have "finite B\<^sub>2" using bprules(3) U_Finite by (cases \B\<^sub>2 = {}\) auto + then have "W (B\<^sub>2 \ {u}) \ W B\<^sub>2 + w u" using \0 < w u\ by (cases \u \ B\<^sub>2\) (auto simp: insert_absorb) + also have "... \ c" using assms(3) . + finally have "W (B\<^sub>2 \ {u}) \ c" . + then have "\B \ wrap (B\<^sub>2 \ {u}). W B \ c" unfolding wrap_Un by blast + moreover have "\B\P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ {{v} |v. v \ V - {u}}. W B \ c" + using bprules(4) by blast + ultimately have 4: "\B\P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ P\<^sub>2 \ wrap (B\<^sub>2 \ {u}) \ {{v} |v. v \ V - {u}}. W B \ c" + by auto + from bpI[OF 1 2 3 4] have 1: "bp (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ P\<^sub>2 \ wrap (B\<^sub>2 \ {u}) \ {{v} |v. v \ V - {u}})" . + + \ \Auxiliary information is preserved\ + have "u \ U" using assms(2) bprules(3) by blast + then have R: "U - (V - {u}) = U - V \ {u}" by blast + have L: "\ (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ P\<^sub>2 \ wrap (B\<^sub>2 \ {u})) = \ (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ P\<^sub>2 \ wrap B\<^sub>2) \ {u}" + unfolding wrap_def using NOTIN by auto + have 2: "\ (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ P\<^sub>2 \ wrap (B\<^sub>2 \ {u})) = U - (V - {u})" + unfolding L R using invrules(2) by simp + have 3: "{} \ P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap (B\<^sub>2 \ {u})" + using bpE(2)[OF 1] by simp + have 4: "B\<^sub>2 \ {u} \ P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ P\<^sub>2" + using NOTIN by auto + have 5: "(P\<^sub>1 \ wrap B\<^sub>1 \ wrap {}) \ (P\<^sub>2 \ wrap (B\<^sub>2 \ {u})) = {}" + using invrules(5) NOTIN unfolding wrap_empty wrap_Un by auto + + from inv\<^sub>1I[OF 1 2 3 4 5] show ?thesis . +qed + +lemma inv\<^sub>1_stepC: + assumes "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V" "u \ V" + shows "inv\<^sub>1 (P\<^sub>1 \ wrap B\<^sub>1) (P\<^sub>2 \ wrap B\<^sub>2) {} {u} (V - {u})" +proof - + note invrules = inv\<^sub>1E[OF assms(1)] + \ \Rule 1-4: Correct Bin Packing\ + have "P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ (P\<^sub>2 \ wrap B\<^sub>2) \ wrap {u} \ {{v} |v. v \ V - {u}} + = P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{u}} \ {{v} |v. v \ V - {u}}" + by (metis (no_types, lifting) Un_assoc Un_empty_right insert_not_empty wrap_empty wrap_not_empty) + also have "... = P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V}" + using assms(2) by auto + finally have EQ: "P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ (P\<^sub>2 \ wrap B\<^sub>2) \ wrap {u} \ {{v} |v. v \ V - {u}} + = P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V}" . + from invrules(1) have 1: "bp (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ (P\<^sub>2 \ wrap B\<^sub>2) \ wrap {u} \ {{v} |v. v \ V - {u}})" + unfolding EQ . + + \ \Auxiliary information is preserved\ + have NOTIN: "\M \ P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ V - {u}}. u \ M" + using invrules(2) assms(2) by blast + have "u \ U" using assms(2) bpE(3)[OF invrules(1)] by blast + then have R: "U - (V - {u}) = U - V \ {u}" by blast + have L: "\ (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ (P\<^sub>2 \ wrap B\<^sub>2) \ wrap {u}) = \ (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ (P\<^sub>2 \ wrap B\<^sub>2)) \ {u}" + unfolding wrap_def using NOTIN by auto + have 2: "\ (P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ (P\<^sub>2 \ wrap B\<^sub>2) \ wrap {u}) = U - (V - {u})" + unfolding L R using invrules(2) by auto + have 3: "{} \ P\<^sub>1 \ wrap B\<^sub>1 \ (P\<^sub>2 \ wrap B\<^sub>2) \ wrap {u}" + using bpE(2)[OF 1] by simp + have 4: "{u} \ P\<^sub>1 \ wrap B\<^sub>1 \ wrap {} \ (P\<^sub>2 \ wrap B\<^sub>2)" + using NOTIN by auto + have 5: "(P\<^sub>1 \ wrap B\<^sub>1 \ wrap {}) \ (P\<^sub>2 \ wrap B\<^sub>2 \ wrap {u}) = {}" + using invrules(5) NOTIN unfolding wrap_def by force + + from inv\<^sub>1I[OF 1 2 3 4 5] show ?thesis . +qed + +text \From this point onward, we will require a different approach for proving lower bounds. + Instead of fixing and assuming the definitions of the \S\ and \L\ sets, we will introduce + the abbreviations \S\<^sub>U\ and \L\<^sub>U\ for any occurrences of the original \S\ and \L\ sets. + The union of \S\ and \L\ can be interpreted as \V\. As a result, occurrences of \V \ S\ + become \(S \ L) \ S = S\, and \V \ L\ become \(S \ L) \ L = L\. + Occurrences of these sets will have to be replaced appropriately.\ +abbreviation S\<^sub>U where + "S\<^sub>U \ {u \ U. w u \ c / 2}" + +abbreviation L\<^sub>U where + "L\<^sub>U \ {u \ U. c / 2 < w u}" + +text \As we will remove elements from \S\ and \L\, we will only be able to show that they remain + subsets of \S\<^sub>U\ and \L\<^sub>U\ respectively.\ +abbreviation SL where + "SL S L \ S \ S\<^sub>U \ L \ L\<^sub>U" + +lemma bp_bins_finite [simp]: + assumes "bp P" + shows "\B \ P. finite B" + using bpE(3)[OF assms] U_Finite by (meson Sup_upper finite_subset) + +lemma bp_sol_finite [simp]: + assumes "bp P" + shows "finite P" + using bpE(3)[OF assms] U_Finite by (simp add: finite_UnionD) + +lemma only_one_L_per_bin: + assumes "bp P" "B \ P" + shows "\x \ B. \y \ B. x \ y \ x \ L\<^sub>U \ y \ L\<^sub>U" +proof (rule ccontr, simp) + assume "\x\B. \y\B. x \ y \ y \ U \ x \ U \ real c < w x * 2 \ real c < w y * 2" + then obtain x y where *: "x \ B" "y \ B" "x \ y" "x \ L\<^sub>U" "y \ L\<^sub>U" by auto + then have "c < w x + w y" by force + have "finite B" using assms by simp + have "y \ B - {x}" using *(2,3) by blast + have "W B = W (B - {x}) + w x" + using *(1) \finite B\ by (simp add: sum.remove) + also have "... = W (B - {x} - {y}) + w x + w y" + using \y \ B - {x}\ \finite B\ by (simp add: sum.remove) + finally have *: "W B = W (B - {x} - {y}) + w x + w y" . + have "\u \ B. 0 < w u" using bpE(3)[OF assms(1)] assms(2) weight by blast + then have "0 \ W (B - {x} - {y})" by (smt DiffD1 sum_nonneg) + with * have "c < W B" using \c < w x + w y\ by simp + then show False using bpE(4)[OF assms(1)] assms(2) by fastforce +qed + +lemma L_lower_bound_card: + assumes "bp P" + shows "card L\<^sub>U \ card P" +proof - + have "\x \ L\<^sub>U. \B \ P. x \ B" + using bpE(3)[OF assms] by blast + then obtain f where f_def: "\u \ L\<^sub>U. u \ f u \ f u \ P" by metis + then have "inj_on f L\<^sub>U" + unfolding inj_on_def using only_one_L_per_bin[OF assms] by blast + then have card_eq: "card L\<^sub>U = card (f ` L\<^sub>U)" by (simp add: card_image) + have "f ` L\<^sub>U \ P" using f_def by blast + moreover have "finite P" using assms by simp + ultimately have "card (f ` L\<^sub>U) \ card P" by (simp add: card_mono) + then show ?thesis unfolding card_eq . +qed + +lemma subset_bp_card: + assumes "bp P" "M \ P" "\B \ M. B \ L\<^sub>U \ {}" + shows "card M \ card L\<^sub>U" +proof - + have "\B \ M. \u \ L\<^sub>U. u \ B" using assms(3) by fast + then have "\f. \B \ M. f B \ L\<^sub>U \ f B \ B" by metis + then obtain f where f_def: "\B \ M. f B \ L\<^sub>U \ f B \ B" .. + have "inj_on f M" + proof (rule ccontr) + assume "\ inj_on f M" + then have "\x \ M. \y \ M. x \ y \ f x = f y" unfolding inj_on_def by blast + then obtain x y where *: "x \ M" "y \ M" "x \ y" "f x = f y" by blast + then have "\u. u \ x \ u \ y" using f_def by metis + then have "x \ y \ {}" by blast + moreover have "pairwise disjnt M" using pairwise_subset[OF bpE(1)[OF assms(1)] assms(2)] . + ultimately show False using * unfolding pairwise_def disjnt_def by simp + qed + moreover have "finite L\<^sub>U" using U_Finite by auto + moreover have "f ` M \ L\<^sub>U" using f_def by blast + ultimately show ?thesis using card_inj_on_le by blast +qed + +lemma L_bins_lower_bound_card: + assumes "bp P" "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 (S \ L)" "\B \ P\<^sub>1 \ wrap B\<^sub>1. B \ L\<^sub>U \ {}" + and SL_def: "SL S L" + shows "card (P\<^sub>1 \ wrap B\<^sub>1 \ {{v} |v. v \ L}) \ card P" +proof - + note invrules = inv\<^sub>1E[OF assms(2)] + have "\B \ {{v} |v. v \ L}. B \ L\<^sub>U \ {}" using SL_def by blast + with assms(3) have + "P\<^sub>1 \ wrap B\<^sub>1 \ {{v} |v. v \ L} \ P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ S \ L}" + "\B \ P\<^sub>1 \ wrap B\<^sub>1 \ {{v} |v. v \ L}. B \ L\<^sub>U \ {}" by blast+ + from subset_bp_card[OF invrules(1) this] show ?thesis + using L_lower_bound_card[OF assms(1)] by linarith +qed + +lemma sum_Un_eq_sum_sum: + assumes "bp P" + shows "(\u \ U. w u) = (\B \ P. W B)" +proof - + have FINITE: "\B \ P. finite B" using assms by simp + have DISJNT: "\A \ P. \B \ P. A \ B \ A \ B = {}" + using bpE(1)[OF assms] unfolding pairwise_def disjnt_def . + have "(\u \ (\P). w u) = (\B \ P. W B)" + using sum.Union_disjoint[OF FINITE DISJNT] by auto + then show ?thesis unfolding bpE(3)[OF assms] . +qed + +lemma sum_lower_bound_card: + assumes "bp P" + shows "(\u \ U. w u) \ c * card P" +proof - + have *: "\B \ P. 0 < W B \ W B \ c" + using bpE(2-4)[OF assms] weight by (metis UnionI assms bp_bins_finite sum_pos) + have "(\u \ U. w u) = (\B \ P. W B)" + using sum_Un_eq_sum_sum[OF assms] . + also have "... \ (\B \ P. c)" using sum_mono * by fastforce + also have "... = c * card P" by simp + finally show ?thesis . +qed + +lemma bp_NE: + assumes "bp P" + shows "P \ {}" + using U_NE bpE(3)[OF assms] by blast + +lemma sum_Un_ge: + fixes f :: "_ \ real" + assumes "finite M" "finite N" "\B \ M \ N. 0 < f B" + shows "sum f M \ sum f (M \ N)" +proof - + have "0 \ sum f N - sum f (M \ N)" + using assms by (smt DiffD1 inf.cobounded2 UnCI sum_mono2) + then have "sum f M \ sum f M + sum f N - sum f (M \ N)" + by simp + also have "... = sum f (M \ N)" + using sum_Un[OF assms(1,2), symmetric] . + finally show ?thesis . +qed + +definition bij_exists :: "'a set set \ 'a set \ bool" where + "bij_exists P V = (\f. bij_betw f P V \ (\B \ P. W B + w (f B) > c))" + +lemma P\<^sub>1_lower_bound_card: + assumes "bp P" "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 (S \ L)" "bij_exists P\<^sub>1 (\(P\<^sub>2 \ wrap B\<^sub>2))" + shows "card P\<^sub>1 + 1 \ card P" +proof (cases \P\<^sub>1 = {}\) + case True + have "finite P" using assms(1) by simp + then have "1 \ card P" using bp_NE[OF assms(1)] + by (metis Nat.add_0_right Suc_diff_1 Suc_le_mono card_gt_0_iff le0 mult_Suc_right nat_mult_1) + then show ?thesis unfolding True by simp +next + note invrules = inv\<^sub>1E[OF assms(2)] + case False + obtain f where f_def: "bij_betw f P\<^sub>1 (\(P\<^sub>2 \ wrap B\<^sub>2))" "\B \ P\<^sub>1. W B + w (f B) > c" + using assms(3) unfolding bij_exists_def by blast + have FINITE: "finite P\<^sub>1" "finite (P\<^sub>2 \ wrap B\<^sub>2)" "finite (P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2)" "finite (wrap B\<^sub>1 \ {{v} |v. v \ S \ L})" + using inv\<^sub>1E(1)[OF assms(2)] bp_sol_finite by blast+ + + have F: "\B \ P\<^sub>2 \ wrap B\<^sub>2. finite B" using invrules(1) by simp + have D: "\A \ P\<^sub>2 \ wrap B\<^sub>2. \B \ P\<^sub>2 \ wrap B\<^sub>2. A \ B \ A \ B = {}" + using bpE(1)[OF invrules(1)] unfolding pairwise_def disjnt_def by auto + have sum_eq: "W (\ (P\<^sub>2 \ wrap B\<^sub>2)) = (\B \ P\<^sub>2 \ wrap B\<^sub>2. W B)" + using sum.Union_disjoint[OF F D] by auto + + have "\B\P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ S \ L}. 0 < W B" + using bpE(2,3)[OF invrules(1)] weight by (metis (no_types, lifting) UnionI bp_bins_finite invrules(1) sum_pos) + then have "(\B \ P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2. W B) \ (\B \ P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ (wrap B\<^sub>1 \ {{v} |v. v \ S \ L}). W B)" + using sum_Un_ge[OF FINITE(3,4), of W] by blast + also have "... = (\B \ P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ S \ L}. W B)" by (smt Un_assoc Un_commute) + also have "... = W U" using sum_Un_eq_sum_sum[OF invrules(1), symmetric] . + finally have *: "(\B \ P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2. W B) \ W U" . + have DISJNT: "P\<^sub>1 \ (P\<^sub>2 \ wrap B\<^sub>2) = {}" using invrules(5) by blast + + \ \This part of the proof is based on the proof on page 72 of the article @{cite BerghammerR03}.\ + have "c * card P\<^sub>1 = (\B \ P\<^sub>1. c)" by simp + also have "... < (\B \ P\<^sub>1. W B + w (f B))" + using f_def(2) sum_strict_mono[OF FINITE(1) False] by fastforce + also have "... = (\B \ P\<^sub>1. W B) + (\B \ P\<^sub>1. w (f B))" + by (simp add: Groups_Big.comm_monoid_add_class.sum.distrib) + also have "... = (\B \ P\<^sub>1. W B) + W (\ (P\<^sub>2 \ wrap B\<^sub>2))" unfolding sum.reindex_bij_betw[OF f_def(1), of w] .. + also have "... = (\B \ P\<^sub>1. W B) + (\B \ P\<^sub>2 \ wrap B\<^sub>2. W B)" unfolding sum_eq .. + also have "... = (\B \ P\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2. W B)" using sum.union_disjoint[OF FINITE(1,2) DISJNT, of W] by (simp add: Un_assoc) + also have "... \ (\u \ U. w u)" using * . + also have "... \ c * card P" using sum_lower_bound_card[OF assms(1)] . + finally show ?thesis by (meson discrete nat_mult_less_cancel_disj of_nat_less_imp_less) +qed + +lemma P\<^sub>1_B\<^sub>1_lower_bound_card: + assumes "bp P" "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 (S \ L)" "bij_exists P\<^sub>1 (\(P\<^sub>2 \ wrap B\<^sub>2))" + shows "card (P\<^sub>1 \ wrap B\<^sub>1) \ card P" +proof - + have "card (P\<^sub>1 \ wrap B\<^sub>1) \ card P\<^sub>1 + card (wrap B\<^sub>1)" + using card_Un_le by blast + also have "... \ card P\<^sub>1 + 1" using wrap_card by simp + also have "... \ card P" using P\<^sub>1_lower_bound_card[OF assms] . + finally show ?thesis . +qed + +lemma P\<^sub>2_B\<^sub>2_lower_bound_P\<^sub>1: + assumes "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 (S \ L)" "2 * card P\<^sub>2 \ card (\P\<^sub>2)" "bij_exists P\<^sub>1 (\(P\<^sub>2 \ wrap B\<^sub>2))" + shows "2 * card (P\<^sub>2 \ wrap B\<^sub>2) \ card P\<^sub>1 + 1" +proof - + note invrules = inv\<^sub>1E[OF assms(1)] and bprules = bpE[OF invrules(1)] + + have "pairwise disjnt (P\<^sub>2 \ wrap B\<^sub>2)" + using bprules(1) pairwise_subset by blast + moreover have "B\<^sub>2 \ P\<^sub>2" using invrules(4) by simp + ultimately have DISJNT: "\P\<^sub>2 \ B\<^sub>2 = {}" + by (auto, metis (no_types, hide_lams) sup_bot.right_neutral Un_insert_right disjnt_iff mk_disjoint_insert pairwise_insert wrap_Un) + + have "finite (\P\<^sub>2)" using U_Finite bprules(3) by auto + have "finite B\<^sub>2" using bp_bins_finite[OF invrules(1)] wrap_not_empty by blast + have "finite P\<^sub>2" "finite (wrap B\<^sub>2)" using bp_sol_finite[OF invrules(1)] by blast+ + have DISJNT2: "P\<^sub>2 \ wrap B\<^sub>2 = {}" unfolding wrap_def using \B\<^sub>2 \ P\<^sub>2\ by auto + have "card (wrap B\<^sub>2) \ card B\<^sub>2" + proof (cases \B\<^sub>2 = {}\) + case False + then have "1 \ card B\<^sub>2" by (simp add: leI \finite B\<^sub>2\) + then show ?thesis using wrap_card[of B\<^sub>2] by linarith + qed simp + + \ \This part of the proof is based on the proof on page 73 of the article @{cite BerghammerR03}.\ + from assms(2) have "2 * card P\<^sub>2 + 2 * card (wrap B\<^sub>2) \ card (\P\<^sub>2) + card (wrap B\<^sub>2) + 1" + using wrap_card[of B\<^sub>2] by linarith + then have "2 * (card P\<^sub>2 + card (wrap B\<^sub>2)) \ card (\P\<^sub>2) + card B\<^sub>2 + 1" + using \card (wrap B\<^sub>2) \ card B\<^sub>2\ by simp + then have "2 * (card (P\<^sub>2 \ wrap B\<^sub>2)) \ card (\P\<^sub>2 \ B\<^sub>2) + 1" + using card_Un_disjoint[OF \finite (\P\<^sub>2)\ \finite B\<^sub>2\ DISJNT] + and card_Un_disjoint[OF \finite P\<^sub>2\ \finite (wrap B\<^sub>2)\ DISJNT2] by argo + then have "2 * (card (P\<^sub>2 \ wrap B\<^sub>2)) \ card (\(P\<^sub>2 \ wrap B\<^sub>2)) + 1" + by (cases \B\<^sub>2 = {}\) (auto simp: Un_commute) + then show "2 * (card (P\<^sub>2 \ wrap B\<^sub>2)) \ card P\<^sub>1 + 1" + using assms(3) bij_betw_same_card unfolding bij_exists_def by metis +qed + +text \We add \SL S L\ to \inv\<^sub>2\ to ensure that the \S\ and \L\ sets only contain objects with correct weights.\ +definition inv\<^sub>2 :: "'a set set \ 'a set set \ 'a set \ 'a set \ 'a set \ 'a set \ bool" where + "inv\<^sub>2 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L \ inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 (S \ L) \ \\inv\<^sub>1\ holds for the partial solution\ + \ (L \ {} \ (\B \ P\<^sub>1 \ wrap B\<^sub>1. B \ L\<^sub>U \ {})) \ \If there are still large objects left, then every bin of the first partial solution must contain a large object\ + \ bij_exists P\<^sub>1 (\(P\<^sub>2 \ wrap B\<^sub>2)) \ \There exists a bijective function between the bins of the first partial solution and the objects of the second one\ + \ (2 * card P\<^sub>2 \ card (\P\<^sub>2)) \ \There are at most twice as many bins in \P\<^sub>2\ as there are objects in \P\<^sub>2\\ + \ SL S L \ \\S\ and \L\ are subsets of \S\<^sub>U\ and \L\<^sub>U\\" + +lemma inv\<^sub>2E: + assumes "inv\<^sub>2 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L" + shows "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 (S \ L)" + and "L \ {} \ \B \ P\<^sub>1 \ wrap B\<^sub>1. B \ L\<^sub>U \ {}" + and "bij_exists P\<^sub>1 (\(P\<^sub>2 \ wrap B\<^sub>2))" + and "2 * card P\<^sub>2 \ card (\P\<^sub>2)" + and "SL S L" + using assms unfolding inv\<^sub>2_def by blast+ + +lemma inv\<^sub>2I: + assumes "inv\<^sub>1 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 (S \ L)" + and "L \ {} \ \B \ P\<^sub>1 \ wrap B\<^sub>1. B \ L\<^sub>U \ {}" + and "bij_exists P\<^sub>1 (\(P\<^sub>2 \ wrap B\<^sub>2))" + and "2 * card P\<^sub>2 \ card (\P\<^sub>2)" + and "SL S L" + shows "inv\<^sub>2 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L" + using assms unfolding inv\<^sub>2_def by blast + +lemma bin_packing_lower_bound_card: + assumes "S = {}" "inv\<^sub>2 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L" "bp P" + shows "card (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ S \ L}) \ 3 / 2 * card P" +proof (cases \L = {}\) + note invrules = inv\<^sub>2E[OF assms(2)] + case True + then have "card (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ S \ L}) + = card (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2)" using assms(1) by simp + also have "... \ card (P\<^sub>1 \ wrap B\<^sub>1) + card (P\<^sub>2 \ wrap B\<^sub>2)" + using card_Un_le[of \P\<^sub>1 \ wrap B\<^sub>1\] by (simp add: Un_assoc) + also have "... \ card P + card (P\<^sub>2 \ wrap B\<^sub>2)" + using P\<^sub>1_B\<^sub>1_lower_bound_card[OF assms(3) invrules(1,3)] by simp + also have "... \ card P + card P / 2" + using P\<^sub>2_B\<^sub>2_lower_bound_P\<^sub>1[OF invrules(1,4,3)] + and P\<^sub>1_lower_bound_card[OF assms(3) invrules(1,3)] by linarith + finally show ?thesis by linarith +next + note invrules = inv\<^sub>2E[OF assms(2)] + case False + have "card (P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ S \ L}) + = card (P\<^sub>1 \ wrap B\<^sub>1 \ {{v} |v. v \ L} \ P\<^sub>2 \ wrap B\<^sub>2)" + using assms(1) by (simp add: Un_commute Un_assoc) + also have "... \ card (P\<^sub>1 \ wrap B\<^sub>1 \ {{v} |v. v \ L}) + card (P\<^sub>2 \ wrap B\<^sub>2)" + using card_Un_le[of \P\<^sub>1 \ wrap B\<^sub>1 \ {{v} |v. v \ L}\] by (simp add: Un_assoc) + also have "... \ card P + card (P\<^sub>2 \ wrap B\<^sub>2)" + using L_bins_lower_bound_card[OF assms(3) invrules(1) invrules(2)[OF False] invrules(5)] by linarith + also have "... \ card P + card P / 2" + using P\<^sub>2_B\<^sub>2_lower_bound_P\<^sub>1[OF invrules(1,4,3)] + and P\<^sub>1_lower_bound_card[OF assms(3) invrules(1,3)] by linarith + finally show ?thesis by linarith +qed + +definition inv\<^sub>3 :: "'a set set \ 'a set set \ 'a set \ 'a set \ 'a set \ 'a set \ bool" where + "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L \ inv\<^sub>2 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L \ B\<^sub>2 \ S\<^sub>U" + +lemma inv\<^sub>3E: + assumes "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L" + shows "inv\<^sub>2 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L" and "B\<^sub>2 \ S\<^sub>U" + using assms unfolding inv\<^sub>3_def by blast+ + +lemma inv\<^sub>3I: + assumes "inv\<^sub>2 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L" and "B\<^sub>2 \ S\<^sub>U" + shows "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L" + using assms unfolding inv\<^sub>3_def by blast + +lemma loop_init: + "inv\<^sub>3 {} {} {} {} S\<^sub>U L\<^sub>U" +proof - + have "S\<^sub>U \ L\<^sub>U = U" by auto + then have *: "inv\<^sub>1 {} {} {} {} (S\<^sub>U \ L\<^sub>U)" + unfolding bp_def partition_on_def pairwise_def wrap_def inv\<^sub>1_def + using weight by auto + have "bij_exists {} (\ ({} \ wrap {}))" + using bij_betwI' unfolding bij_exists_def by fastforce + from inv\<^sub>2I[OF * _ this] have "inv\<^sub>2 {} {} {} {} S\<^sub>U L\<^sub>U" by auto + from inv\<^sub>3I[OF this] show ?thesis by blast +qed + +lemma loop_stepA: + assumes "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L" "B\<^sub>1 = {}" "L = {}" "u \ S" + shows "inv\<^sub>3 P\<^sub>1 P\<^sub>2 {u} B\<^sub>2 (S - {u}) L" +proof - + note invrules = inv\<^sub>2E[OF inv\<^sub>3E(1)[OF assms(1)]] + have WEIGHT: "W B\<^sub>1 + w u \ c" using invrules(5) assms(2,4) by fastforce + from assms(4) have "u \ S \ L" by blast + from inv\<^sub>1_stepA[OF invrules(1) this WEIGHT] assms(2,3) have 1: "inv\<^sub>1 P\<^sub>1 P\<^sub>2 {u} B\<^sub>2 (S - {u} \ L)" by simp + have 2: "L \ {} \ \B\P\<^sub>1 \ wrap {u}. B \ L\<^sub>U \ {}" using assms(3) by blast + from inv\<^sub>2I[OF 1 2] invrules have "inv\<^sub>2 P\<^sub>1 P\<^sub>2 {u} B\<^sub>2 (S - {u}) L" by blast + from inv\<^sub>3I[OF this] show ?thesis using inv\<^sub>3E(2)[OF assms(1)] . +qed + +lemma loop_stepB: + assumes "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L" "B\<^sub>1 = {}" "u \ L" + shows "inv\<^sub>3 P\<^sub>1 P\<^sub>2 {u} B\<^sub>2 S (L - {u})" +proof - + note invrules = inv\<^sub>2E[OF inv\<^sub>3E(1)[OF assms(1)]] + have WEIGHT: "W B\<^sub>1 + w u \ c" using weight invrules(5) assms(2,3) by fastforce + + \ \This observation follows from the fact that the \S\ and \L\ sets have to be disjoint from each other, + and allows us to reuse our proofs of the preservation of \inv\<^sub>1\ by simply replacing \V\ with \S \ L\\ + have *: "S \ L - {u} = S \ (L - {u})" using invrules(5) assms(3) by force + from assms(3) have "u \ S \ L" by blast + from inv\<^sub>1_stepA[OF invrules(1) this WEIGHT] assms(2) * have 1: "inv\<^sub>1 P\<^sub>1 P\<^sub>2 {u} B\<^sub>2 (S \ (L - {u}))" by simp + have "\B\P\<^sub>1. B \ L\<^sub>U \ {}" "{u} \ L\<^sub>U \ {}" using assms(3) invrules(2,5) by blast+ + then have 2: "L \ {} \ \B\P\<^sub>1 \ wrap {u}. B \ L\<^sub>U \ {}" + using assms(3) by (metis (full_types) Un_iff empty_iff insert_iff wrap_not_empty) + from inv\<^sub>2I[OF 1 2] invrules have "inv\<^sub>2 P\<^sub>1 P\<^sub>2 {u} B\<^sub>2 S (L - {u})" by blast + from inv\<^sub>3I[OF this] show ?thesis using inv\<^sub>3E(2)[OF assms(1)] . +qed + +lemma loop_stepC: + assumes "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L" "B\<^sub>1 \ {}" "u \ S" "W B\<^sub>1 + w(u) \ c" + shows "inv\<^sub>3 P\<^sub>1 P\<^sub>2 (B\<^sub>1 \ {u}) B\<^sub>2 (S - {u}) L" +proof - + note invrules = inv\<^sub>2E[OF inv\<^sub>3E(1)[OF assms(1)]] + + \ \Same approach, but removing \{u}\ from \S\ instead of \L\\ + have *: "S \ L - {u} = (S - {u}) \ L" using invrules(5) assms(3) by force + from assms(3) have "u \ S \ L" by blast + from inv\<^sub>1_stepA[OF invrules(1) this assms(4)] * have 1: "inv\<^sub>1 P\<^sub>1 P\<^sub>2 (B\<^sub>1 \ {u}) B\<^sub>2 (S - {u} \ L)" by simp + have "L \ {} \ \B\P\<^sub>1 \ wrap B\<^sub>1. B \ L\<^sub>U \ {}" using invrules(2) by blast + then have 2: "L \ {} \ \B\P\<^sub>1 \ wrap (B\<^sub>1 \ {u}). B \ L\<^sub>U \ {}" + by (smt Int_insert_left Un_empty_right Un_iff Un_insert_right assms(2) insert_not_empty singletonD singletonI wrap_def) + from inv\<^sub>2I[OF 1 2] invrules have "inv\<^sub>2 P\<^sub>1 P\<^sub>2 (B\<^sub>1 \ {u}) B\<^sub>2 (S - {u}) L" by blast + from inv\<^sub>3I[OF this] show ?thesis using inv\<^sub>3E(2)[OF assms(1)] . +qed + +lemma loop_stepD: + assumes "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L" "B\<^sub>1 \ {}" "u \ S" "W B\<^sub>1 + w(u) > c" "W B\<^sub>2 + w(u) \ c" + shows "inv\<^sub>3 (P\<^sub>1 \ wrap B\<^sub>1) P\<^sub>2 {} (B\<^sub>2 \ {u}) (S - {u}) L" +proof - + note invrules = inv\<^sub>2E[OF inv\<^sub>3E(1)[OF assms(1)]] + have *: "S \ L - {u} = (S - {u}) \ L" using invrules(5) assms(3) by force + from assms(3) have "u \ S \ L" by blast + from inv\<^sub>1_stepB[OF invrules(1) this assms(5)] * have 1: "inv\<^sub>1 (P\<^sub>1 \ wrap B\<^sub>1) P\<^sub>2 {} (B\<^sub>2 \ {u}) (S - {u} \ L)" by simp + + have 2: "L \ {} \ \B\P\<^sub>1 \ wrap B\<^sub>1 \ wrap {}. B \ L\<^sub>U \ {}" + using invrules(2) unfolding wrap_empty by blast + + from invrules(3) obtain f where f_def: "bij_betw f P\<^sub>1 (\ (P\<^sub>2 \ wrap B\<^sub>2))" "\B\P\<^sub>1. c < W B + w (f B)" unfolding bij_exists_def by blast + have "B\<^sub>1 \ P\<^sub>1" using inv\<^sub>1E(3)[OF invrules(1)] by blast + have "u \ (\ (P\<^sub>2 \ wrap B\<^sub>2))" using inv\<^sub>1E(2)[OF invrules(1)] assms(3) by blast + then have "(\ (P\<^sub>2 \ wrap (B\<^sub>2 \ {u}))) = (\ (P\<^sub>2 \ wrap B\<^sub>2 \ {{u}}))" + by (metis Sup_empty Un_assoc Union_Un_distrib ccpo_Sup_singleton wrap_empty wrap_not_empty) + also have "... = (\ (P\<^sub>2 \ wrap B\<^sub>2)) \ {u}" by simp + finally have UN: "(\ (P\<^sub>2 \ wrap (B\<^sub>2 \ {u}))) = (\ (P\<^sub>2 \ wrap B\<^sub>2)) \ {u}" . + have "wrap B\<^sub>1 = {B\<^sub>1}" using wrap_not_empty[of B\<^sub>1] assms(2) by simp + let ?f = "f (B\<^sub>1 := u)" + have BIJ: "bij_betw ?f (P\<^sub>1 \ wrap B\<^sub>1) (\ (P\<^sub>2 \ wrap (B\<^sub>2 \ {u})))" + unfolding wrap_empty \wrap B\<^sub>1 = {B\<^sub>1}\ UN using f_def(1) \B\<^sub>1 \ P\<^sub>1\ \u \ (\ (P\<^sub>2 \ wrap B\<^sub>2))\ + by (metis (no_types, lifting) bij_betw_cong fun_upd_other fun_upd_same notIn_Un_bij_betw3) + have "c < W B\<^sub>1 + w (?f B\<^sub>1)" using assms(4) by simp + then have "(\B\P\<^sub>1 \ wrap B\<^sub>1. c < W B + w (?f B))" + unfolding \wrap B\<^sub>1 = {B\<^sub>1}\ using f_def(2) by simp + with BIJ have "bij_betw ?f (P\<^sub>1 \ wrap B\<^sub>1) (\ (P\<^sub>2 \ wrap (B\<^sub>2 \ {u}))) + \ (\B\P\<^sub>1 \ wrap B\<^sub>1. c < W B + w (?f B))" by blast + then have 3: "bij_exists (P\<^sub>1 \ wrap B\<^sub>1) (\ (P\<^sub>2 \ wrap (B\<^sub>2 \ {u})))" + unfolding bij_exists_def by blast + from inv\<^sub>2I[OF 1 2 3] have "inv\<^sub>2 (P\<^sub>1 \ wrap B\<^sub>1) P\<^sub>2 {} (B\<^sub>2 \ {u}) (S - {u}) L" using invrules(4,5) by blast + + from inv\<^sub>3I[OF this] show ?thesis using inv\<^sub>3E(2)[OF assms(1)] assms(3) invrules(5) by blast +qed + +lemma B\<^sub>2_at_least_two_objects: + assumes "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L" "u \ S" "W B\<^sub>2 + w(u) > c" + shows "2 \ card B\<^sub>2" +proof (rule ccontr, simp add: not_le) + have FINITE: "finite B\<^sub>2" using inv\<^sub>1E(1)[OF inv\<^sub>2E(1)[OF inv\<^sub>3E(1)[OF assms(1)]]] + by (metis (no_types, lifting) Finite_Set.finite.simps U_Finite Union_Un_distrib bpE(3) ccpo_Sup_singleton finite_Un wrap_not_empty) + assume "card B\<^sub>2 < 2" + then consider (0) "card B\<^sub>2 = 0" | (1) "card B\<^sub>2 = 1" by linarith + then show False proof cases + case 0 then have "B\<^sub>2 = {}" using FINITE by simp + then show ?thesis using assms(2,3) inv\<^sub>2E(5)[OF inv\<^sub>3E(1)[OF assms(1)]] by force + next + case 1 then obtain v where "B\<^sub>2 = {v}" + using card_1_singletonE by auto + with inv\<^sub>3E(2)[OF assms(1)] have "2 * w v \ c" using inv\<^sub>2E(5)[OF inv\<^sub>3E(1)[OF assms(1)]] by simp + moreover from \B\<^sub>2 = {v}\ have "W B\<^sub>2 = w v" by simp + ultimately show ?thesis using assms(2,3) inv\<^sub>2E(5)[OF inv\<^sub>3E(1)[OF assms(1)]] by force + qed +qed + +lemma loop_stepE: + assumes "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L" "B\<^sub>1 \ {}" "u \ S" "W B\<^sub>1 + w(u) > c" "W B\<^sub>2 + w(u) > c" + shows "inv\<^sub>3 (P\<^sub>1 \ wrap B\<^sub>1) (P\<^sub>2 \ wrap B\<^sub>2) {} {u} (S - {u}) L" +proof - + note invrules = inv\<^sub>2E[OF inv\<^sub>3E(1)[OF assms(1)]] + have *: "S \ L - {u} = (S - {u}) \ L" using invrules(5) assms(3) by force + from assms(3) have "u \ S \ L" by blast + from inv\<^sub>1_stepC[OF invrules(1) this] * have 1: "inv\<^sub>1 (P\<^sub>1 \ wrap B\<^sub>1) (P\<^sub>2 \ wrap B\<^sub>2) {} {u} (S - {u} \ L)" by simp + + have 2: "L \ {} \ \B\P\<^sub>1 \ wrap B\<^sub>1 \ wrap {}. B \ L\<^sub>U \ {}" + using invrules(2) unfolding wrap_empty by blast + + from invrules(3) obtain f where f_def: "bij_betw f P\<^sub>1 (\ (P\<^sub>2 \ wrap B\<^sub>2))" "\B\P\<^sub>1. c < W B + w (f B)" unfolding bij_exists_def by blast + have "B\<^sub>1 \ P\<^sub>1" using inv\<^sub>1E(3)[OF invrules(1)] by blast + have "u \ (\ (P\<^sub>2 \ wrap B\<^sub>2))" using inv\<^sub>1E(2)[OF invrules(1)] assms(3) by blast + have "(\ (P\<^sub>2 \ wrap B\<^sub>2 \ wrap {u})) = (\ (P\<^sub>2 \ wrap B\<^sub>2 \ {{u}}))" unfolding wrap_def by simp + also have "... = (\ (P\<^sub>2 \ wrap B\<^sub>2)) \ {u}" by simp + finally have UN: "(\ (P\<^sub>2 \ wrap B\<^sub>2 \ wrap {u})) = (\ (P\<^sub>2 \ wrap B\<^sub>2)) \ {u}" . + have "wrap B\<^sub>1 = {B\<^sub>1}" using wrap_not_empty[of B\<^sub>1] assms(2) by simp + let ?f = "f (B\<^sub>1 := u)" + have BIJ: "bij_betw ?f (P\<^sub>1 \ wrap B\<^sub>1) (\ (P\<^sub>2 \ wrap B\<^sub>2 \ wrap {u}))" + unfolding wrap_empty \wrap B\<^sub>1 = {B\<^sub>1}\ UN using f_def(1) \B\<^sub>1 \ P\<^sub>1\ \u \ (\ (P\<^sub>2 \ wrap B\<^sub>2))\ + by (metis (no_types, lifting) bij_betw_cong fun_upd_other fun_upd_same notIn_Un_bij_betw3) + have "c < W B\<^sub>1 + w (?f B\<^sub>1)" using assms(4) by simp + then have "(\B\P\<^sub>1 \ wrap B\<^sub>1. c < W B + w (?f B))" + unfolding \wrap B\<^sub>1 = {B\<^sub>1}\ using f_def(2) by simp + with BIJ have "bij_betw ?f (P\<^sub>1 \ wrap B\<^sub>1) (\ (P\<^sub>2 \ wrap B\<^sub>2 \ wrap {u})) + \ (\B\P\<^sub>1 \ wrap B\<^sub>1. c < W B + w (?f B))" by blast + then have 3: "bij_exists (P\<^sub>1 \ wrap B\<^sub>1) (\ (P\<^sub>2 \ wrap B\<^sub>2 \ wrap {u}))" + unfolding bij_exists_def by blast + + have 4: "2 * card (P\<^sub>2 \ wrap B\<^sub>2) \ card (\ (P\<^sub>2 \ wrap B\<^sub>2))" + proof - + note bprules = bpE[OF inv\<^sub>1E(1)[OF invrules(1)]] + have "pairwise disjnt (P\<^sub>2 \ wrap B\<^sub>2)" + using bprules(1) pairwise_subset by blast + moreover have "B\<^sub>2 \ P\<^sub>2" using inv\<^sub>1E(4)[OF invrules(1)] by simp + ultimately have DISJNT: "\P\<^sub>2 \ B\<^sub>2 = {}" + by (auto, metis (no_types, hide_lams) sup_bot.right_neutral Un_insert_right disjnt_iff mk_disjoint_insert pairwise_insert wrap_Un) + have "finite (\P\<^sub>2)" using U_Finite bprules(3) by auto + have "finite B\<^sub>2" using inv\<^sub>1E(1)[OF invrules(1)] bp_bins_finite wrap_not_empty by blast + + have "2 * card (P\<^sub>2 \ wrap B\<^sub>2) \ 2 * (card P\<^sub>2 + card (wrap B\<^sub>2))" + using card_Un_le[of P\<^sub>2 \wrap B\<^sub>2\] by simp + also have "... \ 2 * card P\<^sub>2 + 2" using wrap_card by auto + also have "... \ card (\ P\<^sub>2) + 2" using invrules(4) by simp + also have "... \ card (\ P\<^sub>2) + card B\<^sub>2" using B\<^sub>2_at_least_two_objects[OF assms(1,3,5)] by simp + also have "... = card (\ (P\<^sub>2 \ {B\<^sub>2}))" using DISJNT card_Un_disjoint[OF \finite (\P\<^sub>2)\ \finite B\<^sub>2\] by (simp add: Un_commute) + also have "... = card (\ (P\<^sub>2 \ wrap B\<^sub>2))" by (cases \B\<^sub>2 = {}\) auto + finally show ?thesis . + qed + from inv\<^sub>2I[OF 1 2 3 4] have "inv\<^sub>2 (P\<^sub>1 \ wrap B\<^sub>1) (P\<^sub>2 \ wrap B\<^sub>2) {} {u} (S - {u}) L" + using invrules(5) by blast + + from inv\<^sub>3I[OF this] show ?thesis using assms(3) invrules(5) by blast +qed + +text \The bin packing algorithm as it is proposed on page 78 of the article @{cite BerghammerR03}. + \P\ will not only be a correct solution of the bin packing problem, but the amount of bins + will be a lower bound for \3 / 2\ of the amount of bins of any correct solution \Q\, and thus + guarantee an approximation factor of \3 / 2\ for the optimum.\ +lemma bp_approx: +"VARS P P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V S L u + {True} + S := {}; L:= {}; V := U; + WHILE V \ {} INV {V \ U \ S = {u \ U - V. w(u) \ c / 2} \ L = {u \ U - V. c / 2 < w(u)}} DO + u := (SOME u. u \ V); + IF w(u) \ c / 2 + THEN S := S \ {u} + ELSE L := L \ {u} FI; + V := V - {u} + OD; + P\<^sub>1 := {}; P\<^sub>2 := {}; B\<^sub>1 := {}; B\<^sub>2 := {}; + WHILE S \ {} INV {inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L} DO + IF B\<^sub>1 \ {} + THEN u := (SOME u. u \ S); S := S - {u} + ELSE IF L \ {} + THEN u := (SOME u. u \ L); L := L - {u} + ELSE u := (SOME u. u \ S); S := S - {u} FI FI; + IF W(B\<^sub>1) + w(u) \ c + THEN B\<^sub>1 := B\<^sub>1 \ {u} + ELSE IF W(B\<^sub>2) + w(u) \ c + THEN B\<^sub>2 := B\<^sub>2 \ {u} + ELSE P\<^sub>2 := P\<^sub>2 \ wrap B\<^sub>2; B\<^sub>2 := {u} FI; + P\<^sub>1 := P\<^sub>1 \ wrap B\<^sub>1; B\<^sub>1 := {} FI + OD; + P := P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2; V := L; + WHILE V \ {} + INV {S = {} \ inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L \ V \ L \ P = P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v}|v. v \ L - V}} DO + u := (SOME u. u \ V); P := P \ {{u}}; V := V - {u} + OD + {bp P \ (\Q. bp Q \ card P \ 3 / 2 * card Q)}" +proof (vcg, goal_cases) + case (1 P P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V S L u) + then show ?case by blast +next + case (2 P P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V S L u) + then show ?case by (auto simp: some_in_eq) +next + case (3 P P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V S L u) + then show ?case using loop_init by force +next + case (4 P P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V S L u) + then have INV: "inv\<^sub>3 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L" .. + let ?s = "SOME u. u \ S" + let ?l = "SOME u. u \ L" + note SL_def = inv\<^sub>2E(5)[OF inv\<^sub>3E(1)[OF INV]] + have LIN: "L \ {} \ ?l \ L" using some_in_eq by metis + then have LWEIGHT: "L \ {} \ w ?l \ c" using weight SL_def by blast + from 4 have "S \ {}" .. + then have IN: "?s \ S" using some_in_eq by metis + then have "w ?s \ c" using SL_def by auto + then show ?case + using LWEIGHT loop_stepA[OF INV _ _ IN] loop_stepB[OF INV _ LIN] loop_stepC[OF INV _ IN] + and loop_stepD[OF INV _ IN] loop_stepE[OF INV _ IN] by (cases \B\<^sub>1 = {}\, cases \L = {}\) auto +next + case (5 P P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V S L u) + then show ?case by blast +next + case (6 P P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V S L u) + then have *: "(SOME u. u \ V) \ V" "(SOME u. u \ V) \ L" by (auto simp add: some_in_eq) + then have "P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ L - (V - {SOME u. u \ V})} + = P\<^sub>1 \ wrap B\<^sub>1 \ P\<^sub>2 \ wrap B\<^sub>2 \ {{v} |v. v \ L - V \ {SOME u. u \ V}}" + by blast + with 6 * show ?case by blast +next + case (7 P P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 V S L u) + then have *: "inv\<^sub>2 P\<^sub>1 P\<^sub>2 B\<^sub>1 B\<^sub>2 S L" + using inv\<^sub>3E(1) by blast + from inv\<^sub>1E(1)[OF inv\<^sub>2E(1)[OF *]] 7 + have "bp P" by fastforce + with bin_packing_lower_bound_card[OF _ *] 7 + show ?case by fastforce +qed + +end (* BinPacking_Complete *) + +end (* Theory *) \ No newline at end of file diff --git a/thys/Approximation_Algorithms/Approx_LB_Hoare.thy b/thys/Approximation_Algorithms/Approx_LB_Hoare.thy new file mode 100644 --- /dev/null +++ b/thys/Approximation_Algorithms/Approx_LB_Hoare.thy @@ -0,0 +1,609 @@ +section \Load Balancing\ + +theory Approx_LB_Hoare + imports Complex_Main "HOL-Hoare.Hoare_Logic" +begin + +text \This is formalization of the load balancing algorithms and proofs +in the book by Kleinberg and Tardos \cite{KleinbergT06}.\ + +hide_const (open) sorted + +(* TODO: mv *) + +lemma sum_le_card_Max: "\ finite A; A \ {} \ \ sum f A \ card A * Max (f ` A)" +proof(induction A rule: finite_ne_induct) + case (singleton x) + then show ?case by simp +next + case (insert x F) + then show ?case by (auto simp: max_def order.trans[of "sum f F" "card F * Max (f ` F)"]) +qed + +lemma Max_const[simp]: "\ finite A; A \ {} \ \ Max ((\_. c) ` A) = c" +using Max_in image_is_empty by blast + +abbreviation Max\<^sub>0 :: "nat set \ nat" where +"Max\<^sub>0 N \ (if N={} then 0 else Max N)" + +fun f_Max\<^sub>0 :: "(nat \ nat) \ nat \ nat" where + "f_Max\<^sub>0 f 0 = 0" +| "f_Max\<^sub>0 f (Suc x) = max (f (Suc x)) (f_Max\<^sub>0 f x)" + +lemma f_Max\<^sub>0_equiv: "f_Max\<^sub>0 f n = Max\<^sub>0 (f ` {1..n})" + by (induction n) (auto simp: not_le atLeastAtMostSuc_conv) + +lemma f_Max\<^sub>0_correct: + "\x \ {1..m}. T x \ f_Max\<^sub>0 T m" + "m > 0 \ \x \ {1..m}. T x = f_Max\<^sub>0 T m" + apply (induction m) + apply simp_all + apply (metis atLeastAtMost_iff le_Suc_eq max.cobounded1 max.coboundedI2) + subgoal for m by (cases \m = 0\) (auto simp: max_def) + done + +lemma f_Max\<^sub>0_mono: + "y \ T x \ f_Max\<^sub>0 (T (x := y)) m \ f_Max\<^sub>0 T m" + "T x \ y \ f_Max\<^sub>0 T m \ f_Max\<^sub>0 (T (x := y)) m" + by (induction m) auto + +lemma f_Max\<^sub>0_out_of_range [simp]: + "x \ {1..k} \ f_Max\<^sub>0 (T (x := y)) k = f_Max\<^sub>0 T k" + by (induction k) auto + +lemma fun_upd_f_Max\<^sub>0: + assumes "x \ {1..m}" "T x \ y" + shows "f_Max\<^sub>0 (T (x := y)) m = max y (f_Max\<^sub>0 T m)" + using assms by (induction m) auto + +locale LoadBalancing = (* Load Balancing *) + fixes t :: "nat \ nat" + and m :: nat + and n :: nat + assumes m_gt_0: "m > 0" +begin + +subsection \Formalization of a Correct Load Balancing\ + +subsubsection \Definition\ + +definition lb :: "(nat \ nat) \ (nat \ nat set) \ nat \ bool" where + "lb T A j = ((\x \ {1..m}. \y \ {1..m}. x \ y \ A x \ A y = {}) \ \No job is assigned to more than one machine\ + \ (\x \ {1..m}. A x) = {1..j} \ \Every job is assigned\ + \ (\x \ {1..m}. (\j \ A x. t j) = T x) \ \The processing times sum up to the correct load\)" + +abbreviation makespan :: "(nat \ nat) \ nat" where + "makespan T \ f_Max\<^sub>0 T m" + +lemma makespan_def': "makespan T = Max (T ` {1..m})" + using m_gt_0 by (simp add: f_Max\<^sub>0_equiv) +(* +lemma makespan_correct: + "\x \ {1..m}. T x \ makespan T m" + "m > 0 \ \x \ {1..m}. T x = makespan T m" + apply (induction m) + apply simp_all + apply (metis atLeastAtMost_iff le_Suc_eq max.cobounded1 max.coboundedI2) + subgoal for m by (cases \m = 0\) (auto simp: max_def) + done + +lemma no_machines_lb_iff_no_jobs: "lb T A j 0 \ j = 0" + unfolding lb_def by auto + +lemma machines_if_jobs: "\ lb T A j m; j > 0 \ \ m > 0" + using no_machines_lb_iff_no_jobs by (cases m) auto +*) + +lemma makespan_correct: + "\x \ {1..m}. T x \ makespan T" + "\x \ {1..m}. T x = makespan T" + using f_Max\<^sub>0_correct m_gt_0 by auto + +lemma lbE: + assumes "lb T A j" + shows "\x \ {1..m}. \y \ {1..m}. x \ y \ A x \ A y = {}" + "(\x \ {1..m}. A x) = {1..j}" + "\x \ {1..m}. (\y \ A x. t y) = T x" + using assms unfolding lb_def by blast+ + +lemma lbI: + assumes "\x \ {1..m}. \y \ {1..m}. x \ y \ A x \ A y = {}" + "(\x \ {1..m}. A x) = {1..j}" + "\x \ {1..m}. (\y \ A x. t y) = T x" + shows "lb T A j" using assms unfolding lb_def by blast + +lemma A_lb_finite [simp]: + assumes "lb T A j" "x \ {1..m}" + shows "finite (A x)" + by (metis lbE(2) assms finite_UN finite_atLeastAtMost) + +text \If \A x\ is pairwise disjoint for all \x \ {1..m}\, then the the sum over the sums of the + individual \A x\ is equal to the sum over the union of all \A x\.\ +lemma sum_sum_eq_sum_Un: + fixes A :: "nat \ nat set" + assumes "\x \ {1..m}. \y \ {1..m}. x \ y \ A x \ A y = {}" + and "\x \ {1..m}. finite (A x)" + shows "(\x \ {1..m}. (\y \ A x. t y)) = (\x \ (\y \ {1..m}. A y). t x)" + using assms +proof (induction m) + case (Suc m) + have FINITE: "finite (\x \ {1..m}. A x)" "finite (A (Suc m))" + using Suc.prems(2) by auto + have "\x \ {1..m}. A x \ A (Suc m) = {}" + using Suc.prems(1) by simp + then have DISJNT: "(\x \ {1..m}. A x) \ (A (Suc m)) = {}" using Union_disjoint by blast + have "(\x \ (\y \ {1..m}. A y). t x) + (\x \ A (Suc m). t x) + = (\x \ ((\y \ {1..m}. A y) \ A (Suc m)). t x)" + using sum.union_disjoint[OF FINITE DISJNT, symmetric] . + also have "... = (\x \ (\y \ {1..Suc m}. A y). t x)" + by (metis UN_insert image_Suc_lessThan image_insert inf_sup_aci(5) lessThan_Suc) + finally show ?case using Suc by auto +qed simp + +text \If \T\ and \A\ are a correct load balancing for \j\ jobs and \m\ machines, + then the sum of the loads has to be equal to the sum of the processing times of the jobs\ +lemma lb_impl_job_sum: + assumes "lb T A j" + shows "(\x \ {1..m}. T x) = (\x \ {1..j}. t x)" +proof - + note lbrules = lbE[OF assms] + from assms have FINITE: "\x \ {1..m}. finite (A x)" by simp + have "(\x \ {1..m}. T x) = (\x \ {1..m}. (\y \ A x. t y))" + using lbrules(3) by simp + also have "... = (\x \ {1..j}. t x)" + using sum_sum_eq_sum_Un[OF lbrules(1) FINITE] + unfolding lbrules(2) . + finally show ?thesis . +qed + +subsubsection \Lower Bounds for the Makespan\ + +text \If \T\ and \A\ are a correct load balancing for \j\ jobs and \m\ machines, then the processing time + of any job \x \ {1..j}\ is a lower bound for the load of some machine \y \ {1..m}\\ +lemma job_lower_bound_machine: + assumes "lb T A j" "x \ {1..j}" + shows "\y \ {1..m}. t x \ T y" +proof - + note lbrules = lbE[OF assms(1)] + have "\y \ {1..m}. x \ A y" using lbrules(2) assms(2) by blast + then obtain y where y_def: "y \ {1..m}" "x \ A y" .. + moreover have "finite (A y)" using assms(1) y_def(1) by simp + ultimately have "t x \ (\x \ A y. t x)" using lbrules(1) member_le_sum by fast + also have "... = T y" using lbrules(3) y_def(1) by blast + finally show ?thesis using y_def(1) by blast +qed + +text \As the load of any machine is a lower bound for the makespan, the processing time + of any job \x \ {1..j}\ has to also be a lower bound for the makespan. + Follows from @{thm [source] job_lower_bound_machine} and @{thm [source] makespan_correct}.\ +lemma job_lower_bound_makespan: + assumes "lb T A j" "x \ {1..j}" + shows "t x \ makespan T" + by (meson job_lower_bound_machine[OF assms] makespan_correct(1) le_trans) + +text \The makespan over \j\ jobs is a lower bound for the makespan of any correct load balancing for \j\ jobs.\ +lemma max_job_lower_bound_makespan: + assumes "lb T A j" + shows "Max\<^sub>0 (t ` {1..j}) \ makespan T" + using job_lower_bound_makespan[OF assms] by fastforce + +lemma job_dist_lower_bound_makespan: + assumes "lb T A j" + shows "(\x \ {1..j}. t x) / m \ makespan T" +proof - + have "(\x \ {1..j}. t x) \ m * makespan T" + using assms lb_impl_job_sum[symmetric] + and sum_le_card_Max[of "{1..m}"] m_gt_0 by (simp add: makespan_def') + then have "real (\x \ {1..j}. t x) \ real m * real (makespan T)" + using of_nat_mono by fastforce + then show ?thesis by (simp add: field_simps m_gt_0) +qed + +subsection \The Greedy Approximation Algorithm\ + +text \This function will perform a linear scan from \k \ {1..m}\ and return the index of the machine with minimum load assuming \m > 0\\ +fun min\<^sub>k :: "(nat \ nat) \ nat \ nat" where + "min\<^sub>k T 0 = 1" +| "min\<^sub>k T (Suc x) = + (let k = min\<^sub>k T x + in if T (Suc x) < T k then (Suc x) else k)" + +lemma min_correct: + "\x \ {1..m}. T (min\<^sub>k T m) \ T x" + by (induction m) (auto simp: Let_def le_Suc_eq, force) + +lemma min_in_range: + "k > 0 \ (min\<^sub>k T k) \ {1..k}" + by (induction k) (auto simp: Let_def, force+) + +lemma add_job: + assumes "lb T A j" "x \ {1..m}" + shows "lb (T (x := T x + t (Suc j))) (A (x := A x \ {Suc j})) (Suc j)" + (is \lb ?T ?A _\) +proof - + note lbrules = lbE[OF assms(1)] + + \ \Rule 1: @{term ?A} pairwise disjoint\ + have NOTIN: "\i \ {1..m}. Suc j \ A i" using lbrules(2) assms(2) by force + with lbrules(1) have "\i \ {1..m}. i \ x \ A i \ (A x \ {Suc j}) = {}" + using assms(2) by blast + then have 1: "\x \ {1..m}. \y \ {1..m}. x \ y \ ?A x \ ?A y = {}" + using lbrules(1) by simp + + \ \Rule 2: @{term ?A} contains all jobs\ + have "(\y \ {1..m}. ?A y) = (\y \ {1..m}. A y) \ {Suc j}" + using UNION_fun_upd assms(2) by auto + also have "... = {1..Suc j}" unfolding lbrules(2) by auto + finally have 2: "(\y \ {1..m}. ?A y) = {1..Suc j}" . + + \ \Rule 3: @{term ?A} sums to @{term ?T}\ + have "(\i \ ?A x. t i) = (\i \ A x \ {Suc j}. t i)" by simp + moreover have "A x \ {Suc j} = {}" using NOTIN assms(2) by blast + moreover have "finite (A x)" "finite {Suc j}" using assms by simp+ + ultimately have "(\i \ ?A x. t i) = (\i \ A x. t i) + (\i \ {Suc j}. t i)" + using sum.union_disjoint by simp + also have "... = T x + t (Suc j)" using lbrules(3) assms(2) by simp + finally have "(\i \ ?A x. t i) = ?T x" by simp + then have 3: "\i \ {1..m}. (\j \ ?A i. t j) = ?T i" + using lbrules(3) assms(2) by simp + + from lbI[OF 1 2 3] show ?thesis . +qed + +lemma makespan_mono: + "y \ T x \ makespan (T (x := y)) \ makespan T" + "T x \ y \ makespan T \ makespan (T (x := y))" + using f_Max\<^sub>0_mono by auto + +lemma smaller_optimum: + assumes "lb T A (Suc j)" + shows "\T' A'. lb T' A' j \ makespan T' \ makespan T" +proof - + note lbrules = lbE[OF assms] + have "\x \ {1..m}. Suc j \ A x" using lbrules(2) by auto + then obtain x where x_def: "x \ {1..m}" "Suc j \ A x" .. + let ?T = "T (x := T x - t (Suc j))" + let ?A = "A (x := A x - {Suc j})" + + \ \Rule 1: @{term ?A} pairwise disjoint\ + from lbrules(1) have "\i \ {1..m}. i \ x \ A i \ (A x - {Suc j}) = {}" + using x_def(1) by blast + then have 1: "\x \ {1..m}. \y \ {1..m}. x \ y \ ?A x \ ?A y = {}" + using lbrules(1) by auto + + \ \Rule 2: @{term ?A} contains all jobs\ + have NOTIN: "\i \ {1..m}. i \ x \ Suc j \ A i" using lbrules(1) x_def by blast + then have "(\y \ {1..m}. ?A y) = (\y \ {1..m}. A y) - {Suc j}" + using UNION_fun_upd x_def by auto + also have "... = {1..j}" unfolding lbrules(2) by auto + finally have 2: "(\y \ {1..m}. ?A y) = {1..j}" . + + \ \Rule 3: @{term ?A} sums to @{term ?T}\ + have "(\i \ A x - {Suc j}. t i) = (\i \ A x. t i) - t (Suc j)" + by (simp add: sum_diff1_nat x_def(2)) + also have "... = T x - t (Suc j)" using lbrules(3) x_def(1) by simp + finally have "(\i \ ?A x. t i) = ?T x" by simp + then have 3: "\i \ {1..m}. (\j \ ?A i. t j) = ?T i" + using lbrules(3) x_def(1) by simp + + \ \@{term makespan} is not larger\ + have "lb ?T ?A j \ makespan ?T \ makespan T" + using lbI[OF 1 2 3] makespan_mono(1) by force + then show ?thesis by blast +qed + +text \If the processing time \y\ does not contribute to the makespan, we can ignore it.\ +lemma remove_small_job: + assumes "makespan (T (x := T x + y)) \ T x + y" + shows "makespan (T (x := T x + y)) = makespan T" +proof - + let ?T = "T (x := T x + y)" + have NOT_X: "makespan ?T \ ?T x" using assms(1) by simp + then have "\i \ {1..m}. makespan ?T = ?T i \ i \ x" + using makespan_correct(2) by metis + then obtain i where i_def: "i \ {1..m}" "makespan ?T = ?T i" "i \ x" by blast + then have "?T i = T i" using NOT_X by simp + moreover from this have "makespan T = T i" + by (metis i_def(1,2) antisym_conv le_add1 makespan_mono(2) makespan_correct(1)) + ultimately show ?thesis using i_def(2) by simp +qed + +lemma greedy_makespan_no_jobs [simp]: + "makespan (\_. 0) = 0" + using m_gt_0 by (simp add: makespan_def') + +lemma min_avg: "m * T (min\<^sub>k T m) \ (\i \ {1..m}. T i)" + (is \_ * ?T \ ?S\) +proof - + have "(\_ \ {1..m}. ?T) \ ?S" + using sum_mono[of \{1..m}\ \\_. ?T\ T] + and min_correct by blast + then show ?thesis by simp +qed + +definition inv\<^sub>1 :: "(nat \ nat) \ (nat \ nat set) \ nat \ bool" where + "inv\<^sub>1 T A j = (lb T A j \ j \ n \ (\T' A'. lb T' A' j \ makespan T \ 2 * makespan T'))" + +lemma inv\<^sub>1E: + assumes "inv\<^sub>1 T A j" + shows "lb T A j" "j \ n" + "lb T' A' j \ makespan T \ 2 * makespan T'" + using assms unfolding inv\<^sub>1_def by blast+ + +lemma inv\<^sub>1I: + assumes "lb T A j" "j \ n" "\T' A'. lb T' A' j \ makespan T \ 2 * makespan T'" + shows "inv\<^sub>1 T A j" using assms unfolding inv\<^sub>1_def by blast + +lemma inv\<^sub>1_step: + assumes "inv\<^sub>1 T A j" "j < n" + shows "inv\<^sub>1 (T ((min\<^sub>k T m) := T (min\<^sub>k T m) + t (Suc j))) + (A ((min\<^sub>k T m) := A (min\<^sub>k T m) \ {Suc j})) (Suc j)" + (is \inv\<^sub>1 ?T ?A _\) +proof - + note invrules = inv\<^sub>1E[OF assms(1)] + \ \Greedy is correct\ + have LB: "lb ?T ?A (Suc j)" + using add_job[OF invrules(1) min_in_range[OF m_gt_0]] by blast + \ \Greedy maintains approximation factor\ + have MK: "\T' A'. lb T' A' (Suc j) \ makespan ?T \ 2 * makespan T'" + proof rule+ + fix T\<^sub>1 A\<^sub>1 assume "lb T\<^sub>1 A\<^sub>1 (Suc j)" + from smaller_optimum[OF this] + obtain T\<^sub>0 A\<^sub>0 where "lb T\<^sub>0 A\<^sub>0 j" "makespan T\<^sub>0 \ makespan T\<^sub>1" by blast + then have IH: "makespan T \ 2 * makespan T\<^sub>1" + using invrules(3) by force + show "makespan ?T \ 2 * makespan T\<^sub>1" + proof (cases \makespan ?T = T (min\<^sub>k T m) + t (Suc j)\) + case True + have "m * T (min\<^sub>k T m) \ (\i \ {1..m}. T i)" by (rule min_avg) + also have "... = (\i \ {1..j}. t i)" by (rule lb_impl_job_sum[OF invrules(1)]) + finally have "real m * T (min\<^sub>k T m) \ (\i \ {1..j}. t i)" + by (auto dest: of_nat_mono) + with m_gt_0 have "T (min\<^sub>k T m) \ (\i \ {1..j}. t i) / m" + by (simp add: field_simps) + then have "T (min\<^sub>k T m) \ makespan T\<^sub>1" + using job_dist_lower_bound_makespan[OF \lb T\<^sub>0 A\<^sub>0 j\] + and \makespan T\<^sub>0 \ makespan T\<^sub>1\ by linarith + moreover have "t (Suc j) \ makespan T\<^sub>1" + using job_lower_bound_makespan[OF \lb T\<^sub>1 A\<^sub>1 (Suc j)\] by simp + ultimately show ?thesis unfolding True by simp + next + case False show ?thesis using remove_small_job[OF False] IH by simp + qed + qed + from inv\<^sub>1I[OF LB _ MK] show ?thesis using assms(2) by simp +qed + +lemma simple_greedy_approximation: +"VARS T A i j +{True} +T := (\_. 0); +A := (\_. {}); +j := 0; +WHILE j < n INV {inv\<^sub>1 T A j} DO + i := min\<^sub>k T m; + j := (Suc j); + A := A (i := A(i) \ {j}); + T := T (i := T(i) + t j) +OD +{lb T A n \ (\T' A'. lb T' A' n \ makespan T \ 2 * makespan T')}" +proof (vcg, goal_cases) + case (1 T A i j) + then show ?case by (simp add: lb_def inv\<^sub>1_def) +next + case (2 T A i j) + then show ?case using inv\<^sub>1_step by simp +next + case (3 T A i j) + then show ?case unfolding inv\<^sub>1_def by force +qed + +definition sorted :: "nat \ bool" where + "sorted j = (\x \ {1..j}. \y \ {1..x}. t x \ t y)" + +lemma sorted_smaller [simp]: "\ sorted j; j \ j' \ \ sorted j'" + unfolding sorted_def by simp + +lemma j_gt_m_pigeonhole: + assumes "lb T A j" "j > m" + shows "\x \ {1..j}. \y \ {1..j}. \z \ {1..m}. x \ y \ x \ A z \ y \ A z" +proof - + have "\x \ {1..j}. \y \ {1..m}. x \ A y" + using lbE(2)[OF assms(1)] by blast + then have "\f. \x \ {1..j}. x \ A (f x) \ f x \ {1..m}" by metis + then obtain f where f_def: "\x \ {1..j}. x \ A (f x) \ f x \ {1..m}" .. + then have "card (f ` {1..j}) \ card {1..m}" + by (meson card_mono finite_atLeastAtMost image_subset_iff) + also have "... < card {1..j}" using assms(2) by simp + finally have "card (f ` {1..j}) < card {1..j}" . + then have "\ inj_on f {1..j}" using pigeonhole by blast + then have "\x \ {1..j}. \y \ {1..j}. x \ y \ f x = f y" + unfolding inj_on_def by blast + then show ?thesis using f_def by metis +qed + +text \If \T\ and \A\ are a correct load balancing for \j\ jobs and \m\ machines with \j > m\, + and the jobs are sorted in descending order, then there exists a machine \x \ {1..m}\ + whose load is at least twice as large as the processing time of job \j\.\ +lemma sorted_job_lower_bound_machine: + assumes "lb T A j" "j > m" "sorted j" + shows "\x \ {1..m}. 2 * t j \ T x" +proof - + \ \Step 1: Obtaining the jobs\ + note lbrules = lbE[OF assms(1)] + obtain j\<^sub>1 j\<^sub>2 x where *: + "j\<^sub>1 \ {1..j}" "j\<^sub>2 \ {1..j}" "x \ {1..m}" "j\<^sub>1 \ j\<^sub>2" "j\<^sub>1 \ A x" "j\<^sub>2 \ A x" + using j_gt_m_pigeonhole[OF assms(1,2)] by blast + + \ \Step 2: Jobs contained in sum\ + have "finite (A x)" using assms(1) *(3) by simp + then have SUM: "(\i \ A x. t i) = t j\<^sub>1 + t j\<^sub>2 + (\i \ A x - {j\<^sub>1} - {j\<^sub>2}. t i)" + using *(4-6) by (simp add: sum.remove) + + \ \Step 3: Proof of lower bound\ + have "t j \ t j\<^sub>1" "t j \ t j\<^sub>2" + using assms(3) *(1-2) unfolding sorted_def by auto + then have "2 * t j \ t j\<^sub>1 + t j\<^sub>2" by simp + also have "... \ (\i \ A x. t i)" unfolding SUM by simp + finally have "2 * t j \ T x" using lbrules(3) *(3) by simp + then show ?thesis using *(3) by blast +qed + +text \Reasoning analogous to @{thm [source] job_lower_bound_makespan}.\ +lemma sorted_job_lower_bound_makespan: + assumes "lb T A j" "j > m" "sorted j" + shows "2 * t j \ makespan T" +proof - + obtain x where x_def: "x \ {1..m}" "2 * t j \ T x" + using sorted_job_lower_bound_machine[OF assms] .. + with makespan_correct(1) have "T x \ makespan T" by blast + with x_def(2) show ?thesis by simp +qed + +lemma min_zero: + assumes "x \ {1..k}" "T x = 0" + shows "T (min\<^sub>k T k) = 0" + using assms(1) +proof (induction k) + case (Suc k) + show ?case proof (cases \x = Suc k\) + case True + then show ?thesis using assms(2) by (simp add: Let_def) + next + case False + with Suc have "T (min\<^sub>k T k) = 0" by simp + then show ?thesis by simp + qed +qed simp + +lemma min_zero_index: + assumes "x \ {1..k}" "T x = 0" + shows "min\<^sub>k T k \ x" + using assms(1) +proof (induction k) + case (Suc k) + show ?case proof (cases \x = Suc k\) + case True + then show ?thesis using min_in_range[of "Suc k"] by simp + next + case False + with Suc.prems have "x \ {1..k}" by simp + from min_zero[OF this, of T] assms(2) Suc.IH[OF this] + show ?thesis by simp + qed +qed simp + +definition inv\<^sub>2 :: "(nat \ nat) \ (nat \ nat set) \ nat \ bool" where + "inv\<^sub>2 T A j = (lb T A j \ j \ n + \ (\T' A'. lb T' A' j \ makespan T \ 3 / 2 * makespan T') + \ (\x > j. T x = 0) + \ (j \ m \ makespan T = Max\<^sub>0 (t ` {1..j})))" + +lemma inv\<^sub>2E: + assumes "inv\<^sub>2 T A j" + shows "lb T A j" "j \ n" + "lb T' A' j \ makespan T \ 3 / 2 * makespan T'" + "\x > j. T x = 0" "j \ m \ makespan T = Max\<^sub>0 (t ` {1..j})" + using assms unfolding inv\<^sub>2_def by blast+ + +lemma inv\<^sub>2I: + assumes "lb T A j" "j \ n" + "\T' A'. lb T' A' j \ makespan T \ 3 / 2 * makespan T'" + "\x > j. T x = 0" + "j \ m \ makespan T = Max\<^sub>0 (t ` {1..j})" + shows "inv\<^sub>2 T A j" + unfolding inv\<^sub>2_def using assms by blast + +lemma inv\<^sub>2_step: + assumes "sorted n" "inv\<^sub>2 T A j" "j < n" + shows "inv\<^sub>2 (T (min\<^sub>k T m := T(min\<^sub>k T m) + t(Suc j))) + (A (min\<^sub>k T m := A(min\<^sub>k T m) \ {Suc j})) (Suc j)" + (is \inv\<^sub>2 ?T ?A _\) +proof (cases \Suc j > m\) + case True note invrules = inv\<^sub>2E[OF assms(2)] + \ \Greedy is correct\ + have LB: "lb ?T ?A (Suc j)" + using add_job[OF invrules(1) min_in_range[OF m_gt_0]] by blast + \ \Greedy maintains approximation factor\ + have MK: "\T' A'. lb T' A' (Suc j) \ makespan ?T \ 3 / 2 * makespan T'" + proof rule+ + fix T\<^sub>1 A\<^sub>1 assume "lb T\<^sub>1 A\<^sub>1 (Suc j)" + from smaller_optimum[OF this] + obtain T\<^sub>0 A\<^sub>0 where "lb T\<^sub>0 A\<^sub>0 j" "makespan T\<^sub>0 \ makespan T\<^sub>1" by blast + then have IH: "makespan T \ 3 / 2 * makespan T\<^sub>1" + using invrules(3) by force + show "makespan ?T \ 3 / 2 * makespan T\<^sub>1" + proof (cases \makespan ?T = T (min\<^sub>k T m) + t (Suc j)\) + case True + have "m * T (min\<^sub>k T m) \ (\i \ {1..m}. T i)" by (rule min_avg) + also have "... = (\i \ {1..j}. t i)" by (rule lb_impl_job_sum[OF invrules(1)]) + finally have "real m * T (min\<^sub>k T m) \ (\i \ {1..j}. t i)" + by (auto dest: of_nat_mono) + with m_gt_0 have "T (min\<^sub>k T m) \ (\i \ {1..j}. t i) / m" + by (simp add: field_simps) + then have "T (min\<^sub>k T m) \ makespan T\<^sub>1" + using job_dist_lower_bound_makespan[OF \lb T\<^sub>0 A\<^sub>0 j\] + and \makespan T\<^sub>0 \ makespan T\<^sub>1\ by linarith + moreover have "2 * t (Suc j) \ makespan T\<^sub>1" + using sorted_job_lower_bound_makespan[OF \lb T\<^sub>1 A\<^sub>1 (Suc j)\ \Suc j > m\] + and assms(1,3) by simp + ultimately show ?thesis unfolding True by simp + next + case False show ?thesis using remove_small_job[OF False] IH by simp + qed + qed + have "\x > Suc j. ?T x = 0" + using invrules(4) min_in_range[OF m_gt_0, of T] True by simp + with inv\<^sub>2I[OF LB _ MK] show ?thesis using assms(3) True by simp +next + case False + then have IN_RANGE: "Suc j \ {1..m}" by simp + note invrules = inv\<^sub>2E[OF assms(2)] + then have "T (Suc j) = 0" by blast + + \ \Greedy is correct\ + have LB: "lb ?T ?A (Suc j)" + using add_job[OF invrules(1) min_in_range[OF m_gt_0]] by blast + + \ \Greedy is trivially optimal\ + from IN_RANGE \T (Suc j) = 0\ have "min\<^sub>k T m \ Suc j" + using min_zero_index by blast + with invrules(4) have EMPTY: "\x > Suc j. ?T x = 0" by simp + from IN_RANGE \T (Suc j) = 0\ have "T (min\<^sub>k T m) = 0" + using min_zero by blast + with fun_upd_f_Max\<^sub>0[OF min_in_range[OF m_gt_0]] invrules(5) False + have TRIV: "makespan ?T = Max\<^sub>0 (t ` {1..Suc j})" unfolding f_Max\<^sub>0_equiv[symmetric] by simp + have MK: "\T' A'. lb T' A' (Suc j) \ makespan ?T \ 3 / 2 * makespan T'" + by (auto simp: TRIV[folded f_Max\<^sub>0_equiv] + dest!: max_job_lower_bound_makespan[folded f_Max\<^sub>0_equiv]) + + from inv\<^sub>2I[OF LB _ MK EMPTY TRIV] show ?thesis using assms(3) by simp +qed + +lemma sorted_greedy_approximation: +"sorted n \ VARS T A i j +{True} +T := (\_. 0); +A := (\_. {}); +j := 0; +WHILE j < n INV {inv\<^sub>2 T A j} DO + i := min\<^sub>k T m; + j := (Suc j); + A := A (i := A(i) \ {j}); + T := T (i := T(i) + t j) +OD +{lb T A n \ (\T' A'. lb T' A' n \ makespan T \ 3 / 2 * makespan T')}" +proof (vcg, goal_cases) + case (1 T A i j) + then show ?case by (simp add: lb_def inv\<^sub>2_def) +next + case (2 T A i j) + then show ?case using inv\<^sub>2_step by simp +next + case (3 T A i j) + then show ?case unfolding inv\<^sub>2_def by force +qed + +end (* LoadBalancing *) + +end (* Theory *) \ No newline at end of file diff --git a/thys/Approximation_Algorithms/Approx_MIS_Hoare.thy b/thys/Approximation_Algorithms/Approx_MIS_Hoare.thy new file mode 100755 --- /dev/null +++ b/thys/Approximation_Algorithms/Approx_MIS_Hoare.thy @@ -0,0 +1,561 @@ +section "Independent Set" + +theory Approx_MIS_Hoare +imports + "HOL-Hoare.Hoare_Logic" + "HOL-Library.Disjoint_Sets" +begin + + +text \The algorithm is classical, the proofs are inspired by the ones +by Berghammer and M\"uller-Olm \cite{BerghammerM03}. +In particular the approximation ratio is improved from \\+1\ to \\\.\ + + +subsection "Graph" + +text \A set set is simply a set of edges, where an edge is a 2-element set.\ + +definition independent_vertices :: "'a set set \ 'a set \ bool" where +"independent_vertices E S \ S \ \E \ (\v1 v2. v1 \ S \ v2 \ S \ {v1, v2} \ E)" + +locale Graph_E = + fixes E :: "'a set set" + assumes finite_E: "finite E" + assumes edges2: "e \ E \ card e = 2" +begin + +fun vertices :: "'a set set \ 'a set" where +"vertices G = \G" + +abbreviation V :: "'a set" where +"V \ vertices E" + +definition approximation_miv :: "nat \ 'a set \ bool" where +"approximation_miv n S \ independent_vertices E S \ (\S'. independent_vertices E S' \ card S' \ card S * n)" + +fun neighbors :: "'a \ 'a set" where +"neighbors v = {u. {u,v} \ E}" + +fun degree_vertex :: "'a \ nat" where +"degree_vertex v = card (neighbors v)" + +abbreviation \ :: nat where +"\ \ Max{degree_vertex u|u. u \ V}" + +lemma finite_edges: "e \ E \ finite e" + using card_ge_0_finite and edges2 by force + +lemma finite_V: "finite V" + using finite_edges and finite_E by auto + +lemma finite_neighbors: "finite (neighbors u)" + using finite_V and rev_finite_subset [of V "neighbors u"] by auto + +lemma independent_vertices_finite: "independent_vertices E S \ finite S" + by (metis rev_finite_subset independent_vertices_def vertices.simps finite_V) + +lemma edge_ex_vertices: "e \ E \ \u v. u \ v \ e = {u, v}" +proof - + assume "e \ E" + then have "card e = Suc (Suc 0)" using edges2 by auto + then show "\u v. u \ v \ e = {u, v}" + by (metis card_eq_SucD insertI1) +qed + +lemma \_pos [simp]: "E = {} \ 0 < \" +proof cases + assume "E = {}" + then show "E = {} \ 0 < \" by auto +next + assume 1: "E \ {}" + then have "V \ {}" using edges2 by fastforce + moreover have "finite {degree_vertex u |u. u \ V}" + by (metis finite_V finite_imageI Setcompr_eq_image) + ultimately have 2: "\ \ {degree_vertex u |u. u \ V}" using Max_in by auto + have "\ \ 0" + proof + assume "\ = 0" + with 2 obtain u where 3: "u \ V" and 4: "degree_vertex u = 0" by auto + from 3 obtain e where 5: "e \ E" and "u \ e" by auto + moreover with 4 have "\v. {u, v} \ e" using finite_neighbors insert_absorb by fastforce + ultimately show False using edge_ex_vertices by auto + qed + then show "E = {} \ 0 < \" by auto +qed + +lemma \_max_degree: "u \ V \ degree_vertex u \ \" +proof - + assume H: "u \ V" + have "finite {degree_vertex u |u. u \ V}" + by (metis finite_V finite_imageI Setcompr_eq_image) + with H show "degree_vertex u \ \" using Max_ge by auto +qed + +subsection \Wei's algorithm: \(\+1)\-approximation\ + +text \The 'functional' part of the invariant, used to prove that the algorithm produces an independent set of vertices.\ + +definition inv_iv :: "'a set \ 'a set \ bool" where +"inv_iv S X \ independent_vertices E S + \ X \ V + \ (\v1 \ (V - X). \v2 \ S. {v1, v2} \ E) + \ S \ X" + +text \Strenghten the invariant with an approximation ratio \r\:\ + +definition inv_approx :: "'a set \ 'a set \ nat \ bool" where +"inv_approx S X r \ inv_iv S X \ card X \ card S * r" + +text \Preservation of the functional invariant:\ + +lemma inv_preserv: + fixes S :: "'a set" + and X :: "'a set" + and x :: "'a" + assumes inv: "inv_iv S X" + and x_def: "x \ V - X" + shows "inv_iv (insert x S) (X \ neighbors x \ {x})" +proof - + have inv1: "independent_vertices E S" + and inv2: "X \ V" + and inv3: "S \ X" + and inv4: "\v1 v2. v1 \ (V - X) \ v2 \ S \ {v1, v2} \ E" + using inv unfolding inv_iv_def by auto + have finite_S: "finite S" using inv1 and independent_vertices_finite by auto + have S1: "\y \ S. {x, y} \ E" using inv4 and x_def by blast + have S2: "\x \ S. \y \ S. {x, y} \ E" using inv1 unfolding independent_vertices_def by metis + have S3: "v1 \ insert x S \ v2 \ insert x S \ {v1, v2} \ E" for v1 v2 + proof - + assume "v1 \ insert x S" and "v2 \ insert x S" + then consider + (a) "v1 = x" and "v2 = x" + | (b) "v1 = x" and "v2 \ S" + | (c) "v1 \ S" and "v2 = x" + | (d) "v1 \ S" and "v2 \ S" + by auto + then show "{v1, v2} \ E" + proof cases + case a then show ?thesis using edges2 by force + next + case b then show ?thesis using S1 by auto + next + case c then show ?thesis using S1 by (metis doubleton_eq_iff) + next + case d then show ?thesis using S2 by auto + qed + qed + (* invariant conjunct 1 *) + have "independent_vertices E (insert x S)" + using S3 and inv1 and x_def unfolding independent_vertices_def by auto + (* invariant conjunct 2 *) + moreover have "X \ neighbors x \ {x} \ V" + proof + fix xa + assume "xa \ X \ neighbors x \ {x}" + then consider (a) "xa \ X" | (b) "xa \ neighbors x" | (c) "xa = x" by auto + then show "xa \ V" + proof cases + case a + then show ?thesis using inv2 by blast + next + case b + then show ?thesis by auto + next + case c + then show ?thesis using x_def by blast + qed + qed + (* invariant conjunct 3 *) + moreover have "insert x S \ X \ neighbors x \ {x}" using inv3 by auto + (* invariant conjunct 4 *) + moreover have "v1 \ V - (X \ neighbors x \ {x}) \ v2 \ insert x S \ {v1, v2} \ E" for v1 v2 + proof - + assume H: "v1 \ V - (X \ neighbors x \ {x})" and "v2 \ insert x S" + then consider (a) "v2 = x" | (b) "v2 \ S" by auto + then show "{v1, v2} \ E" + proof cases + case a + with H have "v1 \ neighbors v2" by blast + then show ?thesis by auto + next + case b + from H have "v1 \ V - X" by blast + with b and inv4 show ?thesis by blast + qed + qed + (* conclusion *) + ultimately show "inv_iv (insert x S) (X \ neighbors x \ {x})" unfolding inv_iv_def by blast +qed + +lemma inv_approx_preserv: + assumes inv: "inv_approx S X (\ + 1)" + and x_def: "x \ V - X" + shows "inv_approx (insert x S) (X \ neighbors x \ {x}) (\ + 1)" +proof - + have finite_S: "finite S" using inv and independent_vertices_finite + unfolding inv_approx_def inv_iv_def by auto + have Sx: "x \ S" using inv and x_def unfolding inv_approx_def inv_iv_def by blast + (* main invariant is preserved *) + from inv have "inv_iv S X" unfolding inv_approx_def by auto + with x_def have "inv_iv (insert x S) (X \ neighbors x \ {x})" + proof (intro inv_preserv, auto) qed + (* the approximation ratio is preserved (at most \+1 vertices are removed in any iteration) *) + moreover have "card (X \ neighbors x \ {x}) \ card (insert x S) * (\ + 1)" + proof - + have "degree_vertex x \ \" using \_max_degree and x_def by auto + then have "card (neighbors x \ {x}) \ \ + 1" using card_Un_le [of "neighbors x" "{x}"] by auto + then have "card (X \ neighbors x \ {x}) \ card X + \ + 1" using card_Un_le [of X "neighbors x \ {x}"] by auto + also have "... \ card S * (\ + 1) + \ + 1" using inv unfolding inv_approx_def by auto + also have "... = card (insert x S) * (\ + 1)" using finite_S and Sx by auto + finally show ?thesis . + qed + (* conclusion *) + ultimately show "inv_approx (insert x S) (X \ neighbors x \ {x}) (\ + 1)" + unfolding inv_approx_def by auto +qed + +(* the antecedent combines inv_approx (for an arbitrary ratio r) and the negated post-condition *) +lemma inv_approx: "independent_vertices E S \ card V \ card S * r \ approximation_miv r S" +proof - + assume 1: "independent_vertices E S" and 2: "card V \ card S * r" + have "independent_vertices E S' \ card S' \ card S * r" for S' + proof - + assume "independent_vertices E S'" + then have "S' \ V" unfolding independent_vertices_def by auto + then have "card S' \ card V" using finite_V and card_mono by auto + also have "... \ card S * r" using 2 by auto + finally show "card S' \ card S * r" . + qed + with 1 show "approximation_miv r S" unfolding approximation_miv_def by auto +qed + +theorem wei_approx_\_plus_1: +"VARS (S :: 'a set) (X :: 'a set) (x :: 'a) + { True } + S := {}; + X := {}; + WHILE X \ V + INV { inv_approx S X (\ + 1) } + DO x := (SOME x. x \ V - X); + S := insert x S; + X := X \ neighbors x \ {x} + OD + { approximation_miv (\ + 1) S }" +proof (vcg, goal_cases) + case (1 S X x) (* invariant initially true *) + then show ?case unfolding inv_approx_def inv_iv_def independent_vertices_def by auto +next + case (2 S X x) (* invariant preserved by loop *) + (* definedness of assignment *) + let ?x = "(SOME x. x \ V - X)" + have "V - X \ {}" using 2 unfolding inv_approx_def inv_iv_def by blast + then have "?x \ V - X" using some_in_eq by metis + with 2 show ?case using inv_approx_preserv by auto +next + case (3 S X x) (* invariant implies post-condition *) + then show ?case using inv_approx unfolding inv_approx_def inv_iv_def by auto +qed + + +subsection \Wei's algorithm: \\\-approximation\ + +text \The previous approximation uses very little information about the optimal solution (it has at most as many vertices as the set itself). With some extra effort we can improve the ratio to \\\ instead of \\+1\. In order to do that we must show that among the vertices removed in each iteration, at most \\\ could belong to an optimal solution. This requires carrying around a set \P\ (via a ghost variable) which records the vertices deleted in each iteration.\ + +definition inv_partition :: "'a set \ 'a set \ 'a set set \ bool" where +"inv_partition S X P \ inv_iv S X + \ \P = X + \ (\p \ P. \s \ V. p = {s} \ neighbors s) + \ card P = card S + \ finite P" + +lemma inv_partition_preserv: + assumes inv: "inv_partition S X P" + and x_def: "x \ V - X" + shows "inv_partition (insert x S) (X \ neighbors x \ {x}) (insert ({x} \ neighbors x) P)" +proof - + have finite_S: "finite S" using inv and independent_vertices_finite + unfolding inv_partition_def inv_iv_def by auto + have Sx: "x \ S" using inv and x_def unfolding inv_partition_def inv_iv_def by blast + (* main invariant is preserved *) + from inv have "inv_iv S X" unfolding inv_partition_def by auto + with x_def have "inv_iv (insert x S) (X \ neighbors x \ {x})" + proof (intro inv_preserv, auto) qed + (* conjunct 1 *) + moreover have "\(insert ({x} \ neighbors x) P) = X \ neighbors x \ {x}" + using inv unfolding inv_partition_def by auto + (* conjunct 2 *) + moreover have "(\p\insert ({x} \ neighbors x) P. \s \ V. p = {s} \ neighbors s)" + using inv and x_def unfolding inv_partition_def by auto + (* conjunct 3 *) + moreover have "card (insert ({x} \ neighbors x) P) = card (insert x S)" + proof - + from x_def and inv have "x \ \P" unfolding inv_partition_def by auto + then have "{x} \ neighbors x \ P" by auto + then have "card (insert ({x} \ neighbors x) P) = card P + 1" using inv unfolding inv_partition_def by auto + moreover have "card (insert x S) = card S + 1" using Sx and finite_S by auto + ultimately show ?thesis using inv unfolding inv_partition_def by auto + qed + (* conjunct 4 *) + moreover have "finite (insert ({x} \ neighbors x) P)" + using inv unfolding inv_partition_def by auto + (* conclusion *) + ultimately show "inv_partition (insert x S) (X \ neighbors x \ {x}) (insert ({x} \ neighbors x) P)" + unfolding inv_partition_def by auto +qed + +lemma card_Union_le_sum_card: + fixes U :: "'a set set" + assumes "\u \ U. finite u" + shows "card (\U) \ sum card U" +proof (cases "finite U") + case False + then show "card (\U) \ sum card U" + using card_eq_0_iff finite_UnionD by auto +next + case True + then show "card (\U) \ sum card U" + proof (induct U rule: finite_induct) + case empty + then show ?case by auto + next + case (insert x F) + then have "card(\(insert x F)) \ card(x) + card (\F)" using card_Un_le by auto + also have "... \ card(x) + sum card F" using insert.hyps by auto + also have "... = sum card (insert x F)" using sum.insert_if and insert.hyps by auto + finally show ?case . + qed +qed + +(* this lemma could be more generally about U :: "nat set", but this makes its application more difficult later *) +lemma sum_card: + fixes U :: "'a set set" + and n :: nat + assumes "\S \ U. card S \ n" + shows "sum card U \ card U * n" +proof cases + assume "infinite U \ U = {}" + then have "sum card U = 0" using sum.infinite by auto + then show "sum card U \ card U * n" by auto +next + assume "\(infinite U \ U = {})" + with assms have "finite U" and "U \ {}"and "\S \ U. card S \ n" by auto + then show "sum card U \ card U * n" + proof (induct U rule: finite_ne_induct) + case (singleton x) + then show ?case by auto + next + case (insert x F) + assume "\S\insert x F. card S \ n" + then have 1:"card x \ n" and 2:"sum card F \ card F * n" using insert.hyps by auto + then have "sum card (insert x F) = card x + sum card F" using sum.insert_if and insert.hyps by auto + also have "... \ n + card F * n" using 1 and 2 by auto + also have "... = card (insert x F) * n" using card_insert_if and insert.hyps by auto + finally show ?case . + qed +qed + +(* among the vertices deleted in each iteration, at most \ can belong to an independent set of + vertices: the chosen vertex or (some of) its neighbors *) +lemma x_or_neighbors: + fixes P :: "'a set set" + and S :: "'a set" + assumes inv: "\p\P. \s \ V. p = {s} \ neighbors s" + and ivS: "independent_vertices E S" + shows "\p \ P. card (S \ p) \ \" +proof + fix p + assume "p \ P" + then obtain s where 1: "s \ V \ p = {s} \ neighbors s" using inv by blast + then show "card (S \ p) \ \" + proof cases + assume "s \ S" + then have "S \ neighbors s = {}" using ivS unfolding independent_vertices_def by auto + then have "S \ p \ {s}" using 1 by auto + then have 2: "card (S \ p) \ 1" using subset_singletonD by fastforce + consider (a) "E = {}" | (b) "0 < \" using \_pos by auto + then show "card (S \ p) \ \" + proof cases + case a + then have "S = {}" using ivS unfolding independent_vertices_def by auto + then show ?thesis by auto + next + case b + then show ?thesis using 2 by auto + qed + next + assume "s \ S" + with 1 have "S \ p \ neighbors s" by auto + then have "card (S \ p) \ degree_vertex s" using card_mono and finite_neighbors by auto + then show "card (S \ p) \ \" using 1 and \_max_degree [of s] by auto + qed +qed + +(* the premise combines the invariant and the negated post-condition *) +lemma inv_partition_approx: "inv_partition S V P \ approximation_miv \ S" +proof - + assume H1: "inv_partition S V P" + then have "independent_vertices E S" unfolding inv_partition_def inv_iv_def by auto + moreover have "independent_vertices E S' \ card S' \ card S * \" for S' + proof - + let ?I = "{S' \ p | p. p \ P}" + (* split the optimal solution among the sets of P, which cover V so no element is + lost. We obtain a cover of S' and show the required bound on its cardinality *) + assume H2: "independent_vertices E S'" + then have "S' \ V" unfolding independent_vertices_def using vertices.simps by blast + with H1 have "S' = S' \ \P" unfolding inv_partition_def by auto + then have "S' = (\p \ P. S' \ p)" using Int_Union by auto + then have "S' = \?I" by blast + moreover have "finite S'" using H2 and independent_vertices_finite by auto + then have "p \ P \ finite (S' \ p)" for p by auto + ultimately have "card S' \ sum card ?I" using card_Union_le_sum_card [of ?I] by auto + also have "... \ card ?I * \" + using x_or_neighbors [of P S'] + and sum_card [of ?I \] + and H1 and H2 unfolding inv_partition_def by auto + also have "... \ card P * \" + proof - + have "finite P" using H1 unfolding inv_partition_def by auto + then have "card ?I \ card P" + using Setcompr_eq_image [of "\p. S' \ p" P] + and card_image_le unfolding inv_partition_def by auto + then show ?thesis by auto + qed + also have "... = card S * \" using H1 unfolding inv_partition_def by auto + ultimately show "card S' \ card S * \" by auto + qed + ultimately show "approximation_miv \ S" unfolding approximation_miv_def by auto +qed + +theorem wei_approx_\: +"VARS (S :: 'a set) (X :: 'a set) (x :: 'a) + { True } + S := {}; + X := {}; + WHILE X \ V + INV { \P. inv_partition S X P } + DO x := (SOME x. x \ V - X); + S := insert x S; + X := X \ neighbors x \ {x} + OD + { approximation_miv \ S }" +proof (vcg, goal_cases) + case (1 S X x) (* invariant initially true *) + (* the invariant is initially true with the ghost variable P := {} *) + have "inv_partition {} {} {}" unfolding inv_partition_def inv_iv_def independent_vertices_def by auto + then show ?case by auto +next + case (2 S X x) (* invariant preserved by loop *) + (* definedness of assignment *) + let ?x = "(SOME x. x \ V - X)" + from 2 obtain P where I: "inv_partition S X P" by auto + then have "V - X \ {}" using 2 unfolding inv_partition_def by auto + then have "?x \ V - X" using some_in_eq by metis + (* show that the invariant is true with the ghost variable P := insert ({?x} \ neighbors ?x) P *) + with I have "inv_partition (insert ?x S) (X \ neighbors ?x \ {?x}) (insert ({?x} \ neighbors ?x) P)" + using inv_partition_preserv by blast + then show ?case by auto +next + case (3 S X x) (* invariant implies post-condition *) + then show ?case using inv_partition_approx unfolding inv_approx_def by auto +qed + +subsection "Wei's algorithm with dynamically computed approximation ratio" + +text \In this subsection, we augment the algorithm with a variable used to compute the effective approximation ratio of the solution. In addition, the vertex of smallest degree is picked. With this heuristic, the algorithm achieves an approximation ratio of \(\+2)/3\, but this is not proved here.\ + +definition vertex_heuristic :: "'a set \ 'a \ bool" where +"vertex_heuristic X v = (\u \ V - X. card (neighbors v - X) \ card (neighbors u - X))" + +(* this lemma is needed to show that there exist a vertex to be picked by the heuristic *) +lemma ex_min_finite_set: + fixes S :: "'a set" + and f :: "'a \ nat" + shows "finite S \ S \ {} \ \x. x \ S \ (\y \ S. f x \ f y)" + (is "?P1 \ ?P2 \ \x. ?minf S x") +proof (induct S rule: finite_ne_induct) + case (singleton x) + have "?minf {x} x" by auto + then show ?case by auto +next + case (insert x F) + from insert(4) obtain y where Py: "?minf F y" by auto + show "\z. ?minf (insert x F) z" + proof cases + assume "f x < f y" + then have "?minf (insert x F) x" using Py by auto + then show ?case by auto + next + assume "\f x < f y" + then have "?minf (insert x F) y" using Py by auto + then show ?case by auto + qed +qed + +lemma inv_approx_preserv2: + fixes S :: "'a set" + and X :: "'a set" + and s :: nat + and x :: "'a" + assumes inv: "inv_approx S X s" + and x_def: "x \ V - X" + shows "inv_approx (insert x S) (X \ neighbors x \ {x}) (max (card (neighbors x \ {x} - X)) s)" +proof - + have finite_S: "finite S" using inv and independent_vertices_finite unfolding inv_approx_def inv_iv_def by auto + have Sx: "x \ S" using inv and x_def unfolding inv_approx_def inv_iv_def by blast + (* main invariant is preserved *) + from inv have "inv_iv S X" unfolding inv_approx_def by auto + with x_def have "inv_iv (insert x S) (X \ neighbors x \ {x})" + proof (intro inv_preserv, auto) qed + (* the approximation ratio is preserved *) + moreover have "card (X \ neighbors x \ {x}) \ card (insert x S) * max (card (neighbors x \ {x} - X)) s" + proof - + let ?N = "neighbors x \ {x} - X" + have "card (X \ ?N) \ card X + card ?N" using card_Un_le [of X ?N] by auto + also have "... \ card S * s + card ?N" using inv unfolding inv_approx_def by auto + also have "... \ card S * max (card ?N) s + card ?N" by auto + also have "... \ card S * max (card ?N) s + max (card ?N) s" by auto + also have "... = card (insert x S) * max (card ?N) s" using Sx and finite_S by auto + finally show ?thesis by auto + qed + (* conclusion *) + ultimately show "inv_approx (insert x S) (X \ neighbors x \ {x}) (max (card (neighbors x \ {x} - X)) s)" + unfolding inv_approx_def by auto +qed + +theorem wei_approx_min_degree_heuristic: +"VARS (S :: 'a set) (X :: 'a set) (x :: 'a) (r :: nat) + { True } + S := {}; + X := {}; + r := 0; + WHILE X \ V + INV { inv_approx S X r } + DO x := (SOME x. x \ V - X \ vertex_heuristic X x); + S := insert x S; + r := max (card (neighbors x \ {x} - X)) r; + X := X \ neighbors x \ {x} + OD + { approximation_miv r S }" +proof (vcg, goal_cases) + case (1 S X x r) (* invariant initially true *) + then show ?case unfolding inv_approx_def inv_iv_def independent_vertices_def by auto +next + case (2 S X x r) (* invariant preserved by loop *) + (* definedness of assignment *) + let ?x = "(SOME x. x \ V - X \ vertex_heuristic X x)" + have "V - X \ {}" using 2 unfolding inv_approx_def inv_iv_def by blast + moreover have "finite (V - X)" using 2 and finite_V by auto + ultimately have "\x. x \ V - X \ vertex_heuristic X x" + using ex_min_finite_set [where ?f = "\x. card (neighbors x - X)"] + unfolding vertex_heuristic_def by auto + then have x_def: "?x \ V - X \ vertex_heuristic X ?x" + using someI_ex [where ?P = "\x. x \ V - X \ vertex_heuristic X x"] by auto + with 2 show ?case using inv_approx_preserv2 by auto +next + case (3 S X x r) + then show ?case using inv_approx unfolding inv_approx_def inv_iv_def by auto +qed + +end +end \ No newline at end of file diff --git a/thys/Approximation_Algorithms/Approx_VC_Hoare.thy b/thys/Approximation_Algorithms/Approx_VC_Hoare.thy new file mode 100644 --- /dev/null +++ b/thys/Approximation_Algorithms/Approx_VC_Hoare.thy @@ -0,0 +1,202 @@ +section "Vertex Cover" + +theory Approx_VC_Hoare +imports "HOL-Hoare.Hoare_Logic" +begin + +text \The algorithm is classical, the proof is based on and augments the one +by Berghammer and M\"uller-Olm \cite{BerghammerM03}.\ + +subsection "Graph" + +text \A graph is simply a set of edges, where an edge is a 2-element set.\ + +definition vertex_cover :: "'a set set \ 'a set \ bool" where +"vertex_cover E C = (\e \ E. e \ C \ {})" + +abbreviation matching :: "'a set set \ bool" where +"matching M \ pairwise disjnt M" + +lemma card_matching_vertex_cover: + "\ finite C; matching M; M \ E; vertex_cover E C \ \ card M \ card C" +apply(erule card_le_if_inj_on_rel[where r = "\e v. v \ e"]) + apply (meson disjnt_def disjnt_iff vertex_cover_def subsetCE) +by (meson disjnt_iff pairwise_def) + + +subsection "The Approximation Algorithm" + +text \Formulated using a simple(!) predefined Hoare-logic. +This leads to a streamlined proof based on standard invariant reasoning. + +The nondeterministic selection of an element from a set \F\ is simulated by @{term "SOME x. x \ F"}. +The \SOME\ operator is built into HOL: @{term "SOME x. P x"} denotes some \x\ that satisfies \P\ +if such an \x\ exists; otherwise it denotes an arbitrary element. Note that there is no +actual nondeterminism involved: @{term "SOME x. P x"} is some fixed element +but in general we don't know which one. Proofs about \SOME\ are notoriously tedious. +Typically it involves showing first that @{prop "\x. P x"}. Then @{thm someI_ex} implies +@{prop"P (SOME x. P x)"}. There are a number of (more) useful related theorems: +just click on @{thm someI_ex} to be taken there.\ + +text \Convenient notation for choosing an arbitrary element from a set:\ +abbreviation "some A \ SOME x. x \ A" + +locale Edges = + fixes E :: "'a set set" + assumes finE: "finite E" + assumes edges2: "e \ E \ card e = 2" +begin + +text \The invariant:\ + +definition "inv_matching C F M = + (matching M \ M \ E \ card C \ 2 * card M \ (\e \ M. \f \ F. e \ f = {}))" + +definition invar :: "'a set \ 'a set set \ bool" where +"invar C F = (F \ E \ vertex_cover (E-F) C \ finite C \ (\M. inv_matching C F M))" + +text \Preservation of the invariant by the loop body:\ + +lemma invar_step: + assumes "F \ {}" "invar C F" + shows "invar (C \ some F) (F - {e' \ F. some F \ e' \ {}})" +proof - + from assms(2) obtain M where "F \ E" and vc: "vertex_cover (E-F) C" and fC: "finite C" + and m: "matching M" "M \ E" and card: "card C \ 2 * card M" + and disj: "\e \ M. \f \ F. e \ f = {}" + by (auto simp: invar_def inv_matching_def) + let ?e = "SOME e. e \ F" + have "?e \ F" using \F \ {}\ by (simp add: some_in_eq) + hence fe': "finite ?e" using \F \ E\ edges2 by(intro card_ge_0_finite) auto + have "?e \ M" using edges2 \?e \ F\ disj \F \ E\ by fastforce + have card': "card (C \ ?e) \ 2 * card (insert ?e M)" + using \?e \ F\ \?e \ M\ card_Un_le[of C ?e] \F \ E\ edges2 card finite_subset[OF m(2) finE] + by fastforce + let ?M = "M \ {?e}" + have vc': "vertex_cover (E - (F - {e' \ F. ?e \ e' \ {}})) (C \ ?e)" + using vc by(auto simp: vertex_cover_def) + have m': "inv_matching (C \ ?e) (F - {e' \ F. ?e \ e' \ {}}) ?M" + using m card' \F \ E\ \?e \ F\ disj + by(auto simp: inv_matching_def Int_commute disjnt_def pairwise_insert) + show ?thesis using \F \ E\ vc' fC fe' m' by(auto simp add: invar_def Let_def) +qed + + +lemma approx_vertex_cover: +"VARS C F + {True} + C := {}; + F := E; + WHILE F \ {} + INV {invar C F} + DO C := C \ some F; + F := F - {e' \ F. some F \ e' \ {}} + OD + {vertex_cover E C \ (\C'. finite C' \ vertex_cover E C' \ card C \ 2 * card C')}" +proof (vcg, goal_cases) + case (1 C F) + have "inv_matching {} E {}" by (auto simp add: inv_matching_def) + with 1 show ?case by (auto simp add: invar_def vertex_cover_def) +next + case (2 C F) + thus ?case using invar_step[of F C] by(auto simp: Let_def) +next + case (3 C F) + then obtain M :: "'a set set" where + post: "vertex_cover E C" "matching M" "M \ E" "card C \ 2 * card M" + by(auto simp: invar_def inv_matching_def) + + have opt: "card C \ 2 * card C'" if C': "finite C'" "vertex_cover E C'" for C' + proof - + note post(4) + also have "2 * card M \ 2 * card C'" + using card_matching_vertex_cover[OF C'(1) post(2,3) C'(2)] by simp + finally show "card C \ 2 * card C'" . + qed + + show ?case using post(1) opt by auto +qed + +end (* locale Graph *) + +subsection "Version for Hypergraphs" + +text \Almost the same. We assume that the degree of every edge is bounded.\ + +locale Bounded_Hypergraph = + fixes E :: "'a set set" + fixes k :: nat + assumes finE: "finite E" + assumes edge_bnd: "e \ E \ finite e \ card e \ k" + assumes E1: "{} \ E" +begin + +definition "inv_matching C F M = + (matching M \ M \ E \ card C \ k * card M \ (\e \ M. \f \ F. e \ f = {}))" + +definition invar :: "'a set \ 'a set set \ bool" where +"invar C F = (F \ E \ vertex_cover (E-F) C \ finite C \ (\M. inv_matching C F M))" + +lemma invar_step: + assumes "F \ {}" "invar C F" + shows "invar (C \ some F) (F - {e' \ F. some F \ e' \ {}})" +proof - + from assms(2) obtain M where "F \ E" and vc: "vertex_cover (E-F) C" and fC: "finite C" + and m: "matching M" "M \ E" and card: "card C \ k * card M" + and disj: "\e \ M. \f \ F. e \ f = {}" + by (auto simp: invar_def inv_matching_def) + let ?e = "SOME e. e \ F" + have "?e \ F" using \F \ {}\ by (simp add: some_in_eq) + hence fe': "finite ?e" using \F \ E\ assms(2) edge_bnd by blast + have "?e \ M" using E1 \?e \ F\ disj \F \ E\ by fastforce + have card': "card (C \ ?e) \ k * card (insert ?e M)" + using \?e \ F\ \?e \ M\ card_Un_le[of C ?e] \F \ E\ edge_bnd card finite_subset[OF m(2) finE] + by fastforce + let ?M = "M \ {?e}" + have vc': "vertex_cover (E - (F - {e' \ F. ?e \ e' \ {}})) (C \ ?e)" + using vc by(auto simp: vertex_cover_def) + have m': "inv_matching (C \ ?e) (F - {e' \ F. ?e \ e' \ {}}) ?M" + using m card' \F \ E\ \?e \ F\ disj + by(auto simp: inv_matching_def Int_commute disjnt_def pairwise_insert) + show ?thesis using \F \ E\ vc' fC fe' m' by(auto simp add: invar_def Let_def) +qed + + +lemma approx_vertex_cover_bnd: +"VARS C F + {True} + C := {}; + F := E; + WHILE F \ {} + INV {invar C F} + DO C := C \ some F; + F := F - {e' \ F. some F \ e' \ {}} + OD + {vertex_cover E C \ (\C'. finite C' \ vertex_cover E C' \ card C \ k * card C')}" +proof (vcg, goal_cases) + case (1 C F) + have "inv_matching {} E {}" by (auto simp add: inv_matching_def) + with 1 show ?case by (auto simp add: invar_def vertex_cover_def) +next + case (2 C F) + thus ?case using invar_step[of F C] by(auto simp: Let_def) +next + case (3 C F) + then obtain M :: "'a set set" where + post: "vertex_cover E C" "matching M" "M \ E" "card C \ k * card M" + by(auto simp: invar_def inv_matching_def) + + have opt: "card C \ k * card C'" if C': "finite C'" "vertex_cover E C'" for C' + proof - + note post(4) + also have "k * card M \ k * card C'" + using card_matching_vertex_cover[OF C'(1) post(2,3) C'(2)] by simp + finally show "card C \ k * card C'" . + qed + + show ?case using post(1) opt by auto +qed + +end (* locale Bounded_Hypergraph *) + +end diff --git a/thys/Approximation_Algorithms/ROOT b/thys/Approximation_Algorithms/ROOT new file mode 100644 --- /dev/null +++ b/thys/Approximation_Algorithms/ROOT @@ -0,0 +1,15 @@ +chapter AFP + +session Approximation_Algorithms (AFP) = HOL + + options [timeout = 600] + sessions + "HOL-Library" + "HOL-Hoare" + theories + Approx_VC_Hoare + Approx_MIS_Hoare + Approx_LB_Hoare + Approx_BP_Hoare + document_files + "root.bib" + "root.tex" diff --git a/thys/Approximation_Algorithms/document/root.bib b/thys/Approximation_Algorithms/document/root.bib new file mode 100644 --- /dev/null +++ b/thys/Approximation_Algorithms/document/root.bib @@ -0,0 +1,41 @@ +@string{Springer="Springer"} +@string{LNCS="LNCS"} + +@inproceedings{BerghammerM03, + author = {Rudolf Berghammer and Markus M{\"{u}}ller{-}Olm}, + title = {Formal Development and Verification of Approximation Algorithms Using + Auxiliary Variables}, + booktitle = {Logic Based Program Synthesis and Transformation, {LOPSTR} 2003}, + pages = {59--74}, + year = {2003}, + crossref = {DBLP:conf/lopstr/2003}, + doi = {10.1007/978-3-540-25938-1\_6}, +} + +@proceedings{DBLP:conf/lopstr/2003, + editor = {Maurice Bruynooghe}, + title = {Logic Based Program Synthesis and Transformation, {LOPSTR} 2003}, + series = {LNCS}, + volume = {3018}, + publisher = {Springer}, + year = {2004}, +} + +@article{BerghammerR03, + author = {Rudolf Berghammer and Florian Reuter}, + title = {A linear approximation algorithm for bin packing with absolute approximation + factor 3/2}, + journal = {Sci. Comput. Program.}, + volume = {48}, + number = {1}, + pages = {67--80}, + year = {2003}, + doi = {10.1016/S0167-6423(03)00011-X}, +} + +@book{KleinbergT06, + author = {Jon M. Kleinberg and {\'{E}}va Tardos}, + title = {Algorithm Design}, + publisher = {Addison-Wesley}, + year = {2006}, +} diff --git a/thys/Approximation_Algorithms/document/root.tex b/thys/Approximation_Algorithms/document/root.tex new file mode 100644 --- /dev/null +++ b/thys/Approximation_Algorithms/document/root.tex @@ -0,0 +1,34 @@ +\documentclass[11pt,a4paper]{article} +\usepackage{isabelle,isabellesym} + +% this should be the last package used +\usepackage{pdfsetup} + +% urls in roman style, theory text in math-similar italics +\urlstyle{rm} +\isabellestyle{it} + + +\begin{document} + +\title{Verified Approximation Algorithms} +\author{Robin E{\ss}mann, Tobias Nipkow and Simon Robillard} +\maketitle + +\begin{abstract} +We present the first formal verifications of approximation algorithms +for NP-complete optimization problems: +vertex cover, independent set, load balancing, and bin packing. +The proofs correct incompletnesses in existing proofs +and improve the approximation ratio in one case. +\end{abstract} + +\tableofcontents + +% include generated text of all theories +\input{session} + +\bibliographystyle{abbrv} +\bibliography{root} + +\end{document} diff --git a/thys/ROOTS b/thys/ROOTS --- a/thys/ROOTS +++ b/thys/ROOTS @@ -1,513 +1,514 @@ AODV Auto2_HOL Auto2_Imperative_HOL AVL-Trees AWN Abortable_Linearizable_Modules Abs_Int_ITP2012 Abstract-Hoare-Logics Abstract-Rewriting Abstract_Completeness Abstract_Soundness Adaptive_State_Counting Affine_Arithmetic Aggregation_Algebras Akra_Bazzi Algebraic_Numbers Algebraic_VCs Allen_Calculus Amortized_Complexity AnselmGod Applicative_Lifting +Approximation_Algorithms Architectural_Design_Patterns Aristotles_Assertoric_Syllogistic ArrowImpossibilityGS AutoFocus-Stream Automatic_Refinement AxiomaticCategoryTheory BDD BNF_Operations Bell_Numbers_Spivey Berlekamp_Zassenhaus Bernoulli Bertrands_Postulate Bicategory BinarySearchTree Binding_Syntax_Theory Binomial-Heaps Binomial-Queues BNF_CC Bondy Boolean_Expression_Checkers Bounded_Deducibility_Security Buchi_Complementation Budan_Fourier Buffons_Needle Buildings BytecodeLogicJmlTypes C2KA_DistributedSystems CAVA_Automata CAVA_LTL_Modelchecker CCS CISC-Kernel CRDT CYK CakeML CakeML_Codegen Call_Arity Card_Equiv_Relations Card_Multisets Card_Number_Partitions Card_Partitions Cartan_FP Case_Labeling Catalan_Numbers Category Category2 Category3 Cauchy Cayley_Hamilton Certification_Monads Chord_Segments Circus Clean ClockSynchInst Closest_Pair_Points CofGroups Coinductive Coinductive_Languages Collections Comparison_Sort_Lower_Bound Compiling-Exceptions-Correctly Completeness Complete_Non_Orders Complx ComponentDependencies ConcurrentGC ConcurrentIMP Concurrent_Ref_Alg Concurrent_Revisions Consensus_Refined Constructive_Cryptography Constructor_Funs Containers CoreC++ Core_DOM Count_Complex_Roots CryptHOL CryptoBasedCompositionalProperties DFS_Framework DPT-SAT-Solver DataRefinementIBP Datatype_Order_Generator Decl_Sem_Fun_PL Decreasing-Diagrams Decreasing-Diagrams-II Deep_Learning Density_Compiler Dependent_SIFUM_Refinement Dependent_SIFUM_Type_Systems Depth-First-Search Derangements Deriving Descartes_Sign_Rule Dict_Construction Differential_Dynamic_Logic Differential_Game_Logic Dijkstra_Shortest_Path Diophantine_Eqns_Lin_Hom Dirichlet_L Dirichlet_Series Discrete_Summation DiscretePricing DiskPaxos DynamicArchitectures Dynamic_Tables E_Transcendental Echelon_Form EdmondsKarp_Maxflow Efficient-Mergesort Elliptic_Curves_Group_Law Encodability_Process_Calculi Epistemic_Logic Ergodic_Theory Error_Function Euler_MacLaurin Euler_Partition Example-Submission Factored_Transition_System_Bounding Farkas FFT FLP FOL-Fitting FOL_Harrison FOL_Seq_Calc1 Falling_Factorial_Sum FeatherweightJava Featherweight_OCL Fermat3_4 FileRefinement FinFun Finger-Trees Finite_Automata_HF First_Order_Terms First_Welfare_Theorem Fishburn_Impossibility Fisher_Yates Flow_Networks Floyd_Warshall Flyspeck-Tame FocusStreamsCaseStudies Formal_SSA Formula_Derivatives Fourier Free-Boolean-Algebra Free-Groups FunWithFunctions FunWithTilings Functional-Automata Functional_Ordered_Resolution_Prover GPU_Kernel_PL Gabow_SCC Game_Based_Crypto Gauss-Jordan-Elim-Fun Gauss_Jordan Gauss_Sums GenClock General-Triangle Generalized_Counting_Sort Generic_Deriving Generic_Join GewirthPGCProof Girth_Chromatic GoedelGod GraphMarkingIBP Graph_Saturation Graph_Theory Green Groebner_Bases Groebner_Macaulay Gromov_Hyperbolicity Group-Ring-Module HOL-CSP HOLCF-Prelude HRB-Slicing Heard_Of HereditarilyFinite Hermite Hidden_Markov_Models Higher_Order_Terms Hoare_Time HotelKeyCards Huffman Hybrid_Logic Hybrid_Multi_Lane_Spatial_Logic Hybrid_Systems_VCs HyperCTL IEEE_Floating_Point IMAP-CRDT IMO2019 IMP2 IMP2_Binary_Heap IP_Addresses Imperative_Insertion_Sort Impossible_Geometry Incompleteness Incredible_Proof_Machine Inductive_Confidentiality InfPathElimination InformationFlowSlicing InformationFlowSlicing_Inter Integration Interval_Arithmetic_Word32 Iptables_Semantics Irrationality_J_Hancl Isabelle_C Isabelle_Meta_Model Jacobson_Basic_Algebra Jinja JinjaThreads JiveDataStoreModel Jordan_Hoelder Jordan_Normal_Form KAD KAT_and_DRA KBPs KD_Tree Key_Agreement_Strong_Adversaries Kleene_Algebra Knot_Theory Knuth_Morris_Pratt Koenigsberg_Friendship Kruskal Kuratowski_Closure_Complement LLL_Basis_Reduction LLL_Factorization LOFT LTL LTL_to_DRA LTL_to_GBA LTL_Master_Theorem Lam-ml-Normalization LambdaAuth LambdaMu Lambda_Free_KBOs Lambda_Free_RPOs Landau_Symbols Laplace_Transform Latin_Square LatticeProperties Lambda_Free_EPO Launchbury Lazy-Lists-II Lazy_Case Lehmer Lifting_Definition_Option LightweightJava LinearQuantifierElim Linear_Inequalities Linear_Programming Linear_Recurrences Liouville_Numbers List-Index List-Infinite List_Interleaving List_Inversions List_Update LocalLexing Localization_Ring Locally-Nameless-Sigma Lowe_Ontological_Argument Lower_Semicontinuous Lp MFMC_Countable MSO_Regex_Equivalence Markov_Models Marriage Mason_Stothers Matrix Matrix_Tensor Matroids Max-Card-Matching Median_Of_Medians_Selection Menger MFOTL_Monitor MiniML Minimal_SSA Minkowskis_Theorem Minsky_Machines Modal_Logics_for_NTS Modular_Assembly_Kit_Security Monad_Memo_DP Monad_Normalisation MonoBoolTranAlgebra MonoidalCategory Monomorphic_Monad MuchAdoAboutTwo Multirelations Multi_Party_Computation Myhill-Nerode Name_Carrying_Type_Inference Nat-Interval-Logic Native_Word Nested_Multisets_Ordinals Network_Security_Policy_Verification Neumann_Morgenstern_Utility No_FTL_observers Nominal2 Noninterference_CSP Noninterference_Concurrent_Composition Noninterference_Generic_Unwinding Noninterference_Inductive_Unwinding Noninterference_Ipurge_Unwinding Noninterference_Sequential_Composition NormByEval Nullstellensatz Octonions Open_Induction OpSets Optics Optimal_BST Orbit_Stabiliser Order_Lattice_Props Ordered_Resolution_Prover Ordinal Ordinals_and_Cardinals Ordinary_Differential_Equations PCF PLM Pell POPLmark-deBruijn PSemigroupsConvolution Pairing_Heap Paraconsistency Parity_Game Partial_Function_MR Partial_Order_Reduction Password_Authentication_Protocol Perfect-Number-Thm Perron_Frobenius Pi_Calculus Pi_Transcendental Planarity_Certificates Polynomial_Factorization Polynomial_Interpolation Polynomials Poincare_Bendixson Pop_Refinement Posix-Lexing Possibilistic_Noninterference Pratt_Certificate Presburger-Automata Prim_Dijkstra_Simple Prime_Distribution_Elementary Prime_Harmonic_Series Prime_Number_Theorem Priority_Queue_Braun Priority_Search_Trees Probabilistic_Noninterference Probabilistic_Prime_Tests Probabilistic_System_Zoo Probabilistic_Timed_Automata Probabilistic_While Projective_Geometry Program-Conflict-Analysis Promela Proof_Strategy_Language PropResPI Propositional_Proof_Systems Prpu_Maxflow PseudoHoops Psi_Calculi Ptolemys_Theorem QHLProver QR_Decomposition Quantales Quaternions Quick_Sort_Cost RIPEMD-160-SPARK ROBDD RSAPSS Ramsey-Infinite Random_BSTs Randomised_BSTs Random_Graph_Subgraph_Threshold Randomised_Social_Choice Rank_Nullity_Theorem Real_Impl Recursion-Theory-I Refine_Imperative_HOL Refine_Monadic RefinementReactive Regex_Equivalence Regular-Sets Regular_Algebras Relation_Algebra Rep_Fin_Groups Residuated_Lattices Resolution_FOL Rewriting_Z Ribbon_Proofs Robbins-Conjecture Root_Balanced_Tree Routing Roy_Floyd_Warshall Safe_OCL SATSolverVerification SDS_Impossibility SIFPL SIFUM_Type_Systems SPARCv8 Secondary_Sylow Security_Protocol_Refinement Selection_Heap_Sort SenSocialChoice Separata Separation_Algebra Separation_Logic_Imperative_HOL SequentInvertibility Shivers-CFA ShortestPath Show Sigma_Commit_Crypto Signature_Groebner Simpl Simple_Firewall Simplex Skew_Heap Skip_Lists Slicing Smooth_Manifolds Sort_Encodings Source_Coding_Theorem Special_Function_Bounds Splay_Tree Sqrt_Babylonian Stable_Matching Statecharts Stellar_Quorums Stern_Brocot Stewart_Apollonius Stirling_Formula Stochastic_Matrices Stone_Algebras Stone_Kleene_Relation_Algebras Stone_Relation_Algebras Store_Buffer_Reduction Stream-Fusion Stream_Fusion_Code Strong_Security Sturm_Sequences Sturm_Tarski Stuttering_Equivalence Subresultants SumSquares SuperCalc Surprise_Paradox Symmetric_Polynomials Szpilrajn TESL_Language TLA Tail_Recursive_Functions Tarskis_Geometry Taylor_Models Timed_Automata Topology TortoiseHare Transcendence_Series_Hancl_Rucki Transformer_Semantics Transition_Systems_and_Automata Transitive-Closure Transitive-Closure-II Treaps Tree-Automata Tree_Decomposition Triangle Trie Twelvefold_Way Tycon Types_Tableaus_and_Goedels_God Universal_Turing_Machine UPF UPF_Firewall UpDown_Scheme UTP Valuation VectorSpace Verified-Prover VerifyThis2018 VerifyThis2019 Vickrey_Clarke_Groves VolpanoSmith WHATandWHERE_Security WebAssembly Weight_Balanced_Trees Well_Quasi_Orders Winding_Number_Eval Word_Lib WorkerWrapper XML Zeta_Function Zeta_3_Irrational ZFC_in_HOL pGCL