显而易见的选择是为您的 x 值使用数组,并使用递归函数对总和/积进行建模。
Z3 确实支持递归函数,但它不是万无一失的。充其量你会得到unknown,,因为大多数这样的公式都需要归纳证明; SMT求解器不擅长的事情。在最坏的情况下,您会得到一个无用的答案,或者如果您遇到错误,甚至可能会得到一个虚假的答案。
下面是一个成功的例子:
(declare-fun xs () (Array Int Real))
(define-fun-rec sum ((lb Int) (ub Int)) Real
(ite (> lb ub)
0
(+ (select xs lb)
(sum (+ lb 1) ub))))
(declare-fun lb () Int)
(declare-fun ub () Int)
(assert (= (sum lb ub) 12.34))
(check-sat)
(get-value (lb ub xs))
Z3 回应:
sat
((lb 0)
(ub 0)
(xs ((as const (Array Int Real)) (/ 617.0 50.0))))
这实际上很酷,虽然可能没有你想象的那么令人印象深刻。您也可以将其强制到某个范围:
(declare-fun xs () (Array Int Real))
(define-fun-rec sum ((lb Int) (ub Int)) Real
(ite (> lb ub)
0
(+ (select xs lb)
(sum (+ lb 1) ub))))
(declare-fun lb () Int)
(declare-fun ub () Int)
(assert (= 1 lb))
(assert (= 3 ub))
(assert (= (sum lb ub) 12.34))
(check-sat)
(get-value (lb ub))
(eval (select xs 1))
(eval (select xs 2))
(eval (select xs 3))
这会产生:
sat
((lb 1)
(ub 3))
0.0
(- (/ 121233.0 50.0))
2437.0
这是一个正确的模型。不幸的是,对公式/断言的微小更改会导致它产生无用的答案。如果我尝试:
(declare-fun xs () (Array Int Real))
(define-fun-rec sum ((lb Int) (ub Int)) Real
(ite (> lb ub)
0
(+ (/ 2.0 (select xs lb))
(sum (+ lb 1) ub))))
(assert (= (sum 1 3) 12.34))
(check-sat)
然后我得到:
unknown
随着求解器对递归函数的支持越来越成熟,您当然可以期待它们能够成功回答更多查询。在短期内,您更有可能经常看到unknown 的回复。
就个人而言,我认为当您不知道总和/乘积中有多少项时使用 SMT 求解器并不是最好的主意。如果您知道术语的数量,请务必使用 SMT 求解器。如果没有,最好使用交互式定理证明,即允许您表达递归函数和归纳证明的系统;例如 Isabelle、Coq 等。