简体   繁体   中英

Why does smtlib/z3/cvc4 allow to declare the same constant more than once?

I have a question about declare-const in smtlib.

For example,

In z3/cvc4, the following program doesn't report an error:

C:\Users\Chansey>z3 -in
(declare-const x Int)
(declare-const x Bool)

In the smt-lib-reference, it says that

(declare-fun f (s1... sn) s)... The command reports an error if a function symbol with name f is already present in the current signature.

So the sort s is included in the entire signature of the x , is that right?

But why is it so? What is the motivation behind it?

In my understanding, the x is variable identifier and in general (eg in some general programming languages) we are not allowed to declare the same variable with different types. So I think the above code is best to report an error.

I once thought that perhaps z3/smtlib can support redefinition?, but not...

C:\Users\Chansey>z3 -in
(declare-const x Int)
(declare-const x Bool)
(assert (= x true))
(error "line 3 column 11: ambiguous constant reference, more than one constant with the same sort, use a qualified expre
ssion (as <symbol> <sort>) to disambiguate x")

So the above code is definitely wrong, why not report the error earlier?

PS. If I use the same sort, then it will report an error (that great, I hope the Bool case can also report the error):

C:\Users\Chansey>z3 -in
(declare-fun x () Int)
(declare-fun x () Int)
(error "line 2 column 21: invalid declaration, constant 'x' (with the given signature) already declared")

Thanks.

In SMTLib, a symbol is identified not just by its name, but also by its sort. And it's perfectly fine to use the same name, so long as you have a different sort, as you observed. Here's an example:

(set-logic ALL)
(set-option :produce-models true)
(declare-fun x () Int)
(declare-fun x () Bool)

(assert (= (as x Int) 4))
(assert (= (as x Bool) true))
(check-sat)
(get-model)
(get-value ((as x Int)))
(get-value ((as x Bool)))

This prints:

sat
(
  (define-fun x () Bool
    true)
  (define-fun x () Int
    4)
)
(((as x Int) 4))
(((as x Bool) true))

Note how we use the as construct to disambiguate between the two x 's. This is explained in Section 3.6.4 of http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.6-r2021-05-12.pdf

Having said that, I do agree the part of the document you quoted isn't very clear about this, and perhaps can use a bit of a clarifying text.

Regarding what the motivation is for allowing this sort of usage: There are two main reasons. The first is o simplify generating SMTLib. Note that SMTLib is usually not intended to be hand-written. It's often generated from a higher-level system that uses an SMT solver underneath. So being flexible in allowing symbols to share name so long as they can be distinguished by explicit sort annotations can be beneficial when you use SMTLib as an intermediate language between a higher-level system and the solver itself. But when you're writing SMTLib by hand, you should probably avoid this sort of duplication if you can, for clarity if nothing else.

The second reason is to allow for a limited form of "overloading" to be used. For instance, think about the SMTLib function distinct . This function can operate on any type of object ( Int , Bool , Real etc.), yet it's always called distinct . (We don't have distinct-int , distinct-bool etc.) The solver "distinguishes" which one you meant by doing a bit of an analysis, but in cases it cannot, you can help it along with an as declaration as well. So, theory symbols can be overloaded in this way, which is also the case for = , + , * , etc. Of course, SMTLib does not allow for users to define such overloaded names, but as the document states in footnote 29 on page 91, this restriction might be removed in the future.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM