Java týden Java týden
Aprílový black friday tě nenechá v klidu! Až 80 % prémiového obsahu zdarma. Více informací
Pouze tento týden slevy až 80 % na programování v Javě

Matlab zlehka - Vektory a matice dějství první

Software Matlab Matlab zlehka - Vektory a matice dějství první

Unicorn College ONEbit hosting Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

Matlab je taková důmyslná kalkulačka. Chcete-li se jí naučit používat, je potřeba ovládnou především tyto 2 věci:

  • Práce s dokumentací
  • Práce s maticemi

Dokumentace

Dokumentace je precizní a poměrně rozsáhlá. Je součástí samotné instalace a má i webovou verzi. Dokumentace je konzistentní a když pochopíte její systém a umíte k tomu vhodně položit dotaz do Googlu, většina problémů je napůl vyřešena.

Matice

Druhou nezbytnou záležitostí k ovládnutí MATLABu je práce s maticemi. Jeden příklad za všechny: Máme definované dvourozměrné pole (matici). Úkolem je ke každému prvku pole přičíst hodnotu 20.

Pokud umíte programovat v jiném jazyce, možná by vás napadlo použít cykly. Např. v C# bychom to udělali takto:

var pole = new int[,]{ {5, 6},{9, 8},{6, 1} };
for(int k=0;k < pole.GetLength(0);k++)
  for(int l=0;l < pole.GetLength(1);l++)
    pole[k,l]+=20;

Ekvivalentem v MATLABu ale je:

pole = [5 6; 9 8; 6 1];
pole = pole + 20;

Žádný dvojitý cyklus, pouze jednoduché přičtení. MATLAB zde pochopil, že ke každému prvku z matice chceme přičíst 20. Pokud bychom to udělali toto: pole = pole + [10 20], tedy snažili se přiřadit k matici vektor, zahlásí nám prostředí chybu, protože už neví jak si s tím poradit (co by se od toho také dalo čekat, že...).

Typování

MATLAB je slabě typový jazyk (stejně jako např. JavaScript nebo Python), nemusíme mu definovat, že číslo je int nebo double. Tato vlastnost je skvělá pro rychlé psaní skriptů. Při tvorbě komplexnějšího programu trochu překáží, respektive nepohlídá za vás některé hloupé chyby. Můžeme totiž napsat něco jako:

promenna = 21;
promenna = "teď je tu string a nikdo si nestěžuje"

Nikdo si sice nestěžuje, ale až se o pár desítek řádků kódu dál budeme snažit přičíst k proměnné nějaké číslo, bude to už problém a pro zjišťování jeho příčiny se musíme prokousat o ty desítky řádků zpět (a nevíme jak moc zpět).

Tvorba vektorů

Po teoretické odbočce zpět k maticím. Z definice proměnné pole = [5 6; 9 8; 6 1]; je zřetelné, jak se definuje matice. V hranatých závorkách, oddělovačem čísel je mezera (nebo čárka), oddělovačem řádků je středník. Finální středník je zde proto, aby se zamezilo vypsání do konzole.

Chceme-li vytvořit vektor obsahující čísla například o 1 do 100, lze to pomocí dvojtečky:

vektor = 1:100;

Zkusme si každé druhé číslo od 1 do 100:

vektor = 1:2:100;

Vložením dalšího čísla mezi dvojtečky se tedy definuje krok. Funguje to i s desetinnými čísly:

vektor = 1:0.1:100;

nebo bez té nuly:

vektor = 1:.1:100;

Funguje to též pozpátku, jen je nutné krokovat zápornou hodnotou:

vektor = 100:-.5:1;

Přístup k prvkům vektoru (jaký prvek je na 20. místě vektoru?)

Chceme-li zjistit co se ve vektoru skrývá, tedy přistoupit k prvkům pole, využijeme index a kulaté závorky. Zde přiřazujeme do proměnné v dvacáté číslo vektoru:

v = vektor(20)

Ekvivalentem v C# by bylo:

int v = vektor[19];

Ano, MATLAB, na rozdíl od většiny používaných jazyků, indexuje od 1.

Chceme-li vytáhnout více prvků z vektoru, stačí ho naindexovat vektorem. 20. ,21., a 22. prvek vektoru získám:

prvky20_22 = vektor([20 21 22]);

Zde je částečné vysvětlení toho, proč se k přístupům prvků nevyužívají hranaté závorky – ty se používají k definici vektorů a matic.

Pokud by prvků bylo více, nebudeme je v indexačním vektoru vypisovat všechny, ale zase využijeme dvojtečky:

prvky20_50 = vektor(20:50)

Zde již nepotřebujeme hranatou závorku, vektor se prozradil právě tou dvojtečkou. Dalším způsobem, jak vytáhnout prvky vektoru, je pomocí binárního vektoru:

vektor = [1 5 6 9 8 3];
pouze_neco_z_vek = vektor([0 0 1 1 0 0])

Tímto zápisem říkáme: První prvek neber, druhý také ne, třetí ano, čtvrtý ano, pátý ne, šestý také ne... Výsledkem je [6 9]. Binární vektor musí mít stejnou délku jako vektor původní (jinak by to nedávalo smysl). K čemu je to dobré?

Podmínky při výběru prvků vektoru (vrať čísla větší než 6)

Z vektoru chceme pouze čísla větší než 6:

vetsi_nez_6 = vektor(vektor>6)

Výsledek je [9 8].

Tento na první pohled trochu krkolomný zápis obsahuje dva kroky. Ten vnitřní je tvorba binárního vektoru. Tážeme-li se, zdali je vektor větší než skalár (vektor>6), MATLAB to pochopí a proiteruje podmínkou celý vektor. Tam kde splněna zaznamená jedničku, tam kde nikoliv, nulu. No a tento binární vektor je následně využit k indexování samotného vektoru.

C# ekvivalentem bylo toto:

var vetsi_nez_6  = new List<int>();
for(int k=0;k < pole.GetLength(0);k++)
  if(pole[k]>6)
    vetsi_nez_6.Add(pole[k]);

Anebo zjednodušeně převodem na List a za použití LINQu:

var pole = new int[]{ 1, 5 ,6, 9, 8 , 3 };
var vetsi_nez_6 = (new List<int>(pole)).Where(x=>x>6);

Vícero podmínek při výběru prvků (vrať sudá čísla větší než 6)

Podmínky při tahání prvků z vektoru se pochopitelně dají kumulovat. Chceme-li tedy z vektoru získat pouze prvky větší než 6, které jsou sudé:

vetsi_nez_6_sude = vektor((vektor>6) & (~mod(vektor,2)))

První část výrazu je známá, za ní následuje logické AND (tedy jednička vznikne pouze v případě, že na obou stranách budou jedničky). Druhá část je zodpovědná za určení, zdalipak je číslo ve vektoru sudé. Děje se tak s pomocí funkce mod() (MATLAB nemá operátor modulo, jako třeba C# má %. Procento je v MATLABu používáno pro komentáře). Modulo nějakého čísla je zbytek po celočíselném dělení a může nabývat jakékoliv hodnoty od 0 do čísla-1. V případě, že "modulujeme" s pomocí dvojky, jsou možnosti buď 0 nebo 1. Zde se projevuje výhodnost slabé typovosti. Výstupem funkce mod() je v tomto případě pouze binární vektor. Vlnovka ~ je operátorem negace (v C# vykřičník !). Využíváme jí proto, aby se z jedniček, které vzniknou po "modulování" dvojkou u lichých čísel staly nuly, a tím pádem výsledné číslo nebylo vybráno.

Stejná pravidla jako pro indexování vektorů platí i pro indexování matic. Chceme-li získat z matice M pouze ty, které jsou dělitelné 3, uděláme to následovně:

M = [1 3 6 8; 5 6 9 3; 2 1 2 9];
delitelne_3 = M(mod(M,3)==0) % 1. řešení
delitelne_3_alt = M(~mod(M,3))% 2. řešení

Zde jsem vytvořil 2 řešení, první porovnává výsledek modula s nulou, která vznikne v případě dělitelnosti třemi. Alternativní zápis využívá opět operátoru negace. Ten ze všech čísel, která nejsou 0, udělá právě 0. Výsledky jsou stejné.

Zápis je zcela totožný tomu, jako bychom operaci prováděli s vektory. Výstupem je též vektor, také z toho důvodu, že předem nevíme, jaký výsledek bude a jestli by se vůbec do matice poskládal (jak vytvoříte dvourozměrnou matici o třech prvcích...). MATLAB iteruje maticí podobně jako vektorem. Nemusíme k tomu používat cykly a tento funkcionální a maticový přístup je doporučený způsob práce. Také je to způsob, který spoustě lidem dělá trable řádně uchopit, zvlášť když za vším vidí cyklus (a on tam ve skutečnosti je). Nicméně komu se to podaří, má nad MATLABem zpola vyhráno. A nejen to. Funkcionální přístup se promítá v mnoha jiných jazycích: R, Haskell, Scala, F#, a mnohé další. Koneckonců i C#, především od své 7. verze, přidává způsoby, jak řešit problémy funkcionálně (například výše zmíněný kód pro filtrování čísel větších než 6).

Nahrazení prvků splňujících podmínku (čísla větší než 6 změň na 0)

Už víme jak z vektoru (nebo matice) získáme prvky splňující podmínku. Nyní tyto prvky nahradíme jiným číslem:

vektor = [1 5 6 9 8 3];
vektor(vektor>6) = 0;

Tímto kusem kódu jsme čísla přesahující 6 nahradili nulou. Výběr prvků se nám přesunul na levou stranu rovnítka.

Editace prvků splňujících podmínku (čísla větší než 6 zvětši o 3)

Předchozí příklad čísla zcela nahradil, nyní prvky jen trochu upravíme:

vektor(vektor>6) = vektor(vektor>6) + 3;

Je to zas kombinace již známých postupů. Podmínka je na obou stranách. Tento zápis bych nejradši zjednodušil následovně:

%Tento kód není validní
vektor(vektor>6) +=3;

, tak jak to známe z mnoha jiných jazyků. Nicméně v MATLABu to nelze. Musíme se tedy spokojit s podmínkou na obou stranách. Odporuje to principu DRY (don't repeat yourself). Můžeme s tím provést jen toto:

podminka = vektor>6;
vektor(podminka) = vektor(podminka) + 3;

Nevypadá moc elegantněji, avšak pokud je podmínka náročnější (delší), vyplatí se jí takto odstrčit do proměnné. podminka bude obsahovat pouze 0 a 1.

Cvičení

Na závěr pár příkladů, jejichž řešení naleznete na konci přiloženého souboru. Soubor obsahuje i veškerý kód z tohoto článku.

  • Vytvořte vektor f s celými čísly od 101 do 202 a z něho získejte:
  • první a poslední prvek.
  • prvních 12 prvků.
  • všechny prvky dělitelné 9.
  • každý 4. prvek.
  • vektor jehož hodnoty mají poloviční hodnotu.
  • vektor jehož hodnoty jsou o 7 větší.
  • posledních 13 prvků.
  • posledních 10 prvků dělitelných 2.
  • sedmý až devatenáctý prvek
  • prvky dělitelné pěti jejichž poslední číslovka není 0.

Příště se podrobněji podíváme na matice a konečně si řekneme, k čemu je to všechno dobré :)


 

Stáhnout

Staženo 0x (1.3 kB)
Aplikace je včetně zdrojových kódů

 

 

Článek pro vás napsal tesař.tech
Avatar
Jak se ti líbí článek?
Ještě nikdo nehodnotil, buď první!
Autor se věnuje dýchání přibližně celý život
Miniatura
Předchozí článek
Práce s maticemi a vektory
Miniatura
Všechny články v sekci
Matlab
Aktivity (2)

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!