master > master: code py - korrigierte logik
This commit is contained in:
parent
f45781be71
commit
e3c3bbec37
@ -137,12 +137,11 @@ def rucksack_branch_and_bound_algorithm(
|
||||
while not S.empty():
|
||||
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)));
|
||||
logged_steps.append((lb_estimate, lb, str(S), u, can_add_all, can_add_none));
|
||||
# Update nur nötig, wenn die (eingeschätzte) untere Schranke von A das bisherige Minimum verbessert:
|
||||
A: Mask = S.pop();
|
||||
if lb < lb_estimate:
|
||||
# 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:
|
||||
@ -151,9 +150,9 @@ def rucksack_branch_and_bound_algorithm(
|
||||
vector = A.pad_zeros();
|
||||
else:
|
||||
vector = A;
|
||||
# Branch sonst
|
||||
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:
|
||||
@ -237,35 +236,45 @@ def estimate_lower_bound(
|
||||
|
||||
NOTE: Diese Funktion wird `g(vector)` im Skript bezeichnet.
|
||||
'''
|
||||
|
||||
# Berechnungen bei Items mit bekanntem Status in Rucksack:
|
||||
indexes_one = mask.indexes_one;
|
||||
weight_rucksack = sum(weights[indexes_one]);
|
||||
value_rucksack = sum(values[indexes_one]);
|
||||
|
||||
# Löse mit Greedy-Algorithmus auf Items mit unbekanntem Status.
|
||||
# NOTE: Lösung ist eine Überschätzung des max-Wertes.
|
||||
indexes_unset = mask.indexes_unset;
|
||||
soln_rest = rucksack_greedy_algorithm(
|
||||
capacity = capacity - weight_rucksack, # <- Kapazität = Restgewicht
|
||||
weights = weights[indexes_unset],
|
||||
values = values[indexes_unset],
|
||||
items = items[indexes_unset],
|
||||
fractional = True,
|
||||
verbose = False,
|
||||
);
|
||||
value_rest = soln_rest.total_value;
|
||||
|
||||
# Lösung des [0,1]-Vektors speichern:
|
||||
n = len(mask);
|
||||
vector = np.zeros(shape=(n,), dtype=float);
|
||||
|
||||
# Berechnungen bei Items mit bekanntem Status in Rucksack:
|
||||
value_rucksack = sum(values[indexes_one]);
|
||||
weight_rucksack = sum(weights[indexes_one]);
|
||||
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]);
|
||||
# Für Rest des Rucksacks (Items mit unbekanntem Status):
|
||||
weight_rest = capacity - weight_rucksack;
|
||||
can_add_all = False;
|
||||
can_add_none = False;
|
||||
# Prüfe, ob man als Lösung alles/nichts hinzufügen kann:
|
||||
if len(indexes_unset) > 0 and sum(weights[indexes_unset]) <= weight_rest:
|
||||
can_add_all = True;
|
||||
vector[indexes_unset] = 1;
|
||||
value_rest = sum(values[indexes_unset]);
|
||||
elif len(indexes_unset) > 0 and min(weights[indexes_unset]) > weight_rest:
|
||||
can_add_none = True;
|
||||
vector[indexes_unset] = 0;
|
||||
value_rest = 0;
|
||||
# Sonst mit Greedy-Algorithmus lösen:
|
||||
# NOTE: Lösung ist eine Überschätzung des max-Wertes.
|
||||
else:
|
||||
soln_rest = rucksack_greedy_algorithm(
|
||||
capacity = weight_rest, # <- Kapazität = Restgewicht
|
||||
weights = weights[indexes_unset],
|
||||
values = values[indexes_unset],
|
||||
items = items[indexes_unset],
|
||||
fractional = True,
|
||||
verbose = False,
|
||||
);
|
||||
value_rest = soln_rest.total_value;
|
||||
vector[indexes_unset] = soln_rest.vector;
|
||||
|
||||
# Einschätzung des max-Wertes (Ausgabe mit -1 multiplizieren):
|
||||
# Einschätzung des max-Wertes:
|
||||
value_max_est = value_rucksack + value_rest;
|
||||
|
||||
# Ausgabe mit -1 multiplizieren (weil maximiert wird):
|
||||
return -value_max_est, vector.tolist(), can_add_all, can_add_none;
|
||||
|
@ -57,7 +57,7 @@ def display_order(
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
def display_sum(
|
||||
vector: Union[List[int], List[float]],
|
||||
vector: List[float],
|
||||
values: np.ndarray,
|
||||
as_maximum: bool = True,
|
||||
) -> str:
|
||||
@ -77,27 +77,29 @@ def display_sum(
|
||||
|
||||
def display_branch_and_bound(
|
||||
values: np.ndarray,
|
||||
steps: List[Tuple[float, float, Stack]]
|
||||
steps: List[Tuple[float, float, Stack, List[float], bool, bool]]
|
||||
) -> str:
|
||||
# füge Summen-Ausdrücke für Greedy-Alg hinzu:
|
||||
rows = [];
|
||||
used_vectors = [];
|
||||
for lb_estimate, lb, u, S in steps:
|
||||
for lb_estimate, lb, S, u, can_add_all, can_add_none in steps:
|
||||
pad = '1' if can_add_all else ('0' if can_add_none else '');
|
||||
if u in used_vectors:
|
||||
rows.append((f'{lb_estimate:g}', f'{lb:g}', S));
|
||||
expr = f'{lb:g}';
|
||||
else:
|
||||
used_vectors.append(u)
|
||||
rows.append((f'{lb_estimate:g}', display_sum(vector=u, values=values, as_maximum=False), S));
|
||||
expr = display_sum(vector=u, values=values, as_maximum=False);
|
||||
rows.append((f'{lb_estimate:g}', expr, pad, S));
|
||||
|
||||
table = pd.DataFrame(rows) \
|
||||
.rename(columns={0: 'b', 1: 'g(TOP(S))', 2: 'S'}) \
|
||||
.rename(columns={0: 'b', 1: 'g(TOP(S))', 2: 'pad?', 3: 'S'}) \
|
||||
.reset_index(drop=True);
|
||||
# benutze pandas-Dataframe + tabulate, um schöner darzustellen:
|
||||
repr = tabulate(
|
||||
pd.DataFrame(table),
|
||||
headers=['b', 'g(TOP(S))', 'S'],
|
||||
headers=['b', 'g(TOP(S))', 'pad?', 'S'],
|
||||
showindex=False,
|
||||
colalign=('left', 'left', 'right'),
|
||||
colalign=('left', 'left', 'center', 'right'),
|
||||
tablefmt='rst'
|
||||
);
|
||||
return repr;
|
||||
|
@ -88,5 +88,9 @@ class Mask():
|
||||
'''
|
||||
return Mask([ MaskValue.ONE if u == MaskValue.UNSET else u for u in self.values ]);
|
||||
|
||||
@property
|
||||
def support(self) -> List[int]:
|
||||
return [ i for i, v in enumerate(self.values) if v == MaskValue.ONE ];
|
||||
|
||||
def empty_mask(n: int):
|
||||
return Mask([MaskValue.UNSET for _ in range(n)]);
|
||||
|
Loading…
Reference in New Issue
Block a user