Esempio n. 1
0
def test_bdd_transform(circ):
    circ = circ.unroll(3)
    out = list(circ.outputs)[0]
    f, manager, relabel = to_bdd(circ, output=out)
    expr = from_bdd(f, manager=manager)

    circ2 = expr.aig['i', relabel.inv]['o', {expr.output: out}]
    assert not circ2.latches
    assert circ2.inputs <= circ.inputs
    assert out in circ2.outputs

    f2, _, relabel = to_bdd(expr.aig,
                            manager=manager,
                            output=expr.output,
                            renamer=lambda *x: x[1])
    assert f == f2
Esempio n. 2
0
    def toggle(self, actions: Actions):
        """Toggles a sequence of (sys, env) actions."""
        assert len(actions) == self.horizon
        aps = fn.lpluck(0, self.dyn.simulate(actions))
        expr = preimage(aps=aps, mdp=self.dyn)
        bexpr, *_ = aiger_bdd.to_bdd(
            expr, manager=self.manager, renamer=lambda _, x: x
        )

        return attr.evolve(self, bexpr=xor(self.bexpr, bexpr))
Esempio n. 3
0
def test_set_levels():
    a1, c1, a2, c2 = aiger.atoms('a1', 'c1', 'a2', 'c2')
    expr = (a1 == c1) & (a2 == c2)
    levels = {'c1': 0, 'a1': 1, 'c2': 2, 'a2': 3}

    bexpr, manager, relabels = to_bdd(expr,
                                      renamer=lambda _, x: x,
                                      levels=levels)

    assert all(k == v for k, v in relabels.items())
    assert bexpr.low.negated
    assert not bexpr.high.negated
Esempio n. 4
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)
Esempio n. 5
0
    def sample(self):
        guard, *_ = random.choices(*zip(*self.data), k=1)
        bexpr, manager, *_ = aiger_bdd.to_bdd(guard)
        if bexpr == manager.false:
            raise ValueError('None zero probability assigned to empty set.')

        # Uniformly sample bits and use BDD to error-correct to a model.
        nbits = len(manager.vars)
        bits: int = random.getrandbits(nbits)  # Packed random bits.
        for i in range(nbits):
            var = bexpr.bdd.var_at_level(i)
            decision = bool((bits >> i) & 1)  # Look up ith random bit.
            bexpr2 = bexpr.let(**{var: decision})

            if bexpr2 == manager.false:
                bexpr2 = bexpr.let(**{var: not decision})
                bits ^= 1 << i  # Error correction.
            bexpr = bexpr2
        return self.decode(bits)
Esempio n. 6
0
def to_bdd2(mdp, horizon, output=None, manager=None):
    """
    Compute the BDD for `output`'s value after unrolling the dynamics
    (`mdp`) `horizon` steps.

    Returns a triplet of:
     1. The BDD.
     2. The BDD Manager.
     3. The order object determining if a given bit is a decision or
        chance bit.
    """
    if output is None:
        assert len(mdp.outputs) == 1
        output = fn.first(mdp.outputs)

    circ = cone(mdp.aigbv, output)
    inputs, env_inputs = mdp.inputs, circ.inputs - mdp.inputs
    imap = circ.imap

    def flattened(t):
        def fmt(k):
            idxs = range(imap[k].size)
            return [f"{k}##time_{t}[{i}]" for i in idxs]

        actions = fn.lmapcat(fmt, inputs)
        coin_flips = fn.lmapcat(fmt, env_inputs)
        return actions + coin_flips

    unrolled_inputs = fn.lmapcat(flattened, range(horizon))
    levels = {k: i for i, k in enumerate(unrolled_inputs)}

    circ2 = BV.AIGBV(circ.aig.lazy_aig).unroll(horizon, only_last_outputs=True)
    bexpr, *_ = aiger_bdd.to_bdd(circ2, levels=levels, renamer=lambda _, x: x)

    def count_bits(inputs):
        return sum(imap[i].size for i in inputs)

    order = BitOrder(count_bits(inputs), count_bits(env_inputs), horizon)

    return bexpr, bexpr.bdd, order
Esempio n. 7
0
def test_bdd_transform_smoke():
    to_bdd(atom(3, 'x', signed=False) < 4)