-
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
Clean up OptimAE #921
Clean up OptimAE #921
Conversation
72c682d
to
5891fd2
Compare
23f0bba
to
4188d71
Compare
6e56cbb
to
cb6d88a
Compare
a357a75
to
28c6ba6
Compare
Uhm, I thought it was a good idea to hide completely the priority order in the objective model but in fact, users could feed AE with a file like this one:
With the current implementation, the second
Another tricky example is if we use both |
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.
Uhm, I thought it was a good idea to hide completely the priority order in the objective model but in fact, users could feed AE with a file like this one:
[..]
Another tricky example is if we use both maximize and minimize on the same expression. The second one is ignored. Should we print a warning?
Yeah, I was going to make a remark on that. We shouldn't print a warning, we should print all the objectives requested by the user in the correct order!
(We might want to also print a warning when we perform optimization under an unbounded/strict objective, which should only occur during model generation if I understand correctly)
Not sure how that's tricky — wouldn't removing the test for an existing function in Objective.Model.add
just do The Right Thing™?
src/lib/frontend/frontend.ml
Outdated
@@ -429,6 +437,8 @@ module Make(SAT : Sat_solver_sig.S) : S with type sat_env = SAT.t = struct | |||
|
|||
let th_assume = wrap_f internal_th_assume | |||
|
|||
let optimize = handle_sat_exn internal_optimize |
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 needs to be wrap_f
, not handle_sat_exn
to avoid using an invalid satML environment (see #946 and related issues).
src/lib/frontend/models.ml
Outdated
@@ -604,4 +575,3 @@ let output_concrete_model fmt m = | |||
(* SmtlibCounterExample.output_arrays_counterexample fmt m.arrays; *) | |||
|
|||
Printer.print_fmt fmt "@]@,)"; |
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.
Printer.print_fmt fmt "@]@,)"; | |
Printer.print_fmt fmt "@]@,)" |
| Unknown -> true | ||
| _ -> false | ||
); | ||
let uf, _ = Uf.add uf e 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.
This does not seem right; we don't return the uf
so the added repr is lost.
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.
Uhm, I don't think we need to keep the representative element here. The expression e
here isn't a part of our problem but the expression we try to optimize modulo our constraints. Now, I remember why I add this line before
let repr, _ = Uf.find uf e in
The reason is because the function Uf.find
fails if the expression have never been added to the union-find before. As the expression can be something completely new, this can happen. Consider for instance the input file:
(set-logic ALL)
(set-option :produce-models true)
(declare-const x Int)
(assert (<= x 10))
(maximize (+ x 5))
(check-sat)
(get-model)
(get-objectives)
The expression (+ x 5)
is completely new and the union-find will raise Not_found
exception here.
Now if the expression is already knew, we want to get both its representative in the union-find (in the code it's repr
) and the semantic values returned by X.make
for this expression (in the code it's r1
).
Another solution would be add the expression e
in the union-find when we call the function optimize
of the SAT solver.
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 want to get the representative if there is one or the result of X.make
otherwise then the right code is probably along the lines of:
let repr, r1 =
match Uf.find uf e with
| repr, _ -> repr, Uf.make uf e
| exception Not_found -> let r, _ = X.make e in r, r
That said, I didn't think about it, but you are right — we should add e
in the call to optimize
(this is what was done before when Optimize
was a symbol). Note that this needs to use Theory.add_term
to make sure that all sub-terms are properly added (Uf.add
only adds the term itself but not the subterms).
The real reason to do this is that if we do (maximize (bv2nat x))
for instance, and the problem does not otherwise contain (bv2nat x)
, not adding bv2nat
to the theory would lose some reasoning power (because it would not be seen by the relations, and knowledge about it would not be properly propagated).
@@ -2045,17 +2045,35 @@ let case_split env uf ~for_model = | |||
end | |||
| _ -> res | |||
|
|||
let optimizing_split env uf opt_split = | |||
(* Helper function used in [optimizing_objective] to pick a value | |||
for the polynomial [p] in its interval. We used this function in the case |
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.
for the polynomial [p] in its interval. We used this function in the case | |
for the polynomial [p] in its interval. We use this function in the case |
src/lib/reasoners/theory.ml
Outdated
(* let objectives, reset_cs_env = | ||
update_objectives t.objectives assumed gamma 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.
Why is this no longer needed? What happens if an assertion renders an existing objective invalid?
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.
The purpose of update_objectives
function was to ensure we add new optimization discovered while exploring a term. At this time, we could have optimization everywhere in formulae. In particular, it means the theory module could ignore an optimization constraint before the underlying formula was involved in a formula of the current trail of the SAT solver. I didn't check, but I guess we could even forget an optimization constraint by backtracking.
If we discover a new constraint, we have to throw away all the case splits. A flag in update_objectives
was used to remember that and we call reset_case_split_env
if the flag is up.
Now, we feed the SAT solver with all the optimization constraints at once. I thought it was fine but in fact we perform case splits after each assume. Thus we have to reset casesplits after each optimize
in Theory
.
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 I did! I just forget to remove the dead code commented. :) Thanks for the remark. I will add a comment in optimize
.
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, update_objectives
is for adding new objectives — I mixed it up in my head with partial_objectives_reset
which is used when an objective becomes invalid, thanks for the clarification!
I thought it was fine but in fact we perform case splits after each assume.
Yeah, either after each assume or before matching or after matching depending on the split policy. After each assume is the most aggressive version tho, so I think if we deal with that properly we are good.
I didn't check, but I guess we could even forget an optimization constraint by backtracking.
Now, we feed the SAT solver with all the optimization constraints at once. I thought it was fine but in fact we perform case splits after each assume. Thus we have to reset casesplits after each optimize in Theory.
This remark makes me wonder: previously, we had optimizations in assertions, which are obviously stored in the assertion stack (and so would be normally affected by push
and pop
), but I am not sure that is still the case in this PR (I didn't see any mechanism that would take care of it, but also was not aware it could be an issue prior to your comment). Might be worth checking -- for instance the following should output 0
, not 10
.
(set-option :produce-models true)
(set-logic ALL)
(declare-const x Int)
(assert (<= 0 x 10))
(push 1)
(maximize x)
(pop 1)
(minimize x)
(check-sat)
(get-model)
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.
Uhm I thought it was fine because I use the same semantic as the assert but I probably miss something in solving_loop
. Thanks for the test.
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 dang, I take it that means it does not work then :/ I think it is probably an issue in the Satml_frontend
/ Satml
rather than solving_loop
. The way push
and pop
work in the Satml solver is that we create guards, and assertions within a push/pop assertions are, well, guarded: if the guard is false, the assertion is just ignored.
So for instance the following:
(push 1)
(assert f1)
(check-sat)
is treated as if we had:
(declare-const guard Bool)
(assert (=> guard f1))
(assert guard) ; Generated for all assertions levels that were not popped on (check-sat)
(check-sat)
and the following:
(push 1)
(assert f1)
(pop 1)
(check-sat)
is treated as if we had:
(declare-const guard Bool)
(assert (=> guard f1))
(assert (not guard)) ; Generated on (pop 1)
(check-sat)
and so Th.assume
(which is called during propagation) will never be called on f1
. But I believe that with the current implementation (from my recollection of it, I did not check in detail) we will always call optimize
without taking the guards into account.
In the previous implementation this "just worked" because optimization markers were expressions inside assertions that were not assume
d when the guards are false, but now that optimization markers are declarations there is a little bit more work that needs to be duplicated. In fact there is probably a bit of overlap with #901, now that I think about it.
Given that optimization is still experimental (and that you've said you're sick of working on it for so long, which is understandable :) ), I think dropping support for optimization within push/pop in this PR is acceptable. We can then either deal with that as part of #901 (which I think is on track for inclusion in the next release, since postponing #904 freed up quite some time for me) or otherwise in a separate PR; your 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.
I think I'll take it after we solve #901. I'll print a warning if we try to optimize with push
and pop
. An error isn't necessary here as we still got a correct model but we don't respect the optimization constraint.
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 open an issue #933 and add a warning when we process files involving both optimization constraints and pop
and push
.
src/lib/reasoners/theory.ml
Outdated
in | ||
aux env sem_facts (List.rev env.choices) new_choices | ||
aux env sem_facts (List.rev env.choices) | ||
(Objective.Model.functions env.objectives, 0) new_choices |
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.
Is starting at order 0
here really correct? What if some objectives have been optimized already?
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.
Hm actually it looks like we are optimizing all objectives again at each case split, that looks wasteful (possibly incorrect, but I don't think so since we use equalities for the splits).
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.
Let's clarify a bit the previous behaviour and the current one.
- Before this PR, the function
look_for_sat
proceeds choices in this order whenfor_model = false
:- First, it propagates new choices in the pending queue.
- Then it try to optimize as much as it can objectives for which we didn't get a best value yet (in the current SAT branch of course). If it see an objective whose the previous value is a limit (+oo, -oo or a strict bound), it tries to optimize it again.
- If we fail to optimize a bound, we stop in
optimizing_objective
. - Otherwise, it asks theories to generate new case splits and it goes back to the first point.
Now, if we're generating model (so for_model = true
), the previous code ignore objectives whose the value is a limit and we keep optimize next objectives (with a lower priority).
This is not what we want. If we got a limit for some objective o
, it doesn't make sense to try to optimize objectives with lower priority than o
. But in model generation, we want to keep generating model, even if we can fulfill some objectives.
Let's pick an example:
(set-option :produce-models true)
(set-logic ALL)
(declare-const x Int)
(declare-const y Int)
(maximize x)
(minimize y)
(assert (>= y (- 10)))
(assert (>= x 0))
(check-sat)
(get-model)
(assert (<= x 10))
(check-sat)
(get-model)
If you run AE next
on it with the command
dune exec -- alt-ergo test.smt2 --optimize --objctives-in-interpretation --frontend legacy --dump-models
AE outputs:
unknown
Returned unknown reason = Incomplete
(
(define-fun x () Int +oo)
(define-fun y () Int (- 10))
)
unknown
Returned unknown reason = Incomplete
(
(define-fun x () Int 10)
(define-fun y () Int (- 10))
)
We don't expect that AE keep optimizing objectives after x
before the first check-sat
, but we keep doing it...
Now, if we don't the same on this PR with the command
dune exec -- alt-ergo test2.smt2 --optimize --objectives-in-interpretation
AE outputs:
unknown
(
(define-fun x () Int 1)
(define-fun y () Int 0)
)
; File "test2.smt2", line 12, characters 1-12: I don't know (0.0009) (6 steps) (goal g_2)
unknown
(
(define-fun x () Int 10)
(define-fun y () Int (- 10))
)
The new code does the right thing... by chance! It's because during each case split phase, we do again all the optimizations, even if we got an infinity value before and we stop optimization if we got an infinity value in optimizing_objective
. If the flag for_model
is true
, we stop also optimization but we keep generate new casesplits.
I add a new function next_unknown
in Objective.Model
whose the semantic is closed to the old next_optimization
:
exception Found of Function.t * int
let next_unknown mdl =
try
M.iter (fun { f; order } v ->
match (v : Value.t) with
| Value _ -> ()
| Pinfinity | Minfinity | Limit _ -> raise Exit
| _ -> raise (Found (f, order))
) mdl;
None
with
| Found (f, order) -> Some (f, order)
| Exit -> None
Notice this function isn't very efficient because we keep visiting Value
node in the map again and again. The behaviour of Objective.Model
is basically a queue with some printers. I guess I will rewrite it with a functional queue but let's keep map now, early optimization is risky.
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.
Ok, it's still incorrect for this test:
; This test checks if the optimization doesn't stop after trying to
; optimize a strict bound.
(set-option :produce-models true)
(set-logic ALL)
(declare-const x Real)
(declare-const y Real)
; If the SAT solver explores first the right branch of the following OR gate, it
; shouldn't conclude that x cannot be optimized.
(assert (or (<= x 4.0) (< x 1.5)))
(maximize x)
; The current implementation of SatML explores the right branch of OR gates
; first. We add the following line to be sure the optimization feature still
; works after changing the order of branches.
(assert (or (< y 1.5) (<= y 4.0)))
(maximize y)
(check-sat)
(get-model)
(get-objectives)
During the first assert we don't know that y
will be bound and we get infinity
here. Thus, we have to treat infinity value again after the second assert, otherwise we will print +oo
for y
. This was explained in a comment of the original OptimAE PR.
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.
We don't expect that AE keeps optimize value after
x
after the firstcheck-sat
, but we keep doing it...
I disagree: in that case I fully expect alt-ergo to re-optimize the model because of the new get-sat
and the new constraints added by assert
since the last check-sat
!
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.
Ok my example is ambiguous. I was talking of the first check-sat
only. I totally agree we have to keep optimize if new constraints are involved.
src/lib/reasoners/theory.ml
Outdated
we continue to produce a model if the flag [for_model] is up. *) | ||
if for_model then | ||
aux env sem_facts acc_choices [] | ||
aux env sem_facts acc_choices ([], 0) [] |
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 this is a behavior change — previously we would keep optimizing further objectives while doing model generation, but now we no longer does (this call to aux
goes immediately to generate_choices
). Is that intentional?
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.
Also as far as I can tell, this means that the case splits in the middle of intervals and the such that we create for infinite/limit cases are never used.
in the domain of the polynomial [p]. But we propagate the new | ||
value [value] for this objective. Indeed, we want to be able | ||
to print it while using the statement [get-objective]. *) | ||
middle_value env ~to_max ty p None |
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.
Same remark as above; are standard model generation mechanisms failing somehow?
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.
Before this PR, we use a wrapped case-split as input for this function and we have access to the last computed value for the first-order model through this wrapped case-split.
An alternative implementation would be to give this value as an argument of optimizing_objective
.
Notice that my middle_value
gives a value in the last interval (for the to_max = true
case) of the domain of the polynomial p
. You told me other solvers try to give a bigger value when we maximize strict bound.
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 this is for that! Makes sense. What I was thinking for that case (and what other solvers do I believe) is add an inequality constraint rather than an equality in case that specific value end up not being feasible. For instance, with a nonlinear objective x * x
with x in
1 .. 2range, the range for
x * xis
1 .. 4(AFAIK Alt-Ergo know this) but if we pick
2or
3as a value there is no model whereas if we just constrain
< 3or
> 2` it is.
(I think in this specific case we might go into an infinite loop in the current PR if we actually used this split in look_for_sat
, not sure)
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 I suggest to keep the code as it's now. We could make better change later.
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 I am fine with keeping that code as is for now, but the code in look_for_sat
needs to be fixed to actually use the split during model generation!
@@ -1,8 +1,11 @@ | |||
(set-logic ALL) | |||
(set-option :produce-models true) |
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 should happen before (set-logic ...)
) | ||
(objectives |
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.
As y cannot be optimized, I believe we should warn the user when he invokes (get-objectives)
This PR refactors the way we manage optimization constraints in Alt-Ergo. - Optimization constraints aren't tag on subformulas anymore. Instead we use the MaxSMT syntaxes. - We don't support optimization in Alt-Ergo native format. As this feature haven't been published, we don't need to deprecated it. - We support `maximize`, `minimize` and `get-objectives`. There is no support for `assert-soft`. I think it's out of the scope of this PR. - The SAT solver API exposes two new functions: `optimize` and `get_objectives` which, respectively, register objective function and return the current objective model. - The objective values are expressions.
The optimization constraint is wrong if we use it in incremental mode but it's safe if we use `maximize` and `minimize` at the top level only.
The value produced by `middle_value` in `intervalCalculus` wasn't propagate to the CC(X) module in `look_for_sat`. We propagate it now. I also modify the test `arith7.optimize.smt2` as we cannot use both incremental mode and optimization constraints.
We don't support yet impure terms or formulae in `maximize` and `minimize` statements. Let's print a warning message and ignoring invalid objective functions.
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 we are good with a couple minor omissions noted inline; please fix these before merging!
src/bin/common/solving_loop.ml
Outdated
@@ -350,6 +350,10 @@ let main () = | |||
State.create_key ~pipe:"" "named_terms" | |||
in | |||
|
|||
let has_incremental : int State.key = |
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 it's an int
, it should not be called has_incremental
. I guess two of my comments in the previous round somewhat contradicted each other. Maybe incremental_depth
?
src/bin/common/solving_loop.ml
Outdated
(State.get solver_ctx_key st).ctx stmt | ||
in | ||
(* Using both optimization and incremental mode may be wrong if | ||
some optimization constraints aren't at the toplevel. *) |
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.
Should have a link back to #993
Co-authored-by: Basile Clément <129742207+bclement-ocp@users.noreply.github.com>
Co-authored-by: Basile Clément <129742207+bclement-ocp@users.noreply.github.com>
Co-authored-by: Basile Clément <129742207+bclement-ocp@users.noreply.github.com>
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 way we manage optimization constraints in
Alt-Ergo.
we use the MaxSMT syntaxes.
feature haven't been published, we don't need to deprecated it.
maximize
,minimize
andget-objectives
. There is nosupport for
assert-soft
. I think it's out of the scope of this PR.Besides, it seems that
get-objectives
can take arguments in our current implementation ofSolving_loop
but I didn't findany examples using this syntax, thus I silently ignore these arguments.
optimize
andget_objectives
which, respectively, register objective function andreturn the current objective model.