2014-02-11 1 views
8

Для Matlab требуется 0,02 секунды для вычисления инверсии диагональной матрицы с использованием разреженной команды.Можно ли вычислить инверсию разреженной матрицы в Python так же быстро, как в Matlab?

P = diag(1:10000); 
P = sparse(P); 
tic; 
A = inv(P); 
toc 

Однако для кода Python требуется навсегда - несколько минут.

import numpy as np 
import time 

startTime = time.time() 
P = np.diag(range(1,10000)) 
A = np.linalg.inv(P) 
runningTime = (time.time()-startTime)/60 
print "The script was running for %f minutes" % runningTime 

Я попытался использовать модуль Scipy.sparse, но это не помогло. Время работы снизилось, но только до 40 секунд.

import numpy as np 
import time 
import scipy.sparse as sps 
import scipy.sparse.linalg as spsl 

startTime = time.time() 
P = np.diag(range(1,10000)) 
P_sps = sps.coo_matrix(P) 
A = spsl.inv(P_sps) 
runningTime = (time.time()-startTime)/60 
print "The script was running for %f minutes" % runningTime 

Возможно ли запустить код так быстро, как он работает в Matlab?

+1

хранения матрицы, как P_sps = sps.dia_matrix (P) делает немного улучшения, но Matlab код еще 3 заказы быстрее –

+3

реальный вопрос, почему вы чувствуете потребность в Inver t - матрица. –

+2

Как сказал Хеффернан, вам действительно нужно инвертировать матрицу? См. [This] (http://www.johndcook.com/blog/2010/01/19/dont-invert-that-matrix/) и [это] (http://blogs.sas.com/content/iml/2011/08/10/do-you-really-need-to-compute-that-matrix-inverse /) для нескольких сообщений – gg349

ответ

8

Вот ответ. Когда вы запускаете inv в matlab для разреженной матрицы, matlab проверяет различные свойства матрицы для оптимизации вычисления. Для редкой диагональной матрицы, вы можете запустить followin код, чтобы увидеть, что делает MATLAB

n = 10000; 
a = diag(1:n); 
a = sparse(a); 
I = speye(n,n); 
spparms('spumoni',1); 
ainv = inv(a); 
spparms('spumoni',0); 

Matlab напечатает следующее:

sp\: bandwidth = 0+1+0. 
sp\: is A diagonal? yes. 
sp\: do a diagonal solve. 

Так MATLAB является инвертирование только по диагонали.

Как Scipy инвертирует матрицу? Здесь мы имеем code:

... 
from scipy.sparse.linalg import spsolve 
... 

def inv(A): 
    """ 
    Some comments... 
    """ 
    I = speye(A.shape[0], A.shape[1], dtype=A.dtype, format=A.format) 
    Ainv = spsolve(A, I) 
    return Ainv 

и spsolve

# Cover the case where b is also a matrix 
    Afactsolve = factorized(A) 
    tempj = empty(M, dtype=int) 
    x = A.__class__(b.shape) 
    for j in range(b.shape[1]): 
     xj = Afactsolve(squeeze(b[:, j].toarray())) 
     w = where(xj != 0.0)[0] 
     tempj.fill(j) 
     x = x + A.__class__((xj[w], (w, tempj[:len(w)])), 
          shape=b.shape, dtype=A.dtype) 

т.е., scipy factorize A, а затем решить набор линейных систем, где правые части являются координатными векторами (образующими единичную матрицу). Заказывая все решения в матрице, получим обратную исходную матрицу.

Если Matlab используется диагональной структурой матрицы, но scipy не является (конечно, scipy также использует структуру матрицы, но менее эффективным способом, по крайней мере, для примера), Matlab должен быть намного быстрее.

EDIT Чтобы быть уверенным, что propossed @ P.Escondido, мы будем пробовать незначительные изменения в матрице А, чтобы проследить процедуру MatLab, когда матрица не является диагональной:

n = 10000; a = diag(1:n); a = sparse(a); ainv = sparse(n,n); 
spparms('spumoni',1); 
a(100,10) = 500; a(10,1000) = 200; 
ainv = inv(a); 
spparms('spumoni',0); 

Он печатает из следующих действий:

sp\: bandwidth = 90+1+990. 
sp\: is A diagonal? no. 
sp\: is band density (0.00) > bandden (0.50) to try banded solver? no. 
sp\: is A triangular? no. 
sp\: is A morally triangular? yes. 
sp\: permute and solve. 
sp\: sprealloc in sptsolve: 10000 10000 10000 15001 
+1

спасибо! a (1000,10) = 500; a (10,1000) = 200; к решению и соответствующему выходу. Это дает нам гораздо лучшее представление о том, как работает Matlab. Если вы это сделаете, я остановлю проблему. –

3

Вы Witholding важной информации из вашего программного обеспечения: тот факт, что матрица является диагональной делает его очень легко инвертировать: вы просто инвертировать каждый элемент диагонали:

P = np.diag(range(1,10000)) 
A = np.diag(1.0/np.arange(1,10000)) 

Конечно, это справедливо только для диагональных матриц ...

+0

Точно это справедливо только для диагональных матриц, поэтому ответ на самом деле не работает. Также обратите внимание, что мне не нужно указывать свои знания о структуре Matlab. –

+1

@ P.Escondido Я провожу немного времени, пытаясь понять и обратить внимание на то, что делает Matlab, когда он инвертирует матрицу. Я должен сказать, что флески на мачете отлично справились с этой задачей. За кулисами в игре имеется немало числовых библиотек, использующих специфические характеристики матрицы. Если вы можете предоставить эту дополнительную информацию в свою программу - сделайте себе легкую жизнь и используйте ее, не пытайтесь решать сложные проблемы, если вам не нужно ... – Shai

4

Как насчет splu(), это быстрее, но нужен плотный массив и вернуться плотный массив:

Создать случайную матрицу:

import numpy as np 
import time 
import scipy.sparse as sps 
import scipy.sparse.linalg as spsl 
from numpy.random import randint 
N = 1000 
i = np.arange(N) 
j = np.arange(N) 
v = np.ones(N) 

i2 = randint(0, N, N) 
j2 = randint(0, N, N) 
v2 = np.random.rand(N) 

i = np.concatenate((i, i2)) 
j = np.concatenate((j, j2)) 
v = np.concatenate((v, v2)) 

A = sps.coo_matrix((v, (i, j))) 
A = A.tocsc() 

%time B = spsl.inv(A) 

вычислить обратную матрицу с помощью splu():

%%time 
lu = spsl.splu(A) 
eye = np.eye(N) 
B2 = lu.solve(eye) 

проверка результат:

np.allclose(B.todense(), B2.T) 

Вот выход% Время:

inv: 2.39 s 
splv: 193 ms 
+0

код не компилируется в Python 2.7; проблема заключается в «% времени B = spsl.inv (A)». Какой компилятор мне следует использовать? –

+0

% время - это команда IPython, если вы не используете IPython, просто удалите% time и %% time. – HYRY

0

Если вы пытаетесь с этим результатом будет лучше:

import numpy as np 
import time 
import scipy.sparse as sps 
import scipy.sparse.linalg as spsl 

P = np.diag(range(1,10000)) 
P_sps = sps.coo_matrix(P) 
startTime = time.time() 
A = spsl.inv(P_sps) 
runningTime = (time.time()-startTime)/60 
print "The script was running for %f minutes" % runningTime 

Теперь вы можете сравнить с вашим скриптом matlab.

+0

спасибо, я согласен, что таймер должен был быть запущен прямо перед вычислением, но разница небезопасна. –

+0

Я не думаю, что разница незначительна. – sebas

+3

0,44 против 0,64 минуты. Matlab делает это на 3 порядка быстрее. В этом смысле это незначительно. –

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