refactored Sums into a class in sumfinder (much cleaner) and added method to output Sums to stdout

This commit is contained in:
Guillaume Raffy 2024-08-14 18:34:44 +02:00
parent 6bcdade804
commit e1d71014d4
4 changed files with 259 additions and 61 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,22 +1,22 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from pathlib import Path from pathlib import Path
from sumfinder import load_sums, remove_invalid_sums from sumfinder import Sums
from linuxmem import read_meminfo_stdout from linuxmem import read_meminfo_stdout
def main(): def main():
sums = load_sums(Path('../expe001.5/alambix97-meminfo-sums.json')) sums = Sums.load(Path('../expe001.5/alambix97-meminfo-sums.json'))
print(f'starting sums ({len(sums)} sums):') print(f'starting sums ({sums.get_num_equations()} sums):')
print(sums) sums.print()
variables = read_meminfo_stdout(Path('../bug3897/alambix98/20240806-223916-meminfo.stdout')) variables = read_meminfo_stdout(Path('../bug3897/alambix98/20240806-223916-meminfo.stdout'))
# variables = read_meminfo_stdout(Path('../bug3897/alambix97/20240805-191606-meminfo.stdout')) # variables = read_meminfo_stdout(Path('../bug3897/alambix97/20240805-191606-meminfo.stdout'))
(valid_sums, invalid_sums) = remove_invalid_sums(sums, variables) (valid_sums, invalid_sums) = sums.validate_on_variables(variables)
print(f'invalid sums ({len(invalid_sums)} sums):') print(f'invalid sums ({invalid_sums.get_num_equations()} sums):')
print(invalid_sums) invalid_sums.print()
print(f'valid sums ({len(valid_sums)} sums):') print(f'valid sums ({valid_sums.get_num_equations()} sums):')
print(valid_sums) valid_sums.print()
main() main()

View File

@ -1,7 +1,5 @@
from .sumfinder import Sums # noqa from .sumfinder import Sums # noqa
from .sumfinder import SumExporter # noqa from .sumfinder import SumExporter # noqa
from .sumfinder import load_sums # noqa
from .sumfinder import find_sums # noqa from .sumfinder import find_sums # noqa
from .sumfinder import sums_to_dot # noqa from .sumfinder import sums_to_dot # noqa
from .sumfinder import find_and_graph_sums # noqa from .sumfinder import find_and_graph_sums # noqa
from .sumfinder import remove_invalid_sums # noqa

View File

@ -9,7 +9,7 @@ import subprocess
VarName = str VarName = str
VarValue = int VarValue = int
Sums = List[Dict[VarName, List[VarName]]] Sum = Dict[VarName, List[VarName]]
class IntVariable(): class IntVariable():
@ -24,6 +24,66 @@ class IntVariable():
return f'{self.name}: {self.value}' return f'{self.name}: {self.value}'
class Sums():
variables: Set[IntVariable]
sums: List[Sum]
def __init__(self) -> None:
self.variables = set()
self.sums = []
def get_num_variables(self):
return len(self.variables)
def get_num_equations(self):
return len(self.sums)
@staticmethod
def load(sums_file_path: Path) -> 'Sums':
sums = Sums()
with open(sums_file_path, 'rt', encoding='utf8') as sums_file:
root_dict = json.loads(sums_file.read())
assert root_dict['format'] == 'sums-v001'
sums.sums = root_dict['sums']
sums.variables = {IntVariable(var_id, var_value) for var_id, var_value in root_dict['variables'].items()}
return sums
def save(self, sums_file_path: Path):
root_dict = {}
root_dict['format'] = 'sums-v001'
root_dict['variables'] = {var.name: var.value for var in self.variables}
root_dict['sums'] = self.sums
sums_file_path.write_text(json.dumps(root_dict))
def print(self):
equation_index = 0
for s in self.sums:
print(f"{equation_index}: {s['total']} = {' + '.join([comp_id for comp_id in s['components']])}")
equation_index += 1
def validate_on_variables(self, variables: Dict[VarName, VarValue]) -> Tuple['Sums', 'Sums']:
"""
returns the tuple valid_sums, invalid_sums after checking each of the sum of input_sum againts the given variables
"""
valid_sums: Sums = Sums()
invalid_sums: Sums = Sums()
for _sum in self.sums:
# for total_var_id, components in input_sums.items():
total_var_id = _sum['total']
components = _sum['components']
computed_total_value = 0
for component_var_id in components:
computed_total_value += variables[component_var_id]
real_total_value = variables[total_var_id]
if computed_total_value == real_total_value:
valid_sums.sums.append(_sum)
else:
invalid_sums.sums.append(_sum)
return (valid_sums, invalid_sums)
class ISumHandler(abc.ABC): class ISumHandler(abc.ABC):
@abc.abstractmethod @abc.abstractmethod
@ -48,35 +108,23 @@ class SumExporter(ISumHandler):
'''handler that exports the sums as a graphviz dot file '''handler that exports the sums as a graphviz dot file
''' '''
sum_file_path: Path sum_file_path: Path
variables: Set[IntVariable]
sums: Sums sums: Sums
def __init__(self, sum_file_path: Path): def __init__(self, sum_file_path: Path):
self.sum_file_path = sum_file_path self.sum_file_path = sum_file_path
self.variables = set() self.variables = set()
self.sums = [] self.sums = Sums()
def on_sum_found(self, total: IntVariable, components: List[IntVariable]): def on_sum_found(self, total: IntVariable, components: List[IntVariable]):
self.variables.add(total) self.sums.variables.add(total)
for component in components: for component in components:
self.variables.add(component) self.sums.variables.add(component)
print(f"sum found: {total.name} = {' + '.join([comp.name for comp in components])}") print(f"sum found: {total.name} = {' + '.join([comp.name for comp in components])}")
self.sums.append({'total': total.name, 'components': [comp.name for comp in components]}) self.sums.sums.append({'total': total.name, 'components': [comp.name for comp in components]})
def on_end(self): def on_end(self):
print(f'exporting sums to {self.sum_file_path}') print(f'exporting sums to {self.sum_file_path}')
root_dict = {} self.sums.save(self.sum_file_path)
root_dict['format'] = 'sums-v001'
root_dict['variables'] = {var.name: var.value for var in self.variables}
root_dict['sums'] = self.sums
self.sum_file_path.write_text(json.dumps(root_dict))
def load_sums(sums_file_path: Path) -> Sums:
with open(sums_file_path, 'rt', encoding='utf8') as sums_file:
root_dict = json.loads(sums_file.read())
assert root_dict['format'] == 'sums-v001'
return root_dict['sums']
def explore(total: IntVariable, components: List[IntVariable], cur_sum: VarValue, cur_var_index: int, contrib_components: List[IntVariable], sum_handler: ISumHandler): def explore(total: IntVariable, components: List[IntVariable], cur_sum: VarValue, cur_var_index: int, contrib_components: List[IntVariable], sum_handler: ISumHandler):
@ -266,12 +314,8 @@ def sums_to_dot(sum_file_path: Path, dot_file_path: Path):
"yellowgreen"] "yellowgreen"]
print(f'creating {dot_file_path} from {sum_file_path}') print(f'creating {dot_file_path} from {sum_file_path}')
with open(sum_file_path, 'rt', encoding='utf8') as sum_file: sums = Sums.load(sum_file_path)
root_dict = json.load(sum_file)
# print(root_dict) # print(root_dict)
variables = {IntVariable(var_name, var_value) for var_name, var_value in root_dict['variables'].items()}
# print(variables)
sums = root_dict['sums']
# print(sums) # print(sums)
with open(dot_file_path, 'wt+', encoding='utf8') as dot_file: with open(dot_file_path, 'wt+', encoding='utf8') as dot_file:
dot_file.write(f'digraph {to_dot_symbol(sum_file_path.stem)}\n') dot_file.write(f'digraph {to_dot_symbol(sum_file_path.stem)}\n')
@ -279,10 +323,10 @@ def sums_to_dot(sum_file_path: Path, dot_file_path: Path):
dot_file.write('layout = neato\n') dot_file.write('layout = neato\n')
dot_file.write('overlap = false\n') dot_file.write('overlap = false\n')
for variable in variables: for variable in sums.variables:
dot_file.write(f'{to_dot_symbol(variable.name)} [label="{variable.name}={variable.value}"];\n') dot_file.write(f'{to_dot_symbol(variable.name)} [label="{variable.name}={variable.value}"];\n')
sum_index = 0 sum_index = 0
for s in sums: for s in sums.sums:
dot_file.write(f"{to_dot_symbol(s['total'])} -> {{{','.join([to_dot_symbol(comp) for comp in s['components']])}}} [color={svg_colors[sum_index % len(svg_colors)]}, label={sum_index}];\n") dot_file.write(f"{to_dot_symbol(s['total'])} -> {{{','.join([to_dot_symbol(comp) for comp in s['components']])}}} [color={svg_colors[sum_index % len(svg_colors)]}, label={sum_index}];\n")
sum_index += 1 sum_index += 1
dot_file.write('}\n') dot_file.write('}\n')
@ -298,25 +342,3 @@ def find_and_graph_sums(variables: Dict[str, int], set_id: str):
sums_to_dot(sums_file_path, dot_file_path) sums_to_dot(sums_file_path, dot_file_path)
print(f'creating {svg_file_path} from {dot_file_path}') print(f'creating {svg_file_path} from {dot_file_path}')
subprocess.run(f'dot -Tsvg {dot_file_path} > {svg_file_path}', shell=True, check=True) subprocess.run(f'dot -Tsvg {dot_file_path} > {svg_file_path}', shell=True, check=True)
def remove_invalid_sums(input_sums: Sums, variables: Dict[VarName, VarValue]) -> Tuple[Sums, Sums]:
"""
returns the tuple valid_sums, invalid_sums after checking each of the sum of input_sum againts the given variables
"""
valid_sums: Sums = []
invalid_sums: Sums = []
for _sum in input_sums:
# for total_var_id, components in input_sums.items():
total_var_id = _sum['total']
components = _sum['components']
computed_total_value = 0
for component_var_id in components:
computed_total_value += variables[component_var_id]
real_total_value = variables[total_var_id]
if computed_total_value == real_total_value:
valid_sums.append(_sum)
else:
invalid_sums.append(_sum)
return (valid_sums, invalid_sums)