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():
|
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);
|
lb, u, can_add_all, can_add_none = estimate_lower_bound(mask=S.top(), capacity=capacity, weights=weights, values=values, items=items);
|
||||||
if verbose:
|
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:
|
# Update nur nötig, wenn die (eingeschätzte) untere Schranke von A das bisherige Minimum verbessert:
|
||||||
A: Mask = S.pop();
|
A: Mask = S.pop();
|
||||||
if lb < lb_estimate:
|
if lb < lb_estimate:
|
||||||
# Bound, wenn sich A nicht weiter aufteilen lässt od. man A wie eine einelementige Option behandeln kann:
|
# 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:
|
if not A.splittable() or can_add_all or can_add_none:
|
||||||
lb_estimate = lb;
|
lb_estimate = lb;
|
||||||
if can_add_all:
|
if can_add_all:
|
||||||
@ -151,9 +150,9 @@ def rucksack_branch_and_bound_algorithm(
|
|||||||
vector = A.pad_zeros();
|
vector = A.pad_zeros();
|
||||||
else:
|
else:
|
||||||
vector = A;
|
vector = A;
|
||||||
|
# Branch sonst
|
||||||
else:
|
else:
|
||||||
B, C = A.split();
|
B, C = A.split();
|
||||||
# NOTE: per Wahl erfüllt mind. eine Möglichkeit in B die Kapazitätsschranke.
|
|
||||||
S.push(B);
|
S.push(B);
|
||||||
# Nur dann C auf Stack legen, wenn mind. eine Möglichkeit in C die Kapazitätsschranke erfüllt:
|
# 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:
|
if sum(weights[C.indexes_one]) <= capacity:
|
||||||
@ -237,35 +236,45 @@ def estimate_lower_bound(
|
|||||||
|
|
||||||
NOTE: Diese Funktion wird `g(vector)` im Skript bezeichnet.
|
NOTE: Diese Funktion wird `g(vector)` im Skript bezeichnet.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
# Berechnungen bei Items mit bekanntem Status in Rucksack:
|
|
||||||
indexes_one = mask.indexes_one;
|
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;
|
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);
|
n = len(mask);
|
||||||
vector = np.zeros(shape=(n,), dtype=float);
|
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_one] = 1;
|
||||||
vector[indexes_unset] = soln_rest.vector;
|
|
||||||
|
|
||||||
# Prüfe, ob man als Lösung alles hinzufügen kann:
|
# Für Rest des Rucksacks (Items mit unbekanntem Status):
|
||||||
can_add_all = all([m == 1 for m in soln_rest.vector]);
|
weight_rest = capacity - weight_rucksack;
|
||||||
can_add_none = all([m == 0 for m in soln_rest.vector]);
|
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;
|
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;
|
return -value_max_est, vector.tolist(), can_add_all, can_add_none;
|
||||||
|
@ -57,7 +57,7 @@ def display_order(
|
|||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
def display_sum(
|
def display_sum(
|
||||||
vector: Union[List[int], List[float]],
|
vector: List[float],
|
||||||
values: np.ndarray,
|
values: np.ndarray,
|
||||||
as_maximum: bool = True,
|
as_maximum: bool = True,
|
||||||
) -> str:
|
) -> str:
|
||||||
@ -77,27 +77,29 @@ def display_sum(
|
|||||||
|
|
||||||
def display_branch_and_bound(
|
def display_branch_and_bound(
|
||||||
values: np.ndarray,
|
values: np.ndarray,
|
||||||
steps: List[Tuple[float, float, Stack]]
|
steps: List[Tuple[float, float, Stack, List[float], bool, bool]]
|
||||||
) -> str:
|
) -> str:
|
||||||
# füge Summen-Ausdrücke für Greedy-Alg hinzu:
|
# füge Summen-Ausdrücke für Greedy-Alg hinzu:
|
||||||
rows = [];
|
rows = [];
|
||||||
used_vectors = [];
|
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:
|
if u in used_vectors:
|
||||||
rows.append((f'{lb_estimate:g}', f'{lb:g}', S));
|
expr = f'{lb:g}';
|
||||||
else:
|
else:
|
||||||
used_vectors.append(u)
|
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) \
|
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);
|
.reset_index(drop=True);
|
||||||
# benutze pandas-Dataframe + tabulate, um schöner darzustellen:
|
# benutze pandas-Dataframe + tabulate, um schöner darzustellen:
|
||||||
repr = tabulate(
|
repr = tabulate(
|
||||||
pd.DataFrame(table),
|
pd.DataFrame(table),
|
||||||
headers=['b', 'g(TOP(S))', 'S'],
|
headers=['b', 'g(TOP(S))', 'pad?', 'S'],
|
||||||
showindex=False,
|
showindex=False,
|
||||||
colalign=('left', 'left', 'right'),
|
colalign=('left', 'left', 'center', 'right'),
|
||||||
tablefmt='rst'
|
tablefmt='rst'
|
||||||
);
|
);
|
||||||
return repr;
|
return repr;
|
||||||
|
@ -88,5 +88,9 @@ class Mask():
|
|||||||
'''
|
'''
|
||||||
return Mask([ MaskValue.ONE if u == MaskValue.UNSET else u for u in self.values ]);
|
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):
|
def empty_mask(n: int):
|
||||||
return Mask([MaskValue.UNSET for _ in range(n)]);
|
return Mask([MaskValue.UNSET for _ in range(n)]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user