Skip to content
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

Open
wants to merge 14 commits into
base: next
Choose a base branch
from
Open

Conversation

Halbaroth
Copy link
Collaborator

@Halbaroth Halbaroth commented Apr 19, 2024

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.

@Halbaroth Halbaroth added this to the 2.7.0 milestone Apr 19, 2024
@Halbaroth Halbaroth changed the title Merge records Merge Records theory into ADT theory Jun 11, 2024
@Halbaroth Halbaroth force-pushed the merge-records branch 2 times, most recently from 0e0a6a1 to 3ba843d Compare July 9, 2024 13:35
@Halbaroth Halbaroth force-pushed the merge-records branch 2 times, most recently from 117dfe2 to 1d30760 Compare August 6, 2024 08:57
@Halbaroth Halbaroth linked an issue Aug 16, 2024 that may be closed by this pull request
@Halbaroth Halbaroth changed the title Merge Records theory into ADT theory Remove the Record theory Oct 28, 2024
@Halbaroth
Copy link
Collaborator Author

As I expected, we got regressions if we do not produce a context in the make function of Adt as we did in Records. Consider for instance this example (I got it from a real regression):

(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 Alt-Ergo outputs unsat. It works on next because X.make adds the extra equality (unbox (box void)) = void. The trigger of the first assertion is (f u (box (unbox v))). First, we match (box void) with (box (unbox v)), then we try to match (unbox v) with void. Of course, we cannot match them if we only consider syntactical equality, but Matching allows to match terms modulo equality of the union-find. (unbox (box void)) is in the class of void and can match (unbox v) with v --> (box void).

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 unsat on next and this branch. It succeeds because after many matching rounds, it will try with variable triggers and there is one variable trigger v which covers all the variables of the axiom. In the previous case, it won't generate it because of u. So the instantiation engine produces a fresh instantiation with v = void.

Notice that there is specific code in Matching to manage another corner case of the Records theory. For instance, consider the input:

(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 this branch. On next, Alt-Ergo need to match x with (c y) (it is the pattern of the axiom). Again, we need to match modulo equality. But it does not know that x = (c (b x)). The function xs_modulo_records in the module Matching will add the term (c (b x)) to the list of terms equal to 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 test passes. 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, 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.

@Halbaroth
Copy link
Collaborator Author

In the last patch, I use the context of Adt.make to propagate the same equalities as we did in Records.make. Actually I produce these equalities as soon as the type of the term is an ADT with only one constructor, which is bit more general.

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 X.make.

@Halbaroth
Copy link
Collaborator Author

+55-12 on ae-format and the solver is slightly faster :)

@Halbaroth
Copy link
Collaborator Author

Okay, I was not completely satisfied by the last commit. It is sad to still use the context of X.make.

Another way to solve this issue consists in eliminating as earlier as possible terms of the form (box ... (unbox u) ...) where box is the unique constructor of a record type and unbox is one of its destructor (at the appropriate position). Let us imagine that we have the axiom:

forall u : t. (P u (box (unbox u)))

where P is a undefined predicate and t is our record type.

If we replace it by:

forall w : unit. u = box w --> (P u u)

Alt-Ergo should generate the trigger (P u u) for this axiom. If we have the term (box unit) in the union-find, we can match (P (box unit) (box unit)) against (P u u) with u --> (box unit) and we can take w --> unit. We do not need to add the equality (unbox (box unit)) = unit.

Actually, I tried another transformation:

forall w : unit. 
let u = box w in 
(P u u)

It works if we disable some simplifications done in the smart constructor Expr.mk_let and during triggers generation but we lost other problems.

@Halbaroth Halbaroth force-pushed the merge-records branch 2 times, most recently from 7d55bc9 to 20d966c Compare November 12, 2024 13:17
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 =
..}`.
@Halbaroth
Copy link
Collaborator Author

I think that this PR is now ready to review. I keep the current code with context in X.make even if I dislike this design because I didn't find a proper approach and I think we should merge this PR and look for a better design later.

@Halbaroth Halbaroth marked this pull request as ready for review November 12, 2024 13:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Simple ADT test with different behavior with or without push
1 participant