Add medial tire cut experiment and chaining section
New experiments/run_medial_tire_cut_experiment.py: generates a random maximal planar graph (stacked seed + random diagonal flips), builds the medial graph, takes the tire decomposition at a random vertex level source, walk-depth labels and cuts each full medial tire graph chained down the tire tree, and assembles one final cut graph of M(G) with a global label map (data only; graphics go in a separate script). Fix label_and_cut: the root face is None, which collided with the next(..., None) sentinel, leaving teeth unlabelled when the entry up tooth lay inside a bite gap; use a distinct sentinel so the ascent to the root face runs. Add a "Chaining across the tire tree" section to the paper, clarifying that the candidate parent down teeth are the boundary (singleton) down teeth only -- bite teeth are interior to the parent and shared with no child, so a lower-walk bite is skipped. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -179,7 +179,9 @@ def label_and_cut(graph: FullMedialTireGraph, entry_edge: int,
|
|||||||
# Steps 1-3: the entry face.
|
# Steps 1-3: the entry face.
|
||||||
traverse(innermost_bite(entry_edge, graph.bites), entry_edge, is_entry=True)
|
traverse(innermost_bite(entry_edge, graph.bites), entry_edge, is_entry=True)
|
||||||
|
|
||||||
# Steps 4-6: descend through bites, deepest first.
|
# Steps 4-6: descend (or ascend) through bites, deepest first. The root
|
||||||
|
# face is ``None``, so we use a distinct sentinel for "no unlabelled face".
|
||||||
|
_MISSING = object()
|
||||||
while len(depth) < graph.n:
|
while len(depth) < graph.n:
|
||||||
labelled_bite_teeth = sorted(
|
labelled_bite_teeth = sorted(
|
||||||
(e for e in depth if door_bite(graph, e) is not None),
|
(e for e in depth if door_bite(graph, e) is not None),
|
||||||
@@ -188,8 +190,8 @@ def label_and_cut(graph: FullMedialTireGraph, entry_edge: int,
|
|||||||
for t in labelled_bite_teeth:
|
for t in labelled_bite_teeth:
|
||||||
target = next((F for F in faces_bordered(graph, t)
|
target = next((F for F in faces_bordered(graph, t)
|
||||||
if any(e not in depth for e in face_boundary(graph, F))),
|
if any(e not in depth for e in face_boundary(graph, F))),
|
||||||
None)
|
_MISSING)
|
||||||
if target is not None:
|
if target is not _MISSING:
|
||||||
traverse(target, t, is_entry=False)
|
traverse(target, t, is_entry=False)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -0,0 +1,301 @@
|
|||||||
|
"""Medial tire cut experiment.
|
||||||
|
|
||||||
|
End-to-end experiment for the *Medial Tire Cuts* paper:
|
||||||
|
|
||||||
|
1. Generate a random maximal planar graph G on n vertices (stacked seed plus
|
||||||
|
random diagonal flips; ``random_maximal_planar`` from the medial tire
|
||||||
|
decompositions experiments).
|
||||||
|
2. Build its medial graph M(G).
|
||||||
|
3. Take the nested tire decomposition at one random vertex level source: the
|
||||||
|
BFS-level treads, each realized as a FullMedialTireGraph.
|
||||||
|
4. Walk-depth label and cut each full medial tire graph, chaining the labels
|
||||||
|
down the tire tree, and assemble one final cut graph of M(G) with a global
|
||||||
|
label map.
|
||||||
|
|
||||||
|
This script produces *data* (the final cut graph and its labels); it draws
|
||||||
|
nothing. Anything for the paper (figures) lives in a separate script that
|
||||||
|
imports ``run_experiment`` from here.
|
||||||
|
|
||||||
|
Chaining rule (walk depths across the tire tree).
|
||||||
|
* The root tread (no recognised parent) is entered at an arbitrary up tooth
|
||||||
|
with walk depth 0.
|
||||||
|
* A child tread is entered at the up tooth whose apex is the *same medial
|
||||||
|
vertex* as the parent's down tooth of lowest walk depth -- a parent down
|
||||||
|
tooth and the child up tooth glued to it across the shared level cycle are
|
||||||
|
the same medial vertex of M(G). The entry up tooth's walk depth is that
|
||||||
|
parent down tooth's depth + 1, and the walk increments locally from there.
|
||||||
|
|
||||||
|
Run with the repo venv (networkx + scipy): ``.venv/bin/python``.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import networkx as nx
|
||||||
|
|
||||||
|
# Reuse the realization pipeline from the medial tire decompositions paper, and
|
||||||
|
# the walk-depth labelling/cut from this paper's companion script.
|
||||||
|
_HERE = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
_MTD = os.path.normpath(os.path.join(
|
||||||
|
_HERE, "..", "..",
|
||||||
|
"medial_tire_decompositions_of_plane_triangulations", "experiments"))
|
||||||
|
sys.path.insert(0, _MTD)
|
||||||
|
sys.path.insert(0, _HERE)
|
||||||
|
|
||||||
|
from tire_realization_analysis import ( # noqa: E402
|
||||||
|
extract_tread, medial_graph, medial_tire_facemodel, random_maximal_planar,
|
||||||
|
recognise, triangular_faces,
|
||||||
|
)
|
||||||
|
from medial_tire_cut_labelling import door_bite, label_and_cut # noqa: E402
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# 4. Walk-depth labelling and cut, chained down the tire tree.
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
|
||||||
|
def _apex_vertex(g, bij, edge):
|
||||||
|
"""The medial vertex that is the apex of the tooth on annular ``edge``."""
|
||||||
|
return bij[g.apex_of_edge(edge)]
|
||||||
|
|
||||||
|
|
||||||
|
def _label_treads(treads, results):
|
||||||
|
"""Fill ``results[d]`` with the walk-depth labelling and cuts for each
|
||||||
|
recognised tread ``d``, chaining child entries to parent down teeth."""
|
||||||
|
for d in sorted(treads):
|
||||||
|
g, bij = treads[d]
|
||||||
|
parent = treads.get(d - 1)
|
||||||
|
if parent is None:
|
||||||
|
entry_edge, start_depth = g.up_edges[0], 0 # arbitrary root entry
|
||||||
|
else:
|
||||||
|
pg, pbij = parent
|
||||||
|
pdepth = results[d - 1]["depth"]
|
||||||
|
# parent down teeth, lowest walk depth first
|
||||||
|
down = sorted((pdepth[k], _apex_vertex(pg, pbij, k))
|
||||||
|
for k in pg.down_edges)
|
||||||
|
child_up_apex = {bij[f"u{m}"]: m for m in g.up_edges}
|
||||||
|
entry_edge = start_depth = None
|
||||||
|
for value, apex in down:
|
||||||
|
if apex in child_up_apex:
|
||||||
|
entry_edge, start_depth = child_up_apex[apex], value + 1
|
||||||
|
break
|
||||||
|
if entry_edge is None: # no shared apex (degenerate); root-style
|
||||||
|
entry_edge, start_depth = g.up_edges[0], 0
|
||||||
|
depth, cuts = label_and_cut(g, entry_edge, start_depth=start_depth)
|
||||||
|
results[d] = {"g": g, "bij": bij, "entry_edge": entry_edge,
|
||||||
|
"start_depth": start_depth, "depth": depth, "cuts": cuts}
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Assemble one final cut graph of M(G) with a global label map.
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
|
||||||
|
def _assemble_cut_graph(M, results):
|
||||||
|
"""Apply every tread's cuts to M(G).
|
||||||
|
|
||||||
|
Each cut duplicates an annular medial vertex, splitting its four incident
|
||||||
|
medial edges along the slit between the two teeth meeting there: the tooth
|
||||||
|
on the previous annular edge (with that edge's far annular vertex) goes to
|
||||||
|
one copy, the tooth on the next annular edge to the other.
|
||||||
|
|
||||||
|
Returns ``(H, label_records, warnings)`` where ``H`` is the cut graph (a
|
||||||
|
networkx graph whose split vertices are keyed ``(medial_vertex, "A"/"B",
|
||||||
|
tread)``) and ``label_records`` lists every tooth's walk depth.
|
||||||
|
"""
|
||||||
|
# Per cut annular vertex: map each original neighbour -> which copy keeps it.
|
||||||
|
split = {} # medial_vertex -> {neighbour_medial_vertex: copy_node}
|
||||||
|
warnings = []
|
||||||
|
for d in sorted(results):
|
||||||
|
g, bij = results[d]["g"], results[d]["bij"]
|
||||||
|
n = g.n
|
||||||
|
for c in results[d]["cuts"]:
|
||||||
|
kk = c.vertex
|
||||||
|
if kk is None:
|
||||||
|
continue
|
||||||
|
mv = bij[f"a{kk}"]
|
||||||
|
if mv in split:
|
||||||
|
warnings.append(f"annular vertex a{kk} of tread {d} cut twice; "
|
||||||
|
f"second cut not applied")
|
||||||
|
continue
|
||||||
|
e_prev, e_next = (kk - 1) % n, kk
|
||||||
|
copy_a = (mv, "A", d)
|
||||||
|
copy_b = (mv, "B", d)
|
||||||
|
split[mv] = {
|
||||||
|
bij[f"a{(kk - 1) % n}"]: copy_a,
|
||||||
|
_apex_vertex(g, bij, e_prev): copy_a,
|
||||||
|
bij[f"a{(kk + 1) % n}"]: copy_b,
|
||||||
|
_apex_vertex(g, bij, e_next): copy_b,
|
||||||
|
}
|
||||||
|
|
||||||
|
def resolve(node, other):
|
||||||
|
return split[node][other] if node in split else node
|
||||||
|
|
||||||
|
H = nx.Graph()
|
||||||
|
H.add_nodes_from(v for v in M.nodes() if v not in split)
|
||||||
|
for v, copies in split.items():
|
||||||
|
H.add_nodes_from(set(copies.values()))
|
||||||
|
for u, v in M.edges():
|
||||||
|
H.add_edge(resolve(u, v), resolve(v, u))
|
||||||
|
|
||||||
|
label_records = []
|
||||||
|
for d in sorted(results):
|
||||||
|
g, bij, depth = results[d]["g"], results[d]["bij"], results[d]["depth"]
|
||||||
|
for k in range(g.n):
|
||||||
|
role = ("up" if g.tooth_word[k] == "U"
|
||||||
|
else "bite" if door_bite(g, k) is not None else "down")
|
||||||
|
label_records.append({
|
||||||
|
"tread": d, "edge": k, "role": role,
|
||||||
|
"apex": _apex_vertex(g, bij, k), "walk": depth[k],
|
||||||
|
})
|
||||||
|
return H, label_records, warnings
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Driver.
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
|
||||||
|
def run_experiment(n: int = 12, seed: int = 0, flips: int = 400) -> dict:
|
||||||
|
"""Run the full pipeline and return a structured result.
|
||||||
|
|
||||||
|
Result keys: ``n, seed, G, M, source, treads`` (dict depth -> (g, bij)),
|
||||||
|
``results`` (dict depth -> labelling/cut record), ``skipped`` (list of
|
||||||
|
(depth, reason)), ``cut_graph`` (networkx graph), ``labels`` (list of tooth
|
||||||
|
records), ``warnings``.
|
||||||
|
"""
|
||||||
|
G = random_maximal_planar(n, seed, flips=flips)
|
||||||
|
faces, _ = triangular_faces(G)
|
||||||
|
M = medial_graph(G)
|
||||||
|
source = random.Random(f"source-{seed}").choice(sorted(G.nodes()))
|
||||||
|
levels = nx.single_source_shortest_path_length(G, source)
|
||||||
|
|
||||||
|
treads, skipped = {}, []
|
||||||
|
for d in range(max(levels.values())):
|
||||||
|
tread = extract_tread(faces, levels, d)
|
||||||
|
if tread is None:
|
||||||
|
skipped.append((d, "no tread faces"))
|
||||||
|
continue
|
||||||
|
if len(tread["up"]) < 3:
|
||||||
|
skipped.append((d, f"only {len(tread['up'])} up teeth"))
|
||||||
|
continue
|
||||||
|
rec = recognise(medial_tire_facemodel(tread["tread_faces"]), tread)
|
||||||
|
if rec is None:
|
||||||
|
skipped.append((d, "not a valid full medial tire graph"))
|
||||||
|
continue
|
||||||
|
treads[d] = rec
|
||||||
|
|
||||||
|
results = {}
|
||||||
|
_label_treads(treads, results)
|
||||||
|
cut_graph, labels, warnings = _assemble_cut_graph(M, results)
|
||||||
|
return {
|
||||||
|
"n": n, "seed": seed, "G": G, "M": M, "source": source,
|
||||||
|
"treads": treads, "results": results, "skipped": skipped,
|
||||||
|
"cut_graph": cut_graph, "labels": labels, "warnings": warnings,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Serialization / reporting.
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
|
||||||
|
def _vname(v) -> str:
|
||||||
|
"""Stable string name for a medial vertex (an edge key) or a split node."""
|
||||||
|
if isinstance(v, tuple) and len(v) == 3 and v[1] in ("A", "B"):
|
||||||
|
mv, side, d = v
|
||||||
|
return f"{mv[0]}-{mv[1]}#{side}@T{d}"
|
||||||
|
return f"{v[0]}-{v[1]}"
|
||||||
|
|
||||||
|
|
||||||
|
def to_json(result: dict) -> dict:
|
||||||
|
res = result["results"]
|
||||||
|
treads_out = []
|
||||||
|
for d in sorted(res):
|
||||||
|
g, bij = res[d]["g"], res[d]["bij"]
|
||||||
|
depth, cuts = res[d]["depth"], res[d]["cuts"]
|
||||||
|
teeth = [{
|
||||||
|
"edge": k,
|
||||||
|
"role": ("up" if g.tooth_word[k] == "U"
|
||||||
|
else "bite" if door_bite(g, k) is not None else "down"),
|
||||||
|
"apex": _vname(_apex_vertex(g, bij, k)),
|
||||||
|
"walk": depth[k],
|
||||||
|
} for k in range(g.n)]
|
||||||
|
treads_out.append({
|
||||||
|
"depth": d, "n": g.n, "tooth_word": g.tooth_word,
|
||||||
|
"bites": sorted(list(b) for b in g.bites),
|
||||||
|
"entry_edge": res[d]["entry_edge"], "start_depth": res[d]["start_depth"],
|
||||||
|
"teeth": teeth,
|
||||||
|
"cuts": [{
|
||||||
|
"annular_index": c.vertex,
|
||||||
|
"annular_vertex": _vname(bij[f"a{c.vertex}"]),
|
||||||
|
"last_edge": c.last_tooth, "closing_edge": c.closing_tooth,
|
||||||
|
} for c in cuts],
|
||||||
|
})
|
||||||
|
H = result["cut_graph"]
|
||||||
|
return {
|
||||||
|
"n": result["n"], "seed": result["seed"], "source": result["source"],
|
||||||
|
"graph_edges": sorted([int(u), int(v)] for u, v in result["G"].edges()),
|
||||||
|
"medial_vertices": result["M"].number_of_nodes(),
|
||||||
|
"skipped": [[d, why] for d, why in result["skipped"]],
|
||||||
|
"treads": treads_out,
|
||||||
|
"cut_graph": {
|
||||||
|
"nodes": sorted(_vname(v) for v in H.nodes()),
|
||||||
|
"edges": sorted([_vname(u), _vname(v)] for u, v in H.edges()),
|
||||||
|
},
|
||||||
|
"labels": [{
|
||||||
|
"tread": r["tread"], "edge": r["edge"], "role": r["role"],
|
||||||
|
"apex": _vname(r["apex"]), "walk": r["walk"],
|
||||||
|
} for r in result["labels"]],
|
||||||
|
"warnings": result["warnings"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def summary(result: dict) -> str:
|
||||||
|
H, res = result["cut_graph"], result["results"]
|
||||||
|
lines = [
|
||||||
|
f"random maximal planar graph: n={result['n']} seed={result['seed']} "
|
||||||
|
f"({result['G'].number_of_edges()} edges)",
|
||||||
|
f"medial graph M(G): {result['M'].number_of_nodes()} vertices",
|
||||||
|
f"level source: vertex {result['source']}",
|
||||||
|
f"recognised treads: {sorted(res)}",
|
||||||
|
f"skipped treads: {result['skipped']}",
|
||||||
|
]
|
||||||
|
for d in sorted(res):
|
||||||
|
g = res[d]["g"]
|
||||||
|
ncuts = len(res[d]["cuts"])
|
||||||
|
lines.append(
|
||||||
|
f" tread {d}: |A(T)|={g.n} word={g.tooth_word} "
|
||||||
|
f"bites={sorted(g.bites)} entry=e{res[d]['entry_edge']} "
|
||||||
|
f"start_depth={res[d]['start_depth']} cuts={ncuts}")
|
||||||
|
lines.append(
|
||||||
|
f"final cut graph: {H.number_of_nodes()} vertices, "
|
||||||
|
f"{H.number_of_edges()} edges, "
|
||||||
|
f"{sum(len(r['cuts']) for r in res.values())} cuts total")
|
||||||
|
if result["warnings"]:
|
||||||
|
lines.append("warnings: " + "; ".join(result["warnings"]))
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
parser.add_argument("-n", type=int, default=12, help="number of vertices")
|
||||||
|
parser.add_argument("--seed", type=int, default=0)
|
||||||
|
parser.add_argument("--flips", type=int, default=400,
|
||||||
|
help="number of random diagonal flips when building G")
|
||||||
|
parser.add_argument("--json", metavar="PATH",
|
||||||
|
help="write the full result as JSON to PATH")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
result = run_experiment(n=args.n, seed=args.seed, flips=args.flips)
|
||||||
|
print(summary(result))
|
||||||
|
if args.json:
|
||||||
|
with open(args.json, "w") as fh:
|
||||||
|
json.dump(to_json(result), fh, indent=2)
|
||||||
|
print(f"wrote {args.json}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -6,15 +6,19 @@
|
|||||||
\@writefile{toc}{\contentsline {section}{\tocsection {}{2}{Cutting a full medial tire graph}}{1}{}\protected@file@percent }
|
\@writefile{toc}{\contentsline {section}{\tocsection {}{2}{Cutting a full medial tire graph}}{1}{}\protected@file@percent }
|
||||||
\newlabel{def:walk-depth-cut}{{2.1}{1}}
|
\newlabel{def:walk-depth-cut}{{2.1}{1}}
|
||||||
\citation{bauerfeld-medial-tire}
|
\citation{bauerfeld-medial-tire}
|
||||||
|
\citation{bauerfeld-medial-tire}
|
||||||
|
\newlabel{rem:closing-tooth}{{2.2}{2}}
|
||||||
|
\newlabel{ex:worked-cut}{{2.3}{2}}
|
||||||
|
\@writefile{toc}{\contentsline {section}{\tocsection {}{3}{Chaining across the tire tree}}{2}{}\protected@file@percent }
|
||||||
|
\citation{bauerfeld-medial-tire}
|
||||||
\bibcite{bauerfeld-medial-tire}{1}
|
\bibcite{bauerfeld-medial-tire}{1}
|
||||||
|
\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces A full medial tire graph (left) and its walk-depth labelling and cut (right), from Example\nonbreakingspace 2.3\hbox {}. Black vertices are the annular medial vertices of the cycle $A(T)$; blue vertices are up-tooth apexes, red vertices are down-tooth apexes, and the larger red vertex is the shared apex of the bite on annular edges $0$ and $4$. On the right, each tooth carries its walk depth, and the two red slits mark the cuts: \emph {cut\nonbreakingspace 1} duplicates $a_5$ as the root-face traversal closes, and \emph {cut\nonbreakingspace 2} duplicates $a_1$ as the bite's inner-gap face closes. After the cuts the only bounded faces are the eight teeth.}}{3}{}\protected@file@percent }
|
||||||
|
\newlabel{fig:worked-cut}{{1}{3}}
|
||||||
|
\newlabel{rem:chaining-candidates}{{3.1}{3}}
|
||||||
\newlabel{tocindent-1}{0pt}
|
\newlabel{tocindent-1}{0pt}
|
||||||
\newlabel{tocindent0}{12.7778pt}
|
\newlabel{tocindent0}{12.7778pt}
|
||||||
\newlabel{tocindent1}{17.77782pt}
|
\newlabel{tocindent1}{17.77782pt}
|
||||||
\newlabel{tocindent2}{0pt}
|
\newlabel{tocindent2}{0pt}
|
||||||
\newlabel{tocindent3}{0pt}
|
\newlabel{tocindent3}{0pt}
|
||||||
\newlabel{rem:closing-tooth}{{2.2}{2}}
|
\@writefile{toc}{\contentsline {section}{\tocsection {}{}{References}}{4}{}\protected@file@percent }
|
||||||
\newlabel{ex:worked-cut}{{2.3}{2}}
|
\gdef \@abspage@last{4}
|
||||||
\@writefile{toc}{\contentsline {section}{\tocsection {}{}{References}}{2}{}\protected@file@percent }
|
|
||||||
\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces A full medial tire graph (left) and its walk-depth labelling and cut (right), from Example\nonbreakingspace 2.3\hbox {}. Black vertices are the annular medial vertices of the cycle $A(T)$; blue vertices are up-tooth apexes, red vertices are down-tooth apexes, and the larger red vertex is the shared apex of the bite on annular edges $0$ and $4$. On the right, each tooth carries its walk depth, and the two red slits mark the cuts: \emph {cut\nonbreakingspace 1} duplicates $a_5$ as the root-face traversal closes, and \emph {cut\nonbreakingspace 2} duplicates $a_1$ as the bite's inner-gap face closes. After the cuts the only bounded faces are the eight teeth.}}{3}{}\protected@file@percent }
|
|
||||||
\newlabel{fig:worked-cut}{{1}{3}}
|
|
||||||
\gdef \@abspage@last{3}
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex 2022.10.5) 14 JUN 2026 21:56
|
This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex 2022.10.5) 14 JUN 2026 23:46
|
||||||
entering extended mode
|
entering extended mode
|
||||||
restricted \write18 enabled.
|
restricted \write18 enabled.
|
||||||
%&-line parsing enabled.
|
%&-line parsing enabled.
|
||||||
@@ -498,33 +498,33 @@ e
|
|||||||
|
|
||||||
LaTeX Warning: `h' float specifier changed to `ht'.
|
LaTeX Warning: `h' float specifier changed to `ht'.
|
||||||
|
|
||||||
[2] [3] (./paper.aux) )
|
[2] [3] [4] (./paper.aux) )
|
||||||
Here is how much of TeX's memory you used:
|
Here is how much of TeX's memory you used:
|
||||||
13647 strings out of 478268
|
13648 strings out of 478268
|
||||||
272595 string characters out of 5846347
|
272620 string characters out of 5846347
|
||||||
554433 words of memory out of 5000000
|
558283 words of memory out of 5000000
|
||||||
31476 multiletter control sequences out of 15000+600000
|
31477 multiletter control sequences out of 15000+600000
|
||||||
477049 words of font info for 58 fonts, out of 8000000 for 9000
|
477049 words of font info for 58 fonts, out of 8000000 for 9000
|
||||||
1302 hyphenation exceptions out of 8191
|
1302 hyphenation exceptions out of 8191
|
||||||
84i,9n,89p,936b,704s stack positions out of 10000i,1000n,20000p,200000b,200000s
|
84i,9n,89p,801b,704s stack positions out of 10000i,1000n,20000p,200000b,200000s
|
||||||
</usr/local/texlive/2022/texmf-dist/fonts/type1/public/a
|
</usr/local/texlive/2022/texmf-dist/fonts/type1/publ
|
||||||
msfonts/cm/cmbx10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/am
|
ic/amsfonts/cm/cmbx10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/publi
|
||||||
sfonts/cm/cmbx7.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsf
|
c/amsfonts/cm/cmbx7.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/
|
||||||
onts/cm/cmcsc10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsf
|
amsfonts/cm/cmcsc10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/
|
||||||
onts/cm/cmmi10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfo
|
amsfonts/cm/cmmi10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/a
|
||||||
nts/cm/cmr10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfont
|
msfonts/cm/cmr10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/ams
|
||||||
s/cm/cmr6.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/c
|
fonts/cm/cmr6.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfon
|
||||||
m/cmr7.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/c
|
ts/cm/cmr7.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/
|
||||||
mr8.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmss
|
cm/cmr8.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/
|
||||||
10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy1
|
cmss10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/c
|
||||||
0.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmti10
|
msy10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cm
|
||||||
.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmti8.p
|
ti10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmt
|
||||||
fb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmtt10.pf
|
i8.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmtt1
|
||||||
b>
|
0.pfb>
|
||||||
Output written on paper.pdf (3 pages, 172798 bytes).
|
Output written on paper.pdf (4 pages, 176366 bytes).
|
||||||
PDF statistics:
|
PDF statistics:
|
||||||
82 PDF objects out of 1000 (max. 8388607)
|
85 PDF objects out of 1000 (max. 8388607)
|
||||||
50 compressed objects within 1 object stream
|
52 compressed objects within 1 object stream
|
||||||
0 named destinations out of 1000 (max. 500000)
|
0 named destinations out of 1000 (max. 500000)
|
||||||
13 words of extra memory for PDF output out of 10000 (max. 10000000)
|
13 words of extra memory for PDF output out of 10000 (max. 10000000)
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -261,6 +261,54 @@ the cuts the only bounded faces are the eight teeth.}
|
|||||||
\label{fig:worked-cut}
|
\label{fig:worked-cut}
|
||||||
\end{figure}
|
\end{figure}
|
||||||
|
|
||||||
|
\section{Chaining across the tire tree}
|
||||||
|
|
||||||
|
Definition~\ref{def:walk-depth-cut} labels and cuts a single full medial
|
||||||
|
tire graph. We extend it to the whole medial graph $M(G)$ through the
|
||||||
|
medial tire decomposition of~\cite{bauerfeld-medial-tire}: the tire tree
|
||||||
|
decomposes $M(G)$ into full medial tire graphs $\mathsf{M}(T)$, one per
|
||||||
|
tread $T$, glued along their boundary medial vertices. A parent tread's
|
||||||
|
inner level cycle is a child tread's outer level cycle, and the boundary
|
||||||
|
medial vertices on that shared cycle belong to both treads.
|
||||||
|
|
||||||
|
The key incidence is this. A \emph{boundary} (singleton) down tooth of a
|
||||||
|
parent tread and the up tooth of the child tread glued to it across the
|
||||||
|
shared level cycle have the \emph{same apex}: both apexes are the same
|
||||||
|
medial vertex of $M(G)$, namely the medial vertex of an edge with both
|
||||||
|
endpoints on the shared level cycle. We use this to carry the walk depth
|
||||||
|
from a parent into its children.
|
||||||
|
|
||||||
|
We label tread by tread, outward from the root:
|
||||||
|
\begin{itemize}
|
||||||
|
\item a tread with no parent in the decomposition---in particular the
|
||||||
|
innermost recognised tread---is treated as a \emph{root} and entered at
|
||||||
|
an arbitrary up tooth with walk depth $0$;
|
||||||
|
\item a child tread is entered at the up tooth whose apex is the parent's
|
||||||
|
boundary down tooth of lowest walk depth; that entry up tooth's walk depth
|
||||||
|
is one more than that down tooth's, and the walk then increments locally
|
||||||
|
within the child as in Definition~\ref{def:walk-depth-cut}.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\begin{remark}[Candidate down teeth for chaining]
|
||||||
|
\label{rem:chaining-candidates}
|
||||||
|
The down teeth eligible to fix a child's entry are exactly the
|
||||||
|
\emph{boundary} (singleton) down teeth of the parent: those lying in a
|
||||||
|
single tread face, whose apex is the shared boundary medial vertex glued to
|
||||||
|
a child up tooth. A bite's two down teeth are \emph{not} eligible. By the
|
||||||
|
definition of a bite in~\cite{bauerfeld-medial-tire} its annular edge borders
|
||||||
|
two tread faces, so a bite tooth is interior to the parent tread and its
|
||||||
|
apex is a boundary medial vertex of no child. Hence ``the down tooth of
|
||||||
|
lowest walk depth'' is read among the boundary down teeth only; a bite of
|
||||||
|
even lower walk depth is skipped.
|
||||||
|
\end{remark}
|
||||||
|
|
||||||
|
Applying every tread's cuts to $M(G)$ assembles the per-tread labellings
|
||||||
|
and cuts into a single cut graph of $M(G)$ together with a global
|
||||||
|
walk-depth label map. This pipeline---random maximal planar graph, medial
|
||||||
|
graph, tire decomposition at a vertex level source, and chained walk-depth
|
||||||
|
labelling and cut---is carried out by the experiment script
|
||||||
|
\texttt{experiments/run\_medial\_tire\_cut\_experiment.py}.
|
||||||
|
|
||||||
\begin{thebibliography}{9}
|
\begin{thebibliography}{9}
|
||||||
|
|
||||||
\bibitem{bauerfeld-medial-tire}
|
\bibitem{bauerfeld-medial-tire}
|
||||||
|
|||||||
Reference in New Issue
Block a user