2022-06-14 01:35:10 +02:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
# IMPORTS
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
2022-06-14 09:03:29 +02:00
|
|
|
from src.thirdparty.code import *;
|
2022-06-14 01:35:10 +02:00
|
|
|
from src.thirdparty.maths import *;
|
2022-06-14 09:03:29 +02:00
|
|
|
from src.thirdparty.types import *;
|
2022-06-14 01:35:10 +02:00
|
|
|
|
|
|
|
from src.models.stacks import *;
|
2022-06-14 20:02:22 +02:00
|
|
|
from src.models.rucksack import *;
|
2022-06-14 01:35:10 +02:00
|
|
|
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
# EXPORTS
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
__all__ = [
|
2022-06-14 09:03:29 +02:00
|
|
|
'display_order',
|
2022-06-14 14:40:02 +02:00
|
|
|
'display_rucksack',
|
2022-06-14 01:35:10 +02:00
|
|
|
'display_branch_and_bound',
|
2022-06-14 14:40:02 +02:00
|
|
|
'display_sum',
|
2022-06-14 01:35:10 +02:00
|
|
|
];
|
|
|
|
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2022-06-14 09:03:29 +02:00
|
|
|
# METHOD display order
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
def display_order(
|
|
|
|
order: List[int],
|
2022-06-14 14:40:02 +02:00
|
|
|
costs: np.ndarray,
|
2022-06-14 09:03:29 +02:00
|
|
|
values: np.ndarray,
|
|
|
|
items: np.ndarray,
|
|
|
|
one_based: bool = False,
|
|
|
|
) -> str:
|
|
|
|
table = pd.DataFrame({
|
2022-06-14 14:40:02 +02:00
|
|
|
'items': items,
|
|
|
|
'order': order,
|
|
|
|
'values': values,
|
|
|
|
'costs': costs,
|
2022-06-14 20:02:22 +02:00
|
|
|
'margin': [str(Fraction(Fraction(value), Fraction(cost))) for cost, value in zip(costs, values)],
|
2022-06-14 10:09:21 +02:00
|
|
|
}) \
|
|
|
|
.reset_index(drop=True);
|
2022-06-14 09:03:29 +02:00
|
|
|
if one_based:
|
2022-06-14 10:09:21 +02:00
|
|
|
table['order'] += 1;
|
2022-06-14 09:03:29 +02:00
|
|
|
# benutze pandas-Dataframe + tabulate, um schöner darzustellen:
|
|
|
|
repr = tabulate(
|
2022-06-14 14:40:02 +02:00
|
|
|
table,
|
|
|
|
headers=['item', 'greedy order', 'value', 'cost', 'value/cost'],
|
2022-06-14 09:03:29 +02:00
|
|
|
showindex=False,
|
|
|
|
colalign=('left', 'center', 'center', 'center', 'right'),
|
|
|
|
tablefmt='rst'
|
|
|
|
);
|
|
|
|
return repr;
|
|
|
|
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2022-06-14 14:40:02 +02:00
|
|
|
# METHOD display rucksack
|
2022-06-14 01:35:10 +02:00
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
2022-06-14 14:40:02 +02:00
|
|
|
def display_rucksack(
|
|
|
|
items: np.ndarray,
|
|
|
|
costs: np.ndarray,
|
2022-06-14 01:35:10 +02:00
|
|
|
values: np.ndarray,
|
2022-06-14 20:39:01 +02:00
|
|
|
choice: np.ndarray,
|
2022-06-14 01:35:10 +02:00
|
|
|
) -> str:
|
2022-06-14 20:02:22 +02:00
|
|
|
render = lambda r: f'{r:g}';
|
2022-06-14 14:40:02 +02:00
|
|
|
table = pd.DataFrame({
|
|
|
|
'items': items.tolist() + ['----', '∑'],
|
2022-06-14 22:52:05 +02:00
|
|
|
'nr': list(map(str, choice))
|
|
|
|
+ ['----', f'\x1b[92;1m{float(sum(choice)):g}\x1b[0m'],
|
|
|
|
'costs': list(map(render, costs))
|
|
|
|
+ ['----', f'\x1b[92;1m{sum(choice*costs):g}\x1b[0m'],
|
|
|
|
'values': list(map(render, values))
|
|
|
|
+ ['----', f'\x1b[92;1m{sum(choice*values):g}\x1b[0m'],
|
2022-06-14 14:40:02 +02:00
|
|
|
});
|
|
|
|
repr = tabulate(
|
|
|
|
table,
|
2022-06-14 20:39:01 +02:00
|
|
|
headers=['item', 'nr', 'cost', 'value'],
|
2022-06-14 14:40:02 +02:00
|
|
|
showindex=False,
|
2022-06-14 20:39:01 +02:00
|
|
|
colalign=('left', 'center', 'center', 'center'),
|
2022-06-14 14:40:02 +02:00
|
|
|
tablefmt='rst'
|
|
|
|
);
|
|
|
|
return repr;
|
2022-06-14 01:35:10 +02:00
|
|
|
|
2022-06-14 09:03:29 +02:00
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
# METHOD display result of branch and bound
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
2022-06-15 07:23:07 +02:00
|
|
|
def display_branch_and_bound(values: np.ndarray, steps: List[Step]) -> str:
|
2022-06-14 01:35:10 +02:00
|
|
|
# füge Summen-Ausdrücke für Greedy-Alg hinzu:
|
|
|
|
rows = [];
|
2022-06-14 20:02:22 +02:00
|
|
|
used_choices = [];
|
2022-06-15 07:23:07 +02:00
|
|
|
index_soln = max([-1] + [ i for i, step in enumerate(steps) if step.move == EnumBranchAndBoundMove.BOUND ]);
|
|
|
|
for i, step in enumerate(steps):
|
|
|
|
if step.choice in used_choices:
|
|
|
|
expr = f'{step.bound_subtree:g}';
|
2022-06-14 01:35:10 +02:00
|
|
|
else:
|
2022-06-15 07:23:07 +02:00
|
|
|
used_choices.append(step.choice);
|
|
|
|
expr = display_sum(choice=step.choice, values=values, as_maximum=False, order=step.order, indexes=step.indexes);
|
|
|
|
pad_str = ('' if step.pad == MaskValue.UNSET else step.pad.value);
|
|
|
|
move_str = ('' if step.move == EnumBranchAndBoundMove.NONE else step.move.value);
|
|
|
|
if i == index_soln:
|
|
|
|
move_str = f'{move_str} *';
|
|
|
|
rows.append({
|
|
|
|
'bound': f'{step.bound:+g}',
|
|
|
|
'bound_subtree': expr,
|
|
|
|
'stack': step.stack_str,
|
|
|
|
'pad': f'\x1b[2m{pad_str}\x1b[0m',
|
|
|
|
'move': f'\x1b[2m{move_str}\x1b[0m',
|
|
|
|
});
|
2022-06-14 01:35:10 +02:00
|
|
|
|
2022-06-15 07:23:07 +02:00
|
|
|
table = pd.DataFrame(rows).reset_index(drop=True);
|
2022-06-14 01:35:10 +02:00
|
|
|
# benutze pandas-Dataframe + tabulate, um schöner darzustellen:
|
|
|
|
repr = tabulate(
|
2022-06-14 14:40:02 +02:00
|
|
|
table,
|
2022-06-15 07:23:07 +02:00
|
|
|
headers=['bound', 'g(TOP(S))', 'S — stack', '\x1b[2mpad?\x1b[0m', '\x1b[2mmove\x1b[0m'],
|
2022-06-14 01:35:10 +02:00
|
|
|
showindex=False,
|
2022-06-15 07:23:07 +02:00
|
|
|
colalign=('left', 'left', 'right', 'center', 'left'),
|
2022-06-14 01:35:10 +02:00
|
|
|
tablefmt='rst'
|
|
|
|
);
|
|
|
|
return repr;
|
2022-06-14 14:40:02 +02:00
|
|
|
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
# METHOD display sum
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
def display_sum(
|
2022-06-14 20:02:22 +02:00
|
|
|
choice: List[Fraction],
|
2022-06-14 14:40:02 +02:00
|
|
|
values: np.ndarray,
|
|
|
|
order: Optional[List[int]] = None,
|
2022-06-15 07:23:07 +02:00
|
|
|
indexes: List[int] = [],
|
2022-06-14 14:40:02 +02:00
|
|
|
as_maximum: bool = True,
|
|
|
|
) -> str:
|
2022-06-15 07:23:07 +02:00
|
|
|
def render(x: Tuple[bool, Fraction, float]):
|
|
|
|
b, u, value = x;
|
|
|
|
expr = f'\x1b[91m{value:g}\x1b[0m' if b else f'\x1b[2m{value:g}\x1b[0m';
|
|
|
|
return expr if u == 1 else f'\x1b[4;2m{u}\x1b[0m\x1b[2m·\x1b[0m{expr}';
|
|
|
|
|
|
|
|
parts = [ (i in indexes, u, x) for i, (u, x) in enumerate(zip(choice, values)) ];
|
2022-06-14 14:40:02 +02:00
|
|
|
if not (order is None):
|
|
|
|
parts = [ parts[j] for j in order ];
|
2022-06-15 07:23:07 +02:00
|
|
|
parts = list(filter(lambda x: x[1] > 0, parts));
|
|
|
|
value = sum([ u*x for _, u, x in parts ]);
|
|
|
|
expr = '\x1b[2m+\x1b[0m'.join(map(render, parts));
|
|
|
|
|
2022-06-14 14:40:02 +02:00
|
|
|
if as_maximum:
|
2022-06-15 07:23:07 +02:00
|
|
|
return f'{value:g} \x1b[2m=\x1b[0m {expr}';
|
|
|
|
return f'-{value:g} \x1b[2m= -(\x1b[0m{expr}\x1b[2m)\x1b[0m';
|