Пример #1
0
    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
Пример #2
0
def add_gate(wordlen, left='x', right='y', output='x+y', has_carry=False):
    carry_name = f'{output}_carry'
    assert left != carry_name and right != carry_name

    adder_aig = aiger.source({carry_name: False})

    lefts = named_indexes(wordlen, left)
    rights = named_indexes(wordlen, right)
    outputs = named_indexes(wordlen, output)

    for lname, rname, oname in zip(lefts, rights, outputs):
        adder_aig >>= _full_adder(x=lname,
                                  y=rname,
                                  carry_in=carry_name,
                                  result=oname,
                                  carry_out=carry_name)

    if not has_carry:
        adder_aig >>= aiger.sink([output + '_carry'])

    return aigbv.AIGBV(
        aig=adder_aig,
        input_map=frozenset([(left, lefts), (right, rights)]),
        output_map=frozenset([(output, outputs)]),
    )
Пример #3
0
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)
Пример #4
0
def index_gate(wordlen, idx, input, output=None):
    assert 0 <= idx < wordlen
    if output is None:
        output = input

    imap, omap = BundleMap({input: wordlen}), BundleMap({output: 1})
    inputs, outputs = imap[input], (imap[input][idx], )

    aig = aiger.sink(set(inputs) - set(outputs)) | aiger.identity(outputs)
    relabels = {outputs[0]: omap[output][0]}
    return aigbv.AIGBV(imap=imap, omap=omap, aig=aig['o', relabels])
Пример #5
0
def index_gate(wordlen, idx, input, output=None):
    assert 0 <= idx < wordlen
    if output is None:
        output = input

    inputs = named_indexes(wordlen, input)
    outputs = (inputs[idx], )
    aig = aiger.sink(set(inputs) - set(outputs)) \
        | aiger.identity(outputs)
    return aigbv.AIGBV(
        aig=aig,
        input_map=frozenset([(input, inputs)]),
        output_map=frozenset([(output, outputs)]),
    )
Пример #6
0
    def _encode(self, prev_latch, action, state):
        (step, lmap), circ1 = self._cutlatches()
        curr_step = step << aiger.source(prev_latch)

        for a, v in action.items():
            size = circ1.imap[a].size
            const = aiger_bv.source(size,
                                    aiger_bv.decode_int(v, signed=False),
                                    name=a,
                                    signed=False)
            curr_step <<= const.aig

        expr = uatom(1, "##valid") == 1
        for k, v in fn.chain(state.items()):
            expr &= _constraint(k, v)

        curr_step >>= expr.aig

        query = curr_step >> aiger.sink(prev_latch.keys())
        assert len(query.outputs) == 1

        model = solve(query)
        assert model is not None

        # Fill in any model don't cares.
        model = fn.merge({i: False for i in circ1.aig.inputs}, model)

        # HACK. Put model back into bitvector.
        coins = circ1.imap.omit(self.inputs).unblast(model)

        if len(prev_latch) > 0:
            next_latch_circ = curr_step >> aiger.sink(expr.aig.outputs)
            next_latch = next_latch_circ(model)[0]
            assert next_latch.keys() == prev_latch.keys()
            prev_latch = next_latch

        return coins, prev_latch
Пример #7
0
def add_gate(wordlen, left='x', right='y', output='x+y', has_carry=False):
    carry_name = f'{output}_carry'
    assert left != carry_name and right != carry_name

    adder_aig = aiger.source({carry_name: False})

    imap = BundleMap({left: wordlen, right: wordlen})
    omap = BundleMap({
        output: wordlen,
        has_carry: 1
    } if has_carry else {output: wordlen})

    for lname, rname, oname in zip(imap[left], imap[right], omap[output]):
        adder_aig >>= _full_adder(x=lname,
                                  y=rname,
                                  carry_in=carry_name,
                                  result=oname,
                                  carry_out=carry_name)

    if not has_carry:
        adder_aig >>= aiger.sink([output + '_carry'])

    return aigbv.AIGBV(imap=imap, omap=omap, aig=adder_aig)
Пример #8
0
def sink(wordlen, inputs):
    imap = BundleMap({i: wordlen for i in inputs})
    return aigbv.AIGBV(imap=imap, aig=aiger.sink(fn.lmapcat(imap.get, inputs)))
Пример #9
0
def spec2monitor(spec):
    monitor = spec.aig | A.sink(['red', 'yellow'])
    monitor = monitor['o', {spec.output: 'sat'}]
    monitor = BV.aig2aigbv(monitor)
    return SENSOR >> monitor
Пример #10
0
def sink(wordlen, inputs):
    blasted_inputs = [named_indexes(wordlen, i) for i in inputs]
    return aigbv.AIGBV(
        aig=aiger.sink(fn.lcat(blasted_inputs)),
        input_map=frozenset(fn.lzip(inputs, blasted_inputs)),
    )
Пример #11
0
def coin(prob, input_name=None):
    # TODO: reimplement in terms of common_denominator_method.
    prob = utils.to_frac(prob)
    mux, is_valid = mutex_coins({'H': prob, 'T': 1 - prob})
    return mux >> aiger.sink('T'), is_valid