def brent_kung_add(A, B, cin=0): """Return symbolic logic for an N-bit Brent-Kung adder.""" if len(A) != len(B): raise ValueError("expected A and B to be equal length") N = len(A) # generate/propagate logic gs = [A[i] & B[i] for i in range(N)] ps = [A[i] ^ B[i] for i in range(N)] # carry tree for i in range(floor(log(N, 2))): step = 2**i for start in range(2**(i + 1) - 1, N, 2**(i + 1)): gs[start] = gs[start] | ps[start] & gs[start - step] ps[start] = ps[start] & ps[start - step] # inverse carry tree for i in range(floor(log(N, 2)) - 2, -1, -1): start = 2**(i + 1) - 1 step = 2**i while start + step < N: gs[start + step] = gs[start + step] | ps[start + step] & gs[start] ps[start + step] = ps[start + step] & ps[start] start += step # sum logic ss = [A[0] ^ B[0] ^ cin] ss += [A[i] ^ B[i] ^ gs[i - 1] for i in range(1, N)] return farray(ss), farray(gs)
def brent_kung_add(A, B, cin=0): """Return symbolic logic for an N-bit Brent-Kung adder.""" if len(A) != len(B): raise ValueError("expected A and B to be equal length") N = len(A) # generate/propagate logic gs = [A[i] & B[i] for i in range(N)] ps = [A[i] ^ B[i] for i in range(N)] # carry tree for i in range(floor(log(N, 2))): step = 2**i for start in range(2**(i+1)-1, N, 2**(i+1)): gs[start] = gs[start] | ps[start] & gs[start-step] ps[start] = ps[start] & ps[start-step] # inverse carry tree for i in range(floor(log(N, 2))-2, -1, -1): start = 2**(i+1)-1 step = 2**i while start + step < N: gs[start+step] = gs[start+step] | ps[start+step] & gs[start] ps[start+step] = ps[start+step] & ps[start] start += step # sum logic ss = [A[0] ^ B[0] ^ cin] ss += [A[i] ^ B[i] ^ gs[i-1] for i in range(1, N)] return farray(ss), farray(gs)
def __radd__(self, other): from pyeda.boolalg.bfarray import farray if isinstance(other, Function): return farray([other] + [self]) elif isinstance(other, farray): return farray(list(other.flat) + [self]) else: raise TypeError("expected Function or farray")
def ripple_carry_add(A, B, cin=0): """Return symbolic logic for an N-bit ripple carry adder.""" if len(A) != len(B): raise ValueError("expected A and B to be equal length") ss, cs = list(), list() for i, a in enumerate(A): c = (cin if i == 0 else cs[i-1]) ss.append(a ^ B[i] ^ c) cs.append(a & B[i] | a & c | B[i] & c) return farray(ss), farray(cs)
def ripple_carry_add(A, B, cin=0): """Return symbolic logic for an N-bit ripple carry adder.""" if len(A) != len(B): raise ValueError("expected A and B to be equal length") ss, cs = list(), list() for i, a in enumerate(A): c = (cin if i == 0 else cs[i - 1]) ss.append(a ^ B[i] ^ c) cs.append(a & B[i] | a & c | B[i] & c) return farray(ss), farray(cs)
def __add__(self, other): """Concatenation operator The *other* argument may be a Function or an farray. """ from pyeda.boolalg.bfarray import farray if other in {0, 1}: return farray([self] + [self.box(other)]) elif isinstance(other, Function): return farray([self] + [other]) elif isinstance(other, farray): return farray([self] + list(other.flat)) else: raise TypeError("expected Function or farray")
def __mul__(self, other): from pyeda.boolalg.bfarray import farray if type(other) is not int: raise TypeError("expected multiplier to be an int") if other < 0: raise ValueError("expected multiplier to be non-negative") return farray([self] * other)
def kogge_stone_add(A, B, cin=0): """Return symbolic logic for an N-bit Kogge-Stone adder.""" if len(A) != len(B): raise ValueError("expected A and B to be equal length") N = len(A) # generate/propagate logic gs = [A[i] & B[i] for i in range(N)] ps = [A[i] ^ B[i] for i in range(N)] for i in range(clog2(N)): start = 1 << i for j in range(start, N): gs[j] = gs[j] | ps[j] & gs[j-start] ps[j] = ps[j] & ps[j-start] # sum logic ss = [A[0] ^ B[0] ^ cin] ss += [A[i] ^ B[i] ^ gs[i-1] for i in range(1, N)] return farray(ss), farray(gs)
def kogge_stone_add(A, B, cin=0): """Return symbolic logic for an N-bit Kogge-Stone adder.""" if len(A) != len(B): raise ValueError("expected A and B to be equal length") N = len(A) # generate/propagate logic gs = [A[i] & B[i] for i in range(N)] ps = [A[i] ^ B[i] for i in range(N)] for i in range(clog2(N)): start = 1 << i for j in range(start, N): gs[j] = gs[j] | ps[j] & gs[j - start] ps[j] = ps[j] & ps[j - start] # sum logic ss = [A[0] ^ B[0] ^ cin] ss += [A[i] ^ B[i] ^ gs[i - 1] for i in range(1, N)] return farray(ss), farray(gs)
def __mul__(self, num): """Repetition operator""" from pyeda.boolalg.bfarray import farray if not isinstance(num, int): raise TypeError("expected multiplier to be an int") if num < 0: raise ValueError("expected multiplier to be non-negative") return farray([self] * num)
def __mul__(self, num): """Repetition operator""" from pyeda.boolalg.bfarray import farray if type(num) is not int: raise TypeError("expected multiplier to be an int") if num < 0: raise ValueError("expected multiplier to be non-negative") return farray([self] * num)
def test_degenerate(): xs = farray([]) # These are a bit silly assert xs.uor() == 0 assert xs.unor() == 1 assert xs.uand() == 1 assert xs.unand() == 0 assert xs.uxor() == 0 assert xs.uxnor() == 1 assert_raises(NotImplementedError, xs.decode)
def __radd__(self, other): from pyeda.boolalg.bfarray import farray if other in {0, 1}: return farray([self.box(other)] + [self]) else: raise TypeError("expected Function or farray")
def gray2bin(G): """Convert a gray-coded vector into a binary-coded vector.""" return farray([G[i:].uxor() for i, _ in enumerate(G)])
def test_farray(): # expected shape volume to match items assert_raises(ValueError, farray, [X[0], X[1]], shape=((0, 42), )) # could not determine ftype parameter assert_raises(ValueError, farray, []) # expected ftype to be a type assert_raises(TypeError, farray, [X[0], X[1]], ftype=42) # expected ftype to match items assert_raises(ValueError, farray, [X[0], X[1]], ftype=BinaryDecisionDiagram) # expected ftype to be a property subclass of Function assert_raises(TypeError, farray, [], ftype=int) # expected a sequence of Function assert_raises(TypeError, farray, 42) assert_raises(TypeError, farray, [1, 2, 3, 4]) # expected uniform dimensions assert_raises(ValueError, farray, [[a, b], [w, x, y, z], 42]) assert_raises(ValueError, farray, [[a, b], [w, x, y, z]]) # expected uniform types assert_raises(ValueError, farray, [[a, b], [c, bddvar('d')]]) assert_raises(ValueError, farray, [[a, b], [bddvar('c'), bddvar('d')]]) # _check_shape errors assert_raises(ValueError, farray, [a, b, c, d], shape=((-1, 3), )) assert_raises(ValueError, farray, [a, b, c, d], shape=((3, -1), )) assert_raises(ValueError, farray, [a, b, c, d], shape=((5, 1), )) assert_raises(TypeError, farray, [a, b, c, d], shape=(('foo', 'bar'), )) assert_raises(TypeError, farray, [a, b, c, d], shape=42) temp = farray([[a, b], [c, d]]) assert str(temp) == """\ farray([[a, b], [c, d]])\ """ # __str__ Z = exprvars('z', 2, 2, 2) assert str(Z) == """\ farray([[[z[0,0,0], z[0,0,1]], [z[0,1,0], z[0,1,1]]], [[z[1,0,0], z[1,0,1]], [z[1,1,0], z[1,1,1]]]])\ """ assert str(farray([], ftype=Expression)) == "farray([])" # __getitem__ # expected <= M slice dimensions, got N assert_raises(ValueError, X.__getitem__, (2, 2)) sel = exprvars('s', 2) assert str(X[sel]) == "Or(And(~s[0], ~s[1], x[0]), And(s[0], ~s[1], x[1]), And(~s[0], s[1], x[2]), And(s[0], s[1], x[3]))" assert str(X[:2][sel[0]]) == "Or(And(~s[0], x[0]), And(s[0], x[1]))" # expected clog2(N) bits assert_raises(ValueError, X.__getitem__, sel[0]) # slice step not supported assert_raises(ValueError, X.__getitem__, slice(None, None, 2)) # type error assert_raises(TypeError, X.__getitem__, 'foo') # norm_index assert X[-1] is X[3] assert_raises(IndexError, X.__getitem__, 42) # norm_indices assert X[-3:-1]._items == [X[-3], X[-2]] assert not X[-8:-10]._items assert not X[-10:-8]._items assert not X[8:10]._items assert not X[10:8]._items assert not X[3:1]._items # __setitem__ Z = exprzeros(4, 4) Z[0,0] = X[0] assert Z._items[0] is X[0] # expected item to be a Function assert_raises(TypeError, Z.__setitem__, (0, 0), 42) Z[0,:] = X[:4] assert Z._items[0:4] == [X[0], X[1], X[2], X[3]] # expected item to be an farray assert_raises(TypeError, Z.__setitem__, (0, slice(None, None, None)), 42) # expected item.size = ... assert_raises(ValueError, Z.__setitem__, ..., X[:2]) # slice step not supported assert_raises(ValueError, X.__setitem__, slice(None, None, 2), 42) # type error assert_raises(TypeError, X.__setitem__, 'foo', 42) # __add__ assert (0 + X)._items[0].is_zero() assert (X + 0)._items[4].is_zero() assert (Y[0] + X)._items[0] is Y[0] assert (X + Y[0])._items[4] is Y[0] assert (X[:2] + Y[2:])._items == [X[0], X[1], Y[2], Y[3]] # expected Function or farray assert_raises(TypeError, X.__add__, 42) assert_raises(TypeError, X.__radd__, 42) A = exprvars('a', 2, 5, 6) B = exprvars('b', 2, 5, 6) C = exprvars('c', (1, 3), 5, 6) # regular MDA will retain shape assert (A+B).shape == ((0, 4), (0, 5), (0, 6)) # irregular MDA will not assert (A+C).shape == ((0, 4*5*6), ) # regular MDA will retain shape assert (A*2).shape == ((0, 4), (0, 5), (0, 6)) # irregular MDA will not assert (C*2).shape == ((0, 4*5*6), ) # __mul__ # expected multiplier to be an int assert_raises(TypeError, X.__mul__, 'foo') # expected multiplier to be non-negative assert_raises(ValueError, X.__mul__, -2) assert (X[:2] * 2)._items == [X[0], X[1], X[0], X[1]] assert (2 * X[:2])._items == [X[0], X[1], X[0], X[1]] # offsets Z = exprzeros((1, 5), (17, 21)) assert Z.offsets == (1, 17) # reshape assert Z.reshape(4, 4).shape == ((0, 4), (0, 4)) # expected shape with equal volume assert_raises(ValueError, Z.reshape, 42, 42) # restrict assert str(X.vrestrict({X: '0101'})) == "farray([0, 1, 0, 1])" # compose assert X.compose({X[0]: Y[0]})._items[0] == Y[0] # to_uint / to_int assert uint2exprs(42).to_uint() == 42 assert uint2exprs(42, 8).to_uint() == 42 # expected all functions to be a constant (0 or 1) form assert_raises(ValueError, X.to_uint) # expected num >= 0 assert_raises(ValueError, uint2exprs, -1) # overflow assert_raises(ValueError, uint2exprs, 42, 2) assert_raises(ValueError, int2exprs, 42, 2) assert int2exprs(-42).to_int() == -42 assert int2exprs(-42, 8).to_int() == -42 assert int2exprs(42).to_int() == 42 assert int2exprs(42, 8).to_int() == 42 # zext, sext assert X.zext(1)[4].is_zero() assert X.sext(1)[4] is X[3] # __invert__, __or__, __and__, __xor__ assert str(~X) == "farray([~x[0], ~x[1], ~x[2], ~x[3]])" assert str(X | Y) == "farray([Or(x[0], y[0]), Or(x[1], y[1]), Or(x[2], y[2]), Or(x[3], y[3])])" assert str(X & Y) == "farray([And(x[0], y[0]), And(x[1], y[1]), And(x[2], y[2]), And(x[3], y[3])])" assert str(X ^ Y) == "farray([Xor(x[0], y[0]), Xor(x[1], y[1]), Xor(x[2], y[2]), Xor(x[3], y[3])])" # _op_shape # expected farray input assert_raises(TypeError, X.__or__, 42) Z = exprvars('z', 2, 2) assert str(X | Z) == "farray([Or(x[0], z[0,0]), Or(x[1], z[0,1]), Or(x[2], z[1,0]), Or(x[3], z[1,1])])" Z = exprvars('z', 2, 3) # expected operand sizes to match assert_raises(ValueError, X.__or__, Z) # lsh, rsh assert str(X.lsh(0)) == "(farray([x[0], x[1], x[2], x[3]]), farray([]))" assert str(X << 0) == "farray([x[0], x[1], x[2], x[3]])" assert str(X.lsh(2)) == "(farray([0, 0, x[0], x[1]]), farray([x[2], x[3]]))" assert str(X << 2) == "farray([0, 0, x[0], x[1]])" assert str(X << (2, Y[:2])) == "farray([y[0], y[1], x[0], x[1]])" assert str(X.rsh(0)) == "(farray([x[0], x[1], x[2], x[3]]), farray([]))" assert str(X >> 0) == "farray([x[0], x[1], x[2], x[3]])" assert str(X.rsh(2)) == "(farray([x[2], x[3], 0, 0]), farray([x[0], x[1]]))" assert str(X >> 2) == "farray([x[2], x[3], 0, 0])" assert str(X >> (2, Y[:2])) == "farray([x[2], x[3], y[0], y[1]])" assert_raises(TypeError, X.__lshift__, 'foo') assert_raises(ValueError, X.__lshift__, -1) assert_raises(ValueError, X.__lshift__, (2, Y)) assert_raises(TypeError, X.__rshift__, 'foo') assert_raises(ValueError, X.__rshift__, -1) assert_raises(ValueError, X.__rshift__, (2, Y)) # arsh assert str(X.arsh(0)) == "(farray([x[0], x[1], x[2], x[3]]), farray([]))" assert str(X.arsh(2)) == "(farray([x[2], x[3], x[3], x[3]]), farray([x[0], x[1]]))" assert_raises(ValueError, X.arsh, -1) # unary ops assert str(X.uor()) == "Or(x[0], x[1], x[2], x[3])" assert str(X.unor()) == "Not(Or(x[0], x[1], x[2], x[3]))" assert str(X.uand()) == "And(x[0], x[1], x[2], x[3])" assert str(X.unand()) == "Not(And(x[0], x[1], x[2], x[3]))" assert str(X.uxor()) == "Xor(x[0], x[1], x[2], x[3])" assert str(X.uxnor()) == "Not(Xor(x[0], x[1], x[2], x[3]))" # decode assert str(farray([], ftype=Expression).decode()) == "farray([1])" assert str(X[:2].decode()) == "farray([And(~x[0], ~x[1]), And(x[0], ~x[1]), And(~x[0], x[1]), And(x[0], x[1])])"