#!/usr/bin/env python3
import lzma
import sys
from collections import Counter
from pathlib import Path


def aux_count(n, k):
    return sum(min(i, k) + 1 for i in range(1, n + 1))


def parse_edges(path):
    opener = lzma.open if str(path).endswith(".xz") else open
    vars_n = 0
    clauses = []
    cur = []
    max_clause = 0
    with opener(path, "rt") as f:
        for line in f:
            if not line or line[0] == "c":
                continue
            if line[0] == "p":
                vars_n = int(line.split()[2])
                continue
            for tok in line.split():
                lit = int(tok)
                if lit == 0:
                    if cur:
                        clauses.append(cur)
                        max_clause = max(max_clause, len(cur))
                        cur = []
                else:
                    cur.append(lit)
    k = max_clause - 1
    n = None
    for cand in range(k, vars_n + 1):
        if vars_n - cand == aux_count(cand, k):
            n = cand
            break
    edges = []
    if n:
        seen = set()
        for c in clauses:
            if len(c) == 2 and c[0] < 0 and c[1] < 0 and abs(c[0]) <= n and abs(c[1]) <= n:
                a, b = abs(c[0]) - 1, abs(c[1]) - 1
                if a != b:
                    key = (min(a, b), max(a, b))
                    if key not in seen:
                        seen.add(key)
                        edges.append(key)
    return n, k, edges


def popcount(x):
    return x.bit_count()


def main(paths):
    for raw in paths:
        path = Path(raw)
        n, k, edges = parse_edges(path)
        deg = Counter()
        diff = Counter()
        xor = Counter()
        xor_weight = Counter()
        moddiff = Counter()
        for a, b in edges:
            deg[a] += 1
            deg[b] += 1
            d = b - a
            diff[d] += 1
            moddiff[min(d, n - d)] += 1
            x = a ^ b
            xor[x] += 1
            xor_weight[popcount(x)] += 1
        deg_hist = Counter(deg[i] for i in range(n))
        print(f"\n{path.name} N={n} K={k} edges={len(edges)}")
        print("degree hist", " ".join(f"{d}:{c}" for d, c in sorted(deg_hist.items())))
        print("top modular diffs", moddiff.most_common(24))
        print("top raw diffs", diff.most_common(24))
        print("xor weights", sorted(xor_weight.items()))
        print("top xors", xor.most_common(24))
        print("first edges", edges[:40])


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