Hlavní navigace

Programujeme v jazyku J: vektory a matice

19. 1. 2010
Doba čtení: 10 minut

Sdílet

Dnes se zaměříme na popis problémů, které lze elegantně řešit v programovacím jazyku J. Budeme se zabývat především způsobem práce s vektory a maticemi – popíšeme si primitivní funkce určené pro práci s těmito strukturami, generátory indexů, způsob porovnávání vektorů a matic atd.

Obsah

1. Operace s vektory

2. Praktické příklady práce s vektory

3. Výběr prvků z vektorů

4. Využití generátorů indexů

5. Matice

6. Porovnávání skalárních hodnot i prvků vektorů

7. Obsah následující části seriálu

8. Literatura

9. Odkazy na Internetu

1. Operace s vektory

Programovací jazyk J je, podobně jako jeho ideový předchůdce APL, určen především pro tvorbu aplikací, v nichž se zpracovávají data uložená ve vektorech, maticích či polích s větším počtem dimenzí (může se jednat například o hierarchické mřížky atd.). Z tohoto důvodu je jazyk J vybaven jak jednoduchou syntaxí určenou pro zápis vektorů a matic, tak i sadou primitivních (základních) funkcí, pomocí nichž lze nad vektory i maticemi provádět různé operace. Nejprve si popíšeme primitivní funkce určené pro vytváření i další práci s vektory, které jsou vypsány v následující tabulce. U všech popisovaných funkcí bude uvedena i informace o tom, zda se jedná o funkci monadickou (tj. s jedním parametrem zapisovaným za symbol funkce) či dyadickou (s dvojicí parametrů, z nichž první se zapisuje před a druhý za symbol funkce). Tato informace je v případě jazyků JAPL velmi důležitá, protože již víme, že stejný symbol může být použit pro pojmenování dvou primitivních funkcí lišících se „pouze“ počtem svých parametrů:

Symbol funkce Forma funkce Popis funkce (význam)
+ – * % dyadická základní aritmetické operace prováděné nad dvojicí vektorů na korespondujících prvcích (též prováděné nad skalárem a vektorem)
< <: > >: = ~: dyadická porovnání korespondujících prvků dvou vektorů
# monadická vrací délku vektoru
# dyadická kopie prvků vektoru představovaného druhým parametrem
{ dyadická výběr prvku či více prvků z vektoru na základě indexů vybíraných prvků
{. dyadická výběr prvních n prvků z vektoru
}. dyadická výběr posledních délka-n prvků vektoru (= odstranění prvních n prvků)
, dyadická spojení dvou vektorů či vektoru se skalárem
/: monadická setřídění prvků vektoru sestupně (funkce vrací indexy prvků, ne jejich hodnoty)
\: monadická setřídění prvků vektoru vzestupně (funkce též vrací indexy prvků, ne jejich hodnoty)
i. monadická vytváří seznam (vektor) obsahující řadu čísel začínající nulou, popř. prázdný vek­tor
i: monadická vytváří seznam (vektor) obsahující čísla on -n do n, kde n je parametr funkce
p. monadická výpočet kořenů polynomu reprezentovaného vektorem obsahujícím koeficienty ai

2. Praktické příklady práce s vektory

Základní aritmetické operace, se kterými jsme se již seznámili v předchozí části tohoto seriálu, je možné využít i při práci s vektory. V tomto případě se operace provádí vždy nad dvojicí odpovídajících prvků (dyadické funkce) popř. postupně pro všechny prvky vektoru (funkce monadické). Pokud nejsou délky vektorů shodné, nahlásí interpretr jazyka J chybu typu „length error“:

   NB. Nejdříve vytvoříme tři proměnné
   NB. představující trojici vektorů
   x =: 1 2 3 4
   y =: 9 8 7 6
   z =: 11 12

   NB. Čtyři základní aritmetické operace
   NB. (součet, rozdíl, součin, podíl)
   NB. prováděné nad prvky vektorů
   x+y
10 10 10 10
   y-x
8 6 4 2
   x*y
9 16 21 24
   x%y
0.111111 0.25 0.428571 0.666667

   NB. Následující příkaz skončí s chybou
   NB. neboť délky vektorů (=počty jejich
   NB. prvků) nejsou shodné
   x+z
|length error
|   x    +z

Při použití aritmetických funkcí může být jedním z parametrů i skalární hodnota, viz následující demonstrační příklady:

   NB. Při volání aritmetických funkcí
   NB. je možné zkombinovat skalární hodnotu
   NB. s vektorem
   2 * x
2 4 6 8
   x * 2
2 4 6 8

   NB. Předchozí dva výrazy 2 * x a 2 * y
   NB. sice vrátily shodný výsledek, ale některé
   NB. další aritmetické operace nejsou
   NB. komutativní, například dělení:
   10 % x
10 5 3.33333 2.5
   x % 10
0.1 0.2 0.3 0.4

Následují dva příklady použití dalších funkcí, konkrétně dyadické exponenciální funkce a monadické funkce pro výpočet faktoriálu:

   NB. Při práci s vektory lze samozřejmě
   NB. použít i další primitivní funkce,
   NB. zde například funkci exponenciální
   x^y
1 256 2187 4096

   NB. Monadická funkce (výpočet faktoriálu)
   ! x
1 2 6 24

3. Výběr prvků z vektorů

Další důležitou a současně i často používanou skupinou základních (primitivních) funkcí určených pro práci s vektory jsou funkce, které umožňují z vektoru vybrat hodnoty některých prvků. Jedná se o rozšíření funkcí „take“ a „drop“, se kterými jsme se již seznámili při popisu programovacího jazyka APL, ovšem s tím rozdílem, že prvky vektorů jsou v případě jazyka J číslovány od nuly, tj. první prvek má index roven 0 a index posledního prvku je roven délce vektoru-1. Dále se v této skupině nachází funkce umožňující provést spojení dvou vektorů, která se zapisuje pomocí ASCII znaku „,“ – čárka. V aplikacích se poměrně často vyskytuje i funkce vracející délku vektoru (ASCII znak „#“). V případě matic či polí tato funkce vrací rozměr všech jejich dimenzí, což si ukážeme v navazujících kapitolách:

   NB. Nejdříve opět vytvoříme tři proměnné
   NB. představující trojici vektorů
   x =: 1 2 3 4
   y =: 9 8 7 6
   z =: 11 12

   NB. Zjistíme délky (počet prvků) všech vektorů
   #x
4
   #y
4
   #z
2

   NB. Spojení vektorů pomocí primitivní
   NB. funkce , (čárka)
   w =: x,y,z
   w
1 2 3 4 9 8 7 6 11 12

   NB. Jak je výsledný vektor w dlouhý?
   #w
10

   NB. Výběr pátého prvku (s indexem 4)
   4 { w
9
   NB. Výběr pátého, šestého a sedmého
   NB. prvku vektoru w (obdoba funkce take)
   4 5 6 { w
9 8 7

   NB. Výběr prvních čtyř prvků vektoru
   4 {. w
1 2 3 4

   NB. Vrácení vektoru BEZ jeho prvních
   NB. čtyř prvků (obdoba funkce drop)
   4 }. w
9 8 7 6 11 12

4. Využití generátorů indexů

Ve čtvrté kapitole si ukážeme způsob použití takzvaných generátorů indexů představovaných primitivními funkcemi zapisovanými pomocí symbolů i. a i:. Jedná se o funkce, které odpovídají primitivní funkci ι, s níž jsme se již seznámili při popisu programovacího jazyka APL, ovšem s tím podstatným rozdílem, že první číslo generované funkcí i. má hodnotu nula, nikoli jedna, a poslední číslo má hodnotu n-1 a nikoli n (to souvisí s tím, že v programovacím jazyce J jsou položky vektorů číslovány–indexovány od nuly, podobně jako například v programovacích jazycích C, C++ či Java – viz též předchozí kapitolu věnovanou indexování). Povšimněte si taktéž, že se pomocí funkce i. dá vytvořit velké množství různých (nejenom) aritmetických řad, takže pro tyto účely není nutné používat programové smyčky. Navíc mohou být primitivní funkce i. a i: součástí nějakého složitějšího výrazu, čehož se při psaní aplikací poměrně často využívá, například při programové tvorbě matic (jednotková matice, trojúhelníková matice atd.):

   NB. Základní použití generátoru indexů
   i. 10
0 1 2 3 4 5 6 7 8 9

   NB. Poměrně snadno můžeme dosáhnout toho,
   NB. aby se počáteční hodnota generované
   NB. číselné řady "posunula"
   20 + i. 10
20 21 22 23 24 25 26 27 28 29

   NB. Řada začínající hodnotou -10
   _10 + i. 10
_10 _9 _8 _7 _6 _5 _4 _3 _2 _1

   NB. Posun a současně i změna "kroku"
   NB. při generování číselné řady
   3 + 0.5 * i. 15
3 3.5 4 4.5 5 5.5 6 6.5 7 7.5 8 8.5 9 9.5 10

   NB. Mocninná řada čísla 2 vytvořená
   NB. bez použití programové smyčky
   2 ^ i. 10
1 2 4 8 16 32 64 128 256 512

   NB. Výpočet prvních faktoriálu prvních deseti
   NB. přirozených čísel a nuly.
   NB. (připomeňme si, že funkce se vyhodnocují
   NB.  zprava doleva, tj. nejdříve se vytvoří
   NB.  vektor čísel, na jehož prvky je aplikována
   NB.  primitivní funkce představující faktoriál)
   ! i. 10
1 1 2 6 24 120 720 5040 40320 362880

   NB. Pomocí primitivní funkce i: lze vygenerovat
   NB. číselnou řadu symetrickou okolo nuly
   i: 10
_10 _9 _8 _7 _6 _5 _4 _3 _2 _1 0 1 2 3 4 5 6 7 8 9 10

   NB. Změna kroku číselné řady
   2* i: 10
_20 _18 _16 _14 _12 _10 _8 _6 _4 _2 0 2 4 6 8 10 12 14 16 18 20

   NB. Opět výpočet mocnin čísla 2, tentokrát však
   NB. včetně záporných exponentů
   2^ i: 5
0.03125 0.0625 0.125 0.25 0.5 1 2 4 8 16 32

   NB. Vytvoření prázdného vektoru (jedna z nejčastěji
   NB. používaných možností tvorby prázdného vektoru)
   i. 0


   NB. Ovšem pozor: v následujícím případě
   NB. se vytvoří vektor obsahující jeden prvek
   i: 0

5. Matice

Práce s maticemi je v programovacím jazyku J stejně snadná jako práce s vektory. Základní funkci při práci s maticemi představuje funkce reshape zapisovaná pomocí symbolu $. Tato funkce má stejné vlastnosti jako funkce ρ zmiňovaná při popisu programovacího jazyka APL – v prvním parametru (zapisovaného nalevo od symbolu $) jsou uloženy rozměry matice, v parametru druhém (uváděném napravo od symbolu $) pak její jednotlivé prvky, typicky uložené ve vektoru nebo v jiné matici:

   NB. Vytvoření nulové matice
   NB. o rozměrech 3x3 prvky
   3 3 $ 0
0 0 0
0 0 0
0 0 0

   NB. Vytvoření matice a současně
   NB. i nastavení hodnot jejích prvků
   3 2 $ 1 2 3 4 5 6
1 2
3 4
5 6

   NB. Použití generátoru indexů
   NB. při vytváření matice
   3 4 $ i. 12
0 1  2  3
4 5  6  7
8 9 10 11

Velmi důležitou „maticovou“ funkcí je funkce pro výpočet inverzní matice zapisovaná symbolem %.. Pomocí této funkce lze například vypočítat soustavu n rovnic o n neznámých:

        x + 2y -3z = 15
        x + y + z = 12
       2x - y - z = 0

Nejprve vytvoříme příslušnou matici a zapíšeme do ní koeficienty (multiplikativní konstanty) uvedené před neznámými:

   NB. Prvky ležící na jednotlivých řádcích jsou
   NB. od sebe pro větší přehlednost odděleny
   NB. trojicí mezer.
   m =: 3 3 $   1 2 _3   1 1 1   2 _1 _1
   m
1  2 _3
1  1  1
2 _1 _1

S využitím funkce %.m lze snadno vypočítat inverzní matici:

   %.m
   0 0.333333   0.333333
 0.2 0.333333  _0.266667
_0.2 0.333333 _0.0666667

Po vynásobení inverzní matice vektorem obsahujícím pravé strany rovnic dostaneme kýžený výsledek – hodnoty neznámých x, y a z:

   15 12 0 %.m
4 7 1

Další (ještě pokročilejší) maticové operace si ukážeme příště.

6. Porovnávání skalárních hodnot i prvků vektorů

Pro vzájemné porovnávání skalárních hodnot i hodnot prvků uložených ve vektorech, maticích i polích s vyššími dimenzemi se používají predikátové funkce nahrazující relační operátory známé z jiných programovacích jazyků. Návratovou hodnotou těchto funkcí je buď skalární hodnota 0 nebo 1, popř. vektor či matice obsahující pouze nuly a jedničky (nula samozřejmě značí nepravdu, jednička pravdu). Tyto funkce jsou popsány v následující tabulce. Povšimněte si především způsobu zápisu podmínky „menší nebo rovno“, „větší nebo rovno“ a „nerovnost“, protože se v nich používají znaky, které jsou oproti jiným programovacím jazykům odlišné:

Symbol funkce Forma funkce Popis (význam)
< dyadická predikát „menší než“
<: dyadická predikát „menší nebo rovno“
> dyadická predikát „větší než“
>: dyadická predikát „větší nebo rovno“
= dyadická predikát rovnosti
~: dyadická predikát nerovnosti
e. dyadická predikát „obsahuje“

Použití výše uvedených funkcí při porovnávání skalárních hodnot je velmi snadné:

   1 <: 2
1
   1 >: 2

   1 <: 1
1
   1 ~: 2
1
   1 ~: 1

Kromě vzájemného porovnání skalárních hodnot je možné porovnat všechny prvky vektoru (matice) se skalární hodnotou, popř. prvky dvou vektorů (matic) navzájem. V tomto případě je výsledkem porovnání též vektor či matice obsahující hodnoty 0 a 1:

   NB. Porovnání všech prvků vektoru se skalární hodnotou
   1 2 3 4 > 2
0 0 1 1
   1 2 3 4 < 2
1 0 0 0
   1 2 3 4 = 2
0 1 0 0

   NB. Porovnání dvou vektorů, které v tomto
   NB. případě musí mít shodnou délku.
   1 2 3 4 < 4 3 2 1
1 1 0 0

Poslední funkcí, kterou si v této kapitole popíšeme, je funkce testující existenci prvku (prvků) ve vektoru či matici. Jedná se o funkci označovanou symbolem e., jejímž prvním parametrem je skalární hodnota či vektor hodnot, které se hledají v datové struktuře předané ve druhém parametru této funkce. Návratovou hodnotou funkce e. je pravdivostní hodnota 0 nebo 1 udávající, zda se příslušná hledaná hodnota (první parametr) skutečně ve druhém parametru nachází. Pokud se současně vyhledává více hodnot, je návratovou hodnotou vektor nul a jedniček, jak je to ostatně ukázáno v následujících demonstračních příkladech:

   NB. Vytvoření vektoru čísel
   x=:1 2 3 4 5 0.3 _1 42

   NB. Zjištění, zda vektor obsahuje hodnotu 10
   10 e. x

   NB. Zjištění, zda vektor obsahuje hodnotu 1
   1 e. x
1
   NB. Dtto pro hodnotu 2
   2 e. x
1

   NB. Vytvoření vektoru hledaných čísel
   y=:1 3 5
   NB. Zjištění, zda vektor x obsahuje čísla 1, 3 a 5
   y e. x
1 1 1

   NB. Vyhledání více prvků bez použití
   NB. pomocného vektoru
   1 10 100 1000 42 e. x
1 0 0 0 1

   NB. Vektor, ve kterém je prováděno vyhledávání,
   NB. může být sestrojen funkcí i.
   1 5 10 e. i. 10
1 1 0

   NB. Vyhledání všech násobků dvou v řadě
   NB. obsahující násobky čísla 3.
   (2* i. 20) e. (3* i. 20)
1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0

7. Obsah následující části seriálu

V následující části seriálu o historii výpočetní techniky dokončíme popis programovacího jazyka J. Řekneme si, jaké knihovny jsou dodávané spolu s interpretrem tohoto jazyka a ukážeme si též tvorbu grafů, které v mnoha případech tvoří poměrně významnou část aplikací vytvářených v tomto programovacím jazyce (jedná se například o různé simulace nebo finanční aplikace). Nezapomeneme ani na vysvětlení termínu tacit programming.

Před přípravou dalších dílů prosím laskavé čtenáře, aby sami dopředu určili, kterým směrem by se tento seriál měl vyvíjet; zda popisem hardware (další mainframy, grafické stanice SGI, superpočítače) nebo spíše software a programovacích jazyků (PL/I, RPG, K – pokračovatel J, programovací jazyky zaměřené na výuku).

root_podpora

8. Literatura

  1. Linda Alvord and Norman Thomson, „Easy-J: An Introduction to the World's most Remarkable Programming Language
    October 2002
  2. Ulf Grenander, „Mathematical Experiments on the Computer,
    Academic Press, 1982, ISBN 0–12–301750–5.
  3. K. E. Iverson, „A Programming Language“,
    Wiley, 1962.
  4. K. E. Iverson, „Algebra : an algorithmic treatment“,

    APL Press 1977, Copyright 1972 by Addison Wesley,

    Preliminary Edition entitled „Elementary Algebra

    Copyright 1971 by IBM Corporation.
  5. K. E. Iverson, „Elementary analysis“,

    APL press 1976, Preliminary Edition „Elementary Functions

    Copyright 1974 by IBM Corporation ISBN 0–917326–01–6
  6. K. E. Iverson, „A personal view of APL,
    IBM Systems Journal,
  7. C. Reiter, „Fractuals Visualization and J“,
    Iverson Software, Inc, 1995 ISBN 1–895721–11–3.
  8. J Phrases,
    Iverson Software, 1996, ISBN 1–895721–12–1
  9. Exploring Math“, Iverson Software, 1996, ISBN 1–895721–13-X
  10. J Primer,
    Iverson Software, 1996, ISBN 1–895721–14–8

9. Odkazy na Internetu

  1. Learning J (Roger Stokes)
    http://www.jsoftware.com/…contents.htm
  2. J: a modern, high-level, general-purpose, high-performance programming language
     http://www.jsoftware.com/
  3. K, Kdb: an APL derivative for Solaris, Linux, Windows
     http://www.kx.com
  4. Vector (obsahuje odkazy na články, knihy a blogy o programovacích jazycích APL, J a K)
     http://www.vector.org.uk/
  5. APL – A Glimpse of Heaven
    http://www.vector.org.uk/…/legrand.htm
  6. APL Interpreters
    http://www.vector.org.uk/?…
  7. APL_(programmin­g_language
    http://en.wikipedia.org/wiki/APL_(programming_lan­guage
  8. APL FAQ
    http://www.faqs.org/faqs/apl-faq/
  9. APL FAQ (nejnovější verze)
    http://home.earthlink.net/…apl.faq.html
  10. A+
    http://www.aplusdev.org/
  11. Rosetta Code
    http://rosettacode.org/wiki/Main_Page

Byl pro vás článek přínosný?

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.