#!/usr/bin/env python3
import sys,lzma,time,collections
sys.setrecursionlimit(1000000)
def op(p): return lzma.open(p,'rt') if p.endswith('.xz') else open(p)
def load(path):
 rows=[]; bins=[]
 with op(path) as f:
  for line in f:
   if line[0]=='c' or line[0]=='p': continue
   arr=[int(x) for x in line.split() if x!='0']
   if len(arr)==2: bins.append(tuple(arr))
   elif arr: rows.append(arr)
 rowof={}; idx={}
 for r,row in enumerate(rows):
  for i,lit in enumerate(row): rowof[abs(lit)]=r; idx[abs(lit)]=i
 forb={}; neigh=[set() for _ in rows]
 for a,b in bins:
  va,vb=abs(a),abs(b); r,s=rowof[va],rowof[vb]
  if r==s: continue
  i,j=idx[va],idx[vb]
  forb.setdefault((r,s), [0]*len(rows[r]))[i] |= 1<<j
  forb.setdefault((s,r), [0]*len(rows[s]))[j] |= 1<<i
  neigh[r].add(s); neigh[s].add(r)
 return rows,forb,[list(x) for x in neigh]
def solve(path,limit=60):
 rows,forb,neigh=load(path); R=len(rows); dom=[(1<<len(r))-1 for r in rows]; assigned=[-1]*R; nodes=0; t0=time.time()
 full=[(1<<len(r))-1 for r in rows]
 # initial AC as before omitted
 def propagate(queue,trail):
  while queue:
   s,val=queue.pop()
   for r in neigh[s]:
    if assigned[r]>=0: continue
    masks=forb.get((r,s));
    if masks is None: continue
    old=dom[r]; new=old
    # remove values incompatible with assigned value of s
    bit=1<<val
    for i in range(len(rows[r])):
     if (old>>i)&1 and (masks[i]&bit): new &= ~(1<<i)
    if new!=old:
     trail.append((r,old)); dom[r]=new
     if new==0: return False
     if new & (new-1)==0:
      vv=(new.bit_length()-1); assigned[r]=vv; trail.append(('a',r)); queue.append((r,vv))
  return True
 def rec(depth=0):
  nonlocal nodes
  if time.time()-t0>limit: raise TimeoutError
  nodes+=1
  if nodes%100000==0: print('nodes',nodes,'depth',depth,'unass',sum(a<0 for a in assigned),'time',round(time.time()-t0,1), flush=True)
  if all(a>=0 for a in assigned): return True
  # choose unassigned min domain then max degree
  r=min((i for i,a in enumerate(assigned) if a<0), key=lambda i:(dom[i].bit_count(), -len(neigh[i])))
  vals=[i for i in range(len(rows[r])) if (dom[r]>>i)&1]
  # least constraining
  vals.sort(key=lambda v: sum((forb.get((s,r), [0]*len(rows[s]))[j]>>v)&1 for s in neigh[r] if assigned[s]<0 for j in range(len(rows[s])) if (dom[s]>>j)&1))
  for v in vals:
   trail=[]; old=dom[r]; trail.append((r,old)); dom[r]=1<<v; assigned[r]=v; trail.append(('a',r))
   if propagate([(r,v)], trail):
    if rec(depth+1): return True
   for item in reversed(trail):
    if item[0]=='a': assigned[item[1]]=-1
    else: dom[item[0]]=item[1]
  return False
 try:
  res=rec()
  print(path.split('/')[-1], 'res',res,'nodes',nodes,'time',round(time.time()-t0,2))
 except TimeoutError:
  print(path.split('/')[-1], 'timeout','nodes',nodes,'time',round(time.time()-t0,2))
if __name__=='__main__': solve(sys.argv[1], float(sys.argv[2]) if len(sys.argv)>2 else 60)
