"""Measure the per-partition bridge-orbit size distribution for a dual,
with a modest cap, logging each partition's orbit size and time. Tells us
whether the slowness is a few giant orbits or uniformly heavy."""
import sys
import os
sys.path.insert(0, '/Users/didericis/Code/math-research/papers/'
                'level_resolutions_of_maximal_planar_graphs/experiments')
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import time
from load_holton_mckay import parse_planar_code
from tutte_dual_treecolor import dual_triangulation
from bridge_derived_test import sig, backward_bridge_neighbors
from exhaustive_bridge import valid_parity_partitions


def orbit_size(G, labels, cap, time_cap):
    t0 = time.time()
    seen = {sig(G)}
    frontier = [G]
    while frontier and len(seen) < cap:
        if time.time() - t0 > time_cap:
            return len(seen), time.time() - t0, 'timecap'
        new = []
        for H in frontier:
            for Hp in backward_bridge_neighbors(H, labels):
                s = sig(Hp)
                if s not in seen:
                    seen.add(s)
                    new.append(Hp)
        frontier = new
    return len(seen), time.time() - t0, ('exhausted' if not frontier else 'cap')


def main(i, cap=400000, time_cap=30):
    graphs = parse_planar_code('experiments/nonham38m4.pc')
    G, _ = dual_triangulation(graphs[i][0])
    parts = list(valid_parity_partitions(G))
    print(f'dual {i}: {len(parts)} partitions; cap={cap} time_cap={time_cap}s',
          flush=True)
    sizes = []
    for j, labels in enumerate(parts):
        n, dt, st = orbit_size(G, labels, cap, time_cap)
        sizes.append((n, st))
        print(f'  [{j}] orbit={n} {st} {dt:.1f}s', flush=True)
    exhausted = [n for n, st in sizes if st == 'exhausted']
    unfinished = [(n, st) for n, st in sizes if st != 'exhausted']
    print(f'\nexhausted: {len(exhausted)}/{len(parts)}; '
          f'largest exhausted={max(exhausted) if exhausted else 0}; '
          f'unfinished={len(unfinished)}', flush=True)


if __name__ == '__main__':
    main(int(sys.argv[1]) if len(sys.argv) > 1 else 0)
