def test_env_delay(): tmp = environment.aig | atom('latch').aig env_delay = tmp.feedback(inputs=atom('latch').aig.inputs, outputs=[environment.output], initials=[False], keep_outputs=False) assert not Game(env_delay).is_realizable()
def test_system_delay(): tmp = system.aig | atom('latch').aig system_delay = tmp.feedback(inputs=atom('latch').aig.inputs, outputs=[system.output], initials=[False], keep_outputs=False) assert Game(system_delay).is_realizable()
def to_expression(token_sequence): if isinstance(token_sequence, list): token_sequence = iter(pre_order(token_sequence)) elem = next(token_sequence, None) if elem is None: raise ValueError('Sequence ends before expression is complete.') if elem in variables: return aiger.atom(elem) if elem in bool_constants: return aiger.atom(elem == 'True') if elem in unary_operators: assert elem == 'neg' return ~to_expression(token_sequence) assert elem in binary_operators, 'Unknown op: %s' % elem left = to_expression(token_sequence) right = to_expression(token_sequence) if elem == 'or': return left | right if elem == 'and': return left & right if elem == 'xor': return left ^ right if elem == 'eq': return left == right raise ValueError('Should not reach this point')
def test_force_true(): expr = aiger.atom('x') | aiger.atom('y') cnf1 = aig2cnf(expr, force_true=True) cnf2 = aig2cnf(expr, force_true=False) assert set(cnf1.clauses) > set(cnf2.clauses) assert len(cnf1.clauses) == len(cnf2.clauses) + 1
def test_fresh(): expr = aiger.atom('x') | aiger.atom('y') count = -1 def fresh(_): nonlocal count count -= 1 return count cnf = aig2cnf(expr, fresh=fresh) assert all(x < 1 for x in cnf.output2lit.values())
def from_bdd(node, manager=None): if manager is None: manager = node.bdd name = node.var if name is None: # Must be a leaf True xor False node. return aiger.atom(node == manager.true) test = aiger.atom(name) low, high = [from_bdd(c, manager) for c in (node.low, node.high)] expr = aiger.ite(test, high, low) return ~expr if node.negated else expr
def since_monitor(left, right): tmp = aiger.common._fresh() latch = aiger.common._fresh() left, right = aiger.atom(left), aiger.atom(right) active = aiger.atom(tmp) update = active.implies(left | right) & (~active).implies(right) circ = update.aig['o', {update.output: tmp}] return circ.loopback({ 'input': tmp, 'output': tmp, 'latch': latch, 'init': False })
def is_realizable(self, use_cegar=False, verbose=False): assert len(self.aig.outputs) is 1 initial_state = {x: val for (x, val) in self.aig.latch2init} bad = BoolExpr(aiger.sink(self.aig.latches) | atom(False).aig) transition_relation = \ _cutlatches_and_rename(self.aig) >> \ aiger.bit_flipper(inputs=self.aig.outputs) for i in itertools.count(): # to infinity and beyond print(f'Iteration {i+1}') tmp = transition_relation >> (~bad).aig # do not go to a bad state miter1 = BoolExpr(tmp >> aiger.and_gate(tmp.outputs)) miter2 = eliminate(miter1, self.system, verbose=verbose) next_bad = bad | eliminate( ~miter2, self.environment, verbose=verbose) # delete comments to avoid them accumulate next_bad = BoolExpr(next_bad.aig.evolve(comments=())) if next_bad(inputs=initial_state): print('Unrealizable') return False print('Fixed point check') if is_equal(bad, next_bad): print('Realizable') return True bad = next_bad
def kmodels(wordlen: int, k: int, input=None, output=None): """Return a circuit taking a wordlen bitvector where only k valuations return True. Uses encoding from [1]. Note that this is equivalent to (~x < k). - TODO: Add automated simplification so that the circuits are equiv. [1]: Chakraborty, Supratik, et al. "From Weighted to Unweighted Model Counting." IJCAI. 2015. """ assert 0 <= k < 2**wordlen if output is None: output = _fresh() if input is None: input = _fresh() imap, omap = BundleMap({input: wordlen}), BundleMap({output: 1}) atoms = map(aiger.atom, imap[input]) active = False expr = aiger.atom(False) for atom, bit in zip(atoms, encode_int(wordlen, k, signed=False)): active |= bit if not active: # Skip until first 1. continue expr = (expr | atom) if bit else (expr & atom) aig = expr.aig['o', {expr.output: omap[output][0]}] aig |= aiger.sink(imap[input]) return aigbv.AIGBV(imap=imap, omap=omap, aig=aig)
def test_latch_initialization_true(): latch = atom('latch').aig game_true = latch.feedback(inputs=latch.inputs, outputs=latch.outputs, initials=[True], keep_outputs=True) assert not Game(game_true).is_realizable()
def kmodels(wordlen: int, k: int, input=None, output=None): """Return a circuit taking a wordlen bitvector where only k valuations return True. Uses encoding from [1]. Note that this is equivalent to (~x < k). - TODO: Add automated simplification so that the circuits are equiv. [1]: Chakraborty, Supratik, et al. "From Weighted to Unweighted Model Counting." IJCAI. 2015. """ assert 0 <= k < 2**wordlen if output is None: output = _fresh() if input is None: input = _fresh() input_names = named_indexes(wordlen, input) atoms = map(aiger.atom, input_names) active = False expr = aiger.atom(False) for atom, bit in zip(atoms, encode_int(wordlen, k, signed=False)): active |= bit if not active: # Skip until first 1. continue expr = (expr | atom) if bit else (expr & atom) return aigbv.AIGBV( aig=expr.aig, input_map=frozenset([(input, tuple(input_names))]), output_map=frozenset([(output, (expr.output, ))]), )
def test_latch_initialization_false(): latch = atom('latch').aig game_false = latch.feedback(inputs=latch.inputs, outputs=latch.outputs, initials=[False], keep_outputs=True) print(game_false) assert Game(game_false).is_realizable()
def getCombExpr(g, node): nodeName = node.getName() Util.amirrosDebug('getCombExpr - nodeName = {}'.format(nodeName), GraphSplitter.printDebug) if re.search("^Input_", nodeName): if g.isInput(nodeName): atomName = nodeName.replace("Input_", "") return aiger.atom(atomName) else: fanin = g.fanin(node) if len(fanin) != 1: print( 'ERROR: unknown node type. nodeName = {} with unknown fanin len = {}' .format(nodeName, len(fanin))) exit() child = fanin[0] return GraphSplitter.getCombExpr(g, child) elif re.search("^ConstFalse_", nodeName): return aiger.atom(nodeName) & False elif re.search("^LatchIn_", nodeName): atomName = nodeName + "_CI" return aiger.atom(atomName) elif re.search("^Inverter_", nodeName): invFanIn = g.fanin(node) child = invFanIn[0] return ~GraphSplitter.getCombExpr(g, child) elif re.search("^AndGate_", nodeName): andFanIn = g.fanin(node) a = andFanIn[0] b = andFanIn[1] return GraphSplitter.getCombExpr(g, a) & GraphSplitter.getCombExpr( g, b) else: fanin = g.fanin(node) if len(fanin) != 1: print( 'ERROR: unknown node type. nodeName = {} with unknown fanin len = {}' .format(nodeName, len(fanin))) exit() child = fanin[0] return GraphSplitter.getCombExpr(g, child)
def test_to_aig(): x = aiger.atom('x') c1 = aiger.to_aig(x) c2 = aiger.to_aig(c1) c3 = aiger.to_aig(str(c2)) with tempfile.TemporaryDirectory() as d: path = pathlib.Path(d) / "foo.aag" c3.write(path) c4 = aiger.to_aig(path) for c in [c1, c2, c3, c4]: assert isinstance(c1, aiger.AIG) assert isinstance(c2, aiger.AIG) assert isinstance(c3, aiger.AIG) assert isinstance(c4, aiger.AIG)
def unsigned_lt_gate(wordlen, left, right, output): omap = BundleMap({output: 1}) imap = BundleMap({left: wordlen, right: wordlen}) lefts = map(aiger.atom, imap[left]) rights = map(aiger.atom, imap[right]) def test_bit(expr, lr): l, r = lr expr &= ~(l ^ r) # l == r. expr |= ~l & r # l < r. return expr expr = reduce(test_bit, zip(lefts, rights), aiger.atom(False)) aig = expr.aig['o', {expr.output: omap[output][0]}] return aigbv.AIGBV(imap=imap, omap=omap, aig=aig)
def unsigned_lt_gate(wordlen, left, right, output): left_names = named_indexes(wordlen, left) right_names = named_indexes(wordlen, right) lefts = map(aiger.atom, left_names) rights = map(aiger.atom, right_names) def test_bit(expr, lr): l, r = lr expr &= ~(l ^ r) # l == r. expr |= ~l & r # l < r. return expr expr = reduce(test_bit, zip(lefts, rights), aiger.atom(False)) return aigbv.AIGBV( aig=expr.aig, input_map=frozenset([(left, left_names), (right, right_names)]), output_map=frozenset([(output, (expr.output, ))]), )
def test_is_valid(): assert aiger_sat.is_valid(aiger.atom(True))
import aiger_analysis as aa from aiger import atom x, y = atom('x'), atom('y') expr = x & y | y & atom(True) def test_abc(): assert aa.is_equal(expr, aa.simplify(expr))
def get_model_test(): testformula = aiger.atom('x') | ~aiger.atom('x') testformulamodel = get_model(testformula) assert len(testformulamodel) == 1, testformulamodel
def character(subset): if len(subset) == 0: return aiger.atom(False) return aiger.BoolExpr(aiger.parity_gate(subset))
def visit_id(self, node, _): return aiger.atom(node.text)
from aiger import atom from aiger_analysis.safety_game import Game def test_true(): assert not Game(atom(True).aig).is_realizable() def test_false(): assert Game(atom(False).aig).is_realizable() system, environment = atom('controllable_variable'), atom('env') def test_system(): assert Game(system.aig).is_realizable() assert Game((~system).aig).is_realizable() def test_env(): assert not Game(environment.aig).is_realizable() assert not Game((~environment).aig).is_realizable() def test_latch_initialization_true(): latch = atom('latch').aig game_true = latch.feedback(inputs=latch.inputs, outputs=latch.outputs, initials=[True], keep_outputs=True)
def test_to_expression_drops_surplus_tokens(): # This is not necessarily desired behavior and should be changed eventually. testexpr = generator.to_expression(iter(['var01', 'var00', 'var02'])) assert aiger_sat.are_equiv(testexpr, aiger.atom('var01'))
def variance(expr): return sum(fn.drop(1, weights(expr))) def covariance(expr1, expr2): c1 = fn.pluck(1, coeffs(expr1)) c2 = fn.pluck(1, coeffs(expr2)) return sum(x * y for x, y in fn.drop(1, zip(c1, c2))) def spectral_sample(expr): pass def convolve(expr1, expr2): pass if __name__ == '__main__': x = aiger.atom('x') y = aiger.atom('y') expr = x.implies(y) & x print(list(coeffs(expr))) print(list(weights(expr))) print(sum(weights(expr))) print(mean(expr)) print(variance(expr)) print(covariance(expr, x ^ y))
def to_expression_test(): testexpr = generator.to_expression(iter(['and', 'var00', 'var02'])) assert aiger_sat.are_equiv(testexpr, aiger.atom('var00') & aiger.atom('var02'))
def test_false(): assert Game(atom(False).aig).is_realizable()
def minimized_model_test(): testformula = aiger.atom('x') | ~aiger.atom('x') testformulamodel = get_model(testformula) minimized_testformulamodel = minimize_model(testformula, testformulamodel) assert len(minimized_testformulamodel) == 0, minimized_testformulamodel
def test_elim2(): assert aa.is_equal(atom(True), aa.eliminate(x, ['x']))
def test_true(): assert not Game(atom(True).aig).is_realizable()
def visit_const(self, node, _): return aiger.atom(node.text == "TRUE")