def is_equal(e1, e2): if isinstance(e1, aiger.AIG): assert len(e1.outputs) is 1 e1 = aiger.BoolExpr(e1) if isinstance(e2, aiger.AIG): assert len(e2.outputs) is 1 e2 = aiger.BoolExpr(e2) return is_valid(e1 == e2)
def bmc_equiv(circ1, circ2, horizon, assume=None) -> Iterator[bool]: """ Perform bounded model checking up to horizon to see if circ1 and circ2 are equivilent. """ # Create distinguishing predicate. expr = BV.uatom(1, val=0) for o1 in circ1.outputs: o2 = f'{o1}##copy' size = circ1.omap[o1].size expr |= BV.uatom(size, o1) != BV.uatom(size, o2) expr.with_output('distinguished') monitor = ((circ1 | circ2) >> expr.aigbv).aig assert len(monitor.outputs) == 1 # Make underlying aig lazy. monitor = monitor.lazy_aig # BMC loop for t in range(horizon): delta = horizon - t unrolled = monitor.unroll(delta, only_last_outputs=True) assert len(unrolled.outputs) == 1 unrolled = aiger.BoolExpr(unrolled) if assume is not None: unrolled |= assume yield aiger_sat.is_sat(unrolled)
def eliminate(e, variables, verbose=False): result_aig = _call_cadet(cmn.extract_aig(e), variables, projection=True, verbose=verbose) if type(e) is aiger.BoolExpr: return aiger.BoolExpr(result_aig) return result_aig
def add_expr(self, expr): expr = aiger.BoolExpr(expr.aig) self.unsolved = True self.inputs |= expr.inputs cnf = aig2cnf(expr, fresh=self._id_pool) for clause in cnf.clauses: self.solver.add_clause(clause) self.sym_table.update(cnf.input2lit)
def test_aig2cnf(circ, data): expr1 = aiger.BoolExpr(circ.unroll(1)) cnf = aig2cnf(expr1) g = Glucose3() for c in cnf.clauses: g.add_clause(c) test_input = {i: data.draw(st.booleans()) for i in expr1.inputs} assumptions = [] for name, val in test_input.items(): if name not in cnf.input2lit: continue sym = cnf.input2lit[name] if not val: sym *= -1 assumptions.append(sym) assert expr1(test_input) == g.solve(assumptions=assumptions)
def to_bdd(circ_or_expr, output=None, manager=None, renamer=None, levels=None): if renamer is None: _count = 0 def renamer(*_): nonlocal _count _count += 1 return f"x{_count}" if not isinstance(circ_or_expr, aiger.BoolExpr): circ = aiger.to_aig(circ_or_expr, allow_lazy=True) assert len(circ.latches) == 0 if output is None: assert len(circ.outputs) == 1 output = fn.first(circ.outputs) expr = aiger.BoolExpr(circ) else: expr = circ_or_expr manager = BDD() if manager is None else manager input_refs_to_var = { ref: renamer(i, ref) for i, ref in enumerate(expr.inputs) } manager.declare(*input_refs_to_var.values()) if levels is not None: assert set(manager.vars.keys()) <= set(levels.keys()) levels = fn.project(levels, manager.vars.keys()) levels = fn.walk_keys(input_refs_to_var.get, levels) manager.reorder(levels) manager.configure(reordering=False) def lift(obj): if isinstance(obj, bool): return manager.true if obj else manager.false return obj inputs = {i: manager.var(input_refs_to_var[i]) for i in expr.inputs} out = expr(inputs, lift=lift) return out, out.bdd, bidict(input_refs_to_var)
def is_true_QBF(e, quantifiers): quantifiers = simplify_quantifier_prefix(quantifiers) aig = cmn.extract_aig(e) assert sum(map(len, fn.pluck(1, quantifiers))) == len(aig.inputs) if len(quantifiers) is 1: # solve with SAT if quantifiers[0][0] is 'a': return is_valid(aig) else: assert quantifiers[0][0] is 'e' return is_satisfiable(aig) elif len(quantifiers) is 2: # 2QBF true_return_code = CadetCodes.QBF_IS_TRUE.value if quantifiers[-1][0] is 'a': e = ~aiger.BoolExpr(aig) aig = e.aig true_return_code = CadetCodes.QBF_IS_FALSE.value return _call_cadet(aig, quantifiers[1][1]) == true_return_code else: raise NotImplementedError('Cannot handle general QBF at the moment')
def are_equiv(expr1, expr2, *, engine=Glucose4): # Make sure they're expressions. assert len(expr1.aig.outputs) == len(expr2.aig.outputs) == 1 expr1, expr2 = map(lambda e: aiger.BoolExpr(e.aig), (expr1, expr2)) return is_valid(expr1 == expr2)
def is_valid(e): e = ~aiger.BoolExpr(cmn.extract_aig(e)) return not is_satisfiable(e)
def character(subset): if len(subset) == 0: return aiger.atom(False) return aiger.BoolExpr(aiger.parity_gate(subset))
fullAig = andAig | PI1.aig | PI2.aig fullAig = fullAig.feedback(['CI1'], ['PI1']) fullAig = fullAig.feedback(['CI2'], ['PI2']) #fullAig = andAig #print(fullAig.loopback({"input": "b", "output": "a","init":True})) print(fullAig) exit() in1, out1 = aiger.atoms('in1', 'out1') in2, in3 = aiger.atoms('in2', 'in3') expr1 = out1.with_output('out1') expr2 = in2 & in3 aig1 = in1.aig | expr1.aig aig2 = aig1.feedback(['in1'], ['out1']) aig3 = aig2 | expr2.aig expr4 = aiger.BoolExpr(aig3) in4, in5 = aiger.atoms('in4', 'in5') expr5 = in4 & expr4 print(expr5.aig) exit() outAtom = GraphSplitter.graphToAig(g, o) print(outAtom) exit() w, x, y, z, o = aiger.atoms('w', 'x', 'y', 'z', 'o') expr1 = x & y expr2 = expr1.with_output('and1') expr3 = z & w expr4 = expr3.with_output('and2') aig1 = expr2.aig | expr4.aig