Refactor canonize_colored_graph to return new objects instead of mutating inputs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-21 01:43:52 -04:00
parent 54b33a7003
commit a4d51a6cfc
+12 -15
View File
@@ -41,8 +41,8 @@ def operation_sequence_id(ops: list[Operation]) -> str:
joined = "\n".join(op_to_transform_id(op) for op in ops) joined = "\n".join(op_to_transform_id(op) for op in ops)
return hashlib.sha256(joined.encode()).hexdigest() return hashlib.sha256(joined.encode()).hexdigest()
def canonize_colored_graph(g: Graph, coloring: VertexColoring) -> ColoredGraphId: def canonize_colored_graph(g: Graph, coloring: VertexColoring) -> tuple[Graph, VertexColoring, ColoredGraphId]:
"""Mutate g and coloring to canonical labels and return a canonical ColoredGraphId""" """Return a new canonical graph, new canonical coloring, and a ColoredGraphId without mutating inputs"""
canonical, cert = cast( canonical, cert = cast(
tuple[Graph, dict[Any, int]], tuple[Graph, dict[Any, int]],
g.canonical_label(certificate=True), g.canonical_label(certificate=True),
@@ -55,34 +55,31 @@ def canonize_colored_graph(g: Graph, coloring: VertexColoring) -> ColoredGraphId
for orig_v, canon_idx in cert.items(): for orig_v, canon_idx in cert.items():
color_seq[canon_idx] = coloring[orig_v] color_seq[canon_idx] = coloring[orig_v]
coloring.clear() canonical_coloring = {canon_idx: color for canon_idx, color in enumerate(color_seq)}
for canon_idx, color in enumerate(color_seq):
coloring[canon_idx] = color
coloring_id = base64.urlsafe_b64encode(bytes(color_seq)).decode() coloring_id = base64.urlsafe_b64encode(bytes(color_seq)).decode()
g.relabel(cert) return canonical, canonical_coloring, ColoredGraphId(graph_id=graph_id, coloring_id=coloring_id)
return ColoredGraphId(graph_id=graph_id, coloring_id=coloring_id)
def save_colored_graph(g: Graph, coloring: VertexColoring) -> tuple[Graph, VertexColoring, ColoredGraphId]: def save_colored_graph(g: Graph, coloring: VertexColoring) -> tuple[Graph, VertexColoring, ColoredGraphId]:
""" """
Relabel g and coloring into canonical form, save to disk, and return both. Canonize g and coloring, save to disk, and return the canonical forms with id.
If already saved, load and return the cached graph. If already saved, load and return the cached graph.
""" """
cid = canonize_colored_graph(g, coloring) g_canon, canonical_coloring, cid = canonize_colored_graph(g, coloring)
out_dir = DIR / "data" / "graphs" / cid['graph_id'] / cid['coloring_id'] out_dir = DIR / "data" / "graphs" / cid['graph_id'] / cid['coloring_id']
if (out_dir / "graph.sobj").exists(): if (out_dir / "graph.sobj").exists():
g_canon = cast(Graph, load(str(out_dir / 'graph'))) g_canon = cast(Graph, load(str(out_dir / 'graph')))
return g_canon, coloring, cid return g_canon, canonical_coloring, cid
g.is_planar(set_embedding=True, set_pos=True) g_canon.is_planar(set_embedding=True, set_pos=True)
vertex_colors: defaultdict[str, list[Any]] = defaultdict(list) vertex_colors: defaultdict[str, list[Any]] = defaultdict(list)
for v, c in coloring.items(): for v, c in canonical_coloring.items():
vertex_colors[PALETTE[c]].append(v) vertex_colors[PALETTE[c]].append(v)
out_dir.mkdir(parents=True, exist_ok=True) out_dir.mkdir(parents=True, exist_ok=True)
g.plot( g_canon.plot(
vertex_colors=dict(vertex_colors), vertex_colors=dict(vertex_colors),
title=f"graph: {cid['graph_id']} coloring: {cid['coloring_id']}", title=f"graph: {cid['graph_id']} coloring: {cid['coloring_id']}",
).save(out_dir / 'graph.png') ).save(out_dir / 'graph.png')
save(g, str(out_dir / 'graph')) save(g_canon, str(out_dir / 'graph'))
return g, coloring, cid return g_canon, canonical_coloring, cid
def _neighbors_form_cycle(g: Graph, v: Any) -> bool: def _neighbors_form_cycle(g: Graph, v: Any) -> bool:
"""Return True if the neighbors of v induce a cycle in g.""" """Return True if the neighbors of v induce a cycle in g."""