PyEDA is a Python library for electronic design automation.
- Symbolic Boolean algebra with a selection of function representations:
- Logic expressions
- Truth tables, with three output states (0, 1, "don't care")
- Reduced, ordered binary decision diagrams (ROBDDs)
- SAT solvers:
- Backtracking
- DPLL
- PicoSAT
- Espresso logic minimization
- Formal equivalence
- Multi-dimensional bit vectors
- DIMACS CNF/SAT parsers
- Logic expression parser
Bleeding edge code:
$ git clone git://github.com/cjdrake/pyeda.git
For release tarballs and zipfiles, visit PyEDA's page at the Cheese Shop.
Latest released version using setuptools:
$ easy_install pyeda
Latest release version using pip:
$ pip install pyeda
Installation from the repository:
$ python setup.py install
Invoke your favorite Python terminal, and invoke an interactive pyeda
session:
>>> from pyeda.inter import *
Create some Boolean expression variables:
>>> a, b, c, d = map(exprvar, "abcd")
Construct Boolean functions using overloaded Python operators: ~
(NOT), |
(OR), ^
(XOR), &
(AND), >>
(IMPLIES):
>>> f0 = ~a & b | c & ~d
>>> f1 = a >> b
>>> f2 = ~a & b | a & ~b
>>> f3 = ~a & ~b | a & b
>>> f4 = ~a & ~b & ~c | a & b & c
>>> f5 = a & b | ~a & c
Construct Boolean functions using standard function syntax:
>>> f10 = Or(And(Not(a), b), And(c, Not(d)))
>>> f11 = Implies(a, b)
>>> f12 = Xor(a, b)
>>> f13 = Xnor(a, b)
>>> f14 = Equal(a, b, c)
>>> f15 = ITE(a, b, c)
Construct Boolean functions using higher order operators:
>>> f20 = Nor(a, b, c)
>>> f21 = Nand(a, b, c)
>>> f22 = OneHot(a, b, c)
>>> f23 = OneHot0(a, b, c)
Investigate a function's properties:
>>> f0.support
frozenset({a, b, c, d})
>>> f0.inputs
(a, b, c, d)
>>> f0.top
a
>>> f0.degree
4
>>> f0.cardinality
16
>>> f0.depth
2
Factor complex expressions into only OR/AND and literals:
>>> f11.factor()
Or(~a, b)
>>> f12.factor()
Or(And(~a, b), And(a, ~b))
>>> f13.factor()
Or(And(~a, ~b), And(a, b))
>>> f14.factor()
Or(And(~a, ~b, ~c), And(a, b, c))
>>> f15.factor()
Or(And(a, b), And(~a, c))
Restrict a function's input variables to fixed values, and perform function composition:
>>> f0.restrict({a: 0, c: 1})
Or(b, ~d)
>>> f0.compose({a: c, b: ~d})
Or(And(~c, ~d), And(c, ~d))
Test function formal equivalence:
>>> f2.equivalent(f12)
True
>>> f4.equivalent(f14)
True
Investigate Boolean identities:
# Law of double complement
>>> ~~a
a
# Idempotent laws
>>> a | a
a
>>> a & a
a
# Identity laws
>>> a | 0
a
>>> a & 1
a
# Dominance laws
>>> a | 1
1
>>> a & 0
0
# Commutative laws
>>> (a | b).equivalent(b | a)
True
>>> (a & b).equivalent(b & a)
True
# Associative laws
>>> a | (b | c)
Or(a, b, c)
>>> a & (b & c)
And(a, b, c)
# Distributive laws
>>> (a | (b & c)).to_cnf()
And(Or(a, b), Or(a, c))
>>> (a & (b | c)).to_dnf()
Or(And(a, b), And(a, c))
# De Morgan's laws
>>> Not(a | b).factor()
And(~a, ~b)
>>> Not(a & b).factor()
Or(~a, ~b)
# Absorption laws
>>> (a | (a & b)).absorb()
a
>>> (a & (a | b)).absorb()
a
Perform Shannon expansions:
>>> a.expand(b)
Or(And(a, ~b), And(a, b))
>>> (a & b).expand([c, d])
Or(And(a, b, ~c, ~d), And(a, b, ~c, d), And(a, b, c, ~d), And(a, b, c, d))
Convert a nested expression to disjunctive normal form:
>>> f = a & (b | (c & d))
>>> f.depth
3
>>> g = f.to_dnf()
>>> g
Or(And(a, b), And(a, c, d))
>>> g.depth
2
>>> f.equivalent(g)
True
Convert between disjunctive and conjunctive normal forms:
>>> f = ~a & ~b & c | ~a & b & ~c | a & ~b & ~c | a & b & c
>>> g = f.to_cnf()
>>> h = g.to_dnf()
>>> g
And(Or(a, b, c), Or(a, ~b, ~c), Or(~a, b, ~c), Or(~a, ~b, c))
>>> h
Or(And(~a, ~b, c), And(~a, b, ~c), And(a, ~b, ~c), And(a, b, c))
Create some four-bit vectors, and use slice operators:
>>> A = exprvars('A', 4)
>>> B = exprvars('B', 4)
>>> A
[A[0], A[1], A[2], A[3]]
>>> A[2:]
[A[2], A[3]]
>>> A[-3:-1]
[A[1], A[2]]
Perform bitwise operations using Python overloaded operators: ~
(NOT), |
(OR), &
(AND), ^
(XOR):
>>> ~A
[~A[0], ~A[1], ~A[2], ~A[3]]
>>> A | B
[Or(A[0], B[0]), Or(A[1], B[1]), Or(A[2], B[2]), Or(A[3], B[3])]
>>> A & B
[And(A[0], B[0]), And(A[1], B[1]), And(A[2], B[2]), And(A[3], B[3])]
>>> A ^ B
[Xor(A[0], B[0]), Xor(A[1], B[1]), Xor(A[2], B[2]), Xor(A[3], B[3])]
Reduce bit vectors using unary OR, AND, XOR:
>>> A.uor()
Or(A[0], A[1], A[2], A[3])
>>> A.uxor()
Xor(A[0], A[1], A[2], A[3])
>>> A.uand()
And(A[0], A[1], A[2], A[3])
Create and test functions that implement non-trivial logic such as arithmetic:
>>> from pyeda.logic.addition import *
>>> S, C = ripple_carry_add(A, B)
# Note "1110" is LSB first. This says: "7 + 1 = 8".
>>> S.vrestrict({A: "1110", B: "1000"}).to_uint()
8
Consult the documentation for information about truth tables, and binary decision diagrams. Each function representation has different trade-offs, so always use the right one for the job.
PyEDA includes an extension to the industrial-strength PicoSAT SAT solving engine.
Use the satisfy_one
method to finding a single satisfying input point:
>>> f = OneHot(a, b, c)
>>> f.satisfy_one()
{a: 0, b: 0, c: 1}
Use the satisfy_all
method to iterate through all satisfying input points:
>>> list(f.satisfy_all())
[{a: 0, b: 0, c: 1}, {a: 0, b: 1, c: 0}, {a: 1, b: 0, c: 0}]
For more interesting examples, see the following documentation chapters:
PyEDA includes an extension to the famous Espresso library for the minimization of two-level covers of Boolean functions.
Use the espresso_exprs
function to minimize multiple expressions:
>>> f1 = ~a & ~b & ~c | ~a & ~b & c | a & ~b & c | a & b & c | a & b & ~c
>>> f2 = ~a & ~b & c | a & ~b & c
>>> f1m, f2m = espresso_exprs(f1, f2)
>>> f1m
Or(And(~a, ~b), And(a, b), And(~b, c))
>>> f2m
And(~b, c)
Use the espresso_tts
function to minimize multiple truth tables:
>>> X = exprvars('x', 4)
>>> f1 = truthtable(X, "0000011111------")
>>> f2 = truthtable(X, "0001111100------")
>>> f1m, f2m = espresso_tts(f1, f2)
>>> f1m
Or(x[3], And(x[0], x[2]), And(x[1], x[2]))
>>> f2m
Or(x[2], And(x[0], x[1]))
If you have Nose installed, run the unit test suite with the following command:
$ make test
If you have Coverage installed, generate a coverage report (including HTML) with the following command:
$ make cover
If you have Pylint installed, perform static lint checks with the following command:
$ make lint
If you have Sphinx installed, build the HTML documentation with the following command:
$ make html
PyEDA is developed using Python 3.2+. It is NOT compatible with Python 2.7.
- Chris Drake (cjdrake AT gmail DOT com), http://cjdrake.blogspot.com