Python: Element assignment in a scipy.sparse.diags matrix - python

I'm currently trying to change a row in a matrix which I created using the scipy.sparse.diags function. However, it returns the following error saying that I cannot assign to this object:
TypeError: 'dia_matrix' object does not support item assignment
Is there any way around this without having to change the original vectors used to form the tridiagonal matrix? The following is my code:
def Mass_Matrix(x0):
"""Finds the Mass matrix for any non uniform mesh x0"""
x0 = np.array(x0)
N = len(x0) - 1
h = x0[1:] - x0[:-1]
a = np.zeros(N+1)
a[0] = h[0]/3
for j in range(1,N):
a[j] = h[j-1]/3 + h[j]/3
a[N] = h[N-1]/3
b = h/6
c = h/6
data = [a.tolist(), b.tolist(), c.tolist()]
Positions = [0,1,-1]
Mass_Matrix = diags(data, Positions, (N+1,N+1))
return Mass_Matrix
def Initial_U(x0): #BC here
x0 = np.array(x0)
h = x0[1:] - x0[:-1]
N = len(x0) - 1
Mass = Mass_Matrix(x0)
Mass[0] = 0 #ITEM ASSIGNMENT ERROR
print Mass.toarray()

For a sparse matrix defined with your function:
x0=np.arange(10)
mm=Mass_Matrix(x0)
The csr format is the one that is normally used for calculations, such as matrix multiplication, and linalg solve. It does define assignment, but gives an efficiency warning:
In [29]: mmr=mm.tocsr()
In [30]: mmr[0]=0
/usr/lib/python3/dist-packages/scipy/sparse/compressed.py:690: SparseEfficiencyWarning: Changing the sparsity structure of a csr_matrix is expensive. lil_matrix is more efficient.
SparseEfficiencyWarning)
lil works fine
In [31]: mml=mm.tolil()
In [32]: mml[0]=0
Many of the sparse functions and methods convert one format to another to take advantage of their respective strengths. But the developers haven't implemented all possible combinations. You need to read the pros and cons of the various formats, and also note the methods for each.

Related

Update a Numpy 1D array B in each loop to solve the matrix expression A*x = B

I need to solve x from sparse matrix expression A*x = B in loops, where A is a Scipy CSC sparse-matrix and B is Numpy 1D array. Both A and B are large about 500K rows. Basically, I need to update B in each loop. So the speed to update B is critical. Right now, my way is to define csc_matrix in each loop, and then convert it to 1D Numpy array as below which is really expensive in terms of time:
B = csc_matrix((data,(row, col)),shape=(500000, 1), dtype='complex128').toarray()[:,0];
Please note:
row has lots of the repeated index, such as [0,1,2,0,2,2,3,3....],
col is [0,0, 0,.......0];
Is there fast way to update B in each loop?
Assuming col contains only zeros, data/row/col are Numpy arrays and you want B stored as a Numpy array. You can use Numba to generate B efficiently. Here is how:
import numba
# Works in-place to avoid any slow allocation in the critical loop.
# Note that the type of row may be different.
#nb.njit(void(nb.complex128[:], nb.complex128[:], nb.int64[:]))
def updateVector(B, data, row):
B.fill(0.)
for i in range(len(row)):
B[row[i]] += data[i]
updateVector update the value of B in-place. This assume B has been allocated at the correct size before (using for example B = np.empty(500000, dtype=np.complex128)).
On my machine this is 14 times faster with the following configuration:
row = np.random.randint(0, 500000, size=100000)
col = np.zeros(100000, dtype=np.int64)
data = np.random.rand(100000) + np.random.rand(100000) * 1j

score calculation takes too long: avoid for loops - python

I am new to python and I need your kindly help.
I have three matrices, in particular:
Matrix M (class of the matrix: scipy.sparse.csc.csc_matrix), dimensions: N x C;
Matrix G (class of the matrix: numpy.ndarray), dimensions: C x T;
Matrix L (class of the matrix: numpy.ndarray), dimensions: T x N.
Where: N = 10000, C = 1000, T = 20.
I would like to calculate, this score:
I tried by using two for loops , one for the i-index and one for c. Furthermore, I used a dot product for obtaining the last sum in the equation. But my implementation requires too much times for giving the result.
This is what I implemented:
score = 0.0
for i in range(N):
for c in range(C):
Mic = M[i,c]
score += np.outer(Mic,(np.dot(L[:,i],G[c,:])))
Is there a way to avoid the two for loops?
Thank you in advance!
Best
Try this score = np.einsum("ic,ti,ct->", M, L, G)
EDIT1
By the way, in your case, score = np.sum(np.diag(M # G # L)) (in PYTHON3 starting from version 3.5, you can use the semantics of the # operator for matmul function) is faster than einsum (especially in np.trace((L # M) # G ) due to efficient use of memory, maybe #hpaulj meant this in his comment). But einsum is easier to use for complex tensor products (to encode with einsum I used your math expression directly without thinking about optimization).
Generally, using for with numpy results in a dramatic slowdown in computation speed (think "vectorize your computations" in the case of numpy).

Minimizing a multivariable function of loop iterations

I'm trying to minimize a function f of ~80 variables stored in an array. The function is defined by two nested loops: the outer one indexes array by i, while the inner loop is performed array[i] times and adds the result of a computation to a running total. The computation depends on some conditions x and y and changes slightly every time it's performed, which is why I need the loop structure. Here is a minimal working example in Python:
def f[array]:
total = 0
x = 0
y = 0
for i in range(len(array)):
for j in range(array[i]):
result = 2*x + y
total = total + result
x = x+1
x = 0
y = y+1
return total
So for instance, print f([2,1]) returns 3, since [(2*0) + 0] + [(2*1) + 0] + [(2*0) + 1] = 0+2+1 = 3.
I want to find the entries of array that minimize the value of f. However, when I tell (e.g.) Mathematica to minimize f([x1, x2, ..., x80]) and spit out the minimizer array, the program complains because it can't perform the loops defining f an indeterminate number of times.
In light of this, my question is the following:
How do I minimize a multivariate function whose parameters describe the number of times a given loop is to be iterated?
I had originally tried to implement this in Mathematica, but found that I could not define f by the procedure above. The best I could do is tell Mathematica to perform the loops above, then define f[array_] := total after total had been computed. When I ran my code, Mathematica naturally claimed that it could not evaluate f, throwing an error even before it executed my command to NMinimize[{f[array] array ϵ Integers}, array]. The fact that Mathematica is trying to evaluate f before it is called in NMinimize indicates that I don't quite understand how functions work in Mathematica. Any help in untangling this situation would be greatly appreciated!
As written your function has an analytical minimum and there is no need for numerical optimization. Unfortunately, StackOverflow won't let me show the mathematics of it (if you ask it on MathExchange I can provide a derivation), but given an array A = [a0 a1 ... an] where each ai is a positive integer, and an array Y = [0 1 ... n] the function you posted reduces to the following matrix multiplication A * (A - 1 + Y)' where ' denotes a matrix transpose and * denotes matrix multiplication. So, trivially, the function is minimized when each ai is minimized. So, if this is part of a larger optimization, your task should be focused on finding the minimum of each element of A if the elements themselves are constrained.

Inverting Matricies Python without third-party libraries

I need to invert a matrix containing floats using python, but without using third party libraries (i.e numpy). What is the least computationally intensive way of inverting matrices in such a manner?
I have attempted to use the fact that the transpose of the cofactor matrix times the reciprocal determinant equals the inverse matrix. However I am farely certain that the recursive method is taking too long:
def getMatrixMinor(m,i,j):
return [row[:j] + row[j+1:] for row in (m[:i]+m[i+1:])]
def getMatrixDeternminant(m):
if len(m) == 2:
return m[0][0]*m[1][1]-m[0][1]*m[1][0]
determinant = 0
for c in range(len(m)):
determinant += ((-1)**c)*m[0][c]*getMatrixDeternminant(getMatrixMinor(m,0,c))
return determinant
def getMatrixInverse(m):
determinant = getMatrixDeternminant(m)
if len(m) == 2:
return [[m[1][1]/determinant, -1*m[0][1]/determinant],
[-1*m[1][0]/determinant, m[0][0]/determinant]]
cofactors = []
for r in range(len(m)):
cofactorRow = []
for c in range(len(m)):
minor = getMatrixMinor(m,r,c)
cofactorRow.append(((-1)**(r+c)) * getMatrixDeternminant(minor))
cofactors.append(cofactorRow)
cofactors = transposeMatrix(cofactors)
for r in range(len(cofactors)):
for c in range(len(cofactors)):
cofactors[r][c] = cofactors[r][c]/determinant
return cofactors
Apologies if the formatting is weird.
Inverting by the adjoint matrix has essentially only theoretical value.
Computationally efficient methods never involve computing determinants and so. Take a look at Gaussian elimination, which requires high-school math to understand and is more-or-less the standard starting point for such "endeavors".

vectorizing a function of an array of arrays

I am new to vectorizing code, and I am really psyched about how much faster everything is, but I can't get the high speed out of this particular piece of code...
Here is the housing class...
class GaussianMixtureModel:
def __init__(self, image_matrix, num_components, means=None):
self.image_matrix = image_matrix
self.num_components = num_components
if(means is None):
self.means = np.zeros(num_components)
else:
self.means = np.array(means)
self.variances = np.zeros(num_components)
self.mixing_coefficients = np.zeros(num_components)
And here is what I've got so far that works:
def likelihood(self):
def g2(x):
#N =~ 5
#self.mixing_coefficients = 1D, N items
#self.variances = 1D, N items
#self.means = 1D, N items
mc = self.mixing_coefficients[:,None,None]
std = self.variances[:,None,None] ** 0.5
var = self.variances[:,None,None]
mean = self.means[:,None,None]
return np.log((mc*(1.0/(std*np.sqrt(2.0*np.pi)))*(np.exp(-((x-mean)**2.0)/(2.0*var)))).sum())
f = np.vectorize(g2)
#self.image_matrix =~ 400*700 2D matrix
log_likelihood = (f(self.image_matrix)).sum()
return log_likelihood
And here is what I've got that gives a strange result (note that self.image_matrix is an nxn matrix of a grayscale image):
def likelihood(self):
def g2():
#N =~ 5
#self.mixing_coefficients = 1D, N items
#self.variances = 1D, N items
#self.means = 1D, N items
#self.image_matrix = 1D, 400x700 2D matrix
mc = self.mixing_coefficients[:,None,None]
std = self.variances[:,None,None] ** 0.5
var = self.variances[:,None,None]
mean = self.means[:,None,None]
return np.log((mc*(1.0/(std*np.sqrt(2.0*np.pi)))*(np.exp(-((self.image_matrix-mean)**2.0)/(2.0*var)))).sum())
log_likelihood = (g2()).sum()
return log_likelihood
However, the second version is really fast compared to the first (which takes almost 10 seconds...and speed is really important here, because this is part of a convergence algorithm)
Is there a way to replicate the results of the first version and the speed of the second? (And I'm really not familiar enough with vectorizing to know why the second version isn't working)
The second version is so fast because it only uses the first cell of self.image_matrix:
return np.log((mc*(1.0/(std*np.sqrt(2.0*np.pi)))*(np.exp(-((self.image_matrix[0,0]-mean)**2.0)/(2.0*var)))).sum())
# ^^^^^
This is also why it's completely wrong. It's not actually a vectorized computation over self.image_matrix at all. Don't try to use its runtime as a point of comparison; you can always make wrong code faster than right code.
By eliminating the use of np.vectorize, you can make the first version much faster, but not as fast as the wrong code. The sum inside the log simply needs the appropriate axis specified:
def likelihood(self):
def f(x):
mc = self.mixing_coefficients[:,None,None]
std = self.variances[:,None,None] ** 0.5
var = self.variances[:,None,None]
mean = self.means[:,None,None]
return np.log((mc*(1.0/(std*np.sqrt(2.0*np.pi)))*(np.exp(-((x-mean)**2.0)/(2.0*var)))).sum(axis=0))
log_likelihood = (f(self.image_matrix)).sum()
This can be further simplified and optimized in a few ways. For example, the nested function can be eliminated, and multiplying by 1.0/whatever is slower than dividing by whatever, but eliminating np.vectorize is the big thing.

Categories

Resources