Hlavní navigace

Jazyky umožňující operace s poli aneb rozsáhlý svět „array programmingu“

2. 12. 2021
Doba čtení: 38 minut

Sdílet

 Autor: Depositphotos
Dnes navštívíme rozsáhlý svět jazyků navržených a optimalizovaných pro manipulaci s poli. Taktéž si vysvětlíme, co si vlastně máme pod pojmem „pole“ představit – to totiž ani zdaleka není tak zřejmý termín, jak by se mohlo zdát.

Obsah

1. Jazyky umožňující operace s poli aneb rozsáhlý svět „array programmingu“

2. Podpora n-rozměrných polí v programovacích jazycích a knihovnách

3. Jenže … co si vlastně představit pod jménem pole?

4. Rozdílný přístup k práci s poli v různých programovacích jazycích

5. Optimalizace operací s poli, paralelní výpočty a zpracování signálů

6. Příklady rozdílných přístupů programovacích jazyků při práci s poli

7. Vektory a matice v Dartmouth BASICu popř. v BBS BASICu

8. Pole v programovacím jazyce Julia

9. Vícerozměrná pole, sloupcové a řádkové vektory

10. Změna tvaru pole funkcí reshape

11. Jeden z důsledků typového systému jazyka Julia a měnitelnosti polí

12. N-rozměrná pole v LISPovské rodině programovacích jazyků

13. Knihovna core.matrix

14. Projekt Incanter

15. Infixová notace řešená přes makrosystém jazyka Clojure

16. Broadcasting

17. Vektory v programovacím jazyku Kawa

18. N-rozměrná pole (ND-Array) v jazyku Kawa

19. Obsah navazujícího článku

20. Odkazy na Internetu

1. Jazyky umožňující operace s poli aneb rozsáhlý svět „array programmingu“

V dnešním článku se začneme zabývat jednou poměrně rozsáhlou a současně i poněkud specifickou oblastí v informatice. Tou je zpracování vektorů, matic a taktéž vícerozměrných polí – obecně se v tomto kontextu mluví o n-rozměrných polích. S těmito velmi užitečnými datovými strukturami se můžeme setkat v různých (mnohdy zdánlivě i velmi vzdálených) disciplínách, například ve finančnictví, pojišťovnictví, statistice, zpracování numerických dat, simulacích, zpracování 1D a 2D signálů atd. Zapomenout ovšem nesmíme ani na strojové učení (machine learning) a umělou inteligencí (artifical intelligence), protože například datové struktury určené pro uložení neuronových sítí (zejména konvolučních sítí) jsou realizovány n-rozměrnými poli. Současně se jedná i o velmi zajímavou oblast, neboť právě kvůli nutnosti co nejrychlejší práce s velkými maticemi byly vytvořeny speciální výpočetní bloky v některých superpočítačích (příkladem mohou být superpočítače Cray) a došlo tak k důležitému podnětu pro další rozvoj výpočetní techniky (ten nepřímo vedl k vývoji moderních GPU). A pokud zůstaneme u 1D a 2D polí – zde došlo k rozšíření digitálních signálových procesorů orientovaných a optimalizovaných právě na tuto oblast.

Operace s poli jsou buď součástí syntaxe a sémantiky programovacích jazyků nebo jsou realizovány formou knihovny. Současné knihovny určené pro práci s n-rozměrnými poli dokážou v případě potřeby využít jak některé rozšíření instrukčních sad (SIMD instrukce typu SSE neboli Streaming SIMD Extensions, původně též MMX či 3DNow!), tak i v některých případech programovatelné grafické akcelerátory (GPU). SIMD instrukcemi jsme se již na stránkách Roota zabývali v samostatných článcích, zejména pak v této trojici článků:

  1. SIMD instrukce využívané v moderních mikroprocesorech řady x86
    https://www.root.cz/clanky/simd-instrukce-vyuzivane-v-modernich-mikroprocesorech-rady-x86/
  2. SIMD instrukce v moderních mikroprocesorech řady x86 (2.část: SSE)
    https://www.root.cz/clanky/simd-instrukce-v-modernich-mikroprocesorech-rady-x86–2-cast-sse/
  3. SIMD instrukce v moderních mikroprocesorech řady x86 (3.část: SSE2)
    https://www.root.cz/clanky/simd-instrukce-v-modernich-mikroprocesorech-rady-x86–3-cast-sse2/

2. Podpora n-rozměrných polí v programovacích jazycích a knihovnách

Zmiňme se nyní o některých programovacích jazycích, v nichž manipulace s poli tvoří nedílnou součást takového jazyka (a určuje tak i oblast, v níž se daný programovací jazyk používá). Práce s vektory a maticemi byla (a samozřejmě doposud je) podporována zejména v překladačích FORTRANu, které začaly být po vzniku superpočítačů vybaveny specializovanými algoritmy. Tyto algoritmy dokázaly převést některé typy programových smyček na „vektorové operace“ (což ve skutečnosti byly operace aplikované na „konvoj“ prvků v hluboké pipeline). Paralelně k různým rozšířením FORTRANu ovšem vznikly i specializované jazyky určené téměř výhradně pro práci s vektory i maticemi. Velmi dobrým příkladem jsou programovací jazyky APL a J. I těmito neobvyklými (ale stále používanými!) programovacími jazyky jsme se na stránkách Rootu již zabývali, a to v následujících článcích:

  1. Programování mainframů: jazyk APL
    https://www.root.cz/clanky/pro­gramovani-mainframu-jazyk-apl/
  2. Programovací jazyk APL: programování bez smyček
    https://www.root.cz/clanky/pro­gramovaci-jazyk-apl-programovani-bez-smycek/
  3. Programovací jazyk APL – dokončení
    https://www.root.cz/clanky/pro­gramovaci-jazyk-apl-dokonceni/
  4. Programovací jazyk J – od hieroglyfů k ASCII znakům
    https://www.root.cz/clanky/pro­gramovaci-jazyk-j-ndash-od-hieroglyfu-k-nbsp-ascii-znakum/
  5. Programujeme v jazyku J: vektory a matice
    https://www.root.cz/clanky/pro­gramujeme-v-jazyku-j-ndash-vektory-a-matice/
  6. Programovací jazyk J: operátory, uživatelské funkce a tacit programming
    https://www.root.cz/clanky/pro­gramovaci-jazyk-j-operatory-uzivatelske-funkce-a-tacit-programming/
  7. Oslava 55 let od vzniku první implementace jazyka APL
    https://www.root.cz/clanky/oslava-55-let-od-vzniku-prvni-implementace-programovaciho-jazyka-apl/

Velmi dobrou podporu pro práci s maticemi ovšem nabízí i framework Torch založený na programovacím jazyku Lua, s vektory a maticemi lze pracovat v programovacím jazyku Julia a zapomenout nesmíme ani na knihovnu Numpy. Ta je určená pro programovací jazyk Python. Opět uvedu odkazy na články, v níž se touto populární a velmi často používanou knihovnou zabýváme do větší hloubky, než to umožňuje rozsah dnešního článku:

  1. Zpracování vektorů, matic a N-rozměrných polí v programovacím jazyku Kawa
    https://www.root.cz/clanky/zpracovani-vektoru-matic-a-n-rozmernych-poli-v-programovacim-jazyku-kawa/
  2. Rust: knihovna ndarray pro práci s n-rozměrnými poli
    https://www.root.cz/clanky/rust-knihovna-ndarray-pro-praci-s-n-rozmernymi-poli/
  3. Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
    https://www.root.cz/clanky/pro­gramovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi/
  4. Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi (2)
    https://www.root.cz/clanky/pro­gramovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi-2/
  5. Gophernotes: kombinace interaktivního prostředí Jupyteru s jazykem Go
    https://www.root.cz/clanky/gophernotes-kombinace-interaktivniho-prostredi-jupyteru-s-jazykem-go/
  6. Popis vybraných balíčků nabízených projektem Gonum
    https://www.root.cz/clanky/popis-vybranych-balicku-nabizenych-projektem-gonum/
  7. Integrovaná vývojová prostředí ve Fedoře: vykreslování grafů s využitím knihoven Numpy a matplotlib
    https://mojefedora.cz/integrovana-vyvojova-prostredi-ve-fedore-vykreslovani-grafu-s-vyuzitim-knihoven-numpy-a-matplotlib/
  8. Integrovaná vývojová prostředí ve Fedoře: praktické použití IPython Notebooku a knihovny Numpy (2.část)
    https://mojefedora.cz/integrovana-vyvojova-prostredi-ve-fedore-prakticke-pouziti-ipython-notebooku-a-knihovny-numpy-2-cast/
  9. Integrovaná vývojová prostředí ve Fedoře: praktické použití IPython Notebooku a knihovny Numpy
    https://mojefedora.cz/integrovana-vyvojova-prostredi-ve-fedore-prakticke-pouziti-ipython-notebooku-a-knihovny-numpy/

3. Jenže … co si vlastně představit pod jménem pole?

V programovacích jazycích se termín „pole“ resp. array používá velmi často, ovšem ani zdaleka ne konzistentně. V případě, že se v dokumentaci jazyka bez dalších podrobností termín array použije, je vhodné hledat odpovědi na následující otázky:

  1. Kolik dimenzí může pole mít? Typicky 1 a 2, někdy i více.
  2. Začínají indexy prvků od 0, 1 či je první index volitelný?
  3. Jsou podporována obdélníková pole nebo nepravidelná pole?
  4. Jsou jednotlivé osy na sobě nezávislé? (což vylučuje nepravidelná pole)
  5. Je možné indexy na jednotlivých osách pojmenovat? (a vytvořit tak vlastně datový rámec)
  6. Jedná se o homogenní nebo o heterogenní datovou strukturu? Homogenní struktura může uchovávat prvky jediného (typicky předem definovaného) typu zatímco v heterogenní struktuře mohou být umístěny prvky různých typů.
  7. Je nějakým způsobem omezen datový typ prvků pole? (například jen na celá čísla a čísla reálná).
  8. Lze prvky pole měnit (mutable) nebo je pole neměnitelné (immutable).
  9. Pokud jsou pole heterogenní a měnitelná, může prvek pole obsahovat to samé pole?
  10. Obsahuje pole přímo hodnoty prvků nebo jen reference na prvky?
  11. Jsou prvky v poli uloženy v operační paměti za sebou nebo se jedná o strukturu s ukazateli?
  12. Jsou prvky v 2D poli uloženy po řádcích nebo po sloupcích? (C versus Fortran).
  13. Lze měnit tvar (shape) pole?
  14. Podporuje jazyk operace nad celými poli?
  15. Podporuje jazyk takzvaný broadcasting (aplikaci skaláru na všechny prvky pole atd.)?
  16. Jsou pole plnohodnotným datovým typem nebo speciální strukturou?
  17. Je podporován „literál typu pole“?

4. Rozdílný přístup k práci s poli v různých programovacích jazycích

Různé programovací jazyky přistupují k implementaci polí rozdílným způsobem. Některé jazyky mají striktně omezen počet dimenzí na jednorozměrná pole a dvourozměrné matice. Mezi takové jazyky patří například osmibitové BASICy. Dále je možné pole reprezentovat jako jedinou souvislou oblast paměti (APL) s oddělenými metainformacemi o tvaru pole (shape); další jazyky reprezentují vícerozměrná pole jako pole polí (Java). U jazyků, kde jsou pole uložena v jediném souvislém bloku taktéž záleží na tom, zda je uložení provedeno po řádcích nebo po sloupcích (což je nejviditelnější na dvourozměrných polích). Zajímavým důsledkem oddělení metainformací o tvaru pole od prvků je možnost existence operace pro změnu tvaru pole, tj. například pro konverzi vektoru s 24 prvky na pole s 2×3×4 prvky atd. Poměrně velký rozdíl taktéž spočívá v tom, zda jsou pole homogenní či heterogenní. A pochopitelně samostatný problém představuje uložení pole do prvku sebe sama (což musí být detekováno a řešeno v runtime jazyka).

5. Optimalizace operací s poli, paralelní výpočty a zpracování signálů

V oblasti numerických simulací, což byl jeden z prvních úkolů, na které byly programovatelné počítače nasazeny, se často provádí operace s vektory a maticemi. Ostatně právě pro tento typ úkolů byl navržen programovací jazyk FORTRAN. A po vzniku superpočítačů začaly být překladače FORTRANu vybavovány algoritmy, které dokázaly převést některé typy programových smyček souvisejících s vektorovými a maticovými operacemi na „vektorové operace“. Paralelně vznikly i specializované jazyky určené téměř výhradně pro práci s vektory i maticemi – příkladem je již zmíněná dvojice APL a J. Touto problematikou (kde superpočítače předběhly dobu) se budeme podrobněji zabývat příště.

Operace s poli, přesněji řečeno většinou s jednorozměrnými vektory a maticemi, souvisí i se zpracováním signálů, což je oblast, pro kterou byly vyvinuty specializované čipy – DSP. První typy digitálních signálových procesorů, tj. DSP umístěných na jediném čipu, vznikly až na přelomu sedmdesátých a osmdesátých let minulého století, ovšem o zpracování číslicových signálů v reálném čase se inženýři a posléze i programátoři pokoušeli již dříve. První úspěšné a dá se říci i reálně použitelné systémy vznikly již na minipočítačích na počátku sedmdesátých let minulého století, ovšem vzhledem k poměrně vysoké ceně minipočítačů, jejich velikosti i spotřebě (nenechme se zmýlit předponou mini-, ta vyjadřovala cenu, velikost a výkonnost minipočítačů vzhledem k mainframům :-) byla oblast jejich nasazení omezená pouze na ty technologické provozy, kde nebyla k dispozici dostatečně robustní alternativa. Pokud nebylo možné minipočítače použít, používaly se buď signálové procesory sestavené z více čipů, nebo se namísto zpracování číslicových signálů používala mnohem starší, a nutno říci, že v dané době i propracovanější technologie – analogové počítače, které ovšem pracují na zcela jiném principu, než programovatelné číslicové počítače.

DSP byly optimalizovány na dvě operace – násobení (tj. obsahovaly rychlou násobičku) a na přístup k prvkům vektorů, což zasahuje do oblasti, které se věnujeme dnes. Efektivní adresace prvků vektorů umožnila například realizovat operaci konvoluce, korelace, výpočet FFT atd. Těmito specifickými oblastmi se budeme zabývat později.

6. Příklady rozdílných přístupů programovacích jazyků při práci s poli

Na třetí kapitolu, v níž jsme se zmínili o různých významech pojmu array, nyní navážeme, protože si ukážeme, jak s poli (ať již tento název konkrétně znamená cokoli) pracují různé programovací jazyky. Začneme původním Dartmouth BASICem a na něj navazujícím BBC BASICem, v němž je podpora pro práci s poli až překvapivě dobrá. Zapomenout pochopitelně nemůžeme na programovací jazyk Julia, který s poli pracuje odlišným způsobem (což je zapříčiněno mj. i typovým systémem tohoto jazyka). A ve druhé polovině článku si ukážeme práci s poli v LISPovských programovacích jazycích.

Poznámka: na „klasické“ jazyky z této oblasti ovšem nezapomeneme. Příště si porovnáme především FORTRAN, VectorPascal, R, APL, jazyk J a jazyk BQN (což je mix APL a J, v němž je většina problémů původního APL opravena).

7. Vektory a matice v Dartmouth BASICu popř. v BBS BASICu

Podpora pro manipulace s maticemi (tedy s dvourozměrnými poli) se objevila v Dartmouth BASICu, což je prapředek všech ostatních variant programovacího jazyka BASIC. Ovšem v dalších BASICech, zejména v těch určených pro osmibitové domácí mikropočítače, práci s maticemi nenalezneme – a kupodivu ji nenalezneme ani v moderních BASICech (což ukazuje na neznalost historie :-). Podívejme se na základní podporu pro práci s maticemi v Darthmouth BASICu. Tento jazyk umožňuje zapsat maticové operace s využitím prefixu MAT, tedy následujícím způsobem:

DIM A(4),B(4),C(4)
MAT A = 1
MAT B = 2 * A
MAT C = A + B
MAT PRINT A,B,C
Poznámka: „skalární“ operace by se zapisovaly podobně, akorát by se namísto MAT použil příkaz LET.

V BBC BASICu jsou do určité míry podporována n-rozměrná pole. Jednorozměrné vektory se alokují a používají takto. Povšimněte si toho, že vektor V ve skutečnosti obsahuje jedenáct prvků:

10 REM
11 REM Alokace vektoru
12 REM
15 DIM V(10)
20 REM
21 REM Naplneni vektoru daty
22 REM
30 FOR I=0 TO 10
40   V(I) = I*1
50 NEXT I
60 REM
61 REM Vypis obsahu vektoru
62 REM
70 FOR I=0 TO 10
80   PRINT I,V(I)
90 NEXT I

Výsledek:

 0         0
 1         1
 2         2
 3         3
 4         4
 5         5
 6         6
 7         7
 8         8
 9         9
10        10

Pravidlo „n+1“ platí i pro dvojrozměrná pole neboli matice. Zajímavé je, že DIM jako příkaz alokuje pole a jako funkce vrací počet dimenzí (což do určité míry připomíná APL s monadickými a dyadickými operátory):

10 REM
11 REM Alokace pole 4x5 prvku
12 REM
20 DIM A(3,4)
30 PRINT DIM(A())

Výsledek získaný po spuštění tohoto příkladu:

2

Získat lze i velikosti pole v každé dimenzi, tedy rank, a to voláním funkce DIM se dvěma parametry – polem a indexem dimenze:

10 REM
11 REM Alokace pole 4x5 prvku
12 REM
20 DIM A(3,4)
30 PRINT DIM(A())
40 REM
41 REM Vypis velikosti pole v kazde dimenzi
42 REM
50 FOR D=1 TO DIM(A())
60   PRINT D,DIM(A(),D)
70 NEXT D

Výsledek (rank vrací hodnoty 3 a 4):

2
1         3
2         4

Počet dimenzí ve skutečnosti není omezen na 1 či 2; vytvořit lze například i trojrozměrné pole:

10 REM
11 REM Alokace pole 5x6x7 prvku
12 REM
20 DIM A(4,5,6)
30 PRINT DIM(A())

rank zjišťovaný pro trojrozměrná pole:

10 REM
11 REM Alokace pole 5x6x7 prvku
12 REM
20 DIM A(4,5,6)
30 PRINT DIM(A())
40 REM
41 REM Vypis velikosti pole v kazde dimenzi
42 REM
50 FOR D=1 TO DIM(A())
60   PRINT D,DIM(A(),D)
70 NEXT D

Výsledek:

 3
 1         4
 2         5
 3         6

Kupodivu není podporován tisk celého pole, takže si musíme pomoci dvojicí programových smyček (v případě trojrozměrného pole pak trojicí vnořených programových smyček):

10 REM
11 REM Alokace pole 4x5 prvku
12 REM
20 DIM A(3,4)
30 PRINT DIM(A())
40 REM
41 REM Naplneni prvku pole
42 REM
50 FOR J=0 TO DIM(A(),2)
51   FOR I=0 TO DIM(A(),1)
52     A(I,J) = I*J
53   NEXT I
54 NEXT J
60 REM
61 REM Vypis obsahu pole
62 REM
70 FOR J=0 TO DIM(A(),2)
71   FOR I=0 TO DIM(A(),1)
72     PRINT A(I,J);
73   NEXT I
74   PRINT
75 NEXT J

Výsledek:

2
0         0         0         0
0         1         2         3
0         2         4         6
0         3         6         9
0         4         8        12

BBC Basic podporuje i operace nad celými poli, což je pro zdánlivě primitivní jazyk neobvyklé. Jednotlivé podporované operace jsou vypsány v následující dvojici tabulek. V první tabulce jsou binární operátory, jejichž levým parametrem je pole:

Levý operand Operátor Pravý operand Stručný popis
pole + pole součet prvek po prvku
pole pole rozdíl prvek po prvku
pole * pole součin prvek po prvku
pole / pole podíl prvek po prvku
pole + skalár přičtení skaláru ke všem prvkům pole
skalár + pole přičtení skaláru ke všem prvkům pole
pole skalár odečtení skaláru ke všem prvkům pole
skalár pole odečtení skaláru od všech prvků pole
pole * skalár vynásobení všech prvků pole konstantou
skalár * pole vynásobení všech prvků pole konstantou
pole / skalár vydělení všech prvků pole konstantou
skalár / pole výpočet skalár/prvek
pole . pole maticový součin

V tabulce druhé jsou vypsány operátory zkombinované s přiřazením:

Levá strana Operátor Pravá strana Stručný popis
pole = pole kopie celého pole
pole = skalár nastavení všech prvků pole na zadanou hodnotu
pole = -pole speciální případ, kopie celého pole s otočením znaménka všech prvků
pole += skalár/pole zkrácený zápis pole = pole + skalár/pole
pole -= skalár/pole zkrácený zápis pole = pole – skalár/pole

Můžeme vidět, že některé operace bychom skutečně u „jednoduchého“ BASICu nečekali.

Ukázka operace pole = pole + skalár:

10 REM
11 REM Alokace pole 4x5 prvku
12 REM
20 DIM A(3,4)
30 PRINT DIM(A())
40 REM
41 REM Naplneni prvku pole
42 REM
50 FOR J=0 TO DIM(A(),2)
51   FOR I=0 TO DIM(A(),1)
52     A(I,J) = I*J
53   NEXT I
54 NEXT J
60 REM
61 REM Operace s celym polem
62 REM
65 A() = A() + 1
70 REM
71 REM Vypis obsahu pole
72 REM
80 FOR J=0 TO DIM(A(),2)
81   FOR I=0 TO DIM(A(),1)
82     PRINT A(I,J);
83   NEXT I
84   PRINT
85 NEXT J

Výsledek:

2
1         1         1         1
1         2         3         4
1         3         5         7
1         4         7        10
1         5         9        13

Ukázka operace pole += skalár:

10 REM
11 REM Alokace pole 4x5 prvku
12 REM
20 DIM A(3,4)
30 PRINT DIM(A())
40 REM
41 REM Naplneni prvku pole
42 REM
50 FOR J=0 TO DIM(A(),2)
51   FOR I=0 TO DIM(A(),1)
52     A(I,J) = I*J
53   NEXT I
54 NEXT J
60 REM
61 REM Operace s celym polem
62 REM
65 A() += 1
70 REM
71 REM Vypis obsahu pole
72 REM
80 FOR J=0 TO DIM(A(),2)
81   FOR I=0 TO DIM(A(),1)
82     PRINT A(I,J);
83   NEXT I
84   PRINT
85 NEXT J

Výsledek:

2
1         1         1         1
1         2         3         4
1         3         5         7
1         4         7        10
1         5         9        13

Vynásobení odpovídajících si prvků pole:

10 REM
11 REM Alokace pole 4x5 prvku
12 REM
20 DIM A(3,4)
30 PRINT DIM(A())
40 REM
41 REM Naplneni prvku pole
42 REM
50 FOR J=0 TO DIM(A(),2)
51   FOR I=0 TO DIM(A(),1)
52     A(I,J) = I*J
53   NEXT I
54 NEXT J
60 REM
61 REM Operace s celym polem - nasobeni prvek po prvku
62 REM
65 A() *= A()
70 REM
71 REM Vypis obsahu pole
72 REM
80 FOR J=0 TO DIM(A(),2)
81   FOR I=0 TO DIM(A(),1)
82     PRINT A(I,J);
83   NEXT I
84   PRINT
85 NEXT J

Výsledek:

2
0         0         0         0
0         1         4         9
0         4        16        36
0         9        36        81
0        16        64       144

A konečně nejdelší příklad – maticový součin:

10 REM
11 REM Alokace prvniho pole 5x2 prvku
12 REM
20 DIM A(4,1)
21 PRINT DIM(A())
30 REM
31 REM Naplneni prvku pole
32 REM
40 FOR J=0 TO DIM(A(),2)
41   FOR I=0 TO DIM(A(),1)
42     A(I,J) = I*J
43   NEXT I
44 NEXT J
50 REM
51 REM Alokace druheho pole 2x6 prvku
52 REM
60 DIM B(1,5)
61 PRINT DIM(B())
70 REM
71 REM Naplneni prvku pole
72 REM
80 FOR J=0 TO DIM(B(),2)
81   FOR I=0 TO DIM(B(),1)
82     B(I,J) = I*J
83   NEXT I
84 NEXT J
90 REM
92 REM Maticovy soucin
92 REM
90 DIM C(4,5)
91 C() = A().B()
92 REM
93 REM Vypis obsahu pole
94 REM
95 FOR J=0 TO DIM(C(),2)
96   FOR I=0 TO DIM(C(),1)
97     PRINT C(I,J);
98   NEXT I
99   PRINT
100 NEXT J

Výsledek:

 2
 2
 0         0         0         0         0
 0         1         2         3         4
 0         2         4         6         8
 0         3         6         9        12
 0         4         8        12        16
 0         5        10        15        20

8. Pole v programovacím jazyce Julia

Dalším jazykem, který práci s vícerozměrnými poli podporuje na velmi dobré úrovni (i když s několika problematickými rysy), je programovací jazyk Julia. Základní homogenní datovou strukturou, kterou programovací jazyk Julia svým uživatelům nabízí, jsou jednorozměrná pole. Všechny prvky pole mají stejný typ (ostatně právě proto je to homogenní datová struktura a nikoli struktura heterogenní) a ke každému prvku je možné přistupovat přes jeho index, přičemž indexování prvků má konstantní složitost (nezáleží tedy na délce pole). Prvky v běžných jednorozměrných polích je možné modifikovat, takže pole jsou v jazyku Julia měnitelnými datovými strukturami (mutable). Podívejme se nyní na způsob vytvoření jednorozměrných polí v tomto programovacím jazyce:

julia> a=[1, 2, 3, 4, 5]
5-element Array{Int64,1}:
 1
 2
 3
 4
 5

Při konstrukci pole se automaticky může zjistit datový typ prvků (resp. typ, který všem prvkům odpovídá po případné konverzi). Povšimněte si, jak se jazyk rozhoduje, který typ použít ve chvíli, kdy budeme chtít do pole uložit tři prvky různého typu:

julia> a=[1, 2.1, 1//3]
3-element Array{Float64,1}:
 1.0
 2.1
 0.333333
 
julia> a=[1, 2, 1//3]
3-element Array{Rational{Int64},1}:
 1//1
 2//1
 1//3
 
julia> a=[1/0, -1/0, 0/0]
3-element Array{Float64,1}:
  Inf
 -Inf
  NaN
 
julia> a=[pi, pi]
2-element Array{Irrational{:π},1}:
 π = 3.1415926535897...
 π = 3.1415926535897...

Typ je ovšem v případě potřeby možné specifikovat explicitně:

julia> Int8[1, 2, 3, 4, 5]
5-element Array{Int8,1}:
 1
 2
 3
 4
 5
 
julia> Float16[1, 2, 3, 4, 5]
5-element Array{Float16,1}:
 1.0
 2.0
 3.0
 4.0
 5.0

V případě, že vynecháte čárky, vytvoří se ve skutečnosti dvourozměrné pole s jedním řádkem:

julia> a=[1 2 3 4 5]
1x5 Array{Int64,2}:
 1  2  3  4  5
 
julia> Float16[1 2 3 4 5]
1x5 Array{Float16,2}:
 1.0  2.0  3.0  4.0  5.0
 
julia> a=[1 2 3 4]
1x4 Array{Int64,2}:
 1  2  3  4

9. Vícerozměrná pole, sloupcové a řádkové vektory

V předchozí kapitole jsme si ukázali způsob tvorby jednorozměrných polí v programovacím jazyku Julia. Jak se však vytváří dvourozměrná pole? První pokus, který může vycházet ze zkušeností z jiných programovacích jazyků (například z Pythonu), nebude příliš úspěšný:

julia> [[1,2,3], [4,5,6]]
WARNING: [a,b] concatenation is deprecated; use [a;b] instead
 in depwarn at deprecated.jl:73
 in oldstyle_vcat_warning at ./abstractarray.jl:29
 in vect at abstractarray.jl:32
while loading no file, in expression starting on line 0
6-element Array{Int64,1}:
 1
 2
 3
 4
 5
 6

Problém v předchozím zápisu představovala čárka vložená mezi oba vektory. Jedno z možných řešení může vypadat takto – vytvoříme vlastně pole složené ze dvou sloupců (povšimněte si chybějící čárky mezi vektory):

julia> [[1,2,3] [4,5,6]]
3x2 Array{Int64,2}:
 1  4
 2  5
 3  6

V případě, že preferujete zápis po řádcích, lze použít tento alternativní způsob se středníkem. Je to sice poněkud neobvyklé, ale středník zde nahrazuje volání funkce hvcat() zmíněné níže:

julia> a=[1 2; 3 4]
2x2 Array{Int64,2}:
 1  2
 3  4

Pole se dvěma řádky a třemi sloupci se tedy vytvoří následovně:

julia> [1 2 3 ; 3 4 5]
2x3 Array{Int64,2}:
 1  2  3
 3  4  5

Kromě zápisu prvků pole do hranatých závorek lze pro konstrukci použít i funkce hcat (což znamená „horizontal concatenate“), vcat („vertical concatenate“) a hvcat (kombinace obou možností se specifikací počtu sloupců):

julia> hcat(1,2,3,4)
1x4 Array{Int64,2}:
 1  2  3  4
julia> vcat(1,2,3,4)
4-element Array{Int64,1}:
 1
 2
 3
 4

U funkce hvcat() si povšimněte, že první parametr specifikuje počet sloupců a až po něm následují jednotlivé prvky, což může být poněkud matoucí:

julia> hvcat(2,1,2,3,4)
2x2 Array{Int64,2}:
 1  2
 3  4

Jednosloupcové pole:

julia> hvcat(1,1,2,3,4)
4x1 Array{Int64,2}:
 1
 2
 3
 4

Čtyřsloupcové pole (s jedním řádkem):

julia> hvcat(4,1,2,3,4)
1x4 Array{Int64,2}:
 1  2  3  4

Pro vytvoření pole s udáním typu prvků (ovšem bez inicializace jednotlivých prvků) slouží konstruktor nazvaný jednoduše Array. Při volání tohoto konstruktoru se nejprve ve složených závorkách specifikuje typ prvků a již běžně v kulatých závorkách pak rozměry pole v jednotlivých dimenzích:

help?> Array
search: Array SubArray BitArray DenseArray StridedArray mmap_array
 
  Array(dims)
 
  Array{T}(dims) constructs an uninitialized dense array with element type T.
  dims may be a tuple or a series of integer arguments. The syntax Array(T,
  dims) is also available, but deprecated.

Konstrukce pole o rozměrech 2×2 prvky typu Int8 (osmibitové celé číslo se znaménkem) se provede takto:

julia> a=Array{Int8}(2,2)
2x2 Array{Int8,2}:
 112  -26
  82  -34

Zkusme nyní změnit hodnotu prvku v poli 10×10 prvků:

julia> a[0,0]=42
 
ERROR: LoadError: BoundsError: attempt to access 2×2 Array{Int8,2} at index [0, 0]
Stacktrace:
 [1] setindex!(::Array{Int8,2}, ::Int64, ::Int64, ::Int64) at ./array.jl:550
while loading /home/cg/root/5386118/main.jl, in expression starting on line 3

Vidíme, že se tato operace nepodařila, a to z toho důvodu, že se prvky indexují od jedničky a nikoli od nuly. To se sice může zdát poněkud neobvyklé, ovšem ve skutečnosti mnoho jazyků (dovolím si dokonce říci, že většina jazyků NEodvozených od céčka) zvolilo stejný přístup: Fortran, Mathematica, R, MATLAB, Lua atd. Správně tedy má příkaz vypadat takto:

julia> a[1,1]=42
42

Prvek pole se skutečně změnil:

julia> a
10x10 Array{Float16,2}:
 42.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0

Podívejme se nyní na složitější indexování, tentokrát vektoru:

julia> v=[1 2 3 4 10 -1]
1x6 Array{Int64,2}:
 1  2  3  4  10  -1

Přístup k prvnímu prvku:

julia> v[1]
1

Přístup k prvkům 2 až 4:

julia> v[2:4]
3-element Array{Int64,1}:
 2
 3
 4

Přístup ke všem prvkům vektoru:

julia> v[:]
6-element Array{Int64,1}:
  1
  2
  3
  4
 10
 -1

Pokud potřebujeme přistoupit k poslednímu prvku, není možné použít index –1 (to lze v jiných jazycích), ale používá se zde slovo end. To opět není nijak unikátní, podobně se toto slovo používá i v MATLABu:

julia> v[end]
-1

Kombinace předchozích způsobů – od čtvrtého prvku do konce vektoru:

julia> v[4:end]
3-element Array{Int64,1}:
  4
 10
 -1

Zajímavý je výběr sekvence libovolných prvků vektoru (pole), a to s využitím jiného vektoru obsahujícího indexy prvků. Povšimněte si nutnosti použití dvojitých hranatých závorek – vnější závorky představují operaci výběru prvků, vnitřní závorky vektor indexů:

julia> v[[1,5,6,2,5,5]]
6-element Array{Int64,1}:
  1
 10
 -1
  2
 10
 10

10. Změna tvaru pole funkcí reshape

Další velmi důležitou funkcí, s níž se v praxi často setkáme, je funkce nazvaná reshape(), která dokáže změnit velikost matice a vhodným způsobem přeorganizovat prvky v původní matici (převzato z APL – jak jinak). Této funkci se předávají dva parametry – prvním parametrem je vstupní pole (vektor, matice, …), druhým parametrem (popř. více parametry) pak specifikace tvaru výsledného pole. Podívejme se nejdříve na oficiální popis této funkce:

help?> reshape
search: reshape promote_shape
 
  reshape(A, dims)
 
  Create an array with the same data as the given array, but with different
  dimensions. An implementation for a particular type of array may choose
  whether the data is copied or shared.

Vytvořme si testovací vektor s dvanácti prvky (což je číslo dělitelné 2, 3, 4 i 6):

julia> a=[1 2 3 4 5 6 7 8 9 10 11 12]
1x12 Array{Int64,2}:
 1  2  3  4  5  6  7  8  9  10  11  12

Z tohoto vektoru pak snadno získáme matice o rozměrech 4×3, 3×4, 2×6, 6×2 či 1×12:

julia> reshape(a, 4, 3)
4x3 Array{Int64,2}:
 1  5   9
 2  6  10
 3  7  11
 4  8  12
julia> reshape(a, 3, 4)
3x4 Array{Int64,2}:
 1  4  7  10
 2  5  8  11
 3  6  9  12
julia> reshape(a, 2, 6)
2x6 Array{Int64,2}:
 1  3  5  7   9  11
 2  4  6  8  10  12
julia> reshape(a, 6, 2)
6x2 Array{Int64,2}:
 1   7
 2   8
 3   9
 4  10
 5  11
 6  12

Vytvoření trojrozměrných polí je stejně snadné (a opět je nutné zachovat počet prvků):

julia> reshape(a, 2, 3, 2)
2x3x2 Array{Int64,3}:
[:, :, 1] =
 1  3  5
 2  4  6
 
[:, :, 2] =
 7   9  11
 8  10  12

11. Jeden z důsledků typového systému jazyka Julia a měnitelnosti polí

Víme již, že v jazyku Julia se typ pole odvozuje od prvků, které jsou do pole přiřazeny. Pole celých čísel se tedy vytvoří a použije takto:

a = [1,2,3]
println(a)
 
a[2] = -1
println(a)

Pole je sice homogenním datovým typem, ovšem typový systém jazyka Julia umožňuje vytvořit pole prvků typu Any, což může být další pole:

a = [1,[],3]
println(a)
-> Any[1, Any[], 3]
 
a[2] = [10,10]
println(a)
-> Any[1, [10, 10], 3]

Takže – pole jsou měnitelné datové struktury a mohou obsahovat prvky typu Any. To ovšem znamená, že prvkem pole může být to samé pole!

a[2] = a
println(a)

S výsledkem:

Any[1, Any[#= circular reference @-1 =#], 3]

Dtto při přístupu do (nekonečně zanořené) struktury:

println(a[2])
Any[1, Any[#= circular reference @-1 =#], 3]
Poznámka: podobné chování lze nalézt například i v některých verzích APL nebo v Pythonovských seznamech (což ovšem nejsou plnohodnotná pole).

12. N-rozměrná pole v LISPovské rodině programovacích jazyků

Manipulace s N-rozměrnými poli jsou zdánlivě vyhrazeny pouze programovacím jazykům odvozeným od FORTRANu. To ovšem ve skutečnosti není pravda, protože se poměrně často můžeme setkat s mnohdy velmi vyspělými knihovnami pro práci s těmito datovými typy, které jsou určeny pro LISPovské programovací jazyky. V dalším textu si ve stručnosti popíšeme knihovny resp. přesněji řečeno podporu pro práci s n-rozměrnými poli v jazyku Clojure a taktéž v programovacím jazyku Kawa.

V přednášce nazvané velmi příhodně „Enter the Matrix“, která je dostupná na adrese http://www.slideshare.net/mi­keranderson/2013–1114-enter-thematrix, je mj. ukázáno, jakým způsobem jsou v Clojure implementována různá paradigmata programování. Díky podpoře maker a způsobu zápisu programového kódu v Clojure lze velmi snadno implementovat různé doménově specifické jazyky (DSL), mj. i právě jazyk pro array programming:

Paradigma Jazyk Implementace v Clojure
funkcionální Haskell clojure.core
OOP Smalltalk clojure.core
metaprogramování Lisp clojure.core
logické Prolog core.logic
array programming APL, J core.matrix
Poznámka: původní tabulka byla upravena a doplněna.

13. Knihovna core.matrix

Nejprve se ve stručnosti seznámíme s knihovnou určenou pro práci s n-dimenzionálními poli v programovacím jazyku Clojure. Konkrétně se bude jednat o knihovnu nazvanou core.matrix. Tato knihovna je určená těm vývojářům, kteří ve svých projektech potřebují provádět velké množství operací s maticemi různých dimenzí, a to na poměrně vysoké úrovni, tj. bez nutnosti přesně specifikovat, jakým způsobem mají být matice uloženy v paměti, jakým způsobem se má provádět operace násobení matic atd. Díky tomuto přístupu a taktéž díky vlastnostem programovacího jazyka Clojure (existence tzv. threading makra a funkcí vyššího řádu) se práce s maticemi do značné míry začíná podobat práci v jazyku APL, až na ten rozdíl, že algoritmy zapisované v Clojure jsou pro většinu vývojářů přece jen čitelnější :-). Taktéž je důležité, že rozhraní definované v knihovně core.matrix může mít několik implementací. V současnosti se jedná o implementace poskytované knihovnami vectorz-clj, Clatrix a NDArray. V core.matrix navíc došlo k rozšíření operátorů +, – atd. takovým způsobem, že je lze použít i pro zpracování vektorů a matic (ve skutečnosti se samozřejmě nejedná o skutečné operátory, protože tento koncept Clojure nepotřebuje).

Příklady vybraných operací s maticemi:

matrixtest.core=> (def M1 (matrix [[1 2][3 4]]))
#'matrixtest.core/M1
 
matrixtest.core=> (def M2 (matrix [[5 6][7 8]]))
#'matrixtest.core/M2
 
matrixtest.core=> (pm (+ M1 M2))
[[ 6.000  8.000]
 [10.000 12.000]]
 
matrixtest.core=> (def v (matrix [1 2 3 4 5 6]))
#'matrixtest.core/v
 
matrixtest.core=> (def M (matrix [[1 2] [3 4]]))
#'matrixtest.core/M
 
; trojrozměrná matice
matrixtest.core=> (def MD (matrix [[ [1 2] [3 4] ] [ [5 6] [7 8] ] ]))
#'matrixtest.core/MD
 
matrixtest.core=> (pm MD)
[[[1.000 2.000]
  [3.000 4.000]]
 [[5.000 6.000]
  [7.000 8.000]]]

Získání informací o matici:

matrixtest.core=> (dimensionality v)
1
 
matrixtest.core=> (dimensionality M)
2
 
matrixtest.core=> (dimensionality MD)
3
 
matrixtest.core=> (dimensionality 1)
0
 
matrixtest.core=> (shape M)
[2 2]
 
matrixtest.core=> (shape v)
[6]
 
matrixtest.core=> (shape MD)
[2 2 2]

Změna tvaru matice:

matrixtest.core=> (def v (matrix [1 2 3 4 5 6]))
#'matrixtest.core/v
 
matrixtest.core=> v
[1 2 3 4 5 6]
 
; velmi užitečná funkce převzatá z APL: vektor převeden na matici
matrixtest.core=> (reshape v [2 3])
[[1 2 3] [4 5 6]]
 
matrixtest.core=> (pm *1)
[[1.000 2.000 3.000]
 [4.000 5.000 6.000]]
 
; jiný tvar matice
matrixtest.core=> (reshape v [3 2])
[[1 2] [3 4] [5 6]]
 
matrixtest.core=> (pm *1)
[[1.000 2.000]
 [3.000 4.000]
 [5.000 6.000]]
 
matrixtest.core=> (reshape v [1 6])
[[1 2 3 4 5 6]]
 
matrixtest.core=> (pm *1)
[[1.000 2.000 3.000 4.000 5.000 6.000]]
 
matrixtest.core=> (reshape v [6 1])
[[1] [2] [3] [4] [5] [6]]
 
; sloupec z vektoru
matrixtest.core=> (pm *1)
[[1.000]
 [2.000]
 [3.000]
 [4.000]
 [5.000]
 [6.000]]

14. Projekt Incanter

Projekt Incanter, jenž je taktéž určen pro jazyk Clojure, je založen na zpracování (rozsáhlých) matic a tzv. datasetů. Ve skutečnosti však klasicky chápané matice v Clojure příliš podporovány nejsou. Při studiu základních knihoven Clojure lze dojít k závěru, že vlastně jen velmi málo funkcí a maker je určeno pro práci s těmito datovými typy, i když je samozřejmě možné jak vektory, tak i matice velmi snadno reprezentovat s využitím základních sekvenčních datových struktur Clojure – seznamů a vektorů. Ve skutečnosti to však není zcela ideální řešení, a to hned z několika důvodů, jejichž společným rysem je rychlost prováděných operací. Z tohoto důvodu je v případě implementace algoritmů, v nichž se intenzivně používají operace s maticemi, mnohem výhodnější využít možností specializovaných knihoven. Projektem Incanter je proto interně používána knihovna core.matrix, která byla ve stručnosti představena v předchozí kapitole.

Poznámka: nesmíme taktéž zapomenout na způsob reprezentace datových struktur v operační paměti. Matice jsou většinou homogenní datovou strukturou, kterou lze v případě, že prvky jsou primitivního datového typu, uložit v kompaktní podobě. U obecných vektorů a sekvencí jazyka Clojure tomu tak však není. Problematikou uložené polí primitivních typů na haldě v JVM jsme se zabývali v článku Pohled pod kapotu JVM – jak efektivně jsou uložena pole a řetězce na haldě? (viz například šestou kapitolu).

15. Infixová notace řešená přes makrosystém jazyka Clojure

Incanter je sice knihovna (resp. skupina knihoven) určená pro programovací jazyk Clojure, který je založen na lispovské syntaxi volání funkcí, ovšem díky existenci makra $= je možné výrazy zapisovat i v infixové podobě, a to včetně správného vyhodnocení priorit operátorů. Podívejme se na několik příkladů.

Základní aritmetické operátory s vyhodnocením priorit:

incanter.irepl=> ($= 1 + 2)
3
 
incanter.irepl=> ($= 1 + 2 * 3)
7

Zpracovat lze dokonce i vektory a matice (operátory jsou přetížené):

incanter.irepl=> ($= [1 2 3] + [4 5 6])
[5 7 9]
 
incanter.irepl=> ($= [1 2 3] * [4 5 6])
[4 10 18]
 
incanter.irepl=> ($= [[1 2][3 4]] + [[5 6][7 8]])
[[6 8] [10 12]]

Využití broadcastingu zmíněného v další kapitole:

incanter.irepl=> ($= [1 2 3] + 10)
[11 12 13]
 
incanter.irepl=> ($= [1 2 3] * -1)
[-1 -2 -3]

16. Broadcasting

Podívejme se nyní na některé základní operace s maticemi, zejména na takzvaný broadcasting:

incanter.irepl=> (def A (matrix [[1 2 3]
            #_=>                 [4 5 6]
            #_=>                 [7 8 9]]))
#'incanter.irepl/A

Broadcasting umožňuje převést číslo (přesněji řečeno skalár) na matici stejného řádu, jakou má druhý operand:

incanter.irepl=> ($= A + 2)
#vectorz/matrix [[3.0,4.0,5.0],
[6.0,7.0,8.0],
[9.0,10.0,11.0]]

Vynásobení matice konstantou (skalárem):

incanter.irepl=> ($= A * -1)
#vectorz/matrix [[-1.0,-2.0,-3.0],
[-4.0,-5.0,-6.0],
[-7.0,-8.0,-9.0]]

Vynásobení matice a vektoru, který byl opět rozšířen na matici:

incanter.irepl=> ($= A * [5 0 5])
#vectorz/matrix [[5.0,0.0,15.0],
[20.0,0.0,30.0],
[35.0,0.0,45.0]]

Skutečný „maticový“ součin matice a vektoru:

incanter.irepl=> (mmult A [5 0 0])
#vectorz/vector [5.0,20.0,35.0]

Matici můžeme transponovat:

incanter.irepl=> (trans A)
#vectorz/matrix [[1.0,4.0,7.0],
[2.0,5.0,8.0],
[3.0,6.0,9.0]]

Můžeme provést vynásobení původní matice s maticí transponovanou:

incanter.irepl=> (mmult A (trans A))
#vectorz/matrix [[14.0,32.0,50.0],
[32.0,77.0,122.0],
[50.0,122.0,194.0]]

Další složitější varianta:

incanter.irepl=> (mmult A (trans A) A)
#vectorz/matrix [[492.0,588.0,684.0],
[1194.0,1425.0,1656.0],
[1896.0,2262.0,2628.0]]

17. Vektory v programovacím jazyku Kawa

Dalším LISPovským jazykem je Kawa určená pro běh ve virtuálním stroji Javy. Klasická javovská pole podporovaná v programovacím jazyku Kawa přináší několik výhod, ale pochopitelně i nevýhod. Samotná pole mají pevnou délku a jejich prvky jsou vždy stejného typu (homogenita). Tato vlastnost (což je výhoda a nevýhoda současně) umožňuje velmi efektivní přístup k prvkům pole, který má u jednorozměrných polí konstantní složitost. Současně jsme však omezeni například tím, že do javovských polí není možné jednoduše ukládat zlomky, celá čísla s libovolným rozsahem atd. V případě, že budeme potřebovat využít i tuto funkcionalitu, je nutné namísto polí použít odlišné datové typy programovacího jazyka Kawa. Může se jednat o vektory podporované v mnoha implementacích LISPu i Scheme (a taktéž v jazyku Clojure, i když zde mají vektory zcela odlišné vnitřní uspořádání) nebo o typ pojmenovaný pro větší zmatek v terminologii array.

V této kapitole si ve stručnosti ukážeme práci s takzvanými vektory. Podporovány jsou tyto funkce:

# Funkce Stručný popis funkce
1 vector konstrukce vektoru a inicializace jeho prvků
2 vector-ref přístup k prvku vektoru
3 vector-set! změna hodnoty prvku vektoru
4 vector? predikát: dotaz, zda je předaná hodnota typu vektor či nikoli
5 vector-length vrací délku vektoru, tedy počet jeho prvků
6 vector->list převod vektoru na seznam
7 list->vector opačný převod

Vektor je možné zkonstruovat speciálním „konstruktorem“, v němž se jednotlivé prvky vektoru zapisují do hranatých závorek (což již známe z programovacího jazyka Clojure). K prvkům vektoru se přistupuje funkcí vector-ref:

(define vector1 [1 2 3 4])
 
(display vector1)
(newline)
 
(display (vector-ref vector1 0))
(display (vector-ref vector1 10))

Výsledek:

#(1 2 3 4)
java.lang.ArrayIndexOutOfBoundsException: 10
        at gnu.lists.FVector.get(FVector.java:105)
        at kawa.lib.vectors.vectorRef(vectors.scm:21)
        at Vectors1.run(Vectors1.scm:7)
        at gnu.expr.ModuleExp.evalModule2(ModuleExp.java:289)
        at gnu.expr.CompiledModule.evalModule(CompiledModule.java:42)
        at gnu.expr.CompiledModule.evalModule(CompiledModule.java:60)
        at kawa.Shell.runFile(Shell.java:565)
        at kawa.Shell.runFileOrClass(Shell.java:468)
        at kawa.repl.processArgs(repl.java:700)
        at kawa.repl.main(repl.java:820)
Poznámka: chyba nastala při přístupu k prvku s indexem 10, který ve čtyřprvkovém vektoru pochopitelně neexistuje.

Vektory lze ovšem taktéž zapsat stylem #(), který je kompatibilní s R7RS:

#|kawa:1|# #(1 2 3)
#(1 2 3)
 
#|kawa:2|# [1 2 3]
#(1 2 3)
 
#|kawa:3|# (eq? #(1 2 3) [1 2 3])
#f
 
#|kawa:4|# (equal? #(1 2 3) [1 2 3])
#t

V dalším demonstračním příkladu je namísto zápisu prvků vektoru do hranatých závorek použit konstruktor představovaný funkcí nazvanou jednoduše vector. Taktéž je zde ukázána změna hodnoty vybraného prvku s využitím funkce vector-set! (tato funkce opět obsahuje ve svém jménu vykřičník, protože mění stav aplikace):

(define vector2 (vector 1 2 3 4 5))
 
(display vector2)
(newline)
 
(display (vector-ref vector2 0))
(newline)
 
(vector-set! vector2 2 -1)
 
(display vector2)
(newline)

Výsledek:

#(1 2 3 4 5)
1
#(1 2 -1 4 5)

Dotazy, zda je daná hodnota vektorem či nikoli, používají predikát vector? (všechny predikáty končí otazníkem):

#|kawa:25|# (vector? "A")
#f
 
#|kawa:26|# (vector? [1 2 3])
#t
 
#|kawa:27|# (vector? '(1 2 3))
#f

Další funkce je určena pro získání velikosti vektoru, tedy počtu jeho prvků:

#|kawa:28|# (vector-length [1 2 3])
3
 
#|kawa:29|# (vector-length [])
0

18. N-rozměrná pole (ND-Array) v jazyku Kawa

V této kapitole se ve stručnost seznámíme s možnostmi typu array, což je v jazyce Kawa datový typ představující N-rozměrná pole (neboli nosné téma dnešního článku). Kromě toho si ukážeme i práci s takzvanými „rozsahy“ (range), které do značné míry s poli souvisí.

Datový typ array se používá nejenom v jazyce Kawa, ale například i v programovacím jazyce Racket (jedná se pravděpodobně o nejrozsáhlejší a nejúplnější implementaci Scheme vůbec). Samotné pole se skládá ze dvou částí: hodnot jednotlivých prvků a tvaru pole neboli shape. Tvar pole je důležitou strukturou, protože (nepřímo) určuje, jakým způsobem jsou prvky v poli uspořádány. To však není vše, protože je možné jednoduše tvar pole změnit a tím pádem prvky zdánlivě zpřeházet (interně se ovšem v operační paměti s prvky v některých případech manipulovat nemusí). Další důležitou vlastností datového typu array je možnost uložit do pole libovolné hodnoty; jedná se tedy o heterogenní kontejner, na rozdíl od běžných javovských polí.

Ke konstrukci N-rozměrného pole slouží funkce nazvaná make-array. Této funkci se předává vektor obsahující velikosti (rozsah indexů) N-rozměrného pole ve všech dimenzích. Počet prvků tohoto vektoru tedy odpovídá počtu dimenzí. Dále je možné této funkci předat i hodnoty jednotlivých prvků, což si ukážeme v dalším textu. Funkci make-array si můžeme velmi snadno otestovat přímo v interaktivní smyčce REPL programovacího jazyka Kawa.

Mezním případem je prázdné pole:

#|kawa:3|# (make-array [0])
 
#()

Konstrukce jednoprvkového jednorozměrné pole vypadá takto:

#|kawa:8|# (make-array [1])
 
#(#!null)
Poznámka: povšimněte si, jaká je výchozí hodnota jediného prvku vytvořeného pole.

Desetiprvkový vektor, jehož všechny prvky mají výchozí hodnotu:

#|kawa:5|# (make-array [10])
 
#(#!null #!null #!null #!null #!null #!null #!null #!null #!null #!null)

Konstrukce matice typu 1×1, tedy matice s jediným prvkem, který má výchozí hodnotu:

#|kawa:9|# (make-array [1 1])
 
╔#2a:1:1
║#!null║
╚══════╝

Konstrukce matice s jedním řádkem a dvěma sloupci:

#|kawa:7|# (make-array [1 2])
 
╔#2a:1:2══════╗
║#!null│#!null║
╚══════╧══════╝
Poznámka: povšimněte si, jakým způsobem interpret programovacího jazyka Kawa zobrazuje obsah zkonstruovaného pole. U jednorozměrných polí je výsledek zobrazen formou připomínající běžný seznam nebo vektor, ale u dvourozměrných polí zobrazuje tabulku s obsahem jednotlivých prvků, přičemž je na prvním řádku upřesněn jak počet dimenzí, tak i rozsah indexů v jednotlivých dimenzích (zde konkrétně počet řádků oddělený od počtu sloupců dvojtečkou).

Pokračujme s nepatrně složitější maticí, konkrétně s maticí se dvěma řádky a třemi sloupci:

#|kawa:10|# (make-array [2 3])
 
╔#2a:2:3══════╤══════╗
║#!null│#!null│#!null║
╟──────┼──────┼──────╢
║#!null│#!null│#!null║
╚══════╧══════╧══════╝

Trojrozměrná struktura 2×3×4 prvky:

#|kawa:11|# (make-array [2 3 4])
 
╔#3a:2:3:4════╤══════╤══════╗
║#!null│#!null│#!null│#!null║
╟──────┼──────┼──────┼──────╢
║#!null│#!null│#!null│#!null║
╟──────┼──────┼──────┼──────╢
║#!null│#!null│#!null│#!null║
╠══════╪══════╪══════╪══════╣
║#!null│#!null│#!null│#!null║
╟──────┼──────┼──────┼──────╢
║#!null│#!null│#!null│#!null║
╟──────┼──────┼──────┼──────╢
║#!null│#!null│#!null│#!null║
╚══════╧══════╧══════╧══════╝
Poznámka: u trojrozměrné a taktéž u vícerozměrných struktur je již nutné použít oddělovač jednotlivých 2D podmatic tak, jak je to ukázáno na předchozím výstupu z interpretru programovacího jazyka Kawa. Podrobnější informace najdete na stránce https://www.gnu.org/softwa­re/guile/manual/html_node/A­rray-Syntax.html.

Taktéž trojrozměrná struktura, ovšem tentokrát s tvarem 4×3×2 prvky:

#|kawa:12|# (make-array [4 3 2])
 
╔#3a:4:3:2════╗
║#!null│#!null║
╟──────┼──────╢
║#!null│#!null║
╟──────┼──────╢
║#!null│#!null║
╠══════╪══════╣
║#!null│#!null║
╟──────┼──────╢
║#!null│#!null║
╟──────┼──────╢
║#!null│#!null║
╠══════╪══════╣
║#!null│#!null║
╟──────┼──────╢
║#!null│#!null║
╟──────┼──────╢
║#!null│#!null║
╠══════╪══════╣
║#!null│#!null║
╟──────┼──────╢
║#!null│#!null║
╟──────┼──────╢
║#!null│#!null║
╚══════╧══════╝

Čtyřrozměrné pole:

#|kawa:7|# (make-array [2 2 2 2])
 
╔#4a:2:2:2:2══╗
║#!null│#!null║
╟──────┼──────╢
║#!null│#!null║
╠══════╪══════╣
║#!null│#!null║
╟──────┼──────╢
║#!null│#!null║
╠══════╪══════╣
║#!null│#!null║
╟──────┼──────╢
║#!null│#!null║
╠══════╪══════╣
║#!null│#!null║
╟──────┼──────╢
║#!null│#!null║
╚══════╧══════╝

Pole, které má v jedné dimenzi nulovou velikost a celkově tedy nula prvků:

#|kawa:11|# (make-array [0 2 2 2])
 
#4a:0:2:2:2 ()

Funkci make-arrray, s jejím základním použitím jsme se seznámili v předchozím textu, je možné předat i hodnoty jednotlivých prvků vytvářeného pole. Pokud je počet zadaných hodnot menší než počet prvků, budou se prvky opakovat tak dlouho, až se pole postupně vyplní. Samozřejmě se opět podíváme na příklady.

Vektor obsahující stejné hodnoty ve všech prvcích:

#|kawa:13|# (make-array [10] 1/2)
 
#(1/2 1/2 1/2 1/2 1/2 1/2 1/2 1/2 1/2 1/2)

Dvourozměrné pole (matice) se dvěma řádky a čtyřmi sloupci:

#|kawa:1|# (make-array [2 4] 1 2 3 4 5)
 
╔#2a:2:4╗
║1│2│3│4║
╟─┼─┼─┼─╢
║5│1│2│3║
╚═╧═╧═╧═╝

Pole 5×5 prvků se shodnými řádky:

#|kawa:14|# (make-array [5 5] 1 2 3 4 5)
 
╔#2a:5:5╤═╗
║1│2│3│4│5║
╟─┼─┼─┼─┼─╢
║1│2│3│4│5║
╟─┼─┼─┼─┼─╢
║1│2│3│4│5║
╟─┼─┼─┼─┼─╢
║1│2│3│4│5║
╟─┼─┼─┼─┼─╢
║1│2│3│4│5║
╚═╧═╧═╧═╧═╝

Trojrozměrné pole 2×3×4 prvky:

#|kawa:2|# (make-array [2 3 4] 1 2 3 4 5)
 
#3a:2:3:4
║1│2│3│4║
╟─┼─┼─┼─╢
║5│1│2│3║
╟─┼─┼─┼─╢
║4│5│1│2║
╠═╪═╪═╪═╣
║3│4│5│1║
╟─┼─┼─┼─╢
║2│3│4│5║
╟─┼─┼─┼─╢
║1│2│3│4║
╚═╧═╧═╧═╝

Čtyřrozměrné pole 2×2×2×3 prvky:

#|kawa:11|# (make-array [2 2 2 3] 1 2 3)
 
#4a═╤═╗
║1│2│3║
╟─┼─┼─╢
║1│2│3║
╠═╪═╪═╣
║1│2│3║
╟─┼─┼─╢
║1│2│3║
╠═╪═╪═╣
║1│2│3║
╟─┼─┼─╢
║1│2│3║
╠═╪═╪═╣
║1│2│3║
╟─┼─┼─╢
║1│2│3║
╚═╧═╧═╝

Při inicializaci polí se používá konstrukce range. Jedná se o jeden ze způsobů, jakým lze v programovacím jazyku Kawa popsat sekvenci hodnot bez toho, aby bylo nutné explicitně vypsat všechny prvky v sekvenci (a navíc může být zápis názornější, než v případě použití funkce range známé z mnoha jiných programovacích jazyků). Nejnázornější bude si ukázat možnosti, které při specifikaci rozsahů máme.

Hodnoty od 1 do 9 (hodnota 10 již v rozsahu není):

#|kawa:1|# [1 <: 10]
 
#(1 2 3 4 5 6 7 8 9)

Hodnoty od 1 do 10, včetně obou mezí:

#|kawa:2|# [1 <=: 10]
 
#(1 2 3 4 5 6 7 8 9 10)

Počítání směrem k záporné ose (bez uvedení kroku):

#|kawa:3|# [10 >: 0]
 
#(10 9 8 7 6 5 4 3 2 1)

Dtto, ale včetně nuly:

#|kawa:5|# [10 >=: 0]
 
#(10 9 8 7 6 5 4 3 2 1 0)

Specifikace kroku:

#|kawa:4|# [10 by: -2 >: 0]
 
#(10 8 6 4 2)

Dtto, ale včetně nuly:

#|kawa:6|# [10 by: -2 >=: 0]
 
#(10 8 6 4 2 0)

Práce se zlomky:

#|kawa:7|# [1 by: 1/2 <=: 10]
 
#(1 3/2 2 5/2 3 7/2 4 9/2 5 11/2 6 13/2 7 15/2 8 17/2 9 19/2 10)

Počítání po 1/10 (což v IEEE 754 není možné):

#|kawa:8|# [0 by: 1/10 <=: 1]
 
#(0 1/10 1/5 3/10 2/5 1/2 3/5 7/10 4/5 9/10 1)

Výsledkem bude prázdný vektor:

#|kawa:14|# [0 by: 1 <=: -1]
 
#()
#|kawa:2|# (index-array [[1 <: 10]])
 
╔#1a@1:9╤═╤═╤═╤═╤═╗
║0│1│2│3│4│5│6│7│8║
╚═╧═╧═╧═╧═╧═╧═╧═╧═╝

Popř.:

#|kawa:3|# (index-array [[1 <=: 10]])
╔#1a@1:10═╤═╤═╤═╤═╤═╗
║0│1│2│3│4│5│6│7│8│9║
╚═╧═╧═╧═╧═╧═╧═╧═╧═╧═╝

Dvourozměrné pole:

#|kawa:3|# (index-array [[1 <: 3] [2 <: 6]])
 
#2a@1:2@2:4
║0│1│2│3║
╟─┼─┼─┼─╢
║4│5│6│7║
╚═╧═╧═╧═╝

Trojrozměrné pole:

skolení ELK

#|kawa:5|# (index-array [[1 <: 4] [1 <: 4] [1 <: 4]])
 
#3a@1:3@1:3@1:3
║ 0│ 1│ 2║
╟──┼──┼──╢
║ 3│ 4│ 5║
╟──┼──┼──╢
║ 6│ 7│ 8║
╠══╪══╪══╣
║ 9│10│11║
╟──┼──┼──╢
║12│13│14║
╟──┼──┼──╢
║15│16│17║
╠══╪══╪══╣
║18│19│20║
╟──┼──┼──╢
║21│22│23║
╟──┼──┼──╢
║24│25│26║
╚══╧══╧══╝

Odlišný spodní index:

#|kawa:12|# (index-array [[3 <: 7] [3 <: 7] [3 <: 7]])
 
#3a@3:4@3:4@3:4
║ 0│ 1│ 2│ 3║
╟──┼──┼──┼──╢
║ 4│ 5│ 6│ 7║
╟──┼──┼──┼──╢
║ 8│ 9│10│11║
╟──┼──┼──┼──╢
║12│13│14│15║
╠══╪══╪══╪══╣
║16│17│18│19║
╟──┼──┼──┼──╢
║20│21│22│23║
╟──┼──┼──┼──╢
║24│25│26│27║
╟──┼──┼──┼──╢
║28│29│30│31║
╠══╪══╪══╪══╣
║32│33│34│35║
╟──┼──┼──┼──╢
║36│37│38│39║
╟──┼──┼──┼──╢
║40│41│42│43║
╟──┼──┼──┼──╢
║44│45│46│47║
╠══╪══╪══╪══╣
║48│49│50│51║
╟──┼──┼──┼──╢
║52│53│54│55║
╟──┼──┼──┼──╢
║56│57│58│59║
╟──┼──┼──┼──╢
║60│61│62│63║
╚══╧══╧══╧══╝

19. Obsah navazujícího článku

V navazujícím článku se zaměříme na vybrané „klasické“ jazyky určené pro manipulaci s poli. Jedná se především o FORTRAN (dnes vlastně již psán „Fortran“), dále o jazyky APL a J doplněné o novinku představovanou jazykem BQN a taktéž se zmíníme o dnes již prakticky neznámém projektu VectorPascal. V dalších dílech si pak ukážeme některé možnosti jazyka Fortress.

20. Odkazy na Internetu

  1. What is an Array?
    https://vector.org.uk/what-is-an-array/
  2. Vector (Wolfram MathWorld)
    https://mathworld.wolfram­.com/Vector.html
  3. n-Tuple (Wolfram MathWorld)
    https://mathworld.wolfram.com/n-Tuple.html
  4. n-Vector (Wolfram MathWorld)
    https://mathworld.wolfram.com/n-Vector.html
  5. Matrix (Wolfram MathWorld)
    https://mathworld.wolfram­.com/Matrix.html
  6. Array (Wolfram MathWorld)
    https://mathworld.wolfram­.com/Array.html
  7. ND Arrays (Tensors) in different languages
    https://www.youtube.com/wat­ch?v=WbpbEilgQBc
  8. Extending APL to Infinity\
    https://www.jsoftware.com/pa­pers/eem/infinity.htm
  9. Vector Library (R7RS-compatible)
    https://srfi.schemers.org/srfi-133/srfi-133.html
  10. Vectors (pro Gauche)
    https://practical-scheme.net/gauche/man/gauche-refe/Vectors.html
  11. Kawa: Compiling Scheme to Java
    https://www.mit.edu/afs.new/sip­b/project/kawa/doc/kawa-tour.html
  12. Kawa in Languages shootout
    http://per.bothner.com/blog/2010/Kawa-in-shootout/
  13. Kawa 2.0 Supports Scheme R7RS
    https://developers.slashdot­.org/story/14/12/13/2259225/ka­wa-20-supports-scheme-r7rs/
  14. Kawa — fast scripting on the Java platform
    https://lwn.net/Articles/623349/
  15. Incanter is a Clojure-based, R-like platform for statistical computing and graphics.
    http://incanter.org/
  16. Evolution of incanter (Gource Visualization)
    https://www.youtube.com/wat­ch?v=TVfL5nPELr4
  17. Questions tagged [incanter] (na Stack Overflow)
    https://stackoverflow.com/qu­estions/tagged/incanter?sor­t=active
  18. Data Sorcery with Clojure
    https://data-sorcery.org/contents/
  19. Back to the Future: Lisp as a Base for a Statistical Computing System
    https://rd.springer.com/chap­ter/10.1007/978–3–7908–2084–3_2
  20. Incanter Cheat Sheet
    http://incanter.org/docs/incanter-cheat-sheet.pdf
  21. Back to the Future: Lisp as a Base for a Statistical Computing System (celá verze článku)
    https://www.researchgate.net/pu­blication/227019917_Back_to_the_Fu­ture_Lisp_as_a_Base_for_a_Sta­tistical_Computing_System
  22. BQN: finally, an APL for your flying saucer
    https://mlochbaum.github.io/BQN/
  23. Is BQN stable?
    https://mlochbaum.github.i­o/BQN/commentary/stability­.html
  24. Specification: BQN system-provided values
    https://mlochbaum.github.i­o/BQN/spec/system.html
  25. Tutorial: BQN expressions
    https://mlochbaum.github.i­o/BQN/tutorial/expression­.html
  26. BQN primitives
    https://mlochbaum.github.i­o/BQN/doc/primitive.html
  27. Function trains
    https://mlochbaum.github.i­o/BQN/doc/train.html
  28. BQN community links
    https://mlochbaum.github.i­o/BQN/community/index.html
  29. BQN UV
    https://observablehq.com/@lsh/bqn-uv
  30. APL Wiki
    https://aplwiki.com/wiki/
  31. The Array Cast
    https://www.arraycast.com/e­pisodes/episode-03-what-is-an-array
  32. EnthusiastiCon 2019 – An Introduction to APL
    https://www.youtube.com/wat­ch?v=UltnvW83_CQ
  33. Dyalog
    https://www.dyalog.com/
  34. Try APL!
    https://tryapl.org/
  35. Lisp-Stat Information
    http://homepage.cs.uiowa.e­du/~luke/xls/xlsinfo/
  36. Sample Plots in Incanter
    https://github.com/incanter/in­canter/wiki/Sample-Plots-in-Incanter#line
  37. vectorz-clj
    https://github.com/mikera/vectorz-clj
  38. vectorz – Examples
    https://github.com/mikera/vectorz-clj/wiki/Examples
  39. Basic Vector and Matrix Operations in Julia: Quick Reference and Examples
    https://queirozf.com/entries/basic-vector-and-matrix-operations-in-julia-quick-reference-and-examples
  40. Vectors and matrices in Julia
    https://fncbook.github.io/v1­.0/linsys/demos/matrices-julia.html
  41. Array vs Matrix in R Programming
    https://www.geeksforgeeks.org/array-vs-matrix-in-r-programming/
  42. Concurrency (computer science)
    https://en.wikipedia.org/wi­ki/Category:Concurrency_%28com­puter_science%29
  43. Koprogram
    https://cs.wikipedia.org/wi­ki/Koprogram
  44. Coroutine
    https://en.wikipedia.org/wi­ki/Coroutine
  45. Coroutines in C
    http://www.chiark.greenen­d.org.uk/~sgtatham/corouti­nes.html
  46. S-expression (Wikipedia)
    https://en.wikipedia.org/wiki/S-expression
  47. S-Expressions (Rosetta Code)
    http://rosettacode.org/wiki/S-Expressions
  48. Introducing Julia/Metaprogramming
    https://en.wikibooks.org/wi­ki/Introducing_Julia/Meta­programming
  49. Tutorial for the Common Lisp Loop Macro
    http://www.ai.sri.com/pkarp/loop.html
  50. Clojure Macro Tutorial (Part I, Getting the Compiler to Write Your Code For You)
    http://www.learningclojure­.com/2010/09/clojure-macro-tutorial-part-i-getting.html
  51. Clojure Macro Tutorial (Part II: The Compiler Strikes Back)
    http://www.learningclojure­.com/2010/09/clojure-macro-tutorial-part-ii-compiler.html
  52. Clojure Macro Tutorial (Part III: Syntax Quote)
    http://www.learningclojure­.com/2010/09/clojure-macro-tutorial-part-ii-syntax.html
  53. Clojure Macros and Metaprogramming
    http://clojure-doc.org/articles/language/macros.html
  54. Fatvat – Exploring functional programming: Clojure Macros
    http://www.fatvat.co.uk/2009/02/clo­jure-macros.html
  55. CS 2101 Parallel Computing with Julia
    https://www.coursehero.com/fi­le/11508091/CS-2101-Parallel-Computing-with-Julia/
  56. Julia By Example
    https://samuelcolvin.github­.io/JuliaByExample/
  57. Array Programming
    https://en.wikipedia.org/wi­ki/Array_programming
  58. Discovering Array Languages
    http://archive.vector.org­.uk/art10008110
  59. no stinking loops – Kalothi
    http://www.nsl.com/
  60. Vector (obsahuje odkazy na články, knihy a blogy o programovacích jazycích APL, J a K)
    http://www.vector.org.uk/
  61. APL Interpreters
    http://www.vector.org.uk/?a­rea=interpreters
  62. APL_(programming_language
    http://en.wikipedia.org/wi­ki/APL_(programming_langu­age
  63. APL FAQ
    http://www.faqs.org/faqs/apl-faq/
  64. APL FAQ (nejnovější verze)
    http://home.earthlink.net/~swsir­lin/apl.faq.html
  65. A+
    http://www.aplusdev.org/
  66. APLX
    http://www.microapl.co.uk/
  67. FreeAPL
    http://www.pyr.fi/apl/index.htm
  68. J: a modern, high-level, general-purpose, high-performance programming language
    http://www.jsoftware.com/
  69. K, Kdb: an APL derivative for Solaris, Linux, Windows
    http://www.kx.com
  70. openAPL (GPL)
    http://sourceforge.net/pro­jects/openapl
  71. Parrot APL (GPL)
    http://www.parrotcode.org/
  72. Learning J (Roger Stokes)
    http://www.jsoftware.com/hel­p/learning/contents.htm
  73. Rosetta Code
    http://rosettacode.org/wiki/Main_Page
  74. Why APL
    http://www.acm.org/sigapl/whyapl.htm
  75. Introducing Julia/Functions
    https://en.wikibooks.org/wi­ki/Introducing_Julia/Functi­ons
  76. Functions (Julia documentation)
    https://docs.julialang.or­g/en/v1/manual/functions/
  77. Evaluate binomial coefficients
    http://rosettacode.org/wi­ki/Evaluate_binomial_coef­ficients
  78. Ackermann function
    http://rosettacode.org/wi­ki/Ackermann_function
  79. Julia (front page)
    http://julialang.org/
  80. Julia – dokumentace
    http://docs.julialang.org/
  81. Julia – repositář na GitHubu
    https://github.com/JuliaLang/julia
  82. Julia (programming language)
    https://en.wikipedia.org/wi­ki/Julia_%28programming_lan­guage%29
  83. IJulia
    https://github.com/JuliaLan­g/IJulia.jl
  84. Introducing Julia
    https://en.wikibooks.org/wi­ki/Introducing_Julia
  85. Julia: the REPL
    https://en.wikibooks.org/wi­ki/Introducing_Julia/The_REPL
  86. Month of Julia
    https://github.com/DataWo­okie/MonthOfJulia
  87. Learn X in Y minutes (where X=Julia)
    https://learnxinyminutes.com/doc­s/julia/
  88. New Julia language seeks to be the C for scientists
    http://www.infoworld.com/ar­ticle/2616709/application-development/new-julia-language-seeks-to-be-the-c-for-scientists.html
  89. Julia: A Fast Dynamic Language for Technical Computing
    http://karpinski.org/publi­cations/2012/julia-a-fast-dynamic-language
  90. The LLVM Compiler Infrastructure
    http://llvm.org/
  91. Julia: benchmarks
    http://julialang.org/benchmarks/
  92. Type system
    https://en.wikipedia.org/wi­ki/Type_system
  93. Half-precision floating-point format
    https://en.wikipedia.org/wiki/Half-precision_floating-point_format
  94. Dartmouth BASIC
    https://en.wikipedia.org/wi­ki/Dartmouth_BASIC
  95. BASIC 4th Edition
    http://www.bitsavers.org/pdf/dar­tmouth/BASIC_4th_Edition_Jan68­.pdf
  96. VECTRAN
    https://encyclopedia2.the­freedictionary.com/VECTRAN
  97. Comparison of programming languages (array)
    https://en.wikipedia.org/wi­ki/Comparison_of_programmin­g_languages_(array)
  98. BASIC at 50
    https://www.dartmouth.edu/ba­sicfifty/commands.html
  99. BBC Basic – arrays
    http://www.riscos.com/sup­port/developers/bbcbasic/par­t2/arrays.html
  100. Datová struktura
    https://cs.wikipedia.org/wi­ki/Datov%C3%A1_struktura
  101. SIMD instrukce využívané v moderních mikroprocesorech řady x86
    https://www.root.cz/clanky/simd-instrukce-vyuzivane-v-modernich-mikroprocesorech-rady-x86/
  102. SIMD instrukce v moderních mikroprocesorech řady x86 (2.část: SSE)
    https://www.root.cz/clanky/simd-instrukce-v-modernich-mikroprocesorech-rady-x86–2-cast-sse/
  103. SIMD instrukce v moderních mikroprocesorech řady x86 (3.část: SSE2)
    https://www.root.cz/clanky/simd-instrukce-v-modernich-mikroprocesorech-rady-x86–3-cast-sse2/
  104. Programování mainframů: jazyk APL
    https://www.root.cz/clanky/pro­gramovani-mainframu-jazyk-apl/
  105. Programovací jazyk APL: programování bez smyček
    https://www.root.cz/clanky/pro­gramovaci-jazyk-apl-programovani-bez-smycek/
  106. Programovací jazyk APL – dokončení
    https://www.root.cz/clanky/pro­gramovaci-jazyk-apl-dokonceni/
  107. Programovací jazyk J – od hieroglyfů k ASCII znakům
    https://www.root.cz/clanky/pro­gramovaci-jazyk-j-ndash-od-hieroglyfu-k-nbsp-ascii-znakum/
  108. Programujeme v jazyku J: vektory a matice
    https://www.root.cz/clanky/pro­gramujeme-v-jazyku-j-ndash-vektory-a-matice/
  109. Programovací jazyk J: operátory, uživatelské funkce a tacit programming
    https://www.root.cz/clanky/pro­gramovaci-jazyk-j-operatory-uzivatelske-funkce-a-tacit-programming/
  110. Oslava 55 let od vzniku první implementace jazyka APL
    https://www.root.cz/clanky/oslava-55-let-od-vzniku-prvni-implementace-programovaciho-jazyka-apl/
  111. Zpracování vektorů, matic a N-rozměrných polí v programovacím jazyku Kawa
    https://www.root.cz/clanky/zpracovani-vektoru-matic-a-n-rozmernych-poli-v-programovacim-jazyku-kawa/
  112. Rust: knihovna ndarray pro práci s n-rozměrnými poli
    https://www.root.cz/clanky/rust-knihovna-ndarray-pro-praci-s-n-rozmernymi-poli/
  113. Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
    https://www.root.cz/clanky/pro­gramovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi/
  114. Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi (2)
    https://www.root.cz/clanky/pro­gramovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi-2/
  115. Gophernotes: kombinace interaktivního prostředí Jupyteru s jazykem Go
    https://www.root.cz/clanky/gophernotes-kombinace-interaktivniho-prostredi-jupyteru-s-jazykem-go/
  116. Popis vybraných balíčků nabízených projektem Gonum
    https://www.root.cz/clanky/popis-vybranych-balicku-nabizenych-projektem-gonum/
  117. Integrovaná vývojová prostředí ve Fedoře: vykreslování grafů s využitím knihoven Numpy a matplotlib
    https://mojefedora.cz/integrovana-vyvojova-prostredi-ve-fedore-vykreslovani-grafu-s-vyuzitim-knihoven-numpy-a-matplotlib/
  118. Integrovaná vývojová prostředí ve Fedoře: praktické použití IPython Notebooku a knihovny Numpy (2.část)
    https://mojefedora.cz/integrovana-vyvojova-prostredi-ve-fedore-prakticke-pouziti-ipython-notebooku-a-knihovny-numpy-2-cast/
  119. Integrovaná vývojová prostředí ve Fedoře: praktické použití IPython Notebooku a knihovny Numpy
    https://mojefedora.cz/integrovana-vyvojova-prostredi-ve-fedore-prakticke-pouziti-ipython-notebooku-a-knihovny-numpy/

Autor článku

Pavel Tišnovský vystudoval VUT FIT a v současné době pracuje ve společnosti Red Hat, kde vyvíjí nástroje pro OpenShift.io.