Bex is a rust crate for working with binary expressions.
BddBase
is now 100 times faster (or more, depending on your CPU count!)
-
worker threads are no longer killed and respawned for each top-level query.
-
Extract
wip:WorkState
frombdd_swarm
, introducing a shared queue and concurrent hashmaps so workers can share work without supervision from the main thread. -
the workers now use concurrent queues and hashmaps (thanks to
boxcar
anddashmap
) to share the cache state. -
Dropped
hashbrown
crate for non-shared hashmaps, since it is now the implementation that comes with rust standard library. -
Added
fxhash
as the hasher for all hashmaps. -
Removed top level functions in
nid::
. Use the correspondingnid::NID::
methods instead. (ex:nid::raw(n)
is nown.raw()
) In particular,nid::not(n)
should be written!n
. -
solve::find_factors
is now a generic function rather than a macro.
Aside from the addition of the ops
module, this is primarily
a benchmark release to make it easier to compare the 0.1.5
algorithms with 0.2.0.
-
Rename
BDDBase
toBddBase
, and addreset()
method. -
Add
BddBase::reset(&mut self)
to clear bdd state. -
Cleaned up all compiler warnings.
-
Removed all debug output.
-
Fixed test failures that appeared with different threading configurations.
-
Remove
nvars
from allBase
implementations. This member was only really useful when the height of a node wasn't obvious from the variable index. Because of this,Base::new()
no longer takes a parameter. -
Remove obsolete "substitution" concept from
ast.rs
, and replaceast::Op
with the more flexibleops::Ops
.
Same as 0.1.7 except I forgot to update the readme. :D
-
Added
SwapSolver
, a new substitution solver that (like anySubSolver
) works by iteratively replacing virtual variables (representing AST nodes) with their definitions inside a BDD. What's new here is thatSwapSolver
continuously re-orders the variables (rows) in the BDD at each step so that the substitution is as efficient as possible. -
Added
XVHLScaffold
, a data structure for decision-diagram-like graphs, that allows accessing each row individually. This structure should be considered extremely experimental, and may change in the future (as it does not currently useNID
for node references). -
Added
swarm
module that contains a small framework for distributing work across threads. It is used by theSwapSolver
to swap BDD rows in parallel, and follows the same design asBddSwarm
, which will likely be ported over to this framework in the future. -
Added
ops
module for representing boolean expressions in something like reverse Polish notation. TheOps::RPN
constructor will likely replaceast::Op
as the representation of nodes inast::ASTBase
in a future version, sinceOps::RPN
can represent arbitrary boolean functions with any number of inputs.
This version introduces the ANFBase for working with algebraic normal form using a BDD-like graph structure. This version also introduces Cursors, which provide the ability to iterate through BDD solutions and ANF terms.
It also includes a major refactoring effort: the BDD, AST, and ANF bases now all use the same NID/VID types for node and variable identifiers.
Finally, BDD and ANF graphs are now arranged so that variables with the smallest identifiers now appear at the bottom (so that subgraphs are more likely to be shared across functions with different numbers of inputs, and also so that the size of a node's truth table is immediately apparent from its topmost variable.)
vid::VID
VID
is now an explicit custom type rather than a simple usize. It accounts for both "real" variables (var()
) and virtual ones (vir()
), as well as the meta-constantT
(true) which fills the branch variable slots for theI
andO
BDD nodes.
smaller variables now appear at the bottom of BDD, ANF graphs.
- A new type for
VID
comparison was introduced -vid::VidOrdering
. This lets youcmp_depth
using termsAbove
,Level
, andBelow
rather than theLess
,Equal
,Greater
you get withcmp
. There was no technical reason for this, but I found it much easier to reason about the code in these terms. VidOrdering
is set up so that branch variables with smaller numbers move to the bottom of a BDD. There are numerous benefits to doing this - cross-function cache hits, immediate knowledge of the width of a node's truth table, and (most importantly) a much simpler time converting from ANF to BDD.- There is currently no support for the "industry standard" ordering - the plan in the future is just to make sure the graphviz output shows variable names, and then you can just re-arrange the labels.
NID as universal ID
ASTBase
now usesnid::VID
for input variable identifiers, andnid::NID
for node identifiers, rather than using simpleusize
indices. This means we no longer need to store explicit entries for constants and literals.- The
Base
trait no longer takes type argumentsN
andV
, since all implementations now usenid::NID
andvid::VID
.
Reg type
Reg
provides an general purpose register containing an arbitrary number of bits.- Bits in a Reg can be accessed individually either by number (with
get(ix)
andput(ix,bool))
, or using aVID
(var_get
,var_put
). Indexing by virtual variables is not supported. Reg
also provides a simpleincrement()
method, as well as the more generalripple(start,end)
. These treat the register as a binary number, "add 1" at a specified location, and ripple-carry the result until a 0 is encountered, or the carry overflows the end position. This is all intended to supportCursor
.
Cursor
cur::Cursor
combines aReg
with a stack ofNID
s to provide a tool for navigating through the terms or solutions in a BDD/ANF-like graph structure.
BDDBase
- You can now call
solutions()
on aBDDBase
to iterate through solutions of the BDD. Each solution is presented as aReg
of lengthnvars()
.
ANFBase
- The new
anf
module contains the beginnings of a BDD-like structure for working with expressions in algebraic normal form (XOR-of-ANDs). These two operations plus the constantI
give a complete functional base. The implementation does not yet take advantage of multiple cores.
code cleanup
- Swarming is now the only implementation for BDDBase. (#7)
cargo test
now runs quickly, without generating diagrams (#3)- Unify the AST and BDD "Base" interfaces. (#2, #5)
base
now contains only the abstract traitBase
(formerlyTBase
)Base
methods now act on associated typesSelf::N
andSelf::V
, rather thanNID
andVID
directly.- The old
struct base::Base
is nowast::ASTBase
. Methodssid
,sub
, andwhen
(which might not apply to other implementations) have been moved out oftrait Base
and intostruct ASTBase
directly. - The old
base::{Op,SID,SUB,NID,VID}
types have also moved to theast
module. bdd::BddBase
now implementsbase::Base
.- Some of the tests for
ast
andbdd
have been macro-fied and moved intobase
. These macros allow re-using the same test code for eachBase
implementation.
- The
bdd::NID
type and associated helper functions have been moved intonid
so the same scheme can be reused for otherBase
implementations.
documentation
- Began writing/collecting more documentation in the doc/ directory.
I got most this working back in December and then put it all aside for a while. It's still pretty messy, but I'm starting to work on it again, so I figured I would ship what I have, and then aim for more frequent, small releases as I continue to tinker with it.
multi-threaded workers
- refactored
bdd
so that theBddState
is now owned by aBddWorker
. Further, bothBddState
andBddWorker
are now traits. - Moved
BddWorker
implementation intoSimpleBddWorker
. - Provided multiple implementations for
BddState
-- (so far, one with and one without array bounds checking). - Added a multi-core bdd worker:
BddSwarm
. Between threading and an out-of-order execution model that results in potential short circuiting,ite()
calls that once took 30 or more seconds on my low-end 2-core laptop now run in 0 seconds!
code tuning
- added
solve::sort_by_cost
which optimizes the ast→bdd conversion to take only onebdd_refine_one
step per AST node (improved my still-external benchmark script by an order of magnitude). - in
bdd
,ite_norm
now constructs hi/lo nodes directly from input rather than callingwhen_xx
. This resulted in about a 23% speedup.
(rudimentary) example programs
examples/bdd-solve.rs
demonstrates one method of using bex to solve arbitrary problems. (Albeit very very slowly, still...)examples/bex-shell.rs
is a tiny forth-like interpreter for manipulating expressions interactively.- See examples/README.md for more details.
other improvements
solve::ProgressReport
can now simply save the final result instead of showing it (asdot
can take a very long time to render it into a png). It also now shows progress as a percentage (though only currently accurate whensort_by_cost
was called)
- added
Cargo.toml
documentation link to docs.rs/bex - added this changelog
- Renamed
bex::x32
tobex::int
, used macros to generalize number of bits, addedtimes
,lt
, andeq
functions - Added
bex::solve
for converting between ast and bdd representations. - Added distinction between
real
(input) andvirtual
(intermediate) variables inbdd::NID
- Added graphviz (
*.dot
) output forbase::Base
and improved formatting forbdd::BDDBase
- Various performance enhancements for
bex::bdd
. Most notably:- switched caches to use the
hashbrown
crate (for about a 40% speedup!) - added inlining hints for many functions
- re-ordered logic in bottleneck functions (
norm
,ite_norm
) to minimize work bdd::NID
is now a single u64 with redundant information packed into the NID itself. This way, decisions can be made looking at the NID directly, without fetching the actual node.- Disabled bounds checking for internal node lookups. (unsafe)
- switched caches to use the
- Refactored
bex::bdd
in preparation for multi-threading.- Grouped the internal node lists and the caches by branching variable (VID). This isn't actually an optimization, but I expect(ed?) it to make concurrent solving easier in the future.
- moved all the unsafe, data-mutating operations into a handful of
isolated functions on a single source page. These will likely be
factored out into a new
Worker
struct, eventually.
Initial public version. Work-in-progress code imported from a private repo.