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

Unsoundness in model generation #1022

Closed
bclement-ocp opened this issue Jan 8, 2024 · 1 comment · Fixed by #1025
Closed

Unsoundness in model generation #1022

bclement-ocp opened this issue Jan 8, 2024 · 1 comment · Fixed by #1025
Assignees

Comments

@bclement-ocp
Copy link
Collaborator

On the following sat problem from the SMT-LIB (QF_LIA/20180326-Bromberger/unbd-sage/unbd010v15c/unbd-sage0):

(set-info :smt-lib-version 2.6)
(set-logic QF_LIA)
(set-info :source |
Generated by: Martin Bromberger
Generated on: 2018-01-06
Generator: https://www.mpi-inf.mpg.de/fileadmin/inf/rg1/Documents/RandomUnboundedSageScript.tar.gz
Application: This is a satisfiable problem with bounded and unbounded directions and, therefore, a good test for the termination/completeness of branch-and-bound solvers.
Publications: M. Bromberger. A Reduction from Unbounded Linear Mixed Arithmetic Problems into Bounded Problems. (Work in progress.)

The benchmarks in this class were randomly generated by a sagemath script and by way of construction they are all satisfiable.
Target solver: CVC4 Mathsat SPASS-IQ YICES Z3
|)
(set-info :license "https://creativecommons.org/licenses/by/4.0/")
(set-info :category "random")
(set-info :status sat)
(declare-fun x0 () Int)
(declare-fun x1 () Int)
(declare-fun x2 () Int)
(declare-fun x3 () Int)
(declare-fun x4 () Int)
(declare-fun x5 () Int)
(declare-fun x6 () Int)
(declare-fun x7 () Int)
(declare-fun x8 () Int)
(declare-fun x9 () Int)

(assert (and 
(<= (- 7) (+ (* (- 2) x0) (+ (* (- 1) x2) (+ (* 1 x3) (+ (* 1 x5) (+ (* (- 1) x6) (+ (* 1 x8) (* 1 x9) ))))))) 
(<= 1 (+ (* (- 2) x3) (+ (* (- 1) x4) (+ (* (- 2) x7) (* (- 1) x9) )))) 
(<= 2 (+ (* 2 x0) (+ (* 2 x1) (+ (* 2 x2) (+ (* (- 2) x3) (+ (* 1 x4) (+ (* 2 x6) (* (- 2) x8) ))))))) 
(<= (- 2) (+ (* (- 1) x0) (+ (* 1 x1) (+ (* (- 2) x2) (+ (* 2 x4) (+ (* 2 x5) (+ (* (- 1) x7) (* (- 2) x9) ))))))) 
(<= 15 (+ (* (- 1) x0) (+ (* 1 x2) (+ (* (- 2) x3) (+ (* 2 x5) (+ (* 2 x6) (+ (* 2 x7) (* (- 2) x8) ))))))) 
(<= 8 (+ (* (- 2) x4) (+ (* 2 x5) (+ (* 2 x6) (+ (* (- 2) x8) (* 2 x9) ))))) 
(<= (- 11) (+ (* (- 2) x0) (+ (* 2 x2) (+ (* (- 1) x3) (+ (* 2 x4) (+ (* 1 x5) (+ (* (- 2) x6) (* (- 2) x7) ))))))) 
(<= 9 (+ (* (- 2) x1) (+ (* 2 x3) (+ (* (- 2) x4) (+ (* 2 x7) (* 1 x9) ))))) 
(<= 15 (+ (* 2 x0) (+ (* (- 1) x1) (+ (* (- 1) x3) (+ (* 2 x4) (+ (* 2 x6) (+ (* 1 x7) (+ (* (- 2) x8) (* 1 x9) )))))))) 
(<= 37 (+ (* 9 x0) (+ (* (- 9) x1) (+ (* (- 7) x2) (+ (* 7 x3) (+ (* (- 14) x4) (+ (* (- 15) x5) (+ (* 1 x6) (+ (* 9 x7) (* 7 x8) ))))))))) 
(<= (- 159) (+ (* (- 15) x0) (+ (* 28 x1) (+ (* 16 x2) (+ (* (- 8) x3) (+ (* 36 x4) (+ (* 28 x5) (+ (* (- 7) x6) (+ (* (- 24) x7) (+ (* (- 11) x8) (* (- 4) x9) )))))))))) 
(<= 56 (+ (* 20 x0) (+ (* (- 20) x1) (+ (* (- 13) x2) (+ (* 12 x3) (+ (* (- 32) x4) (+ (* (- 39) x5) (+ (* (- 2) x6) (+ (* 16 x7) (+ (* 20 x8) (* 4 x9) )))))))))) 
(<= 300 (+ (* (- 1) x0) (+ (* (- 35) x1) (+ (* (- 10) x2) (+ (* (- 15) x3) (+ (* (- 26) x4) (+ (* (- 2) x5) (+ (* 19 x6) (+ (* 27 x7) (+ (* (- 9) x8) (* 2 x9) )))))))))) 
(<= (- 45) (+ (* 10 x0) (+ (* (- 1) x1) (+ (* (- 3) x2) (+ (* 19 x3) (+ (* (- 15) x4) (+ (* (- 17) x5) (+ (* (- 6) x6) (+ (* 7 x7) (+ (* 12 x8) (* (- 3) x9) )))))))))) 
(<= 55 (+ (* 17 x0) (+ (* (- 17) x1) (+ (* (- 14) x2) (+ (* 1 x3) (+ (* (- 15) x4) (+ (* (- 30) x5) (+ (* 1 x6) (+ (* 7 x7) (+ (* 13 x8) (* 7 x9) ))))))))))))
(check-sat)
(exit)

Alt-Ergo replies:

$ alt-ergo unbd-sage2.smt2 
                                       
; File "unbd-sage2.smt2", line 43, characters 1-12: I don't know (0.0729) (37 steps) (goal g_1)

unknown

That's good (the problem is SAT).

If we request model generation, however, we have an issue:

$ alt-ergo --produce-model unbd-sage2.smt2
                                       
; File "/tmp/imreg/unbd-sage2.smt2", line 43, characters 1-12: Valid (0.0794) (37 steps) (goal g_1)

unsat

Some more info:

  • This does not only happen for this specific problem but also for a buch of problems in QF_LIA/20180326-Bromberger/unbd-sage and other SAT problems with integers (e.g. QF_LIA/dilig/15-17.smt2).
  • The exception comes from this line and in this call to model_from_simplex
  • This is because the int_sim environment we create with "FM-Simplex encoding" (I do not know what that is) here is actually unsat
  • The issue does not occur with the fm-simplex plugin (so this is an interaction between model generation and the inequalities module)
  • Using the "regular" env.int_sim here works, at least in this specific case, but presumably that is not acceptable to use in the general case (?). I do not know why we need this "FM-Simplex" encoding (yet), but it seems that we are computing it wrong, somehow.
@bclement-ocp
Copy link
Collaborator Author

Minimised with ddSMT (although not actually much simpler):

(set-option :produce-models true)
(set-logic QF_LIA)
(declare-fun x () Int)
(declare-fun x1 () Int)
(declare-fun x2 () Int)
(declare-fun x3 () Int)
(declare-fun x4 () Int)
(declare-fun x5 () Int)
(declare-fun x6 () Int)
(declare-fun x7 () Int)
(declare-fun x9 () Int)
(assert (and
(< 0 x)
(< 0 (+ x x2))
(< 0 (+ x4 x9))
(< 0 (+ x5 x6))
(< 0 (* x1 (- 1)))
(< 1 (+ x3 x5 x9 x2))
(< 1 (+ x5 (* x3 (- 1))))
(< 0 (+ x2 (* 27 x7) (* x3 (- 1)) (* x4 (- 26))))
(< 0 (+ x3 x6 (* 9 x7) (* x1 (- 1)) (* x2 (- 7)) (* x4 (- 14)) (* x5 (- 15))))
(< (- 39) (+ (* x (- 7)) (* 7 x1) (* 2 x2) (* 18 x4) (* 14 x5) (* x6 (- 3)) (* x7 (- 12)) (* x9 (- 1))))))
(check-sat)

@bclement-ocp bclement-ocp self-assigned this Jan 8, 2024
bclement-ocp added a commit to bclement-ocp/alt-ergo that referenced this issue Jan 8, 2024
Model generation for arithmetic constraints proceeds in two stages:

 - In the first stage, we only choose a value for variables that are
   within a finite domain (i.e. integer variables bounded from both
   above and below). This is the behavior of regular case splits, and
   happens in function `default_case_split`.

 - In the second stage, which we only reach if model generation is
   enabled, we must select a value for all variables. In this case, we
   select one interval for variables that can have multiple intervals
   (recall that we model arithmetic domains using unions of intervals).
   This happens in function `case_split_union_of_intervals`. If the
   selected interval is finite, we go back to the first stage in the
   next case split.

 - In the final stage, all remaining variables have infinite intervals
   as domains, and we must now pick a value for these. This happens in
   `model_from_unbounded_domains` -- even though for rational variables,
   the domain can still be bounded. For integers however, infinite
   intervals mean that they lack either a finite lower or upper bound
   (or both). For integers, we create a new simplex environment in
   `fm_simplex_unbounded_integers_encoding` where we adjust the bounds
   by a factor of half the sum of the absolute values of the
   coefficients. This means that an inequality `0 < 3x + 4y` becomes
   `0 + (3 + 4) / 2 < 3x + 4y`, i.e. `3.5 < 3x + 4y`. This removes
   `x = 1, y = 0` from the domain. On its own, this would be correct
   (albeit strange) because after removing a finite number of
   elements from an infinite domain there is still an infinite number of
   elements to choose from. But within a larger system this can (and is)
   problematic.

This patch removes the "adjustment" of the bounds which is not justified
and actually causes unsoundness.

Fixes OCamlPro#1022

Co-Authored-By: Guillaume Bury <guillaume.bury@gmail.com>
bclement-ocp added a commit to bclement-ocp/alt-ergo that referenced this issue Jan 9, 2024
Model generation for arithmetic constraints proceeds in two stages:

 - In the first stage, we only choose a value for variables that are
   within a finite domain (i.e. integer variables bounded from both
   above and below). This is the behavior of regular case splits, and
   happens in function `default_case_split`.

 - In the second stage, which we only reach if model generation is
   enabled, we must select a value for all variables. In this case, we
   select one interval for variables that can have multiple intervals
   (recall that we model arithmetic domains using unions of intervals).
   This happens in function `case_split_union_of_intervals`. If the
   selected interval is finite, we go back to the first stage in the
   next case split.

 - In the final stage, all remaining variables have infinite intervals
   as domains, and we must now pick a value for these. This happens in
   `model_from_unbounded_domains` -- even though for rational variables,
   the domain can still be bounded. For integers however, infinite
   intervals mean that they lack either a finite lower or upper bound
   (or both). For integers, we create a new simplex environment in
   `fm_simplex_unbounded_integers_encoding` where we adjust the bounds
   by a factor of half the sum of the absolute values of the
   coefficients. This means that an inequality `0 < 3x + 4y` becomes
   `0 + (3 + 4) / 2 < 3x + 4y`, i.e. `3.5 < 3x + 4y`. This removes
   `x = 1, y = 0` from the domain. On its own, this would be correct
   (albeit strange) because after removing a finite number of
   elements from an infinite domain there is still an infinite number of
   elements to choose from. But within a larger system this can (and is)
   problematic.

This patch removes the "adjustment" of the bounds which is not justified
and actually causes unsoundness.

Fixes OCamlPro#1022

Co-Authored-By: Guillaume Bury <guillaume.bury@gmail.com>
bclement-ocp added a commit to bclement-ocp/alt-ergo that referenced this issue Jan 9, 2024
Model generation for arithmetic constraints proceeds in two stages:

 - In the first stage, we only choose a value for variables that are
   within a finite domain (i.e. integer variables bounded from both
   above and below). This is the behavior of regular case splits, and
   happens in function `default_case_split`.

 - In the second stage, which we only reach if model generation is
   enabled, we must select a value for all variables. In this case, we
   select one interval for variables that can have multiple intervals
   (recall that we model arithmetic domains using unions of intervals).
   This happens in function `case_split_union_of_intervals`. If the
   selected interval is finite, we go back to the first stage in the
   next case split.

 - In the final stage, all remaining variables have infinite intervals
   as domains, and we must now pick a value for these. This happens in
   `model_from_unbounded_domains` -- even though for rational variables,
   the domain can still be bounded. For integers however, infinite
   intervals mean that they lack either a finite lower or upper bound
   (or both). For integers, we create a new simplex environment in
   `fm_simplex_unbounded_integers_encoding` where we adjust the bounds
   by a factor of half the sum of the absolute values of the
   coefficients. This means that an inequality `0 < 3x + 4y` becomes
   `0 + (3 + 4) / 2 < 3x + 4y`, i.e. `3.5 < 3x + 4y`. This removes
   `x = 1, y = 0` from the domain. On its own, this would be correct
   (albeit strange) because after removing a finite number of
   elements from an infinite domain there is still an infinite number of
   elements to choose from. But within a larger system this can (and is)
   problematic.

This patch removes the "adjustment" of the bounds which is not justified
and actually causes unsoundness.

Fixes OCamlPro#1022

Co-Authored-By: Guillaume Bury <guillaume.bury@gmail.com>
bclement-ocp added a commit to bclement-ocp/alt-ergo that referenced this issue Jan 9, 2024
Model generation for arithmetic constraints proceeds in two stages:

 - In the first stage, we only choose a value for variables that are
   within a finite domain (i.e. integer variables bounded from both
   above and below). This is the behavior of regular case splits, and
   happens in function `default_case_split`.

 - In the second stage, which we only reach if model generation is
   enabled, we must select a value for all variables. In this case, we
   select one interval for variables that can have multiple intervals
   (recall that we model arithmetic domains using unions of intervals).
   This happens in function `case_split_union_of_intervals`. If the
   selected interval is finite, we go back to the first stage in the
   next case split.

 - In the final stage, all remaining variables have infinite intervals
   as domains, and we must now pick a value for these. This happens in
   `model_from_unbounded_domains` -- even though for rational variables,
   the domain can still be bounded. For integers however, infinite
   intervals mean that they lack either a finite lower or upper bound
   (or both). For integers, we create a new simplex environment in
   `fm_simplex_unbounded_integers_encoding` where we adjust the bounds
   by a factor of half the sum of the absolute values of the
   coefficients. This means that an inequality `0 < 3x + 4y` becomes
   `0 + (3 + 4) / 2 < 3x + 4y`, i.e. `3.5 < 3x + 4y`. This removes
   `x = 1, y = 0` from the domain. On its own, this would be correct
   (albeit strange) because after removing a finite number of
   elements from an infinite domain there is still an infinite number of
   elements to choose from. But within a larger system this can (and is)
   problematic.

This patch removes the "adjustment" of the bounds which is not justified
and actually causes unsoundness.

Fixes OCamlPro#1022

Co-Authored-By: Guillaume Bury <guillaume.bury@gmail.com>
Halbaroth pushed a commit that referenced this issue Jan 9, 2024
Model generation for arithmetic constraints proceeds in two stages:

 - In the first stage, we only choose a value for variables that are
   within a finite domain (i.e. integer variables bounded from both
   above and below). This is the behavior of regular case splits, and
   happens in function `default_case_split`.

 - In the second stage, which we only reach if model generation is
   enabled, we must select a value for all variables. In this case, we
   select one interval for variables that can have multiple intervals
   (recall that we model arithmetic domains using unions of intervals).
   This happens in function `case_split_union_of_intervals`. If the
   selected interval is finite, we go back to the first stage in the
   next case split.

 - In the final stage, all remaining variables have infinite intervals
   as domains, and we must now pick a value for these. This happens in
   `model_from_unbounded_domains` -- even though for rational variables,
   the domain can still be bounded. For integers however, infinite
   intervals mean that they lack either a finite lower or upper bound
   (or both). For integers, we create a new simplex environment in
   `fm_simplex_unbounded_integers_encoding` where we adjust the bounds
   by a factor of half the sum of the absolute values of the
   coefficients. This means that an inequality `0 < 3x + 4y` becomes
   `0 + (3 + 4) / 2 < 3x + 4y`, i.e. `3.5 < 3x + 4y`. This removes
   `x = 1, y = 0` from the domain. On its own, this would be correct
   (albeit strange) because after removing a finite number of
   elements from an infinite domain there is still an infinite number of
   elements to choose from. But within a larger system this can (and is)
   problematic.

This patch removes the "adjustment" of the bounds which is not justified
and actually causes unsoundness.

Fixes #1022

Co-authored-by: Guillaume Bury <guillaume.bury@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant