def test(): #for arg in argv[1:]: # inputs, outputs, node_map = readbench.readBench(arg) a = ckt.InputNode('a') b = ckt.InputNode('b') c = ckt.InputNode('c') f = a & b & c g = (a & b) | (~a & ~b) unates = getUnateNodes([f, g]) for u in unates: print(u)
def getUnateNodes(outputs): S = Solver() supports = set() gates = set() for o in outputs: supports = supports.union(o.support()) gates = gates.union(o.transitiveFaninCone()) # topo sort. ckt.computeLevels(gates) def newVar(n): return S.newVar() cnf = [] nmap1 = {} nmap2 = {} cnf += adapter.gateSetToCNF(gates, nmap1, newVar) cnf += adapter.gateSetToCNF(gates, nmap2, newVar) iMap = {} for inp in supports: i1 = ckt.InputNode(inp.name + "__1") i2 = ckt.InputNode(inp.name + "__2") iEq = ckt.XnorGate(i1, i2) nmap = {i1: nmap1[inp], i2: nmap2[inp]} cnf += adapter.circuitToCNF(iEq, nmap, newVar) iMap[inp] = (nmap[i1], nmap[i2], nmap[iEq]) for c in cnf: S.addClause(*c) unates = set() for gate in gates: if gate.is_input(): continue f0 = nmap1[gate] f1 = nmap2[gate] unate = True for i in supports: c1 = checkUnate(S, i, f0, f1, iMap, 0) c2 = checkUnate(S, i, f0, f1, iMap, 1) if not c1 and not c2: unate = False break if unate: unates.add(gate) return unates
def isonecounter_v1(eq, ps, k): subs = {pi: ckt.InputNode(pi.name + '_') for pi in ps} eqp = eq.subst(subs) ds = [(pi ^ subs[pi]) for pi in ps] eqHD = hd(ds, 2 * k) y = ckt.AndGate(eq, eqp, eqHD) inps = [(pi, subs[pi]) for pi in ps] S = Solver() nmap = {} clauses = adapter.circuitToCNF(y, nmap, lambda n: S.newVar()) for pi, qi in inps: S.freeze(nmap[pi]) S.freeze(nmap[qi]) for c in clauses: S.addClause(*c) l = nmap[y] S.addClause(l) r = S.solve() if not r: return False, None # gather all the input values. ms, ns = [], [] for pi, qi in inps: ai, bi = nmap[pi], nmap[qi] mi = int(S.modelValue(ai)) ni = int(S.modelValue(bi)) ms.append(mi) ns.append(ni) # assert the obvious ones. key = {} for ((pi, qi), mi, ni) in itertools.izip(inps, ms, ns): ai, bi = nmap[pi], nmap[qi] if mi == ni: key[pi] = mi #S.addClause(valToLit(key[pi], ai)) #S.addClause(valToLit(key[pi], bi)) # now handle the rest. assumps = [] for ((pi, qi), mi, ni) in itertools.izip(inps, ms, ns): ai, bi = nmap[pi], nmap[qi] if mi != ni: r1 = S.solve(valToLit(mi, ai), valToLit(mi, bi)) r2 = S.solve(valToLit(ni, ai), valToLit(ni, bi)) if r1 == True and r2 == False: key[pi] = mi elif r1 == False and r2 == True: key[pi] = ni else: return False, None #S.addClause(valToLit(key[pi], ai)) #S.addClause(valToLit(key[pi], bi)) ks = [key[pi] for pi in ps] return True, ks
def readFileObject(fobj): "Reads a bench file and returns the tuple (inps, outs, node_map)." fanins = {} node_map = {} output_names = [] inputs = [] for l in fobj.readlines(): f = [] l = l.strip() if len(l) == 0 or l.startswith('#'): continue if 'INPUT(' in l: name = l.replace("INPUT(", "").replace(")", "") node = ckt.InputNode(name) node_map[name] = node inputs.append(node) elif 'OUTPUT(' in l: name = l.replace("OUTPUT(", "").replace(")", "") output_names.append(name) elif '=' in l: parts = [p.strip() for p in l.split('=')] assert len(parts) == 2 gate_name = parts[0] rhs = parts[1] if rhs == 'VDD': node_map[gate_name] = ckt.Const1Node() else: gate_type = rhs[:rhs.find('(')] within_bracket = rhs[rhs.find('(')+1:rhs.find(')')] fanin_names = [p.strip() for p in within_bracket.split(',')] fanins = [node_map[fn] for fn in fanin_names] if gate_type == 'AND': g = ckt.AndGate(*fanins) elif gate_type == 'OR': g = ckt.OrGate(*fanins) elif gate_type == 'NOT': g = ckt.NotGate(*fanins) elif gate_type == 'XOR': g = ckt.XorGate(*fanins) elif gate_type == 'XNOR': g = ckt.XnorGate(*fanins) elif gate_type == 'NAND': g = ckt.NandGate(*fanins) elif gate_type == 'NOR': g = ckt.NorGate(*fanins) elif gate_type == 'BUF' or gate_type == 'BUFF': g = ckt.BufGate(*fanins) else: assert False, gate_type node_map[gate_name] = g g.name = gate_name else: assert False, l outputs = [] for out_name in output_names: output = node_map[out_name] output.name = out_name outputs.append(output) return inputs, outputs, node_map
def test(k, h): sys.setrecursionlimit(8192) ps = [ckt.InputNode('p%d' % i) for i in range(k)] fs = [random.randint(1, 1) for i in range(len(ps))] ys = [~pi if fi else pi for (fi, pi) in itertools.izip(fs, ps)] eq = hd(ys, h) r, ks = isonecounter(eq, ps, h, None) if r: print('fs:', fs) print('ks:', ks) assert fs == ks else: print('TROUBLE!')
def test(): xs = [ckt.InputNode('x%d' % i) for i in range(32)] ys = onecount(xs) eq4 = ckt.AndGate(~ys[0], ~ys[1], ys[2], ~ys[3]) print(len(eq4)) return S = Solver() nmap = {} clauses = circuitToCNF(eq4, nmap, lambda n: S.newVar()) for c in clauses: S.addClause(*c) tt = [] while S.solve(): blockingClause = [] row = [] for xi in itertools.chain(reversed(xs)): li = nmap[xi] vi = S.modelValue(li) row.append(vi) if vi: blockingClause.append(-li) else: blockingClause.append(li) num_ones = sum(row) li = nmap[eq4] vi = S.modelValue(li) row.append(vi) tt.append(row) S.addClause(*blockingClause) assert (num_ones == 4) == vi tt.sort() for row in tt: def listToString(l): return ''.join(str(int(i)) for i in l) p1 = listToString(row[:len(xs)]) p2 = listToString(row[len(xs):]) print('%s | %s ' % (p1, p2))
def isonecounter_v4(eq, ps, k, log): subs = {pi: ckt.InputNode(pi.name + '_') for pi in ps} id_map = {pi: pi for pi in ps} S = Solver() nmap = {} for idx, xi in enumerate(ps): for xj in ps[idx + 1:]: new_map = id_map.copy() new_map[xi] = subs[xi] eq1 = eq.subst(new_map) new_map.pop(xi) new_map1 = new_map.copy() new_map1[subst[xi]] = subst[xi] new_map1[xj] = xi eq2 = eq1.subst(new_map1) new_map2.pop(xj) new_map2 = new_map1.copy() new_map2[xi] = xi new_map2[subst[xi]] = xj eq3 = eq2.subst(new_map2) or1 = eq3 ^ eq
def isonecounter_v3(eq, ps, k, log): subs = {pi: ckt.InputNode(pi.name + '_') for pi in ps} eqp = eq.subst(subs) ds = [(pi ^ subs[pi]) for pi in ps] eqHD = hd(ds, 2 * k) y = ckt.AndGate(eq, eqp, eqHD) inps = [(pi, subs[pi]) for pi in ps] S = Solver() nmap = {} clauses = adapter.circuitToCNF(y, nmap, lambda n: S.newVar()) # freeze literals for pi, qi in inps: S.freeze(nmap[pi]) S.freeze(nmap[qi]) for di in ds: S.freeze(nmap[di]) # add clauses. for c in clauses: S.addClause(*c) l = nmap[y] S.addClause(l) r = S.solve() if not r: return False, None # gather the first round of keys. assumps = [] key = {} for ((pi, qi), di) in itertools.izip(inps, ds): ai, bi = nmap[pi], nmap[qi] mi = int(S.modelValue(ai)) ni = int(S.modelValue(bi)) if mi == ni: key[pi] = mi else: li = nmap[di] assumps.append(-li) r = S.solve(*assumps) if not r: return False, None # and now the second round of keys. for ((pi, qi), di) in itertools.izip(inps, ds): ai, bi = nmap[pi], nmap[qi] mi = int(S.modelValue(ai)) ni = int(S.modelValue(bi)) if mi == ni: key[pi] = mi ks = [key[pi] for pi in ps] if log: pkl.dump(eq, log) pkl.dump(ps, log) pkl.dump(ks, log) log.flush() #log.close() if checkKey(eq, ps, ks, k): return True, ks else: return False, None
def isonecounter_v2(eq, ps, k): S = Solver() subs = {pi: ckt.InputNode(pi.name + '_') for pi in ps} eqp = eq.subst(subs) y = ckt.AndGate(eq, eqp) inps = [(pi, subs[pi]) for pi in ps] ds = [(pi ^ subs[pi]) for pi in ps] nmap = {} ckt_clauses = adapter.circuitToCNF(y, nmap, lambda n: S.newVar()) for di in ds: ckt_clauses += adapter.circuitToCNF(di, nmap, lambda n: S.newVar()) zeros = [] dlits = [nmap[di] for di in ds] while not isPowOf2(len(dlits)): zi = S.newVar() dlits.append(zi) zeros.append(zi) (snw_clauses, es) = sortNetwork(TWO_COMP_EQ, dlits, lambda: S.newVar()) for pi, qi in inps: S.freeze(nmap[pi]) S.freeze(nmap[qi]) for c in zeros: S.addClause(-c) for c in itertools.chain(ckt_clauses, snw_clauses): S.addClause(*c) l = nmap[y] S.addClause(l) for i, ei in enumerate(es): if i < 2 * k: S.addClause(ei) else: S.addClause(-ei) r = S.solve() if not r: return False, None # gather all the input values. ms, ns = [], [] for pi, qi in inps: ai, bi = nmap[pi], nmap[qi] mi = int(S.modelValue(ai)) ni = int(S.modelValue(bi)) ms.append(mi) ns.append(ni) # assert the obvious ones. key = {} for ((pi, qi), mi, ni) in itertools.izip(inps, ms, ns): ai, bi = nmap[pi], nmap[qi] if mi == ni: key[pi] = mi #S.addClause(valToLit(key[pi], ai)) #S.addClause(valToLit(key[pi], bi)) # now handle the rest. assumps = [] for ((pi, qi), mi, ni) in itertools.izip(inps, ms, ns): ai, bi = nmap[pi], nmap[qi] if mi != ni: r1 = S.solve(valToLit(mi, ai), valToLit(mi, bi)) r2 = S.solve(valToLit(ni, ai), valToLit(ni, bi)) if r1 == True and r2 == False: key[pi] = mi elif r1 == False and r2 == True: key[pi] = ni else: return False, None #S.addClause(valToLit(key[pi], ai)) #S.addClause(valToLit(key[pi], bi)) ks = [key[pi] for pi in ps] return True, ks