执行双重求和的最佳方法
most optimal way to perform double summation
例如下面的例子,假设可以轻松执行十万次操作,我如何优化计算 Gxx?如果我只是做嵌套的for循环来执行求和,那需要很长时间。有没有办法使用 sum 函数或其他方法来使这个过程更有效率?:
作为参考,我当前的伪代码是这样做的:
rrange=range(r-(rows-1)/2,r+(rows-1)/2)
crange=range(c-(cols-1)/2,c+(cols-1)/2)
Gxx=0
for rval,cval in product(rrange,crange):
#sum( for x in range())
Gxx+=(someval(rval,cval)-someval2)^2
用于计算Gxx(r,c)元素的单个元素,你无法优化任何东西。这是合乎逻辑的:毕竟你对 x 的结构一无所知所以你将不得不阅读所有 xj,i 范围内的元素。
但是,如果您需要计算整个矩阵,情况就不同了[=63=]。在这种情况下,您可以重用计算前一个元素的工作。
首先是一些基础数学。由于 x-bar(r,c) 不依赖于 j 或 i,这是一个过程中不断。现在我们知道:
(a-b)^2 = a^2+b^2-2*a*b
如果用 b 将其替换回 x-bar 常数。所以如果你把它应用到一个 sommation,你可以声明:
--- ---
\ \
/ (x_ji-b)^2 = / x_ji^2-2*b*x_ji+b^2 = S-2*s*b-D*b^2
--- ---
i,j i,j
与 S
x 元素的 平方 和 s x 个元素的总和。
现在如果你看一个矩阵,第一次迭代,你使用矩阵的某个域:
x x x x x x x x x
/-------\
x |x x x| x x x x x
| |
x |x x x| x x x x x
| |
x |x x x| x x x x x
\-------/
x x x x x x x x x
下一个 迭代,您只将作用域进一步移动一个元素,因此:
x x x x x x x x x
/-------\
x x |x^ x^ x| x x x x
| |
x x |x^ x^ x| x x x x
| |
x x |x^ x^ x| x x x x
\-------/
x x x x x x x x x
用^
表示的x
换句话说就是重用。所以我们可以做的是使用某种滑动 window.
你第一次这样先计算元素的总和和平方和(你存储它们)。接下来,每次移动 "cursor" 时,您都会再次减去不再在范围内的行列,并添加出现在范围内的列。因此,一个基本算法是:
for r in range (rmin,rmax) :
sum = 0
sumsq = 0
jmin = r-(rows-1)/2
jmax = r+(rows-1)/2
#calculate sum and sum of square of the first
imin = cmin-(cols-1)/2
imax = cmin+(cols-1)/2
for j,i in product(range(jmin,jmax),range(imin,imax)) :
xji = x(j,i) #cache xji
sum += xji
sumsq += xji * xji
d = (jmax-jmin)*(imax-imin)
#now we can calculate the first element of the row
xb = xbar(r,cmin)
Gxx(r,cmin) = sumsq-2*sum*xb+d*xb*xb
#now iterate over all elements (except the first)
for c in range(cmin+1,cmax) :
isub = c-1-(cols-1)/2 #column to remove, (previous column = -1)
iadd = c+(cols-1)/2 #column to add
for j in range(jmin,jmax) :
xji = x(j,isub)
sum -= xji
sumsq -= xji*xji
xji = x(j,iadd)
sum += xji
sumsq += xji*xji
#Now the sums and the sum of squares are updated
xb = xbar(r,c)
Gxx(r,c) = sumsq-2*sum*xb+d*xb*xb
我认为会有一些工作来适应算法,但它应该是可行的。此外,请先在一个小实例上检查它是否工作正常。小的舍入误差是可能的。
如果 cols
和 rows
很小,这不会有太大区别,但如果它们很大,它会产生巨大的提升。
例如下面的例子,假设可以轻松执行十万次操作,我如何优化计算 Gxx?如果我只是做嵌套的for循环来执行求和,那需要很长时间。有没有办法使用 sum 函数或其他方法来使这个过程更有效率?:
作为参考,我当前的伪代码是这样做的:
rrange=range(r-(rows-1)/2,r+(rows-1)/2)
crange=range(c-(cols-1)/2,c+(cols-1)/2)
Gxx=0
for rval,cval in product(rrange,crange):
#sum( for x in range())
Gxx+=(someval(rval,cval)-someval2)^2
用于计算Gxx(r,c)元素的单个元素,你无法优化任何东西。这是合乎逻辑的:毕竟你对 x 的结构一无所知所以你将不得不阅读所有 xj,i 范围内的元素。
但是,如果您需要计算整个矩阵,情况就不同了[=63=]。在这种情况下,您可以重用计算前一个元素的工作。
首先是一些基础数学。由于 x-bar(r,c) 不依赖于 j 或 i,这是一个过程中不断。现在我们知道:
(a-b)^2 = a^2+b^2-2*a*b
如果用 b 将其替换回 x-bar 常数。所以如果你把它应用到一个 sommation,你可以声明:
--- ---
\ \
/ (x_ji-b)^2 = / x_ji^2-2*b*x_ji+b^2 = S-2*s*b-D*b^2
--- ---
i,j i,j
与 S
x 元素的 平方 和 s x 个元素的总和。
现在如果你看一个矩阵,第一次迭代,你使用矩阵的某个域:
x x x x x x x x x
/-------\
x |x x x| x x x x x
| |
x |x x x| x x x x x
| |
x |x x x| x x x x x
\-------/
x x x x x x x x x
下一个 迭代,您只将作用域进一步移动一个元素,因此:
x x x x x x x x x
/-------\
x x |x^ x^ x| x x x x
| |
x x |x^ x^ x| x x x x
| |
x x |x^ x^ x| x x x x
\-------/
x x x x x x x x x
用^
表示的x
换句话说就是重用。所以我们可以做的是使用某种滑动 window.
你第一次这样先计算元素的总和和平方和(你存储它们)。接下来,每次移动 "cursor" 时,您都会再次减去不再在范围内的行列,并添加出现在范围内的列。因此,一个基本算法是:
for r in range (rmin,rmax) :
sum = 0
sumsq = 0
jmin = r-(rows-1)/2
jmax = r+(rows-1)/2
#calculate sum and sum of square of the first
imin = cmin-(cols-1)/2
imax = cmin+(cols-1)/2
for j,i in product(range(jmin,jmax),range(imin,imax)) :
xji = x(j,i) #cache xji
sum += xji
sumsq += xji * xji
d = (jmax-jmin)*(imax-imin)
#now we can calculate the first element of the row
xb = xbar(r,cmin)
Gxx(r,cmin) = sumsq-2*sum*xb+d*xb*xb
#now iterate over all elements (except the first)
for c in range(cmin+1,cmax) :
isub = c-1-(cols-1)/2 #column to remove, (previous column = -1)
iadd = c+(cols-1)/2 #column to add
for j in range(jmin,jmax) :
xji = x(j,isub)
sum -= xji
sumsq -= xji*xji
xji = x(j,iadd)
sum += xji
sumsq += xji*xji
#Now the sums and the sum of squares are updated
xb = xbar(r,c)
Gxx(r,c) = sumsq-2*sum*xb+d*xb*xb
我认为会有一些工作来适应算法,但它应该是可行的。此外,请先在一个小实例上检查它是否工作正常。小的舍入误差是可能的。
如果 cols
和 rows
很小,这不会有太大区别,但如果它们很大,它会产生巨大的提升。