0

With the following example I am trying to set a constraint on the length of all possible lists in a quantified way. This will lead to a "unsat" result which I am sure is correct.

Can somebody go into detail why this is unsatisfiable and if there is a way around that limitation without putting the length limitation on a specific variable/constant?

I found this interesting thread but my question was not really answered there. In addition, the answers are old and refer to SMT-LIB version 2.0 (and one to a not quantified version). Maybe Z3 is capable to do so nowadays in a way unknown to me.

(set-logic ALL)
(set-option :produce-unsat-cores true)

(declare-datatypes ((List 1)) ((par (T) ((cons (head T) (tail (List T))) (nil)))))

(define-sort IntList() (List Int))

(define-fun-rec IntList.length((l IntList)) Int
    (ite
        (= l (as nil IntList))
        0
        (+ (IntList.length (tail l)) 1)
    )
)

(assert (! (forall ((this IntList)) (<= 2 (IntList.length this))) :named a10))

(check-sat)
(get-unsat-core)

I use commit 8abb644378ebaf1a9699e1b2fdd32075bcfcea4e of Z3 master as of 2021-01-12, 64-bit on Win10.

John Smith
  • 771
  • 8
  • 25

1 Answers1

1

This assertion:

(assert (! (forall ((this IntList)) (<= 2 (IntList.length this))) :named a10))

is unsatisfiable. As you no doubt noticed, it does not mean that you want z3 to consider only int-lists whose length is at least two. It simply says that all lists that can be generated from the definition you gave have size at least 2. And that's simply a false statement. And that's why this script is unsat.

In short, datatypes in SMT are "freely generated." See https://stackoverflow.com/a/60998125/936310 for a detailed explanation of what that means. If you want to model all lists that are at least size 2, then you'll have to modify your data-type to make sure it ensures that, i.e., instead of the nil case, your base case will have at least two elements to finish off the list. This is the only way of ensuring that the solver considers only lists that are of size >= 2.

To be clear, your desire "I am trying to set a constraint on the length of all possible lists in a quantified way." cannot be expressed with a quantified axiom, if you stick to using the lists as defined in your example. (i.e., with a simple cons and nil.) If that's what you want, you'll have to say something like (pseudo-code):

(assert (forall ((x IntList)) (=> (>= (length-of x) 2) 
                              ... condition you want to prove ...)))

That is, you have to write an implication, and prove what you want under the assumption that the list you have is at least of length 2. This can get really complicated really quick of course, and SMT solvers usually don't do well with quantification, so beware of the complexities.

In general, reasoning about recursive datatypes is not the strong suite for SMT-solvers. The recursive function definition facility is relatively new, and support for them is rare and frequently buggy. Any proof attempt that uses a recursive datatype has to use induction for any interesting property, and SMT solvers just don't do induction out-of-the-box. You might be better of trying actual theorem provers like Isabelle, ACL2, Lean, HOL, etc.

alias
  • 28,120
  • 2
  • 23
  • 40