Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(BV): Word-level propagation for BV logic
This patch implements constraint propagation for the logical operators (and, or, xor) on bit-vectors. The goal of this patch is to ensure that Alt-Ergo has a complete understanding of the logical operators on bit-vectors, and in particular that it will never violate the definition of the logical operators when generating models. They are thus removed from the "suspicious" operators (along with `int2bv` and `bv2nat` that are now handled through the "delayed functions" mechanism, even though this patch does not impact these functions). The patch can be decomposed in changes of the following categories, where each category can mostly be reviewed independently (all in the same patch because they wouldn't really make sense on their own): - Some minor refactoring in `Bitv`, `Th_util`, `Expr`, `ModelMap` and `Symbols` to expose the required functions and types, including a `Th_bitv` constructor for bit-vector case-splits and a built-in symbol for `bvxor` - The new `Bitlist` module introduces a representation of bit-vector domains as bit-lists, i.e. pairs of `(ones, zeroes)` represented as integers where the bits forced to `1` are set in `ones`, and the bits forced to `0` are set in `zeroes`. - There is a new `Congruence` module in `Rel_utils` that is exploited by the BV constraint propagators. The `Congruence` module can be understood as a lighter version of `Use` for semantic values (rather than terms): it provides a mechanism to register "semantic values of interest" (in our case, it will be the arguments of the logical operators and the result of the logical operator themselves) and be notified when the representative of these semantic values of interest are updated. To avoid partially inconsistent states, the congruence module computes the leaves the each semantic values of interest and updates all the semantic values that have a given leaf at once. This `Congruence` module is not BV-specific, hence why it is in `Rel_utils`. - Finally, the main course is in the `Bitv_rel` module, where the new constraint propagators are added. The constraint propagators are represented using separate `Domains` and `Constraints` modules that are kept normalized (i.e. they only reference current class representatives in `Uf`) through the `Congruence` utility. The `Domains` module is simply a map from class representatives to their domain, represented as a `Bitlist`. To avoid unnecessary propagations, the `Domains` module keeps track of the values whose domain has changed since the last propagation, to know that we must propagate the associated constraints again. The `Constraints` module is a set of `Constraint`s that keeps track of the semantic values that are involved in each constraint to avoid unnecessary propagations. The `Constraint`s are normalized (so that if we have both `a = b & c` and `a = b & d`, we only keep one once we learn that `c = d`), and we also keep track of the constraints that were never propagated. The `Bitv_rel` environment then keeps track of a `Domains` and a `Constraints` set that are updated through `Congruence` whenever a class representative changes (detected through equalities with `Subst` origin). After each change to either the domains or the constraints (either through a class representative change or because we added a new constraint), we propagate the fresh constraints and the constraints involving values whose domain has changed. We maintain the invariant that, outside of the `add` and `assume` functions, all the constraints in the `Constraints` set are satisfied by the domains of the `Domains`. In the interest of keeping the patch relatively short and facilitate its review, many desirable features have been left out for now, and there are many places where the implementation can be improved. Notably: - We do not perform any sort of constraint simplification (outside of the normalization used for de-duplication). This can cause backtracking inefficiencies: if we have a constraint involving the concatenation `a @ b`, and we substitute `b -> c`, then detect a conflict involving `a`, the explanation for the substitution `b -> c` will end up in the conflict even though it had no impact, causing more work than necessary. This can be added in a second step. - The constraints are represented in a relational way rather than a functional way. This means that if we have both `a = b & c` and `d = b & c` as constraints, we will not learn that `a = d`. I don't think this has any impact currently, because the only way we can learn a constraint `a = b & c` is if `a` is equal to `b & c` as a term, but could have one in the future if we want to perform simplifications. - Only logical operators are supported. In particular, there is no support for combined reasoning with arithmetic, which is a whole can of worms in itself (in the current Alt-Ergo architecture, we do not have access to the interval domains from the bit-vector theory and conversely). Finally, this patch purposely does not implement any sort of algebraic reasoning on bit-vectors [^1]: while with this patch Alt-Ergo is able to prove theorems such as De Morgan's laws or algebraic properties (associativity, commutativity, neutral elements, inverses, etc.) of the logical operators, this will currently happen through painstaking case-splitting which gets slow on large bit-vector sizes [^2]. [^1]: The equation `x ^ x = 0` happens to be known as a side-effect of the representation of XOR constraints. [^2]: The value of "large" here is actually fairly small, because proving these laws through propagation often requires exploring the full space, which is exponential.
- Loading branch information