def test_discrete_wrapper_smoke():
    x = BV.uatom(3, 'x')
    circ = (x + 1).with_output('z') \
                  .aigbv

    func = from_aigbv(circ)
    assert func({'x': 6})[0] == {'z': 7}

    func2 = from_aigbv(
        circ,
        input_encodings={'x': NEG_ENC},
        output_encodings={'z': NEG_ENC},
    )
    assert func2({'x': -2})[0] == {'z': -3}

    valid = (x <= 2).with_output('##valid') \
                    .aigbv

    func3 = from_aigbv(
        circ | valid,
        input_encodings={'x': NEG_ENC},
        output_encodings={'z': NEG_ENC},
    )
    assert func3({'x': -2})[0] == {'z': -3}

    with pytest.raises(ValueError):
        func3({'x': -3})

    assert func3.inputs == {'x'}
    assert func3.outputs == {'z'}
    assert func3.latches == set()
    assert func3.latch2init == {}
def test_parallel_composition():
    x = BV.uatom(3, 'x')
    circ1 = (x + 1).with_output('y').aigbv \
        | (x < 5).with_output('##valid').aigbv
    func1 = from_aigbv(
        circ1,
        input_encodings={'x': INT_ENC},
        output_encodings={'y': INT_ENC},
    )

    circ2 = x.with_output('z').aigbv \
        | (x > 2).with_output('##valid').aigbv
    func2 = from_aigbv(
        circ2,
        input_encodings={'x': INT_ENC},
        output_encodings={'z': INT_ENC},
    )

    func12 = func1 | func2
    assert func12({'x': 3})[0] == {'y': 4, 'z': 3}

    with pytest.raises(ValueError):
        func12({'x': 0})

    with pytest.raises(ValueError):
        func12({'x': 7})
Exemple #3
0
    def register_distribution(self, probs):
        """
        Register a distribution
        :param probs: The distribution as a list of probabilities
        :return: A pcirc that generates a binary-encoded output sel
          that corresponds to sampling from the distribution.
        """
        dist = tuple(probs)
        if dist not in self._distributions:
            name = f"{self._aut_name}_c{len(self._distributions)}"
            sel = atom(len(probs), name).with_output("sel")
            lookup = bidict({idx: f'sel-{idx}' for idx in range(len(probs))})
            encoder = D.Encoding(decode=lookup.get, encode=lookup.inv.get)
            func = D.from_aigbv(sel.aigbv, input_encodings={name: encoder})

            name2prob = {
                name:
                {f"sel-{index}": prob
                 for index, prob in enumerate(probs)}
            }
            coins_id = f"{self._aut_name}_c{len(self._distributions)}"

            self._distributions[dist] = C.pcirc(func) \
                                         .randomize(name2prob) \
                                         .with_coins_id(coins_id)
        return self._distributions[dist]
def test_readme():
    # Will assume inputs are in 'A', 'B', 'C', 'D', or 'E'.
    ascii_encoder = Encoding(
        decode=lambda x: chr(x + ord('A')),  # Make 'A' map to 0.
        encode=lambda x: ord(x) - ord('A'),
    )

    # Create function which maps: A -> B, B -> C, C -> D, D -> E.
    x = BV.uatom(3, 'x')  # Need 3 bits to capture 5 input types.
    update_expr = (x < 4).repeat(3) & (x + 1)  # 0 if x < 4 else x + 1.
    circ = update_expr.with_output('y').aigbv

    # Need to assert that the inputs are less than 4.
    circ |= (x < 5).with_output('##valid').aigbv

    # Wrap using aiger_discrete.
    func = from_aigbv(
        circ,
        input_encodings={'x': ascii_encoder},
        output_encodings={'y': ascii_encoder},
        valid_id='##valid',
    )

    assert func({'x': 'A'})[0] == {'y': 'B'}
    assert func({'x': 'B'})[0] == {'y': 'C'}
    assert func({'x': 'C'})[0] == {'y': 'D'}
    assert func({'x': 'D'})[0] == {'y': 'E'}
    assert func({'x': 'E'})[0] == {'y': 'A'}
def test_relabel():
    x = BV.uatom(3, 'x')
    circ1 = (x + 1).with_output('y').aigbv \
        | (x < 5).with_output('##valid').aigbv
    func1 = from_aigbv(circ1,)
    assert func1['i', {'x': 'z'}].inputs == {'z'}
    assert func1['o', {'y': 'z'}].outputs == {'z'}
    assert func1['i', {'x': 'z'}].valid_id == func1.valid_id
def test_seq_composition():
    x = BV.atom(4, 'x')
    y = BV.atom(4, 'y')

    circ1 = (x + 1).with_output('y').aigbv \
        | (x < 5).with_output('##valid').aigbv
    func1 = from_aigbv(circ1,)

    circ2 = (y - 1).with_output('z').aigbv \
        | (y > 2).with_output('##valid').aigbv
    func2 = from_aigbv(circ2,)

    func12 = func1 >> func2
    assert func12({'x': 4})[0] == {'z': 4}

    with pytest.raises(ValueError):
        func12({'x': 1})

    func12 = func2 << func1
    assert func12({'x': 4})[0] == {'z': 4}

    with pytest.raises(ValueError):
        func12({'x': 1})
Exemple #7
0
def onehot_gadget(output: str):
    sat = BV.uatom(1, output)
    false, true = BV.uatom(2, 0b01), BV.uatom(2, 0b10)
    expr = BV.ite(sat, true, false) \
             .with_output('sat')

    encoder = D.Encoding(
        encode=lambda x: 1 << int(x),
        decode=lambda x: bool((x >> 1) & 1),
    )

    return D.from_aigbv(
        expr.aigbv,
        output_encodings={'sat': encoder},
    )
Exemple #8
0
def test_readme_mdd():
    # Will assume inputs are in 'A', 'B', 'C', 'D', or 'E'.
    ascii_encoder = Encoding(
        decode=lambda x: chr(x + ord('A')),  # Make 'A' map to 0.
        encode=lambda x: ord(x) - ord('A'),
    )

    one_hot_ascii_encoder = Encoding(
        decode=lambda x: ascii_encoder.decode(ONE_HOT.inv[x]),
        encode=lambda x: ONE_HOT[ascii_encoder.encode(x)],
    )

    # Create function which maps: A -> B, B -> C, C -> D, D -> E.
    x = BV.uatom(3, 'x')  # Need 3 bits to capture 5 input types.
    update_expr = (x < 4).repeat(3) & (x + 1)  # 0 if x < 4 else x + 1.
    circ = update_expr.with_output('y').aigbv
    circ |= (x < 5).with_output('##valid').aigbv
    one_hot_converter = BV.lookup(3,
                                  5,
                                  ONE_HOT,
                                  'y',
                                  'y',
                                  in_signed=False,
                                  out_signed=False)
    circ >>= one_hot_converter

    func_circ = from_aigbv(
        circ,
        input_encodings={'x': ascii_encoder},
        output_encodings={'y': one_hot_ascii_encoder},
        valid_id='##valid',
    )

    assert func_circ({'x': 'A'})[0] == {'y': 'B'}
    assert func_circ({'x': 'B'})[0] == {'y': 'C'}
    assert func_circ({'x': 'C'})[0] == {'y': 'D'}
    assert func_circ({'x': 'D'})[0] == {'y': 'E'}
    assert func_circ({'x': 'E'})[0] == {'y': 'A'}

    func_mdd = to_mdd(func_circ)

    assert func_mdd({'x': 'A'})[0] == 'B'
    assert func_mdd({'x': 'B'})[0] == 'C'
    assert func_mdd({'x': 'C'})[0] == 'D'
    assert func_mdd({'x': 'D'})[0] == 'E'
    assert func_mdd({'x': 'E'})[0] == 'A'
def test_loopback_and_unroll():
    x = BV.uatom(3, 'x')
    y = BV.uatom(3, 'y')
    circ1 = (x + y).with_output('y').aigbv \
        | (x < 7).with_output('##valid').aigbv
    func1 = from_aigbv(circ1,)
    func2 = func1.loopback({
        'input': 'x', 'output': 'y',
        'keep_output': True,
        'init': 0,
    })
    assert func2.simulate([{'y': 1}, {'y': 1}])[-1][0] == {'y': 2}
    with pytest.raises(ValueError):
        assert func2.simulate([{'y': 1}]*10)

    func3 = func2.unroll(2, only_last_outputs=True)
    assert func3({'y##time_0': 0, 'y##time_1': 1})[0] == {'y##time_2': 1}

    with pytest.raises(ValueError):
        assert func3({'y##time_0': 7, 'y##time_1': 0})
Exemple #10
0
def gridworld(n, start=(None, None), compressed_inputs=False):
    # Gridworld is 2 synchronized chains.
    circ = chain(n, 'x', 'ax', start[1]) | chain(n, 'y', 'ay', start[0])
    circ <<= split_gate('a', 2, 'ay', 2, 'ax')  # Combine inputs.
    x = BV.uatom(circ.omap['x'].size, 'x')
    y = BV.uatom(circ.omap['y'].size, 'y')
    circ >>= y.concat(x).with_output('state').aigbv  # Combine outputs.

    if compressed_inputs:
        uncompress = lookup(2,
                            4,
                            COMPRESSION_MAPPING,
                            'a',
                            'a',
                            in_signed=False,
                            out_signed=False)
        circ <<= uncompress

    # Wrap using aiger discrete add encoding + valid inputs.
    actions_map = ACTIONS_C if compressed_inputs else ACTIONS
    action_encoding = aiger_discrete.Encoding(
        encode=actions_map.get,
        decode=actions_map.inv.get,
    )
    state_encoding = aiger_discrete.Encoding(
        encode=lambda s: s.yx,
        decode=lambda yx: G.GridState(yx, n),
    )

    func = aiger_discrete.from_aigbv(
        circ,
        input_encodings={'a': action_encoding},
        output_encodings={'state': state_encoding},
    )
    if not compressed_inputs:
        action = BV.uatom(4, 'a')
        is_1hot = (action != 0) & ((action & (action - 1)) == 0)
        func = func.assume(is_1hot)
    return func
Exemple #11
0
def to_finite_func(circ) -> FiniteFunc:
    if isinstance(circ, FiniteFunc):
        return circ
    return aiger_discrete.from_aigbv(circ.aigbv)
def test_rename_valid():
    func = from_aigbv(BV.uatom(3, 'x').aigbv).rename_valid('foo')
    assert 'foo' in func.circ.outputs
    assert 'foo' == func.valid_id