diff --git a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/branching_medial_tire_decomposition/random_c5_n30_medial_tire_decomposition_1.md b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/branching_medial_tire_decomposition/random_c5_n30_medial_tire_decomposition_1.md index 97b9526..fd3b522 100644 --- a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/branching_medial_tire_decomposition/random_c5_n30_medial_tire_decomposition_1.md +++ b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/branching_medial_tire_decomposition/random_c5_n30_medial_tire_decomposition_1.md @@ -1,19 +1,25 @@ # Random medial tire decomposition 1 -- vertices: 30 -- edges: 84 -- node connectivity: 5 +- original vertices: 30 +- original edges: 84 +- original node connectivity: 5 +- augmented vertices: 33 +- augmented edges: 93 +- same-level faces filled: 3 - source vertex: 14 - tire-tree nodes: 4 - tire-tree edges: 3 -| node | depth | faces | annular | up | down | bites | full medial tires | +| node | depth | faces | annular | up | singleton down | bite apexes | full medial tires | |--:|--:|--:|--:|--:|--:|--:|--:| | T0 | 2 | 23 | 23 | 10 | 13 | 0 | 1 | | T0.0 | | | | 10 | 13 | - | `UDDUDUUDDUDUDUDUDDDUUDD` | | T1 | 1 | 15 | 15 | 5 | 10 | 0 | 1 | | T1.0 | | | | 5 | 10 | - | `UDDDUDDUDUDDDUD` | -| T2 | 3 | 8 | 5 | 11 | 0 | 0 | 1 | -| T2.0 | | | | 5 | 0 | - | `UUUUU` | +| T2 | 3 | 14 | 14 | 11 | 0 | 0 | 4 | +| T2.0 | | | | 3 | 0 | - | `UUU` | +| T2.1 | | | | 3 | 0 | - | `UUU` | +| T2.2 | | | | 5 | 0 | - | `UUUUU` | +| T2.3 | | | | 3 | 0 | - | `UUU` | | T3 | 3 | 5 | 5 | 5 | 0 | 0 | 1 | | T3.0 | | | | 5 | 0 | - | `UUUUU` | diff --git a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/branching_medial_tire_decomposition/random_c5_n30_medial_tire_decomposition_1.pdf b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/branching_medial_tire_decomposition/random_c5_n30_medial_tire_decomposition_1.pdf index 2d81b0f..c2893ef 100644 Binary files a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/branching_medial_tire_decomposition/random_c5_n30_medial_tire_decomposition_1.pdf and b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/branching_medial_tire_decomposition/random_c5_n30_medial_tire_decomposition_1.pdf differ diff --git a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/branching_medial_tire_decomposition/random_c5_n30_medial_tire_decomposition_1.png b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/branching_medial_tire_decomposition/random_c5_n30_medial_tire_decomposition_1.png index 3deba94..4fb8276 100644 Binary files a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/branching_medial_tire_decomposition/random_c5_n30_medial_tire_decomposition_1.png and b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/branching_medial_tire_decomposition/random_c5_n30_medial_tire_decomposition_1.png differ diff --git a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/draw_random_medial_tire_decompositions.py b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/draw_random_medial_tire_decompositions.py index bc4ccba..d48cc60 100644 --- a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/draw_random_medial_tire_decompositions.py +++ b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/draw_random_medial_tire_decompositions.py @@ -52,6 +52,13 @@ class TreadNode: tires: tuple[tuple[FullMedialTireGraph, dict], ...] +@dataclass(frozen=True) +class Augmentation: + graph: nx.Graph + added_vertices: tuple[int, ...] + filled_faces: tuple[tuple[int, tuple[int, int, int], int], ...] + + def sample_plantri_graphs(n: int, count: int, seed: int, scan_limit: int) -> list[nx.Graph]: cmd = [str(REPO_ROOT / "plantri" / "plantri"), "-g", "-c5", str(n)] rng = random.Random(seed) @@ -111,6 +118,39 @@ def edge_face_data(faces): return face_edges, edge_faces +def augment_same_level_faces(g: nx.Graph, source: int) -> Augmentation: + """Stack a new vertex into every facial triangle with one BFS level. + + If a triangular face has all three vertices at level d, the new vertex is + adjacent to those three vertices and therefore has level d + 1. This turns + the same-level region into three adjacent-level tread faces before the tire + decomposition is extracted. + """ + levels = nx.single_source_shortest_path_length(g, source) + faces = triangular_faces(g) + augmented = g.copy() + next_vertex = max(augmented.nodes()) + 1 + added = [] + filled = [] + + for face in faces: + face_levels = {levels[v] for v in face} + if len(face_levels) != 1: + continue + new_vertex = next_vertex + next_vertex += 1 + augmented.add_node(new_vertex) + augmented.add_edges_from((new_vertex, v) for v in face) + added.append(new_vertex) + filled.append((new_vertex, tuple(face), next(iter(face_levels)))) + + return Augmentation( + graph=augmented, + added_vertices=tuple(added), + filled_faces=tuple(filled), + ) + + def depth_components(faces, face_edges, edge_faces, levels): depths = [min(levels[v] for v in face) for face in faces] dual_adj: dict[int, set[int]] = defaultdict(set) @@ -169,10 +209,12 @@ def tread_from_component(faces, levels, face_indices): } -def build_tire_tree(g: nx.Graph, source: int): - faces = triangular_faces(g) +def build_tire_tree(g: nx.Graph, source: int, augment: bool = True): + augmentation = augment_same_level_faces(g, source) if augment else Augmentation(g, (), ()) + work_graph = augmentation.graph + faces = triangular_faces(work_graph) face_edges, edge_faces = edge_face_data(faces) - levels = nx.single_source_shortest_path_length(g, source) + levels = nx.single_source_shortest_path_length(work_graph, source) comps, depths, dual_adj = depth_components(faces, face_edges, edge_faces, levels) comp_of_face = {} for comp_idx, (_depth, face_indices) in enumerate(comps): @@ -215,7 +257,7 @@ def build_tire_tree(g: nx.Graph, source: int): parent_candidates.add(comp_to_node[other_comp]) for parent in parent_candidates: tree_edges.add((parent, child)) - return faces, levels, nodes, sorted(tree_edges) + return augmentation, faces, levels, nodes, sorted(tree_edges) def graph_layout(g: nx.Graph): @@ -225,24 +267,37 @@ def graph_layout(g: nx.Graph): return nx.spring_layout(g, seed=0) -def draw_base_graph(ax, g, levels, source): +def draw_base_graph(ax, g, levels, source, added_vertices=()): pos = graph_layout(g) max_level = max(levels.values()) cmap = plt.get_cmap("viridis", max_level + 1) node_colors = [cmap(levels[v]) for v in g.nodes()] nx.draw_networkx_edges(g, pos, ax=ax, edge_color="#cbd5e1", width=0.8) + added_set = set(added_vertices) nx.draw_networkx_nodes( g, pos, ax=ax, node_color=node_colors, - node_size=[150 if v == source else 72 for v in g.nodes()], - edgecolors=["#dc2626" if v == source else "#111827" for v in g.nodes()], - linewidths=[1.8 if v == source else 0.45 for v in g.nodes()], + node_size=[ + 150 if v == source else 96 if v in added_set else 72 + for v in g.nodes() + ], + edgecolors=[ + "#dc2626" if v == source else "#7c3aed" if v in added_set else "#111827" + for v in g.nodes() + ], + linewidths=[ + 1.8 if v == source else 1.2 if v in added_set else 0.45 + for v in g.nodes() + ], ) labels = {v: str(v) for v in g.nodes()} nx.draw_networkx_labels(g, pos, labels=labels, ax=ax, font_size=5) - ax.set_title(f"G, source {source}; vertex levels 0..{max_level}", fontsize=10) + ax.set_title( + f"Augmented G, source {source}; vertex levels 0..{max_level}", + fontsize=10, + ) ax.set_aspect("equal") ax.axis("off") @@ -374,52 +429,69 @@ def draw_medial_tire_grid(fig, outer_spec, nodes): ax.axis("off") -def write_index(path: Path, graph_idx: int, source: int, g: nx.Graph, nodes, tree_edges): +def write_index( + path: Path, + graph_idx: int, + source: int, + original_graph: nx.Graph, + augmentation: Augmentation, + nodes, + tree_edges, +): + g = augmentation.graph lines = [ f"# Random medial tire decomposition {graph_idx}", "", - f"- vertices: {g.number_of_nodes()}", - f"- edges: {g.number_of_edges()}", - f"- node connectivity: {nx.node_connectivity(g)}", + f"- original vertices: {original_graph.number_of_nodes()}", + f"- original edges: {original_graph.number_of_edges()}", + f"- original node connectivity: {nx.node_connectivity(original_graph)}", + f"- augmented vertices: {g.number_of_nodes()}", + f"- augmented edges: {g.number_of_edges()}", + f"- same-level faces filled: {len(augmentation.added_vertices)}", f"- source vertex: {source}", f"- tire-tree nodes: {len(nodes)}", f"- tire-tree edges: {len(tree_edges)}", "", - "| node | depth | faces | annular | up | down | bites | full medial tires |", + "| node | depth | faces | annular | up | singleton down | bite apexes | full medial tires |", "|--:|--:|--:|--:|--:|--:|--:|--:|", ] for node in nodes: + singleton_down = set(node.down) - set(node.bites) lines.append( f"| T{node.idx} | {node.depth} | {len(node.face_indices)} | " - f"{len(node.annular)} | {len(node.up)} | {len(node.down)} | " + f"{len(node.annular)} | {len(node.up)} | {len(singleton_down)} | " f"{len(node.bites)} | {len(node.tires)} |" ) for comp_idx, (tire, _bij) in enumerate(node.tires): bites = ",".join(f"({i},{j})" for i, j in sorted(tire.bites)) or "-" lines.append( f"| T{node.idx}.{comp_idx} | | | | {len(tire.up_edges)} | " - f"{len(tire.down_edges)} | {bites} | `{tire.tooth_word}` |" + f"{len(tire.singleton_down_edges)} | {bites} | `{tire.tooth_word}` |" ) path.write_text("\n".join(lines) + "\n") -def draw_case(out_dir: Path, graph_idx: int, g: nx.Graph, source: int): - _faces, levels, nodes, tree_edges = build_tire_tree(g, source) +def draw_case(out_dir: Path, graph_idx: int, g: nx.Graph, source: int, augment: bool = True): + augmentation, _faces, levels, nodes, tree_edges = build_tire_tree(g, source, augment=augment) + work_graph = augmentation.graph fig = plt.figure(figsize=(17, 10)) spec = fig.add_gridspec(2, 2, width_ratios=[1.15, 1.0], height_ratios=[1.0, 1.25]) ax_graph = fig.add_subplot(spec[0, 0]) ax_tree = fig.add_subplot(spec[1, 0]) - draw_base_graph(ax_graph, g, levels, source) + draw_base_graph(ax_graph, work_graph, levels, source, augmentation.added_vertices) draw_tire_tree(ax_tree, nodes, tree_edges) draw_medial_tire_grid(fig, spec[:, 1], nodes) fig.suptitle( f"Random 5-connected maximal planar graph {graph_idx}: " - f"n={g.number_of_nodes()}, source={source}", + f"n={g.number_of_nodes()} (+{len(augmentation.added_vertices)}), " + f"source={source}", fontsize=13, ) legend = [ Line2D([0], [0], marker="o", color="w", label="source", markerfacecolor="#fde68a", markeredgecolor="#dc2626", markersize=8), + Line2D([0], [0], marker="o", color="w", label="inserted vertex", + markerfacecolor="#fde68a", markeredgecolor="#7c3aed", markersize=8), Line2D([0], [0], color="black", lw=1.3, label="annular cycle A(T)"), Line2D([0], [0], marker="o", color="w", label="up tooth", markerfacecolor="#2563eb", markersize=6), @@ -441,6 +513,7 @@ def draw_case(out_dir: Path, graph_idx: int, g: nx.Graph, source: int): graph_idx, source, g, + augmentation, nodes, tree_edges, ) @@ -462,7 +535,9 @@ def run(args: argparse.Namespace): sources = [rng.choice(list(graph.nodes())) for graph in graphs] for i, (graph, source) in enumerate(zip(graphs, sources), start=1): - png, pdf, node_count, tire_count = draw_case(out_dir, i, graph, source) + png, pdf, node_count, tire_count = draw_case( + out_dir, i, graph, source, augment=not args.no_augment_same_level_faces + ) print( f"case {i}: source={source}, connectivity={nx.node_connectivity(graph)}, " f"tire nodes={node_count}, full medial tires={tire_count}" @@ -479,6 +554,11 @@ def main(): parser.add_argument("--scan-limit", type=int, default=500) parser.add_argument("--graph6", help="draw this graph6 graph instead of sampling") parser.add_argument("--source", type=int, help="source vertex for --graph6") + parser.add_argument( + "--no-augment-same-level-faces", + action="store_true", + help="skip the same-level-face vertex insertion step", + ) parser.add_argument( "--out-dir", default=str(PAPER_DIR / "experiments" / "random_medial_tire_decompositions"), diff --git a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_1.md b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_1.md index 2b830ff..2898e67 100644 --- a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_1.md +++ b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_1.md @@ -1,18 +1,22 @@ # Random medial tire decomposition 1 -- vertices: 30 -- edges: 84 -- node connectivity: 5 +- original vertices: 30 +- original edges: 84 +- original node connectivity: 5 +- augmented vertices: 31 +- augmented edges: 87 +- same-level faces filled: 1 - source vertex: 9 - tire-tree nodes: 3 - tire-tree edges: 2 -| node | depth | faces | annular | up | down | bites | full medial tires | +| node | depth | faces | annular | up | singleton down | bite apexes | full medial tires | |--:|--:|--:|--:|--:|--:|--:|--:| | T0 | 1 | 16 | 16 | 6 | 10 | 0 | 1 | | T0.0 | | | | 6 | 10 | - | `DUDUDUDDUDDDUDDU` | | T1 | 2 | 20 | 20 | 10 | 10 | 0 | 1 | | T1.0 | | | | 10 | 10 | - | `UUDUUDUDDUDUDUDUUDDD` | -| T2 | 3 | 14 | 13 | 12 | 1 | 1 | 2 | -| T2.0 | | | | 6 | 2 | (1,5) | `UDUUUDUU` | -| T2.1 | | | | 5 | 0 | - | `UUUUU` | +| T2 | 3 | 16 | 16 | 12 | 0 | 1 | 3 | +| T2.0 | | | | 6 | 0 | (1,5) | `UDUUUDUU` | +| T2.1 | | | | 3 | 0 | - | `UUU` | +| T2.2 | | | | 5 | 0 | - | `UUUUU` | diff --git a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_1.pdf b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_1.pdf index da30abd..5ba9d88 100644 Binary files a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_1.pdf and b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_1.pdf differ diff --git a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_1.png b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_1.png index a7316d3..121503e 100644 Binary files a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_1.png and b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_1.png differ diff --git a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_2.md b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_2.md index ccc0fc0..36869e7 100644 --- a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_2.md +++ b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_2.md @@ -1,17 +1,23 @@ # Random medial tire decomposition 2 -- vertices: 30 -- edges: 84 -- node connectivity: 5 +- original vertices: 30 +- original edges: 84 +- original node connectivity: 5 +- augmented vertices: 32 +- augmented edges: 90 +- same-level faces filled: 2 - source vertex: 4 -- tire-tree nodes: 3 -- tire-tree edges: 2 +- tire-tree nodes: 4 +- tire-tree edges: 3 -| node | depth | faces | annular | up | down | bites | full medial tires | +| node | depth | faces | annular | up | singleton down | bite apexes | full medial tires | |--:|--:|--:|--:|--:|--:|--:|--:| | T0 | 1 | 16 | 16 | 7 | 9 | 0 | 1 | | T0.0 | | | | 7 | 9 | - | `DUDUDUDUDUDDUDUD` | | T1 | 2 | 17 | 17 | 9 | 8 | 0 | 1 | | T1.0 | | | | 9 | 8 | - | `UUUDDUDUDUDUDDUUD` | -| T2 | 3 | 14 | 14 | 8 | 5 | 1 | 1 | -| T2.0 | | | | 8 | 6 | (1,5) | `DDUUUDDUUDUDUU` | +| T2 | 3 | 14 | 14 | 8 | 4 | 1 | 1 | +| T2.0 | | | | 8 | 4 | (1,5) | `DDUUUDDUUDUDUU` | +| T3 | 4 | 6 | 6 | 5 | 0 | 0 | 2 | +| T3.0 | | | | 3 | 0 | - | `UUU` | +| T3.1 | | | | 3 | 0 | - | `UUU` | diff --git a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_2.pdf b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_2.pdf index be67d76..7f03ba2 100644 Binary files a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_2.pdf and b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_2.pdf differ diff --git a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_2.png b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_2.png index 42aad72..d56d6f8 100644 Binary files a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_2.png and b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/random_medial_tire_decompositions/random_c5_n30_medial_tire_decomposition_2.png differ