예제 #1
0
def source(wordlen, value, name='x', signed=True):
    if isinstance(value, int):
        value = encode_int(wordlen, value, signed)

    omap = BundleMap({name: wordlen})
    aig = aiger.source({name: bit for name, bit in zip(omap[name], value)})
    return aigbv.AIGBV(aig=aig, omap=omap)
예제 #2
0
def bitwise_negate(wordlen, input='x', output='not x'):
    imap, omap = BundleMap({input: wordlen}), BundleMap({output: wordlen})
    return aigbv.AIGBV(
        imap=imap,
        omap=omap,
        aig=aiger.bit_flipper(inputs=imap[input], outputs=omap[output]),
    )
예제 #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 even_popcount_gate(wordlen, input, output):
    imap, omap = BundleMap({input: wordlen}), BundleMap({output: 1})
    return aigbv.AIGBV(
        imap=imap,
        omap=omap,
        aig=aiger.parity_gate(imap[input], omap[output][0]),
    )
예제 #5
0
def is_nonzero_gate(wordlen, input='x', output='is_nonzero'):
    imap, omap = BundleMap({input: wordlen}), BundleMap({output: 1})
    return aigbv.AIGBV(
        imap=imap,
        omap=omap,
        aig=aiger.or_gate(imap[input], omap[output][0]),
    )
예제 #6
0
def bitwise_binop(binop, wordlen, left='x', right='y', output='x&y'):
    imap = BundleMap({left: wordlen, right: wordlen})
    omap = BundleMap({output: wordlen})

    names = zip(imap[left], imap[right], omap[output])
    return aigbv.AIGBV(
        imap=imap,
        omap=omap,
        aig=reduce(op.or_, (binop([lft, rht], o) for lft, rht, o in names)),
    )
예제 #7
0
def identity_gate(wordlen, input='x', output=None):
    if output is None:
        output = input

    imap, omap = BundleMap({input: wordlen}), BundleMap({output: wordlen})
    return aigbv.AIGBV(
        imap=imap,
        omap=omap,
        aig=aiger.identity(inputs=imap[input], outputs=omap[output]),
    )
예제 #8
0
def repeat(wordlen, input, output=None):
    if output is None:
        output = input

    imap, omap = BundleMap({input: 1}), BundleMap({output: wordlen})
    return aigbv.AIGBV(
        imap=imap,
        omap=omap,
        aig=aiger.tee({imap[input][0]: list(omap[output])}),
    )
예제 #9
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])
예제 #10
0
def tee(wordlen, iomap):
    imap = BundleMap({i: wordlen for i in iomap})
    omap = BundleMap({o: wordlen for o in fn.cat(iomap.values())})

    blasted = defaultdict(list)

    for i, outs in iomap.items():
        for o in outs:
            for k, v in zip(imap[i], omap[o]):
                blasted[k].append(v)

    return aigbv.AIGBV(imap=imap, omap=omap, aig=aiger.tee(blasted))
예제 #11
0
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)
예제 #12
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)
예제 #13
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)))