MN05LAB: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Przykry (dyskusja | edycje)
mNie podano opisu zmian
m Zastępowanie tekstu – „,↵</math>” na „</math>,”
 
(Nie pokazano 9 wersji utworzonych przez 3 użytkowników)
Linia 1: Linia 1:
<!--  
<!--  
Konwertowane  z pliku LaTeX przez latex2mediawiki, zob. http://www.ii.uj.edu.pl/&nbsp;pawlik1/latex2mediawiki.php
Konwertowane  z pliku LaTeX przez latex2mediawiki, zob. http://www.ii.uj.edu.pl/&nbsp;pawlik1/latex2mediawiki.php.
Niezb�dne rozszerzenia i modyfikacje oryginalnego latex2mediawiki
wprowadzi� przykry@mimuw.edu.pl
-->
-->
   
   
=Ćwiczenia: normy i uwarunkowanie=
=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;">
<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: Normy macierzowe</span>  
<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">
<div class="exercise">


Pokazać, że dla macierzy  
Ważnym przykładem macierzy  
<math>\displaystyle A=(a_{i,j})_{i.j=1}^n\inR^{n\times n}</math> mamy
szczególnej postaci są macierze <strong>symetryczne i dodatnio określone</strong>.
Są to macierze spełniające warunki:


<center><math>\displaystyle \|A\|_1 \,=\, \|A^T\|_\infty \,=\,
<center><math>A=A^T \qquad  \mbox{oraz}  \qquad x^T A x\,>\,0,\quad\forall x\ne 0</math></center>
        \max_{1\le j\le n}\sum_{i=1}^n |a_{i,j}|
 
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>
</math></center>


</div></div>
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>


oraz
<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>\displaystyle \|A\|_\infty \,=\, \max_{1\le i\le n}\sum_{j=1}^n |a_{i,j}|.
<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>
</math></center>


<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">
oraz dla <math>x\ne 0</math>
Pokażemy pierwszą równość, druga dowodzi się analogicznie.
 
<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


Najpierw udowodnimy, że dla dowolnego wektora <math>\displaystyle x</math> o normie <math>\displaystyle ||x||_1 = 1</math>,
<center><math>L_{n-1}L_{n-2}\cdots L_2L_1AL_1^TL_2^T\cdots L_{n-2}^TL_{n-1}^T
<center><math>\displaystyle ||Ax||_1 \leq \max_{1\le j\le n}\sum_{i=1}^n
    \,=\,D</math>,</center>
|a_{i,j}|, </math></center>


a następnie wskażemy taki wektor <math>\displaystyle x</math>, dla którego zachodzi równość.
przy czym macierz <math>D</math> jest diagonalna i dodatnio określona,  
a więc wyrazy na diagonali są dodatnie. Oznaczając


Istotnie, dla <math>\displaystyle ||x||_1 = 1</math>,
<center><math>L\,=\,L_1^{-1}L_2^{-1}\cdots L_{n-1}^{-1}  
<center><math>\displaystyle
|(Ax)_i| = |\sum_{j=1}^n a_{ij}x_j| \leq \sum_{j=1}^n |a_{ij}|\cdot|x_j| \leq
\max_j|a_{ij}|\sum_{j=1}^n |x_j| = \max_j|a_{ij}|,
</math></center>
</math></center>


bo <math>\displaystyle \sum_{j=1}^n |x_j|  = ||x||_1 = 1</math>, zatem
dostajemy żądany rozkład.
<center><math>\displaystyle
 
||Ax||_1 = \sum_i |(Ax)_i|\leq \max_j \sum_{i=1}^n |a_{ij}|.
Zauważmy, że przy praktycznej realizacji rozkładu <math>A=LDL^T</math>  
</math></center>
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).


Niech teraz <math>\displaystyle i_0</math> będzie indeksem kolumny macierzy <math>\displaystyle A</math>, dla którego powyższe
Oczywiście, <math>\widetilde{L} = L \sqrt{D}</math>.
maksimum jest przyjmowane. Wtedy w powyższym oszacowaniu równość jest
przyjmowana dla wektora <math>\displaystyle x=e_{i_0}</math>, czyli wektora, który na współrzędnej <math>\displaystyle i_0</math>
ma jedynkę, a poza nią --- same zera.


</div></div></div>
</div></div></div>


<div style="margin-top:1em; padding-top,padding-bottom:1em;">
<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</span>  
<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: Mnożyć przez odwrotność to nie zawsze to samo...</span>  
<div class="exercise">
<div class="exercise">


Pokaż, że dla macierzy rzeczywistej <math>\displaystyle N\times M</math>,
W Octave układ równań <math>Ax=b</math> rozwiązujemy korzystając z "operatora
<center><math>\displaystyle
rozwiązywania równania"
||A||_2 = \max \{\sqrt{\lambda} : \lambda  \mbox{ jest wartością własną macierzy }
<div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>x = A \ b;
A^TA\}.
</pre></div>  
</math></center>
 
Ale w Octave jest także funkcja <code style="color: #006">inv</code>, wyznaczająca macierz
<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">
odwrotną, więc niektóre (nie najlepsze, oględnie mówiąc) podręczniki zalecają
<div style="font-size:smaller; background-color:#efe"> Macierz <math>\displaystyle A^TA</math> jest macierzą symetryczną, co można powiedzieć o jej
<div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>x = inv(A)*b;
wartościach i wektorach własnych? </div>
</pre></div>  
</div></div>
 
Przedyskutuj, które podejście jest lepsze i dlaczego. Przeprowadź eksperymenty
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">   
Niech <math>\displaystyle B= A^TA</math>. Jako macierz symetryczna, ma ona rozkład
Wyznaczenie <math>A^{-1}</math> praktycznie nigdy nie jest konieczne w obliczeniach, a
<center><math>\displaystyle
zwłaszcza do rozwiązania układu równań. Nie dość, że jest bardziej kosztowne, to
B = Q^T\Lambda Q,
dodatkowo nie jest numerycznie poprawne.
</math></center>


gdzie <math>\displaystyle Q</math> jest macierzą ortogonalną, <math>\displaystyle Q^TQ=I</math>, natomiast <math>\displaystyle \Lambda</math> jest macierzą
Przykładowy test mógłby wyglądać jak poniżej. Duże macierze losowe
diagonalną (z wartościami własnymi <math>\displaystyle B</math> na diagonali). Poza tym <math>\displaystyle B</math> jest
zazwyczaj dobrze uwarunkowane.
nieujemnie
określona (dlaczego?), więc wartości własne <math>\displaystyle B</math> nieujemne, zatem wyciąganie z
nich pierwiatka ma sens!


Dla dowolnego wektora <math>\displaystyle x</math> mamy
<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;
<center><math>\displaystyle
tic; X = A \ b; tX = toc;
||Ax||_2^2  = (Ax)^TAx = x^T A^TA x = x^T B x = x^TQ^T\Lambda Q x,
tic; Y = inv(A)*b; tY = toc;
</math></center>
[norm(X-x)/norm(x),  norm(Y-x)/norm(x); tX, tY]
</pre></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>ans =
  1.9861e-13  2.8687e-13
  2.3644e-01  4.0609e-01
</nowiki></div>
Wyszło (z grubsza) dwa razy szybciej i dwa razy dokładniej.


skąd, definiując <math>\displaystyle y=Qx</math>,
<center><math>\displaystyle
||A||_2^2 = \max_x\frac{||Ax||_2^2 }{||x||_2^2} = \max_y\frac{||\Lambda y||_2^2
}{||y||_2^2} = \max \{\lambda_i\},
</math></center>
bo <math>\displaystyle ||Qx||_2 = ||y||_2</math>. 
</div></div></div>
</div></div></div>


<div style="margin-top:1em; padding-top,padding-bottom:1em;">
<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</span>  
<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: Wybór elementu głównego jest naprawdę ważny!</span>  
<div class="exercise">
<div class="exercise">


Dla wektora <math>\displaystyle  x=(x_j)_{j=1}^n\inR^n</math>, niech
Rozwiąż prosty układ równań
<math>\displaystyle rd_\nu( x)=(rd_\nu(x_j))_{j=1}^n</math>. Pokazać, że


<center><math>\displaystyle \| x-rd_\nu( x)\|_p\,\le\,\nu\,\| x\|_p
<center><math>\begin{align} 10^{-18} x_1 + x_2 &= 1,\\
</math></center>
x_1 + 2x_2 &= 4,
\end{align}</math></center>


dla <math>\displaystyle 1\le p\le\infty</math>.  
czterema sposobami:
* na kartce papieru (dokładnie!)
* 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>
* w [http://www.netlib.org/lapack  LAPACKu] lub Octave.
Porównaj uzyskane rozwiązania i wyciągnij wnioski.
</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"> 
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 style="margin-top:1em; padding-top,padding-bottom:1em;">
<div style="margin-top:1em; padding-top,padding-bottom:1em;">
Linia 111: Linia 174:
<div class="exercise">
<div class="exercise">


Dla macierzy <math>\displaystyle A=(a_{i,j})_{i,j=1}^n</math>, niech
Zapisz w Octave algorytm rozkładu LU macierzy (bez wyboru elementu głównego) działający ''in situ''.  
<math>\displaystyle rd_\nu(A)=(rd_\nu(a_{i,j}))_{i,j=1}^n</math>. Pokazać, że


<center><math>\displaystyle \|A-rd_\nu(A)\|_p\,\le\,\nu\,\|A\|_p,
<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">
</math></center>
<div style="font-size:smaller; background-color:#f9fff9; padding: 1em"> Pamiętaj, pętle w Octave wykonują się bardzo wolno! </div>
</div></div>


dla <math>\displaystyle p=1,\infty</math>, oraz
Wykorzystaj go do napisania funkcji, która rozwiąże układ równań <math>Ax=b</math>.


<center><math>\displaystyle \|A-rd_\nu(A)\|_2\,\le\,\|A-rd_\nu(A)\|_E\,\le\,\nu\,\|A\|_E
Przetestuj tę funkcję na kilku macierzach i porównaj czas jego działania z czasem
    \,\le\,\sqrt{n}\,\nu\,\|A\|_2.
wykonania operacji <code style="color: #006">x = A\b</code>.
</math></center>


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)
</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"> 
Najprostszy wariant to po prostu przepisanie algorytmu z wykładu, który już
nawet trochę wykorzystywał notację dwukropkową MATLABa:
<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?
# Czy jest macierzą? Te linie pozostawiamy twojej inwencji
N = size(A,1);
for k=1:N-1
if (A(k,k) == 0.0)
return;
end
for i=k+1:N #wyznaczenie <math>k</math>-tej kolumny <math>L</math>
A(i,k) = A(i,k)/A(k,k);
end
for j=k+1:N #modyfikacja podmacierzy <math>A_{22} = A_{22} - l_{21}u_{12}^T</math>
for i=k+1:N
A(i,j) -= A(i,k)*A(k,j);
end
end
end
L = tril(A,-1) + eye(N);
U = triu(A);
end
</pre></div>
Jednak w tej implementacji mamy do czynienia z nawet potrójnie zagnieżdżonymi
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
blokowych.
<div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>function [L,U] = lufb(A)
# Na początku warto dodać trochę sprawdzania danych: czy A jest kwadratowa? a w ogóle,
# czy jest macierzą? te linie pozostawiamy inwencji Czytelnika
N = size(A,1);
for k=1:N-1
if (A(k,k) == 0.0)
return;
end
#wyznaczenie <math>k</math>-tej kolumny <math>L</math>
A(k+1:N,k) = A(k+1:N,k)/A(k,k);
#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);
end
L = tril(A,-1) + eye(N);
U = triu(A);
end
</pre></div>
<div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>[Kod testujący lufa(0 i lufb()]
N = 100;
A = rand(N) + 1000*eye(N);
format short e;
t = ta = tb = Inf;
K = 5;
for i = 0:K
tic; [L, U] = lu(A); t = min(t,toc);
tic; [La, Ua] = lufa(A); ta = min(ta,toc);
tic; [Lb, Ub] = lufb(A); tb = min(tb,toc);
end
disp("Czasy: lu(), lufa(), lufb()"); [t, ta, tb]
disp("Błąd:");
[norm(L*U - A,inf), norm(La*Ua - A,inf), norm(Lb*Ub - A,inf)]
</pre></div>
Dla macierzy losowych wymiaru <math>N=100</math> dostaliśmy na Pentium 1.5GHz
{| border=1
|+ <span style="font-variant:small-caps"> </span>
|-
| Implementacja  ||  lu (oryginalne)  ||  lufa  ||  lufb
|-
| Czas (s)  ||  4.0436e-03  ||  1.5877e+01  ||    1.0767e-01
|-
| Błąd <math>||LU-A||_\infty</math>  ||  3.4596e-13  ||  8.0747e-13  ||  8.0747e-13
|}
Zwróć uwagę na charakterystyczne fakty:
* Usunięcie wewnętrznych pętli stukrotnie(!) przyspieszyło <code style="color: #006">lufb</code> w
stosunku do <code style="color: #006">lufa</code>
* Gotowa funkcja Octave wciąż jest stukrotnie(!) szybsza od mojej
najszybszej funkcji.
To jest typowe, gdy korzystamy ze środowisk typu Octave czy MATLAB. Czasem
nawet lepiej napisać implementację wykonującą więcej obliczeń, ale korzystającą
w większm stopniu z wbudowanych funkcji Octave, niż napisać samemu implementację
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.
To w znacznym stopniu usuwa problemy związanie z korzystaniem z pętli, ale
wykracza poza zakres naszego kursu.
Funkcja wykorzystująca gotowy rozkład LU do rozwiązania układu <math>Ax=b</math> w MATLABie miałaby postać
<div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>function x = sol(L,U,b)
x = U \ ( L \ b);
end
</pre></div>
gdyż MATLAB prawidłowo rozpoznaje układy z macierzą trójkątną i stosuje szybszy
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 style="margin-top:1em; padding-top,padding-bottom:1em;">
<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</span>  
<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: Układy równań z wieloma prawymi stronami</span>  
<div class="exercise">
<div class="exercise">


Czy algorytm eliminacji Gaussa dla <math>\displaystyle Ax=b</math>, gdzie macierz <math>\displaystyle A</math> jest <strong>symetryczna i dodatnio określona</strong>
Podaj sposób taniego wyznaczenia rozwiązania sekwencji <math>k<N</math> układów równań z tą
zawsze da wynik <math>\displaystyle \widetilde{x}</math> o dużej dokładności, rzędu precyzji arytmetyki?
samą macierzą <math>A\in R^{N\times N}</math> i różnymi prawymi stronami:
<center><math>
Ax_i = b_i, \qquad i = 1,\ldots,k</math></center>
 
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.


<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:#efe"> Oceń wskaźnik wzrostu i skorzystaj z twierdzenia o numerycznej poprawności </div>
<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 139: 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">   
Dla naszej macierzy wskaźnik wzrostu <math>\displaystyle \rho_N \leq 2</math>, zatem algorytm eliminacji
No tak, oczywiście wystarczy
Gaussa jest numerycznie poprawny. Ale <strong>nie znaczy</strong> to, że da wynik <math>\displaystyle \widetilde{x}</math> taki, że


<center><math>\displaystyle \frac{||x-\widetilde{x}||}{||x||} \approx \nu.
{{algorytm|||
</math></center>
<pre>Znajdź rozkład <math>PA = LU</math>;
Utwórz macierz <math>B = [b_1,\ldots,b_k]</math>;
Rozwiąż <math>LY = B</math>;
Rozwiąż <math>UX = Y</math>;
</pre>}}


Ponieważ <math>\displaystyle \widetilde{x}</math> jest dokładnym rozwiązaniem równania z macierzą zaburzoną,
Rozwiązanie każdego z układów <math>LY = B</math> i <math>UX = Y</math> można przyspieszyć, tworząc
<math>\displaystyle \widetilde{A}\widetilde{x} = b</math>, należy ocenić wpływ zaburzenia macierzy na jakość
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
wyniku, a tu już wiemy, że jeśli zaburzenie jest dostatecznie małe (czyli, gdy
funkcji <code style="color: #903">DGETRF</code> (rozkład) i <code style="color: #903">DGETRS</code> (rozwiązanie) oraz w
precyzja arytmetyki jest dostatecznie duża), to
<code style="color: #903">DGESV</code>, łączącej funkcjonalność obu.
 
<center><math>\displaystyle \frac{||x-\widetilde{x}||}{||x||} \approx K\cdot  \mbox{cond} (A)\cdot \nu,
</math></center>
 
a więc <strong> błąd będzie mały tylko wtedy, gdy uwarunkowanie <math>\displaystyle A</math> będzie
niewielkie!</strong> Dobrym przykładem jest tu macierz Hilberta, która jest symetryczna
i dodatnio określona, lecz mimo to już dla średnich <math>\displaystyle N</math> algorytm eliminacji
Gaussa daje wyniki obarczone stuprocentowym błędem! Potwierdź to
eksperymentalnie!
</div></div></div>
</div></div></div>


<div style="margin-top:1em; padding-top,padding-bottom:1em;">
<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: Numeryczne kryterium "numerycznej poprawności"</span>  
<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: Obliczanie wyznacznika macierzy</span>  
<div class="exercise">
<div class="exercise">


Jeśli
Bardzo rzadko w praktyce numerycznej zdarza się potrzeba obliczenia wartości
wyznacznika macierzy <math>A \in R^{N \times N}</math>. Zaproponuj metodę obliczania
<math>\mbox{det} (A)</math> oraz wskaż, jakiego rodzaju problemy numeryczne możesz napotkać.
</div></div>


<center><math>\displaystyle
<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"> 
  (A+E) z\,=\, b,  
Wystarczy wykonać rozkład <math>PA=LU</math>. Wtedy
 
<center><math>\mbox{det}  A\,=\,(-1)^p u_{11}u_{22}\cdots u_{nn},  
</math></center>
</math></center>


gdzie <math>\displaystyle \|E\|_p\le K\nu\|A\|_p</math>,
gdzie <math>p</math> jest liczbą przestawień wierszy w eliminacji. Tak więc, koszt
to oczywiście dla residuum <math>\displaystyle  r= b-A z</math> mamy
obliczenia wyznacznika to <math>O(N^3)</math>.


<center><math>\displaystyle
Kłopoty numeryczne możemy mieć z reprezentacją samej wartości wyznacznika w
  \| r\|_p\,\le\,K\nu\|A\|_p\| z\|_p.
arytmetyce zmiennoprzecinkowej. Ponieważ
</math></center>
 
<center><math>\mbox{det}  (cA) = c^N A</math>,</center>
 
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:


Pokazać, że dla <math>\displaystyle p=1,2,\infty</math> zachodzi też twierdzenie odwrotne, tzn.
Najpierw z losową macierzą <math>100\times 100</math> i jej krotnościami...
jeśli spełniony jest powyższy warunek dla residuum, to istnieje macierz pozornych
zaburzeń <math>\displaystyle E</math> taka, że <math>\displaystyle \|E\|_p\le K\nu\|A\|_p</math> oraz spełniona jest
równość <math>\displaystyle (A+E) z\,=\, b</math>.


Jest to tak zwane <strong>numeryczne kryterium "numerycznej poprawności"</strong>, bo (dla
<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);
konkretnych danych) pozwala, wyłącznie na podstawie obliczonych numerycznie
octave:27> det(A)
wartości ocenić zaburzenie pozorne macierzy, dla którego numeryczny wynik jest
ans = -7.5240e+24
dokładnym rozwiązaniem.
octave:28> det(10*A)
ans = -7.5240e+124
octave:29> det(100*A)
ans = -7.5240e+224
octave:30> det(1000*A)
ans = -Inf
</nowiki></div>
oraz z coraz większymi macierzami losowymi:


<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-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))
<div style="font-size:smaller; background-color:#efe"> Rozpatrzyć
ans =  4.3751e+25
<math>\displaystyle E= r( \mbox{sgn} \,z_i)_{1\le i\le n}^T/\| z\|_1</math> dla <math>\displaystyle p=1</math>,  
octave:33> det(rand(400))
<math>\displaystyle E= r z^T/\| z\|_2^2</math> dla <math>\displaystyle p=2</math>, oraz
ans = -3.0348e+218
<math>\displaystyle E= r( \mbox{sgn} \,z_k) e_k^T/\| z\|_\infty</math> dla <math>\displaystyle p=\infty</math>,  
octave:34> det(rand(800))
gdzie <math>\displaystyle k</math> jest indeksem dla którego <math>\displaystyle |z_k|=\| z\|_\infty</math>. </div>
ans = -Inf
</div></div>
</nowiki></div>
Można sobie z
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>m,c</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.  


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

A=ATorazxTAx>0,x0

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

A=LDLT

zamiast PA=LU, przy czym L jest tu jak zwykle macierzą trójkątną dolną z jedynkami na przekątnej, a D 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 A, szukamy rozkładu wykorzystującego tylko jedną macierz trójkątną dolną:

A=L~L~T,

(oczywiście tym razem nie żądamy, aby L~ miała na diagonali jedynki). Jaka jest relacja między rozkładem LDLT a L~L~T?

Rozwiązanie

Ćwiczenie: Mnożyć przez odwrotność to nie zawsze to samo...

W Octave układ równań Ax=b 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ę.

Rozwiązanie

Ćwiczenie: Wybór elementu głównego jest naprawdę ważny!

Rozwiąż prosty układ równań

1018x1+x2=1,x1+2x2=4,

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.

Rozwiązanie

Ćwiczenie

Zapisz w Octave algorytm rozkładu LU macierzy (bez wyboru elementu głównego) działający in situ.

Wskazówka

Wykorzystaj go do napisania funkcji, która rozwiąże układ równań Ax=b.

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)
Rozwiązanie

Ćwiczenie: Układy równań z wieloma prawymi stronami

Podaj sposób taniego wyznaczenia rozwiązania sekwencji k<N układów równań z tą samą macierzą ARN×N i różnymi prawymi stronami:

Axi=bi,i=1,,k

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.

Wskazówka
Rozwiązanie

Ćwiczenie: Obliczanie wyznacznika macierzy

Bardzo rzadko w praktyce numerycznej zdarza się potrzeba obliczenia wartości wyznacznika macierzy ARN×N. Zaproponuj metodę obliczania det(A) oraz wskaż, jakiego rodzaju problemy numeryczne możesz napotkać.

Rozwiązanie