我可以沿着这些线写一些代码,为不同的频率计算一个符合初始条件的谐波函数。
from numpy import *
...
for i in range(n_freqs):
# A, B so that X(t) = A cos(w t) + B sin(w t)
# and X(t0) = x, dX/dt(t0) = v
w = ws[i] # use a frequency
solver = array(((+cos(w*t0), -sin(w*t0)),
(+sin(w*t0), +cos(w*t0))))
AB = solver @ array((x[i], v[i]/w)) # and store somewhere the result
但我想写更像
的内容Solver = array(((+cos(ws*t0), -sin(ws*t0)),
(+sin(ws*t0), +cos(ws*t0))))
AB = Solver @ vstack((x,v/ws)
M(未)WE
from numpy import *
ws = array((1., 2., 3., 4.))
x = array((3., 6., 2., 1.))
v = x
t0 = 10.0
Solver = array(((+cos(ws*t0), -sin(ws*t0)),
(+sin(ws*t0), +cos(ws*t0))))
AB = Solver @ vstack((x,v/ws)
给了我以下追踪
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: shapes (2,2,4) and (2,4) not aligned: 4 (dim 2) != 2 (dim 0)
,而
(Solver @ vstack((x,v/ws).T).shape # -> (2, 2, 2)
当我想要一个(2, 4)
(或(4,2)
,我不太挑剔)时...
是否可以编写一个循环次表达式,立即计算不同三角函数的系数?
答案 0 :(得分:2)
假设:我们希望得到Solver @ b[0]
,Solver @ b[1]
等等,即针对Solver
和b
的第一个轴并使用{{1}进行迭代} operator。
鉴于:@
,我们可以使用b = np.vstack((x,v/ws))
或einsum
或matmul/@
。
方法#1:使用np.einsum
-
tensordot/dot
方法#2:使用np.matmul
-
np.einsum('ijk,lk->lij',Solver, b).reshape(-1,2)
现在np.matmul(Solver, b.T).transpose(2,0,1).reshape(-1,2)
运算符,我相信,它取代了Python 3.5上的@
,我们只需要将np.matmul
替换为np.matmul(Solver, b.T)
。
方法#3:使用np.tensordot
-
Solver @ b.T
方法#4:我们还可以使用更受欢迎的np.dot
进行一些重塑,然后再将其提供给函数,就像这样 -
np.tensordot(b, Solver, axes=((-1),(-1))).reshape(-1,2)
示例运行 -
1)设置输入:
b.dot(Solver.reshape(4,-1).T).reshape(-1,2)
2)迭代获取输出:
In [7]: ws = np.array((1., 2., 3., 4.))
...: x = np.array((3., 6., 2., 1.))
...: v = x
...: t0 = 10.0
...: Solver = np.array(((+np.cos(ws*t0), -np.sin(ws*t0)), \
...: (np.sin(ws*t0), +np.cos(ws*t0))))
...: b = np.vstack((x,v/ws))
...:
3)使用In [8]: Solver @ b[0]
Out[8]:
array([[-0.42715738, -2.61465808],
[ 2.61465808, -0.42715738]])
In [9]: Solver @ b[1]
Out[9]:
array([[-1.35686862, -0.63436296],
[ 0.63436296, -1.35686862]])
并验证输出:
einsum
4)使用In [10]: np.einsum('ijk,lk->lij',Solver, b).reshape(-1,2)
Out[10]:
array([[-0.42715738, -2.61465808],
[ 2.61465808, -0.42715738],
[-1.35686862, -0.63436296],
[ 0.63436296, -1.35686862]])
并验证输出:
matmul
5)使用In [11]: np.matmul(Solver, b.T).transpose(2,0,1).reshape(-1,2)
Out[11]:
array([[-0.42715738, -2.61465808],
[ 2.61465808, -0.42715738],
[-1.35686862, -0.63436296],
[ 0.63436296, -1.35686862]])
运算符并验证输出:
@
6)使用In [14]: (Solver @ b.T).transpose(2,0,1).reshape(-1,2)
Out[14]:
array([[-0.42715738, -2.61465808],
[ 2.61465808, -0.42715738],
[-1.35686862, -0.63436296],
[ 0.63436296, -1.35686862]])
并验证输出:
tensordot
运行时测试 -
In [15]: np.tensordot(b, Solver, axes=((-1),(-1))).reshape(-1,2)
Out[15]:
array([[-0.42715738, -2.61465808],
[ 2.61465808, -0.42715738],
[-1.35686862, -0.63436296],
[ 0.63436296, -1.35686862]])
假设:我们有类似的东西 -
In [123]: ws = np.random.randint(1,9,(10000))
In [124]: x = np.random.randint(1,9,(10000))
In [125]: v = x
...: t0 = 10.0
...: Solver = np.array(((+np.cos(ws*t0), -np.sin(ws*t0)), \
...: (np.sin(ws*t0), +np.cos(ws*t0))))
...: b = np.vstack((x,v/ws))
...:
In [126]: %timeit np.einsum('ijk,lk->lij',Solver, b).reshape(-1,2)
...: %timeit np.matmul(Solver, b.T).transpose(2,0,1).reshape(-1,2)
...: %timeit np.tensordot(b, Solver, axes=((-1),(-1))).reshape(-1,2)
...: %timeit b.dot(Solver.reshape(4,-1).T).reshape(-1,2)
...:
10000 loops, best of 3: 147 µs per loop
10000 loops, best of 3: 75.1 µs per loop
10000 loops, best of 3: 67.5 µs per loop
10000 loops, best of 3: 60 µs per loop
避免任何堆叠操作并直接使用for i in range(len(x)):
v = x
w = ws[i]
solver = np.array(((+np.cos(w*t0), -np.sin(w*t0)),
(+np.sin(w*t0), +np.cos(w*t0))))
p = np.array((x[i], v[i]/w))
p0 = np.matmul(solver, p) # output at each iteration
,sine
条款的一种方法就是这样 -
cosine
答案 1 :(得分:2)
w
为(n,)
,因此cos(w*t0)
也具有此形状。 Solver
的布局为(2,2),但是(n,)元素为(2,2,n)。你正在用'(2,n)'点'。但是在n
或2
solver(ws[i]) @ array((x[i], v[i]/ws[i]))
表示您希望最后一个维度“适合骑行”,并指向Solver
的最后两个维度。在Einsum表示法中:
np.einsum('ijk,jk->ik', Solver, arr)
In [99]: Solver = np.array(((np.cos(wst),-np.sin(wst)),(np.sin(wst),np.cos(wst))))
In [101]: b = np.vstack((x,v/ws))
In [102]: b.shape
Out[102]: (2, 4)
In [103]: for i in range(4):
...: print(Solver[:,:,i]@b[:,i])
...:
[-0.88515125 -4.14927792]
[-0.29034338 6.70191769]
[ 0.96719065 -1.87322895]
[-0.85321635 0.57837865]
In [104]: np.einsum('ijk,jk->ik',Solver,b)
Out[104]:
array([[-0.88515125, -0.29034338, 0.96719065, -0.85321635],
[-4.14927792, 6.70191769, -1.87322895, 0.57837865]])
@
这不是一个简单的例子,因为它假设数组堆叠在第一维上。例如Solver
应为(n,2,2)
,b
(n,2,1)`
In [106]: Solver.transpose(2,0,1)@(b.T[...,None])
Out[106]:
array([[[-0.88515125],
[-4.14927792]],
[[-0.29034338],
[ 6.70191769]],
[[ 0.96719065],
[-1.87322895]],
[[-0.85321635],
[ 0.57837865]]])
In [107]: _.shape # need to squeeze out the last dim
Out[107]: (4, 2, 1)
如果我的推论是正确的,你的'点'维度是2,那么在该维度上迭代几乎同样快,特别是对于大的n:
res = np.zeros((2,n))
for i in range(2):
res += Solver[:,i,:] * b[i,:]