mathtoolspy/matrix/misc.py
# -*- coding: utf-8 -*-
# mathtoolspy
# -----------
# A fast, efficient Python library for mathematically operations, like
# integration, solver, distributions and other useful functions.
#
# Author: sonntagsgesicht, based on a fork of Deutsche Postbank [pbrisk]
# Version: 0.3, copyright Wednesday, 18 September 2019
# Website: https://github.com/sonntagsgesicht/mathtoolspy
# License: Apache License 2.0 (see LICENSE file)
def transposeMatrix(m):
return list(map(list,list(zip(*m))))
def getMatrixMinor(m,i,j):
return [row[:j] + row[j+1:] for row in (m[:i]+m[i+1:])]
def getMatrixDeternminant(m):
#base case for 2x2 matrix
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)
#special case for 2x2 matrix:
if len(m) == 2:
return [[m[1][1]/determinant, -1*m[0][1]/determinant],
[-1*m[1][0]/determinant, m[0][0]/determinant]]
#find matrix of cofactors
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
# --- cholesky --- https://rosettacode.org/wiki/Cholesky_decomposition#Python
from pprint import pprint
from math import sqrt
def cholesky(A):
L = [[0.0] * len(A) for _ in range(len(A))]
for i in range(len(A)):
for j in range(i + 1):
s = sum(L[i][k] * L[j][k] for k in range(j))
L[i][j] = sqrt(A[i][i] - s) if (i == j) else \
(1.0 / L[j][j] * (A[i][j] - s))
return L
if __name__ == "__main__":
m1 = [[25, 15, -5],
[15, 18, 0],
[-5, 0, 11]]
pprint(cholesky(m1))
print()
m2 = [[18, 22, 54, 42],
[22, 70, 86, 62],
[54, 86, 174, 134],
[42, 62, 134, 106]]
pprint(cholesky(m2), width=120)
# --- mult --- https://integratedmlai.com/matrixinverse/
def print_matrix(Title, M):
print(Title)
for row in M:
print([round(x, 3) + 0 for x in row])
def print_matrices(Action, Title1, M1, Title2, M2):
print(Action)
print((Title1, '\t' * int(len(M1) / 2) + "\t" * len(M1), Title2))
for i in range(len(M1)):
row1 = ['{0:+7.3f}'.format(x) for x in M1[i]]
row2 = ['{0:+7.3f}'.format(x) for x in M2[i]]
print((row1, '\t', row2))
def zeros_matrix(rows, cols):
A = []
for i in range(rows):
A.append([])
for j in range(cols):
A[-1].append(0.0)
return A
def copy_matrix(M):
rows = len(M)
cols = len(M[0])
MC = zeros_matrix(rows, cols)
for i in range(rows):
for j in range(rows):
MC[i][j] = M[i][j]
return MC
def matrix_multiply(A, B):
rowsA = len(A)
colsA = len(A[0])
rowsB = len(B)
colsB = len(B[0])
if colsA != rowsB:
print('Number of A columns must equal number of B rows.')
sys.exit()
C = zeros_matrix(rowsA, colsB)
for i in range(rowsA):
for j in range(colsB):
total = 0
for ii in range(colsA):
total += A[i][ii] * B[ii][j]
C[i][j] = total
return C
def invert_matrix(A, tol=None):
"""
Returns the inverse of the passed in matrix.
:param A: The matrix to be inversed
:return: The inverse of the matrix A
"""
# Section 1: Make sure A can be inverted.
check_squareness(A)
check_non_singular(A)
# Section 2: Make copies of A & I, to use for row operations
n = len(A)
AM = copy_matrix(A)
I = identity_matrix(n)
IM = copy_matrix(I)
# Section 3: Perform row operations
indices = list(range(n)) # to allow flexible row referencing
for fd in range(n): # fd stands for focus diagonal
fdScaler = 1.0 / AM[fd][fd]
# FIRST: scale fd row with fd inverse.
for j in range(n): # Use j to indicate column looping.
AM[fd][j] *= fdScaler
IM[fd][j] *= fdScaler
# SECOND: operate on all rows except fd row as follows:
for i in indices[0:fd] + indices[fd+1:]: # skip fd row
crScaler = AM[i][fd] # cr stands for "current row".
for j in range(n): # cr - crScaler * fdRow
AM[i][j] = AM[i][j] - crScaler * AM[fd][j]
IM[i][j] = IM[i][j] - crScaler * IM[fd][j]
# Section 4: Ensure IM is A inverse within tolerance
if check_matrix_equality(I,matrix_multiply(A,IM),tol):
return IM
else:
raise ArithmeticError("Matrix inverse out of tolerance.")