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

Fix issue 1099 #1102

Merged
merged 6 commits into from
Jun 11, 2024
Merged

Fix issue 1099 #1102

merged 6 commits into from
Jun 11, 2024

Conversation

Halbaroth
Copy link
Collaborator

@Halbaroth Halbaroth commented Apr 30, 2024

The D_cnf module didn't use the flag toplevel as it was done in Cnf. This flag is important because the Expr AST doesn't store quantified type variables with binders as it does for the term variable. Instead, we use a prenex polymorphism approach, which means the quantified type variables are at the top level only.

I believe this PR fixes the issue #1099. I'll check it on Marvin.

NB: I think this bug didn't make Alt-Ergo unsound.

@Halbaroth Halbaroth added this to the 2.6.0 milestone Apr 30, 2024
@Halbaroth Halbaroth linked an issue Apr 30, 2024 that may be closed by this pull request
@Halbaroth Halbaroth force-pushed the fix-1099 branch 2 times, most recently from a55dcc8 to 1be1c40 Compare April 30, 2024 09:15
hra687261
hra687261 previously approved these changes Apr 30, 2024
Copy link
Contributor

@hra687261 hra687261 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@hra687261
Copy link
Contributor

I think its worth adding a test with forall _: x. forall _: y. exist ... to make sure that the behavior is correct in this case as well.
I am not sure but it is possible that in this case, both x and y should be seen as toplevel quantified type variables, I am also not sure if Dolmen or AE simplifies forall _: x. forall _: y. exist ... to forall _: x, _: y. exist ....

@Gbury
Copy link
Collaborator

Gbury commented Apr 30, 2024

Dolmen should indeed aggregate together consecutive quantifications (assuming that there are no trigger annotations in the middle).

@Halbaroth
Copy link
Collaborator Author

I think its worth adding a test with forall _: x. forall _: y. exist ... to make sure that the behavior is correct in this case as well. I am not sure but it is possible that in this case, both x and y should be seen as toplevel quantified type variables, I am also not sure if Dolmen or AE simplifies forall _: x. forall _: y. exist ... to forall _: x, _: y. exist ....

I'll check, thanks ;)

@hra687261 hra687261 dismissed their stale review May 2, 2024 14:09

Dismissing approval due to changes to the PR and regressions

@Halbaroth Halbaroth mentioned this pull request May 2, 2024
@Halbaroth
Copy link
Collaborator Author

The new fix has been tested. We got +19-0. I believe that we lost these tests with Dolmen only.

I did a mistake in the previous patch because I thought that mk_expr in D_cnf was only call on non-toplevel formulas.
In fact mk_form is called on toplevel formulas and this function calls mk_expr with the toplevel flag as true.

So if you call mk_form on a polymorphic axiom, the first forall binder will only contain all the type variables but no term variables. For instance, with the following input:

type 'a t
logic c : 'a t
axiom a : forall x : int. x = x + 1 and c <> c
goal g : false

Dolmen generated the above term for the axiom a:
∀ w1 : Type. ∀ x : int. (x = (x + 1)) ∧ (Distinct ( t(w1) ) (c w1) (c w1))

I believe we should never get a non-toplevel forall binder with type variable. I added an assertion to enforce this invariant.
@Gbury maybe this case can happen in SMT-LIB v3?

I will run a last test on ae-format to ensure the failwith is never raised.

@Gbury
Copy link
Collaborator

Gbury commented May 3, 2024

I don't think this should happen in smtlibv3 (but it's been a long time since I looked at its specification).

However, one of the reasons that dolmen does not enforce type quantification at top-level is that there are a few cases where solvers might be able to / want to handle a type quantification that is not at top-level (or at least, that depends on the definition of top-level). For instance:

  • a formula such as not (exists a : type. ....) which could easily arise out of a negated goal
  • a formula such as (forall a: type. ...) and (forall b: type. ....), and so on...

All in all, I think it's probably better to leave to solvers the task of defining which type quantifications they can handle ? But I'm open to suggestions, ^^

@Halbaroth
Copy link
Collaborator Author

I agree. We should clarify what is supposed to be a top level formula in Alt-Ergo. I think we should test this PR on psmt2 files.

The `D_cnf` module didn't use the flag `toplevel` as it was done in `Cnf`.
This flag is important because the `Expr` AST doesn't store quantified
type variables with binders as it does for the term variable. Instead, we
use a `prenex polymorphism` approach, which means the quantified type
variables are at the top level only.

I believe this PR fixes the issue OCamlPro#1099.
Alt-Ergo only supports prenex polymorphism. This commit
adds a failwith clause in `D_cnf` to enforce this property.
@Halbaroth
Copy link
Collaborator Author

To clarify the meaning of top level in Alt-Ergo, I wrote a better commentary:

      Determine if the quantified formula is at the top level of an asserted
      formula.

      An {e asserted formula} is a formula introduced by {e (assert ...)} or
      generated by a function definition with {e (define-fun ...)}.

      By {e top level}, we mean that the quantified formula is not
      contained in another quantified formula, but the formula can be a
      subformula.

      For instance, the subformula ∀y:int. ¬G(y) of the asserted formula
      ¬(∀y:int. ¬G(y)) is also considered at the top level.

      Notice that quantifiers of the same kind are packed as much as possible.
      For instance, if we assert the formula:
        ∀α. ∀x:list α. ∃y:α. F(x, y)
      Then the two universal quantifiers are packed in a same top level formula
      but the subformula ∃y:α. F(x, y) is not at the top level.

I also tested if we can quantify types in inner formula with the psmt format. We cannot! For instance, the following assertion
is refused by Dolmen:

(set-logic ALL)
(declare-sort t 1)
(declare-fun P (Int) Bool)
(assert (forall ((x Int))
  (=> (P x)
      (par (a) (forall ((x (t a)) (y (t a))) (= x y))))))
(check-sat)

So the assertion I added in D_cnf is fine. Actually, if the frontend produces a formula with inner quantified type variable, the solver is not designed to manage this kind of quantifiers and accepting to reason on a problem with such formulas in the context could be unsound. It is safer to refuse immediately to continue.

@Halbaroth Halbaroth requested a review from hra687261 June 11, 2024 11:15
Copy link
Contributor

@hra687261 hra687261 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some minor remarks.
It is worth running benchmarks again, just to be sure.

Comment on lines 78 to 79
An {e asserted formula} is a formula introduced by {e (assert ...)} or
generated by a function definition with {e (define-fun ...)}.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not familiar with the formatting {e ...} for documentation, not sure what it does. Afaik brackets [...] or [|...|] are usually used for code.
cf: https://ocamlverse.net/content/documentation_guidelines.html

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{e ...} emphasizes the text. I'm used to use brackets for OCaml code only but I haven't strong opinions on this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use the bracket syntax in the last commit.

Comment on lines 81 to 83
By {e top level}, we mean that the quantified formula is not
contained in another quantified formula, but the formula can be a
subformula.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is confusing. Isn't a formula contained in another formula a subformula? Maybe we can use some clearer wording?
For example:

Suggested change
By {e top level}, we mean that the quantified formula is not
contained in another quantified formula, but the formula can be a
subformula.
By {e top level}, we mean that the quantified formula is not
a subformula of another quantified formula.

Should suffice IMO.

@Halbaroth Halbaroth requested a review from hra687261 June 11, 2024 15:22
@Halbaroth Halbaroth enabled auto-merge (squash) June 11, 2024 15:31
@Halbaroth Halbaroth merged commit 2069070 into OCamlPro:next Jun 11, 2024
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Assertion failed in Expr on next
3 participants