"""Witness-hunt for one dual, sharded across processes: shard k of m scans
valid parity partitions [k::m]. First witness found anywhere proves the
dual is bridge-derived. Run several shards in parallel."""
import sys
import os
import time
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__)))
from load_holton_mckay import parse_planar_code
from tutte_dual_treecolor import dual_triangulation
from exhaustive_bridge import valid_parity_partitions
from fast_bridge import EdgeCode
from fast_decide import expand_and_check


def run(i, shard, nshards, cap):
    graphs = parse_planar_code('experiments/nonham38m4.pc')
    G, _ = dual_triangulation(graphs[i][0])
    n = G.number_of_nodes()
    code = EdgeCode(G.nodes())
    code.state0 = code.state_of(G)
    parts = list(valid_parity_partitions(G))
    mine = list(range(shard, len(parts), nshards))
    print(f'dual {i} shard {shard}/{nshards}: {len(mine)} partitions', flush=True)
    t0 = time.time()
    for j in mine:
        labels = parts[j]
        seen = {code.state0}
        frontier = [code.state0]
        found = False
        while frontier and len(seen) < cap:
            new = []
            for st in frontier:
                wit, neigh = expand_and_check(st, code, labels, n)
                if wit:
                    found = True
                    break
                for ns in neigh:
                    if ns not in seen:
                        seen.add(ns)
                        new.append(ns)
            if found:
                break
            frontier = new
        if found:
            print(f'dual {i} shard {shard}: WITNESS at partition {j} '
                  f'(orbit>={len(seen)}, {time.time()-t0:.0f}s) -> BRIDGE-DERIVED',
                  flush=True)
            return
        print(f'  shard {shard} part {j}: no witness (orbit {len(seen)}, '
              f'{time.time()-t0:.0f}s)', flush=True)
    print(f'dual {i} shard {shard}: done, no witness in my partitions', flush=True)


if __name__ == '__main__':
    i = int(sys.argv[1]); shard = int(sys.argv[2]); nshards = int(sys.argv[3])
    cap = int(sys.argv[4]) if len(sys.argv) > 4 else 300000
    run(i, shard, nshards, cap)
