我想优化以下代码:
在蒙特卡罗模拟过程中,我累积了一些f(x)
(f(x)
计算成本很高)并在每个采样步骤后将它们保存在数组bins
中。
编辑:f(x)不是x的确定性函数(我的意思是它生成伪随机数并使用它们来修改结果)并且还取决于先前的计算值f(y)
for(int n=0;n<N;n++)
{
// compute some values f(x) at points "p"
for(auto k: p) bins[k] += f(k);
}
p.size()
远小于bins
的大小,但最终会设置大多数元素。
在模拟之后,我通过对bins
进行加权求和来累积我的最终值(g
是另一个数组中的查找):
for(int l=0;l<M;l++)
for(int k=0;k<bins.size();k++)
finalResult[l] += g(k,l)*bins[k];
我当然可以在每个采样步骤后计算更新后的finalResult
,但由于循环超过M
,这会使程序减慢很多。
我已经尝试了一个非常基本的boost::accumulate
,但这并没有提高性能(如果我坚持使用这种设计,我将不得不最终使用它,因为稳定性)。
所有数组都是Eigen::MatrixXd
类型,因为我需要它们进行BLAS操作。
p.size() < 10^2 N ~ 10^7 M ~ 10^4 bins.size() ~ 10^5
您对此处的优化技术有何建议?
答案 0 :(得分:1)
尝试为每个f(x)
值(即memoization)计算N
一次。例如,如果N
很大(就像在这种情况下那样),请尝试将循环更改为以下内容:
static std::unordered_map<unsigned int, double> memoizedFunction;
for(int n=0;n<N;n++)
{
// compute some values f(x) at points "p"
for(auto k: p)
{
auto it = memoizedFunction.find( k );
if (it == memoizedFunction.end())
{
it = memoizedFunction.emplace( f(k) ).first;
}
bins[k] += *it;
}
}
或者,您可以在k
中存储hit
广告符箱bins[k]
的次数,然后在最后通过并计算bins[k] * f(k)
k
。
答案 1 :(得分:0)
这里只是一个想法,但你可以验证f(x)是线性的 转换然后你可以创建矩阵 A ,使
[f(x)] = A[x] where [x] is the coordinates of x with respect to some basis B.
这可以使f(x)更容易和更快地计算,特别是如果x 存在于基数较小的向量空间中。
然而,如果在坐标和答案之间进行转换是昂贵的 这可以全面消除任何好处(只记住这一点)。
以下是一些可以帮助解释矩阵表示的链接 线性变换。
https://math.colorado.edu/~nita/MatrixRepresentations.pdf https://math.dartmouth.edu/archive/m24w07/public_html/Lecture12.pdf https://en.wikipedia.org/wiki/Transformation_matrix