def num2term(num, vs, conj=False): """Convert a number into a min/max term. Parameters ---------- num : int vs : [Variable] conj : bool conj=False for minterms, conj=True for maxterms Examples -------- Table of min/max terms for Boolean space {a, b, c} +-----+----------+----------+ | num | minterm | maxterm | +=====+==========+==========+ | 0 | a' b' c' | a b c | | 1 | a b' c' | a' b c | | 2 | a' b c' | a b' c | | 3 | a b c' | a' b' c | | 4 | a' b' c | a b c' | | 5 | a b' c | a' b c' | | 6 | a' b c | a b' c' | | 7 | a b c | a' b' c' | +-------+----------+----------+ """ if conj: return tuple(-v if bit_on(num, i) else v for i, v in enumerate(vs)) else: return tuple(v if bit_on(num, i) else -v for i, v in enumerate(vs))
def num2term(num, fs, conj=False): """Convert a number into a min/max term. Parameters ---------- num : int fs : [Function] conj : bool conj=False for minterms, conj=True for maxterms Examples -------- Table of min/max terms for Boolean space {a, b, c} +-----+----------+----------+ | num | minterm | maxterm | +=====+==========+==========+ | 0 | a' b' c' | a b c | | 1 | a b' c' | a' b c | | 2 | a' b c' | a b' c | | 3 | a b c' | a' b' c | | 4 | a' b' c | a b c' | | 5 | a b' c | a' b c' | | 6 | a' b c | a b' c' | | 7 | a b c | a' b' c' | +-------+----------+----------+ """ if conj: return tuple(~f if bit_on(num, i) else f for i, f in enumerate(fs)) else: return tuple(f if bit_on(num, i) else ~f for i, f in enumerate(fs))
def decode(self): """ Return symbolic logic for an N:2^N binary decoder. Example Truth Table for a 2:4 decoder: +===========+=====================+ | A[1] A[0] | D[3] D[2] D[1] D[0] | +===========+=====================+ | 0 0 | 0 0 0 1 | | 0 1 | 0 0 1 0 | | 1 0 | 0 1 0 0 | | 1 1 | 1 0 0 0 | +===========+=====================+ """ # Degenerate case is just [1], but that's not a valid farray if self.size == 0: msg = "decode method undefined for zero-sized farray" raise NotImplementedError(msg) items = [reduce(operator.and_, [f if bit_on(i, j) else ~f for j, f in enumerate(self.items)]) for i in range(2 ** self.size)] return self.__class__(items)
def decode(self): """Return symbolic logic for an N-2^N binary decoder. Example Truth Table for a 2:4 decoder: +===========+=====================+ | A[1] A[0] | D[3] D[2] D[1] D[0] | +===========+=====================+ | 0 0 | 0 0 0 1 | | 0 1 | 0 0 1 0 | | 1 0 | 0 1 0 0 | | 1 1 | 1 0 0 0 | +===========+=====================+ >>> A = bitvec('a', 2) >>> d = A.decode() >>> d.vrestrict({A: "00"}) [1, 0, 0, 0] >>> d.vrestrict({A: "10"}) [0, 1, 0, 0] >>> d.vrestrict({A: "01"}) [0, 0, 1, 0] >>> d.vrestrict({A: "11"}) [0, 0, 0, 1] """ items = [ And(*[ f if bit_on(i, j) else -f for j, f in enumerate(self) ]) for i in range(2 ** len(self)) ] return self.__class__(items)
def decode(self): r""" Return symbolic logic for an :math:`N \rightarrow 2^N` binary decoder. Example Truth Table for a 2:4 decoder: .. csv-table:: :header: :math:`A_1`, :math:`A_0`, :math:`D_3`, :math:`D_2`, :math:`D_1`, :math:`D_0` :stub-columns: 2 0, 0, 0, 0, 0, 1 0, 1, 0, 0, 1, 0 1, 0, 0, 1, 0, 0 1, 1, 1, 0, 0, 0 """ # Degenerate case is just [1], but that's not a valid farray if self.size == 0: msg = "decode method undefined for zero-sized farray" raise NotImplementedError(msg) items = [reduce(operator.and_, [f if bit_on(i, j) else ~f for j, f in enumerate(self.items)]) for i in range(2 ** self.size)] return self.__class__(items)
def num2term(num, fs, conj=False): """Convert *num* into a min/max term in an N-dimensional Boolean space. The *fs* argument is a sequence of :math:`N` Boolean functions. There are :math:`2^N` points in the corresponding Boolean space. The dimension number of each function is its index in the sequence. The *num* argument is an int in range :math:`[0, 2^N)`. If *conj* is ``False``, return a minterm. Otherwise, return a maxterm. For example, consider the 3-dimensional space formed by functions :math:`f`, :math:`g`, :math:`h`. Each vertex corresponds to a min/max term as summarized by the table:: 6-----------7 ===== ======= ========== ========== /| /| num f g h minterm maxterm / | / | ===== ======= ========== ========== / | / | 0 0 0 0 f' g' h' f g h 4-----------5 | 1 1 0 0 f g' h' f' g h | | | | 2 0 1 0 f' g h' f g' h | | | | 3 1 1 0 f g h' f' g' h | 2-------|---3 4 0 0 1 f' g' h f g h' | / | / 5 1 0 1 f g' h f' g h' h g | / | / 6 0 1 1 f' g h f g' h' |/ |/ |/ 7 1 1 1 f g h f' g' h' +-f 0-----------1 ===== ======= ========= =========== .. note:: The ``f g h`` column is the binary representation of *num* written in little-endian order. """ if type(num) is not int: fstr = "expected num to be an int, got {0.__name__}" raise TypeError(fstr.format(type(num))) N = len(fs) if not 0 <= num < 2**N: fstr = "expected num to be in range [0, {}), got {}" raise ValueError(fstr.format(2**N, num)) if conj: return tuple(~f if bit_on(num, i) else f for i, f in enumerate(fs)) else: return tuple(f if bit_on(num, i) else ~f for i, f in enumerate(fs))
def num2term(num, fs, conj=False): """Convert *num* into a min/max term in an N-dimensional Boolean space. The *fs* argument is a sequence of :math:`N` Boolean functions. There are :math:`2^N` points in the corresponding Boolean space. The dimension number of each function is its index in the sequence. The *num* argument is an int in range :math:`[0, 2^N)`. If *conj* is ``False``, return a minterm. Otherwise, return a maxterm. For example, consider the 3-dimensional space formed by functions :math:`f`, :math:`g`, :math:`h`. Each vertex corresponds to a min/max term as summarized by the table:: 6-----------7 ===== ======= ========== ========== /| /| num f g h minterm maxterm / | / | ===== ======= ========== ========== / | / | 0 0 0 0 f' g' h' f g h 4-----------5 | 1 1 0 0 f g' h' f' g h | | | | 2 0 1 0 f' g h' f g' h | | | | 3 1 1 0 f g h' f' g' h | 2-------|---3 4 0 0 1 f' g' h f g h' | / | / 5 1 0 1 f g' h f' g h' h g | / | / 6 0 1 1 f' g h f g' h' |/ |/ |/ 7 1 1 1 f g h f' g' h' +-f 0-----------1 ===== ======= ========= =========== .. note:: The ``f g h`` column is the binary representation of *num* written in little-endian order. """ if not isinstance(num, int): fstr = "expected num to be an int, got {0.__name__}" raise TypeError(fstr.format(type(num))) n = len(fs) if not 0 <= num < 2**n: fstr = "expected num to be in range [0, {}), got {}" raise ValueError(fstr.format(2**n, num)) if conj: return tuple(~f if bit_on(num, i) else f for i, f in enumerate(fs)) else: return tuple(f if bit_on(num, i) else ~f for i, f in enumerate(fs))
def num2point(num, vs): """Convert a number into a point in an N-dimensional space. Parameters ---------- num : int vs : [Variable] """ return {v: bit_on(num, i) for i, v in enumerate(vs)}
def num2upoint(num, vs): """Convert a number into an untyped point in an N-dimensional space. Parameters ---------- num : int vs : [Variable] """ upoint = [set(), set()] for i, v in enumerate(vs): upoint[bit_on(num, i)].add(v.uniqid) return frozenset(upoint[0]), frozenset(upoint[1])
def reduce(self): """Reduce to a canonical form.""" support = frozenset(range(1, self.nvars+1)) new_clauses = set() for clause in self.clauses: vs = list(support - {abs(uniqid) for uniqid in clause}) if vs: for num in range(1 << len(vs)): new_part = {v if bit_on(num, i) else ~v for i, v in enumerate(vs)} new_clauses.add(clause | new_part) else: new_clauses.add(clause) return self.__class__(self.nvars, new_clauses)
def num2point(num, vs): """Convert *num* into a point in an N-dimensional Boolean space. The *vs* argument is a sequence of :math:`N` Boolean variables. There are :math:`2^N` points in the corresponding Boolean space. The dimension number of each variable is its index in the sequence. The *num* argument is an int in range :math:`[0, 2^N)`. For example, consider the 3-dimensional space formed by variables :math:`a`, :math:`b`, :math:`c`. Each vertex corresponds to a 3-dimensional point as summarized by the table:: 6-----------7 ===== ======= ================= /| /| num a b c point / | / | ===== ======= ================= / | / | 0 0 0 0 {a:0, b:0, c:0} 4-----------5 | 1 1 0 0 {a:1, b:0, c:0} | | | | 2 0 1 0 {a:0, b:1, c:0} | | | | 3 1 1 0 {a:1, b:1, c:0} | 2-------|---3 4 0 0 1 {a:0, b:0, c:1} | / | / 5 1 0 1 {a:1, b:0, c:1} c b | / | / 6 0 1 1 {a:0, b:1, c:1} |/ |/ |/ 7 1 1 1 {a:1, b:1, c:1} +-a 0-----------1 ===== ======= ================= .. note:: The ``a b c`` column is the binary representation of *num* written in little-endian order. """ if type(num) is not int: fstr = "expected num to be an int, got {0.__name__}" raise TypeError(fstr.format(type(num))) N = len(vs) if not 0 <= num < 2**N: fstr = "expected num to be in range [0, {}), got {}" raise ValueError(fstr.format(2**N, num)) return {v: bit_on(num, i) for i, v in enumerate(vs)}
def num2point(num, vs): """Convert *num* into a point in an N-dimensional Boolean space. The *vs* argument is a sequence of :math:`N` Boolean variables. There are :math:`2^N` points in the corresponding Boolean space. The dimension number of each variable is its index in the sequence. The *num* argument is an int in range :math:`[0, 2^N)`. For example, consider the 3-dimensional space formed by variables :math:`a`, :math:`b`, :math:`c`. Each vertex corresponds to a 3-dimensional point as summarized by the table:: 6-----------7 ===== ======= ================= /| /| num a b c point / | / | ===== ======= ================= / | / | 0 0 0 0 {a:0, b:0, c:0} 4-----------5 | 1 1 0 0 {a:1, b:0, c:0} | | | | 2 0 1 0 {a:0, b:1, c:0} | | | | 3 1 1 0 {a:1, b:1, c:0} | 2-------|---3 4 0 0 1 {a:0, b:0, c:1} | / | / 5 1 0 1 {a:1, b:0, c:1} c b | / | / 6 0 1 1 {a:0, b:1, c:1} |/ |/ |/ 7 1 1 1 {a:1, b:1, c:1} +-a 0-----------1 ===== ======= ================= .. note:: The ``a b c`` column is the binary representation of *num* written in little-endian order. """ if not isinstance(num, int): fstr = "expected num to be an int, got {0.__name__}" raise TypeError(fstr.format(type(num))) n = len(vs) if not 0 <= num < 2**n: fstr = "expected num to be in range [0, {}), got {}" raise ValueError(fstr.format(2**n, num)) return {v: bit_on(num, i) for i, v in enumerate(vs)}