MN08: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Dorota (dyskusja | edycje)
Nie podano opisu zmian
Przykry (dyskusja | edycje)
Nie podano opisu zmian
Linia 1: Linia 1:
<!--
Konwertowane  z pliku LaTeX przez latex2mediawiki, zob. http://www.ii.uj.edu.pl/&nbsp;pawlik1/latex2mediawiki.php.
Niezb�dne rozszerzenia i modyfikacje oryginalnego latex2mediawiki
wprowadzi� przykry@mimuw.edu.pl
-->
=Wielkie układy równań liniowych=
=Wielkie układy równań liniowych=
{{powrot |Metody numeryczne | do strony głównej
przedmiotu <strong>Metody numeryczne</strong>}}


Wraz z coraz większymi modelami pojawiającymi się w praktyce obliczeniowej,
Wraz z coraz większymi modelami pojawiającymi się w praktyce obliczeniowej,
Linia 11: Linia 21:
stały się rozwiązywalne przy obecnym stanie techniki obliczeniowej!
stały się rozwiązywalne przy obecnym stanie techniki obliczeniowej!


Jednym ze szczególnie ważnych źródeł układów równań z macierzami rozrzedzonymi
Jednym ze szczególnie ważnych źródeł układów równań z macierzami rozrzedzonymi są np. <strong>równania różniczkowe cząstkowe</strong> (a więc np. modele pogody, naprężeń w konstrukcji samochodu, przenikania kosmetyków do głębszych warstw skóry, itp.).
są np. '''równania różniczkowe cząstkowe''' (a więc np. modele pogody, naprężeń w
 
konstrukcji samochodu, przenikania kosmetyków do głębszych warstw skóry, itp.).
Modele wielostanowych systemów kolejkowych (np. routera obsługującego wiele komputerów) także prowadzą do gigantycznych układów równań z macierzami rozrzedzonymi o specyficznej strukturze.
 
Z reguły zadania liniowe ''wielkiego wymiaru'' będą miały strukturę macierzy rozrzedzonej, gdyż najczęściej związki pomiędzy niewiadomymi w równaniu nie dotyczą wszystkich, tylko wybranej grupy.


<div style="margin-top:1em; padding-top,padding-bottom:1em;">
<div style="margin-top:1em; padding-top,padding-bottom:1em;">
<span  style="font-variant:small-caps;">Przykład: Macierz z kolekcji Boeinga</span>  
<span  style="font-variant:small-caps;">Przykład: Macierz z kolekcji Boeinga</span>  
<div class="solution">
<div class="solution" style="margin-left,margin-right:3em;">


Macierz sztywności dla modelu silnika lotniczego wygenerowana swego czasu w
Spójrzmy na macierz sztywności dla modelu silnika lotniczego, wygenerowaną swego czasu w zakładach Boeinga i pochodzącą z dyskretyzacji pewnego równania różniczkowego cząstkowego. Pochodzi z [http://www.cise.ufl.edu/research/sparse/matrices/Boeing  kolekcji Tima Davisa]. Jest to mała macierz, wymiaru 8032 (w kolekcji spotkasz równania z milionem i więcej niewiadomych).
zakładach Boeinga pochodzi z
[http://www.cise.ufl.edu/research/sparse/matrices/Boeing  kolekcji Tima
Davisa] (autora bardzo dobrego solvera równań liniowych z macierzami rzadkimi).
Jest to mała macierz, wymiaru 8032 (w kolekcji spotkasz równania z milionem i
więcej
niewiadomych).


[[Image:MNsparseA.png|thumb|450px|center|Struktura niezerowych elementów macierzy bcsstk38.]]
[[Image:MNsparseA.png|thumb|550px|center|Struktura niezerowych elementów macierzy bcsstk38.]]


Jej <strong>współczynnik wypełnienia</strong> (to znaczy, stosunek liczby niezerowych do wszystkich elementów macierzy) wynosi jedynie <math>\displaystyle 0.006</math>, a więc macierz jest bardzo rozrzedzona: w każdym wierszu są średnio tylko 44 niezerowe elementy.
</div></div>
</div></div>


Modele wielostanowych systemów kolejkowych (np. routera obsługującego wiele komputerów) także
<!--
prowadzą do gigantycznych układów równań z macierzami rozrzedzonymi o
specyficznej strukturze.
 
Z reguły zadania liniowe wielkiego wymiaru będą miały strukturę macierzy
rozrzedzonej, gdyż najczęściej związki pomiędzy niewiadomymi w równaniu nie
dotyczą wszystkich, tylko wybranej grupy.


<div style="margin-top:1em; padding-top,padding-bottom:1em;">
<div style="margin-top:1em; padding-top,padding-bottom:1em;">
<span  style="font-variant:small-caps;">Przykład: Macierz MBEACXC</span>  
<span  style="font-variant:small-caps;">Przykład: Macierz MBEACXC</span>  
<div class="solution">
<div class="solution" style="margin-left,margin-right:3em;">


Dane pochodzą z serwisu  
Dane pochodzą z serwisu  
[http://math.nist.gov/MatrixMarket  MatrixMarket]. Jest to niezbyt duża macierz, wymiaru
[http://math.nist.gov/MatrixMarket  MatrixMarket]. Jest to niezbyt duża macierz, wymiaru <math>\displaystyle 496 \times 496</math>, niesymetryczna, o elementach rzeczywistych. Źródłem tej macierzy jest pewien model ekonomiczny.
<math>\displaystyle 496 \times 496</math>, niesymetryczna, o elementach rzeczywistych. Źródłem tej
macierzy jest pewien model ekonomiczny.


[[Image:MNmbeacxc|thumb|450px|center|Struktura niezerowych elementów macierzy MBEACXC]]
[[Image:MNmbeacxc|thumb|550px|center|Struktura niezerowych elementów macierzy MBEACXC]]


Tylko pozornie macierz ta wydaje się dość gęsta, w rzeczywistości jej współczynnik wypełnienia
Tylko pozornie macierz ta wydaje się dość gęsta, w rzeczywistości jej współczynnik wypełnienia wynosi około 20 procent.  
wynosi około 20 procent.  
</div></div>
</div></div>


==Formaty macierzy rzadkich==
-->
==Reprezentacja macierzy rzadkich==


Zacznijmy od sposobu przechowywania macierzy rozrzedzonych. Naturalnie, nie ma
Zacznijmy od sposobu przechowywania macierzy rozrzedzonych. Naturalnie, nie ma
Linia 63: Linia 63:
wektor, nie będziemy mnożyć przez zera!).  
wektor, nie będziemy mnożyć przez zera!).  


====Format współrzędnych (AIJ)====
===Format współrzędnych===


Do zapamiętania macierzy
Do zapamiętania macierzy <math>\displaystyle A</math> wymiaru <math>\displaystyle N\times M</math> o <math>\displaystyle NNZ</math> niezerowych elementów wykorzystujemy trzy wektory: <code>I</code>,
<math>\displaystyle A</math> wymiaru <math>\displaystyle N\times M</math> o <math>\displaystyle NNZ</math> niezerowych elementów wykorzystujemy trzy wektory: <code>I</code>,
<code>J</code> --- oba typu <code>int</code> --- oraz <code>V</code>, typu <code>double</code>,
<code>J</code> --- oba typu <code>int</code> --- oraz <code>V</code>, typu <code>double</code>,
wszystkie o długości <math>\displaystyle NNZ</math>, przy czym
wszystkie o długości <math>\displaystyle NNZ</math>, przy czym
Linia 74: Linia 73:
</math></center>
</math></center>
   
   
[[Image:MNaij-matrix-format.png|thumb|450px|center|Format AIJ]]
[[Image:MNaij-matrix-format.png|thumb|550px|center|Format AIJ]]


W tym formacie wprowadzane są macierze rzadkie do Octave'a i MATLABa:
W tym formacie wprowadzane są macierze rzadkie do Octave'a i MATLABa:


<div class="code" style="background-color:#e8e8e8; padding:1em"><pre>
<div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>A = sparse(I,J,V,N,N);
</pre></div>  
   
   
A = sparse(I,J,V,N,N);
Jednak wewnętrznie przechowywane są w innym formacie, o którym [[#Format spakowanych kolumn (wierszy)|poniżej]].
</pre></div>
 
<div style="margin-top:1em; padding-top,padding-bottom:1em;">
<span  style="font-variant:small-caps;">Przykład</span>
<div class="solution" style="margin-left,margin-right:3em;">
 
Pokażemy jak w Octave wprowadzić macierz rozrzedzoną.
 
<div style="font-family: monospace; white-space: pre; border-style: dashed; border-width: thin; border-color: black; margin: 1em; padding:1em; color: #444; background-color:#fdfdfd;"><nowiki>octave:10> I = [1, 1, 1, 2, 3, 1, 4];
octave:11> J = [1, 3, 2, 2, 3, 4, 4];
octave:12> V = [1, 2, 3, 4, 5, 6, 7];
octave:13> N = 4;
octave:14> A = sparse(I,J,V,N,N)
A =
 
Compressed Column Sparse (rows = 4, cols = 4, nnz = 7)
 
  (1, 1) ->  1
  (1, 2) ->  3
  (2, 2) ->  4
  (1, 3) ->  2
  (3, 3) ->  5
  (1, 4) ->  6
  (4, 4) ->  7
 
octave:15> spy(A);
</nowiki></div>
   
   
====Format spakowanych kolumn (wierszy)====
Strukturę jej niezerowych elementów ukaże nam polecenie <code style="color: #006">spy(A)</code>. Tak właśnie zostały wygenerowane obrazki macierzy w niniejszym wykładzie.
 
</div></div>
 
===Format spakowanych kolumn (wierszy)===


Format współrzędnych nie narzucał żadnego uporządkowania elementów macierzy
Format współrzędnych nie narzucał żadnego uporządkowania elementów macierzy
Linia 89: Linia 118:
porządku mogłoby wspomóc realizację wybranych istotnych operacji na macierzy,
porządku mogłoby wspomóc realizację wybranych istotnych operacji na macierzy,
na przykład, aby wygodnie było realizować działanie (prawostronnego) mnożenia
na przykład, aby wygodnie było realizować działanie (prawostronnego) mnożenia
macierzy przez wektor, wygodnie byłoby przechowywać elementy macierzy <strong>wierszami</strong>. Tak właśnie jest zorganizowany format spakowanych wierszy,
macierzy przez wektor, dobrze byłoby przechowywać elementy macierzy ''wierszami''. Tak właśnie jest zorganizowany format spakowanych wierszy (''Compressed Sparse Row, CSR''). Analogicznie jest zdefiniowany format
''Compressed Sparse Row (CSR) ''. Analogicznie jest zdefiniowany format
spakowanych kolumn (''Compressed Sparse Column, CSC''), którym zajmiemy się bliżej.
spakowanych kolumn,
''Compressed Sparse Column (CSC) '', którym zajmiemy się bliżej.


Podobnie jak w przypadku formatu współrzędnych, macierz w formacie CSC jest
Podobnie jak w przypadku formatu współrzędnych, macierz w formacie CSC jest
Linia 101: Linia 128:
elementom z <code>AV</code>. Natomiast zamiast tablicy <code>J</code>, jak to było w
elementom z <code>AV</code>. Natomiast zamiast tablicy <code>J</code>, jak to było w
formacie współrzędnych, mamy krótszy wektor typu <code>int</code>, <code>AP</code>, o
formacie współrzędnych, mamy krótszy wektor typu <code>int</code>, <code>AP</code>, o
długości <math>\displaystyle M</math> zawierający na <math>\displaystyle j</math>-tym miejscu indeks pozycji w <code>AV</code>, od
długości <math>\displaystyle M</math>, zawierający na <math>\displaystyle j</math>-tym miejscu indeks pozycji w <code>AV</code>, od
którego rozpoczynają się w <code>AV</code> elementy <math>\displaystyle j</math>-tej kolumny macierzy <math>\displaystyle A</math>.
którego rozpoczynają się w <code>AV</code> elementy <math>\displaystyle j</math>-tej kolumny macierzy <math>\displaystyle A</math>.


[[Image:MNcsc-matrix-format.png|thumb|450px|center|Format CSC]]
[[Image:MNcsc-matrix-format.png|thumb|550px|center|Format CSC]]


Mamy więc zależność, przy założeniu, że <math>\displaystyle AP[0]=0</math>,
Mamy więc zależność, przy założeniu, że <math>\displaystyle AP[0]=0</math>,
Linia 113: Linia 140:


Taki (z drobnymi modyfikacjami) format macierzy wykorzystują np. pakiety ARPACK
Taki (z drobnymi modyfikacjami) format macierzy wykorzystują np. pakiety ARPACK
i UMFPACK.
i UMFPACK (a także, wewnętrznie, Octave i MATLAB).


====Format diagonalny====
===Format diagonalny===


Znacznie mniej uniwersalny niż poprzednie i dlatego rzadziej spotykany. Kolejne
Znacznie mniej uniwersalny niż poprzednie i dlatego rzadziej spotykany. Kolejne
Linia 122: Linia 149:


Szczególnie wygodny do reprezentacji macierzy taśmowych. Wykorzystywany m.in.
Szczególnie wygodny do reprezentacji macierzy taśmowych. Wykorzystywany m.in.
przez funkcję LAPACKa <code>DGBSV</code> służącą rozwiązywaniu równań z macierzami
przez funkcję LAPACKa <code style="color: #903">DGBSV</code> służącą rozwiązywaniu równań z macierzami
taśmowymi.
taśmowymi.
===Uwagi praktyczne===
Mnożenie macierzy w formacie AIJ przez wektor jest kilka razy wolniejsze w porównaniu do macierzy w formacie CSC/CSR (z tych dwóch oczywiście (dlaczego?) CSR jest najszybszy).  Co więcej, okazuje się, że w typowych implementacjach, mnożenie macierzy rozrzedzonej (reprezentowanej np. w formacie CSC) przez wektor jest mało efektywne, mniej więcej na poziomie dziesięciu procent możliwości obliczeniowych procesora.
Jeśli już ''poważnie'' myśleć o przyspieszeniu mnożenia macierzy przez wektor (np. gdy chcemy stosować [[#Stacjonarne metody iteracyjne|iteracyjną metodę rozwiązywania układu równań]] z tą macierzą), warto rozważyć [http://bebop.cs.berkeley.edu/pubs/vuduc2003-dissertation.pdf  inne formaty] --- łączące w sobie podział macierzy na bloki (tak, jak w algorytmach BLAS) i przechowywanie (w zasadzie) tylko niezerowych elementów macierzy.


==Macierze specjalne==
==Macierze specjalne==
Linia 139: Linia 172:
wyspecjalizowane algorytmy.
wyspecjalizowane algorytmy.


====Macierze  taśmowe====
===Macierze  taśmowe===


Macierz <math>\displaystyle A</math> taka, że dla <math>\displaystyle |i-j| \geq d</math>, <math>\displaystyle a_{ij} = 0</math>, nazywamy macierzą taśmową
Macierz <math>\displaystyle A</math> taka, że dla <math>\displaystyle |i-j| \geq d</math>, <math>\displaystyle a_{ij} = 0</math>, nazywamy macierzą taśmową
Linia 152: Linia 185:
W szczególności, gdy macierz jest taśmowa z pasmem o rozstępie <math>\displaystyle d</math> i jednocześnie
W szczególności, gdy macierz jest taśmowa z pasmem o rozstępie <math>\displaystyle d</math> i jednocześnie
diagonalnie dominująca, wtedy rozkład LU takiej macierzy da się wykonać w
diagonalnie dominująca, wtedy rozkład LU takiej macierzy da się wykonać w
miejscu kosztem <math>\displaystyle O(d\,N)</math> czyli liniowym.
miejscu kosztem <math>\displaystyle O(d\,N)</math>, czyli liniowym.


W LAPACKu zaimplementowano szybki solver równań z macierzami taśmowymi,
W [http://www.netlib.org/lapack  LAPACKu] zaimplementowano szybki ''solver'' równań z macierzami taśmowymi,
<code>DGBSV</code> wymagający skądinąd specjalnego sposobu
<code style="color: #903">DGBSV</code>, ale wymagający specjalnego sposobu
przechowywania macierzy wykorzystyjącego format diagonalny.
przechowywania macierzy, wykorzystującego format diagonalny.


====Macierze trójdiagonalne====
===Macierze trójdiagonalne===


Szczególnym przypadkiem macierzy taśmowych są macierze trójdiagonalne, tzn. taśmowe o
Szczególnym przypadkiem macierzy taśmowych są macierze trójdiagonalne, tzn. taśmowe o
Linia 179: Linia 212:
</math></center>
</math></center>


jest tak często spotykane, że
jest bardzo  często spotykane, więc warto przytoczyć algorytm w całej okazałości --- popularnie zwany <strong>algorytmem przeganiania</strong> (niektóre źródła nazywają go ''algorytmem Thomasa'').
warto przytoczyć algorytm w całej okazałości --- popularnie zwany algorytmem
przeganiania.


Zacznijmy jednak od stwierdzenia, kiedy taka macierz nie wymaga wyboru elementu
Zacznijmy jednak od stwierdzenia, kiedy macierz trójdiagonalna  nie wymaga wyboru elementu głównego:
głównego:


{{stwierdzenie|||
{{stwierdzenie|||
Jeśli macierz <math>\displaystyle A</math> ma <strong>słabo</strong> dominującą przekątną, tzn.
Jeśli macierz <math>\displaystyle A</math> ma <strong>słabo dominującą diagonalę</strong>, tzn.


<center><math>\displaystyle |a_i|\,\ge\,|b_i|\,+\,|c_i|,\qquad 1\le i\le N,
<center><math>\displaystyle |a_i|\,\ge\,|b_i|\,+\,|c_i|,\qquad 1\le i\le N,
Linia 198: Linia 228:
}}
}}


{{algorytm|Metoda przeganiania||
{{algorytm|Metoda przeganiania|Metoda przeganiania|
<pre>
<pre><math>\displaystyle d_1</math> = <math>\displaystyle a_1</math>;  
 
<math>\displaystyle d_1</math> = <math>\displaystyle a_1</math>;  
<math>\displaystyle f_1</math> = <math>\displaystyle e_1</math>;
<math>\displaystyle f_1</math> = <math>\displaystyle e_1</math>;
for (i = 2; i <= N; i++)
for (i = 2; i <= N; i++)
Linia 218: Linia 246:
<div style="margin-top:1em; padding-top,padding-bottom:1em;">
<div style="margin-top:1em; padding-top,padding-bottom:1em;">
<span  style="font-variant:small-caps;">Przykład: Strzałka Wilkinsona</span>  
<span  style="font-variant:small-caps;">Przykład: Strzałka Wilkinsona</span>  
<div class="solution">
<div class="solution" style="margin-left,margin-right:3em;">


Rozważmy układ równań z macierzą diagonalnie dominującą postaci
Rozważmy układ równań z macierzą diagonalnie dominującą postaci
Linia 248: Linia 276:
</math></center>
</math></center>


Wtedy okazuje się, że rozkład naszej macierzy nie powoduje już wypełnienia ''
Wtedy okazuje się, że rozkład naszej macierzy nie powoduje już ''wypełnienia'' czynników rozkładu!
fill-in ''
czynników rozkładu!
</div></div>
</div></div>


Właśnie na tym polega główny problem w rozwiązywaniu układów z macierzami
Właśnie na tym polega główny problem w rozwiązywaniu układów z macierzami
rzadkimi metodami bezpośrednimi: maksymalnie wykorzystać rozrzedzenie macierzy
rzadkimi metodami bezpośrednimi: jak maksymalnie wykorzystać rozrzedzenie macierzy tak, by czynniki rozkładu były możliwie mało wypełnione. Albowiem wiedząc to będziemy mogli ograniczyć się jedynie do fizycznego wyznaczenia wartości <strong>niezerowych</strong> elementów macierzy rozkładu. Ponadto wymagania pamięciowe algorytmu nie będą istotnie wykraczać ponad ilość pamięci potrzebnej na przechowanie danych (tzn. macierzy).
tak, by czynniki rozkładu były możliwie mało wypełnione. Albowiem wiedząc to
będziemy mogli ograniczyć się jedynie do fizycznego wyznaczenia wartości <strong>niezerowych</strong> elementów macierzy rozkładu. Ponadto wymagania pamięciowe
algorytmu nie będą istotnie wykraczać ponad ilość pamięci potrzebnej na przechowanie
danych (macierzy).


W ogólnym przypadku rozwiązanie takiego zadania jest trudne i większość
W ogólnym przypadku rozwiązanie takiego zadania jest trudne i większość
algorytmów opiera się na pewnych heurystykach, które warto wspomóc wcześniejszą
algorytmów opiera się na pewnych heurystykach, które jednak w praktyce warto wspomóc wcześniejszą analizą konkretnego układu równań jaki mamy rozwiązać. Najczęściej dąży się do takiego przenumerowania równań i niewiadomych, by w efekcie z góry przewidzieć, gdzie wystąpią zera w macierzach rozkładu --- i, by takich zer było jak najwięcej (by wypełnienie było jak najmniejsze)! Na architekturach z pamięcią hierarchiczną dąży się także do tego, by w trakcie rozkładu można było korzystać z BLAS Level 3, a więc permutacje wierszy i kolumn macierzy muszą to także brać pod uwagę.
analizą konkretnego układu równań, który mamy rozwiązać. Najczęściej dąży się do
takiego przenumerowania równań i niewiadomych, by w efekcie z góry przewidzieć,
gdzie wystąpią zera w macierzach rozkładu --- i, by takich zer było jak
najwięcej (by wypełnienie było jak najmniejsze)! Na architekturach z pamięcią
hierarchiczną dąży się także do tego, by w trakcie rozkładu można było korzystać
z BLAS3, a więc permutacje wierszy i kolumn macierzy muszą to także brać pod
uwagę (tzw. metody wielofrontowe).


Stosuje się kilka strategii wyznaczania korzystnych permutacji
Stosuje się kilka strategii wyznaczania korzystnych permutacji
''reorderingu '', z których warto wymienić  
(''reorderingu''), z których warto wymienić  
* przybliżone algorytmy minimalnego stopnia ''approximate minimum degree ([http://www.cise.ufl.edu/research/sparse/amd  AMD]) ''
* przybliżone algorytmy minimalnego stopnia (''approximate minimum degree, AMD''), np. [http://www.cise.ufl.edu/research/sparse/amd  AMD];
* techniki
* techniki podziału grafów na (prawie) rozłączne składowe ''nested dissection, ND'', np. [http://glaros.dtc.umn.edu/gkhome/views/metis  METIS].
podziału grafów na (prawie) rozłączne składowe ([http://glaros.dtc.umn.edu/gkhome/views/metis  METIS]).
   
   
Używają ich biblioteki
Używają ich biblioteki takie jak [http://www.cise.ufl.edu/research/sparse/umfpack  UMFPACK], czy [http://www.cse.clrc.ac.uk/nag/hsl  HSL].
takie jak [http://www.cise.ufl.edu/research/sparse/umfpack  UMFPACK], czy [http://www.cse.clrc.ac.uk/nag/hsl  HSL].


W Octave mamy do dyspozycji także kilka procedur generujących takie permutacje,
W Octave mamy do dyspozycji także kilka procedur generujących takie permutacje, w tym: <code style="color: #006">colamd</code> (AMD dla macierzy niesymetrycznych) oraz <code style="color: #006">symamd</code> (AMD dla macierzy symetrycznych). Większy wybór oferuje MATLAB, jednak należy bezwzględnie pamiętać o jednym: nie ma uniwersalnej metody ''reorderingu'' i dla konkretnej macierzy może istnieć specjalna metoda, która da oszałamiające rezultaty, podczas gdy standardowe podejścia nie dadzą efektu.
w tym: <code>colamd</code> (AMD dla macierzy niesymetrycznych) oraz <code>symamd</code>
(AMD dla macierzy symetrycznych). Większy wybór oferuje MATLAB, jednak należy
bezwzględnie pamiętać o jednym: nie ma uniwersalnej metody reorderingu i dla
konkretnej macierzy może istnieć specjalna metoda, która da oszałamiające
rezultaty, podczas gdy standardowe podejścia nie dadzą efektu.


<div style="margin-top:1em; padding-top,padding-bottom:1em;">
<div style="margin-top:1em; padding-top,padding-bottom:1em;">
<span  style="font-variant:small-caps;">Przykład: Wypełnienie pewnej macierzy w zależności od użytego algorytmu</span>  
<span  style="font-variant:small-caps;">Przykład: Rozwiązywanie układu z macierzą rozrzedzoną w Octave</span>  
<div class="solution">
<div class="solution" style="margin-left,margin-right:3em;">
 
Najprostszy sposób na wykorzystanie metody bezpośredniego rozwiązywania układu z macierzą rzadką to zastosowanie znanego nam operatora do macierzy typu rozrzedzonego:
 
<div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>A = sparse(...);
x = A \ b;
</pre></div>
Octave domyślnie przyłoży do <math>\displaystyle A</math> reordering <code style="color: #006">colamd</code> i następnie skorzysta z biblioteki UMFPACK, by rozwiązać taki układ. Dodatkowo, badane jest wcześniej, czy macierz nie jest przypadkiem taśmowa o wąskiej wstędze: jeśli jest, to korzysta się z LAPACKa.
 
(Jak widzisz, operator rozwiązywania układu równań jest mocno przeciążony: działa i na macierzach kwadratowych, i na prostokątnych, i na rozrzedzonych --- na każdym rodzaju w inny sposób. Nie dziwi Cię chyba, dlaczego wygodnie było napisać Octave w C++?)
 
</div></div>


Rozważmy macierz pochodzącą z kolekcji
<div style="margin-top:1em; padding-top,padding-bottom:1em;">
[http://www.cise.ufl.edu/research/sparse/matrices/Boeing  Tima Davisa], dotyczącą pewnego zadania
<span  style="font-variant:small-caps;">Przykład: Wypełnienie pewnej macierzy w zależności od użytego reorderingu</span>
mechaniki strukturalnej jakie pojawiło się u Boeinga. Jest to macierz
<div class="solution" style="margin-left,margin-right:3em;">
symetryczna, dodatnio określona, wymiaru 8032.


[[Image:MNsparseA.png|thumb|450px|center|Struktura niezerowych elementów macierzy.]]
Rozważmy ponownie macierz pochodzącą z kolekcji [http://www.cise.ufl.edu/research/sparse/matrices/Boeing  Tima Davisa]. Jest to macierz symetryczna, dodatnio określona, wymiaru 8032, o 355460 elementach niezerowych i, w konsekwencji, o wypełnieniu około 0.6 procent.  


Jest to macierz silnie rozrzedzona, ponieważ ma tylko 355460 niezerowych
[[Image:MNsparseA.png|thumb|550px|center|Struktura niezerowych elementów macierzy.]]
elementów (czyli wypełnienie to tylko 0.5 procent).


Zobaczymy, jak w zależności od użytego algorytmu permutacji kolumn i
Zobaczymy, jak w zależności od użytego algorytmu permutacji kolumn i
wierszy poradzi sobie algorytm rozkładu Cholesky'ego.
wierszy poradzi sobie algorytm rozkładu Cholesky'ego.


[[Image:MNsparsechol.png|thumb|450px|center|Czynnik rozkładu Cholesky'ego <math>\displaystyle L</math> wykonanego
[[Image:MNsparsechol.png|thumb|550px|center|Czynnik rozkładu Cholesky'ego <math>\displaystyle L</math> wykonanego
standardowym algorytmem. Czas rozkładu: 0.892013]]
standardowym algorytmem. Czas rozkładu: 0.892013]]


[[Image:MNsparsecholcolamd.png|thumb|450px|center|Czynnik rozkładu Cholesky'ego <math>\displaystyle L</math> z reorderingiem
[[Image:MNsparsecholcolamd.png|thumb|550px|center|Czynnik rozkładu Cholesky'ego <math>\displaystyle L</math> z reorderingiem
COLAMD. Czas rozkładu: 0.813038]]
COLAMD. Czas rozkładu: 0.813038]]


[[Image:MNsparsecholsymamd.png|thumb|450px|center|Czynnik rozkładu Cholesky'ego <math>\displaystyle L</math> z reorderingiem
[[Image:MNsparsecholsymamd.png|thumb|550px|center|Czynnik rozkładu Cholesky'ego <math>\displaystyle L</math> z reorderingiem
SYMAMD. Czas rozkładu: 0.487683s. Prawie dwa razy
SYMAMD. Czas rozkładu: 0.487683s. Prawie dwa razy
szybciej niż bez reorderingu, chociaż i tak wskutek wzrostu wypełnienia macierzy
szybciej niż bez reorderingu, chociaż i tak wskutek wzrostu wypełnienia macierzy
w dolnym trójkącie mamy aż 2 procent niezerowych elementów.]]
w dolnym trójkącie mamy aż 2 procent niezerowych elementów.]]


[[Image:MNsparsecholsymrcm.png|thumb|450px|center|Czynnik rozkładu Cholesky'ego <math>\displaystyle L</math> z odwrotnym reorderingiem
[[Image:MNsparsecholsymrcm.png|thumb|550px|center|Czynnik rozkładu Cholesky'ego <math>\displaystyle L</math> z odwrotnym reorderingiem
Cuthill-McKee. Czas rozkładu: 0.845928]]
Cuthill-McKee. Czas rozkładu: 0.845928]]


[[Image:MNsparsecholcolperm.png|thumb|450px|center|Czynnik rozkładu Cholesky'ego <math>\displaystyle L</math> z jeszcze
[[Image:MNsparsecholcolperm.png|thumb|550px|center|Czynnik rozkładu Cholesky'ego <math>\displaystyle L</math> z jeszcze
innym (bardzo tanim, ale jak widać czasem zupełnie złym) reorderingiem. Czas rozkładu: 5.947936]]
innym (bardzo tanim, ale jak widać czasem zupełnie złym) reorderingiem. Czas rozkładu: 5.947936]]


Na zakończenie popatrzmy, jak ważne jest spostrzeżenie symetrii macierzy:
Na zakończenie popatrzmy, jak ważne jest spostrzeżenie symetrii macierzy:


[[Image:MNsparseLlu.png|thumb|450px|center|Rozkład LU, czynnik <math>\displaystyle L</math> (bez reorderingu). Czas rozkładu LU: 1.696018s. Nieakceptowalny, podobnie
[[Image:MNsparseLlu.png|thumb|550px|center|Rozkład LU, czynnik <math>\displaystyle L</math> (bez reorderingu). Czas rozkładu LU: 1.696018s. Nieakceptowalny, podobnie
jak drastyczne wypełnienie macierzy.]]
jak drastyczne wypełnienie macierzy.]]


[[Image:MNsparseUlu.png|thumb|450px|center|Rozkład LU, czynnik <math>\displaystyle U</math> (bez reorderingu)]]
[[Image:MNsparseUlu.png|thumb|550px|center|Rozkład LU, czynnik <math>\displaystyle U</math> (bez reorderingu)]]


Jak widać, w naszym przypadku standardowe algorytmy (COLAMD i SYMAMD) poradziły sobie całkiem
Jak widać, w naszym przypadku standardowe algorytmy (COLAMD i SYMAMD) poradziły sobie całkiem nieźle, chociaż wypełnienie i tak znacząco wzrosło. Zapewne, dla tej macierzy, która jest specyficznego typu --- pochodzi z dyskretyzacji równania różniczkowego --- algorytm ND mógłby tu jeszcze lepiej zadziałać.
nieźle, chociaż wypełnienie i tak znacząco wzrosło. Zapewne algorytm oparty na
podziale grafu na prawie rozłączne składowe mógłby tu jeszcze lepiej zadziałać.


</div></div>
</div></div>
Linia 335: Linia 351:
==Stacjonarne metody iteracyjne==
==Stacjonarne metody iteracyjne==


Gdy macierz jest rozrzedzona, mnożenie takiej macierzy przez wektor jest tanie
Gdy macierz jest rozrzedzona, mnożenie takiej macierzy przez wektor jest bardzo tanie (koszt jest proporcjonalny do liczby niezerowych elementów macierzy).
(koszt jest proporcjonalny do liczby <strong>niezerowych</strong> elementów macierzy).
Dlatego, jeśli możemy zadowolić się <strong>rozwiązaniem przybliżonym</strong> układu, a w zamian osiągnąć je tanim kosztem, warto rozważyć metody iteracyjne.
Dlatego, jeśli możemy zadowolić się rozwiązaniem przybliżonym układu, a w zamian
osiągnąć je tanim kosztem, warto rozważyć metody iteracyjne.


Najprostsze metody iteracyjne (najprostsze w analizie i implementacji, ale ---
Najprostsze metody iteracyjne (najprostsze w analizie i implementacji, ale ---
Linia 354: Linia 368:
</math></center>
</math></center>


i zastosować doń [[sec:nieliniowe|Dodaj link: metodę iteracji prostej Banacha]]:
i zastosować doń [[MN02#Iteracja prosta Banacha|metodę iteracji prostej Banacha]]:


<center><math>\displaystyle x_{k+1} = M^{-1}(Zx_k + b).
<center><math>\displaystyle x_{k+1} = M^{-1}(Zx_k + b).
</math></center>
</math></center>


Takie metody nazywamy stacjonarnymi metodami iteracyjnymi.
Takie metody nazywamy stacjonarnymi metodami iteracyjnymi. Aby przeanalizować zbieżność takiej metody, warto rozpatrzyć przypadek ogólniejszy
 
Aby przeanalizować zbieżność takiej metody, warto rozpatrzyć
przypadek ogólniejszy


<center><math>\displaystyle  
<center><math>\displaystyle  
Linia 368: Linia 379:
</math></center>
</math></center>


dla pewnej macierzy <math>\displaystyle B</math>   wektora  
dla pewnej macierzy <math>\displaystyle B</math> oraz wektora <math>\displaystyle c</math>. (Dla stacjonarnej metody iteracyjnej, <math>\displaystyle B=M^{-1}Z</math> oraz <math>\displaystyle c=M^{-1}b</math>.)
<math>\displaystyle c</math> (dla stacjonarnej metody iteracyjnej, <math>\displaystyle B=M^{-1}Z</math> oraz <math>\displaystyle c=M^{-1}b</math>).


W  tym przypadku  
W  tym przypadku  
Linia 386: Linia 396:
zbieżności tej iteracji dla dowolnego wektora startowego <math>\displaystyle x_0</math> jest  
zbieżności tej iteracji dla dowolnego wektora startowego <math>\displaystyle x_0</math> jest  


<center><math>\displaystyle \rho = \max\{ |\lambda| : \lambda  \mbox{ jest wartością własną }  A\} < 1.
<center><math>\displaystyle \rho = \max\{ |\lambda| : \lambda  \mbox{ jest wartością własną }  B\} < 1.
</math></center>
</math></center>


Linia 392: Linia 402:
<math>\displaystyle \rho</math>.
<math>\displaystyle \rho</math>.


====Metoda Jacobiego====
Zaletą stacjonarnych metod iteracyjnych jest również ich prostota,
przez co są one łatwe do zaprogramowania, co łatwo zobaczyć na przykładach metod: [[#Metoda Jacobiego|Jacobiego]] i [[#Metoda Gaussa-Seidela|Gaussa--Seidela]], które teraz omówimy.


[[grafika:Jacobi.jpg|thumb|right|| Jacobi<br>  [[Biografia Jacobi|Zobacz biografię]]]]
===Metoda Jacobiego===


Biorąc <math>\displaystyle D = diag(A)</math>,
Biorąc <math>\displaystyle M = \mbox{diag} (A)</math>, gdzie <math>\displaystyle \mbox{diag} (A)</math> jest macierzą diagonalną składającą się  
gdzie <math>\displaystyle diag(A)</math> jest macierzą diagonalną składającą się  
z wyrazów stojących na głównej przekątnej macierzy  
z wyrazów stojących na głównej przekątnej macierzy  
<math>\displaystyle A</math>, układ <math>\displaystyle A x= b</math> jest równoważny układowi  
<math>\displaystyle A</math>, układ <math>\displaystyle A x= b</math> jest równoważny układowi  


<center><math>\displaystyle D x = Z x +  b,
<center><math>\displaystyle M x = Z x +  b,
</math></center>
</math></center>


Linia 408: Linia 418:


<center><math>\displaystyle x_k\,=\,B x_{k-1}\,+\, c,  
<center><math>\displaystyle x_k\,=\,B x_{k-1}\,+\, c,  
</math></center>,
</math></center>


gdzie <math>\displaystyle B=-D^{-1}Z</math> i <math>\displaystyle  c=D^{-1} b</math>, zwaną  
gdzie <math>\displaystyle B=-M^{-1}Z</math> i <math>\displaystyle  c=M^{-1} b</math>, zwaną  
<strong>metodą Jacobiego</strong>.  
<strong>metodą Jacobiego</strong>.  
Rozpisując ją po współrzędnych dostajemy (numer iteracji wyjątkowo zaznaczamy w postaci ''górnego'' indeksu) układ rozszczepionych równań:
<center><math>\displaystyle x^{(k)}_i = \frac{1}{a_{ii}} \left( b_i - \sum_{j\neq i} a_{ij}x^{(k-1)}_j \right),
</math></center>
co znaczy dokładnie tyle, że w <math>\displaystyle i</math>-tym równaniu wyjściowego układu przyjmujemy za współrzędne <math>\displaystyle x</math> wartości z poprzedniej iteracji i na tej podstawie wyznaczamy wartość <math>\displaystyle x_i</math>.
{{twierdzenie|O zbieżności metody Jacobiego|O zbieżności metody Jacobiego|


W metodzie Jacobiego warunek dostateczny zbieżności,  
W metodzie Jacobiego warunek dostateczny zbieżności,  
Linia 421: Linia 440:
</math></center>
</math></center>


Rzeczywiście, ponieważ wyraz <math>\displaystyle (i,j)</math> macierzy <math>\displaystyle D^{-1}Z</math>  
}}
 
{{dowod|||
Rzeczywiście, ponieważ wyraz <math>\displaystyle (i,j)</math> macierzy <math>\displaystyle M^{-1}Z</math>  
wynosi <math>\displaystyle 0</math> dla <math>\displaystyle i=j</math> oraz <math>\displaystyle a_{i,j}/a_{i,i}</math> dla <math>\displaystyle i\neq j</math>, a więc
wynosi <math>\displaystyle 0</math> dla <math>\displaystyle i=j</math> oraz <math>\displaystyle a_{i,j}/a_{i,i}</math> dla <math>\displaystyle i\neq j</math>, a więc


<center><math>\displaystyle \aligned \lefteqn{\|D^{-1}Z\|_\infty \;=\; \max_{1\le i\le N}
<center><math>\displaystyle \aligned \lefteqn{\|M^{-1}Z\|_\infty \;=\; \max_{1\le i\le N}
   \sum_{j=1,j\ne i}^N{|a_{i,j}|}/{|a_{i,i}|} } \\  
   \sum_{j=1,j\ne i}^N{|a_{i,j}|}/{|a_{i,i}|} } \\  
     && =\;\max_{1\le i\le N}
     && =\;\max_{1\le i\le N}
Linia 431: Linia 453:


przy czym ostatnia nierówność wynika z warunku diagonalnej dominacji.  
przy czym ostatnia nierówność wynika z warunku diagonalnej dominacji.  
}}


<div style="margin-top:1em; padding-top,padding-bottom:1em;">
<div style="margin-top:1em; padding-top,padding-bottom:1em;">
<span  style="font-variant:small-caps;">Przykład: Macierz laplasjanu</span>  
<span  style="font-variant:small-caps;">Przykład: Macierz laplasjanu</span>  
<div class="solution">
<div class="solution" style="margin-left,margin-right:3em;">


Macierz <math>\displaystyle N\times N</math>, zwana <strong>macierzą jednowymiarowego laplasjanu</strong>
Macierz <math>\displaystyle N\times N</math>, zwana <strong>macierzą jednowymiarowego laplasjanu</strong>
Linia 448: Linia 471:
pojawia się w bardzo wielu zastosowaniach, także jako podzadanie w algorytmach
pojawia się w bardzo wielu zastosowaniach, także jako podzadanie w algorytmach
numerycznych. Ta macierz jest macierzą taśmową, symetryczną i dodatnio
numerycznych. Ta macierz jest macierzą taśmową, symetryczną i dodatnio
określoną, więc rozwiązanie układu równań z tą macierzą metodami bezpośrednimi jest łatwe, kosztem <math>\displaystyle O(N)</math>. Ciekawe będzie, jak poradzą sobie z nią metody
określoną, więc układ równań z tą macierzą można bez trudu rozwiązać metodami
iteracyjne.
bezpośrednimi, kosztem <math>\displaystyle O(N)</math>. Stosując do niej metodę Jacobiego mamy <math>\displaystyle M = 2I</math> oraz <math>\displaystyle Z = L - M</math>. Obliczając
 
normę macierzy iteracji Jacobiego dostajemy <math>\displaystyle ||M^{-1}Z||_\infty
Na przykład, w metodzie Jacobiego weźmiemy <math>\displaystyle D = 2I</math> oraz <math>\displaystyle Z = L - D</math>. Obliczając
= 1</math>, co nie rozstrzyga jeszcze o jej zbieżności lub niezbieżności.
normę macierzy iteracji Jacobiego dostajemy <math>\displaystyle ||D^{-1}Z||_\infty
= 1</math>, co nie rozstrzyga jeszcze o jej (nie)zbieżności.


Okazuje się, że są gotowe wzory na wartości własne macierzy <math>\displaystyle L</math>:  
Potrzebna będzie bardziej subtelna analiza. Okazuje się, że są znane wzory na wartości własne macierzy <math>\displaystyle L</math>:  


<center><math>\displaystyle \lambda_j = 4\sin^2 \left(\frac{j \pi }{2(N+1)} \right),
<center><math>\displaystyle \lambda_j = 4\sin^2 \left(\frac{j \pi }{2(N+1)} \right),
</math></center>
</math></center>


dla <math>\displaystyle 1 \leq j \leq N.</math>
dla <math>\displaystyle 1 \leq j \leq N.</math> W konsekwencji, wartościami własnymi <math>\displaystyle M^{-1}Z = \frac{1}{2}Z = \frac{1}{2}L - I</math> są liczby <math>\displaystyle \mu_i = \frac{1}{2} \lambda_i - 1</math>. Ponieważ <math>\displaystyle 0 < \mu_i < 1</math>, znaczy to, że metoda Jacobiego jest zbieżna dla macierzy <math>\displaystyle L</math>.


i w konsekwencji, wartościami własnymi <math>\displaystyle D^{-1}Z = \frac{1}{2}Z = \frac{1}{2}L -
Z drugiej strony, nie dajmy się zwieść optymizmowi matematyka (''"nie martw się, jest zbieżny..."''): nietrudno sprawdzić, że <math>\displaystyle ||Z||_2 = 1 - O(N^{-2}) < 1</math>, co oznacza, że metoda Jacobiego --- choć zbieżna --- dla dużych <math>\displaystyle N</math> staje się
I</math> są liczby <math>\displaystyle \mu_i = \frac{1}{2} \lambda_i - 1</math>. Ponieważ <math>\displaystyle 0 < \mu_i < 1</math>, oraz <math>\displaystyle ||Z||_2 = 1 - O(N^{-2}) < 0</math>, to metoda, choć zbieżna, dla dużych <math>\displaystyle N</math> staje się
zbieżna tak wolno, że w praktyce bezużyteczna!
zbieżna tak wolno, że w praktyce bezużyteczna.
</div></div>
</div></div>


Zaletą stacjonarnych metod iteracyjnych jest również ich prostota,  
===Metoda Gaussa-Seidela===
przez co są one łatwe do zaprogramowania.  
 
<!--
Ciekawostką jest, że Gauss nie miał z nią nic wspólnego, a Seidel był podobno jej przeciwnikiem...
-->
Heurystyka tej metody opiera się na zmodyfikowaniu metody Jacobiego tak, by w każdym momencie iteracji korzystać z najbardziej "aktualnych" współrzędnych przybliżenia rozwiązania <math>\displaystyle x</math>.
 
Rzeczywiście, przecież rozwiązując równanie metody Jacobiego:
 
<center><math>\displaystyle x^{(k)}_i = \frac{1}{a_{ii}} \left( b_i - \sum_{j\neq i} a_{ij}x^{(k-1)}_j \right),
</math></center>
 
nietrudno zauważyć, że w części sumy moglibyśmy odwoływać się do "dokładniejszych" wartości <math>\displaystyle x^{(k)}_j</math>: dla <math>\displaystyle j < i</math>, tzn.
 
<center><math>\displaystyle x^{(k)}_i = \frac{1}{a_{ii}} \left( b_i - \sum_{j< i} a_{ij}x^{(k)}_j - \sum_{j>i} a_{ij}x^{(k-1)}_j \right).
</math></center>
 
W języku rozkładu macierzy <math>\displaystyle A = M - Z</math> i iteracji <math>\displaystyle x_{k+1} = M^{-1}(Zx_k + b)</math> mamy więc <math>\displaystyle M =  \mbox{tril} (A)</math> (dolny trójkąt macierzy <math>\displaystyle A</math>).
 
{{twierdzenie|O zbieżności metody Gaussa-Seidela|O zbieżności metody Gaussa-Seidela|
 
Jeśli macierz <math>\displaystyle A</math> jest diagonalnie dominująca, to metoda Gaussa--Seidela jest zbieżna dla dowolnego wektora startowego <math>\displaystyle x_0</math>.
}}
 
Inny wariant tej metody dostalibyśmy, biorąc za <math>\displaystyle M</math> górny trójkąt macierzy <math>\displaystyle A</math>.  


====Metoda Gaussa--Seidela====
Metoda Gaussa--Seidela jest w wielu przypadkach rzeczywiście szybciej zbieżna od metody Jacobiego, np. tak jest w przypadku macierzy jednowymiarowego Laplasjanu. Wciąż jednak, dodajmy, dla zadań bardzo źle uwarunkowanych jej zbieżność jest zbyt wolna by ją stosować jako samodzielną metodę.


Ciekawostką jest, że Gauss nie miał z nią nic wspólnego, a Seidel był wręcz jej
<div style="margin-top:1em; padding-top,padding-bottom:1em;">
przeciwnikiem...
<span  style="font-variant:small-caps;">Uwaga</span>
<div class="solution" style="margin-left,margin-right:3em;">


====Złożoność stacjonarnych metod iteracyjnych====
Obie metody, Jacobiego i (zwłaszcza) Gaussa--Seidela stosuje się także czasem w prostych algorytmach rozwiązywania <strong>układów równań nieliniowych</strong>: ich zaletą jest to, że głównym składnikiem iteracji jest rozwiązywanie [[MN02|<strong>skalarnego</strong> równania nieliniowego]] na każdym kroku metody.
</div></div>


Zastanówmy się teraz nad złożonością metod  
===Złożoność stacjonarnych metod iteracyjnych===
iteracyjnych. Ponieważ możemy jedynie znaleźć pewne  
 
przybliżenie rozwiązania dokładnego <math>\displaystyle  x^*</math>, przez  
Zastanówmy się teraz nad złożonością metod iteracyjnych. Ponieważ możemy jedynie znaleźć pewne przybliżenie rozwiązania dokładnego <math>\displaystyle  x^*</math>, przez złożoność metody będziemy rozumieli koszt kombinatoryczny obliczenia <math>\displaystyle  x_k</math> z zadaną dokładnością <math>\displaystyle \epsilon>0</math>. Dla uproszczenia założymy, że medoda jest zbieżna liniowo z ilorazem <math>\displaystyle \rho</math>. Zauważmy, że aby zredukować błąd początkowy do <math>\displaystyle \epsilon>0</math>, wystarczy wykonać <math>\displaystyle k=k(\epsilon)</math> iteracji, gdzie <math>\displaystyle k</math> spełnia  
złożoność metody będziemy rozumieli koszt  
kombinatoryczny obliczenia <math>\displaystyle  x_k</math> z zadaną  
dokładnością <math>\displaystyle \epsilon>0</math>. Dla uproszczenia założymy,  
że medoda jest zbieżna liniowo z ilorazem <math>\displaystyle \rho</math>.  
Zauważmy, że aby zredukować błąd początkowy do  
<math>\displaystyle \epsilon>0</math>, wystarczy wykonać <math>\displaystyle k=k(\epsilon)</math> iteracji, gdzie  
<math>\displaystyle k</math> spełnia  


<center><math>\displaystyle \rho^k\| x_0- x^*\|\,\le\,\epsilon,
<center><math>\displaystyle \rho^k\| x_0- x^*\|\,\le\,\epsilon,
Linia 493: Linia 532:
czyli  
czyli  


<center><math>\displaystyle k\,\ge\,\frac{\log(1/\epsilon)-
<center><math>\displaystyle k\,\ge\,\frac{\log(1/\epsilon) - \log(1/\| x_0- x^*\|)}{\log(1/\rho)}.
    \log(1/\| x_0- x^*\|)}{\log(1/\rho)}.
</math></center>
</math></center>


Liczba ta zależy więc w istotny sposób od błędu  
Liczba ta zależy więc w istotny sposób od błędu początkowego i (przede wszystkim) od współczynnika redukcji błędu <math>\displaystyle \rho</math>, natomiast zależność od dokładności <math>\displaystyle \epsilon</math> i wymiaru <math>\displaystyle N</math> układu jest dużo mniej istotna (w zadaniach praktycznych -- takich jak jednowymiarowy laplasjan --- jednak często  
początkowego i (przede wszystkim) od współczynnika redukcji błędu  
<math>\displaystyle \rho</math>, natomiast zależność od dokładności <math>\displaystyle \epsilon</math>  
i wymiaru <math>\displaystyle N</math> układu jest dużo mniej istotna (w zadaniach praktycznych -- takich jak jednowymiarowy laplasjan --- jednak
często  
okazuje się, że... <math>\displaystyle \rho</math> zależy od <math>\displaystyle N</math>!).  
okazuje się, że... <math>\displaystyle \rho</math> zależy od <math>\displaystyle N</math>!).  


Zakładając, że koszt jednej iteracji wynosi <math>\displaystyle c=c(N)</math>  
Zakładając, że koszt jednej iteracji wynosi <math>\displaystyle c=c(N)</math> (<math>\displaystyle c(N)</math> jest tym mniejszy, im mniejsza jest liczba niezerowych elementów macierzy <math>\displaystyle A</math>), złożoność metody jest proporcjonalna do  
(<math>\displaystyle c(N)</math> jest tym mniejszy, im mniejsza jest liczba  
niezerowych elementów macierzy <math>\displaystyle A</math>), złożoność  
metody jest proporcjonalna do  


<center><math>\displaystyle c(N)\,\frac{\log(1/\epsilon)}{\log(1/\rho)}.  
<center><math>\displaystyle c(N)\,\frac{\log(1/\epsilon)}{\log(1/\rho)}.  
</math></center>
</math></center>


Stąd oczywisty wniosek, że metody iteracyjne warto  
Stąd oczywisty wniosek (prawdziwy nie tylko dla metod stacjonarnych), że metody iteracyjne warto stosować zamiast metod bezpośrednich w przypadku, gdy  
stosować zamiast metod bezpośrednich w przypadku, gdy  
* wymiar <math>\displaystyle N</math> układu <math>\displaystyle A x= b</math> jest "duży", oraz  
* wymiar <math>\displaystyle N</math> układu <math>\displaystyle A x= b</math> jest "duży", oraz  
* macierz <math>\displaystyle A</math> układu jest "rozrzedzona", tzn. ma stosunkowo niewielką liczbę elementów  niezerowych, np. proporcjonalną do <math>\displaystyle N</math>.  
* macierz <math>\displaystyle A</math> układu jest "rozrzedzona", tzn. ma stosunkowo niewielką liczbę elementów  niezerowych, np. proporcjonalną do <math>\displaystyle N</math>.  
    
    
Układy o tych własnościach powstają często przy  
Układy o tych własnościach powstają często przy numerycznym rozwiązywaniu równań różniczkowych cząstkowych.  
numerycznym rozwiązywaniu równań różniczkowych  
cząstkowych.  


==Metody przestrzeni Kryłowa==
==Metody przestrzeni Kryłowa==


Zupełnie inny pomysł na realizację metody iteracyjnej przedstawiają metody przestrzeni
Zupełnie inny pomysł na realizację metody iteracyjnej przedstawiają metody przestrzeni Kryłowa, gdzie kolejne przybliżenie <math>\displaystyle x_k</math> dobiera się w taki sposób, by minimalizowało pewną miarę błędu na podprzestrzeni Kryłowa
Kryłowa, gdzie kolejne przybliżenie <math>\displaystyle x_k</math> dobiera się w taki sposób, by
minimalizowało pewną miarę błędu na podprzestrzeni Kryłowa


<center><math>\displaystyle K_k =  \mbox{span} \{r,A_r,\ldots, A^{k-1}r \},
<center><math>\displaystyle K_k =  \mbox{span} \{r,A_r,\ldots, A^{k-1}r \},
</math></center>
</math></center>


gdzie <math>\displaystyle r = b-Ax_0</math> jest residuum na początku iteracji. W zależności od wyboru
gdzie <math>\displaystyle r = b-Ax_0</math> jest ''residuum'' na początku iteracji. (Zwróć uwagę, że przestrzeń Kryłowa jest rozpięta przez kolejne wektory [[MN13#Metoda potęgowa|metody potęgowej]]] --- to nie przypadek!). W zależności od wyboru sposobu miary błędu, dostajemy inną metodę iteracyjną, takie jak CG, GMRES, PCR, BiCG, i inne. Tutaj omówimy pokrótce tylko najpopularniejszą: CG.
sposobu miary błędu, dostajemy inną metodę iteracyjną, takie jak CG, GMRES, PCR,
BiCG, i inne. Tutaj omówimy pokrótce tylko dwie najpopularniejsze: CG i GMRES.


====CG====
===CG===


Metoda <strong>gradientów sprzężonych</strong> ''conjugate gradients (CG) ''działa przy założeniu, że <math>\displaystyle A</math> jest <strong>symetryczna i dodatnio określona</strong>.
Metoda <strong>gradientów sprzężonych</strong>, w skrócie CG (''conjugate gradients''), działa przy założeniu, że <math>\displaystyle A</math> jest <strong>symetryczna i dodatnio określona</strong>.


Kolejne przybliżenie <math>\displaystyle x_k</math> ma minimalizować błąd w normie energetycznej
Kolejne przybliżenie <math>\displaystyle x_k</math> ma minimalizować błąd w normie energetycznej
Linia 546: Linia 570:
na przestrzeni afinicznej <math>\displaystyle x_0 + K_k</math>. Okazuje się (co ''nie jest'' oczywiste --- trzeba skorzystać z rozmaitych własności ortogonalności generowanych wektorów), że takie zadanie minimalizacji daje się bardzo efektywnie rozwiązać, skąd dostajemy bardzo zwarty algorytm:
na przestrzeni afinicznej <math>\displaystyle x_0 + K_k</math>. Okazuje się (co ''nie jest'' oczywiste --- trzeba skorzystać z rozmaitych własności ortogonalności generowanych wektorów), że takie zadanie minimalizacji daje się bardzo efektywnie rozwiązać, skąd dostajemy bardzo zwarty algorytm:


{{algorytm|||
{{algorytm|Metoda CG|Metoda CG|
<pre>
<pre>r = b-A*x;
r = b-A*x;
<math>\displaystyle \rho_0</math> = <math>\displaystyle ||r||_2^2</math>; <math>\displaystyle \beta</math> = 0; k = 1;
<math>\displaystyle \rho_{-1}</math> = 0; <math>\displaystyle \rho_0</math> = <math>\displaystyle ||r||_2^2</math>; <math>\displaystyle \beta</math> = 0; k = 1;
while (!stop)
while <math>\displaystyle \sim</math>STOP
{
{
p = r + <math>\displaystyle \beta</math>*p;
p = r + <math>\displaystyle \beta</math>*p;
w = A*p;
w = A*p;
<math>\displaystyle \alpha</math> = <math>\displaystyle \frac{\rho_{k-1}}{p^Tw}</math>;
<math>\displaystyle \alpha</math> = <math>\displaystyle \rho_{k-1}</math>/<math>\displaystyle p^Tw</math>;
x = x + <math>\displaystyle \alpha</math>*p;
x = x + <math>\displaystyle \alpha</math>*p;
r = r - <math>\displaystyle \alpha</math>*w;
r = r - <math>\displaystyle \alpha</math>*w;
Linia 565: Linia 588:
Jak widać, całą iterację da się wykonać przechowując w pamięci tylko kilka wektorów (a nie, jak możnaby się obawiać, całą przestrzeń <math>\displaystyle K_k</math>), a najdroższym jej elementem jest mnożenie macierzy przez wektor.
Jak widać, całą iterację da się wykonać przechowując w pamięci tylko kilka wektorów (a nie, jak możnaby się obawiać, całą przestrzeń <math>\displaystyle K_k</math>), a najdroższym jej elementem jest mnożenie macierzy przez wektor.


{{twierdzenie|Zbieżność CG jako metody bezpośredniej||
{{twierdzenie|O zbieżności CG jako metody bezpośredniej|O zbieżności CG jako metody bezpośredniej|


Niech <math>\displaystyle A\in R^{N\times N}</math> będzie symetryczna i dodatnio określona. Algorytm CG znajdzie dokładne rozwiązanie po co najwyżej <math>\displaystyle N</math> iteracjach.
Niech <math>\displaystyle A\in R^{N\times N}</math> będzie symetryczna i dodatnio określona. Algorytm CG znajdzie dokładne rozwiązanie po co najwyżej <math>\displaystyle N</math> iteracjach.
Linia 572: Linia 595:
Powyższe twierdzenie, choć teoretycznie interesujące, ma małą wartość praktyczną z dwóch powodów:
Powyższe twierdzenie, choć teoretycznie interesujące, ma małą wartość praktyczną z dwóch powodów:
* dla bardzo dużych <math>\displaystyle N</math>, wykonanie <math>\displaystyle N</math> iteracji może być wciąż zbyt kosztownym zadaniem;
* dla bardzo dużych <math>\displaystyle N</math>, wykonanie <math>\displaystyle N</math> iteracji może być wciąż zbyt kosztownym zadaniem;
* ponieważ w arytmetyce <math>\displaystyle fl_\nu</math> skończonej precyzji ortogonalność, z której korzysta się przy wyprowadzeniu algorytmu nie jest zachowana, i w konsekwencji, po wielu iteracjach, jakość <math>\displaystyle x_k</math> przestaje się poprawiać.
* ponieważ w arytmetyce skończonej precyzji ortogonalność --- z której w bardzo istotny sposób korzysta się przy wyprowadzeniu algorytmu --- pogarsza się z iteracji na iterację i w konsekwencji, po wielu iteracjach, jakość <math>\displaystyle x_k</math> przestaje się poprawiać.
   
   
Dlatego wygodniej potraktować CG jako metodę iteracyjną. Zachodzi bowiem
Dlatego wygodniej potraktować CG jako metodę iteracyjną. Zachodzi bowiem


{{twierdzenie|Zbieżność CG jako metody iteracyjnej||
{{twierdzenie|Zbieżność CG jako metody iteracyjnej|Zbieżność CG jako metody iteracyjnej|


Po <math>\displaystyle k</math> iteracjach metody CG,  
Po <math>\displaystyle k</math> iteracjach metody CG,  
Linia 586: Linia 609:
}}
}}


Metoda GMRES ''Generalized Minimum RESidual ''nie wymaga ani symetrii, ani dodatniej określoności macierzy, jest więc bardziej uniwersalna, choć też bardziej kosztowna od CG.
===GMRES===
 
Metoda GMRES (''Generalized Minimum RESidual'') nie wymaga ani symetrii, ani dodatniej określoności macierzy, jest więc bardziej uniwersalna, choć też bardziej kosztowna od CG. Jej szczegółowe omówienie, w tym --- oszacowania szybkości zbieżności --- wykracza niestety poza ramy niniejszego wykładu.


====Prekondycjoning====
===Ściskanie macierzy===


Zbieżność wszystkich poznanych metod iteracyjnych zależy od własności
Zbieżność wszystkich poznanych metod iteracyjnych zależy od własności
spektralnych macierzy układu. Często w zastosowaniach pojawiające się macierze
spektralnych macierzy układu. Pojawiające się w zastosowaniach macierze
mają niekorzystne własności spektralne (np. bardzo duży wskaźnik uwarunkowania),
często mają niekorzystne własności spektralne (np. bardzo duży wskaźnik uwarunkowania), przez co metody iteracyjne zbiegają na nich bardzo wolno.
przez co metody iteracyjne zbiegają na nich bardzo wolno.


Dlatego bardzo korzystne może być wstępne przetransformowanie układu
Dlatego bardzo korzystne może być wstępne przetransformowanie układu
Linia 603: Linia 627:


<center><math>\displaystyle MAx = Mb,
<center><math>\displaystyle MAx = Mb,
</math></center>,
</math></center>


gdzie macierz <math>\displaystyle MA</math> ma znacznie korzystniejsze własności z punktu widzenia
gdzie macierz <math>\displaystyle MA</math> ma znacznie korzystniejsze własności z punktu widzenia używanej metody iteracyjnej. W przypadku macierzy symetrycznych widzieliśmy, że kluczowe znaczenie dla zbieżności metody miał rozkład wartości własnych: jeśli wartości własne były bardzo rozrzucone po prostej, to uwarunkowanie było bardzo duże i w konsekwencji zbieżność powolna. Aby zbieżność była szybsza, kluczowe jest, by:
używanej metody
* wartości własne <math>\displaystyle MA</math> były upakowane w klastrach
iteracyjnej.
* najlepiej wszystkie w (małym) otoczeniu wartości 1
Taką operację nazywamy <strong>prekondycjoningiem</strong>, a macierz <math>\displaystyle M</math> --- macierzą
prekondycjonera.
Jeśli więc chcielibyśmy przekształcić macierz tak, by metoda iteracyjna dla <math>\displaystyle MA</math> zbiegała szybko, musimy w jakiś sposób "ścisnąć" spektrum macierzy <math>\displaystyle A</math> w okolice jedności. Taką operację nazywamy <strong>ściskaniem</strong> (''preconditioning''), a macierz <math>\displaystyle M</math> --- <strong>imadłem</strong>.


Aby całość miała sens, macierz prekondycjonera <math>\displaystyle M</math> powinna:
Aby całość miała sens, macierz ściskająca <math>\displaystyle M</math> powinna:
* być łatwa w konstrukcji,
* być łatwa w konstrukcji,
* być tania w mnożeniu przez wektor (głównym elementem każdej metody
* być tania w mnożeniu przez wektor (głównym elementem każdej metody iteracyjnej jest mnożenie macierzy przez wektor: <math>\displaystyle M\cdot (A \cdot x)</math>),
iteracyjnej jest mnożenie macierzy przez wektor: <math>\displaystyle M\cdot (A \cdot x)</math>),
* macierz <math>\displaystyle MA</math> powinna mieć znacznie korzystniejsze własności z punktu widzenia używanej metody iteracyjnej.
* macierz <math>\displaystyle MA</math> powinna mieć znacznie korzystniejsze własności z punktu widzenia
używanej metody
iteracyjnej.
   
   
Kilka ekstremalnych propozycji na macierz prekondycjonera to <math>\displaystyle M = I</math> (łatwa w
Kilka ekstremalnych propozycji na macierz imadła to <math>\displaystyle M = I</math> (łatwa w
konstrukcji i tania w mnożeniu, ale nic niestety nie polepsza) oraz
konstrukcji i tania w mnożeniu, ale niestety nic nie polepsza...) oraz
<math>\displaystyle M=A^{-1}</math> (rewelacyjnie poprawia zbieżność metody iteracyjnej, dając zbieżność
<math>\displaystyle M=A^{-1}</math> (rewelacyjnie poprawia zbieżność metody iteracyjnej, dając zbieżność
w jednej iteracji, ale bardzo droga w konstrukcji i mnożeniu). Widać więc, że
w jednej iteracji, ale bardzo droga w konstrukcji i mnożeniu). Widać więc, że
Linia 626: Linia 647:
macierzy odwrotnej.
macierzy odwrotnej.


Dlatego jednym z powszechniej stosowanych rodzajów prekondycjonerów są te oparte na
Dlatego jednym z powszechniej stosowanych (aczkolwiek wciąż nie najbardziej skutecznych) sposobów ściskania są te oparte na zastosowaniu jednego kroku klasycznej metody iteracyjnej.
zastosowaniu jednego kroku klasycznej metody iteracyjnej.


[[Image:MNpcgconv.png|thumb|450px|center|Zbieżność metody CG bez prekondycjonera oraz z prekondycjonerem
[[Image:MNpcgconv.png|thumb|550px|center|Zbieżność metody CG bez żadnego  ściskania oraz ściśniętej
opartym na jednej iteracji (blokowej) metody Jacobiego.]]
imadłem opartym na jednej iteracji (blokowej) metody Jacobiego.]]


Inne prekondycjonery stosują np. techniki tzw. niepełnego rozkładu macierzy,
Inne sposoby ściśnięcia macierzy wykorzystują np. techniki tzw. <strong>niepełnego
albo --- w specyficznych przypadkach --- tzw. metody wielosiatkowe.
rozkładu</strong> macierzy, albo --- w specyficznych przypadkach --- tzw.<strong> metody
wielosiatkowe</strong>.


Okazuje się, że zarówno CG jak i GMRES da się zaimplementować tak, by w jednej
Okazuje się, że zarówno CG jak i GMRES da się zaimplementować tak, by w jednej
iteracji było konieczne tylko jedno mnożenie przez macierz prekondycjonera.
iteracji było konieczne tylko jedno mnożenie przez macierz imadła.
 
==Literatura==
 
W celu dogłębnego zapoznania się z omawianym na wykładzie materiałem, przeczytaj <b>rozdział 4.6 i 4.7</b> w
* D. Kincaid, W. Cheney <cite>Analiza numeryczna</cite>, Wydawnictwa Naukowo-Techniczne, Warszawa 2006, ISBN 83-204-3078-X.
Tym razem wymienione rozdziały nie wystarczą do dogłębnego zrozumienia omawianych treści. Warto więc sięgnąć po jeden z podręczników
* <span style="font-variant:small-caps">C. T. Kelley</span>, <cite>Iterative Solution of Systems of Linear and Nonlinear Equations</cite>, SIAM, 1995,
* <span style="font-variant:small-caps">Y. Saad</span>, <cite>[http://www-users.cs.umn.edu/&nbsp;saad/books.html  Iterative Methods for Sparse Linear Systems]</cite>, PWS, 1996.

Wersja z 19:33, 29 wrz 2006


Wielkie układy równań liniowych

<<< Powrót do strony głównej przedmiotu Metody numeryczne

Wraz z coraz większymi modelami pojawiającymi się w praktyce obliczeniowej, coraz częściej zachodzi potrzeba rozwiązywania zadań algebry liniowej, w której macierze są co prawda wielkiego wymiaru, ale najczęściej rozrzedzone, to znaczy jest w nich bardzo dużo zer. Bardzo często zdarza się, że macierz wymiaru N ma tylko O(N) niezerowych elementów. Wykorzytanie tej specyficznej własności macierzy nie tylko prowadzi do algorytmów istotnie szybszych od ich analogów dla macierzy gęstych (to znaczy takich, które (w założeniu) mają N2 elementów), ale wręcz są jedynym sposobem na to, by niektóre zadania w ogóle stały się rozwiązywalne przy obecnym stanie techniki obliczeniowej!

Jednym ze szczególnie ważnych źródeł układów równań z macierzami rozrzedzonymi są np. równania różniczkowe cząstkowe (a więc np. modele pogody, naprężeń w konstrukcji samochodu, przenikania kosmetyków do głębszych warstw skóry, itp.).

Modele wielostanowych systemów kolejkowych (np. routera obsługującego wiele komputerów) także prowadzą do gigantycznych układów równań z macierzami rozrzedzonymi o specyficznej strukturze.

Z reguły zadania liniowe wielkiego wymiaru będą miały strukturę macierzy rozrzedzonej, gdyż najczęściej związki pomiędzy niewiadomymi w równaniu nie dotyczą wszystkich, tylko wybranej grupy.

Przykład: Macierz z kolekcji Boeinga

Spójrzmy na macierz sztywności dla modelu silnika lotniczego, wygenerowaną swego czasu w zakładach Boeinga i pochodzącą z dyskretyzacji pewnego równania różniczkowego cząstkowego. Pochodzi z kolekcji Tima Davisa. Jest to mała macierz, wymiaru 8032 (w kolekcji spotkasz równania z milionem i więcej niewiadomych).

Struktura niezerowych elementów macierzy bcsstk38.

Jej współczynnik wypełnienia (to znaczy, stosunek liczby niezerowych do wszystkich elementów macierzy) wynosi jedynie 0.006, a więc macierz jest bardzo rozrzedzona: w każdym wierszu są średnio tylko 44 niezerowe elementy.


Reprezentacja macierzy rzadkich

Zacznijmy od sposobu przechowywania macierzy rozrzedzonych. Naturalnie, nie ma sensu przechowywać wszystkich zerowych jej elementów: wystarczy ograniczyć się do zachowania tych niezerowych! W ten sposób zmniejszamy zarówno wymagania pamięciowe, jak i liczbę operacji zmiennoprzecinkowych potrzebnych do prowadzenia działań na macierzy (np. w przypadku mnożenia macierzy przez wektor, nie będziemy mnożyć przez zera!).

Format współrzędnych

Do zapamiętania macierzy A wymiaru N×M o NNZ niezerowych elementów wykorzystujemy trzy wektory: I, J --- oba typu int --- oraz V, typu double, wszystkie o długości NNZ, przy czym

AI[k],J[k]=V[k],k=0,,NNZ1.
Format AIJ

W tym formacie wprowadzane są macierze rzadkie do Octave'a i MATLABa:

A = sparse(I,J,V,N,N);

Jednak wewnętrznie przechowywane są w innym formacie, o którym poniżej.

Przykład

Pokażemy jak w Octave wprowadzić macierz rozrzedzoną.

octave:10> I = [1, 1, 1, 2, 3, 1, 4]; octave:11> J = [1, 3, 2, 2, 3, 4, 4]; octave:12> V = [1, 2, 3, 4, 5, 6, 7]; octave:13> N = 4; octave:14> A = sparse(I,J,V,N,N) A = Compressed Column Sparse (rows = 4, cols = 4, nnz = 7) (1, 1) -> 1 (1, 2) -> 3 (2, 2) -> 4 (1, 3) -> 2 (3, 3) -> 5 (1, 4) -> 6 (4, 4) -> 7 octave:15> spy(A);

Strukturę jej niezerowych elementów ukaże nam polecenie spy(A). Tak właśnie zostały wygenerowane obrazki macierzy w niniejszym wykładzie.

Format spakowanych kolumn (wierszy)

Format współrzędnych nie narzucał żadnego uporządkowania elementów macierzy --- można było je umieszczać w dowolnej kolejności. Narzucenie sensownego porządku mogłoby wspomóc realizację wybranych istotnych operacji na macierzy, na przykład, aby wygodnie było realizować działanie (prawostronnego) mnożenia macierzy przez wektor, dobrze byłoby przechowywać elementy macierzy wierszami. Tak właśnie jest zorganizowany format spakowanych wierszy (Compressed Sparse Row, CSR). Analogicznie jest zdefiniowany format spakowanych kolumn (Compressed Sparse Column, CSC), którym zajmiemy się bliżej.

Podobnie jak w przypadku formatu współrzędnych, macierz w formacie CSC jest przechowywana w postaci trzech wektorów: AV jest wektorem typu double o długości NNZ, zawierającym kolejne niezerowe elementy macierzy A wpisywane kolumnami, AI jest wektorem typu int o długości NNZ, zawierającym numery wierszy macierzy A odpowiadających elementom z AV. Natomiast zamiast tablicy J, jak to było w formacie współrzędnych, mamy krótszy wektor typu int, AP, o długości M, zawierający na j-tym miejscu indeks pozycji w AV, od którego rozpoczynają się w AV elementy j-tej kolumny macierzy A.

Format CSC

Mamy więc zależność, przy założeniu, że AP[0]=0,

AAI[AP[j]+k],j+1=AV[AP[j]+k],j=0,,M1,k=0,,AP[j+1]1.

Taki (z drobnymi modyfikacjami) format macierzy wykorzystują np. pakiety ARPACK i UMFPACK (a także, wewnętrznie, Octave i MATLAB).

Format diagonalny

Znacznie mniej uniwersalny niż poprzednie i dlatego rzadziej spotykany. Kolejne diagonale macierzy przechowujemy w kolejnych wierszach macierzy P×N, gdzie P jest liczbą niezerowych diagonal w ARN×N.

Szczególnie wygodny do reprezentacji macierzy taśmowych. Wykorzystywany m.in. przez funkcję LAPACKa DGBSV służącą rozwiązywaniu równań z macierzami taśmowymi.

Uwagi praktyczne

Mnożenie macierzy w formacie AIJ przez wektor jest kilka razy wolniejsze w porównaniu do macierzy w formacie CSC/CSR (z tych dwóch oczywiście (dlaczego?) CSR jest najszybszy). Co więcej, okazuje się, że w typowych implementacjach, mnożenie macierzy rozrzedzonej (reprezentowanej np. w formacie CSC) przez wektor jest mało efektywne, mniej więcej na poziomie dziesięciu procent możliwości obliczeniowych procesora.

Jeśli już poważnie myśleć o przyspieszeniu mnożenia macierzy przez wektor (np. gdy chcemy stosować iteracyjną metodę rozwiązywania układu równań z tą macierzą), warto rozważyć inne formaty --- łączące w sobie podział macierzy na bloki (tak, jak w algorytmach BLAS) i przechowywanie (w zasadzie) tylko niezerowych elementów macierzy.

Macierze specjalne

Zajmiemy się teraz zadaniem rozwiązywania układu równań liniowych

Ax=b,

ale w sytuacji, gdy macierz A jest rozrzedzona i dużego wymiaru. Dokonamy przeglądu kilku rodzajów algorytmów mających na celu wykorzystanie rozrzedzenia macierzy dla obniżenia kosztu wyznaczenia rozwiązania układu.

Należy pamiętać, że z reguły najlepsze wyniki uzyskuje się, gdy konkretny algorytm dobierze się do konkretnej macierzy. W zastosowaniach pojawiają się m.in. macierze rzadkie o bardzo szczególnej strukturze, dla nich warto stosować wyspecjalizowane algorytmy.

Macierze taśmowe

Macierz A taka, że dla |ij|d, aij=0, nazywamy macierzą taśmową z rozstępem d, o szerokości pasma 2d+1.

Łatwo sprawdzić, że algorytm eliminacji Gaussa (bez wyboru elementu głównego) nie spowoduje dodatkowego wypełnienia w takiej macierzy (a więc da się wykonać w miejscu). W przypadku konieczności wyboru elementu głównego, pesymistyczne oszacowanie rozstępu macierzy rozkładu LU jest równe max{2d,N} --- tak więc, dla niezbyt dużych d wciąż wynikowa macierz jest taśmowa.

W szczególności, gdy macierz jest taśmowa z pasmem o rozstępie d i jednocześnie diagonalnie dominująca, wtedy rozkład LU takiej macierzy da się wykonać w miejscu kosztem O(dN), czyli liniowym.

W LAPACKu zaimplementowano szybki solver równań z macierzami taśmowymi, DGBSV, ale wymagający specjalnego sposobu przechowywania macierzy, wykorzystującego format diagonalny.

Macierze trójdiagonalne

Szczególnym przypadkiem macierzy taśmowych są macierze trójdiagonalne, tzn. taśmowe o rozstępie d=1:

A=(a1c1b2a2c2b3a3cN1bNaN)

Zadanie rozwiązywania równań z taką macierzą

Ax=e

jest bardzo często spotykane, więc warto przytoczyć algorytm w całej okazałości --- popularnie zwany algorytmem przeganiania (niektóre źródła nazywają go algorytmem Thomasa).

Zacznijmy jednak od stwierdzenia, kiedy macierz trójdiagonalna nie wymaga wyboru elementu głównego:

Stwierdzenie

Jeśli macierz A ma słabo dominującą diagonalę, tzn.

|ai||bi|+|ci|,1iN,

(b1=0=cN) i przynajmniej dla jednego indeksu "i" mamy powyżej ostrą nierówność ">", to algorytm przeganiania jest wykonalny bez przestawień wierszy. Ponadto wymaga on 7N operacji arytmetycznych, a więc jest prawie optymalny.

Algorytm Metoda przeganiania


<math>\displaystyle d_1</math> = <math>\displaystyle a_1</math>; 
<math>\displaystyle f_1</math> = <math>\displaystyle e_1</math>;
for (i = 2; i <= N; i++)
{
	<math>\displaystyle l</math> = <math>\displaystyle b_i</math>/<math>\displaystyle a_{i-1}</math>;
	<math>\displaystyle d_i</math> = <math>\displaystyle a_i</math> - <math>\displaystyle l</math> * <math>\displaystyle c_{i-1}</math>;
	<math>\displaystyle f_i</math> = <math>\displaystyle e_i</math> - <math>\displaystyle l</math> * <math>\displaystyle f_{i-1}</math>;
} 
<math>\displaystyle x_1</math> = <math>\displaystyle f_N</math>;
for (i = N-1; i >= 1; i--)
	<math>\displaystyle x_i</math> = <math>\displaystyle f_i</math> - <math>\displaystyle c_i</math> * <math>\displaystyle x_{i+1}</math>;

Metody bezpośrednie

Przykład: Strzałka Wilkinsona

Rozważmy układ równań z macierzą diagonalnie dominującą postaci

A=(**********)

gdzie * oznacza jakiś niezerowy element. Łatwo sprawdzić, że chociaż wyjściowa macierz jest rozrzedzona, to zastosowanie do niej eliminacji Gaussa powoduje, że w wyniku dostajemy gęste czynniki rozkładu.

Tymczasem wystarczy odwrócić kolejność równań i numerację niewiadomych (co dla macierzy jest równoznaczne z odwróceniem porządku wierszy i kolumn, korzystając z pewnej (jakiej?) macierzy permutacji P):

A~=PAPT=(**********)

Wtedy okazuje się, że rozkład naszej macierzy nie powoduje już wypełnienia czynników rozkładu!

Właśnie na tym polega główny problem w rozwiązywaniu układów z macierzami rzadkimi metodami bezpośrednimi: jak maksymalnie wykorzystać rozrzedzenie macierzy tak, by czynniki rozkładu były możliwie mało wypełnione. Albowiem wiedząc to będziemy mogli ograniczyć się jedynie do fizycznego wyznaczenia wartości niezerowych elementów macierzy rozkładu. Ponadto wymagania pamięciowe algorytmu nie będą istotnie wykraczać ponad ilość pamięci potrzebnej na przechowanie danych (tzn. macierzy).

W ogólnym przypadku rozwiązanie takiego zadania jest trudne i większość algorytmów opiera się na pewnych heurystykach, które jednak w praktyce warto wspomóc wcześniejszą analizą konkretnego układu równań jaki mamy rozwiązać. Najczęściej dąży się do takiego przenumerowania równań i niewiadomych, by w efekcie z góry przewidzieć, gdzie wystąpią zera w macierzach rozkładu --- i, by takich zer było jak najwięcej (by wypełnienie było jak najmniejsze)! Na architekturach z pamięcią hierarchiczną dąży się także do tego, by w trakcie rozkładu można było korzystać z BLAS Level 3, a więc permutacje wierszy i kolumn macierzy muszą to także brać pod uwagę.

Stosuje się kilka strategii wyznaczania korzystnych permutacji (reorderingu), z których warto wymienić

  • przybliżone algorytmy minimalnego stopnia (approximate minimum degree, AMD), np. AMD;
  • techniki podziału grafów na (prawie) rozłączne składowe nested dissection, ND, np. METIS.

Używają ich biblioteki takie jak UMFPACK, czy HSL.

W Octave mamy do dyspozycji także kilka procedur generujących takie permutacje, w tym: colamd (AMD dla macierzy niesymetrycznych) oraz symamd (AMD dla macierzy symetrycznych). Większy wybór oferuje MATLAB, jednak należy bezwzględnie pamiętać o jednym: nie ma uniwersalnej metody reorderingu i dla konkretnej macierzy może istnieć specjalna metoda, która da oszałamiające rezultaty, podczas gdy standardowe podejścia nie dadzą efektu.

Przykład: Rozwiązywanie układu z macierzą rozrzedzoną w Octave

Najprostszy sposób na wykorzystanie metody bezpośredniego rozwiązywania układu z macierzą rzadką to zastosowanie znanego nam operatora do macierzy typu rozrzedzonego:

A = sparse(...);
x = A \ b;

Octave domyślnie przyłoży do A reordering colamd i następnie skorzysta z biblioteki UMFPACK, by rozwiązać taki układ. Dodatkowo, badane jest wcześniej, czy macierz nie jest przypadkiem taśmowa o wąskiej wstędze: jeśli jest, to korzysta się z LAPACKa.

(Jak widzisz, operator rozwiązywania układu równań jest mocno przeciążony: działa i na macierzach kwadratowych, i na prostokątnych, i na rozrzedzonych --- na każdym rodzaju w inny sposób. Nie dziwi Cię chyba, dlaczego wygodnie było napisać Octave w C++?)

Przykład: Wypełnienie pewnej macierzy w zależności od użytego reorderingu

Rozważmy ponownie macierz pochodzącą z kolekcji Tima Davisa. Jest to macierz symetryczna, dodatnio określona, wymiaru 8032, o 355460 elementach niezerowych i, w konsekwencji, o wypełnieniu około 0.6 procent.

Struktura niezerowych elementów macierzy.

Zobaczymy, jak w zależności od użytego algorytmu permutacji kolumn i wierszy poradzi sobie algorytm rozkładu Cholesky'ego.

Czynnik rozkładu Cholesky'ego L wykonanego standardowym algorytmem. Czas rozkładu: 0.892013
Czynnik rozkładu Cholesky'ego L z reorderingiem COLAMD. Czas rozkładu: 0.813038
Czynnik rozkładu Cholesky'ego L z reorderingiem SYMAMD. Czas rozkładu: 0.487683s. Prawie dwa razy szybciej niż bez reorderingu, chociaż i tak wskutek wzrostu wypełnienia macierzy w dolnym trójkącie mamy aż 2 procent niezerowych elementów.
Czynnik rozkładu Cholesky'ego L z odwrotnym reorderingiem Cuthill-McKee. Czas rozkładu: 0.845928
Czynnik rozkładu Cholesky'ego L z jeszcze innym (bardzo tanim, ale jak widać czasem zupełnie złym) reorderingiem. Czas rozkładu: 5.947936

Na zakończenie popatrzmy, jak ważne jest spostrzeżenie symetrii macierzy:

Rozkład LU, czynnik L (bez reorderingu). Czas rozkładu LU: 1.696018s. Nieakceptowalny, podobnie jak drastyczne wypełnienie macierzy.
Rozkład LU, czynnik U (bez reorderingu)

Jak widać, w naszym przypadku standardowe algorytmy (COLAMD i SYMAMD) poradziły sobie całkiem nieźle, chociaż wypełnienie i tak znacząco wzrosło. Zapewne, dla tej macierzy, która jest specyficznego typu --- pochodzi z dyskretyzacji równania różniczkowego --- algorytm ND mógłby tu jeszcze lepiej zadziałać.

Stacjonarne metody iteracyjne

Gdy macierz jest rozrzedzona, mnożenie takiej macierzy przez wektor jest bardzo tanie (koszt jest proporcjonalny do liczby niezerowych elementów macierzy). Dlatego, jeśli możemy zadowolić się rozwiązaniem przybliżonym układu, a w zamian osiągnąć je tanim kosztem, warto rozważyć metody iteracyjne.

Najprostsze metody iteracyjne (najprostsze w analizie i implementacji, ale --- jak można się domyślić --- w praktyce najmniej efektywne) polegają na rozkładzie macierzy na część "łatwo odwracalną", M, i "resztę", Z. Dokładniej, jeśli M jest nieosobliwa, to równanie Ax=b można zapisać jako zadanie punktu stałego

Mx=Nx+b,

gdzie Z=MA. Inaczej:

x=M1(Zx+b),

i zastosować doń metodę iteracji prostej Banacha:

xk+1=M1(Zxk+b).

Takie metody nazywamy stacjonarnymi metodami iteracyjnymi. Aby przeanalizować zbieżność takiej metody, warto rozpatrzyć przypadek ogólniejszy

xk=Bxk1+c,

dla pewnej macierzy B oraz wektora c. (Dla stacjonarnej metody iteracyjnej, B=M1Z oraz c=M1b.)

W tym przypadku

xkx*=Bk(x0x*),

a stąd i z nierówności BkBk, mamy

xkx*Bkx0x*.

Warunkiem dostatecznym zbieżności iteracji prostych jest więc B<1. Okazuje się, że warunkiem koniecznym i dostatecznym zbieżności tej iteracji dla dowolnego wektora startowego x0 jest

ρ=max{|λ|:λ jest wartością własną B}<1.

Tak więc, metody oparte na iteracji prostej będą zbieżne liniowo z ilorazem ρ.

Zaletą stacjonarnych metod iteracyjnych jest również ich prostota, przez co są one łatwe do zaprogramowania, co łatwo zobaczyć na przykładach metod: Jacobiego i Gaussa--Seidela, które teraz omówimy.

Metoda Jacobiego

Biorąc M=diag(A), gdzie diag(A) jest macierzą diagonalną składającą się z wyrazów stojących na głównej przekątnej macierzy A, układ Ax=b jest równoważny układowi

Mx=Zx+b,

a stąd (o ile na przekątnej macierzy A nie mamy zera) otrzymujemy metodę iteracyjną

xk=Bxk1+c,

gdzie B=M1Z i c=M1b, zwaną metodą Jacobiego.

Rozpisując ją po współrzędnych dostajemy (numer iteracji wyjątkowo zaznaczamy w postaci górnego indeksu) układ rozszczepionych równań:

xi(k)=1aii(bijiaijxj(k1)),

co znaczy dokładnie tyle, że w i-tym równaniu wyjściowego układu przyjmujemy za współrzędne x wartości z poprzedniej iteracji i na tej podstawie wyznaczamy wartość xi.

Twierdzenie O zbieżności metody Jacobiego

W metodzie Jacobiego warunek dostateczny zbieżności, B<1, jest spełniony np. wtedy, gdy macierz A ma dominującą przekątną, tzn. gdy

|ai,i|>ji|ai,j|,i=1,,N.

Dowód

Rzeczywiście, ponieważ wyraz (i,j) macierzy M1Z wynosi 0 dla i=j oraz ai,j/ai,i dla ij, a więc

Parser nie mógł rozpoznać (nieznana funkcja „\aligned”): {\displaystyle \displaystyle \aligned \lefteqn{\|M^{-1}Z\|_\infty \;=\; \max_{1\le i\le N} \sum_{j=1,j\ne i}^N{|a_{i,j}|}/{|a_{i,i}|} } \\ && =\;\max_{1\le i\le N} \sum_{j=1}^N{|a_{i,j}|}/{|a_{i,i}|}\,-\,1\;<\;1, \endaligned}

przy czym ostatnia nierówność wynika z warunku diagonalnej dominacji.

Przykład: Macierz laplasjanu

Macierz N×N, zwana macierzą jednowymiarowego laplasjanu

L=(2112112)

pojawia się w bardzo wielu zastosowaniach, także jako podzadanie w algorytmach numerycznych. Ta macierz jest macierzą taśmową, symetryczną i dodatnio określoną, więc układ równań z tą macierzą można bez trudu rozwiązać metodami bezpośrednimi, kosztem O(N). Stosując do niej metodę Jacobiego mamy M=2I oraz Z=LM. Obliczając normę macierzy iteracji Jacobiego dostajemy ||M1Z||=1, co nie rozstrzyga jeszcze o jej zbieżności lub niezbieżności.

Potrzebna będzie bardziej subtelna analiza. Okazuje się, że są znane wzory na wartości własne macierzy L:

λj=4sin2(jπ2(N+1)),

dla 1jN. W konsekwencji, wartościami własnymi M1Z=12Z=12LI są liczby μi=12λi1. Ponieważ 0<μi<1, znaczy to, że metoda Jacobiego jest zbieżna dla macierzy L.

Z drugiej strony, nie dajmy się zwieść optymizmowi matematyka ("nie martw się, jest zbieżny..."): nietrudno sprawdzić, że ||Z||2=1O(N2)<1, co oznacza, że metoda Jacobiego --- choć zbieżna --- dla dużych N staje się zbieżna tak wolno, że w praktyce bezużyteczna!

Metoda Gaussa-Seidela

Heurystyka tej metody opiera się na zmodyfikowaniu metody Jacobiego tak, by w każdym momencie iteracji korzystać z najbardziej "aktualnych" współrzędnych przybliżenia rozwiązania x.

Rzeczywiście, przecież rozwiązując równanie metody Jacobiego:

xi(k)=1aii(bijiaijxj(k1)),

nietrudno zauważyć, że w części sumy moglibyśmy odwoływać się do "dokładniejszych" wartości xj(k): dla j<i, tzn.

xi(k)=1aii(bij<iaijxj(k)j>iaijxj(k1)).

W języku rozkładu macierzy A=MZ i iteracji xk+1=M1(Zxk+b) mamy więc M=tril(A) (dolny trójkąt macierzy A).

Twierdzenie O zbieżności metody Gaussa-Seidela

Jeśli macierz A jest diagonalnie dominująca, to metoda Gaussa--Seidela jest zbieżna dla dowolnego wektora startowego x0.

Inny wariant tej metody dostalibyśmy, biorąc za M górny trójkąt macierzy A.

Metoda Gaussa--Seidela jest w wielu przypadkach rzeczywiście szybciej zbieżna od metody Jacobiego, np. tak jest w przypadku macierzy jednowymiarowego Laplasjanu. Wciąż jednak, dodajmy, dla zadań bardzo źle uwarunkowanych jej zbieżność jest zbyt wolna by ją stosować jako samodzielną metodę.

Uwaga

Obie metody, Jacobiego i (zwłaszcza) Gaussa--Seidela stosuje się także czasem w prostych algorytmach rozwiązywania układów równań nieliniowych: ich zaletą jest to, że głównym składnikiem iteracji jest rozwiązywanie skalarnego równania nieliniowego na każdym kroku metody.

Złożoność stacjonarnych metod iteracyjnych

Zastanówmy się teraz nad złożonością metod iteracyjnych. Ponieważ możemy jedynie znaleźć pewne przybliżenie rozwiązania dokładnego x*, przez złożoność metody będziemy rozumieli koszt kombinatoryczny obliczenia xk z zadaną dokładnością ϵ>0. Dla uproszczenia założymy, że medoda jest zbieżna liniowo z ilorazem ρ. Zauważmy, że aby zredukować błąd początkowy do ϵ>0, wystarczy wykonać k=k(ϵ) iteracji, gdzie k spełnia

ρkx0x*ϵ,

czyli

klog(1/ϵ)log(1/x0x*)log(1/ρ).

Liczba ta zależy więc w istotny sposób od błędu początkowego i (przede wszystkim) od współczynnika redukcji błędu ρ, natomiast zależność od dokładności ϵ i wymiaru N układu jest dużo mniej istotna (w zadaniach praktycznych -- takich jak jednowymiarowy laplasjan --- jednak często okazuje się, że... ρ zależy od N!).

Zakładając, że koszt jednej iteracji wynosi c=c(N) (c(N) jest tym mniejszy, im mniejsza jest liczba niezerowych elementów macierzy A), złożoność metody jest proporcjonalna do

c(N)log(1/ϵ)log(1/ρ).

Stąd oczywisty wniosek (prawdziwy nie tylko dla metod stacjonarnych), że metody iteracyjne warto stosować zamiast metod bezpośrednich w przypadku, gdy

  • wymiar N układu Ax=b jest "duży", oraz
  • macierz A układu jest "rozrzedzona", tzn. ma stosunkowo niewielką liczbę elementów niezerowych, np. proporcjonalną do N.

Układy o tych własnościach powstają często przy numerycznym rozwiązywaniu równań różniczkowych cząstkowych.

Metody przestrzeni Kryłowa

Zupełnie inny pomysł na realizację metody iteracyjnej przedstawiają metody przestrzeni Kryłowa, gdzie kolejne przybliżenie xk dobiera się w taki sposób, by minimalizowało pewną miarę błędu na podprzestrzeni Kryłowa

Kk=span{r,Ar,,Ak1r},

gdzie r=bAx0 jest residuum na początku iteracji. (Zwróć uwagę, że przestrzeń Kryłowa jest rozpięta przez kolejne wektory metody potęgowej] --- to nie przypadek!). W zależności od wyboru sposobu miary błędu, dostajemy inną metodę iteracyjną, takie jak CG, GMRES, PCR, BiCG, i inne. Tutaj omówimy pokrótce tylko najpopularniejszą: CG.

CG

Metoda gradientów sprzężonych, w skrócie CG (conjugate gradients), działa przy założeniu, że A jest symetryczna i dodatnio określona.

Kolejne przybliżenie xk ma minimalizować błąd w normie energetycznej indukowanej przez A,

||xkx||A=(xkx)TA(xkx)

na przestrzeni afinicznej x0+Kk. Okazuje się (co nie jest oczywiste --- trzeba skorzystać z rozmaitych własności ortogonalności generowanych wektorów), że takie zadanie minimalizacji daje się bardzo efektywnie rozwiązać, skąd dostajemy bardzo zwarty algorytm:

Algorytm Metoda CG


r = b-A*x;
<math>\displaystyle \rho_0</math> = <math>\displaystyle ||r||_2^2</math>; <math>\displaystyle \beta</math> = 0; k = 1;
while (!stop)
{
	p = r + <math>\displaystyle \beta</math>*p;
	w = A*p;
	<math>\displaystyle \alpha</math> = <math>\displaystyle \rho_{k-1}</math>/<math>\displaystyle p^Tw</math>;
	x = x + <math>\displaystyle \alpha</math>*p;
	r = r - <math>\displaystyle \alpha</math>*w;
	<math>\displaystyle \rho_k</math> = <math>\displaystyle ||r||_2^2</math>;
	<math>\displaystyle \beta</math> = <math>\displaystyle \frac{\rho_{k}}{\rho_{k-1}}</math>;
	k++;	
}

Jak widać, całą iterację da się wykonać przechowując w pamięci tylko kilka wektorów (a nie, jak możnaby się obawiać, całą przestrzeń Kk), a najdroższym jej elementem jest mnożenie macierzy przez wektor.

Twierdzenie O zbieżności CG jako metody bezpośredniej

Niech ARN×N będzie symetryczna i dodatnio określona. Algorytm CG znajdzie dokładne rozwiązanie po co najwyżej N iteracjach.

Powyższe twierdzenie, choć teoretycznie interesujące, ma małą wartość praktyczną z dwóch powodów:

  • dla bardzo dużych N, wykonanie N iteracji może być wciąż zbyt kosztownym zadaniem;
  • ponieważ w arytmetyce skończonej precyzji ortogonalność --- z której w bardzo istotny sposób korzysta się przy wyprowadzeniu algorytmu --- pogarsza się z iteracji na iterację i w konsekwencji, po wielu iteracjach, jakość xk przestaje się poprawiać.

Dlatego wygodniej potraktować CG jako metodę iteracyjną. Zachodzi bowiem

Twierdzenie Zbieżność CG jako metody iteracyjnej

Po k iteracjach metody CG,

||xkx||A2(cond(A)1cond(A)+1)k||x0x||A,

gdzie cond(A)=||A||2||A1||2.

GMRES

Metoda GMRES (Generalized Minimum RESidual) nie wymaga ani symetrii, ani dodatniej określoności macierzy, jest więc bardziej uniwersalna, choć też bardziej kosztowna od CG. Jej szczegółowe omówienie, w tym --- oszacowania szybkości zbieżności --- wykracza niestety poza ramy niniejszego wykładu.

Ściskanie macierzy

Zbieżność wszystkich poznanych metod iteracyjnych zależy od własności spektralnych macierzy układu. Pojawiające się w zastosowaniach macierze często mają niekorzystne własności spektralne (np. bardzo duży wskaźnik uwarunkowania), przez co metody iteracyjne zbiegają na nich bardzo wolno.

Dlatego bardzo korzystne może być wstępne przetransformowanie układu

Ax=b

z macierzą o niekorzystnych własnościach, do układu

MAx=Mb,

gdzie macierz MA ma znacznie korzystniejsze własności z punktu widzenia używanej metody iteracyjnej. W przypadku macierzy symetrycznych widzieliśmy, że kluczowe znaczenie dla zbieżności metody miał rozkład wartości własnych: jeśli wartości własne były bardzo rozrzucone po prostej, to uwarunkowanie było bardzo duże i w konsekwencji zbieżność powolna. Aby zbieżność była szybsza, kluczowe jest, by:

  • wartości własne MA były upakowane w klastrach
  • najlepiej wszystkie w (małym) otoczeniu wartości 1

Jeśli więc chcielibyśmy przekształcić macierz tak, by metoda iteracyjna dla MA zbiegała szybko, musimy w jakiś sposób "ścisnąć" spektrum macierzy A w okolice jedności. Taką operację nazywamy ściskaniem (preconditioning), a macierz M --- imadłem.

Aby całość miała sens, macierz ściskająca M powinna:

  • być łatwa w konstrukcji,
  • być tania w mnożeniu przez wektor (głównym elementem każdej metody iteracyjnej jest mnożenie macierzy przez wektor: M(Ax)),
  • macierz MA powinna mieć znacznie korzystniejsze własności z punktu widzenia używanej metody iteracyjnej.

Kilka ekstremalnych propozycji na macierz imadła to M=I (łatwa w konstrukcji i tania w mnożeniu, ale niestety nic nie polepsza...) oraz M=A1 (rewelacyjnie poprawia zbieżność metody iteracyjnej, dając zbieżność w jednej iteracji, ale bardzo droga w konstrukcji i mnożeniu). Widać więc, że należy poszukiwać czegoś pośredniego, co niskim kosztem przybliża działanie macierzy odwrotnej.

Dlatego jednym z powszechniej stosowanych (aczkolwiek wciąż nie najbardziej skutecznych) sposobów ściskania są te oparte na zastosowaniu jednego kroku klasycznej metody iteracyjnej.

Zbieżność metody CG bez żadnego ściskania oraz ściśniętej imadłem opartym na jednej iteracji (blokowej) metody Jacobiego.

Inne sposoby ściśnięcia macierzy wykorzystują np. techniki tzw. niepełnego rozkładu macierzy, albo --- w specyficznych przypadkach --- tzw. metody wielosiatkowe.

Okazuje się, że zarówno CG jak i GMRES da się zaimplementować tak, by w jednej iteracji było konieczne tylko jedno mnożenie przez macierz imadła.

Literatura

W celu dogłębnego zapoznania się z omawianym na wykładzie materiałem, przeczytaj rozdział 4.6 i 4.7 w

  • D. Kincaid, W. Cheney Analiza numeryczna, Wydawnictwa Naukowo-Techniczne, Warszawa 2006, ISBN 83-204-3078-X.

Tym razem wymienione rozdziały nie wystarczą do dogłębnego zrozumienia omawianych treści. Warto więc sięgnąć po jeden z podręczników