#!/usr/bin/env python3
import collections
import lzma
import sys


def parse(path):
    opener = lzma.open if path.endswith(".xz") else open
    n = 0
    clauses = []
    with opener(path, "rt") as f:
        cur = []
        for line in f:
            if not line or line[0] == "c":
                continue
            if line[0] == "p":
                n = int(line.split()[2])
                continue
            for tok in line.split():
                lit = int(tok)
                if lit == 0:
                    if cur:
                        clauses.append(cur)
                        cur = []
                else:
                    cur.append(lit)
        if cur:
            clauses.append(cur)
    return n, clauses


def main(path):
    n, clauses = parse(path)
    hist = collections.Counter(map(len, clauses))
    N = max(hist)
    long_ids = [i for i, c in enumerate(clauses) if len(c) == N]
    w = len(long_ids) // (2 * N)
    p = None
    g = None
    for pp in range(2, N + 1):
        if N % pp:
            continue
        gg = N // pp
        if hist[pp + 1] == w * N * gg:
            p, g = pp, gg
            break
    print("vars", n, "clauses", len(clauses), "N", N, "w", w, "g", g, "p", p, "hist", dict(hist))
    long_pos = {cid: k for k, cid in enumerate(long_ids)}
    occ = collections.defaultdict(list)
    lit_occ = collections.defaultdict(list)
    for k, cid in enumerate(long_ids):
        for lit in clauses[cid]:
            occ[abs(lit)].append(k)
            lit_occ[lit].append(k)
    table_vars = [v for v, xs in occ.items() if len(xs) == 2]
    print("long vars", len(occ), "table_vars degree2", len(table_vars), "expected", w * N * N)
    sign_patterns = collections.Counter()
    bad = 0
    edges = []
    for v in table_vars:
        signs = []
        ids = []
        for k, cid in enumerate(long_ids):
            pass
        # recover signs from the two long clauses
        lits = []
        for k in occ[v]:
            c = clauses[long_ids[k]]
            for lit in c:
                if abs(lit) == v:
                    lits.append(lit)
                    break
        sign_patterns[tuple(1 if x > 0 else -1 for x in lits)] += 1
        if len(set(1 if x > 0 else -1 for x in lits)) != 1:
            bad += 1
        edges.append((occ[v][0], occ[v][1], v, 1 if lits[0] > 0 else -1))
    print("long occurrence sign patterns", sign_patterns, "bad mixed", bad)

    adj = [[] for _ in long_ids]
    for a, b, v, s in edges:
        adj[a].append((b, v))
        adj[b].append((a, v))
    seen = [False] * len(long_ids)
    comps = []
    colors = [-1] * len(long_ids)
    for i in range(len(long_ids)):
        if seen[i]:
            continue
        q = collections.deque([i])
        seen[i] = True
        colors[i] = 0
        comp = []
        bip = True
        while q:
            x = q.popleft()
            comp.append(x)
            for y, _ in adj[x]:
                if colors[y] < 0:
                    colors[y] = colors[x] ^ 1
                    seen[y] = True
                    q.append(y)
                elif colors[y] == colors[x]:
                    bip = False
        comps.append((comp, bip))
    print("components", [(len(c), b, sum(colors[x] == 0 for x in c), sum(colors[x] == 1 for x in c)) for c, b in comps[:20]])

    table_set = set(table_vars)
    table_lit_to_edge = {}
    for a, b, v, s in edges:
        table_lit_to_edge[v] = (a, b)
    sample = []
    sizep = []
    for ci, c in enumerate(clauses):
        if len(c) == p + 1:
            tv = [abs(l) for l in c if abs(l) in table_set]
            if len(tv) == p:
                nodes = [table_lit_to_edge[v] for v in tv]
                cnt = collections.Counter(x for e in nodes for x in e)
                common = [x for x, cc in cnt.items() if cc == p]
                sizep.append((ci, len(common), common[:4], nodes[:3], c))
                if len(sample) < 5:
                    sample.append(sizep[-1])
    print("p+1 clauses with p table vars", len(sizep), "common hist", collections.Counter(x[1] for x in sizep))
    for s in sample:
        print("sample p+1", s[:4], "clause", s[4])


if __name__ == "__main__":
    main(sys.argv[1])
