2014-02-17 6 views
5

У меня есть большая матрица A формы (n, n, 3, 3) с n около 5000. Теперь я хочу найти обратную и транспонирование матрицы A:Быстрая обратная и транспонированная матрица в Python

import numpy as np 
A = np.random.rand(1000, 1000, 3, 3) 
identity = np.identity(3, dtype=A.dtype) 
Ainv = np.zeros_like(A) 
Atrans = np.zeros_like(A) 
for i in range(1000): 
    for j in range(1000): 
     Ainv[i, j] = np.linalg.solve(A[i, j], identity) 
     Atrans[i, j] = np.transpose(A[i, j]) 

Есть ли более быстрый, более эффективный способ сделать это?

+0

Ваш A не является матрицей, а тензором. Для тензора неясно, как определить обратную или транспонированную. Если вы хотите инвертировать/перенести 2-мерный массив матриц, вы можете посмотреть на тензинину numpy. – Martin

ответ

2

Numpy имеет array.T свойства, которые являются ярлыком для transpose.

Для инверсий вы используете np.linalg.inv(A).

+1

Нет 'array.I'. Это метод объекта 'matrix'. Для массива вы используете 'np.linalg.inv (A)'. – wim

+0

@wim, Правильно! Я отредактирую! – blz

7

Это взято из моего проекта, где я также векторизовал линейную алгебру на многих матрицах 3x3.

Обратите внимание, что существует только петля над 3; а не цикл над n, поэтому код векторизован в важных измерениях. Я не хочу ручаться за то, как это сравнивается с расширением C/numba, чтобы сделать то же самое, хотя и с точки зрения производительности. Это, вероятно, будет значительно быстрее, но, по крайней мере, это ударяет петли над n из воды.

def adjoint(A): 
    """compute inverse without division by det; ...xv3xc3 input, or array of matrices assumed""" 
    AI = np.empty_like(A) 
    for i in xrange(3): 
     AI[...,i,:] = np.cross(A[...,i-2,:], A[...,i-1,:]) 
    return AI 

def inverse_transpose(A): 
    """ 
    efficiently compute the inverse-transpose for stack of 3x3 matrices 
    """ 
    I = adjoint(A) 
    det = dot(I, A).mean(axis=-1) 
    return I/det[...,None,None] 

def inverse(A): 
    """inverse of a stack of 3x3 matrices""" 
    return np.swapaxes(inverse_transpose(A), -1,-2) 
def dot(A, B): 
    """dot arrays of vecs; contract over last indices""" 
    return np.einsum('...i,...i->...', A, B) 


A = np.random.rand(2,2,3,3) 
I = inverse(A) 
print np.einsum('...ij,...jk',A,I) 
+0

Он отлично работает! У вас есть аналогичное решение в случае матрицы 6x6? – user2863620

+0

Вычисление обратного с помощью сопряженного является эффективным только для малых матриц. Инвертирование матриц 6x6 (при условии, что никакая структура не может быть использована) намного дороже, и я могу представить, что цикл по n больше не является таким узким местом в этом сценарии. –

+0

Математический вопрос: является ли перекрестное произведение, необходимое для вычисления сопряжений? –

3

для транспонирования:

тестирование немного в IPython показал:

In [1]: import numpy 
In [2]: x = numpy.ones((5,6,3,4)) 
In [3]: numpy.transpose(x,(0,1,3,2)).shape 
Out[3]: (5, 6, 4, 3) 

так что вы можете просто сделать

Atrans = numpy.transpose(A,(0,1,3,2)) 

транспонировать второго и третьего измерения (оставляя размеры 0 и 1 одинаковыми)

для инверсии:

последний пример http://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.inv.html#numpy.linalg.inv

обратных нескольких матриц могут быть вычислены сразу:

from numpy.linalg import inv 
a = np.array([[[1., 2.], [3., 4.]], [[1, 3], [3, 5]]]) 
>>> inv(a) 
array([[[-2. , 1. ], 
     [ 1.5, -0.5]], 
     [[-5. , 2. ], 
     [ 3. , -1. ]]]) 

Так я думаю, в вашем случае, инверсия может будет осуществляться только с

Ainv = inv(A) 

, и он будет знать, что последние два измерения - это те, которые он должен перевернуть, и что первые измерения - это то, как вы складывали свои данные. Это должно быть намного быстрее

разница в скорости

для транспонирования: ваш метод требует 3.77557015419 сек, и мои потребности 2.86102294922e-06 сек (что является убыстрение более 1 миллиона раз)

для инверсии: я думаю, моя версия numpy недостаточно высока, чтобы попробовать трюк numpy.linalg.inv с формой (n, n, 3,3), чтобы увидеть ускорение там (моя версия 1.6.2, а документы я основывал свое решение на 1,8, но он должен работать на 1,8, если кто-то может это проверить?)

+0

Действительно, это должно работать с последним numpy; но я не знаю, как быстро это будет. Это будет простой вызов inv для каждой матрицы 3x3 в массиве; но накладные расходы на вызов inv без использования их матриц 3x3 могут быть существенными; Я подозреваю, что это будет медленнее, чем решение, которое я опубликовал; но было бы неплохо попробовать. –

+0

@EelcoHoogendoorn не уверен, но может быть быстрее, если вы просто скопируете метод инверсии 3X3, как вы, но нажмете его на C и просто scipy.weave.blitz на нем? - Кто-нибудь с numpy 1.8 способен ускорить сравнение моего метода с вашим? – usethedeathstar

-1

для объекта numpy-matrix, используйте matrix.getI. , например.

A=numpy.matrix('1 3;5 6') 
print (A.getI()) 
+0

Можете ли вы объяснить свой ответ? – soundslikeodd

0

Как отправил wim A.I также работает над матрицей. например

print (A.I)

+0

Похоже, что этот ответ похож на ваш другой ответ здесь. Вы можете отредактировать свой предыдущий ответ, если хотите его улучшить. Или добавьте новый ответ, ЕСЛИ ТОЛЬКО у вас есть другая точка. В любом случае, добро пожаловать в StackOverflow :) – koceeng

Смежные вопросы