A MATLAB programozási nyelv

Vektorizáció

Habár a ciklusok rendkívül hasznosak a legtöbb programozási feladatnál és nélkülözhetetlenek számos programozási nyelvben, Matlabban szükségtelennek bizonyulhatnak főleg vektorok vagy mátrixok kezelésénél. Bemutatjuk a vektorizáció fogalmát, mely azt fejezi ki, hogy átírjuk azt a kódot, mely tradícionális programozási konstrukciókkal -- például ciklussal -- lett megírva és helyettük kihasználjuk a Matlab vektor operációit. Vektorizált kód hamarabb és könyebben elkészül és gyakran gyorsabban is fut.

Ciklusok vektorokkal és mátrixokkal

Legtöbb programozási nyelvben mikor vektoron hajtunk végre műveletet, a for ciklust használjuk, hogy bejárjuk az egész vektort, alkalmazva egy ciklusváltozót. Általánosságban, feltéve, hogy van egy vec vektor változónk, az indexek 1-től a vektor hosszáig terjednek:

for i = 1:length(vec) % csinálunk valamit vec(i)-vel end

Például megszorozhatunk minden elemet 3-mal:

for i = 1:length(vec) vec(i) = vec(i) * 3; end

Hasonlóan, művelet elvégzése mátrixon már beágyazott ciklust igényelne, és ciklusváltozókat használnánk a sorok és oszlopokhoz, hogy az egyes elemeket elérjük. Általánosságban, feltételezve, hogy rendelkezésünkre áll a mat mátrix változó, a size-t használjuk, hogy megállapítsuk a sorok és oszlopok számát:

(sorok oszlopok) = size(mat); for sor = 1:sorok for oszlop = 1:oszlopok % csinálunk valamit mat(sor, oszlop)-pal end

Látni fogjuk, hogy ez teljesen szükségtelen Matlabban.

Operációk vektorokkal és mátrixokkal

Numerikus számítások elvégezhetők a teljes vektorokon vagy mátrixokon. Például szeretnénk megszorozni a v vektor minden elemét 3-mal, ahogy az előző szakaszban láttuk.

>> v = [3 7 2 1]; >> v = v * 3 v = 9 21 6 3

Mátrixon a numerikus számítások minden elemre végrehajtódnak. Például minden elem megszorzása 2-vel automatikus, nem úgy, mint a legtöbb programozási nyelvben, ahol is beágyazott ciklusra volna szükségünk:

>> mat = [4:6; 3:-1:1] mat = 4 5 6 3 2 1 >> mat * 2 ans = 8 10 12 6 4 2

Ezek a skalár operációk; minden elemet a mátrixban vagy vektorban megszorzunk vagy elosztunk egy skalárral.

Vektor műveletek azok a műveletek, melyek egy vektoron vagy mátrixon elemenként kerülnek végrehajtásra. Ez azt jelenti, hogy két mátrix vagy vektor ugyanazzal a mérettel kell rendelkezzen kezdéshez. A következő példák bemutatják az összeadás és kivonást.

>> v1 = 2:5 v1 = 2 3 4 5 >> v2 = [ 33 11 5 1 ] v2 = 33 11 5 1 >> v1 + v2 ans = 35 14 7 6 >> mat1 = [ 5:8; 9:-2:3 ] mat1 = 5 6 7 8 9 7 5 3 >> mat2 = reshape(1:8, 2, 4) mat2 = 1 3 5 7 2 4 5 8 >> mat1 - mat2 ans = 4 3 2 1 7 3 -1 -5

Azonban, bármely műveletnél, mely szorzásra épül (azaz szorzás, osztás és hatványozás), egy pontot (.) kell tenni a műveleti jel elé a vektor mávelethez. Például, a .^ hatványozás operátort kell használnunk, mikor mátrixokkal és vektorokkal van dolgunk, szemben a ^ operátorral. Négyzetre emelni egy vektor azt jelenti, hogy minden eleme önmagával lesz megszorozva, így tehát a .^-t kell használni.

>> v = [ 3 7 2 1 ]; >> v ^ 2 Error using ^ Inputs must be a scalar and a square matrix. To compute elementwise POWER, use POWER (.^) instead. >> v .^ 2 ans = 9 49 4 1

Hasonlóan a .* operátor használatos vektorszorzáskor és ./ vagy .\ vektorosztáshoz. A következő néhány példa bemutatja a szorzást és osztást.

>> v1 = 1:3 v1 = 1 2 3 >> v2 = 7:2:11 v2 = 7 9 11 >> v1 .* v2 ans = 7 18 33

A .^, .*, ./, .\ operátorok vektor operátorok és akkor használjuk őket, mikor ugyanakkora mátrixot vagy vektort szorzunk vagy osztunk elemenként.

Vektorok és mátrixok mint függvény argumentumok

A legtöbb programozási nyelv használata közben előfordul, hogy egy függvényt alkalmaznánk egy vektor vagy mátrix minden elemére, és ehhez magunknak kell ciklus írni. Azonban mikor egy függvénynek adunk át egy egész vektort vagy mátrixot, a függvény a bemenet minden elemére alkalmazva lesz, és az eredmény mérete meg fog egyezni a bemenetével.

Például, számoljuk ki a vec vektor minden elemének koszinuszát. A cos függvény automatikusan visszaadja minden elemnek a koszinuszát és az eredmény azonos méretű lesz a bemenettel.

>> vec = 1:3 vec = 1 2 3 >> cos(vec) ans = 0.5403 -0.4161 -0.9900

Ugyanígy egy mátrix esetén egy ugyanakkora mátrixot kapunk. Például a sign minden elem előjelét számolja ki:

>> mat = [1:-2:-3; 5, 0, -9] mat = 1 -1 -3 5 0 -9 >> sign(mat) ans = 1 -1 -1 1 0 -1

Ugyanez érvényes saját függvényeinkre, amíg a használt műveletek helyesek. Alább látható a függvény, mely kiszámolja egy kör területét.

function t = terulet(sugar) t = pi * sugar * sugar; end

Sajnos ez még nem alkalmas arra, hogy egy mátrix minden elemére kiszámoljuk a területet, mivel feltételeztük, hogy sugar skalár tipusú.

>> terulet(1:3) Error using * Inner matrix dimensions must agree. Error in terulet (line 2) t = pi * sugar * sugar;

Mindez azért történt, mert *-ot használtunk a függvényben, de .* a kötelező, amennyiben elemenként szeretnénk szorozni. A javítás után már minden rendben működik:

function t = terulet(sugar) t = pi * sugar .* sugar; end >> terulet(1:3) ans = 1 4 9

Figyeljük meg, hogy a .* operátor csak a sugár vektor önmagával való szorzásánál szükséges. Pi-vel való szorzás skalár szorzás, így elég *-t használni.

Logikai vektorok

A relációs operátorok alkalmazhatók vektorokra és mátrixokra is. Például adott vec vektorunk és ki szeretnénk deríteni, hogy mely elemei nagyobbak, mint mondjuk 10. Az eredmény egy vektor ugyanazokkal a méretekkel és logikai igaz, hamis értékekkel.

>> vec=[5 6 1 11 23 0]; >> nagyobb = vec > 10 nagyobb = 0 0 0 1 1 0 >> whos Name Size Bytes Class Attributes nagyobb 1x6 6 logical vec 1x6 48 double

Amit kaptunk, az egy logikai vektor. A logikai vektor kitűnően felhasználható az eredeti vektor indexeléséhez. Ezt hívják logikai indexelésnek. A sum segítségével megszámolhatjuk a 10-nél nagyobb elemeket.

>> vec(nagyobb) ans = 11 23 >> sum(nagyobb) ans = 2

Sajnos a következő nem működik, mivel az argumentumként megadott vektor double lebegőpontos számokból áll, a Matlab pedig csak logikai értékek sorozatát fogadja el.

>> vec([0 0 1 0 1 1]) Subscript indices must either be real positive integers or logicals.

Ha magunknak szeretnénk logikai vektort készíteni, használjuk a zeros vagy ones függvényeket a memória lefoglalásához, és konvertáljuk logikai típussá az eredményt:

>> logical(zeros(3)) ans = 0 0 0 0 0 0 0 0 0 >> logical(ones(1,3)) ans = 1 1 1

Ez persze járható út, azonban jobb, ha a true és false függvényeket használjuk, mivel gyorsabbak és hatékonyabban használják a memóriát.

>> false(3) ans = 0 0 0 0 0 0 0 0 0 >> true(1, 3) ans = 1 1 1

Beépített logikai függvények

Számos beépített függvényt kapunk a Matlabbal együtt, melyek hasznosak logikai vektorokkal vagy mátrixokkal használva. Az any függvény logikai igazat ad vissza, ha a vektor bármelyik eleme nemzérus, és hamisat máskülönben. Az all függvény logikai igazat ad vissza csak akkor, ha minden elem nemzérus.

>> vec = [ 1 2 8 0 7 ]; >> any(vec) ans = 1 >> all(vec) ans = 0

A find függvény megkeresi azon indexeit a vektornak, melyek teljesítik az adott követelményt.

>> vec = [ 5 6 13 14 ]; >> find(vec > 10) ans = 3 4

A find függvény mátrixok esetén lineáris indexelést használ, mikor visszaadja az eredményt.

>> mat = [ 1:3; 3:5 ] mat = 1 2 3 3 4 5 >> find(mat == 3) ans = 2 5

Az isequal nagyszerű függvény, mikor vektorok összehasonlításáról van szó. Matlabban az egyenlőség operátor 0-t vagy 1-et ad vissza minden elemre, ha vektort vagy mátrixot hasonlítunk össze. Ezután all függvénnyel megvizsgálhatjuk, hogy minden elem egyenlő-e vagy sem. Mindez azonban egy lépésben is megtehető az isequal segítségével.

>> vec1 = [ 1 8 3 ]; >> vec2 = [ 1 5 3 ]; >> all(vec1 == vec2) ans = 0 >> isequal(vec1, vec2) ans = 0

A Matlab logikai és (&), logikai vagy (|) operátorai elemenként működnek azonos méretű mátrixokra. A || és && operátorok csak skalárokkal használhatók, mátrixokkal nem.

>> vec1 = [ 1 0 5 2 ]; >> vec2 = [ 0 0 1 3 ]; >> vec1 & vec2 ans = 0 0 1 1 >> vec1 | vec2 ans = 1 0 1 1 >> vec1 && vec2 Operands to the || and && operators must be convertible to logical scalar values.

Kód vektorizálása

A vektorizálás az takarja, hogy átírjuk a kódot, mely nem hatékonyan, esetleg más nyelven íródott, hogy kihasználjuk a beépített függvények és műveletek adta lehetőségeket Matlabban. Számos esetben ez azt jelenti, hogy ezeket a beépített függvényeket és operátorokat használunk ciklusok és kiválasztó utasítások helyett.

Például a signum függvény a következő:

function eredmeny = signum(mat) [ sorok oszlopok ] = size(mat); for sor = 1:sorok for oszlop = 1:oszlopok if mat(sor, oszlop) > 0 eredmeny(sor, oszlop) = 1; elseif mat(sor, oszlop) == 0 eredmeny(sor, oszlop) = 0; else eredmeny(sor, oszlop) = -1; end end end end >> signum([0 -1 2 3]) ans = 0 -1 1 1

Persze, gyorsan rájövünk, hogy ez nem más, mint a beépített sign függvény! Tehát nem kell a signum függvény megírásával bajlódnunk Matlabban.

Hogy tudjunk kódot vektorizálni Matlabban, néhány fontos dolgot kell fejben tartani:

Számos függvény található a Matlabban, mely felváltja az olyan kódokat, melyek végigiterálnak és kiválasztanak. Néhányat bemutattunk, de érdemes összefoglalni őket hasznosságuk hangsúlyozása érdekében:

Említést érdemelnek a diff és meshgrid függvények. A diff kiszámolja egy vektor szomszédos elemeinek különbségét:

>> diff([5 6 15 8]) ans = 1 9 -7

Például jól jöhet a diff akkor, ha egy jeleket tartalmazó vektorban meg szeretnénk keresni, hol lehet nulla a jel, hol megy át pozitívból negatívba és fordítva.

>> vec = [-2.0 -1.5 0.5 1.0 -0.5]; >> signumvec = sign(vec) signumvec = -1 -1 1 1 -1 >> diffvec = diff(signumvec) diffvec = 0 2 0 -2 >> find(diffvec) ans = 2 4

Azt kaptuk tehát, hogy a 2. és 3., 4. és 5. elemek között veszi fel a jel a nulla értéket.

A meshgrid függvény bemenetként vár két vektort és kimenete két mátrix, melyek megadják az x és y koordinátákat egy képen, vagy használható olyan függvényekhez, melyeknek bemenete x és y. Például egy 3 x 2-as méretű kép pontjai lehetnek a következő koordináták:

(1,1) (2,1) (3,1) (1,2) (2,2) (3,2)

A mátrixok, melyek együttesen határozzák meg a koordinátákat a meshgrid függvénnyel hozhatók létre:

>> [ x y ] = meshgrid(1:3, 1:2) x = 1 2 3 1 2 3 y = 1 1 1 2 2 2

Ha ki szeretnénk számolni valamilyen függvényt (legyen most f(x,y) = 2*x+y) a koordinátákon, akkor vektorizált kóddal a következő módon tehetjük meg:

>> f = 2*x+y f = 3 5 7 4 6 8