From f45781be71e328446e53e6fd566619050cc981d7 Mon Sep 17 00:00:00 2001 From: raj_mathe Date: Tue, 14 Jun 2022 11:24:32 +0200 Subject: [PATCH] =?UTF-8?q?master=20>=20master:=20code=20py=20-=20pad=20on?= =?UTF-8?q?es/zeros=20f=C3=BCr=20einelementige=20F=C3=A4lle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/algorithms/rucksack/algorithms.py | 31 ++++++++++++------- code/python/src/models/rucksack/mask.py | 12 +++++++ 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/code/python/src/algorithms/rucksack/algorithms.py b/code/python/src/algorithms/rucksack/algorithms.py index 189436a..b85a3e9 100644 --- a/code/python/src/algorithms/rucksack/algorithms.py +++ b/code/python/src/algorithms/rucksack/algorithms.py @@ -83,7 +83,7 @@ def rucksack_greedy_algorithm( if verbose: # Umsortierung rückgängig machen: vector = [ soln.vector[i] for i in order ]; - rucksack = [ uorder[r] for r in rucksack ]; + rucksack = sorted([ uorder[r] for r in rucksack ]); permute_data(weights=weights, values=values, items=items, perm=uorder); # Ausdrücke bestimmen: expr_value = display_sum(vector=vector, values=values); @@ -135,24 +135,29 @@ def rucksack_branch_and_bound_algorithm( S = Stack(); S.push(vector); while not S.empty(): - lb, u = estimate_lower_bound(mask=S.top(), capacity=capacity, weights=weights, values=values, items=items); + lb, u, can_add_all, can_add_none = estimate_lower_bound(mask=S.top(), capacity=capacity, weights=weights, values=values, items=items); if verbose: logged_steps.append((lb_estimate, lb, u, str(S))); # Update nur nötig, wenn die (eingeschätzte) untere Schranke von A das bisherige Minimum verbessert: A: Mask = S.pop(); if lb < lb_estimate: - # Branch: - if A.splittable(): + # Bound, wenn sich A nicht weiter aufteilen lässt od. man A wie eine einelementige Option behandeln kann: + # Branch sonst + if not A.splittable() or can_add_all or can_add_none: + lb_estimate = lb; + if can_add_all: + vector = A.pad_ones(); + elif can_add_none: + vector = A.pad_zeros(); + else: + vector = A; + else: B, C = A.split(); # NOTE: per Wahl erfüllt mind. eine Möglichkeit in B die Kapazitätsschranke. S.push(B); # Nur dann C auf Stack legen, wenn mind. eine Möglichkeit in C die Kapazitätsschranke erfüllt: if sum(weights[C.indexes_one]) <= capacity: S.push(C); - # Bound, wenn die Maske den Rucksack komplett bestimmt: - else: - lb_estimate = lb; - vector = A; # Aspekte der Lösung speichern rucksack = vector.indexes_one; # Indexes von Items im Rucksack @@ -169,7 +174,7 @@ def rucksack_branch_and_bound_algorithm( repr = display_branch_and_bound(values=values, steps=logged_steps); # Umsortierung rückgängig machen: vector = [ soln.vector[i] for i in order ]; - rucksack = [ uorder[r] for r in rucksack ]; + rucksack = sorted([ uorder[r] for r in rucksack ]); permute_data(weights=weights, values=values, items=items, perm=uorder); # Ausdrücke bestimmen: expr_value = display_sum(vector=vector, values=values); @@ -223,7 +228,7 @@ def estimate_lower_bound( weights: np.ndarray, values: np.ndarray, items: np.ndarray, -) -> Tuple[float, List[float]]: +) -> Tuple[float, List[float], bool]: ''' Wenn partielle Information über den Rucksack festgelegt ist, kann man bei dem unbekannten Teil das Rucksack-Problem @@ -257,6 +262,10 @@ def estimate_lower_bound( vector[indexes_one] = 1; vector[indexes_unset] = soln_rest.vector; + # Prüfe, ob man als Lösung alles hinzufügen kann: + can_add_all = all([m == 1 for m in soln_rest.vector]); + can_add_none = all([m == 0 for m in soln_rest.vector]); + # Einschätzung des max-Wertes (Ausgabe mit -1 multiplizieren): value_max_est = value_rucksack + value_rest; - return -value_max_est, vector.tolist(); + return -value_max_est, vector.tolist(), can_add_all, can_add_none; diff --git a/code/python/src/models/rucksack/mask.py b/code/python/src/models/rucksack/mask.py index fc36d65..606da01 100644 --- a/code/python/src/models/rucksack/mask.py +++ b/code/python/src/models/rucksack/mask.py @@ -76,5 +76,17 @@ class Mask(): vector2[self.index] = MaskValue.ONE; return Mask(vector1), Mask(vector2); + def pad_zeros(self) -> Mask: + ''' + Completes mask by filling in unset values with zeros + ''' + return Mask([ MaskValue.ZERO if u == MaskValue.UNSET else u for u in self.values ]); + + def pad_ones(self) -> Mask: + ''' + Completes mask by filling in unset values with zeros + ''' + return Mask([ MaskValue.ONE if u == MaskValue.UNSET else u for u in self.values ]); + def empty_mask(n: int): return Mask([MaskValue.UNSET for _ in range(n)]);