-
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
Remove the Record
theory
#1095
base: next
Are you sure you want to change the base?
Remove the Record
theory
#1095
Conversation
0e0a6a1
to
3ba843d
Compare
117dfe2
to
1d30760
Compare
1d30760
to
4ac01de
Compare
2e54e7a
to
79099b0
Compare
Records
theory into ADT
theoryRecord
theory
As I expected, we got regressions if we do not produce a context in the (set-logic ALL)
(declare-datatype unit ((void)))
(declare-datatype t ((box (unbox unit))))
(declare-fun f (t t) Bool)
(assert (forall ((u t) (v t)) (f u (box (unbox v)))))
(assert (not (f (box void) (box void))))
(check-sat) We expect that If you modify the input file as follows: (set-logic ALL)
(declare-datatype unit ((void)))
(declare-datatype t ((box (unbox unit))))
(declare-fun f (t) Bool)
(assert (forall ((v t)) (f (box (unbox v)))))
(assert (not (f (box void))))
(check-sat) Alt-Ergo outputs Notice that there is specific code in (set-logic ALL)
(declare-datatype t ((c (b Bool))))
(declare-fun f (t) Bool)
(declare-const x t)
(assert (forall ((y Bool)) (f (c y))))
(assert (not (f x)))
(check-sat) Alt-Ergo outputs I removed this code in the present branch and did not write anything to replace it but still the test passes. It works for a good reason! First of all, the ADT |
75b2d25
to
31c4c66
Compare
In the last patch, I use the context of I am running benchmarks to check if this patch removes most of the regressions. Even if it does, I would prefer a solution without using the context of |
+55-12 on ae-format and the solver is slightly faster :) |
Okay, I was not completely satisfied by the last commit. It is sad to still use the context of Another way to solve this issue consists in eliminating as earlier as possible terms of the form
where If we replace it by:
Alt-Ergo should generate the trigger Actually, I tried another transformation:
It works if we disable some simplifications done in the smart constructor |
7d55bc9
to
20d966c
Compare
I think that this PR is now ready to review. I keep the current code with context in |
20d966c
to
08f5d40
Compare
08f5d40
to
16251af
Compare
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.
Looks good overall, but there are a few things that seem non-obvious to me that I'd like to see explained.
src/lib/reasoners/adt.ml
Outdated
if Compat.List.is_empty c_args then | ||
Fmt.pf ppf "%a" DE.Term.Const.print c_name | ||
else | ||
Fmt.pf ppf "(%a %a)" | ||
DE.Term.Const.print c_name | ||
Fmt.(box @@ list ~sep:sp @@ pair nop X.print) c_args | ||
|
||
| Select d -> | ||
Fmt.pf ppf "%a#!!%a" X.print d.d_arg DE.Term.Const.print d.d_name | ||
|
||
Fmt.pf ppf "(%a %a)" X.print d.d_arg DE.Term.Const.print d.d_name |
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 looks like it is an AE-style printer rather than an SMT-lib style printer, not sure it should be changed.
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.
It is a debug message, so we can print whatever we want. In my opinion, we should avoid using different formats for debug messaged based on the input format. We could use a similar printer than Dolmen for these debug messages. This modification contradicts with my own opinion (because infix notations are more readable) ;)
src/lib/reasoners/adt.ml
Outdated
let { E.f; xs; ty; _ } = E.term_view t in | ||
let sx, ctx = | ||
let ssx, ctx = |
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 should call this rev_rs
and rs
below to denote that they are semantic value -- ssx
and xxs
are not particularly readable names!
src/lib/reasoners/adt_rel.ml
Outdated
of the `Arith` and `Records` theories. The semantic | ||
values `cons` never involves such values. *) | ||
assert (Compat.List.is_empty ctx); | ||
let r', _ctx = X.make cons in | ||
let eq = Shostak.L.(view @@ mk_eq r r') in | ||
Some (eq, E.mk_constr c xs ty) |
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.
Some (eq, E.mk_constr c xs ty) | |
Some (eq, cons) |
(* In the current implementation of `X.make`, we produce | ||
a nonempty context only for interpreted semantic values | ||
of the `Arith` and `Records` theories. The semantic | ||
values `cons` never involves such values. *) | ||
assert (Compat.List.is_empty ctx); |
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 can't keep the assertion because now we create side conditions for ADTs (when they are records), but we shold keep a comment to explain why it is OK to ignore these side conditions.
(* In the current implementation of `X.make`, we produce | ||
a nonempty context only for interpreted semantic values | ||
of the `Arith` and `Records` theories. The semantic | ||
values `cons` never involves such values. *) | ||
assert (Compat.List.is_empty ctx); |
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 as above -- we should keep a comment why it is OK to ignore the second return value of X.make
.
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 put a link to the issue #1296
let { E.f = f; xs = xs; ty = ty; _ } = E.term_view t in | ||
if Symbols.compare f_pat f = 0 then xs::l | ||
else | ||
begin | ||
match f_pat, ty with | ||
| Symbols.Op (Symbols.Record), Ty.Trecord record -> | ||
(xs_modulo_records t record) :: l | ||
| _ -> l | ||
end |
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 not needed for records as ADTs?
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 previously explained in this PR why this piece of code is no longer necessary. I forgot about it too and investigated it again! I'm copying my explanation here with additional details:
The specific code in Matching is there to handle a corner case of the Record theory. For instance, consider the input file:
(set-logic ALL)
(declare-datatype t ((c (b Bool))))
(declare-fun f (t) Bool)
(declare-const x t)
(assert (forall ((y Bool)) (f (c y))))
(assert (not (f x)))
(check-sat)
Alt-Ergo outputs unsat on next and on this branch. On next, Alt-Ergo needs to match x
with (c y)
, as it is the pattern of the first axiom. We need to match modulo equality. But it does not know that x = (c (b x))
. This equation is only generated for record construction terms and x
is a variable. The function xs_modulo_records
adds the term (c (b x))
into the class of x
and Alt-Ergo produces the right instance.
I removed this code in the present branch and did not write anything to replace it but still the above test succeeds. It works for a good reason!
First of all, the ADT x
is sent to Adt_rel
thanks to the new function init
in Uf
.
Since t
is a record type, we immediately obtain a domain of size 1 for x
and we produce a fresh boolean term k and the equality x = (c k)
. Of course (c k)
is the new representative element and we can match it against the pattern of the axiom.
name : DE.ty_cst; | ||
mutable lbs : (DE.term_cst * t) list; | ||
record_constr : DE.term_cst; | ||
(* for ADTs that become records. default 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.
Can't say I am sad to see this one go.
| "tableaux" -> | ||
{acc with filters = Some ["tableaux"]} |
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 seem to remember the difference between Tableaux and CDCL went away when adding the field equations to the context — is it not the case?
If not, a comment should be added to the test to explain why it is failing with CDCL.
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.
Good catch. It is a regression. The test:
(set-logic ALL)the
(declare-datatype t ((B (i Int))))
(declare-const e t)
(assert ((_ is B) e))
(assert (forall ((n Int)) (distinct e (B n))))
(check-sat)
succeeds on next but fails on this branch. Note that this input file is very closed to issue #1295 but (assert ((_ is B) e)
is a ground constraint on e
. Currently, this branch manages to discover the equality e = (B .k)
for a fresh integer .k
but the new term (B .k)
never reaches the matching environment. More precisely, the new term is discarded here:
alt-ergo/src/lib/reasoners/satml.ml
Lines 1084 to 1099 in 837293e
try | |
(*let full_model = nb_assigns() = nb_vars () in*) | |
(* XXX what to do with the other results of Th.assume ? *) | |
let t,_,cpt = | |
Th.assume ~ordered:false | |
(List.rev facts) env.unit_tenv | |
in | |
Steps.incr (Steps.Th_assumed cpt); | |
env.unit_tenv <- t; | |
C_none | |
with Ex.Inconsistent (dep, _terms) -> | |
(* XXX what to do with terms ? *) | |
(* Printer.print_dbg | |
"th inconsistent : %a @." Ex.print dep; *) | |
if Options.get_profiling() then Profiling.theory_conflict(); | |
C_theory dep |
In tableaux, all the new terms generated by relations are sent to the matching environment.
Actually, I tried to fix this issue months ago. See cca3280. The benchmark was pretty bad (+25-195 after correction).
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 test is still ignored on CDCL but I put a link to the issue #1262
src/lib/reasoners/adt.ml
Outdated
let ctx = | ||
match cases with | ||
| [{ destrs; _ }] -> | ||
List.fold_left2 | ||
(fun ctx x (d, d_ty) -> | ||
let access = E.mk_term (Sy.destruct d) [t] d_ty in | ||
E.mk_eq ~iff:false x access :: ctx | ||
) ctx xs destrs | ||
| _ -> ctx | ||
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.
Can you add a comment explaining what we are doing here?
As we load by default prelude with plenty of axioms, we got a lot of messages about these axioms in the debugging printers of `Matching`. This commit changes this behavior. We only print messages if there is at least one candidate.
Currently, the test `record.smt2` of the issue 1008 only succeeds with the Tableaux SAT solver
The function `xs_modulo_records` is not useful anymore. Indeed, all the ADT variables are sent to the ADT relation thanks to the `init` function of `Uf`. As record type has only one constructor by definition, this will always replace a record variable by a record definition in the union find and we can match patterns of the form `{ lbl1 = ..; ...; lblk = ..}`.
This reverts commit 31c4c66.
This reverts commit 874ea98.
16251af
to
9628209
Compare
9628209
to
4fb7fff
Compare
This PR removes the Record theory and sends all the records to the ADT theory.
This modification does not fix #1008 as expected because SatML does not send some terms generated by
Adt_rel
to the instantiation engine.