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


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


def main():
    for path in sys.argv[1:]:
        nvars = nclauses = 0
        size_hist = collections.Counter()
        pos = collections.Counter()
        neg = collections.Counter()
        pair_blocks = collections.Counter()
        normalized_hist = collections.Counter()
        clauses = 0
        with open_maybe_xz(path) as f:
            for line in f:
                if not line or line[0] == "c":
                    continue
                parts = line.split()
                if not parts:
                    continue
                if parts[0] == "p":
                    nvars = int(parts[2])
                    nclauses = int(parts[3])
                    continue
                lits = [int(x) for x in parts if x != "0"]
                if not lits:
                    continue
                clauses += 1
                size_hist[len(lits)] += 1
                for lit in lits:
                    (pos if lit > 0 else neg)[abs(lit)] += 1
                if all(((abs(lits[i]) + 1 == abs(lits[i + 1])) and
                        (min(abs(lits[i]), abs(lits[i + 1])) % 2 == 1) and
                        ((lits[i] > 0) == (lits[i + 1] > 0)))
                       for i in range(0, len(lits), 2)) if len(lits) % 2 == 0 else False:
                    pair_blocks[len(lits) // 2] += 1
                    key = tuple((abs(lits[i]) + 1) // 2 for i in range(0, len(lits), 2))
                    signs = tuple(1 if lits[i] > 0 else -1 for i in range(0, len(lits), 2))
                    normalized_hist[(key, signs)] += 1

        used = set(pos) | set(neg)
        degs = [pos[v] + neg[v] for v in used]
        pos_minus_neg = [pos[v] - neg[v] for v in used]
        # Infer n when var count = 4*C(n,2).
        inferred_n = None
        disc = 1 + 2 * nvars
        root = int(math.isqrt(disc))
        if root * root == disc and (1 + root) % 2 == 0:
            inferred_n = (1 + root) // 2
        print(path)
        print(f"  header vars={nvars} clauses={nclauses} parsed={clauses} inferred_n={inferred_n}")
        print(f"  clause sizes={dict(sorted(size_hist.items()))}")
        print(f"  pair-shaped clauses={dict(sorted(pair_blocks.items()))}")
        print(f"  used vars={len(used)} min/max degree={min(degs)}/{max(degs)} avg={sum(degs)/len(degs):.2f}")
        print(f"  polarity delta min/max={min(pos_minus_neg)}/{max(pos_minus_neg)}")
        print(f"  duplicate exact normalized clauses={sum(c-1 for c in normalized_hist.values() if c > 1)}")


if __name__ == "__main__":
    main()
