MN08: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Przykry (dyskusja | edycje)
mNie podano opisu zmian
Przykry (dyskusja | edycje)
mNie podano opisu zmian
Linia 1: Linia 1:


==Szybka transformacja Fouriera (FFT)==
=Wielkie układy równań liniowych=


Algorytm FFT dla dyskretnej transformacji Fouriera (DFT) i jego krewniacy dla
Wraz z coraz większymi modelami pojawiającymi się w praktyce obliczeniowej,
wyznaczania dyskretnej transformacji cosinusów (DCT i MDCT), choć dotyczą
coraz częściej zachodzi potrzeba rozwiązywania zadań algebry liniowej, w której
pozornie dość abstrakcyjnych zadań, zrewolucjonizowały wiele dziedzin życia.
macierze są co prawda wielkiego wymiaru, ale najczęściej <strong>rozrzedzone</strong>, to
Między innymi, wykorzystuje się je w
znaczy jest w nich bardzo dużo zer. Bardzo często zdarza się, że macierz
* kompresji obrazów w formacie JPEG (DCT)
wymiaru <math>\displaystyle N</math> ma tylko <math>\displaystyle O(N)</math> niezerowych elementów. Wykorzytanie tej specyficznej
* kompresji dźwięku w formacie MP3 i pokrewnych (MDCT)
własności macierzy nie tylko prowadzi do algorytmów istotnie szybszych od ich
* rozwiązywaniu ważnych równań różniczkowych cząstkowych (DFT)
analogów dla macierzy gęstych (to znaczy takich, które (w założeniu) mają <math>\displaystyle N^2</math>
elementów), ale wręcz są jedynym sposobem na to, by niektóre zadania w ogóle
a także do  
stały się rozwiązywalne przy obecnym stanie techniki obliczeniowej!
* fitrowania szumów (DFT)
* szybkiego mnożenia wielomianów (DFT)
W niniejszym wykładzie ograniczymy się do przedstawienia szybkiego algorytmu
rozwiązywania zadania DFT, algorytmy rozwiązywania zadań pokrewnych (DCT, MDCT,
itp.) opierają się na podobnych zasadach.


Zacznijmy od postawienia zadania obliczeniowego DFT. Jest ono (pozornie!)
Jednym ze szczególnie ważnych źródeł układów równań z macierzami rozrzedzonymi
jednocześnie banalne i wydumane:
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.).


Dla danego zestawu <math>\displaystyle N</math> liczb <math>\displaystyle f_\alpha\in C</math>, <math>\displaystyle \alpha = 0,\ldots, N-1</math>,
<div style="margin-top:1em; padding-top,padding-bottom:1em;">
wyznaczyć  <math>\displaystyle N</math> wartości
<span  style="font-variant:small-caps;">Przykład: Macierz z kolekcji Boeinga</span>  
<div class="solution">


<center><math>\displaystyle c_j = \sum_{\alpha = 0}^{N-1} f_\alpha \omega_N^{j\alpha},
Macierz sztywności dla modelu silnika lotniczego, wygenerowana swego czasu w
</math></center>
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).


dla <math>\displaystyle j=0,\ldots, N-1</math>, przy czym <math>\displaystyle \omega_N = \exp(-i\frac{2\Pi}{N})</math>. Jak
[[Image:MNsparseA.png|thumb|450px|center|Struktura niezerowych elementów macierzy bcsstk38.]]
pamiętamy, jednostka urojona <math>\displaystyle i</math> spełnia <math>\displaystyle i = \sqrt{-1}</math>. Taką operację nazywamy
''dyskretną transformacją Fouriera'', DFT.


Ponieważ dane <math>\displaystyle f</math> są wektorem <math>\displaystyle f = [f_0,\ldots,f_{N-1}]^T</math>, wynik <math>\displaystyle c</math> też jest wektorem, a zadanie jest liniowe,
</div></div>
możemy wszystko zapisać macierzowo:


<center><math>\displaystyle c = F_N f,
Modele wielostanowych systemów kolejkowych (np. routera obsługującego wiele komputerów) także
</math></center>
prowadzą do gigantycznych układów równań z macierzami rozrzedzonymi o
specyficznej strukturze.


gdzie
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.


<center><math>\displaystyle
<div style="margin-top:1em; padding-top,padding-bottom:1em;">
F_N = (\omega_N^{j\alpha})_{j,\alpha = 0,\ldots, N-1} =
<span  style="font-variant:small-caps;">Przykład: Macierz MBEACXC</span>  
\begin{pmatrix}
<div class="solution">
1 & 1 & 1 & \cdots & 1\\
1 & \omega_N & \omega_N^2 & \cdots & \omega_N^{N-1} \\
1 & \omega_N^2 & \omega_N^4 & \cdots & \omega_N^{2(N-1)} \\
  &            &            & \cdots & \\
1 & \omega_N^{N-1} & \omega_N^{2(N_1)} & \cdots & \omega_N^{(N-1)^2}
\end{pmatrix} .
</math></center>


Tak więc, gdyby naiwnie podejść do zadania, moglibyśmy je rozwiązać brutalnie,
Dane pochodzą z serwisu
tworząc na początek macierz <math>\displaystyle F_N</math>, a następnie wyznaczając iloczyn macierzy
[http://math.nist.gov/MatrixMarket  MatrixMarket]. Jest to niezbyt duża macierz, wymiaru
przez wektor, co łatwo zrobić kosztem <math>\displaystyle O(N^2)</math> operacji. Dlatego istotne jest,
<math>\displaystyle 496 \times 496</math>, niesymetryczna, o elementach rzeczywistych. Źródłem tej
że algorytm FFT, który za chwilę omówimy, będzie działać kosztem <math>\displaystyle O(N\log\,N)</math>,
macierzy jest pewien model ekonomiczny.
czyli praktycznie liniowym (w obu przypadkach stałe proporcjonalności są równe
2) w dodatku będzie miał znacznie mniejsze wymagania pamięciowe. Już nawet gdy
<math>\displaystyle N=8</math> (przypadek kompresji JPEG), mamy <math>\displaystyle N^2 = 512</math>, gdy tymczasem  <math>\displaystyle N\log\,N =
24</math>, więc zysk jest ponaddwudziestokrotny, co ma kapitalne znaczenie, bo zamiast
czekać na zapis zdjęcia (powiedzmy) pół sekundy, czekalibyśmy długie 10 (sic!)
sekund... albo nasza(?) cyfrówka kosztowałaby majątek...


{{fakt|||
[[Image:MNmbeacxc|thumb|450px|center|Struktura niezerowych elementów macierzy MBEACXC]]
Macierz <math>\displaystyle F</math> jest symetryczna oraz <math>\displaystyle \frac{1}{N} F_N^* F_N = I</math>.
}}


Zauważmy, że nasza macierz ma jeszcze więcej specjalnej struktury, powtarza się
Tylko pozornie macierz ta wydaje się dość gęsta, w rzeczywistości jej współczynnik wypełnienia
w niej bardzo wiele takich samych współczynników (sprawdź dla <math>\displaystyle N=4</math>, w ogólności
wynosi około 20 procent.
ma tylko <math>\displaystyle N</math> różnych wyrazów), gdyż <math>\displaystyle \omega_N^N = 1</math> (dla
</div></div>
<math>\displaystyle j=0,\ldots,N-1</math>, <math>\displaystyle \omega_N^j</math> to nic innego jak wszystkie zespolone pierwiastki z jedynki), a
jak wiadomo, mnożenie przez 1 nic nie kosztuje --- o ile tylko się wie, że ''gdzie'' jest ta jedynka. Z grubsza na tym właśnie będzie polegać siła algorytmu
FFT!


W wyprowadzeniu algorytmu szybkiej transformacji Fouriera, ''Fast Fourier
==Formaty macierzy rzadkich==
Transform, FFT ''oprzemy się poraz kolejny na regule "dziel i rządź". Dla
uproszczenia analizy przyjmiemy, że <math>\displaystyle N</math> jest naturalną potęgą dwójki, w
szczególności <math>\displaystyle N = 2m</math> dla pewnego naturalnego <math>\displaystyle m</math>.


Rzeczywiście, rozbijając naszą sumę na sumę po indeksach parzystych i
Zacznijmy od sposobu przechowywania macierzy rozrzedzonych. Naturalnie, nie ma
sumę  po indeksach nieparzystych, mamy
sensu przechowywać wszystkich <strong>zerowych</strong> 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!).


<center><math>\displaystyle \aligned c_j &= f_0 \omega_N^{0\cdot j} + f_2 \omega_N^{2\cdot j} + \ldots + f_{N-2}
====Format współrzędnych (AIJ)====
\omega_N^{(N-2)\cdot j}\\
&& + f_1 \omega_N^{1\cdot j} + f_3 \omega_N^{3\cdot j} + \ldots + f_{N-1}
\omega_N^{(N-1)\cdot j}.
\endaligned</math></center>


Suma po indeksach parzystych da się zapisać w postaci
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>,
<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


<center><math>\displaystyle  
<center><math>\displaystyle  
\sum_{k=0}^{m-1} f_{2k} (\omega_m) ^ {jk}
A_{I[k], J[k]} = V[k], \qquad\forall k = 0,\ldots, NNZ-1.
</math></center>
</math></center>
[[Image:MNaij-matrix-format.png|thumb|450px|center|Format AIJ]]


i analogicznie suma po indeksach nieparzystych da się zapisać
W tym formacie wprowadzane są macierze rzadkie do Octave'a i MATLABa:


<center><math>\displaystyle
<div class="code" style="background-color:#e8e8e8; padding:1em"><pre>
\omega_N^j\cdot \sum_{k=0}^{m-1} f_{2k+1} (\omega_m) ^ {jk}
</math></center>
A = sparse(I,J,V,N,N);
</pre></div>
====Format spakowanych kolumn (wierszy)====


gdyż <math>\displaystyle \omega_N^2 = \omega_m</math>, a więc wygląda na to, że nasze zadanie wyznaczenia
Format współrzędnych nie narzucał żadnego uporządkowania elementów macierzy
dyskretnej transformacji Fouriera wymiaru <math>\displaystyle N</math> da się sprowadzić do analogicznych zadań mniejszego
--- można było je umieszczać w dowolnej kolejności. Narzucenie sensownego
rozmiaru.
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,  wygodnie byłoby przechowywać elementy macierzy <strong>wierszami</strong>. 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.


Rzeczywiście, korzystając z tego, że <math>\displaystyle j = \beta m + \widetilde{j}</math>, gdzie <math>\displaystyle \widetilde{j}
Podobnie jak w przypadku formatu współrzędnych, macierz w formacie CSC jest
= 0,\ldots, m-1</math>, oraz <math>\displaystyle \beta = 0</math> lub <math>\displaystyle 1</math>, mamy <math>\displaystyle \omega_m^j =
przechowywana w postaci trzech wektorów: <code>AV</code> jest wektorem typu
\omega_m^{\widetilde{j}}</math>.
<code>double</code> o długości <math>\displaystyle NNZ</math>, zawierającym <strong>kolejne</strong> niezerowe elementy
macierzy <math>\displaystyle A</math> wpisywane <strong>kolumnami</strong>, <code>AI</code> jest wektorem typu <code>int</code>
o długości <math>\displaystyle NNZ</math>, zawierającym numery wierszy macierzy <math>\displaystyle A</math>, odpowiadających
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
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>.


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


<center><math>\displaystyle \aligned \Phi_{\widetilde{j}} &= \sum_{k=0}^{m-1} f_{2k} \omega_m^{\widetilde{j}k}, \qquad
Mamy więc zależność, przy założeniu, że <math>\displaystyle AP[0]=0</math>,
\widetilde{j} = 0,\ldots, m-1,\\
<center><math>\displaystyle  
\Psi_{\widetilde{j}} &= \sum_{k=0}^{m-1} f_{2k+1} \omega_m^{\widetilde{j}k},  
A_{AI[AP[j]+k],j+1} = AV[AP[j]+k], \qquad j = 0,\ldots,M-1, \, k =
\endaligned</math></center>
0,\ldots,AP[j+1]-1.
 
</math></center>
(jak widać są to DFT dla dwa razy krótszych wektorów, złożonych z tylko
parzystych lub tylko nieparzystych współrzędnych <math>\displaystyle f</math>) dostajemy ostatecznie
 
<center><math>\displaystyle \aligned c_{\widetilde{j}} = \Phi_{\widetilde{j}} + \omega_N^{\widetilde{j}} \Psi_{\widetilde{j}},\\
c_{\widetilde{j}+m} = \Phi_{\widetilde{j}} - \omega_N^{\widetilde{j}} \Psi_{\widetilde{j}}.
\endaligned</math></center>


Tym samym, wyznaczenie DFT wymiaru <math>\displaystyle N</math> udało się rzeczywiście sprowadzić
Taki (z drobnymi modyfikacjami) format macierzy wykorzystują np. pakiety ARPACK
do wyznaczenia dwóch DFT wymiaru <math>\displaystyle m = N/2</math> oraz drobnej manipulacji na
i UMFPACK.
ich wynikach zgodnie z powyższym wzorem. Oczywiście, te mniejsze transformacje
można wyznaczyć takim samym sposobem, co prowadzi do zależności rekurencyjnej,
która kończy się na wektorach długości 1, na których DFT to po prostu
identyczność.


Proste sprawdzenie pokazuje, że koszt takiego algorytmu jest rzędu
====Format diagonalny====
<math>\displaystyle O(N\log\,N)</math>, a nie <math>\displaystyle O(N^2)</math>, jak dla naiwnego algorytmu mnożenia wektora przez
gęstą macierz. Zysk jest więc, nawet dla niewielkich <math>\displaystyle N</math>, istotny.


{{algorytm|Prosta wersja algorytmu FFT||
Znacznie mniej uniwersalny niż poprzednie i dlatego rzadziej spotykany. Kolejne
<pre>
diagonale macierzy przechowujemy w kolejnych wierszach macierzy <math>\displaystyle P\times N</math>,
gdzie <math>\displaystyle P</math> jest liczbą niezerowych diagonal w <math>\displaystyle A\in R^{N\times N}</math>.


function y <nowiki>=</nowiki> fft(x)
Szczególnie wygodny do reprezentacji macierzy taśmowych. Wykorzystywany m.in.
N <nowiki>=</nowiki> length(f);
przez funkcję LAPACKa <code>DGBSV</code> służącą rozwiązywaniu równań z macierzami
if N <nowiki>=</nowiki><nowiki>=</nowiki> 1
taśmowymi.
y <nowiki>=</nowiki> x;
else
<math>\displaystyle \omega</math> <nowiki>=</nowiki> <math>\displaystyle \exp(-\frac{2\Pi}{N}i)</math>;
<math>\displaystyle \omega_k</math> <nowiki>=</nowiki> <math>\displaystyle \omega^{N/2-1}</math>;
u <nowiki>=</nowiki> fft( f[0:2:N-2] );
v <nowiki>=</nowiki> fft( f[1:2:N-1] );
v <nowiki>=</nowiki> v * <math>\displaystyle \omega_k</math>;
y <nowiki>=</nowiki> [ u+v ; u-v ];
end
end
</pre>}}


===Efektywna implementacja FFT===
==Macierze specjalne==


Jak już zdążyliśmy się przyzwyczaić, w algorytmach numerycznych unikamy
Zajmiemy się teraz zadaniem rozwiązywania układu równań liniowych
stosowania jawnej rekurencji, gdy tylko to możliwe. W przypadku FFT można jej
również uniknąć, wyznaczając zawczasu --- korzystając z tzw. odwrócenia bitów
--- porządek, w którym należy składać 1-wymiarowe DFT w coraz dłuższe wektory
zgodnie ze wzorem powyżej tak, by na końcu dostać pożądany wektor <math>\displaystyle c = F_Nf</math>.
 
Ponadto, istnieją warianty algorytmu FFT, które np. działają na danych
rzeczywistych. Na analogicznych zasadach co FFT oparte są również algorytmy
wykonujące tzw. dyskretną transformację cosinusów (DCT) i jej wariant MDCT
stosowany w kodekach audio takich jak MP3, AAC, czy Ogg-Vorbis..
 
===Interpolacja trygonometryczna===
 
Jednym z wielu zadań, w których daje się zastosować algorytm FFT, jest zadanie
interpolacji trygonometrycznej:
 
Dla danych węzłów <math>\displaystyle x_k = \frac{2\pi k }{N}</math>, <math>\displaystyle k = 0,\ldots,N-1</math>, znaleźć
wielomian <math>\displaystyle P</math> (zmiennej rzeczywistej, o wartościach zespolonych) stopnia <math>\displaystyle \leq N-1</math> postaci
<center><math>\displaystyle  
<center><math>\displaystyle  
P(x) = \sum_{k=0}^{N-1} \beta_k \bar{\omega}^k,
Ax = b,
</math></center>
</math></center>


gdzie <math>\displaystyle \bar{\omega} = e^{ix} = \cos(x) + i\, \sin(x)</math> (stąd nazwa: trygonometryczny)
ale w sytuacji, gdy macierz <math>\displaystyle A</math> 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.
taki, że
<center><math>\displaystyle
P(x_k) = y_k, \qquad k = 0,\ldots,N-1,
</math></center>


dla zadanych wartości <math>\displaystyle y_k</math>.  
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.


W języku macierzy DFT możemy zapisać zadanie interpolacji trygonometrycznej jako
====Macierze taśmowe====
zadanie wyznaczania wektora <math>\displaystyle \beta</math> takiego, że
<center><math>\displaystyle
\bar{F_N}\beta = y
</math></center>


dla zadanego wektora <math>\displaystyle y</math>.
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ą
z rozstępem <math>\displaystyle d</math>, o szerokości pasma <math>\displaystyle 2d+1</math>.  


{{twierdzenie|||
Łatwo sprawdzić, że algorytm eliminacji Gaussa (bez wyboru elementu głównego)
Współczynniki <math>\displaystyle \beta = [\beta_0,\ldots,\beta_{N-1}]^T</math> poszukiwanego wielomianu
nie spowoduje dodatkowego wypełnienia w takiej macierzy (a więc da się wykonać w
trygonometrycznego wyrażają się wzorem
miejscu). W przypadku konieczności wyboru elementu głównego, pesymistyczne
<center><math>\displaystyle  
oszacowanie rozstępu macierzy rozkładu LU jest równe <math>\displaystyle \max\{2d,N\}</math> --- tak
\beta = \frac{1}{N} F_N y.
więc, dla niezbyt dużych <math>\displaystyle d</math> wciąż wynikowa macierz jest taśmowa. 
</math></center>


}}
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
miejscu, kosztem <math>\displaystyle O(d\,N)</math>, czyli liniowym.


{{dowod|||
W LAPACKu zaimplementowano szybki solver równań z macierzami taśmowymi,
Jak wiemy, <math>\displaystyle \frac{1}{N} F_N^* F_N = I</math>, więc, z symetrii macierzy <math>\displaystyle F_N</math> wynika,
<code>DGBSV</code>, wymagający skądinąd specjalnego sposobu
że <math>\displaystyle (\bar{F_N})^{-1} = \frac{1}{N} F_N</math>.
przechowywania macierzy, wykorzystyjącego format diagonalny.
}}


Można pokazać, że  gdy dane są rzeczywiste, zadanie interpolacji
====Macierze trójdiagonalne====
trygonometrycznej można wyrazić
korzystając wyłącznie z liczb rzeczywistych.
Jeśli <math>\displaystyle y_k\in R</math>, <math>\displaystyle k = 0,\ldots,N-1</math>, to wtedy (rzeczywisty) wielomian trygonometryczny
<center><math>\displaystyle
p(x) = \sum_{k=0}^{N-1} \left( a_k \cos(\frac{2k\pi}{N} x) - b_k \sin(\frac{2k\pi}{N} x)\right),
</math></center>
 
gdzie <math>\displaystyle a_k = Re(\beta_k)</math>, <math>\displaystyle b_k = Im(\beta_k)</math>, interpoluje <math>\displaystyle y_k</math> w węzłach
<math>\displaystyle x_k</math>. Oczywiście, powyższa formuła w rzeczywistości ma o połowę mniej wyrazów,
ze względu na własności funkcji trygonometrycznych.


===Splot===
Szczególnym przypadkiem macierzy taśmowych są macierze trójdiagonalne, tzn. taśmowe o
rozstępie <math>\displaystyle d=1</math>:


W niektórych zastosowaniach potrzebne jest wyznaczenie ''splotu'' dwóch
wektorów, to znaczy, wyznaczenie wyrażeń postaci
<center><math>\displaystyle  
<center><math>\displaystyle  
z_k = \sum_{j=0}^{N-1} u_j v_{k-j}, \qquad k = 0, \ldots, N-1.
A =  
</math></center>
 
Zapisując to macierzowo, szukamy iloczynu wektora <math>\displaystyle u</math> z cykliczną macierzą Toeplitza
(macierz Toeplitza ma stałe wyrazy wzdłuż diagonali) wyznaczoną przez <math>\displaystyle v</math>,
<center><math>\displaystyle
z =  
\begin{pmatrix}  
\begin{pmatrix}  
v_0 & v_1 & \cdots      & v_{N-1} \\
a_1 & c_1 & & \\
v_{N-1} & v_0 & \cdots & v_{N-2}\\
b_2 & a_2 & c_2      &   & \\
  \vdots  & \ddots & \ddots & \vdots \\
  & b_3 & a_3  & \ddots & \\
v_1    & \cdots    v_{N-1} & v_0
  & & \ddots & \ddots & c_{N-1}\\
\end{pmatrix}  \cdot \begin{pmatrix} u_0\\u_1\\\vdots\\u_{N-1}\end{pmatrix} ,
  &  &      & b_N & a_N
\end{pmatrix}  
</math></center>
</math></center>


tak więc pozornie zadanie wyznaczenia splotu powinno kosztować tyle, co
Zadanie rozwiązywania równań z taką macierzą
mnożenie macierzy przez wektor, a więc <math>\displaystyle O(N^2)</math> operacji. Tymczasem
prosty rachunek pozwala sprawdzić, że odpowiednie transformacje Fouriera,
<math>\displaystyle \hat{z} = F_N z</math>, <math>\displaystyle \hat{u} = F_N u</math>, <math>\displaystyle \hat{v} = F_N v</math>
spełniają równanie z macierzą diagonalną!
 
<center><math>\displaystyle  
<center><math>\displaystyle  
\hat{z} = N \cdot \begin{pmatrix} \hat{v}_0 & & \\
Ax = e
& \ddots & \\
& & \hat{v}_{N-1}
\end{pmatrix}  \cdot \hat{u} = N\cdot \begin{pmatrix} \hat{v}_0 \hat{u}_0\\
\vdots  \\
\hat{v}_{N-1}\hat{u}_{N-1}
\end{pmatrix} ,
</math></center>
</math></center>


a to mnożenie daje się wykonać kosztem liniowym, tym samym całe zadanie daje się
jest tak często spotykane, że
policzyć kosztem <math>\displaystyle O(N\log\,N)</math>.
warto przytoczyć algorytm w całej okazałości --- popularnie zwany algorytmem
 
przeganiania.
===Biblioteki===
 
Najpopularniejszą obecnie biblioteką implementującą algorytm FFT dla  DFT, DCT i
innych pokrewnych (bez ograniczenia, że  wymiar jest naturalną potęgą dwójki),
jest [http://www.fftw.org  FFTW] której nazwa jest skrótowcem od  niezbyt
skromnie brzmiącego ang. The Fastest Fourier Transform in the West. Z tej
biblioteki korzystają m.in. funkcje MATLABa i Octave'a <code>fft</code> oraz
<code>ifft</code> dla transformacji DFT (to znaczy mnożenia przez <math>\displaystyle F_N</math>) i,
odpowiednio, transformacji odwrotnej, <math>\displaystyle \frac{1}{N}\bar{F}_N</math>.
 
FFTW jest napisana w C i w dużym stopniu wykorzystuje możliwości współczesnych
procesorów, takie jak potokowanie i instrukcje wektorowe SSE2 i SSE3. Poniżej
pokazujemy przykładowy prościutki kod w C, realizujący DFT na pojedynczym
wektorze zespolonym.
 
<div class="code" style="background-color:#e8e8e8; padding:1em"><pre>
/* Kompilacja:
gcc -o dft dft.c -lfftw3 -lm */
#include <complex.h> /* rozszerzenie GCC dające operacje na typach zespolonych */
#include <fftw3.h>
#include <math.h>
#define N 8
 
int main(void)
{
fftw_complex *F, *C;
fftw_plan Plan;
double normfactor <nowiki>=</nowiki> 1.0/N;
int i;
 
F <nowiki>=</nowiki> fftw_malloc( N * sizeof(fftw_complex) );
C <nowiki>=</nowiki> fftw_malloc( N * sizeof(fftw_complex) );
 
for( i <nowiki>=</nowiki> 0; i < N; i++ ) /* inicjalizacja wartości tablicy F */
{
F[i] <nowiki>=</nowiki> i*M_PI*(1-0.5*I);
}
 
Plan <nowiki>=</nowiki> fftw_plan_dft_1d( N, F, C, FFTW_FORWARD, FFTW_ESTIMATE );
 
fftw_execute( Plan );
 
for( i <nowiki>=</nowiki> 0; i < N; i++ ) /* normalizacja wyznaczonego C */
C[i] *<nowiki>=</nowiki> normfactor;
 
for( i <nowiki>=</nowiki> 0; i < N; i++ )
{
printf("F[\%d] <nowiki>=</nowiki> \%8.3lf + \%8.3lfi <nowiki>|</nowiki> C[\%d] <nowiki>=</nowiki> \%8.3lf + \%8.3lfi\n",
i, creal(F[i]), cimag(F[i]), i, creal(C[i]), cimag(C[i]));
}
 
/* .... teraz moglibyśmy zmienić wartości F i ponownie wyznaczyć C,
korzystając z tego samego Planu! */
 
/* sprzątamy */
 
fftw_destroy_plan( Plan );
fftw_free( F );
fftw_free( C );
 
return(0);
}
</pre></div>
Zwrócmy uwagę na linię <code>Plan<nowiki>=</nowiki>fftw_plan_dft_1d(...)</code>. To tutaj dokonywane są
ustalenia, w jakiej kolejności mają być prowadzone obliczenia. Jest to operacja
dość kosztowna, dlatego jeśli mamy wyznaczyć wiele takich samych DFT, tylko na
różnych danych, należy przed pierwszą DFT taki plan zachować, a potem już gotowy
wykorzystać, gdy chcemy aplikować DFT dla następnych danych.
 
==Interpolacja splajnowa==


Interpolacja  wielomianami interpolacyjnymi, chociaż korzysta z funkcji gładkich
Zacznijmy jednak od stwierdzenia, kiedy taka macierz nie wymaga wyboru elementu
i łatwo reprezentowalnych w komputerze, ma jednak również pewne wady.
głównego:
Zauważmy, że błąd interpolacji może być bardzo duży (zjawisko Rungego), a poza
tym, interpolacja jest nielokalna: nawet mała zmiana warości funkcji w pojedynczym węźle
może powodować dużą zmianę zachowania całego wielomianu interpolacyjnego.
Czasem więc lepiej jest zastosować innego rodzaju
interpolację, np. posługując się funkcjami sklejanymi. 


===Co to są funkcje sklejane?===
{{stwierdzenie|||
Jeśli macierz <math>\displaystyle A</math> ma <strong>słabo</strong> dominującą przekątną, tzn.


W ogólności przez funkcję sklejaną rozumie się każdą
<center><math>\displaystyle |a_i|\,\ge\,|b_i|\,+\,|c_i|,\qquad 1\le i\le N,
funkcję przedziałami wielomianową. Nas będą jednak
interesować szczególne funkcje tego typu i dlatego termin
''funkcje sklejane'' zarezerwujemy dla funkcji
przedziałami wielomianowych i posiadających dodatkowe
własności, które teraz określimy.
 
Niech dany będzie przedział skończony <math>\displaystyle [a,b]</math> i węzły
 
<center><math>\displaystyle a \,=\, x_0 \,<\, x_1 \,<\, \cdots \,<\, x_n \,=\, b,  
</math></center>
</math></center>


przy czym <math>\displaystyle n\ge 1</math>.
(<math>\displaystyle b_1=0=c_N</math>) i przynajmniej dla jednego indeksu "<math>\displaystyle i</math>" mamy powyżej
 
ostrą nierówność "<math>\displaystyle ></math>", to algorytm przeganiania jest wykonalny bez
{{definicja|||
przestawień wierszy. Ponadto wymaga on <math>\displaystyle 7N</math> operacji arytmetycznych,
Funkcję <math>\displaystyle s:R\toR</math> nazywamy funkcją
a więc jest prawie optymalny.  
sklejaną rzędu <math>\displaystyle r</math> (<math>\displaystyle r\ge 1</math>) odpowiadającą węzłom
<math>\displaystyle x_j</math>, <math>\displaystyle 0\le j\le n</math>, jeśli spełnione są następujące
dwa warunki:
; (i)
:  <math>\displaystyle s</math> jest wielomianem stopnia co najwyżej <math>\displaystyle 2r-1</math> na każdym
z przedziałów <math>\displaystyle [x_{j-1},x_j]</math>, tzn.
<math>\displaystyle s_{|[x_{j-1},x_j]}\in\Pi_{2r-1}</math>, <math>\displaystyle 1\le j\le n</math>,  
 
; (ii)
:  <math>\displaystyle s</math> jest <math>\displaystyle (2r-2)</math>-krotnie różniczkowalna w sposób
ciągły na całej prostej, tzn. <math>\displaystyle s\in C^{(2r-2)}(R)</math>.
Jeśli ponadto
; (iii)
:  <math>\displaystyle s</math> jest wielomianem stopnia co najwyżej <math>\displaystyle r-1</math> poza
<math>\displaystyle (a,b)</math>, tzn. <math>\displaystyle s_{|(-\infty,a]},s_{|[b,+\infty)}\in\Pi_{r-1}</math>,
to <math>\displaystyle s</math> jest naturalną funkcją sklejaną.  
}}
}}


Klasę naturalnych funkcji sklejanych rzędu <math>\displaystyle r</math> opartych na
{{algorytm|Metoda przeganiania||
węzłach <math>\displaystyle x_j</math> będziemy oznaczać przez
<pre>
<math>\displaystyle {\cal S}_r(x_0,\ldots,x_n)</math>, albo po prostu <math>\displaystyle {\cal S}_r</math>,
jeśli węzły są ustalone.


Na przykład, funkcją sklejaną rzędu pierwszego (<math>\displaystyle r=1</math>)  
<math>\displaystyle d_1</math> = <math>\displaystyle a_1</math>;
jest funkcja ciągła i liniowa na poszczególnych
<math>\displaystyle f_1</math> = <math>\displaystyle e_1</math>;
przedziałach <math>\displaystyle [x_{j-1},x_j]</math>. Jest ona naturalna, gdy poza
for (i = 2; i <= N; i++)
<math>\displaystyle (a,b)</math> jest funkcją stała. Tego typu funkcje nazywamy
{
''liniowymi funkcjami sklejanymi''.
<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>;
Najważniejszymi a praktycznego punktu widzenia są jednak
<math>\displaystyle f_i</math> = <math>\displaystyle e_i</math> - <math>\displaystyle l</math> * <math>\displaystyle f_{i-1}</math>;
funkcje sklejane rzędu drugiego odpowiadające <math>\displaystyle r=2</math>. Są
}
to funkcje, które są na <math>\displaystyle R</math> dwa razy różniczkowalne w
<math>\displaystyle x_1</math> = <math>\displaystyle f_N</math>;
sposób ciągły, a na każdym z podprzedziałów są
for (i = N-1; i >= 1; i--)
wielomianami stopnia co najwyżej trzeciego. W tym przypadku
<math>\displaystyle x_i</math> = <math>\displaystyle f_i</math> - <math>\displaystyle c_i</math> * <math>\displaystyle x_{i+1}</math>;
mówimy o ''kubicznych funkcjach sklejanych''. Funkcja
</pre>}}
sklejana kubiczna jest naturalna, gdy poza <math>\displaystyle (a,b)</math> jest
wielomianem liniowym.


===Interpolacja i gładkość===
==Metody bezpośrednie==


Pokażemy najpierw ważny lemat, który okaże się kluczem
<div style="margin-top:1em; padding-top,padding-bottom:1em;">
do dowodu dalszych twierdzeń.
<span  style="font-variant:small-caps;">Przykład: Strzałka Wilkinsona</span>
<div class="solution">


Niech <math>\displaystyle W^r(a,b)</math> będzie klasą funkcji <math>\displaystyle f:[a,b]\toR</math> takich,
Rozważmy układ równań z macierzą diagonalnie dominującą postaci
że <math>\displaystyle f</math> jest <math>\displaystyle (r-1)</math> razy różniczkowalna na <math>\displaystyle [a,b]</math> w sposób
ciągły oraz <math>\displaystyle f^{(r)}(x)</math> istnieje prawie wszędzie na <math>\displaystyle [a,b]</math>
i jest całkowalna z kwadratem, tzn.


<center><math>\displaystyle \aligned W^r(a,b) &= \{\,f\in C^{(r-1)}([a,b]):\, f^{(r)}(x)
<center><math>\displaystyle A = \begin{pmatrix}  
    \mbox{  istnieje p.w. na  }  [a,b] \\
* & * & * & \cdots & * \\
    && \qquad\qquad\qquad\qquad \mbox{ oraz  }
* & * &       &  & \\
      f^{(r)}\in{\cal L}_2(a,b)\,\}.
* &  & *      & & \\
\endaligned</math></center>
\vdots & & & \ddots & \\
 
* &  &      &  & *
Oczywiście każda funkcja sklejana rzędu <math>\displaystyle r</math> (niekoniecznie
\end{pmatrix}
naturalna) należy do <math>\displaystyle W^r(a,b)</math>.
 
{{lemat|||
   
Niech <math>\displaystyle f\in W^r(a,b)</math> będzie funkcją
zerującą się w węzłach, tzn.
 
<center><math>\displaystyle f(x_j)\,=\,0,\qquad 0\le j\le n.
</math></center>
</math></center>


Wtedy dla dowolnej naturalnej funkcji sklejanej <math>\displaystyle s\in {\cal S}_r</math>  
gdzie <math>\displaystyle *</math> oznacza jakiś niezerowy element.
mamy
Łatwo sprawdzić, że chociaż wyjściowa macierz jest rozrzedzona, to zastosowanie do niej eliminacji Gaussa powoduje, że w wyniku
dostajemy <strong>gęste</strong> czynniki rozkładu.


<center><math>\displaystyle \int_a^b f^{(r)}(x)s^{(r)}(x)\,dx\,=\,0.
Tymczasem wystarczy odwrócić kolejność równań i numerację niewiadomych (co dla
</math></center>
macierzy jest równoznaczne z odwróceniem porządku wierszy i kolumn, korzystając
z pewnej (jakiej?) macierzy permutacji <math>\displaystyle P</math>):


}}
<center><math>\displaystyle \widetilde{A} = PAP^T = \begin{pmatrix}  
 
* &        &  & & *\\
{{dowod|||
  & \ddots  & & & \vdots\\
Dla <math>\displaystyle r=1</math> funkcja <math>\displaystyle s'</math> jest przedziałami stała.
  &      & * &  & * \\
Oznaczając przez <math>\displaystyle a_j</math> jej wartość na <math>\displaystyle [x_{j-1},x_j]</math> dostajemy
    &        &  &  * & * \\
 
* & \cdots & * & * & *
<center><math>\displaystyle \aligned \int_a^b f'(x)s'(x)\,dx &=  
\end{pmatrix}  
          \sum_{j=1}^n\int_{t_{j-1}}^{t_j} f'(x)a_j\,dx \\
        &= \sum_{j=1}^n a_j(f(x_j)-f(x_{j-1}))\,=\,0,
\endaligned</math></center>
 
ponieważ <math>\displaystyle f</math> zeruje się w <math>\displaystyle t_j</math>.
 
Rozpatrzmy teraz przypadek <math>\displaystyle r\ge 2</math>. Ponieważ
 
<center><math>\displaystyle (f^{(r-1)}s^{(r)})'\,=\,f^{(r)}s^{(r)}\,+\,f^{(r-1)}s^{(r+1)},
</math></center>
</math></center>


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


<center><math>\displaystyle \int_a^b f^{(r)}(x)s^{(r)}(x)\,dx\,=\,f^{(r-1)}(x)s^{(r)}(x)
Właśnie na tym polega główny problem w rozwiązywaniu układów z macierzami
    \Big |_a^b \,-\,\int_a^b f^{(r-1)}(x)s^{(r+1)}(x)\,dx.
rzadkimi metodami bezpośrednimi: maksymalnie wykorzystać rozrzedzenie macierzy
</math></center>
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).


Wobec tego, że <math>\displaystyle s</math> jest poza przedziałem <math>\displaystyle (a,b)</math> wielomianem stopnia
W ogólnym przypadku rozwiązanie takiego zadania jest trudne i większość
co najwyżej <math>\displaystyle r-1</math> oraz <math>\displaystyle s^{(r)}</math> jest ciągła na <math>\displaystyle R</math>, mamy
algorytmów opiera się na pewnych heurystykach, które warto wspomóc wcześniejszą
<math>\displaystyle s^{(r)}(a)=0=s^{(r)}(b)</math>, a stąd
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).


<center><math>\displaystyle f^{(r-1)}(x)s^{(r)}(x)\Big |_a^b\,=\,0.  
Stosuje się kilka strategii wyznaczania korzystnych permutacji
</math></center>
''reorderingu '', z których warto wymienić
* przybliżone algorytmy minimalnego stopnia ''approximate minimum degree ([http://www.cise.ufl.edu/research/sparse/amd  AMD]) ''
* techniki
podziału grafów na (prawie) rozłączne składowe ([http://glaros.dtc.umn.edu/gkhome/views/metis  METIS]).
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].


Postępując podobnie, tzn. całkując przez części <math>\displaystyle r-1</math> razy
W Octave mamy do dyspozycji także kilka procedur generujących takie permutacje,
otrzymujemy w końcu
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.


<center><math>\displaystyle \int_a^b f^{(r)}(x)s^{(r)}(x)\,dx\,=\,(-1)^{r-1}
<div style="margin-top:1em; padding-top,padding-bottom:1em;">
      \int_a^b f'(x)s^{(2r-1)}(x)\,dx.
<span  style="font-variant:small-caps;">Przykład: Wypełnienie pewnej macierzy w zależności od użytego algorytmu</span>  
</math></center>
<div class="solution">


Funkcja <math>\displaystyle s^{(2r-1)}</math> jest przedziałami stała, a więc możemy
Rozważmy macierz pochodzącą z kolekcji
teraz zastosować ten sam argument jak dla <math>\displaystyle r=1</math>, aby pokazać,  
[http://www.cise.ufl.edu/research/sparse/matrices/Boeing  Tima Davisa], dotyczącą pewnego zadania
że ostatnia całka jest równa zeru.}}
mechaniki strukturalnej jakie pojawiło się u Boeinga. Jest to macierz
symetryczna, dodatnio określona, wymiaru 8032.  


Funkcje sklejane chcielibyśmy zastosować do interpolacji funkcji.  
[[Image:MNsparseA.png|thumb|450px|center|Struktura niezerowych elementów macierzy.]]
Ważne jest więc, aby odpowiednie zadanie interpolacyjne miało
jednoznaczne rozwiązanie.  


{{twierdzenie|||
Jest to macierz silnie rozrzedzona, ponieważ ma tylko 355460 niezerowych
Jeśli <math>\displaystyle n+1\ge r</math>, to dla dowolnej funkcji
elementów (czyli wypełnienie to tylko 0.5 procent).
<math>\displaystyle f:[a,b]\toR</math> istnieje dokładnie jedna naturalna funkcja sklejana
<math>\displaystyle s_f\in {\cal S}_r</math> interpolująca <math>\displaystyle f</math> w węzłach <math>\displaystyle x_j</math>, tzn. taka,
że


<center><math>\displaystyle s_f(x_j)\,=\,f(x_j),\qquad 0\le j\le n.
Zobaczymy, jak w zależności od użytego algorytmu permutacji kolumn i
</math></center>
wierszy poradzi sobie algorytm rozkładu Cholesky'ego.


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


{{dowod|||
[[Image:MNsparsecholcolamd.png|thumb|450px|center|Czynnik rozkładu Cholesky'ego <math>\displaystyle L</math> z reorderingiem
Pokażemy najpierw, że jedyną naturalną
COLAMD. Czas rozkładu: 0.813038]]
funkcją sklejaną interpolującą dane zerowe jest funkcja zerowa.
Rzeczywiście, jeśli <math>\displaystyle s(x_j)=0</math> dla <math>\displaystyle 0\le j\le n</math>, to podstawiając
w poprzednim Lemacie <math>\displaystyle f = s</math> otrzymujemy


<center><math>\displaystyle \int_a^b \Big(s^{(r)}(x)\Big)^2\,dx\,=\,0.
[[Image:MNsparsecholsymamd.png|thumb|450px|center|Czynnik rozkładu Cholesky'ego <math>\displaystyle L</math> z reorderingiem
</math></center>
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.]]


Stąd <math>\displaystyle s^{(r)}</math> jest funkcją zerową, a więc <math>\displaystyle s</math> jest
[[Image:MNsparsecholsymrcm.png|thumb|450px|center|Czynnik rozkładu Cholesky'ego <math>\displaystyle L</math> z odwrotnym reorderingiem
wielomianem stopnia co najwyżej <math>\displaystyle r-1</math> zerującym się w co
Cuthill-McKee. Czas rozkładu: 0.845928]]
najmniej <math>\displaystyle n+1</math> punktach <math>\displaystyle x_j</math>. Wobec tego, że <math>\displaystyle n+1>r-1</math>,
otrzymujemy <math>\displaystyle s\equiv 0</math>.  


Zauważmy teraz, że problem znalezienia naturalnej funkcji sklejanej
[[Image:MNsparsecholcolperm.png|thumb|450px|center|Czynnik rozkładu Cholesky'ego <math>\displaystyle L</math> z jeszcze
<math>\displaystyle s</math> interpolującej <math>\displaystyle f</math> można sprowadzić do rozwiązania kwadratowego
innym (bardzo tanim, ale jak widać czasem zupełnie złym) reorderingiem. Czas rozkładu: 5.947936]]
układu równań liniowych. Na każdym przedziale <math>\displaystyle [x_{i-1},x_i]</math>,
<math>\displaystyle 1\le i\le n</math>, jest ona postaci


<center><math>\displaystyle s(x)\,=\,w_i(x)\,=\,\sum_{j=0}^{2r-1} a_{i,j}x^j,
Na zakończenie popatrzmy, jak ważne jest spostrzeżenie symetrii macierzy:
</math></center>


dla pewnych współczynników <math>\displaystyle a_{i,j}\inR</math>, a na
[[Image:MNsparseLlu.png|thumb|450px|center|Rozkład LU, czynnik <math>\displaystyle L</math> (bez reorderingu). Czas rozkładu LU: 1.696018s. Nieakceptowalny, podobnie
<math>\displaystyle (-\infty,a]</math> i <math>\displaystyle [b,\infty)</math> mamy odpowiednio
jak drastyczne wypełnienie macierzy.]]


<center><math>\displaystyle s(x)\,=\,w_0(x)\,=\,\sum_{j=0}^{r-1} a_{0,j}x^j
[[Image:MNsparseUlu.png|thumb|450px|center|Rozkład LU, czynnik <math>\displaystyle U</math> (bez reorderingu)]]
</math></center>


i
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 algorytm oparty na
podziale grafu na prawie rozłączne składowe mógłby tu jeszcze lepiej zadziałać.


<center><math>\displaystyle s(x)\,=\,w_{n+1}(x)\,=\,\sum_{j=0}^{r-1} a_{n+1,j}x^j.
</div></div>
</math></center>


Aby wyznaczyć <math>\displaystyle s</math>, musimy więc znaleźć ogółem <math>\displaystyle 2r(n+1)</math>
==Stacjonarne metody iteracyjne==
współczynników <math>\displaystyle a_{i,j}</math>, przy czym są one związane
<math>\displaystyle (2r-1)(n+1)</math> warunkami jednorodnymi wynikającymi z gładkości,


<center><math>\displaystyle w_i^{(k)}(x_i)\,=\,w_{i+1}^{(k)}(x_i)
Gdy macierz jest rozrzedzona, mnożenie takiej macierzy przez wektor jest tanie
</math></center>
(koszt jest proporcjonalny do liczby <strong>niezerowych</strong> 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.


dla <math>\displaystyle 0\le i\le n</math> i <math>\displaystyle 0\le k\le 2r-2</math>, oraz <math>\displaystyle n+1</math>  
Najprostsze metody iteracyjne (najprostsze w analizie i implementacji, ale ---
niejednorodnymi warunkami interpolacyjnymi,
jak można się domyślić --- w praktyce najmniej efektywne) polegają na rozkładzie
macierzy na część "łatwo odwracalną", <math>\displaystyle M</math>, i "resztę", <math>\displaystyle Z</math>. Dokładniej,
jeśli <math>\displaystyle M</math> jest nieosobliwa, to równanie <math>\displaystyle Ax = b</math> można zapisać jako
zadanie punktu stałego


<center><math>\displaystyle w_i(x_i)\,=\,f(x_i)
<center><math>\displaystyle Mx = Nx + b,
</math></center>
</math></center>


dla <math>\displaystyle 0\le i\le n</math>. Otrzymujemy więc układ <math>\displaystyle 2r(n+1)</math>
gdzie <math>\displaystyle Z=M-A</math>. Inaczej:
równań liniowych ze względu na <math>\displaystyle 2r(n+1)</math> niewiadomych
<math>\displaystyle a_{i,j}</math>.
 
Naturalna funkcja sklejana interpolująca <math>\displaystyle f</math> jest
wyznaczona jednoznacznie wtedy i tylko wtedy, gdy układ ten
ma jednoznaczne rozwiązanie. To zaś zachodzi, gdy zero jest
jedynym rozwiązaniem układu jednorodnego. Rzeczywiście,
układ jednorodny odpowiada zerowym warunkom interpolacyjnym,
przy których, jak pokazaliśmy wcześniej, zerowa funkcja
sklejana (której odpowiada <math>\displaystyle a_{i,j}=0</math>, <math>\displaystyle \forall i,j</math>) 
jest jedynym rozwiązaniem zadania interpolacyjnego.}}
 
Naturalne funkcje sklejane możemy więc używać do
interpolacji funkcji. Pokażemy teraz inną ich własność,
która jest powodem dużego praktycznego zainteresowania
funkcjami sklejanymi.  


{{twierdzenie|||
<center><math>\displaystyle x = M^{-1}(Zx + b),
Niech <math>\displaystyle f\in W^r(a,b)</math> i niech <math>\displaystyle s_f\in {\cal S}_r</math>
będzie naturalną funkcją sklejaną rzędu <math>\displaystyle r</math> interpolującą
<math>\displaystyle f</math> w węzłach <math>\displaystyle x_j</math>, <math>\displaystyle 0\le j\le n</math>. Wtedy
 
<center><math>\displaystyle  
  \int_a^b \Big(  f^{(r)}(x)\Big)^2\,dx\,\ge\,
  \int_a^b \Big(s_f^{(r)}(x)\Big)^2\,dx.
</math></center>
</math></center>


}}
i zastosować doń [[sec:nieliniowe|Dodaj link: metodę iteracji prostej Banacha]]:
 
{{dowod|||
Jeśli przedstawimy <math>\displaystyle f</math> w postaci
<math>\displaystyle f=s_f+(f-s_f)</math>, to
 
<center><math>\displaystyle \aligned \int_a^b\Big(f^{(r)}(x)\Big)^2\,dx 
    &= \int_a^b\Big(s_f^{(r)}(x)\Big)^2\,dx\,+\,
        \int_a^b\Big((f-s_f)^{(r)}(x)\Big)^2\,dx \\
    & & \qquad\qquad 2\,\int_a^b s_f^{(r)}(x)(f-s_f)^{(r)}(x)\,dx.
\endaligned</math></center>
 
Funkcja <math>\displaystyle f-s_f</math> jest w klasie <math>\displaystyle W^r(a,b)</math> i zeruje się w węzłach
<math>\displaystyle x_j</math>, <math>\displaystyle 0\le j\le n</math>. Z Lematu wynika więc, że
<math>\displaystyle \int_a^b s_f^{(r)}(x)(f-s_f)^{(r)}(x)dx=0</math>, a stąd wynika teza.}}
 
Wartość całki <math>\displaystyle \int_a^b(f^{(r)}(x))^2 dx</math> może być w
ogólności uważana za miarę gładkości funkcji.
Dowiedzioną nierówność możemy więc zinterpretować w
następujący sposób. Naturalna funkcja sklejana jest w
klasie <math>\displaystyle W^r(a,b)</math> najgładszą funkcją spełniającą dane
warunki interpolacyjne w wybranych węzłach <math>\displaystyle x_j</math>.
 
Jak już wspomnieliśmy, najczęściej używanymi są kubiczne
funkcje sklejane. Dlatego rozpatrzymy je oddzielnie.


===Kubiczne funkcje sklejane===
<center><math>\displaystyle x_{k+1} = M^{-1}(Zx_k + b).
 
Jeśli zdecydowaliśmy się na użycie kubicznych funkcji
sklejanych to powstaje problem wyznaczenia <math>\displaystyle s_f\in{\cal S}_2</math>
interpolującej daną funkcję <math>\displaystyle f</math>, tzn. takiej, że
<math>\displaystyle s_f(x_i)=f(x_i)</math> dla <math>\displaystyle 0\le i\le n</math>. W tym celu, na każdym
przedziale <math>\displaystyle [x_i,x_{i+1}]</math> przedstawimy <math>\displaystyle s_f</math> w postaci jej
rozwinięcia w szereg Taylora w punkcie <math>\displaystyle x_i</math>,
 
<center><math>\displaystyle s_f(x)\,=\,w_i(x)\,=\,a_i+b_i(x-x_i)+
    c_i\frac{(x-x_i)^2}2+d_i\frac{(x-x_i)^3}6,
</math></center>
</math></center>


i podamy algorytm obliczania <math>\displaystyle a_i,b_i,c_i,d_i</math>
Takie metody nazywamy stacjonarnymi metodami iteracyjnymi.
dla <math>\displaystyle 0\le i\le n-1</math>.  


Warunki brzegowe i warunki ciągłości
Aby przeanalizować zbieżność takiej metody, warto rozpatrzyć
dla <math>\displaystyle s_f''</math> dają nam <math>\displaystyle w_0''(x_0)=0=w_{n-1}''(x_n)</math> oraz
przypadek ogólniejszy
<math>\displaystyle w_i''(x_{i+1})=w_{i+1}''(x_{i+1})</math>, czyli
 
<center><math>\displaystyle \aligned c_0 &= 0, \\ 
  c_i+d_ih_i &= c_{i+1}, \qquad 0\le i\le n-2, \\
  c_{n-1}+d_{n-1}h_{n-1} &= 0,
\endaligned</math></center>
 
gdzie <math>\displaystyle h_i=x_{i+1}-x_i</math>. Stąd, przyjmując dodatkowo
<math>\displaystyle c_n=0</math>, otrzymujemy


<center><math>\displaystyle  
<center><math>\displaystyle  
  d_i\,=\,\frac{c_{i+1}-c_i}{h_i},\qquad 1\le i\le n-1.
  x_k\,=\,B x_{k-1}\,+\, c,
</math></center>
</math></center>


Z warunków ciągłości dla <math>\displaystyle s_f'</math> dostajemy z kolei
dla pewnej macierzy <math>\displaystyle B</math>   wektora
 
<math>\displaystyle c</math> (dla stacjonarnej metody iteracyjnej, <math>\displaystyle B=M^{-1}Z</math> oraz <math>\displaystyle c=M^{-1}b</math>).
<center><math>\displaystyle b_i+c_ih_i+d_ih_i^2/2\,=\,b_{i+1},
    \qquad 0\le i\le n-2,
</math></center>


oraz
W  tym przypadku


<center><math>\displaystyle  
<center><math>\displaystyle x_k- x^*\,=\,B^k( x_0- x^*),  
  b_{i+1}\,=\,b_i+h_i(c_{i+1}+c_i)/2,  
    \qquad 0\le i\le n-2.
</math></center>
</math></center>


Warunki ciągłości <math>\displaystyle s_f</math> dają w końcu
a stąd i z nierówności <math>\displaystyle \|B^k\|\le\|B\|^k</math>, mamy


<center><math>\displaystyle  
<center><math>\displaystyle \| x_k- x^*\|\,\le\,
  a_i+b_ih_i+c_ih_i^2/2+d_ih_i^3/6\,=\,a_{i+1},  
          \|B\|^k\| x_0- x^*\|.  
    \qquad 0\le i\le n-2.  
</math></center>
</math></center>


Powyższe równania definiują
Warunkiem dostatecznym zbieżności iteracji prostych
nam na odcinku <math>\displaystyle [a,b]</math> naturalną kubiczną funkcję
jest więc <math>\displaystyle \|B\|<1</math>. Okazuje się, że warunkiem koniecznym i dostatecznym
sklejaną. Ponieważ poszukiwana funkcja sklejana <math>\displaystyle s_f</math> ma
zbieżności tej iteracji dla dowolnego wektora startowego <math>\displaystyle x_0</math> jest
interpolować <math>\displaystyle f</math>, mamy dodatkowych <math>\displaystyle n+1</math> warunków
interpolacyjnych <math>\displaystyle w_i(x_i)=f(x_i)</math>, <math>\displaystyle 0\le i\le n-1</math>,
oraz <math>\displaystyle w_{n-1}(x_n)=f(x_n)</math>, z których


<center><math>\displaystyle  
<center><math>\displaystyle \rho = \max\{ |\lambda| : \lambda  \mbox{ jest wartością własną }  A\} < 1.
  a_i\,=\,f(x_i), \qquad 0\le i\le n-1.
</math></center>
</math></center>


Teraz możemy warunki ciągłości przepisać jako
Tak więc, metody oparte na iteracji prostej, będą zbieżne liniowo z ilorazem
 
<math>\displaystyle \rho</math>.
<center><math>\displaystyle f(x_{i+1})\,=\,f(x_i)+b_ih_i+c_ih_i^2+d_ih_i^3/6,
</math></center>


przy czym wzór ten zachodzi również dla <math>\displaystyle i=n-1</math>.
====Metoda Jacobiego====
Po wyrugowaniu <math>\displaystyle b_i</math> i podstawieniu <math>\displaystyle d_i</math> z ([[##dei|Uzupelnic: dei ]]),
mamy


<center><math>\displaystyle
[[grafika:Jacobi.jpg|thumb|right|| Jacobi<br> [[Biografia Jacobi|Zobacz biografię]]]]
  b_i\,=\,f(x_i,x_{i+1})+h_i(c_{i+1}+2c_i)/6,
  \qquad 0\le i\le n-1,
</math></center>


gdzie <math>\displaystyle f(x_i,x_{i+1})</math> jest odpowiednią różnicą
Biorąc <math>\displaystyle D = diag(A)</math>
dzieloną. Możemy teraz powyższe wyrażenie na <math>\displaystyle b_i</math>  
gdzie <math>\displaystyle diag(A)</math> jest macierzą diagonalną składającą się
podstawić, aby otrzymać
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


<center><math>\displaystyle c_ih_i/6+c_{i+1}(h_i+h_{i+1})/3+c_{i+1}h_{i+1}/6
<center><math>\displaystyle D x = Z x + b,
  \,=\,f(x_{i+1},x_{i+2})-f(x_i,x_{i+1}).
</math></center>
</math></center>


Wprowadzając oznaczenie
a stąd (o ile na przekątnej macierzy <math>\displaystyle A</math> nie mamy zera)
otrzymujemy metodę iteracyjną


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


możemy to równanie przepisać jako
gdzie <math>\displaystyle B=-D^{-1}Z</math> i <math>\displaystyle  c=D^{-1} b</math>, zwaną
 
<strong>metodą Jacobiego</strong>.
<center><math>\displaystyle \frac{h_i}{h_i+h_{i+1}}c_i^*\,+\,2\,c_{i+1}^*\,+\,
  \frac{h_{i+1}}{h_i+h_{i+1}}c_{i+2}^*\,=\,
  f(x_i,x_{i+1},x_{i+2}),
</math></center>


<math>\displaystyle 0\le i\le n-2</math>, albo w postaci macierzowej
W metodzie Jacobiego warunek dostateczny zbieżności,
<math>\displaystyle \|B\|<1</math>, jest spełniony np. wtedy, gdy macierz <math>\displaystyle A</math> ma
dominującą przekątną, tzn. gdy


<center><math>\displaystyle  
<center><math>\displaystyle  
   \left(\begin{array} {cccccc}
   |a_{i,i}|\,>\,\sum_{j\neq i}|a_{i,j}|,\qquad \forall i = 1,\ldots, N.
    2  & w_1 \\
  u_2 &  2  & w_2 \\
      & u_3 &  2    & w_3 \\
      &    &\ddots &\ddots  &\ddots \\
      &    &      & u_{n-2} &  2  & w_{n-2} \\
      &    &      &        & u_{n-1} &  2
    \end{array} \right)
  \left(\begin{array} {c}
    c_1^*\\ c_2^*\\ c_3^*\\ \vdots\\ c_{n-2}^*\\ c_{n-1}^*
      \end{array} \right) \,=\,
  \left(\begin{array} {c}
    v_1\\ v_2\\ v_3\\ \vdots\\ v_{n-2}\\ v_{n-1}
      \end{array} \right),
</math></center>
</math></center>


gdzie
Rzeczywiście, ponieważ wyraz <math>\displaystyle (i,j)</math> macierzy <math>\displaystyle D^{-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


<center><math>\displaystyle \aligned && u_i\,=\,\frac{h_{i-1}}{h_{i-1}+h_i},\qquad
<center><math>\displaystyle \aligned \lefteqn{\|D^{-1}Z\|_\infty \;=\; \max_{1\le i\le N}
    w_i\,=\,\frac{h_i}{h_{i-1}+h_i}, \\
  \sum_{j=1,j\ne i}^N{|a_{i,j}|}/{|a_{i,i}|} } \\  
  && v_i\,=\,f(x_{i-1},x_i,x_{i+1}).
    && =\;\max_{1\le i\le N}
      \sum_{j=1}^N{|a_{i,j}|}/{|a_{i,i}|}\,-\,1\;<\;1,
\endaligned</math></center>
\endaligned</math></center>


Ostatecznie, aby znaleźć współczynniki <math>\displaystyle a_i,b_i,c_i,d_i</math>
przy czym ostatnia nierówność wynika z warunku diagonalnej dominacji.  
należy najpierw rozwiązać układ równań liniowych,
a potem zastosować wzory definiujące pozostałe współczynniki.  


Zauważmy, że macierz układu równań liniowych jest
<div style="margin-top:1em; padding-top,padding-bottom:1em;">
trójdiagonalna i ma dominującą przekątną. Układ
<span  style="font-variant:small-caps;">Przykład: Macierz laplasjanu</span>  
można więc rozwiązać kosztem proporcjonalnym do
<div class="solution">
wymiaru <math>\displaystyle n</math> używając algorytmu przeganiania. Koszt znalezienia wszystkich
współczynników kubicznej funkcji sklejanej
interpolującej <math>\displaystyle f</math> jest więc też proporcjonalny do <math>\displaystyle n</math>.


Na końcu oszacujemy jeszcze błąd interpolacji naturalnymi
Macierz <math>\displaystyle N\times N</math>, zwana <strong>macierzą jednowymiarowego laplasjanu</strong>
kubicznymi funkcjami sklejanymi na przedziale <math>\displaystyle [a,b]</math>.
<center><math>\displaystyle  
Będziemy zakładać, że <math>\displaystyle f</math> jest dwa razy
L = \begin{pmatrix}
różniczkowalna w sposób ciągły.
2 & -1 &      &  \\
-1 & 2 & \ddots & \\
    & \ddots & \ddots & -1 \\
    &      &  -1 & 2
\end{pmatrix}
</math></center>


{{twierdzenie|||
pojawia się w bardzo wielu zastosowaniach, także jako podzadanie w algorytmach
J
numerycznych. Ta macierz jest macierzą taśmową, symetryczną i dodatnio
eśli <math>\displaystyle f\in F^1_M([a,b])</math> to
okresloną,  więc rozwiązanie układu równań z tą macierzą jest łatwe metodami
bezpośrednimi, kosztem <math>\displaystyle O(N)</math>. Ciekawe będzie, jak poradzą sobie z nią metody
iteracyjne.


<center><math>\displaystyle \|f-s_f\|_{C([a,b])}\,\le\,5\,M\,
Na przykład, w metodzie Jacobiego weźmiemy <math>\displaystyle D = 2I</math> oraz <math>\displaystyle Z = L - D</math>. Obliczając
      \max_{1\le i\le n}(x_i-x_{i-1})^2.
normę macierzy iteracji Jacobiego dostajemy <math>\displaystyle ||D^{-1}Z||_\infty
</math></center>
= 1</math>, co nie rozstrzyga jeszcze o jej (nie)zbieżności.


W szczególności, dla podziału równomiernego
Okazuje się, że są gotowe wzory na wartości własne macierzy <math>\displaystyle L</math>:
<math>\displaystyle x_i=a+(b-a)i/ń</math>, <math>\displaystyle 0\le i\le n</math>, mamy


<center><math>\displaystyle \|f-s_f\|_{ C([a,b])}\,\le\,
<center><math>\displaystyle \lambda_j = 4\sin^2 \left(\frac{j \pi }{2(N+1)} \right),
      5\,M\,\Big(\frac{b-a}n\Big)^2.
</math></center>
</math></center>


}}
dla <math>\displaystyle 1 \leq j \leq N.</math>


{{dowod|||
i w konsekwencji, wartościami własnymi <math>\displaystyle D^{-1}Z = \frac{1}{2}Z = \frac{1}{2}L -
Wykorzystamy obliczoną wcześniej 
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ę
postać interpolującej funkcji sklejanej <math>\displaystyle s_f</math>.  
zbieżna tak wolno, że w praktyce bezużyteczna.
Dla <math>\displaystyle x\in [x_i,x_{i+1}]</math> mamy
</div></div>


<center><math>\displaystyle \aligned w_i(x) &= f(x_i)\,+\,\left(\frac{f(x_{i+1})-f(x_i)}{h_i}
Zaletą stacjonarnych metod iteracyjnych jest również ich prostota,  
  -h_i(c_{i+1}^*+2c_i^*)\right)(x-x_i) \\ &&\qquad\qquad \,+\,
przez co są one łatwe do zaprogramowania.  
    3c_i^*(x-x_i)^2\,+\,\frac{c_{i+1}^*-c_i^*}{h_i}(x-x_i)^3.
\endaligned</math></center>


Z rozwinięcia <math>\displaystyle f</math> w szereg Taylora w punkcie <math>\displaystyle x_i</math> dostajemy
====Metoda Gaussa--Seidela====
<math>\displaystyle f(x)=f(x_i)+f'(x_i)(x-x_i)+f''(\xi_1)(x-x_i)^2/2</math> oraz
<math>\displaystyle (f(x_{i+1})-f(x_i))/h_i=f'(x_i)+h_if''(\xi_2)/2</math>. Stąd


<center><math>\displaystyle \aligned \lefteqn{f(x)-s_f(x) \,=\, f(x)-w_i(x)} \\
Ciekawostką jest, że Gauss nie miał z nią nic wspólnego, a Seidel był wręcz jej
  &= \frac{f''(\xi_1)}2(x-x_i)^2-\left(\frac{f''(\xi_2)}2
przeciwnikiem...
      -(c_{i+1}^*+2c_i^*)\right)h_i(x-x_i) \\
  & & \qquad\qquad\qquad -3c_i^*(x-x_i)^2
      -\frac{c_{i+1}^*-c_i^*}{h_i}(x-x_i)^3,
\endaligned</math></center>


oraz
====Złożoność stacjonarnych metod iteracyjnych====


<center><math>\displaystyle \aligned
Zastanówmy się teraz nad złożonością metod
  |f(x)-s_f(x)| &\le &(M+2|c_{i+1}^*|+6|c_i^*|)h_i^2 \\
iteracyjnych. Ponieważ możemy jedynie znaleźć pewne
    &= (M+8\max_{1\le i\le n-1}|c_i^*|)h_i^2.
przybliżenie rozwiązania dokładnego <math>\displaystyle  x^*</math>, przez
\endaligned</math></center>
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


Niech teraz <math>\displaystyle \max_{1\le i\le n-1}|c_i^*|=|c_s^*|</math>.
<center><math>\displaystyle \rho^k\| x_0- x^*\|\,\le\,\epsilon,
Z postaci układu ([[##ukltrd|Uzupelnic: ukltrd ]]) otrzymujemy
</math></center>


<center><math>\displaystyle \aligned |c_s^*| &= 2|c_s^*|-|c_s^*|(u_s+w_s) \,\le\,
czyli
    |u_sc_{s-1}^*+2c_s^*+w_sc_{s+1}| \\
  &= |f(x_{s-1},x_s,x_{s+1})|\,\le\,
      \Big|\frac{f''(\xi_3)}2\Big|\,\le\,\frac 12 M,
\endaligned</math></center>


a stąd i z ([[##psik|Uzupelnic: psik ]])
<center><math>\displaystyle k\,\ge\,\frac{\log(1/\epsilon)-
 
    \log(1/\| x_0- x^*\|)}{\log(1/\rho)}.
<center><math>\displaystyle |f(x)-s_f(x)|\,\le\,5Mh_i^2,
</math></center>
</math></center>


co kończy dowód.
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>
{{uwaga|||
i wymiaru <math>\displaystyle N</math> układu jest dużo mniej istotna (w zadaniach praktycznych -- takich jak jednowymiarowy laplasjan --- jednak
Zamiast terminu funkcje sklejane używa
często
się też często terminów ''splajny'' (ang.  
okazuje się, że... <math>\displaystyle \rho</math> zależy od <math>\displaystyle N</math>!).  
''spline''-sklejać), albo ''funkcje gięte''.
}}
 
{{uwaga|||


Niech
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


<center><math>\displaystyle W^r_M(a,b)\,=\,\Big\{\,f\in W^r(a,b):\,
<center><math>\displaystyle c(N)\,\frac{\log(1/\epsilon)}{\log(1/\rho)}.  
    \int_a^b\left(f^{(r)}(x)\right)^2\,dx\le M\,\Big\}.
</math></center>
</math></center>


Ustalmy węzły <math>\displaystyle a=x_0<\cdots<x_n=b</math>. Dla <math>\displaystyle f\in W^r_M(a,b)</math>,  
Stąd oczywisty wniosek, że metody iteracyjne warto
niech <math>\displaystyle s_f</math> będzie naturalną funkcją sklejaną
stosować zamiast metod bezpośrednich w przypadku gdy
interpolującą <math>\displaystyle f</math> w <math>\displaystyle x_j</math>, <math>\displaystyle 0\le j\le n</math>, a <math>\displaystyle a_f</math>
* wymiar <math>\displaystyle N</math> układu <math>\displaystyle A x= b</math> jest "duży", oraz
dowolną inną aproksymacją korzystającą jedynie
* macierz <math>\displaystyle A</math> układu jest "rozrzedzona", tzn. ma stosunkowo niewielką liczbę elementów  niezerowych, np. proporcjonalną do <math>\displaystyle N</math>.
z informacji o wartościach <math>\displaystyle f</math> w tych węzłach , tzn.
 
Układy o tych własnościach powstają często przy
numerycznym rozwiązywaniu równań różniczkowych
cząstkowych.  


<center><math>\displaystyle a_f\,=\,\phi(f(x_0),\ldots,f(x_n)).
==Metody przestrzeni Kryłowa==
</math></center>


Załóżmy, że błąd aproksymacji mierzymy nie w normie
Zupełnie inny pomysł na realizację metody iteracyjnej przedstawiają metody przestrzeni
Czebyszewa, ale w normie średniokwadratowej, zdefiniowanej
Kryłowa, gdzie kolejne przybliżenie <math>\displaystyle x_k</math> dobiera się w taki sposób by
jako
minimalizowało pewną miarę błędu na podprzestrzeni Kryłowa


<center><math>\displaystyle \|g\|_{{\cal L}_2(a,b)}\,=\,\sqrt{\int_a^b (g(x))^2\,dx}.
<center><math>\displaystyle K_k =  \mbox{span} \{r,A_r,\ldots, A^{k-1}r \},
</math></center>
</math></center>


Wtedy
gdzie <math>\displaystyle r = b-Ax_0</math> jest residuum na początku iteracji. 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 dwie najpopularniejsze: CG i GMRES.


<center><math>\displaystyle \sup_{f\in W^r_M(a,b)}\|f-s_f\|_{{\cal L}_2(a,b)}\,\le\,
====CG====
  \sup_{f\in W^r_M(a,b)}\|f-a_f\|_{{\cal L}_2(a,b)}.
</math></center>


Aproksymacja naturalnymi funkcjami sklejanymi jest więc
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>.
optymalna w klasie <math>\displaystyle W^r_M(a,b)</math>.  


Można również pokazać, że interpolacja <math>\displaystyle s_f^*</math>
Kolejne przybliżenie <math>\displaystyle x_k</math> ma minimalizować błąd w normie energetycznej
naturalnymi funkcjami sklejanymi na węzłach równoodległych
indukowanej przez <math>\displaystyle A</math>,
<math>\displaystyle x_j=a+(b-a)j/ń</math>, <math>\displaystyle 0\le j\le n</math>, jest optymalna co do
rzędu w klasie <math>\displaystyle W^r_M(a,b)</math>, wśród wszystkich aproksymacji
korzystających jedynie z informacji o wartościach funkcji
w <math>\displaystyle n+1</math> dowolnych punktach, oraz


<center><math>\displaystyle \max_{f\in W^r_M(a,b)}\|f-s^*_f\|_{{\cal L}_2(a,b)}
<center><math>\displaystyle ||x_k -x||_A =  \sqrt{(x_k -x)^TA(x_k -x)}
    \,\asymp\,n^{-r}.
</math></center>
</math></center>


}}
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:


{{uwaga|||
{{algorytm|||
 
<pre>
Tak jak wielomiany, naturalne
r = b-A*x;
funkcje sklejane interpolujące dane funkcje można
<math>\displaystyle \rho_{-1}</math> = 0; <math>\displaystyle \rho_0</math> = <math>\displaystyle ||r||_2^2</math>; <math>\displaystyle \beta</math> = 0; k = 1;
reprezentować przez ich współczynniki w różnych bazach.
while <math>\displaystyle \sim</math>STOP
Do tego celu można na przykład użyć bazy kanonicznej
{
<math>\displaystyle K_j</math>, <math>\displaystyle 0\le j\le n</math>, zdefiniowanej równościami
p = r + <math>\displaystyle \beta</math>*p;
 
w = A*p;
<center><math>\displaystyle K_j(x_i)\,=\,\left\{\begin{array} {ll}
<math>\displaystyle \alpha</math> = <math>\displaystyle \frac{\rho_{k-1}}{p^Tw}</math>;
        0 &\quad i\ne j, \\
x = x + <math>\displaystyle \alpha</math>*p;
        1 &\quad i=j, \end{array} \right.
r = r - <math>\displaystyle \alpha</math>*w;
</math></center>
<math>\displaystyle \rho_k</math> = <math>\displaystyle ||r||_2^2</math>;
 
<math>\displaystyle \beta</math> = <math>\displaystyle \frac{\rho_{k}}{\rho_{k-1}}</math>;
przy której <math>\displaystyle s_f(x)=\sum_{j=0}^n f(x_j)K_j(x)</math>. Baza
k++;
kanoniczna jest jednak niewygodna w użyciu, bo funkcje <math>\displaystyle K_j</math>  
}
w ogólności nie zerują się na żadnym podprzedziale,
</pre>}}
a tym samym manipulowanie nimi jest utrudnione.
 
Częściej używa się bazy B-sklejanej <math>\displaystyle B_j</math>, <math>\displaystyle 0\le j\le n</math>.
W przypadku funkcji kubicznych, <math>\displaystyle r=2</math>, jest ona zdefiniowana
przez następujące warunki:
 
<center><math>\displaystyle \aligned B_j(x_j) &= 1, \qquad \mbox{ dla  }  0\le j\le n, \\
    B_j(x) &= 0,\qquad \mbox{ dla  }  x\le x_{j-2}, j\ge 2,
      \mbox{  oraz  dla  }  x\ge x_{j+2}, j\le n-2. 
\endaligned</math></center>
 
Dla <math>\displaystyle B_0</math> i <math>\displaystyle B_1</math> dodatkowo żądamy, aby
 
<center><math>\displaystyle B_0''(x_0)\,=\,0\,=\,B_1''(x_0),\qquad B_1(x_0)\,=\,0,
</math></center>


a dla <math>\displaystyle B_{n-1}</math> i <math>\displaystyle B_n</math> podobnie
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.


<center><math>\displaystyle B_{n-1}''(x_n)\,=\,0\,=\,B_n''(x_n),
{{twierdzenie|Zbieżność CG jako metody bezpośredniej||
      \qquad B_{n-1}(x_{n-1})\,=\,0.
</math></center>


Wtedy <math>\displaystyle B_j</math> nie zeruje się tylko na przedziale
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.
<math>\displaystyle (x_{j-2},x_{j+2})</math>, Wyznaczenie współczynników
rozwinięcia w bazie <math>\displaystyle \{B_i\}_{i=0}^n</math> funkcji sklejanej
interpolującej <math>\displaystyle f</math> wymaga rozwiązania układu liniowego
z macierzą trójdiagonalną <math>\displaystyle \{B_j(x_i)\}_{i,j=0}^n</math>, a
więc koszt obliczenia tych współczynników jest
proporcjonalny do <math>\displaystyle n</math>.  
}}
}}


{{uwaga|||
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
Oprócz naturalnych funkcji
* 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ć.
sklejanych często rozpatruje się też ''okresowe funkcje
sklejane''. Są to funkcje <math>\displaystyle \tilde s:R\toR</math> spełniające
warunki '''(i)''', '''(ii)''' z Rozdziału [[##warfs|Uzupelnic: warfs ]], oraz
warunek:
 
; (iii)'
:  <math>\displaystyle \tilde s^{(i)}</math> jest dla <math>\displaystyle 0\le i\le r-1</math>  
funkcją okresową o okresie <math>\displaystyle (b-a)</math>, tzn.
<math>\displaystyle \tilde s^{(i)}(x)=\tilde s^{(i)}(x+(b-a))</math>, <math>\displaystyle \forall x</math>.  
   
   
Klasę okresowych funkcji sklejanych rzędu <math>\displaystyle r</math> oznaczymy
Dlatego wygodniej potraktować CG jako metodę iteracyjną. Zachodzi bowiem
przez <math>\displaystyle \widetilde{\cal S}_r</math>. Funkcje te mają podobne
własności jak naturalne funkcje sklejane. Dokładniej,
niech
 
<center><math>\displaystyle
  \tilde W^r(a,b)\,=\,\{\,f\in W^r(a,b):\,
    f^{(i)}(a)=f^{(i)}(b),\; 0\le i\le r-1\,\},
</math></center>


tzn. <math>\displaystyle \tilde W^r(a,b)</math> jest klasą funkcji z <math>\displaystyle W^r(a,b)</math>,
{{twierdzenie|Zbieżność CG jako metody iteracyjnej||
które można przedłużyć do funkcji, krórych wszystkie
pochodne do rzędu <math>\displaystyle r-1</math> włącznie są <math>\displaystyle (b-a)</math>-okresowe
na <math>\displaystyle R</math>. Wtedy dla dowolnej funkcji <math>\displaystyle f\in\tilde W^r(a,b)</math>
zerującej się w węzłach <math>\displaystyle x_j</math>, oraz dla dowolnej
<math>\displaystyle \tilde s\in\widetilde{\cal S}_r</math> mamy
 
<center><math>\displaystyle
  \int_a^b f^{(r)}(x)\tilde s^{(r)}(x)\,dx\,=\,0.
</math></center>


Jest to odpowiednik Lematu [[##bwazny|Uzupelnic: bwazny ]] w przypadku okresowym.
Po <math>\displaystyle k</math> iteracjach metody CG,  
W szczególności wynika z niego jednoznaczność
rozwiązania zadania interpolacyjnego dla okresowych
funkcji <math>\displaystyle f</math> (tzn. takich, że <math>\displaystyle f(a)=f(b)</math>), jak również
odpowiednia własność minimalizacyjna okresowych funkcji
sklejanych. Dokładniej, jeśli <math>\displaystyle f\in\tilde W^r(a,b)</math> oraz
<math>\displaystyle \tilde s_f\in\widetilde{\cal S}_r</math> interpoluje <math>\displaystyle f</math> w węzłach
<math>\displaystyle x_j</math>, <math>\displaystyle 0\le j\le n</math>, to


<center><math>\displaystyle \int_a^b \Big(  f^{(r)}(x)\Big)^2\,dx\,\ge\,
<center><math>\displaystyle ||x_k - x||_A \leq 2 \, \left( \frac{\sqrt{ \mbox{cond} (A)} - 1}{\sqrt{ \mbox{cond} (A)} +1}\right)^k \, ||x_0 - x||_A,
  \int_a^b \Big(\tilde s_f^{(r)}(x)\Big)^2\,dx.
</math></center>
</math></center>


gdzie <math>\displaystyle  \mbox{cond} (A) = ||A||_2||A^{-1}||_2</math>.
}}
}}


{{uwaga|||
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.


Klasyczne zadanie
====Prekondycjoning====
aproksymacyjne w przestrzeniach funkcji definiuje się
w następujący sposób.


Niech <math>\displaystyle F</math> będzie pewną przestrzenią liniową funkcji
Zbieżność wszystkich poznanych metod iteracyjnych zależu od własności
<math>\displaystyle f:[a,b]\toR</math>, w której określona została norma
spektralnych macierzy układu. Często w zastosowaniach pojawiające się macierze
<math>\displaystyle \|\cdot\|</math>. Niech <math>\displaystyle V_n\subset F</math> będzie podprzestrzenią
mają niekorzystne własności spektralne (np. bardzo duży wskaźnik uwarunkowania)
w <math>\displaystyle F</math> wymiaru <math>\displaystyle n</math>. Dla danej <math>\displaystyle f\in F</math>, należy znaleźć
przez co metody iteracyjne zbiegają na nich bardzo wolno.
funkcję <math>\displaystyle v_f\in F</math> taką, że


<center><math>\displaystyle \|f-v_f\|\,=\,\min_{v\in V_n}\|f-v\|.
Dlatego bardzo korzystne może być wstępne przetransformowanie układu
</math></center>


Okazuje się, że tak postawione zadanie ma rozwiązanie
<center><math>\displaystyle Ax = b
<math>\displaystyle v_f</math>, choć nie zawsze jest ono wyznaczone jednoznacznie,
zob. ćw. [[##rkl|Uzupelnic: rkl ]].
 
Jako przykład, rozpatrzmy <math>\displaystyle F=W^r(a,b)</math>. Utożsamiając
funkcje <math>\displaystyle f_1,f_2\in W^r(a,b)</math> takie, że
<math>\displaystyle f_1(x)-f_2(x) \in\Pi_{r-1}</math>, zdefiniujemy w <math>\displaystyle W^r(a,b)</math> normę
 
<center><math>\displaystyle \|f\|\,=\,\sqrt{\int_a^b\left(f^{(r)}(x)\right)^2\,dx}. 
</math></center>
</math></center>


Dla ustalonych węzłów <math>\displaystyle a=x_0<\cdots<x_n=b</math>, niech
z macierzą o niekorzystnych własnościach, do układu


<center><math>\displaystyle V_{n+1}\,=\,{\cal S}_r
<center><math>\displaystyle MAx = Mb,
</math></center>
</math></center>


będzie podprzestrzenią w <math>\displaystyle W^r(a,b)</math> naturalnych funkcji
gdzie macierz <math>\displaystyle MA</math> ma znacznie korzystniejsze własności z punktu widzenia
sklejanych rzędu <math>\displaystyle r</math> opartych węzłach <math>\displaystyle x_j</math>, <math>\displaystyle 0\le j\le n</math>.  
używanej metody
Oczywiście <math>\displaystyle  \mbox{dim} {\cal S}_r=n+1</math>, co wynika z
iteracyjnej.
jednoznaczności rozwiązania w <math>\displaystyle {\cal S}_r</math> zadania
Taką operację nazywamy <strong>prekondycjoningiem</strong>, a macierz <math>\displaystyle M</math> --- macierzą
interpolacji. Okazuje się, że wtedy optymalną dla
prekondycjonera.
<math>\displaystyle f\in W^r(a,b)</math> jest naturalna funkcja sklejana <math>\displaystyle s_f</math>  
interpolująca <math>\displaystyle f</math> w węzłach <math>\displaystyle x_j</math>, tzn.  


<center><math>\displaystyle \|f-s_f\|\,=\,\min_{s\in {\cal S}_r}\|f-s\|.  
Aby całość miała sens, macierz prekondycjonera <math>\displaystyle M</math> powinna:
</math></center>
* być łatwa w konstrukcji,
* 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>),
* 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
konstrukcji i tania w mnożeniu, ale nic nie polepsza, niestety...) oraz
<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
należy poszukiwać czegoś pośredniego, co niskim kosztem przybliża działanie
macierzy odwrotnej.


Rzeczywiście, ponieważ norma w przestrzeni <math>\displaystyle W^r(a,b)</math>
Dlatego jednym z powszechniej stosowanych rodzajów prekondycjonerów są oparte na
generowana jest przez iloczyn skalarny
zastosowaniu jednego kroku klasycznej metody iteracyjnej.


<center><math>\displaystyle (f_1,f_2)\,=\,
[[Image:MNpcgconv.png|thumb|450px|center|Zbieżność metody CG bez prekondycjonera oraz z prekondycjonerem
    \int_a^b f_1^{(r)}(x)f_2^{(r)}(x)\,dx,
opartym na jednej iteracji (blokowej) metody Jacobiego.]]
</math></center>


jest to przestrzeń unitarna. Znane twierdzenie mówi, że
Inne prekondycjonery stosują np. techniki tzw. niepełnego rozkładu macierzy,
w przestrzeni unitarnej najbliższą danej <math>\displaystyle f</math> funkcją
albo --- w specyficznych przypadkach --- tzw. metody wielosiatkowe.
w dowolnej domkniętej podprzestrzeni <math>\displaystyle V</math> jest rzut
prostopadły <math>\displaystyle f</math> na <math>\displaystyle V</math>, albo równoważnie, taka funkcja
<math>\displaystyle v_f\in V_{n+1}</math>, że iloczyn skalarny


<center><math>\displaystyle (f-v_f, v)\,=\,0, \qquad\forall v\in V.
Okazuje się, że zarówno CG jak i GMRES da się zaimplementować tak, by w jednej
</math></center>
iteracji było konieczne tylko jedno mnożenie przez macierz prekondycjonera.
 
W naszym przypadku, ostatnia równość jest równoważna
 
<center><math>\displaystyle \int_a^b(f-v_f)^{(r)}(x)s^{(r)}(x)\,dx\,=\,0,
    \quad\forall s\in{\cal S}_r.
</math></center>
 
To zaś jest na mocy Lematu [[##bwazny|Uzupelnic: bwazny ]] prawdą gdy <math>\displaystyle v_f</math>
interpoluje <math>\displaystyle f</math> w punktach <math>\displaystyle x_j</math>, czyli <math>\displaystyle v_f=s_f</math>.
 
Dodajmy jeszcze, że nie zawsze interpolacja daje najlepszą
aproksymację w sensie klasycznym, zob. ćw. [[##intkla|Uzupelnic: intkla ]].
}}

Wersja z 18:25, 1 wrz 2006

Wielkie układy równań liniowych

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.).

Przykład: Macierz z kolekcji Boeinga

Macierz sztywności dla modelu silnika lotniczego, wygenerowana swego czasu w 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).

Struktura niezerowych elementów macierzy bcsstk38.

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 MBEACXC

Dane pochodzą z serwisu MatrixMarket. Jest to niezbyt duża macierz, wymiaru 496×496, niesymetryczna, o elementach rzeczywistych. Źródłem tej macierzy jest pewien model ekonomiczny.

Struktura niezerowych elementów macierzy MBEACXC

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

Formaty 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 (AIJ)

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);

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, wygodnie 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.

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.

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, wymagający skądinąd specjalnego sposobu przechowywania macierzy, wykorzystyją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 tak często spotykane, że warto przytoczyć algorytm w całej okazałości --- popularnie zwany algorytmem przeganiania.

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

Stwierdzenie

Jeśli macierz A ma słabo dominującą przekątną, 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 fill-in 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: 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 (macierzy).

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ą 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 reorderingu , z których warto wymienić

  • przybliżone algorytmy minimalnego stopnia approximate minimum degree (AMD)
  • techniki

podziału grafów na (prawie) rozłączne składowe (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: Wypełnienie pewnej macierzy w zależności od użytego algorytmu

Rozważmy macierz pochodzącą z kolekcji Tima Davisa, dotyczącą pewnego zadania mechaniki strukturalnej jakie pojawiło się u Boeinga. Jest to macierz symetryczna, dodatnio określona, wymiaru 8032.

Struktura niezerowych elementów macierzy.

Jest to macierz silnie rozrzedzona, ponieważ ma tylko 355460 niezerowych elementów (czyli wypełnienie to tylko 0.5 procent).

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 algorytm oparty na podziale grafu na prawie rozłączne składowe mógłby tu jeszcze lepiej zadziałać.

Stacjonarne metody iteracyjne

Gdy macierz jest rozrzedzona, mnożenie takiej macierzy przez wektor jest 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ń Dodaj link: 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 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ą A}<1.

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

Metoda Jacobiego

Plik:Jacobi.jpg
Jacobi
Zobacz biografię

Biorąc D=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

Dx=Zx+b,

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

xk=Bxk1+c,

gdzie B=D1Z i c=D1b, zwaną metodą 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.

Rzeczywiście, ponieważ wyraz (i,j) macierzy D1Z 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{\|D^{-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 okresloną, więc rozwiązanie układu równań z tą macierzą jest łatwe metodami bezpośrednimi, kosztem O(N). Ciekawe będzie, jak poradzą sobie z nią metody iteracyjne.

Na przykład, w metodzie Jacobiego weźmiemy D=2I oraz Z=LD. Obliczając normę macierzy iteracji Jacobiego dostajemy ||D1Z||=1, co nie rozstrzyga jeszcze o jej (nie)zbieżności.

Okazuje się, że są gotowe wzory na wartości własne macierzy L:

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

dla 1jN.

i w konsekwencji, wartościami własnymi D1Z=12Z=12LI są liczby μi=12λi1. Ponieważ 0<μi<1, oraz ||Z||2=1O(N2)<0 to metoda, choć zbieżna, dla dużych N staje się zbieżna tak wolno, że w praktyce bezużyteczna.

Zaletą stacjonarnych metod iteracyjnych jest również ich prostota, przez co są one łatwe do zaprogramowania.

Metoda Gaussa--Seidela

Ciekawostką jest, że Gauss nie miał z nią nic wspólnego, a Seidel był wręcz jej przeciwnikiem...

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, ż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. 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 dwie najpopularniejsze: CG i GMRES.

CG

Metoda gradientów sprzężonych conjugate gradients (CG) 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


r = b-A*x;
<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 <math>\displaystyle \sim</math>STOP
{
	p = r + <math>\displaystyle \beta</math>*p;
	w = A*p;
	<math>\displaystyle \alpha</math> = <math>\displaystyle \frac{\rho_{k-1}}{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 Zbieżność 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 flν skończonej precyzji ortogonalność z której korzysta się przy wyprowadzeniu algorytmu nie jest zachowana 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.

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.

Prekondycjoning

Zbieżność wszystkich poznanych metod iteracyjnych zależu od własności spektralnych macierzy układu. Często w zastosowaniach pojawiające się macierze 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. Taką operację nazywamy prekondycjoningiem, a macierz M --- macierzą prekondycjonera.

Aby całość miała sens, macierz prekondycjonera 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 prekondycjonera to M=I (łatwa w konstrukcji i tania w mnożeniu, ale nic nie polepsza, niestety...) 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 rodzajów prekondycjonerów są oparte na zastosowaniu jednego kroku klasycznej metody iteracyjnej.

Zbieżność metody CG bez prekondycjonera oraz z prekondycjonerem opartym na jednej iteracji (blokowej) metody Jacobiego.

Inne prekondycjonery stosują 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 prekondycjonera.