Example #1
0
    def unroll(self,
               horizon,
               *,
               init=True,
               omit_latches=True,
               only_last_outputs=False):
        hist_valid = LTL.atom(self.valid_id) \
                        .historically() \
                        .with_output(self.valid_id)
        monitor = BV.aig2aigbv(hist_valid.aig)

        circ = (self.circ >> monitor).unroll(
            horizon,
            init=init,
            omit_latches=omit_latches,
            only_last_outputs=only_last_outputs)

        if not only_last_outputs:
            times = range(1, horizon)
            circ >>= BV.sink(1, (f'{self.valid_id}##time_{t}' for t in times))
        valid_id = f'{self.valid_id}##time_{horizon}'
        assert valid_id in circ.outputs

        input_encodings = timed_encodings(self.input_encodings, circ.inputs)
        output_encodings = timed_encodings(self.output_encodings, circ.outputs)
        return from_aigbv(
            circ=circ,
            input_encodings=input_encodings,
            output_encodings=output_encodings,
            valid_id=valid_id,
        )
Example #2
0
def test_never_false_redemption():
    spec = LTL.atom('x').historically()
    monitor = BV.aig2aigbv(spec.aig)
    assert len(monitor.latches) == 1
    monitor = monitor['l', {fn.first(monitor.latches): 'z'}]

    # Environment can save you.
    x, y = BV.uatom(1, 'x'), BV.uatom(1, 'y')
    xy = (x | y).with_output('x')  # env y can override x.


    dyn = C.pcirc(xy.aigbv) \
           .randomize({'y': {0: 0.75, 1: 0.25}})

    horizon = 3
    model = from_pcirc(dyn, monitor, steps=horizon)

    coeff = np.log(2)  # Special coeff to make LSE visit powers of 2.
    actor = improviser(model, coeff)

    v8 = coeff
    v7 = 0
    v6 = coeff / 4
    v5 = np.logaddexp(v6, coeff)
    v4 = (np.log(8) + v5) / 4
    v3 = np.logaddexp(v4, v5)
    v2 = (3 * np.log(4) + v3) / 4
    v1 = np.logaddexp(v2, v3)

    expected = sorted([v8, v7, v6, v5, v4, v3, v2, v1])
    expected = fn.lmap(pytest.approx, expected)

    vals = sorted(list(actor.node2val.values()))
    assert all(x == y for x, y in zip(vals, expected))

    def lprob(elems):
        return actor.prob(elems, log=True)

    assert lprob([]) == 0
    assert lprob([1]) == pytest.approx(v3 - v1)

    for prefix in [[1], [1, 0, 1], [1, 1, 1], [1, 1, 1, 1, 1]]:
        for bit in [0, 1]:
            expected = pytest.approx(-np.log(4) + bit * np.log(3))
        assert lprob(prefix + [bit]) - lprob(prefix) == expected

    ctrl = actor.policy()
    example = []
    for env in [None, 0, 0]:
        example.append(ctrl.send(env))
    assert -float('inf') < lprob(example)

    ctrl = actor.policy(observe_states=True)
    example = []
    for env in [None, ({'x': 1}, None), ({'x': 1}, None)]:
        example.append(ctrl.send(env))
    assert -float('inf') < lprob(example)
def sys3():
    mdp = sys1()
    mdp |= C.circ2mdp(BV.tee(1, {'c': ['c', 'c_next']}))
    coin = (~C.coin((1, 2), name='c')).with_output('c')
    mdp <<= coin

    delay = BV.aig2aigbv(aiger.delay(['c'], [True]))
    delay = C.circ2mdp(delay)

    return mdp >> delay
Example #4
0
def test_never_false():
    spec = LTL.atom('x').historically()
    monitor = BV.aig2aigbv(spec.aig)
    dyn = C.pcirc(BV.identity_gate(1, 'x'))

    horizon = 3
    model = from_pcirc(dyn, monitor, steps=horizon)
    graph = model.graph()
    assert len(graph.nodes) == horizon + 2
    assert len(graph.edges) == 2 * horizon
Example #5
0
def test_preimage():
    spec, mdp = scenario_reactive()

    sys1 = mdp.aigbv >> BV.sink(1, ['c_next', '##valid'])
    sys2 = sys1 >> BV.aig2aigbv(spec.aig)

    def act(action, coin):
        return {'a': (action, ), 'c': (coin, )}

    actions = [act(True, True), act(True, False), act(True, True)]
    observations = fn.lpluck(0, sys1.simulate(actions))

    expr = preimage(observations, sys1)
    assert expr.inputs == {
        'c##time_0',
        'c##time_1',
        'c##time_2',
        'a##time_0',
        'a##time_1',
        'a##time_2',
    }

    bexpr1, manager, order = to_bdd2(sys2, horizon=3)

    def accepts(bexpr, actions):
        """Check if bexpr accepts action sequence."""
        timed_actions = {}
        for t, action in enumerate(actions):
            c, a = action['c'], action['a']
            timed_actions.update({
                f'c##time_{t}[0]': c[0],
                f'a##time_{t}[0]': a[0]
            })

        assert timed_actions.keys() == manager.vars.keys()
        tmp = manager.let(timed_actions, bexpr)
        assert tmp in (manager.true, manager.false)
        return tmp == manager.true

    assert not accepts(bexpr1, actions)

    bexpr2, _, input2var = aiger_bdd.to_bdd(expr,
                                            manager=manager,
                                            renamer=lambda _, x: x)

    assert accepts(bexpr2, actions)
    assert not accepts(~bexpr2, actions)

    bexpr3 = xor(bexpr1, bexpr2)

    assert accepts(bexpr3, actions)
Example #6
0
def test_never_false_redemption():
    spec = LTL.atom('x').historically()
    monitor = BV.aig2aigbv(spec.aig)

    # Environment can save you.
    x, y = BV.uatom(1, 'x'), BV.uatom(1, 'y')
    xy = (x | y).with_output('x')  # env y can override x.

    dyn = C.pcirc(xy.aigbv) \
           .randomize({'y': {0: 0.4, 1: 0.6}})

    horizon = 3
    model = from_pcirc(dyn, monitor, steps=horizon)
    graph = model.graph()
    assert len(graph.nodes) == 2 * horizon + 2
    assert len(graph.edges) == 4 * horizon
Example #7
0
def test_smoke():
    spec = PLTL.atom('a').historically()
    spec = BV.aig2aigbv(spec.aig)
    spec = C.circ2mdp(spec)
    spec <<= C.coin((1, 8), name='c')
    spec >>= C.circ2mdp(BV.sink(1, ['c']))  # HACK

    bdd, manager, order = to_bdd2(spec, horizon=3)

    assert bdd.dag_size == 4

    for i in range(order.total_bits*order.horizon):
        t = order.time_step(i)
        var = manager.var_at_level(i)
        action, t2, _ = TIMED_INPUT_MATCHER.match(var).groups()
        assert t == int(t2)
        decision = action in spec.inputs
        assert decision == order.is_decision(i)
Example #8
0
def test_find_env_input():
    x, c = map(aiger_ptltl.atom, ('x', 'c'))

    sys = (x & c).historically().aig
    sys = circ2mdp(aiger_bv.aig2aigbv(sys))
    sys <<= coin((1, 2), name='c')

    assert sys.inputs == {'x'}
    assert len(sys.outputs) == 1

    out, *_ = sys.outputs

    start = end = sys.aigbv.latch2init
    action = {'x': (True, )}
    coins = sys.find_env_input(start, action, end)

    _, lmap = sys.aigbv(inputs={**action, **coins})
    assert lmap == end
Example #9
0
def test_find_coin_flips():
    x, c = map(aiger_ptltl.atom, ('x', 'c'))

    sys = (x & c).historically().aig
    sys = circ2mdp(aiger_bv.aig2aigbv(sys))
    sys <<= coin((1, 2), name='c')

    assert sys.inputs == {'x'}
    assert len(sys.outputs) == 1

    out, *_ = sys.outputs
    sys_actions = 3 * [{'x': (True, )}]
    states = 3 * [{out: (True, )}]

    actions = sys.encode_trc(sys_actions, states)
    assert not any(v['c'][0] for v in actions)

    sys_actions2, states2 = sys.decode_trc(actions)
    assert sys_actions2 == sys_actions
    assert states2 == states
Example #10
0
def concretize(
        monitor, sys: C.MDP, horizon: int, manager=None
) -> ConcreteSpec:
    """
    Convert an abstract specification monitor and a i/o transition
    system into a concrete specification over the horizion.
    """
    # Make format correct.
    if not isinstance(monitor, C.MDP):
        assert hasattr(monitor, 'aig') or hasattr(monitor, 'aigbv')
        if hasattr(monitor, 'aigbv'):
            monitor = monitor.aigbv
        else:
            monitor = BV.aig2aigbv(monitor.aig)
        monitor = C.MDP(monitor)

    # Remove ignored outputs of sys.
    for sym in (monitor.inputs ^ sys.outputs):
        size = sys._aigbv.omap[sym].size
        monitor >>= C.MDP(BV.sink(size, [sym]))

    bexpr, manager, order = to_bdd2(sys >> monitor, horizon)
    return ConcreteSpec(bexpr, order, sys_inputs=sys.inputs, mdp=sys)
Example #11
0
def test_smoke2():
    spec, mdp = scenario_reactive()

    spec_circ = BV.aig2aigbv(spec.aig)
    mdp >>= C.circ2mdp(spec_circ)
    output = spec.output

    bdd, manager, order = to_bdd2(mdp, horizon=3, output=output)

    assert bdd.dag_size == 7

    def translate(mapping):
        return mapping

    assert bdd.count(6) == 8

    node = bdd

    assert bdd.bdd.let(translate({
        'a##time_0[0]': True,
        'c##time_0[0]': False,
        'a##time_1[0]': True,
    }), bdd) == bdd.bdd.false

    assert bdd.bdd.let(translate({
        'a##time_0[0]': True,
        'c##time_0[0]': True,
        'a##time_1[0]': False,
    }), bdd) == bdd.bdd.false

    assert node.low == bdd.bdd.false

    assert bdd.bdd.let(translate({
        'a##time_0[0]': True,
        'c##time_0[0]': True,
        'a##time_1[0]': True,
        'c##time_1[0]': True,
        'a##time_2[0]': True,
        'c##time_2[0]': True,
    }), bdd) == bdd.bdd.true

    assert bdd.bdd.let(translate({
        'a##time_0[0]': True,
        'c##time_0[0]': False,
        'a##time_1[0]': False,
        'c##time_1[0]': False,
        'a##time_2[0]': False,
        'c##time_2[0]': False,
    }), bdd) == bdd.bdd.true

    assert bdd.bdd.let(translate({
        'c##time_0[0]': False,
        'a##time_1[0]': True,
    }), bdd) == bdd.bdd.false

    assert bdd.bdd.let(translate({
        'c##time_0[0]': True,
        'a##time_1[0]': False,
    }), bdd) == bdd.bdd.false

    assert bdd.bdd.let(translate({
        'c##time_1[0]': False,
        'a##time_2[0]': True,
    }), bdd) == bdd.bdd.false

    assert bdd.bdd.let(translate({
        'c##time_1[0]': True,
        'a##time_2[0]': False,
    }), bdd) == bdd.bdd.false

    assert bdd.bdd.let(translate({
        'c##time_2[0]': False,
    }), bdd) == bdd

    assert bdd.bdd.let(translate({
        'c##time_2[0]': True,
    }), bdd) == bdd
Example #12
0
def test_never_false1():
    spec = LTL.atom('x').historically()
    monitor = BV.aig2aigbv(spec.aig)
    dyn = C.pcirc(BV.identity_gate(1, 'x'))

    horizon = 4
    model = from_pcirc(dyn, monitor, steps=horizon)

    coeff = np.log(2)
    actor = model.improviser(rationality=coeff)

    expected = [
        0,
        coeff,
        np.log(1 + 2),
        np.log(3 + 2),
        np.log(7 + 2),
        np.log(15 + 2),
    ]
    # LSE visits powers of 2 for the special coeff.
    expected = fn.lmap(pytest.approx, expected)

    vals = sorted(list(actor.node2val.values()))
    assert all(x == y for x, y in zip(expected, vals))

    expected = sorted([
        np.log(9) - np.log(17),
        np.log(8) - np.log(17),
    ])
    expected = fn.lmap(pytest.approx, expected)

    def lprob(elems):
        return actor.prob(elems, log=True)

    assert lprob([]) == 0
    assert lprob([1]) == pytest.approx(np.log(9) - np.log(17))
    assert lprob([1, 1]) == pytest.approx(np.log(5) - np.log(17))
    assert lprob([1, 1, 1]) == pytest.approx(np.log(3) - np.log(17))
    assert lprob([1, 1, 1, 1]) == pytest.approx(coeff - np.log(17))

    # ----------- Fail on first state ---------------------
    base = np.log(8) - np.log(17)
    assert lprob([0]) == pytest.approx(base)
    # Uniform after failing.
    assert lprob([0, 1]) == pytest.approx(base - np.log(2))
    assert lprob([0, 0]) == pytest.approx(base - np.log(2))
    assert lprob([0, 0, 0]) == pytest.approx(base - np.log(4))
    assert lprob([0, 0, 1]) == pytest.approx(base - np.log(4))

    # ----------- Fail on second state ---------------------
    base = np.log(4) - np.log(17)
    assert lprob([1, 0]) == pytest.approx(base)
    assert lprob([1, 0, 0]) == pytest.approx(base - np.log(2))
    assert lprob([1, 0, 1]) == pytest.approx(base - np.log(2))
    assert lprob([1, 0, 0, 0]) == pytest.approx(base - np.log(4))
    assert lprob([1, 1, 0, 1]) == pytest.approx(base - np.log(4))

    with pytest.raises(ValueError):
        lprob([1, 1, 1, 1, 1, 1])

    example = list(actor.sample())
    assert -float('inf') < lprob(example)

    ctrl = actor.policy()
    example = []
    for env in [None, 0, 0, 0]:
        example.append(ctrl.send(env))
    assert -float('inf') < lprob(example)

    actor = model.improviser(psat=0.7)
    assert actor.sat_prob() == pytest.approx(0.7)
Example #13
0
def valid_circ(action):
    hist_valid = PLTL.atom('valid').historically().with_output('valid')
    hist_valid = aiger_bv.aig2aigbv(hist_valid.aig)

    return is_1hot(action) >> hist_valid
def create_sensor(aps):
    sensor = BV.aig2aigbv(A.empty())
    for name, ap in APS.items():
        sensor |= ap.with_output(name).aigbv
    return sensor
def spec2monitor(spec):
    monitor = spec.aig | A.sink(['red', 'yellow'])
    monitor = monitor['o', {spec.output: 'sat'}]
    monitor = BV.aig2aigbv(monitor)
    return SENSOR >> monitor
import aiger_bv as BV
import aiger_coins as C
import aiger_ptltl as LTL

from mce.equiv import equiv_states

X = LTL.atom('x')
Y = LTL.atom('y')
SYS = C.circ2mdp(BV.aig2aigbv((X.once() | Y.once()).aig))


def test_equiv_states_smoke():
    state = SYS._aigbv.latch2init

    for t in range(3):
        assert equiv_states(SYS, 3, t, state1=state, state2=state)

    state1 = SYS.aigbv({'x': (True, ), 'y': (False, )})[1]
    state2 = SYS.aigbv({'x': (False, ), 'y': (True, )})[1]
    assert state1 != state2

    for t in range(3):
        assert equiv_states(SYS, 3, t, state1=state1, state2=state2)