master > master: code py - korrigierte logik

This commit is contained in:
RD 2022-06-14 12:19:35 +02:00
parent f45781be71
commit e3c3bbec37
3 changed files with 49 additions and 34 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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)]);