Python/Maths: Convert a matrix into a lower triangular matrix - python

I defined the matrix a. Then I wrote an algorithm which turns the matrix a into a lower triangular matrix (I provided the programme below)
The algorithm does work because if I do "print(" ")" at the end of the algorithm I do receive a lower triangular matrix
But when I do "print(a)" directly afterwards (so after the algorithm for the lower triangular matrix)
I still receive the previous matrix a... and then it is not a lower triangular matrix. So I would like the matrix a to "permanently" be a lower triangular matrix, and not just whenever I use this algorithm (with the "print(" ")" at the end)
How can I sort of "change" the matrix a in a way that it stays a lower triangular matrix? I hope I expressed myself well.
Here is my python code:
import numpy as np
s = 5
#s is the number of columns and rows respectively#
a = np.array([[None]*s]*s)
print(a)
#I receive a matrix with 5 columns/rows respectively#
#Calculates number of rows and columns present in given matrix#
rows = len(a);
cols = len(a[0]);
if(rows != cols):
print("Matrix should be a square matrix");
else:
#Performs required operation to convert given matrix into lower triangular matrix
print("Lower triangular matrix: ");
for i in range(0, rows):
for j in range(0, cols):
if(j > i):
print("0"),
else:
print(a[i][j]),
print(" ");
#so far it works perfectly fine. If I use this algorithm I do receive a lower triangular matrix#
print(a)
#my wish was that now that I do print(a) again that it would print the matrix a but as a lower triangular matrix. because of the previous algorithm. but I get the same matrix as I did when I did "print(A)" for the first time.#type here

Keep in mind that printing and assigning values to variables are different actions:
print shows a message on the screen but does not change the value of any variable.
Assignment, such as x = 2 or a[i][j] = 0 changes the value that is stored in that place in memory.
If you want to change the matrix, then you need to use the assignment operator to change the values. In practice you just need to add a[i][j] = 0 in the correct place.
if(j > i):
a[i][j] = 0 # <-- add this line
print("0"),
Now the elements in the upper right part will be set to zero.

Related

Computing determinant of nxn matrix without using inbuilt modules

I'm writing some code which generates a random matrix and then proceeds to find its determinant. This is what I have so far, using the recursive formula for the determinant:
import numpy as np
import random
myarray = []
myinput=input('Choose a value for N:')
N=int(myinput)
for i in range(N):
myarray.append([0.0]*N)
for j in range(N):
for i in range(N):
myarray[i][j] = random.randint(0,100)
M=np.array(myarray)
print(M)
def det(matrix):
determinant=0
a=0
while a<N:
M_0a=np.delete(matrix,0,axis=0)
M_0a=np.delete(M_0a,a,axis=1)
print(M_0a)
a+=1
determinant= determinant + ((-1)**a)*(M[0][a])*det(M_0a)
return determinant
print(det(M))
I've written the function kind of incorrectly as I'm unsure how to proceed. Basically the while loop successively eliminates the rows and columns in the 0th row and ath column, but I guess I need some sort of if statement for the condition that the new matrix is 2x2, thus ending the loop and calculating the base determinant of the 2x2 matrix?
Thanks

how to init a array with each element holding the value different from its neighbours

I have a matrix or a multiple array written in python, each element in the array is an integer ranged from 0 to 7, how would I randomly initalize this matrix or multiple array, so that for each element holds a value, which is different from the values of its 4 neighbours(left,right, top, bottom)? can it be implemented in numpy?
You can write your own matrix initializer.
Go through the array[i][j] for each i, j pick a random number between 0 and 7.
If the number equals to either left element: array[i][j-1] or to the upper one: array[i-1][j] regenerate it once again.
You have 2/7 probability to encounter such a bad case, and 4/49 to make it twice in a row, 8/343 for 3 in a row, etc.. the probability dropes down very quickly.
The average case complexity for n elements in a matrix would be O(n).
A simpler problem that might get you started is to do the same for a 1d array. A pure-python solution would look like:
def sample_1d(n, upper):
x = [random.randrange(upper)]
for i in range(1, n)"
xi = random.randrange(upper - 1)
if xi >= x:
xi += 1
x.append(xi)
return x
You can vectorize this as:
def sample_1d_v(n, upper):
x = np.empty(n)
x[0] = 0
x[1:] = np.cumsum(np.random.randint(1, upper, size=n-1)) % upper
x += np.random.randint(upper)
return
The trick here is noting that if there is adjacent values must be different, then the difference between their values is uniformly distributed in [1, upper)

python function globalizing input variables?

I have a python function that solves matrix equations using Gaussian elimination with partial pivoting. I've been using it as part of a matrix solving module. When I use the Gaussian elimination function by passing it the matrix, called 'A' (a 2D numpy array), and vector of constants called 'b' (1D numpy array), the function seems to operate globally on the variables passed to it instead of using local variables. I am using the same name for the variables being passed to the function and the variables inside the function, but shouldn't the function be using copies of the variables passed to it?
I think the issue might be with the "tuple exchanges." I know they do funky things with variable referencing but I'm not knowledgable enough to say exactly what is wrong here.
The function:
def Gaussian_eliminiation(A,b):
#Gaussian elimination with scaled partial pivoting
n = len(b)
#make sure the arrays are storing float variables and not integers
if not A.dtype == float or b.dtype == float:
print "Variables may be integers and not floats"
#find scaling factors
s = np.zeros((n,))
for i in range(n):
s[i] = max(abs(A[i,:]))
#eliminate, moving through each pivot row with i
for i in range(n-1):
#put the correct pivot row in place
(_, idx) = max_idx(abs(A[i:n,i])/s[i:n])
idx += i
if(idx != i):
#swap values with tuple exchanges
for j in range(i,n):
(A[i,j],A[idx,j]) = (A[idx,j],A[i,j])
(b[i],b[idx]) = (b[idx],b[i])
(s[i],s[idx]) = (s[idx],s[i])
#use the pivot in row i to work on row j
for j in range(i+1,n):
m = A[j,i]/float(A[i,i])
#operate on the elements of row j and the b vector
A[j,i:] -= m*A[i,i:]
b[j] -= m*b[i]
if(A[n-1,n-1] == 0):
print "\nThere is no unique solution to the matrix.",
print "The final row is empty:\n",A,'<--\n'
return (A,b)

How to compare diagonally opposed element of a multidimensional array with numpy

I have a non-symmetrical matrix and basically I would like to compare diagonally opposed element as follow:
if the diagonally opposed element are equal but opposed in sign, keep the absolute value of an element and zero the diagonally opposed value
if it is not the case, then one of the two element is 0 (but we don't know which one), so take the absolute value of both.
Once this is done transpose the lower triangle of the matrix and add it to the upper triangle.
I came up with the following python loop:
for i in range(0, number_files):
for j in range(0, len(Identifier)):
for k in range(0,len(Identifier)):
if Matrix[i][j][k] == - Matrix[i][k][j]:
Matrix[i][j][k] = abs(Matrix[i][j][k])
Matrix[i][k][j] = 0
else:
Matrix[i][j][k] = abs(Matrix[i][j][k]) # one of this two
Matrix[i][k][j] = abs(Matrix[i][k][j]) # values is 0
Matrix[i] = np.tril(Matrix[i],0).transpose() + np.triu(Matrix[i],0)
However, this is very slow and I was wondering how I could improve it with numpy.
I know I can generate a test for example with:
test=np.isclose(Matrix.transpose(),-Matrix)
which will return a boolean matrix, but I do not know how to proceed with that.
Many thanks in advance for your help
Lets start by creating a sample matrix:
>>> a = np.random.randint(-3, 3, 100).reshape(10,10)
Getting its upper and lower triangles:
>>> triu = np.triu(a)
>>> tril = np.tril(a)
Note that triu and tril are the same size as a, but filled with zeros outside the triangle.
Define the triangle you want to modify, and transpose the other. E.g. modify upper triangle:
>>> tril = tril.T
As you suggested, do one of the following to create a mask where your condition applies:
# For integer data
>>> mask = (triu == -tril) & (triu != 0)
# For real data
>>> mask = np.isclose(triu, -tril) & ~np.isclose(triu, 0)
Note the new condition added (!= 0), to avoid comparisons comparisons where triu and tril are filled with 0. mask will contain True where an element from the upper triangle triu matches lower triangle tril.
Implement your conditions:
# Second and abs part of the first condition
>>> a = np.abs(a)
# Set upper diagonal when matches lower diagonal to 0
>>> a[mask] = 0

Remove/set the non-zero diagonal elements of a sparse matrix in scipy

Say I would like to remove the diagonal from a scipy.sparse.csr_matrix. Is there an efficient way of doing so? I saw that in the sparsetools module there are C functions to return the diagonal.
Based on other SO answers here and here my current approach is the following:
def csr_setdiag_val(csr, value=0):
"""Set all diagonal nonzero elements
(elements currently in the sparsity pattern)
to the given value. Useful to set to 0 mostly.
"""
if csr.format != "csr":
raise ValueError('Matrix given must be of CSR format.')
csr.sort_indices()
pointer = csr.indptr
indices = csr.indices
data = csr.data
for i in range(min(csr.shape)):
ind = indices[pointer[i]: pointer[i + 1]]
j = ind.searchsorted(i)
# matrix has only elements up until diagonal (in row i)
if j == len(ind):
continue
j += pointer[i]
# in case matrix has only elements after diagonal (in row i)
if indices[j] == i:
data[j] = value
which I then follow with
csr.eliminate_zeros()
Is that the best I can do without writing my own Cython code?
Based on #hpaulj's comment, I created an IPython Notebook which can be seen on nbviewer. This shows that out of all methods mentioned the following is the fastest (assume that mat is a sparse CSR matrix):
mat - scipy.sparse.dia_matrix((mat.diagonal()[scipy.newaxis, :], [0]), shape=(one_dim, one_dim))

Categories

Resources