FA-88346 / Mesh topology invariants / Open access
Euler count omits the edge from the last vertex back to the first · case 01
Every face loses one edge, so E is too small and chi too large.
ROOT CAUSE
The face edge loop stops at n-1 pairs instead of wrapping around.
VERIFIED REPAIR
Iterate all n corners with (i+1) mod n.
Unsuccessful approach: Clamping the successor index creates a self-loop edge instead of the closing edge.
Case contract
Input: list of polygon faces (vertex index lists). V counts referenced vertices, E distinct undirected edges (closing edge included), F faces, chi=V-E+F, C connected components (via edges), B boundary loops = components of the graph of edges used by exactly one face. Return [V,E,F,chi,C,B,genus] with genus=(2C-chi-B)/2 or null when that numerator is odd (non-orientable signal).
Why this case matters
Mesh processing pipelines (remeshing, export, simulation, printing) trust these topological counts and adjacency answers; a wrong invariant silently accepts broken meshes or rejects valid ones.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
faces=x
edges={}
for f in faces:
n=len(f)
for i in range(n-1):
a,b=f[i],f[i+1]
k=(min(a,b),max(a,b))
edges[k]=edges.get(k,0)+1
verts=sorted({v for f in faces for v in f})
V=len(verts)
E=len(edges)
Fc=len(faces)
chi=V-E+Fc
parent={v:v for v in verts}
def find(v):
while parent[v]!=v:
v=parent[v]
return v
for a,b in edges:
ra,rb=find(a),find(b)
if ra!=rb: parent[ra]=rb
comps=len({find(v) for v in verts})
bpar={}
def bfind(v):
while bpar[v]!=v:
v=bpar[v]
return v
for (a,b),c in edges.items():
if c==1:
bpar.setdefault(a,a)
bpar.setdefault(b,b)
ra,rb=bfind(a),bfind(b)
if ra!=rb: bpar[ra]=rb
loops=len({bfind(v) for v in bpar})
g=2*comps-chi-loops
genus=None if g%2 else g//2
return [V,E,Fc,chi,comps,loops,genus]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['tetrahedron', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]]], [4, 6, 4, 2, 1, 0, 0]], ['cube quads', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [8, 12, 6, 2, 1, 0, 0]], ['octahedron', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], [6, 12, 8, 2, 1, 0, 0]], ['quad torus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0], [3, 6, 7, 4], [4, 7, 8, 5], [5, 8, 6, 3], [6, 0, 1, 7], [7, 1, 2, 8], [8, 2, 0, 6]]], [9, 18, 9, 0, 1, 0, 1]], ['triangle torus', [[[0, 3, 4], [0, 4, 1], [1, 4, 5], [1, 5, 2], [2, 5, 3], [2, 3, 0], [3, 6, 7], [3, 7, 4], [4, 7, 8], [4, 8, 5], [5, 8, 6], [5, 6, 3], [6, 0, 1], [6, 1, 7], [7, 1, 2], [7, 2, 8], [8, 2, 0], [8, 0, 6]]], [9, 27, 18, 0, 1, 0, 1]], ['disk fan', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], [6, 10, 5, 1, 1, 1, 0]], ['quad annulus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0]]], [6, 9, 3, 0, 1, 2, 0]]], [['cube quads', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [8, 12, 6, 2, 1, 0, 0]], ['triangle torus', [[[0, 3, 4], [0, 4, 1], [1, 4, 5], [1, 5, 2], [2, 5, 3], [2, 3, 0], [3, 6, 7], [3, 7, 4], [4, 7, 8], [4, 8, 5], [5, 8, 6], [5, 6, 3], [6, 0, 1], [6, 1, 7], [7, 1, 2], [7, 2, 8], [8, 2, 0], [8, 0, 6]]], [9, 27, 18, 0, 1, 0, 1]], ['disk fan', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], [6, 10, 5, 1, 1, 1, 0]], ['quad annulus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0]]], [6, 9, 3, 0, 1, 2, 0]], ['mobius strip', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 9, 3, 0, 1, 1, None]], ['projective plane', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [1, 2, 4], [2, 3, 5], [3, 4, 1], [4, 5, 2], [5, 1, 3]]], [6, 15, 10, 1, 1, 0, None]], ['two tetrahedra', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [4, 6, 5], [4, 5, 7], [5, 6, 7], [4, 7, 6]]], [8, 12, 8, 4, 2, 0, 0]]], [['octahedron', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], [6, 12, 8, 2, 1, 0, 0]], ['mobius strip', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 9, 3, 0, 1, 1, None]], ['projective plane', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [1, 2, 4], [2, 3, 5], [3, 4, 1], [4, 5, 2], [5, 1, 3]]], [6, 15, 10, 1, 1, 0, None]], ['two tetrahedra', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [4, 6, 5], [4, 5, 7], [5, 6, 7], [4, 7, 6]]], [8, 12, 8, 4, 2, 0, 0]], ['gapped indices', [[[0, 1, 5], [1, 7, 5]]], [4, 5, 2, 1, 1, 1, 0]], ['open cylinder', [[[0, 1, 5], [0, 5, 4], [1, 2, 6], [1, 6, 5], [2, 3, 7], [2, 7, 6], [3, 0, 4], [3, 4, 7]]], [8, 16, 8, 0, 1, 2, 0]], ['book of three pages', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [5, 7, 3, 1, 1, 1, 0]]], [['quad torus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0], [3, 6, 7, 4], [4, 7, 8, 5], [5, 8, 6, 3], [6, 0, 1, 7], [7, 1, 2, 8], [8, 2, 0, 6]]], [9, 18, 9, 0, 1, 0, 1]], ['gapped indices', [[[0, 1, 5], [1, 7, 5]]], [4, 5, 2, 1, 1, 1, 0]], ['open cylinder', [[[0, 1, 5], [0, 5, 4], [1, 2, 6], [1, 6, 5], [2, 3, 7], [2, 7, 6], [3, 0, 4], [3, 4, 7]]], [8, 16, 8, 0, 1, 2, 0]], ['book of three pages', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [5, 7, 3, 1, 1, 1, 0]], ['quad grid', [[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]]], [9, 12, 4, 1, 1, 1, 0]], ['mixed quad and triangle', [[[0, 1, 2, 3], [3, 2, 4]]], [5, 6, 2, 1, 1, 1, 0]], ['tetra plus disk', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [10, 11, 12], [10, 12, 13], [10, 13, 14], [10, 14, 15], [10, 15, 11]]], [10, 16, 9, 3, 2, 1, 0]]], [['tetrahedron', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]]], [4, 6, 4, 2, 1, 0, 0]], ['cube quads', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [8, 12, 6, 2, 1, 0, 0]], ['triangle torus', [[[0, 3, 4], [0, 4, 1], [1, 4, 5], [1, 5, 2], [2, 5, 3], [2, 3, 0], [3, 6, 7], [3, 7, 4], [4, 7, 8], [4, 8, 5], [5, 8, 6], [5, 6, 3], [6, 0, 1], [6, 1, 7], [7, 1, 2], [7, 2, 8], [8, 2, 0], [8, 0, 6]]], [9, 27, 18, 0, 1, 0, 1]], ['quad grid', [[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]]], [9, 12, 4, 1, 1, 1, 0]], ['mixed quad and triangle', [[[0, 1, 2, 3], [3, 2, 4]]], [5, 6, 2, 1, 1, 1, 0]], ['tetra plus disk', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [10, 11, 12], [10, 12, 13], [10, 13, 14], [10, 14, 15], [10, 15, 11]]], [10, 16, 9, 3, 2, 1, 0]], ['tetrahedra sharing a face', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [0, 1, 4], [1, 2, 4], [0, 4, 2]]], [5, 9, 7, 3, 1, 0, None]]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| tetrahedron | [4, 6, 4, 2, 1, 1, None] | [4, 6, 4, 2, 1, 0, 0] | Failed |
| cube quads | [8, 12, 6, 2, 1, 2, -1] | [8, 12, 6, 2, 1, 0, 0] | Failed |
| octahedron | [6, 12, 8, 2, 1, 1, None] | [6, 12, 8, 2, 1, 0, 0] | Failed |
| quad torus | [9, 18, 9, 0, 1, 3, None] | [9, 18, 9, 0, 1, 0, 1] | Failed |
| triangle torus | [9, 27, 18, 0, 1, 1, None] | [9, 27, 18, 0, 1, 0, 1] | Failed |
| disk fan | [6, 10, 5, 1, 1, 1, 0] | [6, 10, 5, 1, 1, 1, 0] | Passed |
| quad annulus | [6, 6, 3, 3, 1, 1, -1] | [6, 9, 3, 0, 1, 2, 0] | Failed |
SHA-256 / e32e9c662a1de6da525e6818cac0e13176ea5fcc57e5ccf005fb0c071205a2da
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
faces=x
edges={}
for f in faces:
n=len(f)
for i in range(n):
a,b=f[i],f[min(i+1,n-1)]
k=(min(a,b),max(a,b))
edges[k]=edges.get(k,0)+1
verts=sorted({v for f in faces for v in f})
V=len(verts)
E=len(edges)
Fc=len(faces)
chi=V-E+Fc
parent={v:v for v in verts}
def find(v):
while parent[v]!=v:
v=parent[v]
return v
for a,b in edges:
ra,rb=find(a),find(b)
if ra!=rb: parent[ra]=rb
comps=len({find(v) for v in verts})
bpar={}
def bfind(v):
while bpar[v]!=v:
v=bpar[v]
return v
for (a,b),c in edges.items():
if c==1:
bpar.setdefault(a,a)
bpar.setdefault(b,b)
ra,rb=bfind(a),bfind(b)
if ra!=rb: bpar[ra]=rb
loops=len({bfind(v) for v in bpar})
g=2*comps-chi-loops
genus=None if g%2 else g//2
return [V,E,Fc,chi,comps,loops,genus]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['tetrahedron', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]]], [4, 6, 4, 2, 1, 0, 0]], ['cube quads', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [8, 12, 6, 2, 1, 0, 0]], ['octahedron', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], [6, 12, 8, 2, 1, 0, 0]], ['quad torus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0], [3, 6, 7, 4], [4, 7, 8, 5], [5, 8, 6, 3], [6, 0, 1, 7], [7, 1, 2, 8], [8, 2, 0, 6]]], [9, 18, 9, 0, 1, 0, 1]], ['triangle torus', [[[0, 3, 4], [0, 4, 1], [1, 4, 5], [1, 5, 2], [2, 5, 3], [2, 3, 0], [3, 6, 7], [3, 7, 4], [4, 7, 8], [4, 8, 5], [5, 8, 6], [5, 6, 3], [6, 0, 1], [6, 1, 7], [7, 1, 2], [7, 2, 8], [8, 2, 0], [8, 0, 6]]], [9, 27, 18, 0, 1, 0, 1]], ['disk fan', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], [6, 10, 5, 1, 1, 1, 0]], ['quad annulus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0]]], [6, 9, 3, 0, 1, 2, 0]]], [['cube quads', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [8, 12, 6, 2, 1, 0, 0]], ['triangle torus', [[[0, 3, 4], [0, 4, 1], [1, 4, 5], [1, 5, 2], [2, 5, 3], [2, 3, 0], [3, 6, 7], [3, 7, 4], [4, 7, 8], [4, 8, 5], [5, 8, 6], [5, 6, 3], [6, 0, 1], [6, 1, 7], [7, 1, 2], [7, 2, 8], [8, 2, 0], [8, 0, 6]]], [9, 27, 18, 0, 1, 0, 1]], ['disk fan', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], [6, 10, 5, 1, 1, 1, 0]], ['quad annulus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0]]], [6, 9, 3, 0, 1, 2, 0]], ['mobius strip', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 9, 3, 0, 1, 1, None]], ['projective plane', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [1, 2, 4], [2, 3, 5], [3, 4, 1], [4, 5, 2], [5, 1, 3]]], [6, 15, 10, 1, 1, 0, None]], ['two tetrahedra', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [4, 6, 5], [4, 5, 7], [5, 6, 7], [4, 7, 6]]], [8, 12, 8, 4, 2, 0, 0]]], [['octahedron', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], [6, 12, 8, 2, 1, 0, 0]], ['mobius strip', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 9, 3, 0, 1, 1, None]], ['projective plane', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [1, 2, 4], [2, 3, 5], [3, 4, 1], [4, 5, 2], [5, 1, 3]]], [6, 15, 10, 1, 1, 0, None]], ['two tetrahedra', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [4, 6, 5], [4, 5, 7], [5, 6, 7], [4, 7, 6]]], [8, 12, 8, 4, 2, 0, 0]], ['gapped indices', [[[0, 1, 5], [1, 7, 5]]], [4, 5, 2, 1, 1, 1, 0]], ['open cylinder', [[[0, 1, 5], [0, 5, 4], [1, 2, 6], [1, 6, 5], [2, 3, 7], [2, 7, 6], [3, 0, 4], [3, 4, 7]]], [8, 16, 8, 0, 1, 2, 0]], ['book of three pages', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [5, 7, 3, 1, 1, 1, 0]]], [['quad torus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0], [3, 6, 7, 4], [4, 7, 8, 5], [5, 8, 6, 3], [6, 0, 1, 7], [7, 1, 2, 8], [8, 2, 0, 6]]], [9, 18, 9, 0, 1, 0, 1]], ['gapped indices', [[[0, 1, 5], [1, 7, 5]]], [4, 5, 2, 1, 1, 1, 0]], ['open cylinder', [[[0, 1, 5], [0, 5, 4], [1, 2, 6], [1, 6, 5], [2, 3, 7], [2, 7, 6], [3, 0, 4], [3, 4, 7]]], [8, 16, 8, 0, 1, 2, 0]], ['book of three pages', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [5, 7, 3, 1, 1, 1, 0]], ['quad grid', [[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]]], [9, 12, 4, 1, 1, 1, 0]], ['mixed quad and triangle', [[[0, 1, 2, 3], [3, 2, 4]]], [5, 6, 2, 1, 1, 1, 0]], ['tetra plus disk', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [10, 11, 12], [10, 12, 13], [10, 13, 14], [10, 14, 15], [10, 15, 11]]], [10, 16, 9, 3, 2, 1, 0]]], [['tetrahedron', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]]], [4, 6, 4, 2, 1, 0, 0]], ['cube quads', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [8, 12, 6, 2, 1, 0, 0]], ['triangle torus', [[[0, 3, 4], [0, 4, 1], [1, 4, 5], [1, 5, 2], [2, 5, 3], [2, 3, 0], [3, 6, 7], [3, 7, 4], [4, 7, 8], [4, 8, 5], [5, 8, 6], [5, 6, 3], [6, 0, 1], [6, 1, 7], [7, 1, 2], [7, 2, 8], [8, 2, 0], [8, 0, 6]]], [9, 27, 18, 0, 1, 0, 1]], ['quad grid', [[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]]], [9, 12, 4, 1, 1, 1, 0]], ['mixed quad and triangle', [[[0, 1, 2, 3], [3, 2, 4]]], [5, 6, 2, 1, 1, 1, 0]], ['tetra plus disk', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [10, 11, 12], [10, 12, 13], [10, 13, 14], [10, 14, 15], [10, 15, 11]]], [10, 16, 9, 3, 2, 1, 0]], ['tetrahedra sharing a face', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [0, 1, 4], [1, 2, 4], [0, 4, 2]]], [5, 9, 7, 3, 1, 0, None]]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| tetrahedron | [4, 9, 4, -1, 1, 1, 1] | [4, 6, 4, 2, 1, 0, 0] | Failed |
| cube quads | [8, 17, 6, -3, 1, 2, None] | [8, 12, 6, 2, 1, 0, 0] | Failed |
| octahedron | [6, 16, 8, -2, 1, 1, None] | [6, 12, 8, 2, 1, 0, 0] | Failed |
| quad torus | [9, 27, 9, -9, 1, 3, 4] | [9, 18, 9, 0, 1, 0, 1] | Failed |
| triangle torus | [9, 36, 18, -9, 1, 1, 5] | [9, 27, 18, 0, 1, 0, 1] | Failed |
| disk fan | [6, 15, 5, -4, 1, 1, None] | [6, 10, 5, 1, 1, 1, 0] | Failed |
| quad annulus | [6, 9, 3, 0, 1, 4, -1] | [6, 9, 3, 0, 1, 2, 0] | Failed |
SHA-256 / 1d0246dedabed5c9106fe651d65f019e4ff29be99ef9cc2cb798d7bb4a8669be
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
faces=x
edges={}
for f in faces:
n=len(f)
for i in range(n):
a,b=f[i],f[(i+1)%n]
k=(min(a,b),max(a,b))
edges[k]=edges.get(k,0)+1
verts=sorted({v for f in faces for v in f})
V=len(verts)
E=len(edges)
Fc=len(faces)
chi=V-E+Fc
parent={v:v for v in verts}
def find(v):
while parent[v]!=v:
v=parent[v]
return v
for a,b in edges:
ra,rb=find(a),find(b)
if ra!=rb: parent[ra]=rb
comps=len({find(v) for v in verts})
bpar={}
def bfind(v):
while bpar[v]!=v:
v=bpar[v]
return v
for (a,b),c in edges.items():
if c==1:
bpar.setdefault(a,a)
bpar.setdefault(b,b)
ra,rb=bfind(a),bfind(b)
if ra!=rb: bpar[ra]=rb
loops=len({bfind(v) for v in bpar})
g=2*comps-chi-loops
genus=None if g%2 else g//2
return [V,E,Fc,chi,comps,loops,genus]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['tetrahedron', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]]], [4, 6, 4, 2, 1, 0, 0]], ['cube quads', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [8, 12, 6, 2, 1, 0, 0]], ['octahedron', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], [6, 12, 8, 2, 1, 0, 0]], ['quad torus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0], [3, 6, 7, 4], [4, 7, 8, 5], [5, 8, 6, 3], [6, 0, 1, 7], [7, 1, 2, 8], [8, 2, 0, 6]]], [9, 18, 9, 0, 1, 0, 1]], ['triangle torus', [[[0, 3, 4], [0, 4, 1], [1, 4, 5], [1, 5, 2], [2, 5, 3], [2, 3, 0], [3, 6, 7], [3, 7, 4], [4, 7, 8], [4, 8, 5], [5, 8, 6], [5, 6, 3], [6, 0, 1], [6, 1, 7], [7, 1, 2], [7, 2, 8], [8, 2, 0], [8, 0, 6]]], [9, 27, 18, 0, 1, 0, 1]], ['disk fan', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], [6, 10, 5, 1, 1, 1, 0]], ['quad annulus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0]]], [6, 9, 3, 0, 1, 2, 0]]], [['cube quads', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [8, 12, 6, 2, 1, 0, 0]], ['triangle torus', [[[0, 3, 4], [0, 4, 1], [1, 4, 5], [1, 5, 2], [2, 5, 3], [2, 3, 0], [3, 6, 7], [3, 7, 4], [4, 7, 8], [4, 8, 5], [5, 8, 6], [5, 6, 3], [6, 0, 1], [6, 1, 7], [7, 1, 2], [7, 2, 8], [8, 2, 0], [8, 0, 6]]], [9, 27, 18, 0, 1, 0, 1]], ['disk fan', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], [6, 10, 5, 1, 1, 1, 0]], ['quad annulus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0]]], [6, 9, 3, 0, 1, 2, 0]], ['mobius strip', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 9, 3, 0, 1, 1, None]], ['projective plane', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [1, 2, 4], [2, 3, 5], [3, 4, 1], [4, 5, 2], [5, 1, 3]]], [6, 15, 10, 1, 1, 0, None]], ['two tetrahedra', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [4, 6, 5], [4, 5, 7], [5, 6, 7], [4, 7, 6]]], [8, 12, 8, 4, 2, 0, 0]]], [['octahedron', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], [6, 12, 8, 2, 1, 0, 0]], ['mobius strip', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 9, 3, 0, 1, 1, None]], ['projective plane', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [1, 2, 4], [2, 3, 5], [3, 4, 1], [4, 5, 2], [5, 1, 3]]], [6, 15, 10, 1, 1, 0, None]], ['two tetrahedra', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [4, 6, 5], [4, 5, 7], [5, 6, 7], [4, 7, 6]]], [8, 12, 8, 4, 2, 0, 0]], ['gapped indices', [[[0, 1, 5], [1, 7, 5]]], [4, 5, 2, 1, 1, 1, 0]], ['open cylinder', [[[0, 1, 5], [0, 5, 4], [1, 2, 6], [1, 6, 5], [2, 3, 7], [2, 7, 6], [3, 0, 4], [3, 4, 7]]], [8, 16, 8, 0, 1, 2, 0]], ['book of three pages', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [5, 7, 3, 1, 1, 1, 0]]], [['quad torus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0], [3, 6, 7, 4], [4, 7, 8, 5], [5, 8, 6, 3], [6, 0, 1, 7], [7, 1, 2, 8], [8, 2, 0, 6]]], [9, 18, 9, 0, 1, 0, 1]], ['gapped indices', [[[0, 1, 5], [1, 7, 5]]], [4, 5, 2, 1, 1, 1, 0]], ['open cylinder', [[[0, 1, 5], [0, 5, 4], [1, 2, 6], [1, 6, 5], [2, 3, 7], [2, 7, 6], [3, 0, 4], [3, 4, 7]]], [8, 16, 8, 0, 1, 2, 0]], ['book of three pages', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [5, 7, 3, 1, 1, 1, 0]], ['quad grid', [[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]]], [9, 12, 4, 1, 1, 1, 0]], ['mixed quad and triangle', [[[0, 1, 2, 3], [3, 2, 4]]], [5, 6, 2, 1, 1, 1, 0]], ['tetra plus disk', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [10, 11, 12], [10, 12, 13], [10, 13, 14], [10, 14, 15], [10, 15, 11]]], [10, 16, 9, 3, 2, 1, 0]]], [['tetrahedron', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]]], [4, 6, 4, 2, 1, 0, 0]], ['cube quads', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [8, 12, 6, 2, 1, 0, 0]], ['triangle torus', [[[0, 3, 4], [0, 4, 1], [1, 4, 5], [1, 5, 2], [2, 5, 3], [2, 3, 0], [3, 6, 7], [3, 7, 4], [4, 7, 8], [4, 8, 5], [5, 8, 6], [5, 6, 3], [6, 0, 1], [6, 1, 7], [7, 1, 2], [7, 2, 8], [8, 2, 0], [8, 0, 6]]], [9, 27, 18, 0, 1, 0, 1]], ['quad grid', [[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]]], [9, 12, 4, 1, 1, 1, 0]], ['mixed quad and triangle', [[[0, 1, 2, 3], [3, 2, 4]]], [5, 6, 2, 1, 1, 1, 0]], ['tetra plus disk', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [10, 11, 12], [10, 12, 13], [10, 13, 14], [10, 14, 15], [10, 15, 11]]], [10, 16, 9, 3, 2, 1, 0]], ['tetrahedra sharing a face', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [0, 1, 4], [1, 2, 4], [0, 4, 2]]], [5, 9, 7, 3, 1, 0, None]]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| tetrahedron | [4, 6, 4, 2, 1, 0, 0] | [4, 6, 4, 2, 1, 0, 0] | Passed |
| cube quads | [8, 12, 6, 2, 1, 0, 0] | [8, 12, 6, 2, 1, 0, 0] | Passed |
| octahedron | [6, 12, 8, 2, 1, 0, 0] | [6, 12, 8, 2, 1, 0, 0] | Passed |
| quad torus | [9, 18, 9, 0, 1, 0, 1] | [9, 18, 9, 0, 1, 0, 1] | Passed |
| triangle torus | [9, 27, 18, 0, 1, 0, 1] | [9, 27, 18, 0, 1, 0, 1] | Passed |
| disk fan | [6, 10, 5, 1, 1, 1, 0] | [6, 10, 5, 1, 1, 1, 0] | Passed |
| quad annulus | [6, 9, 3, 0, 1, 2, 0] | [6, 9, 3, 0, 1, 2, 0] | Passed |
SHA-256 / 2d245b5ff589df0ad0185d9ead85a28b9f184b1a562c7ecc947dfb54fadd3a7b
Verification & scope
Pure combinatorial teaching model over integer face lists with a stipulated contract; no geometry kernel or file format is implied. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:51:07.152033+00:00.
Case digest / 094b4209681e6e45744ad2a0e25388f323844ce06439c107189dda09fdfac0ab