In [5]:
from __future__ import unicode_literals #ékezetes betűk

Egyszerű lineáris egyenletrendszerek

Írjunk egy egyszerű rutint ami egy előre megadott \(A\) 2x2-es mátrix-ból és egy 2 elemű \(b\) vektorból megoldja az \(Ax=b\) lineáris egyenletet és vissza adja az \(x\) vektort! Használjuk a szimbolikus mintapélda utolsó feladatának eredményét!

In [1]:
def megold22(A,b):
    x=array([0.0,0.0]);
    determinans=A[0,0]*A[1,1]-A[0,1]*A[1,0];
    x[0]=(A[1,1]*b[0]-A[0,1]*b[1])/determinans;
    x[1]=(A[0,0]*b[1]-A[1,0]*b[0])/determinans;
    return x
    

Vizsgáljuk meg a rutin viselkedését! Legyen \[A=\begin{pmatrix} \cos(\varphi) & -\sin(\varphi)\\ \sin(\varphi) & \cos(\varphi) \end{pmatrix}\] valamint \[b=\begin{pmatrix} 0 \\ 1 \end{pmatrix}\] illetve a \(\phi=\pi/6\). Azaz keressük azt a vektort amit ha elforgatunk \(30^\circ\)-al akkor egy \(y\) irányú egységvektort kapunk!

In [2]:
#A b iletve phi értékadás
phi=pi/6;
A=array([[cos(phi), -sin(phi)],
         [sin(phi),  cos(phi)]])
b=array([0,1])

Ezután már készek vagyunk meghívni a rutint!

In [3]:
megold22(A,b) # A megoldás
Out[3]:
array([ 0.5      ,  0.8660254])

Szemfülesebb halgatók már előre is megsejthették a helyes megoldást:

In [4]:
array([cos(pi/3),sin(pi/3)]) #Vajon ez hogy jött ki.. ?
Out[4]:
array([ 0.5      ,  0.8660254])

Vizsgáljunk meg még egy példát! Legyen \[A=\begin{pmatrix} 3 & 4\\ 9 & 12 \end{pmatrix}\] valamint \[b=\begin{pmatrix} 1 \\ 3 \end{pmatrix}\]

In [10]:
# Az A és b tömbök inicializálása
A=array([[3,  4],
         [9, 12]])
b=array([1,3])
In [11]:
# a megoldás... 
megold22(A,b) # Vajon van megoldás ?
-c:4: RuntimeWarning: divide by zero encountered in long_scalars
-c:5: RuntimeWarning: divide by zero encountered in long_scalars

Out[11]:
array([ 0.,  0.])

Amint a fenti hibaüzenet is mutatja az algoritmusunkban bizony valahol nullával osztottunk! Ha jobban megnézzük a mátrixot akkor észre vehetjük hogy a determinánsa zérus mivel a második sor az első háromszorosa! Ilyen esetben tehát nem is várunk megoldás, hiszen ilyen esetben a vizsgált két egyenlet nem független egymástól!

Lineáris algebra rutinok

Oldjuk meg az előző forgatós feladatot a numpy lineáris egyenlet rendszer megoldó rutinjával is! A rutin neve most is solve(), figyelnünk kell azonban hogy ez nem ugyan az a függvény amit a szimbolikus egyenletrendszerek megoldására használtunk! Ez egy jó példája annak hogy attól függően hogy éppen milyen csomagokat töltöttünk be az import parancsal bizonyos függvények bizony másképp viselkednek! A jelen rendszerben (sagemathcloud) a numpy mindíg betöltődik automatikusan minden egyes újy notebookhoz. Hogy elkerüljük a sympy hasonló nevű rutinjával a keveredést célszerű új notebook-ot nyitni, vagy legalább újra betölteni a numpy csomagot " from numpy import * " paranccsal!

In [71]:
#A változók inicializálása
phi=pi/6;
A=array([[cos(phi), -sin(phi)],
         [sin(phi),  cos(phi)]])
b=array([0,1])
#A függvény meghívása, az eredmény a várt vektor...
solve(A,b) 
Out[71]:
array([ 0.5      ,  0.8660254])

A numpy a lineáris algebrában használt függvények illetve konvenciók használatának könnyítésére "matrix" típusú objektumokat használ. Vizsgáljuk meg mi a különbség sima "array" illetve "matrix" típusú tömbök között!

In [24]:
#Tesztelő tömbök
A=array([[1,2],[3,4]])
B=array([[11,22],[33,44]])
In [27]:
A*B # A "*" itt elementkénti szorzást jelent
Out[27]:
array([[ 11,  44],
       [ 99, 176]])
In [28]:
#Tesztelő tömbök
A=matrix(array([[1,2],[3,4]]))
B=matrix(array([[11,22],[33,44]]))
In [29]:
A*B # A "*" itt valódi mátrix szorzás!!!!
Out[29]:
matrix([[ 77, 110],
        [165, 242]])

Egy pár hasznos mátrix művelet:

In [30]:
A.T # Egy mátrix traszponáltja
Out[30]:
matrix([[1, 3],
        [2, 4]])
In [31]:
trace(A) # A mátrix trace-e, vagy spur-ja vagyis a diagonális elemek összege
Out[31]:
5
In [33]:
det(A) # A mátrix determinánsa
Out[33]:
-2.0000000000000004
In []:
inv(A) # A mátrix inverze.. ha létezik..
In []:
A*inv(A) # ennek az egységmátrixnak kell lennie!!!
In [51]:
(2.422+1.342j) # numpy-ban a képzetes számokat így lehet leírni
Out[51]:
(2.422+1.342j)
In [54]:
C=A+B*1.0j # Ez egy komplex mátrix, Így lehet két mátrixot össze adni.. a + jel itt is elemenként működik!
C
Out[54]:
matrix([[ 1.+11.j,  2.+22.j],
        [ 3.+33.j,  4.+44.j]])
In [55]:
C.H # Ez pedig az adjungáltja azaz a transzponált mátrix komplex konjugáltja
Out[55]:
matrix([[ 1.-11.j,  3.-33.j],
        [ 2.-22.j,  4.-44.j]])
In [69]:
b=matrix(array([[1],[2]])) # ez egy 1 oszopból álló mátrix.. vagyis oszlopvektor
A*b # Amit meg tudunk szorozni balról egy mátrix-al
Out[69]:
matrix([[ 5],
        [11]])
In [70]:
b=matrix(array([[1,2]])) # ez egy 1 sorból álló mátrix.. vagyis sorvektor
b*B # Amit meg tudunk szorozni jobbról egy mátrix-al
Out[70]:
matrix([[ 77, 110]])

Oldjunk meg "matrix"-okal egy lineáris egyenletrenszert! Válasszunk véletlenszerű mátrixokat!

In [72]:
A=matrix(rand(10,10)) # Ez egy 10x10-es véletlen mátrix
b=matrix(rand(10,1))  # Ez egy 10x1-es véletlen mátrix.. egy oszlopvektor
x=solve(A,b) # A solve változatlanul működik..

A puding próbája az evés! Vizsgáljuk meg a kapott x menyire teljesíti a megoldandó problémát:

In [73]:
A*x-b 
Out[73]:
matrix([[  3.33066907e-16],
        [  1.66533454e-16],
        [ -7.77156117e-16],
        [  3.33066907e-16],
        [  0.00000000e+00],
        [  2.22044605e-16],
        [  5.55111512e-16],
        [  1.11022302e-16],
        [  2.22044605e-16],
        [  4.44089210e-16]])

Ezt vártuk! Az eltérés csak numerikus szemét !!

Vizsgáljunk meg most egy olyan lineáris egyenletrendszert ahol a mátrix egy 10x10-es mátrix és mindenkét első mellékátlója -1 a többi elem pedig nulla! A \(b\) vektor elemeit pedig válaszuk a következő módon:

In [135]:
b=sin(2*array(range(1,11))*pi/11)
In [153]:
A=matrix(zeros((10,10))) # Inicializálás
for i in range(9):#A mellékátlók 1-el rövidebbek mint a mátrix mérete!
    A[i,i+1]=-1.0 #A mellékátlók feltöltése -1 -el
    A[i+1,i]=-1.0
A
Out[153]:
matrix([[ 0., -1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
        [-1.,  0., -1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
        [ 0., -1.,  0., -1.,  0.,  0.,  0.,  0.,  0.,  0.],
        [ 0.,  0., -1.,  0., -1.,  0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0., -1.,  0., -1.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0., -1.,  0., -1.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0., -1.,  0., -1.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0.,  0., -1.,  0., -1.,  0.],
        [ 0.,  0.,  0.,  0.,  0.,  0.,  0., -1.,  0., -1.],
        [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0., -1.,  0.]])
In []:
x=solve(A,b)    # A megoldás

Hasonlítsuk össze a bemenő \(b\) vektort és az \(x\)-et! A számértékeiket is!

In [137]:
#A vektorok "alakja"
plot(b,'o-',label='b') # A bemenő vektor
plot(x,'o-',label='x') # A kijövő vektor
legend();# ábra magyarázat

Irassuk ki az értékeket illetve az értékek hányadosát is!

In [134]:
for i in range(10):
    print x[i],b[i],b[i]/x[i]
-0.146813246469 0.281732556841 -1.91898594723
-0.281732556841 0.540640817456 -1.91898594723
-0.393827570986 0.755749574354 -1.91898594723
-0.474017017513 0.909631995355 -1.91898594723
-0.515804424368 0.989821441881 -1.91898594723
-0.515804424368 0.989821441881 -1.91898594723
-0.474017017513 0.909631995355 -1.91898594723
-0.393827570986 0.755749574354 -1.91898594723
-0.281732556841 0.540640817456 -1.91898594723
-0.146813246469 0.281732556841 -1.91898594723

Úgy tűnik ez egy saját vektora a mátrixnak!!! Azaz \(b=\lambda x\) illetve az eredeti egyenlet \[Ax=\lambda x\] alakú volt!

Egy mátrix sajátértékeit és ajaátvektorait is meg tudjuk határozni! Ehez az eig() illetve eigvals() rutinokat használhatjuk!

In [134]:
eigvals(A) # Ez az A mátrix sajátértékeit adja, keressük meg a fent megtalált sajátértéket!
Out[134]:
array([-1.91898595, -1.68250707, -1.30972147, -0.83083003, -0.28462968,
        0.28462968,  1.91898595,  1.68250707,  1.30972147,  0.83083003])
In [139]:
vals,vecs=eig(A) #Ez a sajátvektorokat is megadja
In [142]:
vals #itt vannak a sajátértékek
Out[142]:
array([-1.91898595, -1.68250707, -1.30972147, -0.83083003, -0.28462968,
        0.28462968,  1.91898595,  1.68250707,  1.30972147,  0.83083003])
In [141]:
vecs #itt pedig a saját vektorok
Out[141]:
matrix([[-0.12013117,  0.23053002,  0.3222527 ,  0.38786839, -0.42206128,
         -0.42206128, -0.12013117, -0.23053002, -0.3222527 ,  0.38786839],
        [-0.23053002,  0.38786839,  0.42206128,  0.3222527 , -0.12013117,
          0.12013117,  0.23053002,  0.38786839,  0.42206128, -0.3222527 ],
        [-0.3222527 ,  0.42206128,  0.23053002, -0.12013117,  0.38786839,
          0.38786839, -0.3222527 , -0.42206128, -0.23053002, -0.12013117],
        [-0.38786839,  0.3222527 , -0.12013117, -0.42206128,  0.23053002,
         -0.23053002,  0.38786839,  0.3222527 , -0.12013117,  0.42206128],
        [-0.42206128,  0.12013117, -0.38786839, -0.23053002, -0.3222527 ,
         -0.3222527 , -0.42206128, -0.12013117,  0.38786839, -0.23053002],
        [-0.42206128, -0.12013117, -0.38786839,  0.23053002, -0.3222527 ,
          0.3222527 ,  0.42206128, -0.12013117, -0.38786839, -0.23053002],
        [-0.38786839, -0.3222527 , -0.12013117,  0.42206128,  0.23053002,
          0.23053002, -0.38786839,  0.3222527 ,  0.12013117,  0.42206128],
        [-0.3222527 , -0.42206128,  0.23053002,  0.12013117,  0.38786839,
         -0.38786839,  0.3222527 , -0.42206128,  0.23053002, -0.12013117],
        [-0.23053002, -0.38786839,  0.42206128, -0.3222527 , -0.12013117,
         -0.12013117, -0.23053002,  0.38786839, -0.42206128, -0.3222527 ],
        [-0.12013117, -0.23053002,  0.3222527 , -0.38786839, -0.42206128,
          0.42206128,  0.12013117, -0.23053002,  0.3222527 ,  0.38786839]])

A saját vektorok mátrixának i-edik oszlopa tartalmaza az i-edik sajátértékhez \(\lambda_i\) tartozó sajátvektort normált sajátvektort $x_i $. Tehát igaz az hogy \[x^\dagger_i A x_i=\lambda_i\]

In [147]:
vecs[:,3].H * A * vecs[:,3]-vals[3] # a 4. sajátvektor leellenőrzése
Out[147]:
matrix([[ -4.44089210e-16]])

Jelenítsük meg az első 5 sajátvektort!

In [152]:
#itt egy ciklus ahelyett hogy ötször kiírnánk a plot parancsot
for i in range(5):
        plot(array(vecs[:,i]),  # a plot parancs csak array-t eszik
             'o-', # pont és bogyó minden görbére
             label='az '+str(i)+'. sajátvektor' # a görbék címkéje legyen "az i. sajátvektor" alakú
             ) #
legend();
In []: