Jak operator odwrotnego ukośnika MATLAB rozwiązuje dla macierzy kwadratowych?


36

Porównywałem kilka moich kodów z „zapasowymi” kodami MATLAB. Jestem zaskoczony wynikami.

Uruchomiłem przykładowy kod (Sparse Matrix)

n = 5000;
a = diag(rand(n,1));
b = rand(n,1);
disp('For a\b');
tic;a\b;toc;
disp('For LU');
tic;LULU;toc;
disp('For Conj Grad');
tic;conjgrad(a,b,1e-8);toc;
disp('Inv(A)*B');
tic;inv(a)*b;toc;

Wyniki:

    For a\b
    Elapsed time is 0.052838 seconds.

    For LU
    Elapsed time is 7.441331 seconds.

    For Conj Grad
    Elapsed time is 3.819182 seconds.

    Inv(A)*B
    Elapsed time is 38.511110 seconds.

W przypadku gęstej matrycy:

n = 2000;
a = rand(n,n);
b = rand(n,1);
disp('For a\b');
tic;a\b;toc;
disp('For LU');
tic;LULU;toc;
disp('For Conj Grad');
tic;conjgrad(a,b,1e-8);toc;
disp('For INV(A)*B');
tic;inv(a)*b;toc;

Wyniki:

For a\b
Elapsed time is 0.575926 seconds.

For LU
Elapsed time is 0.654287 seconds.

For Conj Grad
Elapsed time is 9.875896 seconds.

Inv(A)*B
Elapsed time is 1.648074 seconds.

Jak do cholery jest tak niesamowicie?


1
Wbudowany ukośnik odwrotny MATLAB, innymi słowy bezpośredni solver dla układu równań liniowych, wykorzystuje metodę wielopłaszczyznową dla macierzy rzadkich, dlatego A \ B jest tak niesamowity.
Shuhao Cao,

1
Wykorzystuje kod Tima Davisa dostępny na stronie cise.ufl.edu/research/sparse . Niesamowita przemija też, gdy masz nietrywialny problem
stali

1
Co to jest „LULU”? Jak myślisz, dlaczego jest to dobra implementacja faktoryzacji LU i późniejszego bezpośredniego rozwiązania?
Jed Brown

3
@Nunoxic Jakie wdrożenie? Sam to napisałeś? Wydajna, gęsta algebra liniowa, choć zwykle dobrze rozumiana algorytmicznie, nie jest łatwa do skutecznego wdrożenia na nowoczesnym sprzęcie. Najlepsze implementacje BLAS / Lapack powinny zbliżyć się do szczytu dla macierzy tego rozmiaru. Ponadto z twoich komentarzy mam wrażenie, że uważasz, że LU i eliminacja Gaussa to różne algorytmy.
Jed Brown

1
Wywołuje kod Fortran napisany przy użyciu Intel MKL.
Zapytanie

Odpowiedzi:


37

W Matlabie komenda „\” wywołuje algorytm, który zależy od struktury macierzy A i obejmuje sprawdzenie (mały narzut) właściwości A.

  1. Jeśli A jest rzadki i zwinięty, zastosuj solver zwężający się.
  2. Jeśli A jest górną lub dolną trójkątną matrycą, zastosuj algorytm podstawiania wstecznego.
  3. Jeśli A jest symetryczny i ma rzeczywiste dodatnie elementy ukośne, spróbuj dokonać faktoryzacji Choleskiego. Jeśli A jest rzadkie, najpierw zastosuj zmianę kolejności, aby zminimalizować wypełnienie.
  4. Jeśli żadne z powyższych kryteriów nie jest spełnione, wykonaj ogólną trójkątną faktoryzację, stosując eliminację Gaussa z częściowym przestawieniem.
  5. Jeśli A jest rzadkie, zastosuj bibliotekę UMFPACK.
  6. Jeśli A nie jest kwadratowe, zastosuj algorytmy oparte na faktoryzacji QR dla nieokreślonych systemów.

Aby zmniejszyć koszty ogólne, można użyć polecenia linsolve w Matlabie i wybrać odpowiedni solver spośród tych opcji.


Zakładając, że mam do czynienia z niestrukturalną gęstą matrycą o wymiarach 10000 x 10000 ze wszystkimi elementami niezerowymi (wysoki poziom gęstości), jaki byłby mój najlepszy zakład? Chcę wyodrębnić ten 1 algorytm, który działa dla gęstych matryc. Czy to eliminacja LU, QR czy Gaussa?
Zapytanie

1
Brzmi jak krok 4, w którym wywoływana jest eliminacja Gaussa, co odpowiada najbardziej ogólnemu przypadkowi, w którym nie można wykorzystać struktury A w celu zwiększenia wydajności. Zasadniczo jest to faktoryzacja LU, a następnie jeden krok do przodu, po którym następuje krok wstecz.
Allan P. Engsig-Karup,

Dzięki! Myślę, że to daje mi kierunek do myślenia. Obecnie eliminacja gaussowska jest najlepsza, jaką mamy do rozwiązywania takich nieustrukturyzowanych problemów, prawda?
Zapytanie

37

Jeśli chcesz zobaczyć, co a\brobi dla twojej konkretnej matrycy, możesz ustawić spparms('spumoni',1)i dokładnie określić, jakim algorytmem byłeś pod wrażeniem. Na przykład:

spparms('spumoni',1);
A = delsq(numgrid('B',256));
b = rand(size(A,2),1);
mldivide(A,b);  % another way to write A\b

wyjdzie

sp\: bandwidth = 254+1+254.
sp\: is A diagonal? no.
sp\: is band density (0.01) > bandden (0.50) to try banded solver? no.
sp\: is A triangular? no.
sp\: is A morally triangular? no.
sp\: is A a candidate for Cholesky (symmetric, real positive diagonal)? yes.
sp\: is CHOLMOD's symbolic Cholesky factorization (with automatic reordering) successful? yes.
sp\: is CHOLMOD's numeric Cholesky factorization successful? yes.
sp\: is CHOLMOD's triangular solve successful? yes.

więc widzę, że w tym przypadku „\” użyło „CHOLMOD”.


3
+1 za nowe ustawienia MATLAB, o których nigdy nie słyszałem. Dobra gra, proszę pana.
Geoff Oxberry

2
Hej dzięki! Jest w środku help mldivide.
dranxo

16

W przypadku rzadkich macierzy Matlab używa UMFPACK do operacji „ \”, która w twoim przykładzie zasadniczo przegląda wartości a, odwraca je i mnoży je przez wartości b. Jednak w tym przykładzie powinieneś użyć b./diag(a), który jest znacznie szybszy.

W przypadku gęstych systemów operator odwrotnego ukośnika jest nieco bardziej skomplikowany. Krótki opis tego, co się dzieje, gdy jest podany tutaj . Zgodnie z tym opisem, w twoim przykładzie Matlab rozwiązałby a\bza pomocą podstawienia wstecznego. W przypadku ogólnych macierzy kwadratowych stosuje się rozkład LU.


Regd. Rzadkość, inv macierzy diag byłaby po prostu odwrotnością elementów diagonalnych, więc b./diag(a) działałoby, ale a \ b działa niesamowicie również w przypadku ogólnych macierzy rzadkich. Dlaczego Linsolve lub LULU (Moja zoptymalizowana wersja LU) nie jest szybsza niż a b dla gęstych matryc w tym przypadku.
Zapytanie

@Nunoxic Czy Twój LULU robi coś, aby wykryć przekątną lub trójkątność gęstej matrycy? Jeśli nie, zajmie to tyle samo czasu dla każdej matrycy, niezależnie od jej zawartości lub struktury.
Pedro

Nieco. Ale dzięki flagom linsolve OPT zdefiniowałem wszystko, co można zdefiniować w strukturze. Jednak a \ b jest szybszy.
Zapytanie

@Nunoxic, za każdym razem, gdy wywołujesz funkcję użytkownika, powodujesz narzuty. Matlab robi wszystko wewnętrznie dla ukośnika odwrotnego, np. Rozkład i późniejsze nałożenie prawej strony, przy bardzo niewielkim obciążeniu, dzięki czemu będzie szybszy. Ponadto w testach należy użyć więcej niż jednego połączenia, aby uzyskać wiarygodne czasy, np tic; for k=1:100, a\b; end; toc.
Pedro

5

Zasadniczo, jeśli masz rzadką matrycę o rozsądnej złożoności (tj. Nie musi to być szablon 5-punktowy, ale w rzeczywistości może być dyskretyzacją równań Stokesa, dla których liczba niezerowych w rzędzie wynosi znacznie większy niż 5), wówczas rzadki bezpośredni solver, taki jak UMFPACK, zazwyczaj pokonuje iteracyjny solver Kryłowa, jeśli problem nie jest większy niż około 100 000 niewiadomych.

Innymi słowy, dla większości rzadkich macierzy wynikających z dyskretyzacji 2D, najszybszym rozwiązaniem jest bezpośredni solver. Tylko w przypadku problemów 3D, w których szybko dostajesz ponad 100 000 niewiadomych, konieczne jest użycie iteracyjnego solvera.


3
Nie jest dla mnie jasne, jak to odpowiada na pytanie, ale mam również problem z tym założeniem. Prawdą jest, że solwery bezpośrednie zwykle działają dobrze w przypadku problemów ze skromnym rozmiarem 2D, ale bezpośrednie solwery cierpią w 3D na długo przed 100k niewiadomych (separatory wierzchołków są znacznie większe niż w 2D). Ponadto twierdzę, że w większości przypadków (np. Operatory eliptyczne) iteracyjne solwery można wykonać szybciej niż solwery bezpośrednie, nawet w przypadku problemów średniej wielkości 2D, ale może to wymagać znacznego wysiłku (np. Użycie odpowiednich składników, aby działanie wielu siatek) .
Jed Brown

1
Jeśli twoje problemy są dość małe i nie chcesz myśleć o projektowaniu niejawnych solverów, lub jeśli twoje problemy są bardzo trudne (jak Maxwell o wysokiej częstotliwości) i nie chcesz poświęcać swojej kariery projektowaniu dobrych solverów, to ja zgadzają się, że rzadkie bezpośrednie solwery są doskonałym wyborem.
Jed Brown

Właściwie moim problemem jest zaprojektowanie dobrego gęstego solvera. Nie mam konkretnej aplikacji jako takiej (stąd brak struktury). Chciałem ulepszyć kilka moich kodów i sprawić, by były konkurencyjne w stosunku do obecnie używanych. Byłem ciekawy \ b i tego, jak zawsze bije bzdury z mojego kodu.
Zapytanie

@JedBrown: Tak, być może przy znacznym wysiłku można uzyskać iteracyjne solwery, aby pokonać bezpośredni solver nawet przy małych problemach 2D. Ale dlaczego to robisz? W przypadku problemów z <100k niewiadomych, rzadkie bezpośrednie solwery w 2d są wystarczająco szybkie. Chciałem powiedzieć: w przypadku tak małych problemów nie marnuj czasu na majstrowanie i wymyślanie najlepszej kombinacji parametrów - po prostu weź blackbox.
Wolfgang Bangerth,

Istnieje już rząd wielkości różnicy czasu między rzadkim Cholesky i (opartym na macierzy) geometrycznym multigrid dla „łatwych” problemów 2D z 100k dof przy użyciu 5-punktowego szablonu (~ 0,5 sekundy w porównaniu do ~ 0,05 sekundy). Jeśli szablon używa drugich sąsiadów (np. Dyskretyzacja czwartego rzędu, Newton w przypadku niektórych reologii nieliniowych, stabilizacji itp.), Wielkość separatorów wierzchołków w przybliżeniu podwaja się, więc koszt bezpośredniego rozwiązania wzrasta około 8x (koszt jest większy zależne od problemu dla MG). Przy wielu krokach czasowych lub pętlach optymalizacji / UQ różnice te są znaczące.
Jed Brown
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.