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

def open_any(p):
    return lzma.open(p,'rt') if str(p).endswith('.xz') else open(p)

def parse(p):
    n=m=None; clauses=[]
    for line in open_any(p):
        if not line or line[0]=='c': continue
        if line[0]=='p':
            _,fmt,n,m=line.split()[:4]; n=int(n); m=int(m)
        else:
            lits=list(map(int,line.split()))
            if lits and lits[-1]==0: lits=lits[:-1]
            if lits: clauses.append(tuple(lits))
    return n,clauses

def prof(p):
    n,clauses=parse(p)
    size=collections.Counter(map(len,clauses))
    pos=[0]*(n+1); neg=[0]*(n+1)
    for c in clauses:
        for l in c:
            (pos if l>0 else neg)[abs(l)]+=1
    deg=[pos[i]+neg[i] for i in range(1,n+1)]
    print('\nFILE',os.path.basename(p))
    print('vars clauses',n,len(clauses),'sizes',dict(sorted(size.items())))
    print('deg min/avg/max',min(deg),sum(deg)/n,max(deg),'pos lits',sum(pos),'neg lits',sum(neg))
    print('pure pos/neg/unused',sum(neg[i]==0 and pos[i]>0 for i in range(1,n+1)),sum(pos[i]==0 and neg[i]>0 for i in range(1,n+1)),sum(pos[i]+neg[i]==0 for i in range(1,n+1)))
    print('top degrees',sorted(((deg[i-1],i,pos[i],neg[i]) for i in range(1,n+1)), reverse=True)[:12])
    # binary graph components
    parent=list(range(n+1))
    def find(x):
        while parent[x]!=x:
            parent[x]=parent[parent[x]]; x=parent[x]
        return x
    def union(a,b):
        ra,rb=find(a),find(b)
        if ra!=rb: parent[rb]=ra
    for c in clauses:
        vs=[abs(l) for l in c]
        for v in vs[1:]: union(vs[0],v)
    comps=collections.Counter(find(i) for i in range(1,n+1))
    print('components',len(comps),'largest',comps.most_common(8))
    # clause signatures first 20 sorted size big
    print('sample clauses',clauses[:5])

for p in sys.argv[1:]: prof(p)
