This may seem like a silly question, but I am a bloody newby in Python (and in programming). I am running a physics simulation that involves many (~10 000) 2x2 matrices that I store in an array. I call these matrices M and the array T in the code below. Then I simply want to compute the product of all of these matrices. This is what I came up with, but it looks ugly and it would be so much work for 10000+ 2x2 matrices. Is there a simpler way or an inbuilt function that I could use?
import numpy as np
#build matrix M (dont read it, just an example, doesnt matter here)
def M(k1 , k2 , x):
a = (k1 + k2) * np.exp(1j * (k2-k1) * x)
b = (k1 - k2) * np.exp(-1j * (k1 + k2) * x)
c = (k1 - k2) * np.exp(1j * (k2 + k1) * x)
d = (k1 + k2) * np.exp(-1j * (k2 - k1) * x)
M = np.array([[a , b] , [c , d]])
M *= 1. / (2. * k1)
return M
#array of test matrices T
T = np.array([M(1,2,3), M(3,3,3), M(54,3,9), M(33,11,42) ,M(12,9,5)])
#compute the matrix product of T[0] * T[1] *... * T[4]
#I originally had this line of code, which is wrong, as pointed out in the comments
#np.dot(T[0],np.dot(T[1], np.dot(T[2], np.dot(T[2],np.dot(T[3],T[4])))))
#it should be:
np.dot(T[0], np.dot(T[1], np.dot(T[2],np.dot(T[3],T[4]))))
Not very NumPythonic, but you could do:
reduce(lambda x,y: np.dot(x,y), T, np.eye(2))
Or more concisely, as suggested
reduce(np.dot, T, np.eye(2))
Related
I have the following Matlab code:
A=[length(x) sum(x) sum(y) sum(x.*y);
sum(x) sum(x.^2) sum(x.*y) sum(y.*x.^2);
sum(y) sum(x.*y) sum(y.^2) sum(x.*y.^2);
sum(x.*y) sum((x.^2).*y) sum(x.*y.^2) sum((x.^2).*(y.^2))];
v=[sum(z); sum(z.*x); sum(z.*y); sum(x.*y.*z)];
solution=inv(A)*v;
a=solution(1);
b=solution(2);
c=solution(3);
d=solution(4);
which I want to convert into Python. I have no knowledge of Matlab, and with some research came up with the following Python code:
A = [
[len(x), x.sum(), y.sum(), (x * y).sum()],
[x.sum(), (x**2).sum(), (x * y).sum(), ((y * x) ** 2).sum()],
[y.sum(), (x * y).sum(), (y**2).sum(), ((x * y) ** 2).sum()],
[(x * y).sum(), ((x**2) * y).sum(), ((x * y)**2).sum(), ((x**2) * (y**2)).sum()]
]
v = [z.sum(), (z * x).sum(), (z * y).sum(), (x * y * z).sum()]
solution = np.linalg.inv(A) * v
I excpected a list with 4 values, which should be the coefficients which I want to use for a function. However, the result is another matrix. What am I doing wrong?
In the last step, you should use matrix multiplication instead of corresponding position multiplication.
Matrix multiplication uses operator#:
solution = np.linalg.inv(A) # v
Or function numpy.matmul:
solution = np.matmul(np.linalg.inv(A), v)
I have an expression for a complex function as follows:
f(z) = 1/jwC + (R1(1+jwC1) + R2(1+jwC2))/(1+jwR1C1)(1+jwR2C2)
where j = sqrt(-1)
How do I compute f(z) in Python, given the values of w, R1, R2, C, C1, C2 and then seperate out the real and imaginary portions of f(z)?
Complex numbers are one of the standard types in Python.
So you could just write:
#!/usr/bin/env python3
def f(w, R1, R2, C, C1, C2):
return 1 / (1j * w * C) + (R1 * (1 + 1j * w * C1) + R2 * (
1 + 1j * w * C2)) / ((1 + 1j * w * R1 * C1) * (1 + 1j * w * R2 * C2))
result = f(w=1000, R1=100, R2=200, C=100.0e-9, C1=100.0e-9, C2=200.0e-9)
print(result)
print(result.real)
print(result.imag)
(NB: please check the math epxression yourself, since I didn't verify if the results are actually correct. I may have misinterpreted your equation or made a typo.)
I have a function in python that is meant to operate on a scalar input, but multiplies matrices in the process. The exact code is shown below:
def f(t, n):
T = np.pi
a_0 = 0.5
n = np.arange(1, n + 1)
# Calculate the Fourier series of f(t)
a_n = np.sin(n*T) / (n * np.pi)
b_n = (1 - np.cos(n * T)) / (n * np.pi)
res = a_0 + np.sum(a_n * np.cos(n*t)) + np.sum(b_n * np.sin(n*t))
return res
Now, I want this to operate on a vector of inputs t, and for the implementation to stay vectorised (not to use for loops). I can see that making a matrix of dimensions len(t) x n where the initial vector n is just stacked vertically len(t) times, and then performing elementwise multiplication with t would be a solution, but what would be the proper way to implement this function?
Here's one vectorized approach that accepts a vector of inputs as t making use of broadcasting and sum-reduction for the final step with matrix-multiplication using np.dot -
def f_vectorized(t, n): # where t is an array
t2D = t[:,None]
T = np.pi
a_0 = 0.5
n = np.arange(1, n + 1)
a_n = np.sin(n*T) / (n * np.pi)
b_n = (1 - np.cos(n * T)) / (n * np.pi)
nt2D = n*t2D
return a_0 + np.cos(nt2D).dot(a_n) + np.sin(nt2D).dot(b_n)
Sample run -
In [142]: t
Out[142]: array([8, 1, 8, 0, 2, 7, 8, 8])
In [143]: n = 5
In [144]: f_vectorized(t,n)
Out[144]:
array([ 1.03254608, 0.94354963, 1.03254608, 0.5 , 0.95031599,
1.04127659, 1.03254608, 1.03254608])
Here is a formulaic "vectorisation". Note that only a handful of changes were necessary. First line and last but one.
First line: the asanyarray allows to accept array-like inputs, i.e. scalars, arrays, nested lists etc. and treat them all the same. The indexing adds one axis at the very end. That is the space for the Fourier coefficients. Conveniently, these will be automatically broadcast since they occupy the last dimension and missing axes are inserted on the left. This is why the code works almost unchanged.
Only the summations in the end have to be restricted to the Fourier axis, which is what the ..., axis=-1) kwargs do.
def f(t, n):
t = np.asanyarray(t)[..., None]
T = np.pi
a_0 = 0.5
n = np.arange(1, n + 1)
# Calculate the Fourier series of f(t)
a_n = np.sin(n*T) / (n * np.pi)
b_n = (1 - np.cos(n * T)) / (n * np.pi)
res = a_0 + np.sum(a_n * np.cos(n*t), axis=-1) + np.sum(b_n * np.sin(n*t), axis=-1)
return res
So I've been trying to fit to an exponentially modified gaussian function (if interested, https://en.wikipedia.org/wiki/Exponentially_modified_Gaussian_distribution)
import numpy as np
import scipy.optimize as sio
import scipy.special as sps
def exp_gaussian(x, h, u, c, t):
z = 1.0/sqrt(2.0) * (c/t - (x-u)/c) #not important
k1 = k2 = h * c / t * sqrt(pi / 2) #not important
n1 = 1/2 * (c / t)**2 - (x-u)/t #not important
n2 = -1 / 2 * ((x - u) / c)**2 #not important
y = np.zeros(len(x))
y += (k1 * np.exp(n1) * sps.erfc(z)) * (z < 0)
y += (k2 * np.exp(n2) * sps.erfcx(z)) * (z >= 0)
return y
In order to prevent overflow problems, one of two equivilent functions must be used depending on whether z is positive or negative (see Alternative forms for computation from previous wikipedia page).
The problem I am having is this: The line y += (k2 * np.exp(n2) * sps.erfcx(z)) * (z >= 0)is only supposed to add to y when z is positive. But if z is, say, -30, sps.erfcx(-30) is inf, and inf * False is NaN. Therefore, instead of leaving y untouched, the resulting y is clustered with NaN. Example:
x = np.linspace(400, 1000, 1001)
y = exp_gaussian(x, 100, 400, 10, 5)
y
array([ 84.27384586, 86.04516723, 87.57518493, ..., nan,
nan, nan])
I tried the replacing the line in question with the following:
y += numpy.nan_to_num((k2 * np.exp(n2) * sps.erfcx(z)) * (z >= 0))
But doing this ran into serious runtime issues. Is there a way to only evaluate (k2 * np.exp(n2) * sps.erfcx(z)) on the condition that (z >= 0) ? Is there some other way to solve this without sacrificing runtime?
Thanks!
EDIT: After Rishi's advice, the following code seems to work much better:
def exp_gaussian(x, h, u, c, t):
z = 1.0/sqrt(2.0) * (c/t - (x-u)/c)
k1 = k2 = h * c / t * sqrt(pi / 2)
n1 = 1/2 * (c / t)**2 - (x-u)/t
n2 = -1 / 2 * ((x - u) / c)**2
return = np.where(z >= 0, k2 * np.exp(n2) * sps.erfcx(z), k1 * np.exp(n1) * sps.erfc(z))
How about using numpy.where with something like: np.where(z >= 0, sps.erfcx(z), sps.erfc(z)). I'm no numpy expert, so don't know if it's efficient. Looks elegant at least!
One thing you could do is create a mask and reuse it so it wouldn't need to be evaluated twice. Another idea is to use the nan_to_num only once at the end
mask = (z<0)
y += (k1 * np.exp(n1) * sps.erfc(z)) * (mask)
y += (k2 * np.exp(n2) * sps.erfcx(z)) * (~mask)
y = numpy.nan_yo_num(y)
Try and see if this helps...
I have the following set of equations, and I want to solve them simultaneously for X and Y. I've been advised that I could use numpy to solve these as a system of linear equations. Is that the best option, or is there a better way?
a = (((f * X) + (f2 * X3 )) / (1 + (f * X) + (f2 * X3 ))) * i
b = ((f2 * X3 ) / (1 + (f * X) + (f2 * X3))) * i
c = ((f * X) / (1 + (j * X) + (k * Y))) * i
d = ((k * Y) / (1 + (j * X) + (k * Y))) * i
f = 0.0001
i = 0.001
j = 0.0001
k = 0.001
e = 0 = X + a + b + c
g = 0.0001 = Y + d
h = i - a
As noted by Joe, this is actually a system of nonlinear equations. You are going to need more firepower than numpy alone provides.
Solution of nonlinear equations is tricky, and the typical approach is to define an objective function
F(z) = sum( e[n]^2, n=1...13 )
where z is a vector containing a value for each of your 13 variables a,b,c,d,e,f,g,h,i,X,Y and e[n] is the amount by which each of your 13 equations is violated. For example
e[3] = (d - ((k * Y) / (1 + (j * X) + (k * Y))) * i )
Once you have that objective function, then you can apply a nonlinear solver to try to find a z for which F(z)=0. That of course corresponds to a solution to your equations.
Commonly used solvers include:
The Solver in Microsoft Excel
The python library scipy.optimize
Fitting routines in the Gnu Scientific Library
Matlab's optimization toolbox
Note that all of them will work far better if you first alter your set of equations to eliminate as many variables as practical before trying to run the solver (e.g. by substituting for k wherever it is found). The reduced dimensionality makes a big difference.