要计算 IRR,您需要求解一个多项式方程。这必须对每个现金流量向量分别进行。因此,应用于irr
多维矩阵不会提高执行时间。我怀疑 Matlab 内部仍然使用循环。
您可能可以通过使用优化选项来获得一些速度,fsolve
但不太可能有很大的改进。据推测,Matlab 开发人员已经选择了一种足够好的方法。
因此,您唯一的其他选择是并行化。如果您可以访问服务器或笔记本电脑/台式机有多个 CPU,则可以通过irr
并行运行函数来减少运行时间。(您可能还需要一个并行计算工具箱。)
我稍微修改了您的示例以使用随机现金流值以使其更易于检查。但是,我减少了场景和时间点的数量,以便该timeit
函数可以在合理的时间内运行多个模拟。(另外,请记住,执行时间似乎是时间点数量的指数。)
t = 150;
noScenarios = 10;
noThreads = 4;
CF = rand(t,noScenarios,noScenarios,noScenarios);
CF = [-rand(1,noScenarios,noScenarios,noScenarios); CF];
h1 = @() f1(CF, noScenarios);
fprintf("%0.4f : single thread, loop\n", timeit(h1))
h2 = @() f2(CF, noScenarios);
fprintf("%0.4f : single thread, vectorized\n", timeit(h2))
poolObj = parpool('local', noThreads);
h3 = @() f3(CF, noScenarios);
fprintf("%0.4f : parallelized outer loop\n", timeit(h3))
delete(poolObj);
poolObj = parpool('local', noThreads);
h4 = @() f4(CF, noScenarios);
fprintf("%0.4f : parallelized inner loop\n", timeit(h4))
delete(poolObj);
function res = f1(CF, noScenarios)
res = zeros(noScenarios, noScenarios, noScenarios);
for scenarios1 = 1:noScenarios
for scenarios2 = 1:noScenarios
for scenarios3 = 1:noScenarios
res(scenarios1,scenarios2,scenarios3) = irr(CF(:,scenarios1,scenarios2,scenarios3));
end
end
end
end
function res = f2(CF, noScenarios)
res = reshape(irr(CF), noScenarios, noScenarios, noScenarios);
end
function res = f3(CF, noScenarios)
res = zeros(noScenarios, noScenarios, noScenarios);
parfor scenarios1 = 1:noScenarios
for scenarios2 = 1:noScenarios
for scenarios3 = 1:noScenarios
res(scenarios1,scenarios2,scenarios3) = irr(CF(:,scenarios1,scenarios2,scenarios3));
end
end
end
end
function res = f4(CF, noScenarios)
res = zeros(noScenarios, noScenarios, noScenarios);
for scenarios1 = 1:noScenarios
for scenarios2 = 1:noScenarios
parfor scenarios3 = 1:noScenarios
res(scenarios1,scenarios2,scenarios3) = irr(CF(:,scenarios1,scenarios2,scenarios3));
end
end
end
end
当我在具有 4 个 CPU 和 16 Gb 内存的服务器上运行此代码时,我得到了以下结果。
19.9357 : single thread, loop
20.4318 : single thread, vectorized
...
5.6346 : parallelized outer loop
...
12.4640 : parallelized inner loop
如您所见,矢量化版本irr
的循环没有提供任何好处。在这种情况下,它会稍微慢一些。在我的其他测试中,它偶尔会更快一些。
但是,您可以通过将外部循环与parfor
函数并行化来显着减少运行时间。它比并行化最内层循环要好,因为每个批次都有一定的执行开销。因此,少量较大的批次比大量的较小批次具有更低的开销。
以下是并行化的工作原理。首先,您使用以下命令创建一个本地工作线程池。确保不超过您拥有的 CPU 数量。parpool
可以无限期地等待,直到创建所有本地工作人员,并且只有在 CPU 可用时才能创建本地工作人员。
poolObj = parpool('local', noThreads);
创建池可能需要几秒钟。这就是为什么我把它移到我计时的功能之外。对于较大的作业,池创建时间与总执行时间相比是微不足道的。
在这里,我将池对象保存在一个变量中,然后将其删除。但是,它是可选的。默认情况下,池在 30 分钟不活动或 Matlab 终止后被销毁。
之后,您将for
要并行化的循环替换为parfor
调用,即for scenarios1 = 1:noScenarios
变为parfor scenarios1 = 1:noScenarios
. 默认情况下,parfor
将使用所有可用的工作人员,但您也可以指定允许使用的工作人员的最大数量parfor (scenarios1 = 1:noScenarios, maxWorkers)
。但是请注意,执行顺序并不能保证,即第五次迭代可能在第三次迭代之前执行。