what is the solution to a tridiagonal matrix in python? - python

I'm working on a problem right now on tridiagonal matrix, i used the tridiagonal matrix algorithim in wiki https://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm to implement a solution and i have attempted it but my solution is not complete.
I'm confused and i need help also here is my script using jupyter notebook
import numpy as np
# The diagonals and the solution vector
b = np.array((5, 6, 6, 6, 6, 6, 6, 6, 5), dtype=float) # Main Diagonal
a= np.array((1, 1, 1, 1, 1, 1, 1, 1), dtype = float) # Lower Diagonal
c = np.array((1, 1, 1, 1, 1, 1, 1, 1), dtype = float) # Upper Diagonal
d = np.array((3, 2, 1, 3, 1, 3, 1, 2, 3), dtype = float) # Solution Vector
#number of rows
n = d.size
newC = np.zeros(n, dtype= float)
newD = np.zeros(n, dtype = float)
x = np.zeros(n, dtype = float)
# the first coefficents
newC[0] = c[0] / b[0]
newD[0] = d[0] / b[0]
for i in range(1, n - 1):
newC[i] = c[i] / (b[i] - a[i] * newC[i - 1])
for i in range(1, n -1):
newD[i] = (d[i] - a[i] * newD[i - 1]) / (b[i] - a[i] * newC[i - 1])
x[n - 1] = newD[n - 1]
for i in reversed(range(0, n - 1)):
x[i] = newD[i] - newC[i] * x[i + 1]
x

The vectors a and c should be the same length as b and d, so just prepend/append zero the them respectively. Additionally, the range should be range(1,n) otherwise your last solution element is 0 when it shouldn't be. You can see this modified code, as well as a comparison to a known algorithm, showing that it gets the same answer.
import numpy as np
# The diagonals and the solution vector
b = np.array((5, 6, 6, 6, 6, 6, 6, 6, 5), dtype=float) # Main Diagonal
a= np.array((0, 1, 1, 1, 1, 1, 1, 1, 1), dtype = float) # Lower Diagonal
c = np.array((1, 1, 1, 1, 1, 1, 1, 1, 0), dtype = float) # Upper Diagonal
d = np.array((3, 2, 1, 3, 1, 3, 1, 2, 3), dtype = float) # Solution Vector
print(b.size)
print(a.size)
#number of rows
n = d.size
newC = np.zeros(n, dtype= float)
newD = np.zeros(n, dtype = float)
x = np.zeros(n, dtype = float)
# the first coefficents
newC[0] = c[0] / b[0]
newD[0] = d[0] / b[0]
for i in range(1, n):
newC[i] = c[i] / (b[i] - a[i] * newC[i - 1])
for i in range(1, n):
newD[i] = (d[i] - a[i] * newD[i - 1]) / (b[i] - a[i] * newC[i - 1])
x[n - 1] = newD[n - 1]
for i in reversed(range(0, n - 1)):
x[i] = newD[i] - newC[i] * x[i + 1]
# Test with know algorithme
mat = np.zeros((n, n))
for i in range(n):
mat[i,i] = b[i]
if i < n-1:
mat[i, i+1] = a[i+1]
mat[i+1, i] = c[i]
print(mat)
sol = np.linalg.solve(mat, d)
print(x)
print(sol)

That's because of how a, b, c and d are defined in the wikipedia article. If you look carefully, you'll see that the first element of a is a2, also the loop for newD goes to n. So, to have understandable indices to the arrays, i suggest you add a phantom element a1. And you get:
import numpy as np
# The diagonals and the solution vector
b = np.array((5, 6, 6, 6, 6, 6, 6, 6, 5), dtype=float) # Main Diagonal
a = np.array((np.nan, 1, 1, 1, 1, 1, 1, 1, 1), dtype = float) # Lower Diagonal
# with added a1 element
c = np.array((1, 1, 1, 1, 1, 1, 1, 1), dtype = float) # Upper Diagonal
d = np.array((3, 2, 1, 3, 1, 3, 1, 2, 3), dtype = float) # Solution Vector
#number of rows
n = d.size
newC = np.zeros(n, dtype= float)
newD = np.zeros(n, dtype = float)
x = np.zeros(n, dtype = float)
# the first coefficents
newC[0] = c[0] / b[0]
newD[0] = d[0] / b[0]
for i in range(1, n - 1):
newC[i] = c[i] / (b[i] - a[i] * newC[i - 1])
for i in range(1, n): # Add the last iteration `n`
newD[i] = (d[i] - a[i] * newD[i - 1]) / (b[i] - a[i] * newC[i - 1])
x[n - 1] = newD[n - 1]
for i in reversed(range(0, n - 1)):
x[i] = newD[i] - newC[i] * x[i + 1]
x

Related

Finding the coordinates of max sum path in matrix

I have this method which returns the max sum of the path from top left to bottom right (can move only to the right or bottom).
def max_path(grid):
N = len(grid)
M = len(grid[0])
sum = [[0 for i in range(M + 1)] for i in range(N + 1)]
for i in range(1, N + 1):
for j in range(1, M + 1):
sum[i][j] = (max(sum[i - 1][j], sum[i][j - 1]) + grid[i - 1][j - 1])
return sum[N][M]
matrix = [[1, 2, 3], [3, 4, 5]]
print(max_path(matrix))
output : 1 + 3 + 4 + 5 = 13
But what I want to get is also the coordinates of the points of the path:
[(0,0) (1,0) (1,1) (1,2)]
You can try the below code to get your job done.
from itertools import permutations, product
def get_max_sum(table):
height, width = len(table), len(table[0])
sum_, *pos = max((sum(table[x][y] for x, y in zip(*pairs)), *zip(*pairs))
for pairs in product(
permutations(range(height)),
([*range(i, width), *range(i)] for i in range(width))))
return (sum_, *sorted(pos))
sum_, *pos = get_max_sum(
[[1, 2, 3],
[2, 3, 5],
[4, 9, 16]]
)
Output:
20 #maximum sum
(0, 1) (1, 0) (2, 2) #co -ordinates
The variable sum after the nested-for loops (as written in your code) is
[0, 0, 0, 0],
[0, 1, 3, 6],
[0, 4, 8, 13]
You can work out the coordinates of the max sum by having a initial "pointer" at the bottom right corner (i=1, j =2, ignoring the zeros), and comparing the values that is on the top (i=0, i=2) and on the left (i=1, j=1). Since 8 is larger than 6, we move the "pointer" to the left, and now i=1, j=1.
4 is larger than 3, so we move the pointer to 4 (i=1, j=0)
1 is larger than 0, so we move the pointer to 1 (i=0, j=0)
A basic (untested) implementation of the algorithm is as follows:
def max_path(grid):
N = len(grid)
M = len(grid[0])
sum = [[0 for i in range(M + 1)] for i in range(N + 1)]
for i in range(1, N + 1):
for j in range(1, M + 1):
sum[i][j] = (max(sum[i - 1][j], sum[i][j - 1]) + grid[i - 1][j - 1])
j = M
i = N
path = []
while i > 0 and j > 0:
path.append((i-1,j-1))
if sum[i-1][j] <= sum[i][j-1]:
j -= 1
else:
i -= 1
path.reverse()
return sum[N][M],path
matrix = [[1, 2, 3], [3, 4, 5]]
print(max_path(matrix))

Unable to access float object in a 2D array in Python

I need to return the vector solution x of Ux = b for an upper triangular matrix U and vector b using back substitution, but I'm unable to actually access an element of the matrix U.
def BackSub(U, b):
n = len(U)
x = [0 for i in range(n)]
for i in range(n - 1, -1, -1):
s = 0
for j in range(n - 1, i, -1):
s += (U[i][j])*b[j]
b[i] = (b[i] - s)/(U[i][i])
return b
b = [5, 6, 3, 2]
U = [[ 1, 2, 1, 0],
[ 0, 3, -5, 9],
[ 0, 0, 0.5, 1],
[ 0, 0, 0, 7]]
N = GaussElim(U, b)
x = BackSub(N, b)
It returns
TypeError: 'float' object is not subscriptable for U[i][i]
The GaussElim function is this
import numpy as np
def GaussElim(A, b):
n = len(b) #n is matrix size
#Elimination phase
for k in range(0 , n - 1): #k is matrix row
for i in range(k + 1, n): #i is matrix col
if A[i][k] != 0:
factor = A[i][k]/ A[k][k]
A[i][k + 1 : n] = A[i][k + 1 : n] - np.multiply(factor, A[k][k + 1 : n])
b[i] = b[i] - np.multiply(factor, b[k])
#Back substitution
for k in range(n - 1, -1, -1):
b[k] = (b[k] - dot(A[k][k + 1 : n], b[k + 1 : n]))/A[k][k]
return b

sum of elements in martix of matrices using numpy

I have a matrix of matrices with some arbitrary shape (N1,N2,k,k), meaning N1*N2 matrices with shape k*k.
I wish to calculate the sum of each matrix (of shape (k,k)) and convert the matrix itself with that sum.
the resulting array would be of shape (N1,N2), where each element positioned in some index i,j is the sum of the corresponding matrix in that given index.
is there a way of doing so with numpy operations? (that is - no looping over range(N1) and range(N2))
here's a simple example (Im using * with the first array and the second array transpose just to create the example):
m = np.array([[0, 0, 0, 0]]).reshape(2, 2) # matrix element of size k*k (k=2)
a = np.array([m, m + 1, m + 2, m + 3])
b = np.array([m, m + 1, m + 2, m + 3])
reshaped1 = a[:, np.newaxis] # (N1,1,k,k) where N1=4
reshaped2 = b[np.newaxis, :] # (1,N2,k,k) where N2=4
mult = reshaped1 * reshaped2 # (N1,N2,k,k)=(4,4,2,2)
I wish to create a new array res that will contain the sum of all mult elements. that can somewhat be done with the following pseudo:
for i in range(N1):
for j in range(N2):
res[i,j] = sum(mult[i,j])
appreciate your help!
If I understand you correctly, you can use np.sum with multiple axes:
np.sum(mult, axis=(2, 3))
Output:
array([[ 0, 0, 0, 0],
[ 0, 4, 8, 12],
[ 0, 8, 16, 24],
[ 0, 12, 24, 36]])
try using np.sum(np.sum(mult,axis=3),axis=2)
import numpy as np
N1=4
N2=4
m = np.array([[0, 0, 0, 0]]).reshape(2, 2) # matrix element of size k*k (k=2)
a = np.array([m, m + 1, m + 2, m + 3])
b = np.array([m, m + 1, m + 2, m + 3])
reshaped1 = a[:, np.newaxis] # (N1,1,k,k) where N1=4
reshaped2 = b[np.newaxis, :] # (1,N2,k,k) where N2=4
mult = reshaped1 * reshaped2 # (N1,N2,k,k)=(4,4,2,2)
np.sum(mult,axis=3)
res=np.zeros((4,4))
for i in range(N1):
for j in range(N2):
res[i,j] = np.sum(mult[i,j])
print(np.array_equal(np.sum(np.sum(mult,axis=3),axis=2),res))
>>> True

Erosion operation (python)

I am trying to implement the erosion function for a binary image without using standard libraries (cv2,..). That's what I got at the moment. Is it possible to simplify my code so that there are only vector or matrix operations? Any other suggestions are also welcome.
mask = np.array([
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1]
])
def erosion(image, mask):
mask_size = mask.shape[0]
left_half = int(mask_size / 2)
right_half = int(mask_size / 2)
if mask_size % 2 == 0:
right_half += 1
result = image.copy()
# Идем по изображению
for i in range(left_half, result.shape[0] - right_half):
for j in range(left_half, result.shape[1] - right_half):
left_border = int(mask_size / 2)
mask_i = 0
mask_j = 0
flag = False
right_border = left_border
if mask_size % 2 != 0:
right_border += 1
# Идем по маске, перебираем каждый элемент маски
for k in range(i - left_border, i + right_border):
mask_j = 0
for l in range(j - left_border, j + right_border):
if mask[mask_i, mask_j] == 1 and image[k, l] == 0:
result[i, j] = 0
flag = True
break
mask_j += 1
mask_i += 1
if(flag):
break
if not (flag):
result[i, j] = 255
return result

"index 1 is out of bounds for axis 0 with size 1" in python

I seem to be having an indexing problem? I do not know how to interpret this error... :/ I think it has to do with how I initialized u.
I have this 3x3 G matrix that I created using the variable u (a vector, x - y). I just made a zero matrix for now bc I'm not quite sure how to code it yet, there are lots of partials and norms involved haha. x_j = (x_1 (j), x_2 (j), x_3 (j)) and y_j = (y_1 (j), y_2 (j), y_3 (j)). x and y are nx3 vectors. alpha_j is a 3x3 matrix. The A matrix is block diagonal matrix of size 3nx3n. I am having trouble with the W matrix (size 3nx3n, where the (i,j)th block is the 3x3 matrix given by alpha_i*G_[ij]*alpha_j).
def G(u):
u1 = u[0]
u2 = u[1]
u3 = u[2]
g = np.array([[0,0,0],[0,0,0],[0,0,0]],complex)
return g
def W(x, y, k, alpha, A):
# initialization
n = x.shape[0] # the number of x vextors
result = np.zeros([3*n,3*n],complex)
u = np.matlib.zeros((n, 3)) # u = x - y
print(u)
num_in_blocks = n
# variables
a_i = alpha_j(alpha, A)
a_j = alpha_j(alpha, A)
for i in range(0, 2):
x1 = x[i] # each row of x
y1 = y[i] # each row of y
for j in range(0, n-1):
u[i][j] = x1[j] - y1[j] # each row of x minus each row of y
if i != j:
block_result = a_i * G((u[i][j]), k) * a_j
for k in range(num_in_blocks):
for l in range(num_in_blocks):
result[3*i + k, 3*j + l] = block_result[i, j]
return result
def alpha_j(a, A):
alph = np.array([[0,0,0],[0,0,0],[0,0,0]],complex)
n = A.shape[0]
rho = np.random.rand(n,1)
for i in range(0, n-1):
for j in range(0, n-1):
alph[i,j] = (rho[i] * a * A[i,j])
return alph
#------------------------------------------------------------------
# random case
def x(n):
return np.random.randint(100, size=(n, 3))
def y(n):
return np.random.randint(100, size=(n, 3))
# SYSTEM PARAMETERS
theta = 0 # can range from [0, 2pi)
chi = 10 + 1j
lam = 0.5 # microns (values between .4-.7)
k = (2 * np.pi)/lam # 1/microns
V_0 = (0.05)**3 # microns^3
K = k * np.array([[0], [np.sin(theta)], [np.cos(theta)]])
alpha = (V_0 * 3 * chi)/(chi + 3)
A = np.matlib.identity(3)
#------------------------------------------------------------------
# TEST FUNCTIONS
w = W(x(3), y(3), k, alpha, A)
print(w)
I keep getting the error "invalid index to scalar variable." at the line u1 = u[0].
np.matlib makes a np.matrix, a subclass of np.ndarray. It's supposed to give a MATLAB feel, and (nearly) always produces a 2d array. Its use in new code is being discouraged.
In [42]: U = np.matrix(np.arange(9).reshape(3,3))
In [43]: U
Out[43]:
matrix([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
Indexing with [0] picks the first row, but returns a 2d matrix.
In [44]: U[0]
Out[44]: matrix([[0, 1, 2]])
In [45]: U[0].shape
Out[45]: (1, 3)
Adding another [1] still indexes the first dimension (which is now size 1):
In [46]: U[0][1]
---------------------------------------------------------------------------
IndexError: index 1 is out of bounds for axis 0 with size 1
Normally we index numpy arrays with a composite index:
In [47]: U[0,1]
Out[47]: 1
If we make an ndarray instead:
In [48]: U = np.arange(9).reshape(3,3)
In [49]: U
Out[49]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In [50]: U[0]
Out[50]: array([0, 1, 2]) # 1d
In [51]: U[0][1] # works,
Out[51]: 1
In [52]: U[0,1] # still preferable
Out[52]: 1

Categories