我设置了一些边界/约束并希望解决它们,但是当我使用函数乘法和除法时,优化并不像我认为的那样。
这是我的代码:
import com.microsoft.z3.*;
import java.util.*;
System.setProperty( "java.library.path", "/local/Programs/z3-4.6.0-x64-osx-10.11.6/bin/" );
//set sys_paths to null
final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
sysPathsField.setAccessible(true);
sysPathsField.set(null, null);
//System.loadLibrary("libz3java");
HashMap<String, String> cfg = new HashMap<String, String>();
cfg.put("model", "true");
Context ctx = new Context(cfg);
RealExpr P = ctx.mkRealConst("Power");
RealExpr LowerBoundP = ctx.mkReal(0);
RealExpr UpperBoundP = ctx.mkReal(4000);
BoolExpr boundP1 = ctx.mkLe(P, UpperBoundP);
BoolExpr boundP2 = ctx.mkGe(P, LowerBoundP);
BoolExpr bothBoundsP = ctx.mkAnd(boundP1, boundP2);
RealExpr Mass = ctx.mkRealConst("Mass");
RealExpr LowerBoundMass = ctx.mkReal(1000);
RealExpr UpperBoundMass = ctx.mkReal(2000);
BoolExpr boundMass1 = ctx.mkLe(Mass, UpperBoundMass);
BoolExpr boundMass2 = ctx.mkGe(Mass, LowerBoundMass);
BoolExpr bothBoundsMass = ctx.mkAnd(boundMass1, boundMass2);
System.out.println("Optimizing System ...");
Optimize optsys = ctx.mkOptimize();
optsys.Add(
bothBoundsP,
bothBoundsMass,
//Here is the Division that does not work
ctx.mkEq(ctx.mkDiv(P,Mass), Speed)
//Multiplication does not work as well
//ctx.mkEq(ctx.mkMul(P,Mass), Speed)
);
Optimize.Handle optimizeSpeed = optsys.MkMaximize(Speed);
System.out.println(optsys.Check());
System.out.println(optsys.getReasonUnknown());
System.out.println("Optimized Speed: " + optimizeSpeed);
它作为分区和乘法的输出:
Optimizing System ...
UNKNOWN
(incomplete (theory arithmetic))
Optimized Speed: 0
虽然分别应该是4和8000000。它应该是可以满足的,而不是未知的。 这里有什么问题,为什么我不能优化这个简单的功能?
我发现了这个: How does Z3 handle non-linear integer arithmetic?
这是否意味着这个等式无法解决?乘法和除法不是线性的吗?
答案 0 :(得分:2)
这里的问题是Z3的优化器无法真正处理非线性算法。 (在这种情况下,非线性意味着您乘以/除以两个符号量。乘以/除以常数应该没问题。)
这些情况下的技巧是进行迭代循环。您将断言置于其中,然后迭代以获得“更好”的值,只要满足约束即可。当然,这不能保证收敛,所以你可能不得不在某个时刻“切断”循环。
对于您的示例,这是Python中的等效编码:
from z3 import *
s = Solver()
Power = Real ('Power')
s.add (Power >= 0);
s.add (Power <= 4000)
Mass = Real ('Mass')
s.add (Mass >= 1000);
s.add (Mass <= 2000);
Speed = Real ('Speed');
s.add (Speed == Power/Mass);
i = 1
m = None
while s.check() == sat:
m = s.model ()
print ("Iteration %d: " % i),
print m[Speed]
s.add (Speed > m[Speed])
i = i+1
print "Final model: "
print m
打印:
$ python a.py
Iteration 1: 1/1001
Iteration 2: 2/1001
Iteration 3: 3/1001
Iteration 4: 2
Iteration 5: 3
Iteration 6: 4
Final model:
[Power = 4000, Mass = 1000, Speed = 4]
我相信你可以把它翻译成Java;虽然我建议至少使用更好的语言来玩这些想法。