MATLAB - lekce 9
Stránka 1 z 14
Pole buněk (cell arrays) Pole buněkjsou datovým typem MATLABu (cell) a umožňují uložit různé druhy dat do jedné proměnné. Mohou mít rozměry 1×n, m×1 nebo m×n (nebo být vícerozměrná).
Vytvoření pole buněk Pole buněk vytváříme • pomocí složených závorek, do kterých uvedeme jednotlivé prvky pole buněk. Příklad - pole buněk o rozměru 2×2: P = {[1 4 3; 0 5 8; 7 2 9], 'Anne Smith'; 3+7i, -pi:pi/4:pi};
• pomocí funkce cell: ◦ c = cell(n) ... pole buněk typu n#&215;n s prázdnými prvky (n musí být skalár); ◦ c = cell(m, n) nebo c = cell([m, n]) ... pole buněk typu m×n s prázdnými prvky (vstupy musí být skaláry); ◦ c = cell(m, n, p,...) nebo c = cell([m n p ...]) ... pole buněk o rozměrech m×n×p×... s prázdnými prvky (vstupy musí být skaláry); ◦ c = cell(size(A)) ... pole buněk stejného rozměru jako A, s prázdnými prvky. Příklad: >> A = ones(2,2); >> c = cell(size(A)) c = [] []
[] []
Tato funkce je také vhodná pro předalokování paměti pro pole buněk - jednotlivé prvky pak inicializujeme pomocí přiřazovacího příkazu (viz níže - přístup k prvkům pole buněk). • pomocí jednotlivých přiřazovacích příkazů: ◦ se složenými závorkami (tzv. content indexing): >> P{1,1} = [1 4 3; 0 5 8; 7 2 9]; >> P{1,2} = 'Anne Smith'; >> P{2,1} = 3+7i; >> P{2,2} = -pi:pi/10:pi;
◦ s kulatými závorkami (tzv. cell indexing): >> P(1,1) = {[1 4 3; 0 5 8; 7 2 9]}; >> P(1,2) = {'Anne Smith'};
MATLAB - lekce 9
Stránka 2 z 14
>> P(2,1) = {3+7i}; >> P(2,2) = {-pi:pi/10:pi;}
Pozn. 1: oba uvedené způsoby vytvoří stejné pole buněk jako příkaz P = {[1 4 3; 0 5 8; 7 2 9], 'Anne Smith'; 3+7i, -pi:pi/4:pi};
Pozn. 2: přiřazením lze pole buněk "nafukovat" (MATLAB udržuje obdélníkové schéma, a proto "chybějící" neinicializované prvky obsahují prázdnou matici): >> P(3,3) = {5};
dává tento výsledek:
Vnořená pole buněk Prvkem pole buněk může být i jiné pole buněk: >> retezce = char('Anne >> C2 = {'text' [4 2; 1 >> C1 = {[3 4 2; 9 7 6; [1.43 2.98 7.83 5.67
Obsah pole buněk C1:
Smith', '9/12/94', 'Class II', 'Obs. 1', 'Obs. 2'); 5]; [7.3 2.5; 1.4 0] .02+8i}; 8 5 1] retezce [.25+3i 8-16i; 34+5i 7+.92i]; ... 4.21] [-7 2 -14; 8 3 -45; 52 -16 3] C2}
MATLAB - lekce 9
Stránka 3 z 14
Paměťové nároky MATLAB si uchovává interní informace o poli buněk ve spojitém segmentu paměti (tzv. header). Při zvětšení pole buněk proto může dojít k chybě "out of memory". Samotné prvky pole buněk jsou v paměti uchovávány nespojitě. Vždy je lepší paměť předalokovat pomocí funkce cell, pokud dopředu známe rozměry pole buněk.
Přístup k prvkům pole buněk • Přístup k obsahu jednoho prvku pole buněk - složené závorky s uvedením indexu/ů (podle počtu dimenzí): >> C1{1,1} % obsahem je matice ans = 3 9 8
4 7 5
2 6 1
>> C1{2,3} % obsahem je jiné pole buněk ans = 'text' [2x2 double]
[2x2 double] [0.0200 + 8.0000i]
>> C1{2,3}{2,1} % přístup k prvku vnořeného pole buněk ans = 7.3000 1.4000
2.5000 0
>> C1{2,3}{2,1}(1,2) % prvek matice ve vnořeném poli buněk ans = 2.5000
Při změně prvku se indexovaný prvek uvede na levou stranu přiřazení: >> C1{2,3}{2,1}(1,2) = 8 C1 = [3x3 double] [1x5 double]
[5x10 char ] [3x3 double]
[2x2 double] {2x2 cell }
>> C1{2,3}{2,1} % kontrola změny prvku ans = 7.3000 1.4000
8.0000 0
• Přístup k jednomu prvku jakožto poli buněk - kulaté závorky s uvedením indexu/ů (nevrátí obsah, ale jednoprvkové pole buněk):
MATLAB - lekce 9
Stránka 4 z 14
>> C1(1,1) % vrátí jednoprvkové pole buněk ans = [3x3 double] >> ans{1} % tj. C1{1,1} je totéž jako C1(1,1){1} ans = 3 9 8
4 7 5
2 6 1
• Přístup k obdélníkové časti pole buněk - kulaté závorky a "vektorová indexace": >> C(3,1:4) = {magic(5), 'Hello', uint8(100), [1:3:19]} C = [] [] [] [] [] [] [] [] [5x5 double] 'Hello' [100] [1x7 double] >> clear C >> C(2:3,5:6) = {magic(5), 'Hello'; uint8(100), [1:3:19]} C = [] [] [] [] [] [] [] [] [] [] [5x5 double] [ 100] [] [] [] [] 'Hello' [1x7 double]
Pokud přiřazujeme do části pole buněk hodnoty, tak musí souhlasit rozměry! >> clear C >> C(2:3,5:6) = {magic(5), 'Hello', uint8(100), [1:3:19]} % chyba ??? Subscripted assignment dimension mismatch.
Mazání prvku/ů v poli buněk Jednotlivé buňky (prvky) pole buněk lze mazat - smazat lze celý řádek nebo sloupec (přiřazením prázdné matice). Pokud při "jednoprvkové" indexaci smažeme jeden prvek, tak výsledné pole buněk bude typu 1×n. Příklad: >> D = C1; >> D(:,2) = [] % pole typu 2×2 >> D = C1; >> D(6) = [] % pole typu 1×5
Spojování polí buněk Pole buněk lze spojovat: • pomocí hranatých závorek - vznikne pole buněk s prvky spojovaných polí, • pomocí složených závorek - vznikne pole buněk, kde prvky jsou spojovaná pole buněk, • pomocí funkce cat: ◦ C = cat(dim, A, B) ... spojí obě pole buněk podle zadané dimenze, ◦ C = cat(dim, A1, A2, A3, A4, ...) ... spojí všechna zadaná pole buněk podle zadané dimenze.
MATLAB - lekce 9
Stránka 5 z 14
Jsou-li vstupní pole neprázdná, pak cat(2, A, B) vrací totéž jako [A, B] a cat(1, A, B) vrací totéž jako [A; B]. • pomocí funkce horzcat: ... spojí vstupní proměnné v horizontálním směru (podle druhé dimenze) vstupy musí mít stejný počet řádků (první dimenzi) a zbylé dimenze (vyšší než 2)! MATLAB volá C = horzcat(A1, A2,...) pro syntaxi C = [A1 A2 ...]. C = horzcat(A1, A2, ...)
• pomocí funkce vertcat: ... spojí vstupní proměnné ve vertikálním směru (podle první dimenze) vstupy musí mít stejný počet sloupců (druhou dimenzi) a zbylé dimenze (vyšší než 2)! MATLAB volá C = vertcat(A1, A2,...) pro syntaxi C = [A1; A2; ...].
C = vertcat(A1, A2, ...)
Funkce pro práci s poli buněk Zjišťování rozměrů pole buněk Pro zjišťování rozměrů lze použít již známé funkce: • size ... rozměr pole buněk: ◦ d = size(X) ... vrátí n-prvkový vektor (n je počet dimenzí) s rozměry, ◦ [m,n] = size(X) ... počet řádků a sloupců pole buněk, ◦ m = size(X,dim) ... počet prvků v dané dimenzi dim (kladný skalár), ◦ [d1,d2,d3,...,dn] = size(X) ... podrobnosti v nápovědě. • length ... počet prvků v největší dimenzi: >> A=cell(12,32,8,1,4); >> length(A) ans = 32
• ndims ... počet dimenzí pole buněk • numel ... počet prvků (ve všech dimenzích) pole buněk
Zobrazení obsahu pole buněk • celldisp ... výpis obsahu jednotlivých buněk (do Command Window) Vyzkoušejte: >> celldisp(C2) >> celldisp(C1)
• cellplot ... grafické znázornění struktury pole buněk (do okna Figure) Vyzkoušejte: >> cellplot(C2) >> cellplot(C1)
• deal ... rozdistribuuje vstupní pole do výstupních proměnných (od MATLABu 7.0 je toto možno provádět bez funkce deal, pouze s použitím operátoru :) Vyzkoušejte: >> P2 = {magic(6) ones(3,1) eye(3) zeros(3,1)}; >> [a,b,c,d] = deal(P2{:}) >> [a,b,c,d] = P2{:} % od MATLABu 7.0
MATLAB - lekce 9
Stránka 6 z 14
Změna rozměru pole buněk Pokud potřebujeme přeuspořádat pole buněk (se zachováním počtu prvků!), lze využít funkci reshape: • B = reshape(A,m,n) ... převede A "po sloupcích" na rozměr m×n (nelze přidat ani odstranit prvky - m.n se musí shodovat s původním počtem prvků!): >> C1, numel(C1) C1 = [3x3 double] [1x5 double] ans = 6
[5x10 char ] [3x3 double]
[2x2 double] {2x2 cell }
>> D = reshape(C1,3,2) D = [3x3 double] [3x3 double] [1x5 double] [2x2 double] [5x10 char ] {2x2 cell } >> D = reshape(C1,4,2) % chyba ??? Error using ==> reshape To RESHAPE the number of elements must not change.
• B = reshape(A,m,n,p,...) nebo B = reshape(A,[m n p ...]) ... převede na vícerozměrné pole buněk, opět musí souhlasit počet nových a starých prvků • B = reshape(A,...,[],...) ... dopočítá chybějící dimenzi a převede pole buněk na nové rozměry - [] smí být uvedeny právě jednou
Aplikace funkcí na pole buněk • cellfun ... zavolá danou funkci pro každý prvek skalárního pole buněk • varargin ... počet vstupů funkce (u funkce s proměnným počtem vstupů) • varargout ... počet výstupů funkce (u funkce s proměnným počtem výstupů)
Informační funkce Funkce pro zjištění, zda proměnná je datového typu pole buněk (cell array): iscell.
Konverze na jiné datové typy • cell2struct ... převede pole buněk na pole struktur • struct2cell ... převede pole struktur na pole buněk • cell2mat ... převede pole buněk obsahující matice na jednu velkou matici (rozměry prvků pole buněk musí dohromady dát "obdélník"!) • mat2cell ... rozdělí matici dopole buněk podle zadaných rozměrů (2. a 3. vstup jsou "dělicí vektory") • num2cell ... převede pole čísel (matici) na pole buněk - každý prvek je jedna buňka
MATLAB - lekce 9
Stránka 7 z 14
Struktury (structures) Struktura je datový typ MATLABu (struct), který obsahuje pojmenované "datové kontejnery" - položky (fields). Položka struktury smí obsahovat data libovolného datového typu. Příklad 1: struktura s s položkami a (obsahuje vektor), b (obsahuje řetězec) a c (obsahuje matici):
Příklad 2: struktura patient s položkami name (obsahuje řetězec), billing (obsahuje skalár) a test (obsahuje matici):
Struktura tedy podobně jako pole buněk umožňuje uchovávat heterogenní data, ale navíc díky pojmenovaným položkám umožňuje opatřit tato data "popiskem".
Vytvoření struktury Jména položek struktury musí splňovat stejná pravidla jako názvy proměnných v MATLABu (viz 1. týden). Rozlišují se velká a malá písmena (case-sensitive názvy položek). Struktury lze vytvářet: • pomocí přiřazovacího příkazu - pro přístup k položce struktury se používá tečka: >> >> >> >>
s.a = [1 4 7 2 9 3]; % vytvoří strukturu s 1 položkou s.b = 'James'; % přidá další položku s.c = magic(3); s
s = a: [1 4 7 2 9 3] b: 'James' c: [3x3 double]
• pomocí funkce struct (vstupem jsou dvojice jméno položky - hodnota): >> s = struct('a',[1 4 7 2 9 3], 'b','James', 'c',magic(3));
MATLAB - lekce 9
Stránka 8 z 14
Vnořené struktury Prvkem struktury může být jiná struktura, např.: >> S1 = struct('jmeno','Jan', 'narozen',1980); >> S2 = struct('clovek',S1, 'vyska',180, 'vaha',72.4);
Paměťové nároky Struktura nevyžaduje souvislý blok paměti, pouze každá její položka musí mít svůj spojitý blok paměti. Dále se spojitě ukládají interní informace o struktuře (např. jména položek atp.). Pro případ vytvoření velkého pole struktur je vhodné předalokovat paměť. To lze provést jedním z následujících způsobů (příklady jsou pro dvourozměrné pole 25×50, tj. "matici" struktur): • S(25,50) = struct( 'a', [], 'b', [], 'c',[]); % inicializujeme poslední prvek neboli S(25,50).a = []; S(25,50).b = []; S(25,50).c = [];
• S(1:25,1:50) = struct('a', 20, 'b', 30, 'c', 40); % přiřadíme do všech prvků stejnou strukturu
neboli S = repmat(struct('a', 20, 'b', 30, 'c', 40), [25 50]);
Sdružování struktur do polí Pro efektivnější zpracování dat se struktury často sdružují do polí. Pole struktur lze vytvářet: • pomocí přiřazovacího příkazu - za název pole struktur se uvede do kulatých závorek index do pole struktur a přiřadí se mu data (jedna struktura), • pomocí funkce struct: ◦ výsledek funkce přiřadíme do prvku pole struktur, ◦ vytvoříme celé pole struktur pomocí polí buněk místo hodnot položek. Příklad: rozšíříme strukturu s na pole struktur: 1. způsob s(2).a='Anne'; s(2).b=pi; s(2).c=[1:7]';
2. způsob s(2) = struct('a','Anne', 'b',pi, 'c',[1:7]'); 3. způsob % vše v jednom clear s s = struct('a',{[1 4 7 2 9 3], 'Anne'}, ... 'b',{'James',pi}, ... 'c',{magic(3),[1:7]'})
MATLAB - lekce 9
Stránka 9 z 14
Ve všech případech dostaneme tento výsledek:
Poznámka: pro efektivnější zpracování je vhodné, aby stejně pojmenované položky obsahovaly podobná data (např. aby v položce a byl vždy řetězec apod.). MATLAB udržuje úplnost každé struktury v poli struktur, tzn. pokud nepřiřadíme data do nějaké položky, tak je chápána jako prázdná matice: >> s(3).c = [1 3 1 2 1] % položky 'a' a 'b' budou prázdné s = 1x3 struct array with fields: a b c
POZOR: pokud budeme do pole struktur přidávat prvek pomocí funkce struct, tak musíme vyplnit VŠECHNY položky! >> s(4) = struct('a','George', 'c',[1:5]) % chybí položka 'b' ??? Subscripted assignment between dissimilar structures.
Přístup k položkám struktury Pro přístup k položce struktury se používá tečka a název položky. Příklad: >> auto = struct('typ','Skoda Fabia', 'barva','modra', 'rok',2003); >> auto.barva ans = modra
V případě pole struktur se příslušný prvek indexuje kulatými závorkami s indexem do pole, a pak tečka a jméno položky struktury. Příklad:
MATLAB - lekce 9
Stránka 10 z 14
>> auto(2) = struct('typ','Skoda Octavia', 'barva','stribrna', 'rok',2005); >> auto(2).barva ans = stribrna
Pozn.: lze indexovat i část pole struktur nebo vypsat hodnoty jedné položky všech struktur v poli: >> auta2 = auto(1:2); % první dvě auta - 'auta2' je opět pole struktur >> auto.rok % výpis hodnot položky 'rok' u VŠECH struktur v poli ans = 2003 ans = 2005 >> v = [auto.rok] % v tomto případě je možné uložit hodnoty do vektoru
V případě vnořených struktur se tečka opakuje tolikrát, kolikrát je potřeba. Příklad: >> auto(3) = struct('typ',struct('a','Audi','b','BMW'), 'barva','bila', 'rok',2003); >> auto(3).typ.a ans = Audi
Dynamická jména položek MATLAB umožňuje přistupovat k položkám struktury pomocí dynamického jména - je nutno použít tečku a za ní kulaté závorky s výrazem, který bude převeden na jméno konkrétní položky: jméno_struktury.(výraz) (při provádění příkazu se výraz
převede na jméno položky).
Funkce pro práci s položkami struktury funkce
popis fieldnames vrátí jména všech položek struktury jako pole buněk (obsahuje řetězce) isfield zjistí, zda daná položka existuje v dané struktuře getfield vrátí obsah zadané položky v zadané struktuře setfield nastaví nový obsah položky struktury a vrátí změněnou strukturu rmfield vymaže položku ze struktury orderfields vrátí kopii zadané struktury, která má abecedně seřazené položky
Funkce pro práci se strukturou funkce struct isstruct
popis vytvoření struktury, resp. polí struktur (popis výše) jedná se o strukturu?
struct2cell cell2struct size length ndims numel
fce je popsána u polí buněk
MATLAB - lekce 9
Stránka 11 z 14
reshape deal cat horzcat vertcat structfun
aplikuje funkci na každou položku (skalární) struktury
Třídy a objekty Protože v MATLABu 7.6 byl objektový model přepracován, tak následující text bude obsahovat podle potřeby poznámku, které verze se text odstavce týká: M+7.6 (nový), M-7.6 (starý). Starý objektový model je stále ještě podporován. Třídy a objekty umožňují přidat do MATLABu nové typy dat a nové operace. Třída může obsahovat členské proměnné a metody (členské funkce). Objekt je instancí dané třídy.
Výhody OOP • Přetížení funkcí a operátorů - lze vytvářet metody nad existujícími funkcemi MATLABu. (Pokud se volá funkce, jejímž parametrem je objekt, MATLAB nejprve zjistí, zda je taková metoda pro danou třídu definována. Pokud ano, MATLAB ji zavolá, jinak je volána normální funkce MATLABu.) • Zapouzdření dat a metod - členské proměnné a metody nejsou viditelné mimo objekt (např. z příkazové řádky) - lze je použít pouze v metodách dané třídy. Tím je zajištěno, že vlastnosti objektu jsou chráněné před metodami, které nejsou určeny pro danou třídu. • Dědičnost - lze vytvářet hierarchii tříd (rodiče a potomky), potomek dědí data i metody od rodičovské třídy; lze dědit od jednoho rodiče (single inheritance) nebo od více rodičů (multiple inheritance). • Agregace - lze vytvořit třídy, kde objekt je obsažen v jiném objektu.
Hierarchie datových typů v MATLABu
Je vidět, že user classes jsou odvozeny ze struktur. Všechny třídy, které vytvoříme, spadají pod struktury.
MATLAB - lekce 9
Stránka 12 z 14
Vytváření objektů ... M-7.6 Třídy lze do prostředí MATLABu přidat pomocí adresáře (class directory), kde jsou uloženy M-soubory s metodami (M-funkce) a konstruktor (M-funkce obsahující volání funkceclass. Objekty vytváříme pomocí konstruktoru třídy (s předáním příslušných argumentů). Konstruktor nejprve vytvoří strukturu - její položky budou členské proměnné třídy (vlastnosti objektu). Před koncem funkce/konstruktoru musí být zavolána funkce proměnná = class(proměnná,'třída'), která z dané proměnné (typu struktura) vytvoří objekt. Tato proměnná (objekt) je pak výstupem konstruktoru. Konstruktor by měl zkontrolovat, zda vytvářený objekt je bezrozporný a validní!!! V MATLABu se konstruktor jmenuje stejně jako třída. Např. volání konstruktoru příkazem p = polynom([1 0 -2 -5]);
vytvoří objekt nazvaný p patřící do třídy polynom. Poté lze používat všechny metody definované pro třídu polynom. Metody pro danou třídu musí být umístěny v jednom adresáři (tzv. class directory), který se musí jmenovat @třída. Toto je první místo, kde MATLAB hledá metody pro danou třídu. Syntaxe pro volané metody (daného objektu) jsou podobné jako u obyčejných funkcí: [out1,out2,...] = metoda(objekt,arg1,arg2, ...);
Class directory = adresář, jehož jméno začíná znakem @ (je-li jméno třídy a jméno konstruktoru polynom, pak class directory se jmenuje @polynom). Jsou v něm uloženy všechny metody i konstruktor (definice) dané třídy. Při práci s konstruktorem a metodami dané třídy musí být pracovní adresář MATLABu nastaven tak, aby class directory byl bezprostředně jeho podadresářem! (Nebo přidat do vyhledávacích cest.) Přidání class directory do cest MATLABu Po vytvoření class directory je potřeba aktualizovat cesty MATLABu (MATLAB path), aby mohl nalézt zdrojové soubory pro třídu. Class directory nemůže být přidán přímo, ale přidáme rodičovský adresář: např. třída @polynom umístěná v adresáři c:/my_classes/@polynom
bude přidána do cest MATLABu použitím příkazu addpath c:/my_classes;
Privátní metody Privátní metody mohou být volány pouze jinými metodami dané třídy. Definujeme je tak, že příslušné Msoubory umístíme do podadresáře private (v adresáři @třída), např. @třída/private/update_obj.m
Tedy update_obj nemůže být volána z příkazového řádku MATLABu, ale mohou ji používat metody dané třídy.
MATLAB - lekce 9
Stránka 13 z 14
Ladění metod Podobá se ladění obyčejných funkcí, ale je potřeba přidat jméno class directory: dbstop @polynom/char
Vytváření objektů ... M+7.6 V novém objektovém modelu je konstruktor (resp. definice třídy) i metody uložen v jednom M-souboru. Přibylo několik klíčových slov, které umožňují oddělit členské proměnné od metod a především celý M-soubor začíná klíčovým slovem classdef. Pusťte si demo http://www.mathworks.com/support/2010b/matlab/7.11/demos/DevelopingClassesOverview.html.
na
Prozkoumejte nápovědu (např. na http://www.mathworks.com/help/techdoc/matlab_oop/brhzttf.html).
Přetěžování operátorů Class directory může také obsahovat funkce pro různé operátory MATLABu (např. aritmetické operátory, spojování atd.) - tzv. přetížené operátory:
Operace
M-soubor
Popis
a + b
plus(a,b)
součet
a - b
minus(a,b)
rozdíl
-a
uminus(a)
unární plus
+a
uplus(a)
unární minus
a.*b
times(a,b)
násobení po prvcích
a*b
mtimes(a,b)
násobení (maticové)
a./b
rdivide(a,b)
dělení po prvcích zprava
a.\b
ldivide(a,b)
dělení po prvcích zleva
a/b
mrdivide(a,b)
dělení (maticové) zprava
a\b
mldivide(a,b)
dělení (maticové) zleva
a.^b
power(a,b)
umocnění po prvcích
a^b
mpower(a,b)
umocnění (maticové)
a < b
lt(a,b)
menší než
a > b
gt(a,b)
větší než
a <= b
le(a,b)
menší nebo rovno
a >= b
ge(a,b)
větší nebo rovno
a ~= b
ne(a,b)
nerovno
a == b
eq(a,b)
rovno
a & b
and(a,b)
logické AND
MATLAB - lekce 9
Stránka 14 z 14
a | b
or(a,b)
logické OR
~a
not(a)
logické NOT
a:d:b a:b
colon(a,d,b) colon(a,b)
operátor dvojtečka
a'
ctranspose(a)
transpozice (komplexní)
a.'
transpose(a)
transpozice
výpis do command window
display(a)
výpis
[a b]
horzcat(a,b,...)
horizontální spojení proměnných
[a; b]
vertcat(a,b,...)
vertikální spojení proměnných
a(s1,s2,...sn)
subsref(a,s)
indexace
a(s1,...,sn) = b subsasgn(a,s,b)
přiřazení do prvku (dle indexu)
b(a)
indexace
Změna definice třídy clear classes
subsindex(a)