为什么Matlab的solve函数运行一次后需要更少的时间?

时间:2019-04-15 04:55:14

标签: matlab performance runtime solver

我有一些Matlab代码,在某些符号约束上调用了solve函数。第一次运行,求解需要大约6秒钟。第一次之后,求解大约需要0.3秒。如果我更改输入变量,则求解将再次花费约6秒钟。

这是因为,在第一次执行之后,Matlab记得它曾经有答案并且只是简单地重用了它吗?还是正在发生其他事情?

下面是一些代码,可以证明这种行为。

clear; clc

d1 = 25;
d2 = 15;
d3 = 7.5;
d4 = 4.5;

x1 = -0.1521;
y1 = 0.2673;
z1 = 2.3;

x21 = -0.3473;
y21 = 0.3298;

x3 = -0.434;
y3 = 0.2502;
z3 = 2.3;

g = [x1-x3,y1-y3,z1-z3];


syms  X1 Y1 Z1  X2 Y2 Z2  X3 Y3 Z3  X4 Y4 Z4 ...
    x22 y22 z22 t2_2d t1_2d ...
    t1 t2 t3 t4 ...
    real
assumeAlso([Z1 Z2 Z3 Z4 t1 t2 t3],'positive')


constraints = [
        x22 == (t2_2d * (-1/g(1)) ) + x21
        x22 == (t1_2d * g(1)) + x1

        y22 == (t2_2d * (-1/g(2)) ) + y21
        y22 == (t1_2d * g(2)) + y1

        z22 == z1


        X1 == t1*x1
        Y1 == t1*y1
        Z1 == t1*z1

        X2 == t2*x22
        Y2 == t2*y22
        Z2 == t2*z22

        X3 == t3*x3
        Y3 == t3*y3
        Z3 == t3*z3


        (X1-X3)^2 + (Y1-Y3)^2 + (Z1-Z3)^2 == (d1+d2)^2
        (X1-X2)^2 + (Y1-Y2)^2 + (Z1-Z2)^2 == d1^2
        (X2-X3)^2 + (Y2-Y3)^2 + (Z2-Z3)^2 == d2^2


        sum([X4 Y4 Z4] .* cross([X1 Y1 Z1],[X3 Y3 Z3])) == 0
        (X1-X4)^2 + (Y1-Y4)^2 + (Z1-Z4)^2 == (d1+d2+d3)^2 + d4^2
        (X3-X4)^2 + (Y3-Y4)^2 + (Z3-Z4)^2 == d3^2 + d4^2
];

tic
solved = solve(constraints);
toc

tic
solved = solve(constraints);
toc

tic
solved = solve(constraints);
toc

tic
solved = solve(constraints);
toc

这个问题背后的动机是,我希望在更改输入的约束相同的情况下尽快运行求解器。我希望答案能帮助我找到一种方法,使每次运行时间约为0.3秒,而不是6秒。

1 个答案:

答案 0 :(得分:1)

我的猜测是,这是因为代码将在第一次执行时被缓存,因此后续运行会更快。通过更改参数,您必须运行一次代码,以便缓存新定义。

MATLAB可以通过使用临时目录来缓存脚本句柄。例如,执行clean all,然后在运行脚本之前和之后运行[M,X,C] = inmem('-completenames')。您会注意到缓存了以下类:

{'matlab.internal.editor.eval.TempFolder'                           }
{'matlab.internal.editor.eval.TmpFilePath'                          }
{'matlab.internal.editor.EODataStore'                               }

但是关于性能,我仔细研究了一下,当它传递到resolve()时,花了3秒的运行时中约有99%用于评估符号表达式,因此,预计后续运行时的运行时会低得多,因为您的符号表达式未更改。现在,通过更改参数,您将不得不再次等待3秒钟,以便重新评估它。如果您想确切了解正在发生的事情,可以分析一下solve()调用:

profile on
solved = solve(constraints);
profile viewer

然后您可以看到mupadengine.evalin内部发生了什么,这是负责符号表达式求值的那个。