vectors two multiply matrices matmul inner complex array python matrix numba inverse

python - two - numpy multiply matrices



Inversión matricial sin numpy (4)

Quiero invertir una matriz sin usar numpy.linalg.inv .

La razón es que estoy usando Numba para acelerar el código, pero no se admite numpy.linalg.inv, así que me pregunto si puedo invertir una matriz con el código de Python "clásico".

Con numpy.linalg.inv, un código de ejemplo se vería así:

import numpy as np M = np.array([[1,0,0],[0,1,0],[0,0,1]]) Minv = np.linalg.inv(M)


Al menos desde el 16 de julio de 2018, Numba tiene una matriz inversa rápida. (Puede ver cómo sobrecargan el inverso NumPy estándar y otras operaciones here ).

Aquí están los resultados de mi evaluación comparativa:

import numpy as np from scipy import linalg as sla from scipy import linalg as nla import numba def gen_ex(d0): x = np.random.randn(d0,d0) return x.T + x @numba.jit def inv_nla_jit(A): return np.linalg.inv(A) @numba.jit def inv_sla_jit(A): return sla.inv(A)

Para matrices pequeñas es particularmente rápido:

ex1 = gen_ex(4) %timeit inv_nla_jit(ex1) # NumPy + Numba %timeit inv_sla_jit(ex1) # SciPy + Numba %timeit nla.inv(ex1) # NumPy %timeit sla.inv(ex1) # SciPy

[Afuera]

2.54 µs ± 467 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 67.3 µs ± 9.18 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) 63.5 µs ± 7.65 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) 56.6 µs ± 5.03 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Tenga en cuenta que la aceleración solo funciona para NumPy inverso, no para SciPy (como se esperaba).

Matriz ligeramente más grande:

ex2 = gen_ex(40) %timeit inv_nla_jit(ex2) # NumPy + Numba %timeit inv_sla_jit(ex2) # SciPy + Numba %timeit nla.inv(ex2) # NumPy %timeit sla.inv(ex2) # SciPy

[Afuera]

131 µs ± 12.9 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) 278 µs ± 26.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 231 µs ± 24.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 189 µs ± 11.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Así que todavía hay una aceleración aquí, pero SciPy se está poniendo al día.


Aquí hay una solución más elegante y escalable, imo. Funcionará para cualquier matriz nxn y puede ser útil para los otros métodos. Tenga en cuenta que getMatrixInverse (m) toma una matriz de matrices como entrada. Por favor, siéntase libre de hacer cualquier pregunta.

def transposeMatrix(m): return map(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


Para una matriz de 4 x 4 es probable que sea casi correcto usar la fórmula matemática, que puede encontrar usando la "fórmula de Google para 4 por 4 de matriz inversa". Por ejemplo aquí (no puedo responder por su exactitud):

http://www.cg.info.hiroshima-cu.ac.jp/~miyazaki/knowledge/teche23.html

En general, invertir una matriz general no es para los débiles de corazón. Debe tener en cuenta todos los casos matemáticamente difíciles y saber por qué no se aplican a su uso, y detectarlos cuando se le suministran insumos patológicamente matemáticos (esto o resultados de baja precisión o basura numérica con el conocimiento de que no importará en su caso de uso siempre y cuando no termine dividiendo por cero o desbordando MAXFLOAT ... que puede capturar con un controlador de excepciones y presentar como "Error: la matriz es singular o muy similar").

En general, como programador es mejor usar el código de la biblioteca escrito por expertos en matemáticas numéricas, a menos que esté dispuesto a pasar tiempo comprendiendo la naturaleza física y matemática del problema particular al que se está dirigiendo y convertirse en su propio experto en matemáticas en su propio campo de especialista.


Usé la fórmula de http://cg.info.hiroshima-cu.ac.jp/~miyazaki/knowledge/teche23.html para escribir la función que realiza la inversión de una matriz de 4x4:

import numpy as np def myInverse(A): detA = np.linalg.det(A) b00 = A[1,1]*A[2,2]*A[3,3] + A[1,2]*A[2,3]*A[3,1] + A[1,3]*A[2,1]*A[3,2] - A[1,1]*A[2,3]*A[3,2] - A[1,2]*A[2,1]*A[3,3] - A[1,3]*A[2,2]*A[3,1] b01 = A[0,1]*A[2,3]*A[3,2] + A[0,2]*A[2,1]*A[3,3] + A[0,3]*A[2,2]*A[3,1] - A[0,1]*A[2,2]*A[3,3] - A[0,2]*A[2,3]*A[3,1] - A[0,3]*A[2,1]*A[3,2] b02 = A[0,1]*A[1,2]*A[3,3] + A[0,2]*A[1,3]*A[3,1] + A[0,3]*A[1,1]*A[3,2] - A[0,1]*A[1,3]*A[3,2] - A[0,2]*A[1,1]*A[3,3] - A[0,3]*A[1,2]*A[3,1] b03 = A[0,1]*A[1,3]*A[2,2] + A[0,2]*A[1,1]*A[2,3] + A[0,3]*A[1,2]*A[2,1] - A[0,1]*A[1,2]*A[2,3] - A[0,2]*A[1,3]*A[2,1] - A[0,3]*A[1,1]*A[2,2] b10 = A[1,0]*A[2,3]*A[3,2] + A[1,2]*A[2,0]*A[3,3] + A[1,3]*A[2,2]*A[3,0] - A[1,0]*A[2,2]*A[3,3] - A[1,2]*A[2,3]*A[3,0] - A[1,3]*A[2,0]*A[3,2] b11 = A[0,0]*A[2,2]*A[3,3] + A[0,2]*A[2,3]*A[3,0] + A[0,3]*A[2,0]*A[3,2] - A[0,0]*A[2,3]*A[3,2] - A[0,2]*A[2,0]*A[3,3] - A[0,3]*A[2,2]*A[3,0] b12 = A[0,0]*A[1,3]*A[3,2] + A[0,2]*A[1,0]*A[3,3] + A[0,3]*A[1,2]*A[3,0] - A[0,0]*A[1,2]*A[3,3] - A[0,2]*A[1,3]*A[3,0] - A[0,3]*A[1,0]*A[3,2] b13 = A[0,0]*A[1,2]*A[2,3] + A[0,2]*A[1,3]*A[2,0] + A[0,3]*A[1,0]*A[2,2] - A[0,0]*A[1,3]*A[2,2] - A[0,2]*A[1,0]*A[2,3] - A[0,3]*A[1,2]*A[2,0] b20 = A[1,0]*A[2,1]*A[3,3] + A[1,1]*A[2,3]*A[3,0] + A[1,3]*A[2,0]*A[3,1] - A[1,0]*A[2,3]*A[3,1] - A[1,1]*A[2,0]*A[3,3] - A[1,3]*A[2,1]*A[3,0] b21 = A[0,0]*A[2,3]*A[3,1] + A[0,1]*A[2,0]*A[3,3] + A[0,3]*A[2,1]*A[3,0] - A[0,0]*A[2,1]*A[3,3] - A[0,1]*A[2,3]*A[3,0] - A[0,3]*A[2,0]*A[3,1] b22 = A[0,0]*A[1,1]*A[3,3] + A[0,1]*A[1,3]*A[3,0] + A[0,3]*A[1,0]*A[3,1] - A[0,0]*A[1,3]*A[3,1] - A[0,1]*A[1,0]*A[3,3] - A[0,3]*A[1,1]*A[3,0] b23 = A[0,0]*A[1,3]*A[2,1] + A[0,1]*A[1,0]*A[2,3] + A[0,3]*A[1,1]*A[2,0] - A[0,0]*A[1,1]*A[2,3] - A[0,1]*A[1,3]*A[2,0] - A[0,3]*A[1,0]*A[2,1] b30 = A[1,0]*A[2,2]*A[3,1] + A[1,1]*A[2,0]*A[3,2] + A[1,2]*A[2,1]*A[3,0] - A[1,0]*A[2,1]*A[3,2] - A[1,1]*A[2,2]*A[3,0] - A[1,2]*A[2,0]*A[3,1] b31 = A[0,0]*A[2,1]*A[3,2] + A[0,1]*A[2,2]*A[3,0] + A[0,2]*A[2,0]*A[3,1] - A[0,0]*A[2,2]*A[3,1] - A[0,1]*A[2,0]*A[3,2] - A[0,2]*A[2,1]*A[3,0] b32 = A[0,0]*A[1,2]*A[3,1] + A[0,1]*A[1,0]*A[3,2] + A[0,2]*A[1,1]*A[3,0] - A[0,0]*A[1,1]*A[3,2] - A[0,1]*A[1,2]*A[3,0] - A[0,2]*A[1,0]*A[3,1] b33 = A[0,0]*A[1,1]*A[2,2] + A[0,1]*A[1,2]*A[2,0] + A[0,2]*A[1,0]*A[2,1] - A[0,0]*A[1,2]*A[2,1] - A[0,1]*A[1,0]*A[2,2] - A[0,2]*A[1,1]*A[2,0] Ainv = np.array([[b00, b01, b02, b03], [b10, b11, b12, b13], [b20, b21, b22, b23], [b30, b31, b32, b33]]) / detA return Ainv