You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
6.3 KiB
Python
175 lines
6.3 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# IMPORTS
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
from src.thirdparty.code import *;
|
|
from src.thirdparty.maths import *;
|
|
from src.thirdparty.types import *;
|
|
|
|
from src.core.utils import *;
|
|
from src.setup import config;
|
|
from models.generated.config import *;
|
|
from src.models.stacks import *;
|
|
from src.models.rucksack import *;
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# EXPORTS
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
__all__ = [
|
|
'display_order',
|
|
'display_rucksack',
|
|
'display_branch_and_bound',
|
|
'display_sum',
|
|
];
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# METHOD display order
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
def display_order(
|
|
order: List[int],
|
|
costs: np.ndarray,
|
|
values: np.ndarray,
|
|
items: np.ndarray,
|
|
one_based: bool = False,
|
|
) -> str:
|
|
table = pd.DataFrame({
|
|
'items': items,
|
|
'order': iperm(order),
|
|
'values': values,
|
|
'costs': costs,
|
|
'margin': [f'{value/cost:.6f}' for cost, value in zip(costs, values)],
|
|
}) \
|
|
.reset_index(drop=True);
|
|
if one_based:
|
|
table['order'] += 1;
|
|
# benutze pandas-Dataframe + tabulate, um schöner darzustellen:
|
|
repr = tabulate(
|
|
table,
|
|
headers=['item', 'greedy order', 'value', 'cost', 'value/cost'],
|
|
showindex=False,
|
|
colalign=('left', 'center', 'center', 'center', 'right'),
|
|
tablefmt='rst'
|
|
);
|
|
return repr;
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# METHOD display rucksack
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
def display_rucksack(
|
|
items: np.ndarray,
|
|
costs: np.ndarray,
|
|
values: np.ndarray,
|
|
choice: List[Fraction],
|
|
) -> str:
|
|
show_options = config.OPTIONS.rucksack.show;
|
|
render = lambda r: f'{r:g}';
|
|
choice = np.asarray(choice);
|
|
rucksack = np.where(choice > 0);
|
|
if not(EnumRucksackShow.all_weights in show_options):
|
|
items = items[rucksack];
|
|
costs = costs[rucksack];
|
|
values = values[rucksack];
|
|
choice = choice[rucksack];
|
|
table = pd.DataFrame({
|
|
'items': items.tolist() + ['----', '∑'],
|
|
'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'],
|
|
});
|
|
repr = tabulate(
|
|
table,
|
|
headers=['item', 'nr', 'cost', 'value'],
|
|
showindex=False,
|
|
colalign=('left', 'center', 'center', 'center'),
|
|
tablefmt='rst'
|
|
);
|
|
return repr;
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# METHOD display result of branch and bound
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
def display_branch_and_bound(values: np.ndarray, steps: List[Step]) -> str:
|
|
show_options = config.OPTIONS.rucksack.show;
|
|
show_all_sums = (EnumRucksackShow.all_sums in show_options);
|
|
|
|
rows = [];
|
|
used_choices = [];
|
|
index_soln = max([-1] + [ i for i, step in enumerate(steps) if step.move == EnumBranchAndBoundMove.BOUND ]);
|
|
for i, step in enumerate(steps):
|
|
if show_all_sums or step.choice not in used_choices:
|
|
# Füge Summen-Ausdrücke für Greedy-Alg hinzu:
|
|
used_choices.append(step.choice);
|
|
expr = display_sum(choice=step.choice, values=values, as_maximum=False, order=step.order, indexes=step.indexes);
|
|
else:
|
|
expr = '';
|
|
bound_str = f'{step.bound:+g}';
|
|
solution_str = f'{step.solution or ""}';
|
|
move_str = ('' if step.move == EnumBranchAndBoundMove.NONE else step.move.value);
|
|
if i == index_soln:
|
|
bound_str = f'* \x1b[92;1m{bound_str}\x1b[0m';
|
|
rows.append({
|
|
'bound': f'{bound_str}',
|
|
'bound_subtree': f'{step.bound_subtree:g}',
|
|
'bound_subtree_sum': expr,
|
|
'stack': step.stack_str,
|
|
'solution': f'\x1b[2m{solution_str}\x1b[0m',
|
|
'move': f'\x1b[2m{move_str}\x1b[0m',
|
|
});
|
|
|
|
table = pd.DataFrame(rows).reset_index(drop=True);
|
|
# benutze pandas-Dataframe + tabulate, um schöner darzustellen:
|
|
repr = tabulate(
|
|
table,
|
|
headers=['bound', 'g(TOP(S))', '', 'S — stack', '\x1b[2msoln\x1b[0m', '\x1b[2mmove\x1b[0m'],
|
|
showindex=False,
|
|
colalign=('right', 'right', 'left', 'right', 'center', 'left'),
|
|
tablefmt='simple'
|
|
);
|
|
return repr;
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# METHOD display sum
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
def display_sum(
|
|
choice: List[Fraction],
|
|
values: np.ndarray,
|
|
order: Optional[List[int]] = None,
|
|
indexes: List[int] = [],
|
|
as_maximum: bool = True,
|
|
) -> str:
|
|
show_options = config.OPTIONS.rucksack.show;
|
|
show_all_weights = (EnumRucksackShow.all_weights in show_options);
|
|
|
|
def render(x: Tuple[bool, Fraction, float]):
|
|
b, u, value = x;
|
|
if u == 0:
|
|
expr = f'\x1b[94;2m{value:g}\x1b[0m' if b else f'\x1b[2m{value:g}\x1b[0m';
|
|
else:
|
|
expr = f'\x1b[94m{value:g}\x1b[0m' if b else f'\x1b[0m{value:g}\x1b[0m';
|
|
if not show_all_weights and u == 1:
|
|
return expr;
|
|
return f'\x1b[2;4m{u}\x1b[0m\x1b[2m·\x1b[0m{expr}';
|
|
|
|
parts = [ (i in indexes, u, x) for i, (u, x) in enumerate(zip(choice, values)) ];
|
|
if not (order is None):
|
|
parts = [ parts[j] for j in order ];
|
|
if not show_all_weights:
|
|
parts = list(filter(lambda x: x[1] > 0, parts));
|
|
|
|
expr = '\x1b[2m + \x1b[0m'.join(map(render, parts));
|
|
|
|
if as_maximum:
|
|
return f'\x1b[2m=\x1b[0m {expr}';
|
|
return f'\x1b[2m= -(\x1b[0m{expr}\x1b[2m)\x1b[0m';
|