为什么Matlab求解函数在运行一次后花费的时间更少?
Why does Matlab's solve function take less time after being run once?
我有一些 Matlab 代码可以根据某些符号约束调用求解函数。第一次运行时,解决大约需要 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 秒。
我的猜测是,这是因为代码在第一次执行时会被缓存,所以后续的运行s会更快。通过更改参数,您必须 运行 代码一次,以便缓存新定义。
MATLAB 可以使用临时目录缓存脚本句柄。例如,在 运行 脚本之前和之后执行 clean all
,然后 运行 [M,X,C] = inmem('-completenames')
。您会注意到缓存了以下 类:
{'matlab.internal.editor.eval.TempFolder' }
{'matlab.internal.editor.eval.TmpFilePath' }
{'matlab.internal.editor.EODataStore' }
但关于性能,我调查了它,大约 99% 的 3 秒 运行 时间都花在了评估传递给 solve() 的符号表达式上,因此预计 运行time 对于随后的 运行s 会少很多,因为你的符号表达式没有改变。现在,通过更改参数,您必须再次等待 3 秒才能重新评估它。如果您想确切了解发生了什么,可以分析您的 solve() 调用:
profile on
solved = solve(constraints);
profile viewer
然后你可以看到mupadengine.evalin里面发生了什么,它是负责符号表达式求值的。
我有一些 Matlab 代码可以根据某些符号约束调用求解函数。第一次运行时,解决大约需要 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 秒。
我的猜测是,这是因为代码在第一次执行时会被缓存,所以后续的运行s会更快。通过更改参数,您必须 运行 代码一次,以便缓存新定义。
MATLAB 可以使用临时目录缓存脚本句柄。例如,在 运行 脚本之前和之后执行 clean all
,然后 运行 [M,X,C] = inmem('-completenames')
。您会注意到缓存了以下 类:
{'matlab.internal.editor.eval.TempFolder' }
{'matlab.internal.editor.eval.TmpFilePath' }
{'matlab.internal.editor.EODataStore' }
但关于性能,我调查了它,大约 99% 的 3 秒 运行 时间都花在了评估传递给 solve() 的符号表达式上,因此预计 运行time 对于随后的 运行s 会少很多,因为你的符号表达式没有改变。现在,通过更改参数,您必须再次等待 3 秒才能重新评估它。如果您想确切了解发生了什么,可以分析您的 solve() 调用:
profile on
solved = solve(constraints);
profile viewer
然后你可以看到mupadengine.evalin里面发生了什么,它是负责符号表达式求值的。