57 lines
2.9 KiB
Python
57 lines
2.9 KiB
Python
"""Compare fixed Project/node/port/endpoint geometry and report routing changes.
|
|
|
|
Usage: python compare_probe.py OLD_JSONL NEW_JSONL NEW_OUTPUT_JSON
|
|
No layout-quality pass is inferred from equal inputs or successful execution.
|
|
"""
|
|
from pathlib import Path
|
|
import hashlib
|
|
import json
|
|
import sys
|
|
|
|
old_path, new_path, out = map(Path, sys.argv[1:])
|
|
def read(path):
|
|
rows = [json.loads(line) for line in path.read_text(encoding='utf-8').splitlines()]
|
|
return {row['fixture']: row for row in rows if 'fixture' in row}
|
|
old, new = read(old_path), read(new_path)
|
|
assert old.keys() == new.keys()
|
|
def variants(row):
|
|
yield 'before', row['before_project'], row['before']
|
|
yield 'baseline', row['after_project'], row['after']
|
|
for name in ['reset_only_control', 'experimental_candidate', 'manual_planar_order_witness']:
|
|
if row[name] is not None:
|
|
yield name, row[name]['project'], row[name]['metrics']
|
|
def endpoints(metrics):
|
|
return {e['id']: [e['points'][0], e['points'][-1]] for e in metrics['routed_edges']}
|
|
keys = ['proper_crossings', 'pairwise_collinear_shared_length',
|
|
'nonterminal_pairwise_shared_length', 'unrelated_node_collisions',
|
|
'unrelated_edge_node_penetrations', 'label_node_collisions',
|
|
'label_label_collisions', 'unrelated_label_stroke_intersections',
|
|
'warning_count', 'route_bends', 'route_length', 'drawing_area']
|
|
results = []
|
|
for name in old:
|
|
lhs, rhs = list(variants(old[name])), list(variants(new[name]))
|
|
assert len(lhs) == len(rhs)
|
|
for (variant, op, om), (other, np, nm) in zip(lhs, rhs):
|
|
assert variant == other
|
|
fixed = {'project':op == np, 'nodes':om['projected_nodes'] == nm['projected_nodes'],
|
|
'ports':om['projected_ports'] == nm['projected_ports'],
|
|
'route_endpoints':endpoints(om) == endpoints(nm)}
|
|
results.append({'fixture':name, 'variant':variant, 'fixed_geometry':fixed,
|
|
'metrics':{key:{'old':om[key], 'new':nm[key]} for key in keys},
|
|
'new_point_contacts':nm.get('point_contacts'),
|
|
'new_point_contact_details':nm.get('point_contact_details')})
|
|
summary = {'old_sha256':hashlib.sha256(old_path.read_bytes()).hexdigest(),
|
|
'new_sha256':hashlib.sha256(new_path.read_bytes()).hexdigest(),
|
|
'all_projects_nodes_ports_endpoints_exact':all(all(r['fixed_geometry'].values()) for r in results),
|
|
'scope':'Fixed-geometry comparison; quality vector retained, no aggregate quality pass.',
|
|
'results':results}
|
|
with out.open('x',encoding='utf-8') as f:
|
|
json.dump(summary,f,indent=2)
|
|
f.write('\n')
|
|
print(json.dumps({k:v for k,v in summary.items() if k != 'results'}))
|
|
for row in results:
|
|
if row['variant'] == 'experimental_candidate':
|
|
print(json.dumps({'fixture':row['fixture'], 'fixed_geometry':row['fixed_geometry'],
|
|
'changed_metrics':{k:v for k,v in row['metrics'].items() if v['old'] != v['new']},
|
|
'point_contacts':row['new_point_contacts']}))
|