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


def open_dimacs(path):
    if str(path).endswith(".xz"):
        return lzma.open(path, "rt")
    return open(path, "rt")


def parse(path):
    nvars = nclauses = 0
    clauses = []
    with open_dimacs(path) as f:
        for line in f:
            if not line or line[0] == "c":
                continue
            if line[0] == "p":
                parts = line.split()
                nvars, nclauses = int(parts[2]), int(parts[3])
                continue
            lits = [int(x) for x in line.split()]
            if lits and lits[-1] == 0:
                lits.pop()
            if lits:
                clauses.append(lits)
    return nvars, nclauses, clauses


def main():
    for arg in sys.argv[1:]:
        path = Path(arg)
        nvars, hdr_clauses, clauses = parse(path)
        dist = collections.Counter(len(c) for c in clauses)
        long = []
        pos = neg = 0
        occ = [0] * (nvars + 1)
        posocc = [0] * (nvars + 1)
        negocc = [0] * (nvars + 1)
        for i, c in enumerate(clauses):
            all_pos = all(l > 0 for l in c)
            if len(c) >= 20 and all_pos:
                long.append((i, c))
            for l in c:
                if l > 0:
                    pos += 1
                    posocc[l] += 1
                else:
                    neg += 1
                    negocc[-l] += 1
                occ[abs(l)] += 1
        print(f"== {path.name} ==")
        print(f"vars={nvars} clauses={len(clauses)} hdr={hdr_clauses} lits={pos+neg} pos={pos} neg={neg}")
        print("sizes", " ".join(f"{k}:{v}" for k, v in sorted(dist.items())[:20]), "...", " ".join(f"{k}:{v}" for k, v in sorted(dist.items())[-10:]))
        print(f"long_pos={len(long)}")
        if long:
            sizes = collections.Counter(len(c) for _, c in long)
            print("long sizes", sorted(sizes.items()))
            for idx, c in long[:6]:
                diffs = [b - a for a, b in zip(c, c[1:])]
                print(f" long clause#{idx} len={len(c)} min={min(c)} max={max(c)} first={c[:12]} diffs_head={diffs[:12]}")
            for idx, c in long[-3:]:
                print(f" long tail clause#{idx} min={min(c)} max={max(c)} first={c[:8]} last={c[-8:]}")
        high_occ = sorted(((occ[v], v, posocc[v], negocc[v]) for v in range(1, nvars + 1)), reverse=True)[:20]
        print("top occ", high_occ[:10])
        gaps = []
        used = [v for v in range(1, nvars + 1) if occ[v]]
        last = 0
        for v in used:
            if v != last + 1:
                gaps.append((last + 1, v - 1))
            last = v
        if last < nvars:
            gaps.append((last + 1, nvars))
        print("used_range", (used[0], used[-1]) if used else None, "gaps", gaps[:10], "ngaps", len(gaps))


if __name__ == "__main__":
    main()
