问题
Consider the following SMT-LIB code:
(set-option :auto_config false)
(set-option :smt.mbqi false)
; (set-option :smt.case_split 3)
(set-option :smt.qi.profile true)
(declare-const x Int)
(declare-fun trigF (Int Int Int) Bool)
(declare-fun trigF$ (Int Int Int) Bool)
(declare-fun trigG (Int) Bool)
(declare-fun trigG$ (Int) Bool)
; Essentially noise
(declare-const y Int)
(assert (!
(not (= x y))
:named foo
))
; Essentially noise
(assert (forall ((x Int) (y Int) (z Int)) (!
(= (trigF$ x y z) (trigF x y z))
:pattern ((trigF x y z))
:qid |limited-F|
)))
; Essentially noise
(assert (forall ((x Int)) (!
(= (trigG$ x) (trigG x))
:pattern ((trigG x))
:qid |limited-G|
)))
; This assumption is relevant
(assert (forall ((a Int) (b Int) (c Int)) (!
(and
(trigG a)
(trigF a b c))
:pattern ((trigF a b c))
:qid |bar|
)))
Trying to assert that axiom bar
holds, i.e.,
(push)
(assert (not (forall ((a Int) (b Int) (c Int))
(and
(trigG a)
(trigF a b c)))))
(check-sat)
(pop)
fails (Z3 4.3.2 - build hashcode 47ac5c06333b):
unknown
[quantifier_instances] limited-G : 1 : 0 : 1
Question 1: Why did Z3 only instantiate limited-G
but neither limited-F
nor bar
(which would prove the assertion)?
Question 2: Commenting any of the (useless) assertions foo
, limited-F
or limited-G
allows Z3 to prove the assertion - why is that? (Depending on which are commented, either only bar
or bar
and limited-F
are instantiated.)
In case it is related to the observed behaviour: I would like to set smt.case_split
to 3
(my configuration follows the one omitted by MSR's Boogie tool), but Z3 gives me WARNING: auto configuration (option AUTO_CONFIG) must be disabled to use option CASE_SPLIT=3, 4 or 5
, despite the fact that (set-option :auto_config false)
.
回答1:
The situation is as follows:
when using pattern based instantiation exclusively Z3 takes a somewhat operational approach to finding quantifier instantiations.
by disabling MBQI you rely on the equality matching engine.
- case_split = 3 instructs Z3 to use relevancy heuristic when choosing candidates for equality matching.
- The assert (not (forall (a, b, c) (and (trigG a) (trigF a b c)))) expands into a disjunction (or (not (trigG a!0)) (not (trigF a!0 b!1 c!2))).
- only one of the two disjuncts is relevant for satisfying the formula.
- The search sets (trigG a!0) to false, so the clause is satisfied. The trigger (trigF a b c) is therefore never activated.
You can bypass this issue by distributing in universal quantifiers over conjunctions, and supplying patterns in each case. Thus, you(r tool) could rewrite the axiom:
(assert (forall ((a Int) (b Int) (c Int)) (!
(and
(trigG a)
(trigF a b c))
:pattern ((trigF a b c))
:qid |bar|
)))
to the two axioms.
(assert (forall ((a Int)) (! (trigG a) :pattern ((trigG a))))
(assert (forall ((a Int) (b Int) (c Int)) (!
(trigF a b c)
:pattern ((trigF a b c))
:qid |bar|
)))
The issue of setting auto-completion seems fixed. I somewhat recently fixed bug in the way that some top-level configurations were reset if multiple top-level configurations were set in the smt-lib input.
来源:https://stackoverflow.com/questions/25622964/surprising-behaviour-when-trying-to-prove-a-forall