Package: py-aiger-bv
pyAiger-BV: Extension of pyAiger for manipulating
    sequential bitvector circuits.Table of ContentsAboutInstallationBitVector Expr DSLSequential Circuit DSLAbout Py-Aiger-BVThis library provides word level abstractions on top ofpy-aiger. This is done by theAIGBVwhich groups inputs, outputs, and latches into namedorderedsequences, e.g. bitvectors.The resulting objects can be turned intoAIGs where each input,
output, or latches name has its index appended to its name. For example,
an bitvector input,'x'with 3 bits becomes inputs'x[0]', 'x[1]', 'x[3]'InstallationIf you just need to useaiger_bv, you can just run:$ pip install py-aiger-bvFor developers, note that this project uses thepoetrypython package/dependency
management tool. Please familarize yourself with it and then
run:$ poetry installBitVector Expression DSLAs in py-aiger, when writing combinatorial circuits, the Sequential
Circuit DSL can be somewhat clumsy. For this common usecase, we have
developed the BitVector Expression DSL. This DSL actually consists of
two DSLs for signed and unsigned BitVectors.  All circuits generated
this way have a single output word. We use abig-endianencoding
where the most significant digit is the first element of the tuple
representing the word. For signed numbers, two's complement is used.importaiger_bv# Create 16 bit variables.x=aiger_bv.atom(16,'x')y=aiger_bv.atom(16,'y',signed=True)# Signed by default.z=aiger_bv.uatom(16,'z')# Equiv to signed=False.# bitwise ops.expr1=x&y# Bitwise and.expr2=x|y# Bitwise or.expr3=x^y# Bitwise xor.expr4=~x# Bitwise negation.# arithmeticexpr5=x+yexpr6=x-yexpr7=x<<yexpr8=x>>y# logical if unsigned, arithmetic if signed.expr9=-x# Arithmetic negation. Only defined for signed expr.expr10=abs(x)expr11=x@y# inner product of bitvectors mod 2 (+ is xor).# comparisonexpr12=x==yexpr13=x!=yexpr14=x<yexpr15=x<=yexpr16=x>yexpr17=x>=y# Atoms can be constants.expr18=x&aiger_bv.atom(16,3)expr19=x&aiger_bv.atom(16,0xff)# BitVector expressions can be concatenated.expr20=x.concat(y)# Particular bits can be indexed to create new expressions.expr21=x[1]# Single bit expressions can be repeated.expr22=x[1].repeat(10)# And you can inspect the AIGBV if needed.circ=x.aigbv# And you can inspect the AIG if needed.circ=x.aigbv.aig# And of course, you can get a BoolExpr from a single output aig.expr=aiger_bv.UnsignedBVExpr(circ)Sequential Circuit DSLpy-aiger-bv's Sequential Circuit DSL implements the same basic api as
py-aiger's Sequential Circuit DSL, but operates at the (variable
length) word level rather than the bit level.importaigerimportaiger_bvcirc=...# Create a circuit (see below).# We assume this circuit has word level# inputs: x,y, outputs: z, w, q, latches: a, bassertcirc.inputs=={'x','y'}assertcirc.outputs=={'z','w','q'}assertcirc.latches=={'a','b'}Sequential compositioncirc3=circ1>>circ2Parallel compositioncirc3=circ1|circ2Adding Feedback (inserts a delay)# Connect output y to input x with delay (initialized to True).# (Default initialization is False.)cir2=circ.feedback(inputs=['x'],outputs=['y'],initials=[True],keep_outputs=True)Relabeling# Relabel input 'x' to 'z'.circ2=circ['i',{'x':'z'}]# Relabel output 'y' to 'w'.circ2=circ['o',{'y':'w'}]# Relabel latches 'l1' to 'l2'.circ2=circ['l',{'l1':'l2'}]Evaluation# Combinatoric evaluation.circ(inputs={'x':(True,False,True),'y':(True,False)})# Sequential evaluation.circ.simulate([{'x':(True,False,True),'y':(True,False)},{'x':(False,False,True),'y':(False,False)},])# Simulation Coroutine.sim=circ.simulator()# Coroutinenext(sim)# Initializeprint(sim.send({'x':(True,False,True),'y':(True,False)}))print(sim.send({'x':(False,False,True),'y':(False,False)}))# Unrollcirc2=circ.unroll(steps=10,init=True)aiger.AIG to aiger.AIGBVThere are two main ways to take an objectAIGfromaigerand
convert it into anAIGBVobject. The first is theaig2aigbvcommand which simply makes all inputs words of size 1.# Create aiger_bv.AIGERBV object from aiger.AIG object.circ=...# Some aiger.AIG objectword_circ=aiger_bv.aig2aigbv(circ)# aiger_bv.AIGBV objectGadget LibraryGeneral Manipulation# Copy outputs 'x' and 'y' to 'w1, w2' and 'z1, z2'.circ1=circ>>aiger_bv.tee(wordlen=3,iomap={'x':('w1','w2'),'y':('z1','z2')})# Take 1 bit output, 'x', duplicate it 5 times, and group into# a single 5-length word output, 'y'.circ2=circ>>aiger_bv.repeat(wordlen=5,input='x',output='z')# Reverse order of a word.circ3=circ>>aiger_bv.reverse_gate(wordlen=5,input='x',output='z')# Sink and Source circuits (see encoding section for encoding details).## Always output binary encoding for 15.circ4=aiger_bv.source(wordlen=4,value=15,name='x',signed=False)## Absorb output 'y'circ5=circ>>aiger_bv.sink(wordlen=4,inputs=['y'])# Identity Gatecirc6=circ>>aiger_bv.identity_gate(wordlen=3,input='x')# Combine/Concatenate wordscirc7=circ>>aiger_bv.combine_gate(left_wordlen=3,left='x',right_wordlen=3,right='y',output='z')# Split wordscirc8=circ>>aiger_bv.split_gate(input='x',left_wordlen=1,left='z',right_wordlen=2,right='w')# Select single index of circuit and make it a wordlen=1 output.circ9=circ>>aiger_bv.index_gate(wordlen=3,idx=1,input='x',output='x1')Bitwise Operationsaiger_bv.bitwise_and(3, left='x', right='y', output='x&y')aiger_bv.bitwise_or(3, left='x', right='y', output='x|y')aiger_bv.bitwise_xor(3, left='x', right='y', output='x^y')aiger_bv.bitwise_negate(3, left='x', output='~x')Arithmeticaiger_bv.add_gate(3, left='x', right='y', output='x+y')aiger_bv.subtract_gate_gate(3, left='x', right='y', output='x-y')aiger_bv.inc_gate(3, left='x', output='x+1')aiger_bv.dec_gate(3, left='x', output='x+1')aiger_bv.negate_gate(3, left='x', output='-x')aiger_bv.logical_right_shift(3, shift=1, input='x', output='x>>1')aiger_bv.arithmetic_right_shift(3, shift=1, input='x', output='x>>1')aiger_bv.left_shift(3, shift=1, input='x', output='x<<1')Comparisonaiger_bv.is_nonzero_gate(3, input='x', output='is_nonzero')aiger_bv.is_zero_gate(3, input='x', output='is_zero')aiger_bv.eq_gate(3, left='x', right='y', output='x=y')aiger_bv.ne_gate(3, left='x', right='y', output='x!=y')aiger_bv.unsigned_lt_gate(3, left='x', right='y', output='x<y')aiger_bv.unsigned_gt_gate(3, left='x', right='y', output='x>y')aiger_bv.unsigned_le_gate(3, left='x', right='y', output='x<=y')aiger_bv.unsigned_ge_gate(3, left='x', right='y', output='x>=y')aiger_bv.signed_lt_gate(3, left='x', right='y', output='x<y')aiger_bv.signed_gt_gate(3, left='x', right='y', output='x>y')aiger_bv.signed_le_gate(3, left='x', right='y', output='x<=y')aiger_bv.signed_ge_gate(3, left='x', right='y', output='x>=y')