v2.0.0
Major rewrite of the internal logic of Adiar to pay off technical debt and to support more complex BDD operations. These changes also address major quality-of-life issues in the API of v1.x. Finally, these changes brings Adiar much closer to support other types of decision diagrams (e.g. QMDDs) and many other features.
With this rewrite in-hand, Adiar now includes a much more complex (and faster) implementation of Multi-variable Quantification. Furthermore, this rewrite also supported the addition of Levelized Random Access to improve the performance of some of its operations.
New Features
-
Functional Bridge:
Adiar now uses generic and versatile functions to bridge between Adiar and the user's code. To this end, Adiar provides thepredicate<...>
andgenerator<...>
types to pass information into Adiar andconsumer<...>
to pass information back out again. All functions of v1.x that used some file, e.g.bdd_restrict
,zdd_onset
,bdd_varprofile
etc. all now provide one (or more) of these functions instead. For example,bdd_exists
is now overloaded with the following alternativesbdd_exists(f, x)
: quantify the variable x (also part of v1.x).bdd_exists(f, pred)
: quantify all variables i in f where pred(i) evaluates to true.bdd_exists(f, gen)
: quantify all variables i generated by gen(). Here it is important that gen() provides the variables in descending order.bdd_exists(f, begin, end)
: quantify all variables i from begin to end (assuming these are sorted in descending order).
-
Execution Policy:
Each algorithm (when relevant) has been overloaded with anexec_policy
as its first argument. This class provides a thread-safe way of passing options into an algorithm, e.g. whether the algorithm should use internal or external memory data structures. This replaces the use of the globally set enum values, e.g.memory_mode
. -
adiar_set_domain(...)
- Overloaded to allow creating the domain 0, 1, ..., n-1 when given the number of variables n.
- Overloaded to set domain given a generator function, or an iterator.
-
<adiar/version.h>
This header file contains compile-time and inlinable integer/string variables with the current version of Adiar.
Binary Decision Diagrams
-
bdd_top()
andbdd_bot()
Provide a uniform interface for getting the top and the bot value of the lattice. This provides a more uniform and interchangeable interface between BDDs and ZDDs where you do not need to think about the reduction rules. -
bdd_and(...)
andbdd_or(...)
These BDD builder functions now support negated variables. This can either be parsed as pairs with a negation flag, i.e.{x, true}
, or by parsing the negated label, i.e.-x
. -
bdd_const(...)
andbdd_isconst(f)
Added as aliases forbdd_terminal(...)
andbdd_isterminal(f)
, respectively. -
bdd_topvar(f)
Added functions to get root variable. Until the addition of a non-identity variable ordering, this is equivalent tobdd_minvar(f)
. -
bdd_restrict(f, x, v)
,bdd_low(f)
andbdd_high(f)
Added overload with a single variable. The new functions,bdd_low(f)
andbdd_high(f)
, are aliases for setting the top variable to the desired value. -
bdd_iscube(f)
andbdd_cube(...)
The builder function is an alias forbdd_and
whereas the predicate is an O(1) operation to recognise this type of diagram. -
bdd_isvar(f)
,bdd_isithvar(f)
, andbdd_isnithvar(f)
Predicates for whether a BDD is a single variable. These are resolved in constant-time. -
bdd_satmin(f, ...)
andbdd_satmax(f, ...)
Add overload with a callback function or iterators to be compatible with any data structure of your choice. -
bdd_optmin(f, c)
New function to derive the assignment in f that is minimal with respect to a linear cost function c. -
bdd_printdot(f, out)
Now takes a third optional Boolean argument,include_id
. If true, then the output includes the level-specific identifiers (which are useful for debugging). By default, this is false and outputs a decision diagram as in most literature.
Zero-suppressed Decision Diagrams
-
zdd_top(...)
, andzdd_bot(...)
:
Provide a uniform interface for getting the top and the bot value of the lattice. This provides a more uniform and interchangeable interface between BDDs and ZDDs where you do not need to think about the reduction rules. -
zdd_topvar(A)
Added functions to get root variable. Until the addition of a non-identity variable ordering, this is equivalent tozdd_minvar(A)
. -
zdd_onset(A, ...)
, andzdd_offset(A, ...)
Added overload with a single variable. By default, the variable iszdd_topvar(A)
. -
zdd_ispoint(A)
andzdd_point(...)
The builder function is an alias forzdd_vars
whereas the predicate is an O(1) operation to recognise this type of diagram. -
zdd_minelem(A, ...)
, andzdd_maxelem(A, ...)
Add overload with a callback function or iterators to be compatible with any data structure of your choice. -
zdd_printdot(f, out)
Now takes a third optional Boolean argument,include_id
. If true, then the output includes the level-specific identifiers (which are useful for debugging). By default, this is false and outputs a decision diagram as in most literature.
Optimisations
-
The algorithms
bdd_apply
,zdd_binop
, their derivatives, andbdd_exists
,bdd_forall
, andzdd_project
now use a level-by-level random access on one of the input (if possible). This circumvents using an entire priority queue, thereby drastically improving performance in some cases. This is especially beneficial when applying an operator to a very large decision diagram together with a narrow one.With
exec_policy::access
one can turn this optimisation off and/or force it to always be used. -
The functions
bdd_equal(f,g)
andzdd_equal(A,B)
terminate in constant time, if the width of the two decision diagrams are not the same. -
Added proper support for quantification of multiple variable. This is done with the new Nested Sweeping framework to add support for an I/O-efficient simulation of BDD operations that (may) recurse on intermediate results. This provides a completely new multi-variable quantification operations that is similar to the one in other BDD packages
With
exec_policy::quantify::algorithm
, one can pick between this and the previous approach of quantifying one variable at a time. -
bdd_apply(f,g,op)
andzdd_binop(A,B,op)
now precompute whether the operator op is shortcutting, idempotent or negating for either Boolean value. The commutative operators, e.g. and, or, and xor, are also pre-compiled with these predicates to further optimise conditional if-statements. -
bdd_satmin(f)
,bdd_satmax(f)
,zdd_minelem(A)
, andzdd_maxelem(A)
Stores the intermediate result in an internal memory stack (since it can at most be 8 MiB in size) rather than writing it out to disk. This should improve their performance slightly.
Bug Fixes
- The result of
adiar_stats()
is now fixed such that the values for reduce and substitute are correct. - Many small fixes to make Adiar compile with GCC, Clang, and MSVC on Linux, Mac, and Windows. Simultaneously, we have now set up continuous integration, such that we can truly ensure we support all platforms.
Breaking Changes
There has been a major rewrite of the internal logic of Adiar to pay off technical debt and to get Adiar ready for an I/O-efficient implementation of the Nested Sweeping framework used for multi-variable quantification. At the same time, this also brings Adiar much closer to support other types of decision diagrams (e.g. QMDDs) and to store BDDs on disk and loading them again later.
-
All internal logic in <adiar/internal/...> has been moved into its nested namespace
adiar::internal
. If you use anything from this namespace (e.g. the node and the node_writer classes) then you are not guaranteed non-breaking changes. -
Files, streams and their writers have been moved, rewritten, and renamed. Since newly added predicates and generator functions superseed any use of
adiar::file<...>
, all file-based overloads have been removed.
Furthermore, the entire API has been overhuled to have a consistent naming scheme. For example, the function is_true(const bdd &)
has been renamed to bdd_istrue(const bdd&)
. This makes them consistent with the rest of the API. The domain and statistics functions have also been renamed for consistency.
Other Breaking Changes
-
bdd_satmin(f)
andbdd_satmax(f)
, resp.zdd_minelem(A)
andzdd_maxelem(A)
:- The return type when called without a callback function has been turned into a
bdd
, resp.zdd
. This ought to make their return type more usable in a symbolic context. - Similar to other BDD packages, these operations now only report the labels of the nodes visited on the path through the BDD. That is, the output is now independent of the global variable domain and the BDD's levels.
- The return type when called without a callback function has been turned into a
-
bdd_varprofile(...)
andzdd_varprofile(...)
These have been renamed tobdd_support(...)
andzdd_support(...)
. This improves its discoverability and better reflects its content. -
Removed the functions
bdd_counter
andzdd_sized_set
. They may be added anew as a more generic implementation of Pseudo Boolean Constaints. -
The semantics of the
zdd_ithvar
function has been changed to be more akin to the BDD semantics. That is,zdd_ithvar(i)
is the set of all bitvectors where i is true. Symmetrically, thezdd_nithvar
function has been added. The original semantics ofzdd_ithvar
is still provided with thezdd_singleton
function. -
Canonicity of a BDD and ZDD is now a function rather than a member variable. The value is derived from the two underlying features of being indexable and sorted.
-
The old
adiar::bool_op
is now replaced with a future-proofadiar::predicate<bool, bool>
. -
The enum
memory_mode
has been removed in favour of using an Execution Policy. -
The two-level granularity of statistics has been removed. If you want to compile Adiar with statistics you just have to set the CMake variable
ADIAR_STATS
to ON, -
Every deprecated function from v1.x has been removed.
Contributors
- Steffan Sølvsten ( @SSoelvsten )
- Casper Moldrup Rysgaard ( @Crowton )
- Erik Funder Carstensen ( @halvko )
A huge thanks to Anna Blume Jakobsen ( @AnnaBlume99 ), Andrew Miner ( @asminer ), and Jaco van de Pol ( @jacopol ), for their valuable feedback and suggestions for the design and features of the public API.
Finally, also thanks to Ayoub Aboutarbouch ( @itsmeYO92 ), Maxim Smolskiy ( @MaximSmolskiy ), Nils Husung ( @nhusung ), and Sai Rugveth Vankayala ( @rugveth1210 ) for their small fixes and clean-ups.
License
Adiar 2.0.0 is distributed under the MIT license. But, notice that it depends on the TPIE library which is licensed under LGPL v3. So, by extension any binary file of Adiar is covered by the very same license.