简体   繁体   English

计算numpy中的L2内积?

[英]Calculating the L2 inner product in numpy?

I'm thinking about the L2 inner product. 我正在考虑L2内部产品。

I am specifically interested in performing these calculations using numpy/scipy. 我对使用numpy / scipy执行这些计算特别感兴趣。 The best I have come up with is performing an array-based integral such as numpy.trapz . 我想到的最好的方法是执行基于数组的积分,例如numpy.trapz

import numpy as np
n=100000.
h=1./n
X = np.linspace(-np.pi,np.pi,n)

def L2_inner_product(f,g):
    return np.trapz(f*g,dx=2*np.pi*h)/np.pi

print L2_inner_product(np.sin(X), np.sin(X))
print L2_inner_product(np.cos(2*X), np.cos(2*X))
print L2_inner_product(np.sin(X), np.cos(X))
print L2_inner_product(np.sin(X), np.cos(3*X))
print L2_inner_product(np.ones(n),np.ones(n))

0.99999
0.99999
-3.86525742539e-18
1.6565388966e-18
1.99998

To be clear, I am not interested in using Mathematica, Sage, or Sympy. 需要明确的是,我对使用Mathematica,Sage或Sympy不感兴趣。 I am specifically interested in numpy/scipy, in which I am exploring the numpy "array space" as a finite subspace of Hilbert Space. 我对numpy / scipy特别感兴趣,在其中我将numpy“数组空间”作为Hilbert空间的有限子空间进行探索。 Within these parameters, have others implemented an L2 inner product, perhaps using numpy.inner or numpy.linalg.norm ? 在这些参数中,是否有人使用numpy.innernumpy.linalg.norm实现了L2内部产品?

With respect to speed, numpy.inner is probably the best choice for fixed n . 就速度而言, numpy.inner可能是固定n的最佳选择。 numpy.trapz should be converging faster though. numpy.trapz应该收敛得更快。 Either way, if you are worried about speed, you should also take into account the evaluation of the functions themselves will also take some time. 无论哪种方式,如果您担心速度,则还应该考虑到对函数本身的评估也将花费一些时间。

Below some simple benchmark I ran using different inner product implementations. 在一些简单的基准测试之下,我使用了不同的内部产品实现。

Timings 计时

The plot below shows the runtime for the computation of only the integral, ie not the function evaluation. 下图显示了仅计算积分(即不计算函数)的运行时间。 While numpy.trapz is a constant factor slower, numpy.inner is as fast as calling BLAS dirrectly. 虽然numpy.trapz是一个常数因子,但numpy.inner与直接调用BLAS一样快。 As Ophion pointed out, numpy.inner calls BLAS internally probably with some overhead for input checking. 正如Ophion指出的那样, numpy.inner内部调用BLAS可能numpy.inner输入检查带来一些开销。 用于计算内部乘积中乘积和的运行时。

It is also interesting to look at the time it takes to evaluate the function itself, which has of course to be done to compute the inner product. 查看功能本身所需的时间也很有趣,这当然需要计算内部乘积。 Below a plot that shows the evaluation for standard transcendental functions numpy.sin , numpy.sqrt and numpy.exp . 在显示标准超越函数numpy.sinnumpy.sqrtnumpy.exp的评估的numpy.sqrt numpy.exp The scaling is of course the same for the evaluation and the summing of the products and the overall time required is comparable 评估的比例当然是相同的,产品的总和与所需的总时间是可比的

内部产品中功能评估的运行时。

Error 错误

Finally, one should also consider the accuracy of the different methods, and it's here where it actually gets interesting. 最后,还应该考虑不同方法的准确性,而这正是它真正引起人们关注的地方。 Below a plot of the convergence of the different implementation for the computation of 下面是不同实现的收敛图,用于计算 \\ langle exp(x),exp(x)\\ rangle . Here we can see that numpy.trapz actually scales much better than the other two implementations, which don't even reach machine precision before I run out of memory. 在这里,我们可以看到numpy.trapz实际上比其他两个实现好得多,在我用完内存之前,这两个实现甚至都没有达到机器精度。

在此处输入图片说明

Conclusion 结论

Considering the bad convergence properties of numpy.inner , I would go for numpy.trapz . 考虑到numpy.inner的不良收敛特性,我将使用numpy.trapz But even then a lot of integration nodes are required to get satisfactory accuracy. 但是即使如此,仍需要大量集成节点才能获得令人满意的精度。 Since your integration domain is fixed you might even try going for higher order quadratures. 由于您的集成域是固定的,因此您甚至可以尝试使用更高阶的正交。

Code

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sls
from scipy.linalg.blas import ddot
import timeit

## Define inner product.
def l2_inner_blas( f, g, dx ):
    return ddot( f, g )*dx / np.pi

def l2_inner( f, g, dx ):
    return np.inner( f, g )*dx / np.pi

def l2_inner_trapz( f, g, dx ):
    return np.trapz(f*g,dx=dx) / np.pi

sin1 = lambda x: np.sin( x )
sin2 = lambda x: np.sin( 2.0 * x)

## Timing setups.
setup1 = "import numpy as np; from __main__ import l2_inner,"
setup1 += "l2_inner_trapz, l2_inner_blas, sin1, sin2;"
setup1 += "n=%d; x=np.linspace(-np.pi,np.pi,n); dx=2.0*np.pi/(n-1);"
setup1 += "f=sin1(x); g=sin2(x);"

def time( n ):
    setupstr = setup1 % n
    time1 = timeit.timeit( 'l2_inner( f, g, dx)', setupstr, number=10 )
    time2 = timeit.timeit( 'l2_inner_blas( f, g, dx)', setupstr, number=10 )
    time3 = timeit.timeit( 'l2_inner_trapz( f, g, dx)', setupstr, number=10 )
    return (time1, time2, time3)

setup2 = "import numpy as np; x = np.linspace(-np.pi,np.pi,%d);"
def time_eval( n ):
    setupstr = setup2 % n
    time_sin = timeit.timeit( 'np.sin(x)', setupstr, number=10 )
    time_sqrt = timeit.timeit( 'np.sqrt(x)', setupstr, number=10 )
    time_exp = timeit.timeit( 'np.exp(x)', setupstr, number=10 )
    return (time_sin, time_sqrt, time_exp)

## Perform timing for vector product.
times = np.zeros( (7,3) )
for i in range(7):
    times[i,:] = time( 10**(i+1) )

x = 10**np.arange(1,8,1)
f, ax = plt.subplots()
ax.set( xscale='log', yscale='log', title='Inner vs. BLAS vs. trapz', \
        ylabel='time [s]', xlabel='n')
ax.plot( x, times[:,0], label='numpy.inner' )
ax.plot( x, times[:,1], label='scipy.linalg.blas.ddot')
ax.plot( x, times[:,2], label='numpy.trapz')
plt.legend()

## Perform timing for function evaluation.
times_eval = np.zeros( (7,3) )
for i in range(7):
    times_eval[i,:] = time_eval( 10**(i+1) )

x = 10**np.arange(1,8,1)
f, ax = plt.subplots()
ax.set( xscale='log', yscale='log', title='sin vs. sqrt vs. exp', \
        ylabel='time [s]', xlabel='n')
ax.plot( x, times_eval[:,0], label='numpy.sin' )
ax.plot( x, times_eval[:,1], label='numpy.sqrt')
ax.plot( x, times_eval[:,2], label='numpy.exp' )
plt.legend()

## Test convergence.
def error( n ):
    x = np.linspace( -np.pi, np.pi, n )
    dx = 2.0 * np.pi / (n-1)
    f = np.exp( x )
    l2 = 0.5/np.pi*(np.exp(2.0*np.pi) - np.exp(-2.0*np.pi))
    err1 = np.abs( (l2 - l2_inner( f, f, dx )) / l2)
    err2 = np.abs( (l2 - l2_inner_blas( f, f, dx )) / l2)
    err3 = np.abs( (l2 - l2_inner_trapz( f, f, dx )) / l2)
    return (err1, err2, err3)

acc = np.zeros( (7,3) )
for i in range(7):
    acc[i,:] = error( 10**(i+1) )

x = 10**np.arange(1,8,1)
f, ax = plt.subplots()
ax.plot( x, acc[:,0], label='numpy.inner' )
ax.plot( x, acc[:,1], label='scipy.linalg.blas.ddot')
ax.plot( x, acc[:,2], label='numpy.trapz')
ax.set( xscale='log', yscale='log', title=r'$\langle \exp(x), \exp(x) \rangle$', \
        ylabel='Relative Error', xlabel='n')
plt.legend()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM