#!/usr/bin/env python3
from recover_thresholds import parse, detect_n, fanin, unit_eval
import sys, os, time, re

def recover(path):
    nv,clauses=parse(path); N=detect_n(clauses); memo={}; preds=[]; th=[]
    for j in range(1,N+1):
        a=2*N+j; seed=j; triggers=[]
        for cl in clauses:
            if -a in cl and seed in cl:
                triggers=[x for x in cl if x not in (-a,seed) and x>0]; break
        ps=set()
        for tr in triggers: ps |= fanin(tr,N,clauses,memo)
        ps=sorted(ps); theta=10**9 if not ps else None
        local=[cl for cl in clauses if len(cl)>1 and max(abs(x) for x in cl) <= max(triggers+[a])]
        for k in range(len(ps)+1):
            ass=[-seed]+[(N+p if idx<k else -(N+p)) for idx,p in enumerate(ps)]
            val=unit_eval(nv,local,ass)
            if val and val[a]>0: theta=k; break
        preds.append([p-1 for p in ps]); th.append(theta if theta is not None else 10**9)
    return preds,th

def closure(preds, th, seeds):
    n=len(preds); active=seeds; changed=True
    while changed:
        changed=False
        for v in range(n):
            if (active>>v)&1: continue
            c=sum(1 for p in preds[v] if (active>>p)&1)
            if c>=th[v]: active|=1<<v; changed=True
    return active

def solve(preds,th,K,deadline):
    n=len(preds); full=(1<<n)-1; memo={}; nodes=0
    out=[[] for _ in range(n)]
    for v,ps in enumerate(preds):
        for p in ps: out[p].append(v)
    def benefit(active,v): return (closure(preds,th,active| (1<<v)) ^ active).bit_count()
    def rec(seeds,active,k):
        nonlocal nodes
        nodes+=1
        if nodes%1000==0 and time.time()>deadline: raise TimeoutError
        active=closure(preds,th,active|seeds)
        if active==full: return seeds
        if k==0: return None
        key=(active,k)
        if key in memo: return None
        inactive=[v for v in range(n) if not (active>>v)&1]
        # Branch on a small stalled core: vertices with largest deficit pressure first.
        cand=sorted(inactive, key=lambda v:(-benefit(active,v), th[v]-sum(1 for p in preds[v] if (active>>p)&1), -len(out[v])))
        # Keep completeness, but try high-benefit vertices first.
        for v in cand:
            r=rec(seeds | (1<<v), active | (1<<v), k-1)
            if r is not None: return r
        memo[key]=1; return None
    try: return rec(0,0,K),nodes,len(memo)
    except TimeoutError: return None,nodes,len(memo)

if __name__ == '__main__':
    for path in sys.argv[1:]:
        preds,th=recover(path); m=re.search(r'_(\d+)\.cnf', os.path.basename(path)); K=int(m.group(1))
        t=time.time(); sol,nodes,mem=solve(preds,th,K,t+60)
        print(os.path.basename(path),'K',K,'sol',None if sol is None else sol.bit_count(),'nodes',nodes,'mem',mem,'time',round(time.time()-t,2),'set',None if sol is None else [i+1 for i in range(len(preds)) if (sol>>i)&1])
