优化乘法和除法

时间:2018-03-07 19:44:14

标签: java z3

我设置了一些边界/约束并希望解决它们,但是当我使用函数乘法和除法时,优化并不像我认为的那样。

这是我的代码:

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?

这是否意味着这个等式无法解决?乘法和除法不是线性的吗?

1 个答案:

答案 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;虽然我建议至少使用更好的语言来玩这些想法。