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

def gen_row(bits, y0, sel, aux0):
    # common y variables y0..y0+9, candidate bits bits[0..5] encode [b0..b4,0,b5,0,0,finalspecial]
    a=aux0; out=[]; b=bits
    y=lambda i:y0+i
    out += [(b[0],y(0),a),(-b[0],-y(0),a),(b[0],-y(0))]; prev=a; a+=1
    for idx in range(1,5):
        cur=a; a+=1; x=b[idx]; yv=y(idx)
        out += [(x,yv,cur,-prev),(x,yv,-cur,prev),(-x,-yv,cur,-prev),(-x,-yv,-cur,prev),(-x,yv,prev),(x,-yv,-prev)]
        prev=cur
    cur=a; a+=1; out += [(y(5),cur,-prev),(y(5),-cur,prev),(-y(5),-prev)]; prev=cur
    cur=a; a+=1; x=b[5]; yv=y(6)
    out += [(x,yv,cur,-prev),(x,yv,-cur,prev),(-x,-yv,cur,-prev),(-x,-yv,-cur,prev),(-x,yv,prev),(x,-yv,-prev)]; prev=cur
    cur=a; a+=1; out += [(y(7),cur,-prev),(y(7),-cur,prev),(-y(7),-prev)]; prev=cur
    out += [(-y(8),-prev),(-y(9),-prev),(-y(8),-y(9),-prev),(y(8),y(9),prev)]
    for i in range(5): out += [(-sel,-y(i),b[i]),(-sel,-b[i],y(i))]
    out += [(-sel,-y(5))]
    out += [(-sel,-y(6),b[5]),(-sel,-b[5],y(6))]
    for i in [7,8,9]: out += [(-sel,-y(i))]
    xor_aux=[]
    for i in range(5):
        cur=a; a+=1; xor_aux.append(cur); x=b[i]; yv=y(i)
        out += [(sel,yv,x,-cur),(sel,-yv,-x,-cur),(sel,-yv,x,cur),(sel,yv,-x,cur)]
    cur=a; a+=1; xor_aux.append(cur); out += [(sel,y(5),-cur),(sel,-y(5),cur)]
    cur=a; a+=1; xor_aux.append(cur); x=b[5]; yv=y(6); out += [(sel,yv,x,-cur),(sel,-yv,-x,-cur),(sel,-yv,x,cur),(sel,yv,-x,cur)]
    for i in [7,8,9]:
        cur=a; a+=1; xor_aux.append(cur); out += [(sel,y(i),-cur),(sel,-y(i),cur)]
    out.append(tuple([sel]+xor_aux))
    return out

def detect(path, limit=None):
    with lzma.open(path,'rt') as fh:
        head=fh.readline().split(); V=int(head[2]); C=int(head[3])
        first=fh.readline().split(); P=abs(int(first[2]))-1
        clauses=[tuple(int(x) for x in first if x!='0')]
        for i,line in enumerate(fh,1):
            clauses.append(tuple(int(x) for x in line.split() if x!='0'))
            if limit and i>=limit: break
    blocks=[]; pos=0
    while pos+92<=len(clauses):
        cl=clauses[pos]
        matched=False
        if len(cl)==3 and cl[0]>0 and cl[1]>0 and cl[2]>P:
            x0,y0,aux0=cl
            # try first row layout with y0=x0+6, selector x0+16
            # and subsequent rows +7, stop at selector clause
            for mode in [0]:
                yy=y0
                # infer bits and selector for rows from first row if y0=x0+6 else not a min block first row
                if yy==x0+6:
                    row=0; p=pos; sels=[]; starts=[]
                    ok=True
                    while p+92<=len(clauses):
                        if row==0:
                            bits=list(range(x0,x0+6)); sel=x0+16
                        else:
                            s=x0+17+7*(row-1); bits=list(range(s,s+6)); sel=s+6
                        g=gen_row(bits,yy,sel,aux0+18*row)
                        if clauses[p:p+92]!=g:
                            break
                        sels.append(sel); starts.append(bits[0]); row+=1; p+=92
                    if row>0 and p<len(clauses) and clauses[p]==tuple(reversed(sels)):
                        blocks.append((pos,p+1,x0,yy,row,sels[0],sels[-1],aux0))
                        pos=p+1; matched=True
                        break
        if not matched:
            pos+=1
    print(os.path.basename(path),'P',P,'blocks',len(blocks),'consumed clauses',sum(b[1]-b[0] for b in blocks))
    cnt=collections.Counter(b[4] for b in blocks)
    print(' kdist',dict(cnt))
    print(' first10',blocks[:10])
    print(' last5',blocks[-5:])
    if blocks:
        print(' var ranges firstlast', (blocks[0][2], blocks[0][6]), (blocks[-1][2],blocks[-1][6]))

if __name__=='__main__':
    for path in sys.argv[1:]: detect(path)
