如果我有一首颂歌并以两种方式写出来,比如:
function re=rabdab()
x=linspace(0,2000,2000)';
tic;
[T,Y] = ode45(@fun,[x],[0 1 1]);
[T,Y] = ode45(@fun,[x],[0 1 1]);
[T,Y] = ode45(@fun,[x],[0 1 1]);
toc;
tic;
[A,B] = ode45(@fun2,[x],[0 1 1]);
[A,B] = ode45(@fun2,[x],[0 1 1]);
[A,B] = ode45(@fun2,[x],[0 1 1]);
toc;
function dy = fun(t,y)
dy = zeros(3,1); % a column vector
dy = [y(2) * y(3);...
-y(1) * y(3);...
-0.51 * y(1) * y(2);];
function dy = fun2(t,y)
dy = zeros(3,1); % a column vector
dy(1) = y(2) * y(3);
dy(2) = -y(1) * y(3);
dy(3) = -0.51 * y(1) * y(2);
时间几乎没有差别。一个人和另一个人一样长。但我认为fun
是fun2
的矢量化版本。或者我错了?
目的是加快我的代码。该示例来自matlab网页。
我想我还没有真正明白“矢量化”是什么意思。
如果这已经过矢量化,那么非矢量化代码会是什么样的?
答案 0 :(得分:3)
Vectorization是一个与functional programming密切相关的概念。在MATLAB中,它意味着对数组(向量或矩阵)执行操作,而不隐式编写循环。
例如,如果要为1到100之间的每个整数f(x) = 2x
计算函数x
,可以写:
for x = 1:100
f(x) = 2 * x;
end
不是矢量化代码。矢量化版本是:
x = 1:100; %// Declare a vector of integer values from 1 to 100
f = 2 * x; %// Vectorized operation "*"
甚至更短:
f = 2 * (1:100);
MATLAB是一种解释型语言,所以很明显,解释器将其转换为“引擎盖下”的某种循环,但它经过优化并且通常比实际解释循环要快得多(读取this question以供参考)。嗯,有点像 - 直到最近发布的MATLAB,其中已集成了JIT acceleration(阅读here)。
现在回到你的代码:你在这里有两个代码的矢量化版本:一个垂直连接三个值,另一个直接将这些值分配到列向量中。这基本上是一回事。如果你用一个显式的for循环完成它,这将不会被“矢量化”。关于“向量化”循环的实际性能增益(即,将for循环转换为向量化操作),这取决于for循环实际上由于JIT加速实际上的速度。
似乎没有太多工作要加速你的代码。您的函数非常基本,因此它归结为ode45
的内部实现,您无法修改它。
如果您对进一步阅读有关矢量化和编写更快的MATLAB代码感兴趣,请参阅以下文章:Loren on the Art of MATLAB: "Speeding Up MATLAB Applications"。
快乐的编码!
答案 1 :(得分:1)
虽然前面的答案在一般情况下是正确的,vectorized 在 ODE 的上下文中意味着更具体的东西。简而言之,对于 f(t,y)
列向量,如果 f(t,[y1 y2 ...])
返回 [f(t,y1) f(t,y2) ...]
,函数 y1,y2
被向量化。根据文档 [1],“这允许求解器减少计算雅可比矩阵的所有列所需的函数评估次数。”
下面的函数 fun3
和 fun4
在 ODE 意义上被正确矢量化:
function re=rabdab()
x=linspace(0,20000,20000)';
opts=odeset('Vectorized','on');
tic;
[T,Y] = ode45(@fun,[x],[0 1 1]);
[T,Y] = ode45(@fun,[x],[0 1 1]);
[T,Y] = ode45(@fun,[x],[0 1 1]);
toc;
tic;
[A,B] = ode45(@fun2,[x],[0 1 1]);
[A,B] = ode45(@fun2,[x],[0 1 1]);
[A,B] = ode45(@fun2,[x],[0 1 1]);
toc;
tic;
[A,B] = ode45(@fun3,[x],[0 1 1],opts);
[A,B] = ode45(@fun3,[x],[0 1 1],opts);
[A,B] = ode45(@fun3,[x],[0 1 1],opts);
toc;
tic;
[A,B] = ode45(@fun4,[x],[0 1 1],opts);
[A,B] = ode45(@fun4,[x],[0 1 1],opts);
[A,B] = ode45(@fun4,[x],[0 1 1],opts);
toc;
function dy = fun(t,y)
dy = zeros(3,1); % a column vector
dy = [y(2) * y(3);...
-y(1) * y(3);...
-0.51 * y(1) * y(2);];
function dy = fun2(t,y)
dy = zeros(3,1); % a column vector
dy(1) = y(2) * y(3);
dy(2) = -y(1) * y(3);
dy(3) = -0.51 * y(1) * y(2);
function dy = fun3(t,y)
dy = zeros(size(y)); % a matrix with arbitrarily many columns, rather than a column vector
dy = [y(2,:) .* y(3,:);...
-y(1,:) .* y(3,:);...
-0.51 .* y(1,:) .* y(2,:);];
function dy = fun4(t,y)
dy = [y(2,:) .* y(3,:);... % same as fun3()
-y(1,:) .* y(3,:);...
-0.51 .* y(1,:) .* y(2,:);];
(顺便说一句:用 zeros
省略不必要的内存分配让 fun4
的运行速度比 fun3
略快。)
bvp4c
确实需要对第一个和第二个参数进行矢量化。 [1]官方文档 [1] 提供了有关 ODE 特定矢量化的更多详细信息(请参阅“雅可比属性说明”部分)。
[1] https://www.mathworks.com/help/releases/R2015b/matlab/ref/odeset.html