-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactoring Enum_rel
using domains on class representatives only
#1078
Conversation
afebbd6
to
1944788
Compare
1944788
to
33e4f53
Compare
This PR refactors the `Adt` relations in order to use a proper type for the domains of enum semantic values. See PR OCamlPro#1078
This PR refactors the `Adt` relations in order to use a proper type for the domains of enum semantic values. See PR OCamlPro#1078
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the code in this PR is technically correct (the best kind of correct!) and without major flaws; as such, I'd be OK with merging it provided the remarks regarding comments/documentation are addressed.
However, I have concerns regarding regarding long-term maintainability (and some performance issues but those are probably minor) regarding the SimpleDomains_make
functor, explained below.
To the best of my understanding, Alt-Ergo currently generates a Subst
equality r → rr
when r
gets assigned to a new representative rr
exactly two cases1:
r
is a leaf (in the sense ofX.is_a_leaf
), orr
is a term representative, i.e. there is a termt
in the problem such thatr = X.make t = Uf.make uf t
This means that my assertion "if we see r1 = r2
as Other
then we will see r1 = rr
and r2 = rr
as Subst
equalities", reproduced here in a comment, is not entirely correct (sorry! I keep forgetting about this edge case) if either r1
or r2
is not a term representative. For the Enum
theory it does not matter because all enum semantic values are necessarily term representatives2, but looking forward to #1087 we can have ADTs that are not class term representatives (see below for an example).
This is the reason why the Domains_make
functor has a leaves_map
field that it uses during substitution (see also discussion in #1040), so that we catch this edge case. SimpleDomains_make
does not, and thus will miss domain updates in the presence of such synthetic representatives.
For the enum and ADT theories, this has zero impact on the correctness: the only way to generate synthetic representatives would be if they are argument of an ADT constructor (for instance, an ADT constructor with a bit-vector argument), but once we know the constructor, the unknown
domain is the tightest possible! It does mean that the theory will go through different paths depending on whether a synthetic representative was substituted (we will not find it in the map, so we will return its unknown
value) or no synthetic representative was substituted (we will find it in the map), which could easily cause subtle bugs in the future.
For these reasons, I think it would be preferrable to either use the more general Domains_make
(adding back the propagate
function; doing this will be more computationally expensive), or folding the SimpleDomains_make
definition into the enum theory and inlining it for that theory specifically. Inlining it for that theory allows some optimisations because we can make use of the remark above (once we know the constructor we know the domain) to avoid looking in the map if we have a constructor (in both find
and update
). This has the disadvantage that the code needs to be copy-and-pasted from enum to adt, but if the plan is to merge both, that will be an acceptable temporary situation; since the SimpleDomains
makes use of some specificity of these theories, it also makes sense for the implementation to be there rather than in the more generic Rel_utils
module.
Footnotes
-
I think there is also a variant of the 2nd case where
r
results from the AC-completion of term representatives, but it does not really matter here. ↩ -
Except if users define an AC symbol over enums, but I'd classify this as an AC(X) bug since it impacts many theories, see Preserve mapping between old and new representatives with AC symbols #823 ↩
src/lib/reasoners/enum_rel.ml
Outdated
(* Only Enum values can have a domain. This case can happen since we | ||
don't dispatch the literals processed in [assume] by their types in | ||
the Relation module. *) | ||
invalid_arg "unknown" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this case can happen, it must not raise an Invalid_argument
exception as per the documentation of Invalid_argument:
As a general rule, this exception should not be caught, it denotes a programming error and the code should be modified not to trigger it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forgot to update, but it looks like this case can no longer happen because we do check the types before calling Domains.add
, so the code is correct but the comment no longer is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So why do you use invalid_arg
in the very same situation in Bitv_rel
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because in the Bitv_rel
case it can't happen (there is a check for the type)! In fact, as noted in my 2nd comment, it is also the case here; the code is right but the comment that says "this case can happen" is wrong.
src/lib/reasoners/enum_rel.ml
Outdated
let fold_leaves _f _rr _d _ = assert false | ||
|
||
let map_leaves _f _rr _ = assert false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the following would be correct (e.g. would allow usage with Domains_make
):
let fold_leaves _f _rr _d _ = assert false | |
let map_leaves _f _rr _ = assert false | |
let fold_leaves f r d acc = f r d acc | |
let map_leaves f r acc = f r acc |
src/lib/reasoners/enum_rel.ml
Outdated
(* Needed for models generation because fresh terms are not added with the | ||
function add. *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't the function needed for models generation is add_rec
? This comment is on add
.
src/lib/reasoners/rel_utils.ml
Outdated
returned domain is identical to the domain of [d], only the | ||
justifications are changed. *) | ||
val unknown : X.r -> t | ||
(** [unknown r] returns a full domain for values of the semantic value [r]. *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change makes the documentation (and the function unknown
) unclear: a "full domain" means that all values are possible, so it shouldn't depend on the semantic value.
What this does currently is that it returns a full domain in the Bitv
theory, and either a full domain or a singleton domain for the Enum
theory. It would be more foolproof to keep the unknown
function as-is and to add a val create : X.r -> t
(or val default
) that returns a default domain for the representative r
(it is a bit weird that unknown r
is able to represent a precise singleton domain which is not "unknown" at all).
(Essentially this boils down to a difference in the way that the Domains_make
and SimpleDomains_make
functors want to use this function: Domains_make
wants to call it on the leaves, then use map_leaves
to build up a larger combined domain; SimpleDomains_make
wants to call it on every value.)
src/lib/reasoners/enum_rel.ml
Outdated
if Domain.cardinal d = 1 then | ||
let c = Domain.choose d in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: this (and assume_distinct
above) might make the intent clearer if written:
match Domain.as_singleton d with
| Some c -> ...
| None -> eqs
src/lib/reasoners/rel_utils.ml
Outdated
(** [update r d t] replaces the domain of [r] in [t] by [d]. The | ||
representative [r] is marked [changed] after this call. *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not replace it, it intersects it, and r
is only marked changed
if this causes the domain to change. The documentation should also make it clear that the new domain must have had any explanations justifying that it applies to r
already added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, Domain.update
is only used in assume_distinct
where nd
is always a subset of the old domain, so we don't need to perform an intersection here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the code and the doc disagree fixing either if fine by me :)
(Note that skipping the intersection here is a bit risky because we could end up widening a domain, which is a completeness bug, so this should be called out in the documentation)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a heavy assert to check we never update a domain with another one that isn't a subset.
src/lib/reasoners/enum_rel.ml
Outdated
|
||
let add env _ r _ = add_aux env r, [] | ||
let case_split_limit env n = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
case_split_limit
makes it sound like it will be true
if the limit is reached (I understood this on first read and was confused). Maybe call it case_split_ok
or can_split
?
src/lib/reasoners/rel_utils.ml
Outdated
match MX.find r t.domains with | ||
| _ -> t | ||
| exception Not_found -> | ||
let nd = Domain.unknown r in | ||
internal_update r nd t |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the function add
can be a no-op; there is no need to add unknown
domains since that is the default value returned by get
, and the unknown r
domain should be stable by propagation (unless some constraint applies, in which case the constraint will trigger the propagation).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I add this function for sake of completeness. If you replace it by no-op, you got regressions. For instance the following problem from the test suite:
type t = A | B
logic f: t , int -> int
goal g8:
forall x:t.
forall y:int.
f(x,y) = f(A,y) or f(x,y) = f(B,y)
is unsat
with the current add
operation but we got unknown
with no-op.
The reason is simple. The map env.domains
has two roles. It saves the domains of enum semantic values AND it saves the set of seen semantic values.
In the above test, x
is never seen in a constraint before the first case-split round. If we don't add a domain for it in env.domains
, the function Domains.fold
won't see it while performing case-split and we lost the opportunity to discover the inconsistency here.
We can:
- add a set in the environment of the theory to save seen semantic values and fold on it during the case splits;
- keep the current implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, it is also used for case splits, that makes sense, thanks for checking it out. I think it would be useful to note that this is useful for case splits in a comment here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, it wasn't clear at all ;)
src/lib/reasoners/rel_utils.ml
Outdated
let nd = Domain.intersect ~ex:Explanation.empty (Domain.unknown r) d in | ||
internal_update r nd t |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If nd
is equal to Domain.unknown r
then there is nothing to do, or at least Domain.unknown r
should be used instead (I think this is important to make sure domains associated with constants always have an empty explanation).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that we can replace this implementation by the following one:
let update r d t =
let od = get r t in
let nd = Domain.intersect ~ex:Explanation.empty od d in
if Domain.equal od nd then
t
else
internal_update r nd t
The update
function is only used in assume_distinct
.
Now, Domain.equal od nd
is true
if and only if both od
and nd
are the default domain for the type of r
. If r
isn't in the map t.domains
, this implementation doesn't add it to the map but I think it's ok.
Actually, add_rec
ensures that all the enum
semantic values of the current context are in the map t.domains
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I think this is important to make sure domains associated with constants always have an empty explanation).
To my understanding, the previous implementation of update
could add unnecessary explanations. Technically, it's correct but if we want to use explanations to produce a proof for instance, we could got useless hypotheses in this proof, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, using get
here should work and is simpler.
Unnecessary explanations translate to useless hypotheses in the proof, yes (depending on the way you see it, it is either useless hypotheses in the proof of the current branch, or unnecessary disjunctions in the proof of the user's statement, where we repeat the same sub-proof in both branches).
To clarify the type of cases I have in mind when writing the comment above, I believe that using the
would result in a bogus entry in the table of the form |
I think that inlining the functor is the best choice here. |
I'm no sure it's correct to do this optimization. As we only store domains for the current class representatives, we cannot return the default domain when we see a constructor. Let's imagine we have a semantic value let add r t =
match MX.find r t.domains with
| _ -> t
| exception Not_found ->
let nd = Domain.default r in
internal_update r nd t
let get r t =
try MX.find r t.domains
with Not_found -> Domain.default r |
The semantics of an entry |
More formally: an entry |
3f4453c
to
03c5af7
Compare
This PR refactors the `Enum` relations in order to use a proper type for the domains of enum semantic values. Now, we only store domains for class representatives and I believe that the new implementation is simpler to understand and to maintain. I don't use the functor `Domains_make` of `Rel_utils` as domain's propagations performed in `Enum_rel` are much simpler than the propagations in the BV theory.
The previous implementation of `Domain.update` could replace a default domain (with the empty explanation) by a default one with a non-empty explanation. There is no reason to add these extra explanations. This new implementation doesn't update the map `t.domains` if the intersection is a default domain. It means `update` doesn't add a domain if `d` is a default domain and `r` isn't in the map, which is ok as we ensure that all seen semantic values are added to `t.domains` in `assume`.
The `unknown` function in `Enum_rel` doesn't return the full domain for constructor semantic values but the tightest possible domain for it. The `default` name is more appropriate for this behaviour.
As we inlined the function `SimpleDomains_make` in `Enum_rel`, we can write more efficient code for this theory. We don't need to look in the map `t.domains` for constructor semantic values as we always produce the same default domain for them, that is a singleton without any explanation.
We don't need to perform an intersection in `Domain.update` as we always call it on domains that are subsets of the old ones.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there are still a couple places where constant entries into the map slip through the cracks but otherwise looks good 👍
src/lib/reasoners/enum_rel.ml
Outdated
match MX.find r t.domains with | ||
| _ -> t | ||
| exception Not_found -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
match MX.find r t.domains with | |
| _ -> t | |
| exception Not_found -> | |
if MX.mem r t.domains then t else |
src/lib/reasoners/enum_rel.ml
Outdated
(* We have to add a default domain if the key `r` isn't in map in order to | ||
be sure that the case-split mechanism will attempt to choose a value | ||
for it. *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is only true if r
is not a constructor, no? We ignore Cons
values in both case_split
and get
so I don't think entries for them are ever used.
src/lib/reasoners/enum_rel.ml
Outdated
| exception Not_found -> d | ||
in | ||
let t = remove r t in | ||
internal_update nr nnd t |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update
should be used rather than internal_update
to avoid adding unnecessary explanations (and also avoid storing domains for constants)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we don't store at all domains for the constructor, we should use get
in subst
as follows to get the appropriate
intersection:
let subst ~ex r nr t =
match MX.find r t.domains with
| d ->
let nd = Domain.intersect ~ex d (get nr t) in
let t = remove r t in
update nr nd t
| exception Not_found -> t
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah right! In fact this:
let nnd =
match MX.find nr t.domains with
| nd -> Domain.intersect ~ex d nd
| exception Not_found -> d
in
was a soundness bug because update
does not intersect and so we lose the explanation ex
if nr
is not in t.domains
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also rename update
into tighten
. update
isn't a meaningful name.
This PR refactors the `Adt` relations in order to use a proper type for the domains of enum semantic values. See PR OCamlPro#1078
This PR refactors the `Adt` relations in order to use a proper type for the domains of enum semantic values. See PR OCamlPro#1078
This PR refactors the `Adt` relations in order to use a proper type for the domains of enum semantic values. See PR OCamlPro#1078
This PR refactors the `Adt` relations in order to use a proper type for the domains of enum semantic values. See PR OCamlPro#1078
The PR OCamlPro#1078 introduces a soundness bug in `assume_distinct`. We have to propagate explanations of singleton domains, otherwise we may raise Inconsistency with an empty explanation. Add a test that caught the bug.
The PR #1078 introduces a soundness bug in `assume_distinct`. We have to propagate explanations of singleton domains, otherwise we may raise Inconsistency with an empty explanation. Add a test that caught the bug.
This PR refactors the `Adt` relations in order to use a proper type for the domains of enum semantic values. See PR OCamlPro#1078
This PR refactors the `Adt` relations in order to use a proper type for the domains of enum semantic values. See PR OCamlPro#1078
This PR refactors the `Adt` relations in order to use a proper type for the domains of enum semantic values. See PR OCamlPro#1078
This PR refactors the `Adt` relations in order to use a proper type for the domains of enum semantic values. See PR OCamlPro#1078
) This PR refactors the `Adt` relations in order to use a proper type for the domains of enum semantic values. See PR #1078
CHANGES: ### Command-line interface - Enable FPA theory by default (OCamlPro/alt-ergo#1177) - Remove deprecated output channels (OCamlPro/alt-ergo#782) - Deprecate the --use-underscore since it produces models that are not SMT-LIB compliant (OCamlPro/alt-ergo#805) - Add --dump-models-on to dump models on a specific output channel (OCamlPro/alt-ergo#838) - Use consistent return codes (OCamlPro/alt-ergo#842) - Add --continue-on-error flag to set the SMT-LIB error behavior (OCamlPro/alt-ergo#853) - Make dolmen the default value for the --frontend option (OCamlPro/alt-ergo#857) - Restore functionality to broken `--profiling` option (OCamlPro/alt-ergo#947) - Add bare-bones support for interactive input in SMT-LIB format (OCamlPro/alt-ergo#949) - Less confusing behavior on timeout (OCamlPro/alt-ergo#982, OCamlPro/alt-ergo#984) - Add `--strict` option for SMT-LIB compliant mode (OCamlPro/alt-ergo#916, OCamlPro/alt-ergo#1133) - Deprecate `sum`, `typing` and `warnings` debug flags (OCamlPro/alt-ergo#1204) ### SMT-LIB support - Add support for the many new SMT-LIB commands (OCamlPro/alt-ergo#837, OCamlPro/alt-ergo#848, OCamlPro/alt-ergo#852, OCamlPro/alt-ergo#863, OCamlPro/alt-ergo#911, OCamlPro/alt-ergo#942, OCamlPro/alt-ergo#945, OCamlPro/alt-ergo#961, OCamlPro/alt-ergo#975, OCamlPro/alt-ergo#1069) - Expose the FPA rounding builtin in the SMT-LIB format (OCamlPro/alt-ergo#876, OCamlPro/alt-ergo#1135) - Allow changing the SAT solver using (set-option) (OCamlPro/alt-ergo#880) - Add support for the `:named` attribute (OCamlPro/alt-ergo#957) - Add support for quoted identifiers (OCamlPro/alt-ergo#909, OCamlPro/alt-ergo#972) - Add support for naming lemmas in SMT-LIB syntax (OCamlPro/alt-ergo#1141, OCamlPro/alt-ergo#1143) ### Model generation - Use post-solve SAT environment in model generation, fixing issues where incorrect models were generated (OCamlPro/alt-ergo#789) - Restore support for records in models (OCamlPro/alt-ergo#793) - Use abstract values instead of dummy values in models where the actual value does not matter (OCamlPro/alt-ergo#804, OCamlPro/alt-ergo#835) - Use fresh names for all abstract values to prevent accidental captures (OCamlPro/alt-ergo#811) - Add support for model generation with the default CDCL solver (OCamlPro/alt-ergo#829) - Support model generation for the BV theory (OCamlPro/alt-ergo#841, OCamlPro/alt-ergo#968) - Add support for optimization (MaxSMT / OptiSMT) with lexicographic Int and Real objectives (OCamlPro/alt-ergo#861, OCamlPro/alt-ergo#921) - Add a SMT-LIB printer for expressions (OCamlPro/alt-ergo#952, OCamlPro/alt-ergo#981, OCamlPro/alt-ergo#1082, OCamlPro/alt-ergo#931, OCamlPro/alt-ergo#932) - Ensure models have a value for all constants in the problem (OCamlPro/alt-ergo#1019) - Fix a rare soundness issue with integer constraints when model generation is enabled (OCamlPro/alt-ergo#1025) - Support model generation for the ADT theory (OCamlPro/alt-ergo#1093, OCamlPro/alt-ergo#1153) ### Theory reasoning - Add word-level propagators for the BV theory (OCamlPro/alt-ergo#944, OCamlPro/alt-ergo#1004, OCamlPro/alt-ergo#1007, OCamlPro/alt-ergo#1010, OCamlPro/alt-ergo#1011, OCamlPro/alt-ergo#1012, OCamlPro/alt-ergo#1040, OCamlPro/alt-ergo#1044, OCamlPro/alt-ergo#1054, OCamlPro/alt-ergo#1055, OCamlPro/alt-ergo#1056, OCamlPro/alt-ergo#1057, OCamlPro/alt-ergo#1065, OCamlPro/alt-ergo#1073, OCamlPro/alt-ergo#1144, OCamlPro/alt-ergo#1152) - Add interval domains and arithmetic propagators for the BV theory (OCamlPro/alt-ergo#1058, OCamlPro/alt-ergo#1083, OCamlPro/alt-ergo#1084, OCamlPro/alt-ergo#1085) - Native support for bv2nat of bit-vector normal forms (OCamlPro/alt-ergo#1154) - Fix incompleteness issues in the BV solver (OCamlPro/alt-ergo#978, OCamlPro/alt-ergo#979) - Abstract more arguments of AC symbols to avoid infinite loops when they contain other AC symbols (OCamlPro/alt-ergo#990) - Do not make irrelevant decisions in CDCL solver, improving performance slightly (OCamlPro/alt-ergo#1041) - Rewrite the ADT theory to use domains and integrate the enum theory into the ADT theory (OCamlPro/alt-ergo#1078, OCamlPro/alt-ergo#1086, OCamlPro/alt-ergo#1087, OCamlPro/alt-ergo#1091, OCamlPro/alt-ergo#1094, OCamlPro/alt-ergo#1138) - Rewrite the Intervals module entirely (OCamlPro/alt-ergo#1108) - Add maximize/minimize terms for matching (OCamlPro/alt-ergo#1166) - Internalize `sign_extend` and `repeat` (OCamlPro/alt-ergo#1192) - Run cross-propagators to completion (OCamlPro/alt-ergo#1221) - Support binary distinct on arbitrary bit-widths (OCamlPro/alt-ergo#1222) - Only perform optimization when building a model (OCamlPro/alt-ergo#1224) - Make sure domains do not overflow the default domain (OCamlPro/alt-ergo#1225) - Do not build unnormalized values in `zero_extend` (OCamlPro/alt-ergo#1226) ### Internal/library changes - Rewrite the Vec module (OCamlPro/alt-ergo#607) - Move printer definitions closer to type definitions (OCamlPro/alt-ergo#808) - Mark proxy names as reserved (OCamlPro/alt-ergo#836) - Use a Zarith-based representation for numbers and bit-vectors (OCamlPro/alt-ergo#850, OCamlPro/alt-ergo#943) - Add native support for (bvnot) in the BV solver (OCamlPro/alt-ergo#856) - Add constant propagators for partially interpreted functions (OCamlPro/alt-ergo#869) - Remove `Util.failwith` in favor of `Fmt.failwith` (OCamlPro/alt-ergo#872) - Add more `Expr` smart constructors (OCamlPro/alt-ergo#877, OCamlPro/alt-ergo#878) - Do not use existential variables for integer division (OCamlPro/alt-ergo#881) - Preserve `Subst` literals to prevent accidental incompleteness (OCamlPro/alt-ergo#886) - Properly start timers (OCamlPro/alt-ergo#924) - Compute a concrete representation of a model instead of performing (OCamlPro/alt-ergo#925) - Allow direct access to the SAT API in the Alt-Ergo library computations during printing (OCamlPro/alt-ergo#927) - Better handling for step limit (OCamlPro/alt-ergo#936) - Add a generic option manager to deal with the dolmen state (OCamlPro/alt-ergo#951) - Expose an imperative SAT API in the Alt-Ergo library (OCamlPro/alt-ergo#962) - Keep track of the SMT-LIB mode (OCamlPro/alt-ergo#971) - Add ability to decide on semantic literals (OCamlPro/alt-ergo#1027, OCamlPro/alt-ergo#1118) - Preserve trigger order when parsing quantifiers with multiple trigger (OCamlPro/alt-ergo#1046). - Store domains inside the union-find module (OCamlPro/alt-ergo#1119) - Remove some polymorphic hashtables (OCamlPro/alt-ergo#1219) ### Build and integration - Drop support for OCaml <4.08.1 (OCamlPro/alt-ergo#803) - Use dune-site for the inequalities plugins. External pluginsm ust now be registered through the dune-site plugin mechanism in the `(alt-ergo plugins)` site to be picked up by Alt-Ergo (OCamlPro/alt-ergo#1049). - Add a release workflow (OCamlPro/alt-ergo#827) - Add a Windows workflow (OCamlPro/alt-ergo#1203) - Mark the dune.inc file as linguist-generated to avoid huge diffs (OCamlPro/alt-ergo#830) - Use GitHub Actions badges in the README (OCamlPro/alt-ergo#882) - Use `dune build @check` to build the project (OCamlPro/alt-ergo#887) - Enable warnings as errors on the CI (OCamlPro/alt-ergo#888) - Uniformization of internal identifiers generation (OCamlPro/alt-ergo#905, OCamlPro/alt-ergo#918) - Use an efficient `String.starts_with` implementation (OCamlPro/alt-ergo#912) - Fix the Makefile (OCamlPro/alt-ergo#914) - Add `Logs` dependency (OCamlPro/alt-ergo#1206) - Use `dynamic_include` to include the generated file `dune.inc` (OCamlPro/alt-ergo#1199) - Support Windows (OCamlPro/alt-ergo#1184,OCamlPro/alt-ergo#1189,OCamlPro/alt-ergo#1195,OCamlPro/alt-ergo#1199,OCamlPro/alt-ergo#1200) - Wrap the library `Alt_ergo_prelude` (OCamlPro/alt-ergo#1223) ### Testing - Use --enable-assertions in tests (OCamlPro/alt-ergo#809) - Add a test for push/pop (OCamlPro/alt-ergo#843) - Use the CDCL solver when testing model generation (OCamlPro/alt-ergo#938) - Do not test .smt2 files with the legacy frontend (OCamlPro/alt-ergo#939) - Restore automatic creation of .expected files (OCamlPro/alt-ergo#941) ### Documentation - Add a new example for model generation (OCamlPro/alt-ergo#826) - Add a Pygments lexer for the Alt-Ergo native language (OCamlPro/alt-ergo#862) - Update the current authors (OCamlPro/alt-ergo#865) - Documentation of the `Enum` theory (OCamlPro/alt-ergo#871) - Document `Th_util.lit_origin` (OCamlPro/alt-ergo#915) - Document the CDCL-Tableaux solver (OCamlPro/alt-ergo#995) - Document Windows support (OCamlPro/alt-ergo#1216) - Remove instructions to install Alt-Ergo on Debian (OCamlPro/alt-ergo#1217) - Document optimization feature (OCamlPro/alt-ergo#1231)
CHANGES: ### Command-line interface - Enable FPA theory by default (OCamlPro/alt-ergo#1177) - Remove deprecated output channels (OCamlPro/alt-ergo#782) - Deprecate the --use-underscore since it produces models that are not SMT-LIB compliant (OCamlPro/alt-ergo#805) - Add --dump-models-on to dump models on a specific output channel (OCamlPro/alt-ergo#838) - Use consistent return codes (OCamlPro/alt-ergo#842) - Add --continue-on-error flag to set the SMT-LIB error behavior (OCamlPro/alt-ergo#853) - Make dolmen the default value for the --frontend option (OCamlPro/alt-ergo#857) - Restore functionality to broken `--profiling` option (OCamlPro/alt-ergo#947) - Add bare-bones support for interactive input in SMT-LIB format (OCamlPro/alt-ergo#949) - Less confusing behavior on timeout (OCamlPro/alt-ergo#982, OCamlPro/alt-ergo#984) - Add `--strict` option for SMT-LIB compliant mode (OCamlPro/alt-ergo#916, OCamlPro/alt-ergo#1133) - Deprecate `sum`, `typing` and `warnings` debug flags (OCamlPro/alt-ergo#1204) ### SMT-LIB support - Add support for the many new SMT-LIB commands (OCamlPro/alt-ergo#837, OCamlPro/alt-ergo#848, OCamlPro/alt-ergo#852, OCamlPro/alt-ergo#863, OCamlPro/alt-ergo#911, OCamlPro/alt-ergo#942, OCamlPro/alt-ergo#945, OCamlPro/alt-ergo#961, OCamlPro/alt-ergo#975, OCamlPro/alt-ergo#1069) - Expose the FPA rounding builtin in the SMT-LIB format (OCamlPro/alt-ergo#876, OCamlPro/alt-ergo#1135) - Allow changing the SAT solver using (set-option) (OCamlPro/alt-ergo#880) - Add support for the `:named` attribute (OCamlPro/alt-ergo#957) - Add support for quoted identifiers (OCamlPro/alt-ergo#909, OCamlPro/alt-ergo#972) - Add support for naming lemmas in SMT-LIB syntax (OCamlPro/alt-ergo#1141, OCamlPro/alt-ergo#1143) ### Model generation - Use post-solve SAT environment in model generation, fixing issues where incorrect models were generated (OCamlPro/alt-ergo#789) - Restore support for records in models (OCamlPro/alt-ergo#793) - Use abstract values instead of dummy values in models where the actual value does not matter (OCamlPro/alt-ergo#804, OCamlPro/alt-ergo#835) - Use fresh names for all abstract values to prevent accidental captures (OCamlPro/alt-ergo#811) - Add support for model generation with the default CDCL solver (OCamlPro/alt-ergo#829) - Support model generation for the BV theory (OCamlPro/alt-ergo#841, OCamlPro/alt-ergo#968) - Add support for optimization (MaxSMT / OptiSMT) with lexicographic Int and Real objectives (OCamlPro/alt-ergo#861, OCamlPro/alt-ergo#921) - Add a SMT-LIB printer for expressions (OCamlPro/alt-ergo#952, OCamlPro/alt-ergo#981, OCamlPro/alt-ergo#1082, OCamlPro/alt-ergo#931, OCamlPro/alt-ergo#932) - Ensure models have a value for all constants in the problem (OCamlPro/alt-ergo#1019) - Fix a rare soundness issue with integer constraints when model generation is enabled (OCamlPro/alt-ergo#1025) - Support model generation for the ADT theory (OCamlPro/alt-ergo#1093, OCamlPro/alt-ergo#1153) ### Theory reasoning - Add word-level propagators for the BV theory (OCamlPro/alt-ergo#944, OCamlPro/alt-ergo#1004, OCamlPro/alt-ergo#1007, OCamlPro/alt-ergo#1010, OCamlPro/alt-ergo#1011, OCamlPro/alt-ergo#1012, OCamlPro/alt-ergo#1040, OCamlPro/alt-ergo#1044, OCamlPro/alt-ergo#1054, OCamlPro/alt-ergo#1055, OCamlPro/alt-ergo#1056, OCamlPro/alt-ergo#1057, OCamlPro/alt-ergo#1065, OCamlPro/alt-ergo#1073, OCamlPro/alt-ergo#1144, OCamlPro/alt-ergo#1152) - Add interval domains and arithmetic propagators for the BV theory (OCamlPro/alt-ergo#1058, OCamlPro/alt-ergo#1083, OCamlPro/alt-ergo#1084, OCamlPro/alt-ergo#1085) - Native support for bv2nat of bit-vector normal forms (OCamlPro/alt-ergo#1154) - Fix incompleteness issues in the BV solver (OCamlPro/alt-ergo#978, OCamlPro/alt-ergo#979) - Abstract more arguments of AC symbols to avoid infinite loops when they contain other AC symbols (OCamlPro/alt-ergo#990) - Do not make irrelevant decisions in CDCL solver, improving performance slightly (OCamlPro/alt-ergo#1041) - Rewrite the ADT theory to use domains and integrate the enum theory into the ADT theory (OCamlPro/alt-ergo#1078, OCamlPro/alt-ergo#1086, OCamlPro/alt-ergo#1087, OCamlPro/alt-ergo#1091, OCamlPro/alt-ergo#1094, OCamlPro/alt-ergo#1138) - Rewrite the Intervals module entirely (OCamlPro/alt-ergo#1108) - Add maximize/minimize terms for matching (OCamlPro/alt-ergo#1166) - Internalize `sign_extend` and `repeat` (OCamlPro/alt-ergo#1192) - Run cross-propagators to completion (OCamlPro/alt-ergo#1221) - Support binary distinct on arbitrary bit-widths (OCamlPro/alt-ergo#1222) - Only perform optimization when building a model (OCamlPro/alt-ergo#1224) - Make sure domains do not overflow the default domain (OCamlPro/alt-ergo#1225) - Do not build unnormalized values in `zero_extend` (OCamlPro/alt-ergo#1226) ### Internal/library changes - Rewrite the Vec module (OCamlPro/alt-ergo#607) - Move printer definitions closer to type definitions (OCamlPro/alt-ergo#808) - Mark proxy names as reserved (OCamlPro/alt-ergo#836) - Use a Zarith-based representation for numbers and bit-vectors (OCamlPro/alt-ergo#850, OCamlPro/alt-ergo#943) - Add native support for (bvnot) in the BV solver (OCamlPro/alt-ergo#856) - Add constant propagators for partially interpreted functions (OCamlPro/alt-ergo#869) - Remove `Util.failwith` in favor of `Fmt.failwith` (OCamlPro/alt-ergo#872) - Add more `Expr` smart constructors (OCamlPro/alt-ergo#877, OCamlPro/alt-ergo#878) - Do not use existential variables for integer division (OCamlPro/alt-ergo#881) - Preserve `Subst` literals to prevent accidental incompleteness (OCamlPro/alt-ergo#886) - Properly start timers (OCamlPro/alt-ergo#924) - Compute a concrete representation of a model instead of performing (OCamlPro/alt-ergo#925) - Allow direct access to the SAT API in the Alt-Ergo library computations during printing (OCamlPro/alt-ergo#927) - Better handling for step limit (OCamlPro/alt-ergo#936) - Add a generic option manager to deal with the dolmen state (OCamlPro/alt-ergo#951) - Expose an imperative SAT API in the Alt-Ergo library (OCamlPro/alt-ergo#962) - Keep track of the SMT-LIB mode (OCamlPro/alt-ergo#971) - Add ability to decide on semantic literals (OCamlPro/alt-ergo#1027, OCamlPro/alt-ergo#1118) - Preserve trigger order when parsing quantifiers with multiple trigger (OCamlPro/alt-ergo#1046). - Store domains inside the union-find module (OCamlPro/alt-ergo#1119) - Remove some polymorphic hashtables (OCamlPro/alt-ergo#1219) ### Build and integration - Drop support for OCaml <4.08.1 (OCamlPro/alt-ergo#803) - Use dune-site for the inequalities plugins. External pluginsm ust now be registered through the dune-site plugin mechanism in the `(alt-ergo plugins)` site to be picked up by Alt-Ergo (OCamlPro/alt-ergo#1049). - Add a release workflow (OCamlPro/alt-ergo#827) - Add a Windows workflow (OCamlPro/alt-ergo#1203) - Mark the dune.inc file as linguist-generated to avoid huge diffs (OCamlPro/alt-ergo#830) - Use GitHub Actions badges in the README (OCamlPro/alt-ergo#882) - Use `dune build @check` to build the project (OCamlPro/alt-ergo#887) - Enable warnings as errors on the CI (OCamlPro/alt-ergo#888) - Uniformization of internal identifiers generation (OCamlPro/alt-ergo#905, OCamlPro/alt-ergo#918) - Use an efficient `String.starts_with` implementation (OCamlPro/alt-ergo#912) - Fix the Makefile (OCamlPro/alt-ergo#914) - Add `Logs` dependency (OCamlPro/alt-ergo#1206) - Use `dynamic_include` to include the generated file `dune.inc` (OCamlPro/alt-ergo#1199) - Support Windows (OCamlPro/alt-ergo#1184,OCamlPro/alt-ergo#1189,OCamlPro/alt-ergo#1195,OCamlPro/alt-ergo#1199,OCamlPro/alt-ergo#1200) - Wrap the library `Alt_ergo_prelude` (OCamlPro/alt-ergo#1223) ### Testing - Use --enable-assertions in tests (OCamlPro/alt-ergo#809) - Add a test for push/pop (OCamlPro/alt-ergo#843) - Use the CDCL solver when testing model generation (OCamlPro/alt-ergo#938) - Do not test .smt2 files with the legacy frontend (OCamlPro/alt-ergo#939) - Restore automatic creation of .expected files (OCamlPro/alt-ergo#941) ### Documentation - Add a new example for model generation (OCamlPro/alt-ergo#826) - Add a Pygments lexer for the Alt-Ergo native language (OCamlPro/alt-ergo#862) - Update the current authors (OCamlPro/alt-ergo#865) - Documentation of the `Enum` theory (OCamlPro/alt-ergo#871) - Document `Th_util.lit_origin` (OCamlPro/alt-ergo#915) - Document the CDCL-Tableaux solver (OCamlPro/alt-ergo#995) - Document Windows support (OCamlPro/alt-ergo#1216) - Remove instructions to install Alt-Ergo on Debian (OCamlPro/alt-ergo#1217) - Document optimization feature (OCamlPro/alt-ergo#1231)
This PR refactors the
Enum
relations in order to use a proper typefor the domains of enum semantic values.
Now, we only store domains for class representatives and I believe that the new
implementation is simpler to understand and to maintain.
I don't use the functor
Domains_make
ofRel_utils
as domain'spropagations performed in
Enum_rel
are much simpler than the propagations inthe BV theory.