diff --git a/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_1.md b/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_1.md index 0a38fbf..5746a96 100644 --- a/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_1.md +++ b/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_1.md @@ -5,13 +5,24 @@ - deep-embedded edges: 84 - graph seed: 59 - deep-embedded minimum degree: 3 +- chosen face: (8, 9, 19) - chosen source cap vertex: 24 +- root entry tooth: e2 (apex medial vertex = level-1 edge (19, 8)) - recognised treads: 11 -- skipped treads: [(0, 'only 0 up teeth')] +- skipped treads: [((0, 0), 'only 0 up teeth')] - removed source-dual edges: 29 - annular/cap cuts: 12 - up-apex cuts: 17 +- **source-dual cut is a tree: True** (56 dual faces, 55 edges, 1 component(s), acyclic=True) + +## Walk-distance labelling of the source-dual cut + +Each dual face (vertex of the source-dual cut) is labelled by its distance, within the cut, from the **cap down tooth of the first entry**: the triangular face `(8, 24, 19)` = `{source 24, edge (19, 8)}` (dual node 34). + +- maximum distance: 21 +- distance histogram (faces by distance): `{0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 2, 6: 3, 7: 3, 8: 4, 9: 4, 10: 4, 11: 4, 12: 3, 13: 3, 14: 2, 15: 2, 16: 1, 17: 2, 18: 3, 19: 4, 20: 2, 21: 1}` + - dual cut figure: `full_medial_tire_cut_walk_1_dual.png` - tire cut grid: `full_medial_tire_cut_walk_1_tires.png` - combined PDF: `full_medial_tire_cut_walk_1.pdf` diff --git a/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_1.pdf b/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_1.pdf index 935bb18..0a2c808 100644 Binary files a/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_1.pdf and b/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_1.pdf differ diff --git a/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_1_dual.png b/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_1_dual.png index 6de6864..429f63e 100644 Binary files a/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_1_dual.png and b/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_1_dual.png differ diff --git a/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_2.md b/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_2.md index 7c5be78..85fc705 100644 --- a/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_2.md +++ b/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_2.md @@ -7,7 +7,7 @@ - deep-embedded minimum degree: 3 - chosen face: (4, 12, 11) - chosen source cap vertex: 20 -- root entry tooth: e3 +- root entry tooth: e3 (apex medial vertex = level-1 edge (11, 4)) - recognised treads: 3 - skipped treads: [((0, 0), 'only 0 up teeth')] - removed source-dual edges: 20 @@ -16,6 +16,13 @@ - **source-dual cut is a tree: True** (38 dual faces, 37 edges, 1 component(s), acyclic=True) +## Walk-distance labelling of the source-dual cut + +Each dual face (vertex of the source-dual cut) is labelled by its distance, within the cut, from the **cap down tooth of the first entry**: the triangular face `(4, 20, 11)` = `{source 20, edge (11, 4)}` (dual node 15). + +- maximum distance: 17 +- distance histogram (faces by distance): `{0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 3, 6: 3, 7: 3, 8: 3, 9: 3, 10: 4, 11: 3, 12: 2, 13: 1, 14: 1, 15: 1, 16: 1, 17: 1}` + - dual cut figure: `full_medial_tire_cut_walk_2_dual.png` - tire cut grid: `full_medial_tire_cut_walk_2_tires.png` - combined PDF: `full_medial_tire_cut_walk_2.pdf` diff --git a/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_2.pdf b/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_2.pdf index e3e0337..6c4553b 100644 Binary files a/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_2.pdf and b/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_2.pdf differ diff --git a/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_2_dual.png b/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_2_dual.png index a5d4970..7b1b6c9 100644 Binary files a/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_2_dual.png and b/papers/medial_tire_cuts/experiments/full_walk/full_medial_tire_cut_walk_2_dual.png differ diff --git a/papers/medial_tire_cuts/experiments/medial_tire_dual_cut_experiment.py b/papers/medial_tire_cuts/experiments/medial_tire_dual_cut_experiment.py index 391e6e6..7d4b6df 100644 --- a/papers/medial_tire_cuts/experiments/medial_tire_dual_cut_experiment.py +++ b/papers/medial_tire_cuts/experiments/medial_tire_dual_cut_experiment.py @@ -221,6 +221,44 @@ def dual_face_missing(G, removed): for v in G.nodes()} +def dual_cut_graph(result): + """The source-dual cut itself: the dual graph with every removed (cut) dual + edge deleted. This is the graph the walk distances are read on.""" + D = result["dual"].copy() + removed = result["removed_dual_edges"] + D.remove_edges_from([(u, v) for u, v, d in D.edges(data=True) + if d["primal"] in removed]) + return D + + +def entry_down_tooth_face(result): + """Index of the cap down tooth of the first entry: the triangular face + ``{source, x, y}`` where ``(x, y)`` is the first entry medial vertex (the + root tread's entry up-tooth apex, a level-1 edge that is a down tooth of the + source cap). This dual node roots the walk-distance labelling. Returns + None if no such face exists.""" + em = result.get("entry_medial_vertex") + if em is None: + return None + target = frozenset((result["source"], em[0], em[1])) + for fi, f in enumerate(result["faces"]): + if frozenset(f) == target: + return fi + return None + + +def dual_cut_distances(result): + """Distance of every dual face from the first entry's cap down tooth, + measured in the source-dual cut. + + Returns ``(dist, root)`` where ``dist`` maps each reachable dual face to its + distance and ``root`` is the rooting dual face (or None if absent).""" + root = entry_down_tooth_face(result) + if root is None: + return {}, None + return nx.single_source_shortest_path_length(dual_cut_graph(result), root), root + + # --------------------------------------------------------------------------- # # The four chained entry points. # --------------------------------------------------------------------------- # @@ -420,6 +458,7 @@ def _draw_dual_cut_ax(ax, result): missing = result["dual_face_missing"] source = result["source"] entry_medial = result.get("entry_medial_vertex") + dist, root = dual_cut_distances(result) pos_v = _radial_source_layout(G, source, result["levels"]) def centroid(fi): @@ -454,9 +493,20 @@ def _draw_dual_cut_ax(ax, result): color="0.80" if cut else "0.25", lw=1.0 if cut else 1.3, linestyle=(0, (2, 2)) if cut else "solid", zorder=1) + # dual nodes labelled by walk distance from the first entry's cap down + # tooth; the rooting dual face is gold. for fi in dual.nodes(): x, y = pos[fi] - ax.plot(x, y, "o", ms=4, color="#3a6ea5", zorder=3) + d = dist.get(fi) + if fi == root: + ax.plot(x, y, "o", ms=12, mfc="#ffd24d", mec="#b8860b", + mew=1.3, zorder=3) + else: + ax.plot(x, y, "o", ms=10, mfc="white", mec="#3a6ea5", + mew=0.8, zorder=3) + ax.text(x, y, str(d) if d is not None else "∞", + color="#13335c", fontsize=5.5, fontweight="bold", + ha="center", va="center", zorder=4) # label each source-graph vertex by its id; the cap source is flagged. for v in G.nodes(): x, y = pos_v[v] @@ -475,12 +525,15 @@ def _draw_dual_cut_ax(ax, result): ha="left", va="bottom", zorder=7, bbox=dict(boxstyle="circle,pad=0.05", fc="white", ec="#b03030", lw=0.6)) + root_face = result["faces"][root] if root is not None else None + max_dist = max(dist.values()) if dist else 0 ax.set_title(f"source-dual cut (cap source {source}, entry " f"e{result['entry_edge']} = medial vtx {entry_medial}); " f"gray = edges missing after cuts\n" - f"green star = first entry medial vertex; red numbers = " - f"#missing dual edges around each dual face; " - f"max {result['max_missing']}", fontsize=9) + f"blue dual-node numbers = distance from gold root " + f"(cap down tooth {root_face} of first entry; max {max_dist}); " + f"green star = first entry; red = #missing dual edges per face", + fontsize=9) ax.set_aspect("equal") ax.axis("off")