Reputation: 1573
I'd like to multiply two matrices (to be clear I want it in the linear algebra meaning of the word, i.e., if you want further clarification of what I mean see this Wikipedia article) I've tried A * B
(which I got by following the MATLAB to Numpy guide at Scipy Wiki) but when A
had dimensions of (N-1)x(N-1) and B
had dimensions of (N-1)x(N+1) it gave out the ValueError (where N=100
):
ValueError: operands could not be broadcast together with shapes (99,99) (99,101)
I also tried np.dot(A,B)
in case I was unintentionally using an array (ps. this could be the case, as I do have a few np.asarray commands for the vectors I built A and B from. How do I convert them to matrices?) and not a matrix and got the same result.
This is my code in full (granted A and B are replaced by np.diag(xasub)
and np.sin...
, respectively and this is on the d2Tsub
line)
import numpy as np
import scipy.special as sp
N = 100
n = range(0,N+1)
xmin = -10
xmax = 5
pi = np.pi
x = np.cos(np.multiply(pi / float(N), n))
xa = np.asarray(x)
xasub = xa[1:N]
xc = (1+xa)*(xmax-xmin) / float(2)
xcsub = xc[1:N]
na = np.asarray(n)
nd = np.transpose(na)
T = np.cos(np.outer(np.arccos(xa),nd))
Tsub = T[1:-1]
from numpy import linalg as LA
dT = np.sin(np.outer(np.arccos(xa),nd))*na
dTsub = dT[1:-1]
d2Tsub = np.diag(np.power((xasub*xasub-1),-1)) * (Tsub*nd - np.diag(xasub) * np.sin(np.outer(np.arccos(xasub),nd))) * nd
Upvotes: 0
Views: 301
Reputation: 231385
I've replicated your MATLAB code with:
N = 100.
n = np.arange(N+1).reshape(1,-1)
x = np.cos(np.pi*n/N).T
xsub = x[1:-1,:]
T = np.cos(np.arccos(x)*n) # broadcasted outer product
Tsub = T[1:-1,:]
dT = np.dot(np.sin(np.arccos(x)*n), np.diag(n.flat))
# np.diag needs 1d input to generate 2d array
# this is a case of matrix multiplication, the np.dot for array
# * for np.matrix
continuing
temp = np.dot(np.diag(xsub.flat), np.sin(np.arccos(xsub)*n))
temp = np.dot(Tsub, np.diag(n.flat)) - temp
temp = np.dot(temp, np.diag(n.flat))
d2Tsub = np.dot(np.diag((1/np.sqrt(1-xsub**2)).flat), temp))
messy, but runs and generates matching value. Use of np.matrix
versions of these arrays might simplify the appearance, as would cleaning up the repeated np.diag(...flat)
.
for the rest of d2T
, this vstack
is a pretty literal translation.
d2T1 = ((-1)**n) * (n**2-1) * (n**2)/3
d2T2 = (n**2-1) * (n**2)/3
d2T = np.vstack([d2T1, d2Tsub, d2T2])
last step is a matrix divide. MATLAB has 2 versions:
D2 = np.linalg.solve(T, d2T) # matlab T\d2T
D2 = np.linalg.solve(T.T, d2T.T).T # matlab d2T/T
I worked out this last equivalence from the Octave docs for Y/X
and X\Y
.
This is a literal translation. I'm not trying to understand what is going on, or to make it idiomatic numpy
.
A partial simplification. No need for matrix products to use diagonal matrices. Simple (broadcasted) element multiplication is enough.
n = np.arange(N+1)
x = np.cos(np.pi*n/N)[:,None]
Xn = np.arccos(x)*n
T = np.cos(Xn)
dT = np.sin(Xn)*n
xsub = x[1:-1,:]
d2Tsub = ((1-xsub**2)**(-.5)) * (T[1:-1,:] * n - xsub * np.sin(Xn[1:-1,:]))
d2T2 = (n**2-1) * (n**2)/3
d2T1 = ((-1)**n) * d2T2
You could probably replace a lot of the diag(n)*
in matlab with n.*
For example
dT = n.*sin(acos(x)*n); # equals
dT = sin(acos(x)*n)*diag(n);
However, I tested this in Octave which now has broadcasting. I'm not sure where MATLAB stands in that regard.
Upvotes: 1
Reputation: 30210
In fact, you have all arrays and no matrices:
xasub : <type 'numpy.ndarray'>
xc : <type 'numpy.ndarray'>
xa : <type 'numpy.ndarray'>
xmin : <type 'int'>
LA : <type 'module'>
na : <type 'numpy.ndarray'>
nd : <type 'numpy.ndarray'>
Tsub : <type 'numpy.ndarray'>
np : <type 'module'>
pi : <type 'float'>
dTsub : <type 'numpy.ndarray'>
N : <type 'int'>
T : <type 'numpy.ndarray'>
sp : <type 'module'>
xcsub : <type 'numpy.ndarray'>
n : <type 'list'>
xmax : <type 'int'>
x : <type 'numpy.ndarray'>
dT : <type 'numpy.ndarray'>
So you'll need to modify the last line to use np.dot()
accordingly, for example (with horrible variable names):
#d2Tsub = np.diag(np.power((xasub*xasub-1),-1)) * (Tsub*nd - np.diag(xasub) * np.sin(np.outer(np.arccos(xasub),nd)))*nd * nd
d2T_1 = np.diag(np.power((xasub*xasub-1),-1))
d2T_2 = np.dot( np.diag(xasub), np.sin(np.outer(np.arccos(xasub),nd)) )
d2T_3 = np.dot(d2T_1, (Tsub*nd - d2T_2))
d2Tsub = np.dot(d2T_3, nd)
print d2Tsub.shape # (99L,)
Of course, you could use the a.dot(b)
syntax instead of np.dot(a,b)
and save a tiny bit space.
Upvotes: 0