MN05LAB: Różnice pomiędzy wersjami
m MN Ćwiczenia 5 moved to MN05LAB |
m Zastępowanie tekstu – „,↵</math>” na „</math>,” |
||
(Nie pokazano 7 wersji utworzonych przez 3 użytkowników) | |||
Linia 1: | Linia 1: | ||
<!-- | <!-- | ||
Konwertowane z pliku LaTeX przez latex2mediawiki, zob. http://www.ii.uj.edu.pl/ pawlik1/latex2mediawiki.php | Konwertowane z pliku LaTeX przez latex2mediawiki, zob. http://www.ii.uj.edu.pl/ pawlik1/latex2mediawiki.php. | ||
Niezb�dne rozszerzenia i modyfikacje oryginalnego latex2mediawiki | |||
wprowadzi� przykry@mimuw.edu.pl | |||
--> | --> | ||
= | =Rozwiązywanie układów równań liniowych= | ||
{{powrot |Metody numeryczne | do strony głównej | |||
przedmiotu <strong>Metody numeryczne</strong>}} | |||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"> | |||
Oglądaj wskazówki i rozwiązania __SHOWALL__<br> | |||
Ukryj wskazówki i rozwiązania __HIDEALL__ | |||
</div> | |||
<div style="margin-top:1em; padding-top,padding-bottom:1em;"> | |||
<span style="font-variant:small-caps;">Uwaga</span> | |||
<div class="solution" style="margin-left,margin-right:3em;"> | |||
Niektóre fragmenty zadań wymagają wykorzystania procedur LAPACKa; te części odłóż do momentu, gdy opanujesz następny wykład, dotyczący m.in. [[MN06#BLAS, LAPACK i ATLAS|bibliotek algebry liniowej]]. | |||
</div></div> | |||
<div style="margin-top:1em; padding-top,padding-bottom:1em;"> | |||
<span style="display: block; background-color:#fefeee; border-bottom: 1px solid #E5E5E5; line-height: 1.1em; padding-bottom: 0.2em; font-variant:small-caps; color:#1A6ABF;">Ćwiczenie: Metoda Cholesky'ego</span> | |||
<div class="exercise"> | |||
Ważnym przykładem macierzy | |||
szczególnej postaci są macierze <strong>symetryczne i dodatnio określone</strong>. | |||
Są to macierze spełniające warunki: | |||
<center><math>A=A^T \qquad \mbox{oraz} \qquad x^T A x\,>\,0,\quad\forall x\ne 0</math></center> | |||
Dla takich macierzy można nieco zmniejszyć koszt kombinatoryczny | |||
i zużycie pamięci, przeprowadzając trochę inny rozkład na macierze trójkątne: | |||
tak, aby otrzymać | |||
rozkład | |||
<center><math>A\,=\,L\, D\, L^T | |||
</math></center> | |||
zamiast <math>PA=LU</math>, przy czym <math>L</math> jest tu jak zwykle macierzą | |||
trójkątną dolną z jedynkami na przekątnej, a <math>D</math> jest macierzą | |||
diagonalną z dodatnimi elementami na diagonali. Opracuj taki algorytm. W jego | |||
implementacji możesz porównywać się z procedurą LAPACKa <code style="color: #903">DPOSV</code>. | |||
Inny wariant tego samego | |||
rozkładu to tak zwany rozkład <strong>Cholesky'ego--Banachiewicza</strong>, w którym, przy tych | |||
samych założeniach na <math>A</math>, szukamy rozkładu wykorzystującego tylko jedną macierz | |||
trójkątną dolną: | |||
<center><math>A\,=\,\widetilde{L}\, \widetilde{L}^T</math>,</center> | |||
(oczywiście tym razem nie żądamy, aby <math>\widetilde{L}</math> miała na diagonali jedynki). | |||
Jaka jest relacja między rozkładem <math>LDL^T</math> a <math>\widetilde{L}\widetilde{L}^T</math>? | |||
</div></div> | |||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"><div style="margin-left:1em"> | |||
Bez zmniejszenia ogólności rozpatrzymy | |||
tylko pierwszy krok rozkładu <math>LDL^T</math>. W tym celu zauważmy najpierw, że | |||
<math>a_{1,1}= e_1^TA e_1>0</math> (gdzie <math>e_1</math> jest pierwszym | |||
wersorem), a więc nie musimy przestawiać wierszy, | |||
bo element na diagonali jest niezerowy. W pierwszym kroku mnożymy | |||
macierz <math>A</math> z lewej strony przez odpowiednią macierz <math>L_1</math>, a potem | |||
z prawej przez <math>L_1^T</math>. Kluczem do zrozumienia algorytmu jest uwaga, | |||
że efektem mnożenia macierzy <math>L_1 A</math> z prawej strony przez <math>L_1^T</math> | |||
jest wyzerowanie elementów pierwszego wiersza poza <math>a_{1,1}</math> | |||
i pozostawienie niezmienionych pozostałych elementów. Ponadto | |||
macierz <math>A^{(1)}=L_1 AL_1^T</math> jest symetryczna i dodatnio określona. | |||
Rzeczywiście, | |||
<center><math>\Big(A^{(1)}\Big)^T\,=\,(L_1AL_1^T)^T | |||
\,=\,(L_1^T)^TA^TL_1^T\,=\,L_1AL_1^T, | |||
</math></center> | |||
oraz dla <math>x\ne 0</math> | |||
<center><math>x^T A^{(1)} x\,=\, x^T L_1 A L_1^T x | |||
\,=\,(L_1^T x)^T A(L_1^T x)\,>\,0</math>,</center> | |||
bo <math>x\ne 0</math> implikuje <math>L_1^T x\ne 0</math>. Stąd | |||
<math>a^{(1)}_{2,2}= e_2^TA^{(1)} e_2>0</math>. Postępując tak | |||
dalej otrzymujemy | |||
<center><math>L_{n-1}L_{n-2}\cdots L_2L_1AL_1^TL_2^T\cdots L_{n-2}^TL_{n-1}^T | |||
\,=\,D</math>,</center> | |||
przy czym macierz <math>D</math> jest diagonalna i dodatnio określona, | |||
a więc wyrazy na diagonali są dodatnie. Oznaczając | |||
<center><math>L\,=\,L_1^{-1}L_2^{-1}\cdots L_{n-1}^{-1} | |||
</math></center> | |||
dostajemy żądany rozkład. | |||
Zauważmy, że przy praktycznej realizacji rozkładu <math>A=LDL^T</math> | |||
wystarczy modyfikować jedynie wyrazy pod i na głównej przekątnej | |||
macierzy wyjściowej ponieważ, jak zauważyliśmy, wszystkie kolejne | |||
macierze <math>A^{(k)}</math> są symetryczne. Pozwala to zmniejszyć --- w stosunku do | |||
rozkładu LU --- koszt | |||
obliczeniowy o połowę, do <math>2n^3/3</math> operacji arytmetycznych i zmieścić czynniki | |||
rozkładu w pamięci przeznaczonej na przechowywanie istotnych elementów <math>A</math> | |||
(czyli w dolnym trójkącie macierzy). | |||
Oczywiście, <math>\widetilde{L} = L \sqrt{D}</math>. | |||
</div></div></div> | |||
<div style="margin-top:1em; padding-top,padding-bottom:1em;"> | <div style="margin-top:1em; padding-top,padding-bottom:1em;"> | ||
Linia 10: | Linia 110: | ||
<div class="exercise"> | <div class="exercise"> | ||
W Octave układ równań <math> | W Octave układ równań <math>Ax=b</math> rozwiązujemy korzystając z "operatora | ||
rozwiązywania równania" | rozwiązywania równania" | ||
<div | <div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>x = A \ b; | ||
</pre></div> | |||
Ale w Octave jest także funkcja <code style="color: #006">inv</code>, wyznaczająca macierz | |||
odwrotną, więc niektóre (nie najlepsze, oględnie mówiąc) podręczniki zalecają | odwrotną, więc niektóre (nie najlepsze, oględnie mówiąc) podręczniki zalecają | ||
<div | <div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>x = inv(A)*b; | ||
</pre></div> | |||
x = inv(A)*b; | |||
</pre></div> | |||
Przedyskutuj, które podejście jest lepsze i dlaczego. Przeprowadź eksperymenty | Przedyskutuj, które podejście jest lepsze i dlaczego. Przeprowadź eksperymenty | ||
numeryczne weryfikujące | numeryczne weryfikujące twoją tezę. | ||
</div></div> | </div></div> | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"><div style="margin-left:1em"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"><div style="margin-left:1em"> | ||
Wyznaczenie <math> | Wyznaczenie <math>A^{-1}</math> praktycznie nigdy nie jest konieczne w obliczeniach, a | ||
zwłaszcza do rozwiązania układu równań. Nie dość, że jest bardziej kosztowne, to | zwłaszcza do rozwiązania układu równań. Nie dość, że jest bardziej kosztowne, to | ||
dodatkowo nie jest numerycznie poprawne. | dodatkowo nie jest numerycznie poprawne. | ||
Przykładowy test mógłby wyglądać | Przykładowy test mógłby wyglądać jak poniżej. Duże macierze losowe są | ||
zazwyczaj dobrze uwarunkowane | zazwyczaj dobrze uwarunkowane. | ||
<div | <div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>N = 400; A = rand(N,N);x = rand(N,1); b = A*x; | ||
N = 400; A = rand(N,N);x = rand(N,1); b = A*x; | |||
tic; X = A \ b; tX = toc; | tic; X = A \ b; tX = toc; | ||
tic; Y = inv(A)*b; tY = toc; | tic; Y = inv(A)*b; tY = toc; | ||
[norm(X-x)/norm(x), norm(Y-x)/norm(x); tX, tY] | [norm(X-x)/norm(x), norm(Y-x)/norm(x); tX, tY] | ||
</pre></div | </pre></div> | ||
ans = | <div style="font-family: monospace; white-space: pre; border-style: dashed; border-width: thin; border-color: black; margin: 1em; padding:1em; color: #444; background-color:#fdfdfd;"><nowiki>ans = | ||
1.9861e-13 2.8687e-13 | 1.9861e-13 2.8687e-13 | ||
2.3644e-01 4.0609e-01 | 2.3644e-01 4.0609e-01 | ||
</ | </nowiki></div> | ||
Wyszło (z grubsza) dwa razy szybciej i dwa razy dokładniej. | Wyszło (z grubsza) dwa razy szybciej i dwa razy dokładniej. | ||
Linia 62: | Linia 153: | ||
Rozwiąż prosty układ równań | Rozwiąż prosty układ równań | ||
<center><math>\ | <center><math>\begin{align} 10^{-18} x_1 + x_2 &= 1,\\ | ||
x_1 + 2x_2 &= 4, | x_1 + 2x_2 &= 4, | ||
\ | \end{align}</math></center> | ||
czterema sposobami: | czterema sposobami: | ||
Linia 70: | Linia 161: | ||
* w komputerze, w arytmetyce podwójnej precyzji, korzystając z rozkładu LU <strong>bez wyboru elementu głównego</strong> | * w komputerze, w arytmetyce podwójnej precyzji, korzystając z rozkładu LU <strong>bez wyboru elementu głównego</strong> | ||
* jak poprzednio, ale <strong>z wyborem elementu głównego w kolumnie</strong> | * jak poprzednio, ale <strong>z wyborem elementu głównego w kolumnie</strong> | ||
* w LAPACKu lub Octave. | * w [http://www.netlib.org/lapack LAPACKu] lub Octave. | ||
Porównaj uzyskane rozwiązania i wyciągnij wnioski. | Porównaj uzyskane rozwiązania i wyciągnij wnioski. | ||
Linia 76: | Linia 167: | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"><div style="margin-left:1em"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"><div style="margin-left:1em"> | ||
Rozwiązanie uzyskane bez wyboru elementu głównego jest bardzo mało precyzyjne <math> | Rozwiązanie uzyskane bez wyboru elementu głównego jest bardzo mało precyzyjne: <math>x_1</math> jest obarczone bardzo dużym błędem! Prosta analiza pokazuje, że winę za to ponosi bardzo wielki współczynnik w macierzy <math>L</math>. Tak nie jest, gdy stosujemy wybór elementu: elementy <math>L</math> są zawsze mniejsze od 1. Dlatego LAPACK i Octave dają w przypadku naszej macierzy rezultat będący bardzo dobrym przybliżeniem wyniku dokładnego. | ||
</div></div></div> | </div></div></div> | ||
Linia 86: | Linia 177: | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka </span><div class="mw-collapsible-content" style="display:none"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka </span><div class="mw-collapsible-content" style="display:none"> | ||
<div style="font-size:smaller; background-color:# | <div style="font-size:smaller; background-color:#f9fff9; padding: 1em"> Pamiętaj, pętle w Octave wykonują się bardzo wolno! </div> | ||
</div></div> | </div></div> | ||
Wykorzystaj go do napisania funkcji, która rozwiąże układ równań <math> | Wykorzystaj go do napisania funkcji, która rozwiąże układ równań <math>Ax=b</math>. | ||
Przetestuj tę funkcję na kilku macierzach i porównaj czas jego działania z czasem | Przetestuj tę funkcję na kilku macierzach i porównaj czas jego działania z czasem | ||
wykonania operacji <code>x = A\b</code>. | wykonania operacji <code style="color: #006">x = A\b</code>. | ||
Spróbuj zastosować swój algorytm do kilku specjalnych macierzy: | Spróbuj zastosować swój algorytm do kilku specjalnych macierzy: | ||
Linia 103: | Linia 194: | ||
Najprostszy wariant to po prostu przepisanie algorytmu z wykładu, który już | Najprostszy wariant to po prostu przepisanie algorytmu z wykładu, który już | ||
nawet trochę wykorzystywał notację dwukropkową MATLABa: | nawet trochę wykorzystywał notację dwukropkową MATLABa: | ||
<div | <div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>function [L,U] = lufa(A) | ||
# Na początku warto dodać trochę sprawdzania danych: czy A jest kwadratowa? | |||
function [L,U] = lufa(A) | # Czy jest macierzą? Te linie pozostawiamy twojej inwencji | ||
# Na początku warto dodać trochę sprawdzania danych: czy A jest kwadratowa? | |||
# | |||
N = size(A,1); | N = size(A,1); | ||
Linia 114: | Linia 203: | ||
return; | return; | ||
end | end | ||
for i=k+1:N #wyznaczenie <math> | for i=k+1:N #wyznaczenie <math>k</math>-tej kolumny <math>L</math> | ||
A(i,k) = A(i,k)/A(k,k); | A(i,k) = A(i,k)/A(k,k); | ||
end | end | ||
for j=k+1:N #modyfikacja podmacierzy <math> | for j=k+1:N #modyfikacja podmacierzy <math>A_{22} = A_{22} - l_{21}u_{12}^T</math> | ||
for i=k+1:N | for i=k+1:N | ||
A(i,j) -= A(i,k)*A(k,j); | A(i,j) -= A(i,k)*A(k,j); | ||
Linia 126: | Linia 215: | ||
U = triu(A); | U = triu(A); | ||
end | end | ||
</pre></div> | </pre></div> | ||
Jednak w tej implementacji mamy do czynienia z nawet | Jednak w tej implementacji mamy do czynienia z nawet potrójnie zagnieżdżonymi | ||
pętlami, co dla nawet średnich <math> | pętlami, co dla nawet średnich <math>N</math> może być powodem sporego spowolnienia | ||
algorytmu. Warto więc uniknąć pętli, odwołując się do instrukcji wektorowych i | algorytmu. Warto więc uniknąć pętli, odwołując się do instrukcji wektorowych i | ||
blokowych. | blokowych. | ||
<div | <div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>function [L,U] = lufb(A) | ||
function [L,U] = lufb(A) | |||
# Na początku warto dodać trochę sprawdzania danych: czy A jest kwadratowa? a w ogóle, | # Na początku warto dodać trochę sprawdzania danych: czy A jest kwadratowa? a w ogóle, | ||
# czy jest macierzą? te linie pozostawiamy inwencji Czytelnika | # czy jest macierzą? te linie pozostawiamy inwencji Czytelnika | ||
Linia 144: | Linia 231: | ||
return; | return; | ||
end | end | ||
#wyznaczenie <math> | #wyznaczenie <math>k</math>-tej kolumny <math>L</math> | ||
A(k+1:N,k) = A(k+1:N,k)/A(k,k); | A(k+1:N,k) = A(k+1:N,k)/A(k,k); | ||
#modyfikacja podmacierzy <math> | #modyfikacja podmacierzy <math>A_{22} = A_{22} - l_{21}u_{12}^T</math> | ||
A(k+1:N,k+1:N) -= A(k+1:N,k)*A(k,k+1:N); | A(k+1:N,k+1:N) -= A(k+1:N,k)*A(k,k+1:N); | ||
end | end | ||
Linia 152: | Linia 239: | ||
U = triu(A); | U = triu(A); | ||
end | end | ||
</pre></div> | </pre></div> | ||
<div | <div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>[Kod testujący lufa(0 i lufb()] | ||
N = 100; | N = 100; | ||
A = rand(N) + 1000*eye(N); | A = rand(N) + 1000*eye(N); | ||
Linia 175: | Linia 261: | ||
disp("Błąd:"); | disp("Błąd:"); | ||
[norm(L*U - A,inf), norm(La*Ua - A,inf), norm(Lb*Ub - A,inf)] | [norm(L*U - A,inf), norm(La*Ua - A,inf), norm(Lb*Ub - A,inf)] | ||
</pre></div> | </pre></div> | ||
Dla macierzy wymiaru <math> | Dla macierzy losowych wymiaru <math>N=100</math> dostaliśmy na Pentium 1.5GHz | ||
{| border=1 | {| border=1 | ||
Linia 186: | Linia 272: | ||
| Czas (s) || 4.0436e-03 || 1.5877e+01 || 1.0767e-01 | | Czas (s) || 4.0436e-03 || 1.5877e+01 || 1.0767e-01 | ||
|- | |- | ||
| Błąd <math> | | Błąd <math>||LU-A||_\infty</math> || 3.4596e-13 || 8.0747e-13 || 8.0747e-13 | ||
|} | |} | ||
Zwróć uwagę na charakterystyczne fakty: | Zwróć uwagę na charakterystyczne fakty: | ||
* Usunięcie wewnętrznych pętli stukrotnie(!) przyspieszyło <code>lufb</code> w | * Usunięcie wewnętrznych pętli stukrotnie(!) przyspieszyło <code style="color: #006">lufb</code> w | ||
stosunku do <code>lufa</code> | stosunku do <code style="color: #006">lufa</code> | ||
* Gotowa funkcja Octave wciąż jest stukrotnie(!) szybsza od mojej | * Gotowa funkcja Octave wciąż jest stukrotnie(!) szybsza od mojej | ||
najszybszej funkcji. | najszybszej funkcji. | ||
Linia 199: | Linia 285: | ||
nawet lepiej napisać implementację wykonującą więcej obliczeń, ale korzystającą | nawet lepiej napisać implementację wykonującą więcej obliczeń, ale korzystającą | ||
w większm stopniu z wbudowanych funkcji Octave, niż napisać samemu implementację | w większm stopniu z wbudowanych funkcji Octave, niż napisać samemu implementację | ||
liczącą mniej, ale korzystającą z licznych instrukcji <code>for...</code> i podobnych. | liczącą mniej, ale korzystającą z licznych instrukcji <code style="color: #006">for...</code> i podobnych. | ||
Innym sposobem przyspieszenia działania funkcji Octave jest ich prekompilacja. | Innym sposobem przyspieszenia działania funkcji Octave jest ich prekompilacja. | ||
Linia 205: | Linia 291: | ||
wykracza poza zakres naszego kursu. | wykracza poza zakres naszego kursu. | ||
Funkcja wykorzystująca gotowy rozkład LU do rozwiązania układu <math> | Funkcja wykorzystująca gotowy rozkład LU do rozwiązania układu <math>Ax=b</math> w MATLABie miałaby postać | ||
<div | <div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>function x = sol(L,U,b) | ||
function x = sol(L,U,b) | |||
x = U \ ( L \ b); | x = U \ ( L \ b); | ||
end | end | ||
</pre></div> | </pre></div> | ||
gdyż MATLAB prawidłowo rozpoznaje układy z macierzą trójkątną i stosuje szybszy | gdyż MATLAB prawidłowo rozpoznaje układy z macierzą trójkątną i stosuje szybszy | ||
algorytm. | algorytm. | ||
[[ | Jeśli chodzi o popełnione błędy dla macierzy Hilberta, wyjaśnienie znajdziesz w wykładzie [[MN07|o uwarunkowaniu układu równań liniowych]]. | ||
</div></div></div> | </div></div></div> | ||
Linia 254: | Linia 309: | ||
<div class="exercise"> | <div class="exercise"> | ||
Podaj sposób taniego wyznaczenia rozwiązania sekwencji <math> | Podaj sposób taniego wyznaczenia rozwiązania sekwencji <math>k<N</math> układów równań z tą | ||
samą macierzą <math> | samą macierzą <math>A\in R^{N\times N}</math> i różnymi prawymi stronami: | ||
<center><math> | <center><math> | ||
Ax_i = b_i, \qquad i = 1,\ldots,k | Ax_i = b_i, \qquad i = 1,\ldots,k</math></center> | ||
</math></center> | |||
Układy równań z tą samą macierzą, ale ze zmieniającą się prawą stroną równania | Układy równań z tą samą macierzą, ale ze zmieniającą się prawą stroną równania | ||
powstają często przy rozwiązywaniu | powstają często na przykład przy rozwiązywaniu równań różniczkowych cząstkowych, gdzie prawa strona układu odpowiada zmieniającym się warunkom brzegowym. | ||
gdzie prawa strona układu odpowiada zmieniającym się warunkom brzegowym. | |||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka </span><div class="mw-collapsible-content" style="display:none"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka </span><div class="mw-collapsible-content" style="display:none"> | ||
<div style="font-size:smaller; background-color:# | <div style="font-size:smaller; background-color:#f9fff9; padding: 1em"> Wystarczy tylko <strong>jeden raz</strong> wyznaczyć rozkład LU macierzy <math>A</math> </div> | ||
</div></div> | </div></div> | ||
Linia 271: | Linia 324: | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"><div style="margin-left:1em"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"><div style="margin-left:1em"> | ||
No tak, oczywiście | No tak, oczywiście wystarczy | ||
wystarczy | |||
{{algorytm||| | {{algorytm||| | ||
<pre> | <pre>Znajdź rozkład <math>PA = LU</math>; | ||
Znajdź rozkład <math> | Utwórz macierz <math>B = [b_1,\ldots,b_k]</math>; | ||
Utwórz macierz <math> | Rozwiąż <math>LY = B</math>; | ||
Rozwiąż <math> | Rozwiąż <math>UX = Y</math>; | ||
Rozwiąż <math> | |||
</pre>}} | </pre>}} | ||
Rozwiązanie każdego z układów <math> | Rozwiązanie każdego z układów <math>LY = B</math> i <math>UX = Y</math> można przyspieszyć, tworząc | ||
warianty algorytmów podstawienia w przód i w tył, operujące od razu na wszystkich kolumnach macierzy <math> | warianty algorytmów podstawienia w przód i w tył, operujące od razu na wszystkich kolumnach macierzy <math>B</math>. Zaimplementowano je w [http://www.netlib.org/lapack LAPACKu], w tandemie | ||
funkcji <code>DGETRF</code> (rozkład) i <code>DGETRS</code> (rozwiązanie) oraz w | funkcji <code style="color: #903">DGETRF</code> (rozkład) i <code style="color: #903">DGETRS</code> (rozwiązanie) oraz w | ||
<code | <code style="color: #903">DGESV</code>, łączącej funkcjonalność obu. | ||
</div></div></div> | </div></div></div> | ||
Linia 381: | Linia 344: | ||
Bardzo rzadko w praktyce numerycznej zdarza się potrzeba obliczenia wartości | Bardzo rzadko w praktyce numerycznej zdarza się potrzeba obliczenia wartości | ||
wyznacznika macierzy <math> | wyznacznika macierzy <math>A \in R^{N \times N}</math>. Zaproponuj metodę obliczania | ||
<math> | <math>\mbox{det} (A)</math> oraz wskaż, jakiego rodzaju problemy numeryczne możesz napotkać. | ||
</div></div> | </div></div> | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"><div style="margin-left:1em"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"><div style="margin-left:1em"> | ||
Wystarczy wykonać rozkład <math> | Wystarczy wykonać rozkład <math>PA=LU</math>. Wtedy | ||
<center><math> | <center><math>\mbox{det} A\,=\,(-1)^p u_{11}u_{22}\cdots u_{nn}, | ||
</math></center> | </math></center> | ||
gdzie <math> | gdzie <math>p</math> jest liczbą przestawień wierszy w eliminacji. Tak więc, koszt | ||
obliczenia wyznacznika to <math> | obliczenia wyznacznika to <math>O(N^3)</math>. | ||
Kłopoty numeryczne możemy mieć z reprezentacją samej wartości wyznacznika w | Kłopoty numeryczne możemy mieć z reprezentacją samej wartości wyznacznika w | ||
arytmetyce zmiennoprzecinkowej. Ponieważ | arytmetyce zmiennoprzecinkowej. Ponieważ | ||
<center><math> | <center><math>\mbox{det} (cA) = c^N A</math>,</center> | ||
</math></center> | |||
to dość łatwo będzie trafić (przy większych niż średnich wartościach <math> | to dość łatwo będzie trafić (przy większych niż średnich wartościach <math>N</math>) na wartości wyznacznika, które będą albo potwornie duże, albo potwornie małe. Zresztą, zrób eksperyment: | ||
wyznacznika, które będą albo potwornie duże, albo potwornie małe. Zresztą, zrób | |||
eksperyment: | |||
Najpierw z losową macierzą <math> | Najpierw z losową macierzą <math>100\times 100</math> i jej krotnościami... | ||
<div | <div style="font-family: monospace; white-space: pre; border-style: dashed; border-width: thin; border-color: black; margin: 1em; padding:1em; color: #444; background-color:#fdfdfd;"><nowiki>octave:26> A=rand(100); | ||
octave:26> A=rand(100); | |||
octave:27> det(A) | octave:27> det(A) | ||
ans = -7.5240e+24 | ans = -7.5240e+24 | ||
Linia 417: | Linia 375: | ||
octave:30> det(1000*A) | octave:30> det(1000*A) | ||
ans = -Inf | ans = -Inf | ||
</ | </nowiki></div> | ||
oraz z coraz większymi macierzami losowymi: | oraz z coraz większymi macierzami losowymi: | ||
<div | <div style="font-family: monospace; white-space: pre; border-style: dashed; border-width: thin; border-color: black; margin: 1em; padding:1em; color: #444; background-color:#fdfdfd;"><nowiki>octave:32> det(rand(100)) | ||
octave:32> det(rand(100)) | |||
ans = 4.3751e+25 | ans = 4.3751e+25 | ||
octave:33> det(rand(400)) | octave:33> det(rand(400)) | ||
Linia 429: | Linia 385: | ||
octave:34> det(rand(800)) | octave:34> det(rand(800)) | ||
ans = -Inf | ans = -Inf | ||
</ | </nowiki></div> | ||
Można sobie z | Można sobie z | ||
tym poradzić, szacując wpierw rząd wielkości wyznacznika, a następnie | tym poradzić, szacując wpierw rząd wielkości wyznacznika, a następnie | ||
reprezentując jego wartość w formie cecha--mantysa, np. jako parę liczb <math> | reprezentując jego wartość w formie cecha--mantysa, np. jako parę liczb <math>m,c</math> | ||
takich, że <math> | takich, że <math>\mbox{det} (A) = m\cdot 10^c</math>, ale | ||
dopasowując obie tak, by nie nastąpił ani nadmiar, ani niedomiar. | dopasowując obie tak, by nie nastąpił ani nadmiar, ani niedomiar. | ||
</div></div></div> | </div></div></div> |
Aktualna wersja na dzień 21:45, 11 wrz 2023
Rozwiązywanie układów równań liniowych
<<< Powrót do strony głównej przedmiotu Metody numeryczne
Oglądaj wskazówki i rozwiązania __SHOWALL__
Ukryj wskazówki i rozwiązania __HIDEALL__
Uwaga
Niektóre fragmenty zadań wymagają wykorzystania procedur LAPACKa; te części odłóż do momentu, gdy opanujesz następny wykład, dotyczący m.in. bibliotek algebry liniowej.
Ćwiczenie: Metoda Cholesky'ego
Ważnym przykładem macierzy szczególnej postaci są macierze symetryczne i dodatnio określone. Są to macierze spełniające warunki:
Dla takich macierzy można nieco zmniejszyć koszt kombinatoryczny i zużycie pamięci, przeprowadzając trochę inny rozkład na macierze trójkątne: tak, aby otrzymać rozkład
zamiast , przy czym jest tu jak zwykle macierzą
trójkątną dolną z jedynkami na przekątnej, a jest macierzą
diagonalną z dodatnimi elementami na diagonali. Opracuj taki algorytm. W jego
implementacji możesz porównywać się z procedurą LAPACKa DPOSV
.
Inny wariant tego samego
rozkładu to tak zwany rozkład Cholesky'ego--Banachiewicza, w którym, przy tych
samych założeniach na , szukamy rozkładu wykorzystującego tylko jedną macierz
trójkątną dolną:
(oczywiście tym razem nie żądamy, aby miała na diagonali jedynki). Jaka jest relacja między rozkładem a ?
Ćwiczenie: Mnożyć przez odwrotność to nie zawsze to samo...
W Octave układ równań rozwiązujemy korzystając z "operatora rozwiązywania równania"
x = A \ b;
Ale w Octave jest także funkcja inv
, wyznaczająca macierz
odwrotną, więc niektóre (nie najlepsze, oględnie mówiąc) podręczniki zalecają
x = inv(A)*b;
Przedyskutuj, które podejście jest lepsze i dlaczego. Przeprowadź eksperymenty numeryczne weryfikujące twoją tezę.
Ćwiczenie: Wybór elementu głównego jest naprawdę ważny!
Rozwiąż prosty układ równań
czterema sposobami:
- na kartce papieru (dokładnie!)
- w komputerze, w arytmetyce podwójnej precyzji, korzystając z rozkładu LU bez wyboru elementu głównego
- jak poprzednio, ale z wyborem elementu głównego w kolumnie
- w LAPACKu lub Octave.
Porównaj uzyskane rozwiązania i wyciągnij wnioski.
Ćwiczenie
Zapisz w Octave algorytm rozkładu LU macierzy (bez wyboru elementu głównego) działający in situ.
Wykorzystaj go do napisania funkcji, która rozwiąże układ równań .
Przetestuj tę funkcję na kilku macierzach i porównaj czas jego działania z czasem
wykonania operacji x = A\b
.
Spróbuj zastosować swój algorytm do kilku specjalnych macierzy:
- Hilberta dużego wymiaru
- diagonalnej z jednym elementem bardzo małym (a nawet równym zero)
Ćwiczenie: Układy równań z wieloma prawymi stronami
Podaj sposób taniego wyznaczenia rozwiązania sekwencji układów równań z tą samą macierzą i różnymi prawymi stronami:
Układy równań z tą samą macierzą, ale ze zmieniającą się prawą stroną równania powstają często na przykład przy rozwiązywaniu równań różniczkowych cząstkowych, gdzie prawa strona układu odpowiada zmieniającym się warunkom brzegowym.
Ćwiczenie: Obliczanie wyznacznika macierzy
Bardzo rzadko w praktyce numerycznej zdarza się potrzeba obliczenia wartości wyznacznika macierzy . Zaproponuj metodę obliczania oraz wskaż, jakiego rodzaju problemy numeryczne możesz napotkać.