3

これは、 Z3 SMT 2.0 と Z3 py の実装で以前に尋ねた質問に関連してい ます。無限大の正の実数に対して完全な代数を実装しましたが、ソルバーが正しく動作しません。コメントされた制約が制約の実際の解決策を提供する場合、この単純なインスタンスでは不明になります。

# Data type declaration
MyR = Datatype('MyR')
MyR.declare('inf');
MyR.declare('num',('re',RealSort()))

MyR = MyR.create()
inf = MyR.inf
num  = MyR.num
re  = MyR.re

# Functions declaration
#sum 
def msum(a, b):
    return If(a == inf, a, If(b == inf, b, num(re(a) + re(b))))

#greater or equal 
def mgeq(a, b):
  return If(a == inf, True, If(b == inf, False, re(a) >= re(b)))

#greater than
def mgt(a, b):
  return If(a == inf, b!=inf, If(b == inf, False, re(a) > re(b)))

#multiplication  inf*0=0 inf*inf=inf  num*num normal
def mmul(a, b):
    return If(a == inf, If(b==num(0),b,a), If(b == inf, If(a==num(0),a,b), num(re(a)*re(b))))

s0,s1,s2 = Consts('s0 s1 s2', MyR)

# Constraints add to solver
constraints =[
  s2==mmul(s0,s1),
  s0!=inf,
  s1!=inf
]
#constraints =[s2==mmul(s0,s1),s0==num(1),s1==num(2)]

sol1= Solver()
sol1.add(constraints)

set_option(rational_to_decimal=True)

if sol1.check()==sat:
  m = sol1.model()
  print m
else:
  print sol1.check()

これが驚くべきことなのか予想されることなのかはわかりません。それを機能させる方法はありますか?

4

1 に答える 1

4

あなたの問題は非線形です。Z3の新しい (そして完全な) 非線形算術ソルバー ( nlsat) は、代数データ型などの他の理論とは統合されていません。投稿を参照してください。

これは現在のバージョンの制限です。将来のバージョンでは、この問題に対処します。

それまでの間、別のエンコーディングを使用して問題を回避できます。実数演算とブール値のみを使用する場合、問題は の範囲になりnlsatます。MyR1 つの可能性は、Z3 ブール式と Z3 実数式の Python ペアとしてエンコードすることです。

これは部分的なエンコードです。すべての演算子をエンコードしたわけではありません。この例は、 http://rise4fun.com/Z3Py/EJLqからオンラインでも入手できます。

from z3 import *

# Encoding MyR as pair (Z3 Boolean expression, Z3 Real expression)
# We use a class to be able to overload +, *, <, ==
class MyRClass:
    def __init__(self, inf, val):
        self.inf = inf
        self.val = val
    def __add__(self, other):
        other = _to_MyR(other)
        return MyRClass(Or(self.inf, other.inf), self.val + other.val)
    def __radd__(self, other):
        return self.__add__(other)
    def __mul__(self, other):
        other = _to_MyR(other)
        return MyRClass(Or(self.inf, other.inf), self.val * other.val)
    def __rmul(self, other):
        return self.__mul__(other)
    def __eq__(self, other):
        other = _to_MyR(other)
        return Or(And(self.inf, other.inf),
                  And(Not(self.inf), Not(other.inf), self.val == other.val))
    def __ne__(self, other):
        return Not(self.__eq__(other))

    def __lt__(self, other):
        other = _to_MyR(other)
        return And(Not(self.inf),
                   Or(other.inf, self.val < other.val))

def MyR(name):
    # A MyR variable is encoded as a pair of variables name.inf and name.var
    return MyRClass(Bool('%s.inf' % name), Real('%s.val' % name))

def MyRVal(v):
    return MyRClass(BoolVal(False), RealVal(v))

def Inf():
    return MyRClass(BoolVal(True), RealVal(0))

def _to_MyR(v):
    if isinstance(v, MyRClass):
        return v
    elif isinstance(v, ArithRef):
        return MyRClass(BoolVal(False), v)
    else:
        return MyRVal(v)

s0 = MyR('s0')
s1 = MyR('s1')
s2 = MyR('s2')

sol = Solver()
sol.add( s2 == s0*s1,
         s0 != Inf(),
         s1 != Inf(),
         s0 == s1,
         s2 == 2,
         )
print sol
print sol.check()
print sol.model()
于 2012-12-13T21:37:09.753 に答える