Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi

28. 4. 2015
Doba čtení: 21 minut

Sdílet

V dnešní části seriálu o programovacím jazyku Clojure i o knihovnách dostupných vývojářům používajícím Clojure, se budeme zabývat knihovnami určenými pro práci s vektory a maticemi. Tato oblast IT, která je někdy nazývána array programming, se neustále rozvíjí a to mj. i díky rozšiřování možností GPU.

Obsah

1. Array programming a specializované programovací jazyky určené pro zpracování matic

2. Programovací jazyk APL

3. Programovací jazyk J

4. Další programovací jazyky podporující práci s vektory a maticemi

5. Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi

6. Knihovna core.matrix

7. První demonstrační příklad: vítejte v Matrixu

8. Další vlastnosti knihovny core.matrix zkoumané s využitím REPLu

9. Repositář s demonstračními příklady

10. Odkazy na předchozí části seriálu

11. Knihy a články o programovacích jazycích APL a J

12. Odkazy na Internetu

1. Array programming a specializované programovací jazyky určené pro zpracování matic

Jednou poměrně rozsáhlou oblastí v IT je zpracování vektorů a matic, protože s těmito strukturami se můžeme setkat v různých disciplínách, například ve finančnictví, pojišťovnictví, statistice, zpracování numerických dat, simulacích atd. Současně se jedná i o velmi zajímavou oblast, neboť právě kvůli co nejrychlejší práci 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). Současné knihovny dokážou v případě potřeby využít jak některé rozšíření instrukčních sad (SIMD instrukce typu SSE, původně též MMX či 3DNow!), tak i programovatelné grafické akcelerátory (GPU). Práce s vektory a maticemi byla (a samozřejmě doposud je) podporována v překladačích FORTRANu, které začaly být po vzniku superpočítačů vybaveny algoritmy, které dokázaly převést některé typy programových smyček na „vektorové operace“. Paralelně vznikly i specializované jazyky určené téměř výhradně pro práci s vektory i maticemi – příkladem jsou jazyky APL a J zmíněné ve druhé a ve třetí kapitole.

My se v dnešním článku budeme zabývat použitím knihovny nazvané core.matrix, která vývojářům pracujícím s programovacím jazykem Clojure nabízí prakticky všechny potřebné operace, které se při práci s vektory a maticemi používají (včetně například výpočtu inverzní matice). Navíc je tato knihovna zajímavá tím, že předepisuje rozhraní pro všechny operace, ovšem konkrétní implementaci je možné vybrat. To například znamená, že pokud je řešen nějaký problém, v němž se ve velké míře používají takzvané řídké matice (pěkným příkladem z praxe může být Google matrix), lze – beze změny uživatelského programu – vybrat takovou reprezentaci matic a takové algoritmy, které jsou optimalizovány právě pro práci s řídkými maticemi a nikoli s maticemi uloženými ve formě dvourozměrného pole.

2. Programovací jazyk APL

Kanonickým programovacím jazykem orientovaným téměř výhradně právě na array programming je programovací jazyk nazvaný APL. Historie APL se začala psát již v roce 1957. Právě tehdy Kenneth Iverson z Harvardské university vytvořil notaci vhodnou pro jednotný zápis matematických funkcí i tvorbu funkcí nových. V roce 1962 byla tato notace popsána v knize „A Programming Language“ a o několik let později se začaly objevovat skutečné interpretry i překladače programovacího jazyka používajícího stejné symboly, jaké popsal Iverson ve své knize. Konkrétně se jednalo o jazyk IVSYS implementovaný v roce 1965, který byl následován jazykem APL\1130 z roku 1967, jenž pracoval na počítači IBM 1130. Další implementace tohoto jazyka vznikly na mainframech IBM/360 a IBM/370, později se různé (ve větší či menší míře modifikované) verze APL začaly používat i na minipočítačích a posléze i na mikropočítačích. Dnes existují implementace pro všechny rozšířené operační systémy mikropočítačů, takže APL je možné použít na Linuxu, Mac OS i Microsoft Windows

apl

Obrázek 1: Rozložení znaků na klávesnici používané při programování v jazyku APL. Speciální znaky na klávesnici reprezentují základní (primitivní) funkce a operátory.

Jedním z typických rysů programovacího jazyka APL je jeho orientace na zpracování vektorů a matic (obecně polí téměř libovolné dimenze, většina implementací povoluje definovat až 63dimenzionální struktury) bez nutnosti použití čítačů či programových smyček. Jazyk APL s těmito datovými strukturami pracuje z hlediska programátora prakticky stejně jako se skalárními hodnotami (čísly), takže například součet položek dvou polí je zapisován stejně jako součet dvou číselných hodnot. Dalším typickým rysem je způsob aplikace funkcí na hodnoty (obecně pole) a vzájemné kombinace funkcí pomocí operátorů (slovem operátor jsou v jazyce APL označovány funkce vyššího řádu, tj. funkce vracející jiné funkce; s funkcemi vyššího řádu se můžeme setkat i v mnoha dalších programovacích jazycích). Pomocí funkcí a operátorů, které jsou přímo v APL definovány, je možné nahradit i řídicí struktury – podmíněné příkazy a programové smyčky – které dokonce v prvních verzích jazyka ani nebylo možné zapisovat (v pozdějších verzích se pro usnadnění programování tyto řídicí struktury do APL přidaly).

j_lang1_3

Obrázek 2: Zápis idiomů (krátkých, v daném kontextu ustálených výrazů) v jazyku APL se skutečně odlišuje od naprosté většiny ostatních programovacích jazyků. Zajímavé je, že programátoři mající dlouhodobější zkušenosti s APL, tyto idiomy nečtou po jednotlivých symbolech, ale po jejich větších skupinách či dokonce celý idiom jako celek, tj. podobným způsobem, jakým lidé čtou běžné texty (v nich taktéž mají pro mozek smysl skupiny symbolů, nikoli jednotlivé znaky, což lidem umožňuje plynule přečíst i text, v němž jsou některé znaky zpřeházené či nahrazené jinými písmeny).

3. Programovací jazyk J

Programovací jazyk APL do vývoje některých typů aplikací (finančnictví, simulace, …) přinesl mnoho nových myšlenek (ostatně i proto se doposud používá), ale i několik nectností, ostatně jako každý programovací jazyk, který vznikl na samotném začátku vývoje interpretrů a překladačů, tj. v době, kdy ještě nebyla teorie překladačů tak rozvinutá jako v pozdějších letech (nejvíce byla neexistence teorie překladačů patrná u prvního překladače Fortranu firmou IBM, jehož vývoj by byl při uplatnění dnešních znalostí mnohem rychlejší i levnější). Už při letmém pohledu na programy napsané v programovacím jazyce APL (obrázek číslo 2) je zřejmé, že se v něm používá velké množství symbolů, které se nenachází ve znakové sadě ASCII, což je sice velmi unikátní vlastnost (právě proto mnozí vývojáři v APL programují čistě pro radost), ale způsobuje poměrně velké problémy, a to jak při zápisu programů (rozložení znaků na klávesnici), tak i při jejich úpravách, prezentaci na Internetu, protože zdaleka ne všechny fonty obsahují všechny požadované symboly.

Z výše uvedených důvodů otec jazyka APL (již zmiňovaný Kenneth Iverson) na počátku devadesátých let minulého století navrhl nový programovací jazyk nazvaný jednoduše J, který některé výše zmíněné nedostatky jazyka APL odstranil a navíc jazyk rozšířil o některé důležité nové rysy, primitivní funkce i operátory. 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.

4. Další programovací jazyky podporující práci s vektory a maticemi

Práce s vektory a maticemi ovšem nebyla pouze doménou programovacího jazyka APL. Nesmíme totiž zapomenout na ideového následníka APL, jímž je programovací jazyk nazvaný J (viz též samostatnou kapitolu s odkazy na další informační zdroje). Kromě dua APL a J byly maticové operace součástí programovacího jazyka BASIC, konkrétně jeho původní „originální a jediné pravé“ varianty nazvané Dartmouth BASIC, který ve své třetí verzi pocházející z roku 1966 obsahoval deklaraci MAT doplňující již dříve používanou deklaraci pole příkazem DIM. Zajímavé přitom je, že se v BASICu operace pro deklaraci a práci s maticemi objevily dříve než podpora řetězců, což bylo pravděpodobně způsobeno především tím, že oba autoři BASICu (John Kemeny a Thomas Kurtz) byli matematici a současně i vývojáři s velmi dobrou znalostí programovacího jazyka FORTRAN.

V současnosti je používáno relativně velké množství programovacích jazyků popř. specializovaných knihoven orientovaných na práci s vektory a poli. Z komerčních nástrojů je zapotřebí jmenovat především známý MATLAB vydávaný společností MathWorks, nativní práci s maticemi a vektory ovšem velmi dobře podporuje také nástroj GNU Octave (https://gnu.org/software/octave/), jazyk R (http://www.r-project.org/) a také relativně nový jazyk Julia (http://julialang.org/, zajímavé výsledky benchmarků lze najít na adrese http://julialang.org/benchmarks/). Z knihoven jmenujme především oblíbenou a dnes dosti intenzivně využívanou Pythonovskou knihovnu NumPy (http://www.numpy.org/).

5. Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi

Pojďme si nyní říci, jakým způsobem je práce s maticemi podporována v programovacím jazyku Clojure. 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. My se dnes seznámíme především s elegantně navrženou knihovnou core.matrix. Příště se budeme zabývat ještě výkonnějším řešením: knihovnou Neanderthal, která využívá vysoce optimalizovanou nativní knihovnu ATLAS (Automatically Tuned Linear Algebra Software) s možností využití vysokého výpočetního výkonu současných GPU.

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)

6. Knihovna core.matrix

Jak jsme si již řekli v úvodní kapitole, je knihovna nazvaná core.matrix určená těm vývojářům, kteří ve svých projektech potřebují provádět velké množství operací s těmito strukturami, a to na poměrně vysoké úrovni, tj. bez nutnosti přesně specifikovat, jak mají být matice uloženy v paměti, jakým způsobem provádět operaci 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 APL, až na ten rozdíl, že algoritmy zapisované v Clojure jsou pro většinu vývojářů přece jen čitelnější :-). Taktéž jsme si řekli, že rozhraní definované v knihovně core.matrix může mít několik implementací. V současnosti se jedná o 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).

7. První demonstrační příklad: vítejte v Matrixu

Základní možnosti nabízené knihovnou core.matrix si ukážeme v dnešním prvním demonstračním příkladu nazvaném jednoduše matrix1. Nejprve s pomocí nástroje Leiningen vytvoříme adresář s kostrou projektu, a to následujícím příkazem:

lein new app matrix1
Generating a project called matrix1 based on the 'app' template.

Následně je nutné upravit projektový soubor, tj. soubor nazvaný project.clj takovým způsobem, aby se ve vektoru uloženém pod klíčem :dependencies objevil i prvek specifikující knihovnu core.matrix. Úprava je velmi jednoduchá, jak je ostatně patrné i z výpisu:

(defproject matrix1 "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.6.0"]
                 [net.mikera/core.matrix "0.34.0"]]
  :main ^:skip-aot matrix1.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})

Třetím krokem je stažení knihovny core.matrix i všech dalších knihoven, na nichž core.matrix závisí. Tento krok opět zajistí nástroj Leiningen:

lein deps
Retrieving net/mikera/core.matrix/0.34.0/core.matrix-0.34.0.pom from clojars
Retrieving net/mikera/clojure-pom/0.4.0/clojure-pom-0.4.0.pom from clojars
Retrieving net/mikera/mikera-pom/0.4.0/mikera-pom-0.4.0.pom from central
Retrieving org/sonatype/oss/oss-parent/9/oss-parent-9.pom from central
Retrieving org/clojure/clojure/1.7.0-alpha6/clojure-1.7.0-alpha6.pom from central
Retrieving org/clojure/tools.macro/0.1.5/tools.macro-0.1.5.pom from central
Retrieving org/clojure/clojure/1.4.0/clojure-1.4.0.pom from central
Retrieving org/sonatype/oss/oss-parent/5/oss-parent-5.pom from central
Retrieving org/clojure/tools.macro/0.1.5/tools.macro-0.1.5.jar from central
Retrieving net/mikera/core.matrix/0.34.0/core.matrix-0.34.0.jar from clojars

Vlastní zdrojový kód prvního demonstračního příkladu je taktéž poměrně jednoduchý. Můžeme v něm vidět dvojici příkazů use, které načtou všechny funkce a všechna makra z jmenných prostorů clojure.core.matrix a clojure.core.matrix.operators. Následně se vytvoří čtvercová matice nazvaná M a dvouprvkový vektor nazvaný v, s nimiž je provedeno několik operací. Funkce pm slouží pro výpis obsahu matice na standardní výstup v „pěkném“ tvaru (pretty print). Lze samozřejmě použít i funkci print či println:

(ns matrix1.core
    (:gen-class))
 
(use 'clojure.core.matrix)
(use 'clojure.core.matrix.operators)
 
(defn -main
  "Vitejte v Matrixu..."
  [& args]
  (let [M (matrix [[1 2] [3 4]])
        v (matrix [1 2])]
        (pm M)
        (pm v)
        (pm (* v 2))
        (pm (mul M v))
        (pm (* M M))
        (pm (inner-product M v))))

Po spuštění tohoto příkladu se nejdříve vypíšou varování, že ve jmenném prostoru core.matrix.operators došlo k předeklarování globálních symbolů *, -, /, + a == a po těchto pěti řádcích se vypíše obsah matice M, vektoru v, vektoru v vynásobeného dvěma, součinu M*v, součinu M*M atd.:

WARNING: * already refers to: #'clojure.core/* in namespace: matrix1.core, being replaced by: #'clojure.core.matrix.operators/*
WARNING: - already refers to: #'clojure.core/- in namespace: matrix1.core, being replaced by: #'clojure.core.matrix.operators/-
WARNING: / already refers to: #'clojure.core// in namespace: matrix1.core, being replaced by: #'clojure.core.matrix.operators//
WARNING: + already refers to: #'clojure.core/+ in namespace: matrix1.core, being replaced by: #'clojure.core.matrix.operators/+
WARNING: == already refers to: #'clojure.core/== in namespace: matrix1.core, being replaced by: #'clojure.core.matrix.operators/==
[[1.000 2.000]
 [3.000 4.000]]
[1.000 2.000]
[2.000 4.000]
[[1.000 4.000]
 [3.000 8.000]]
[[1.000  4.000]
 [9.000 16.000]]
[5.000 11.000]

8. Další vlastnosti knihovny core.matrix zkoumané s využitím REPLu

Funkce a makra nabízená knihovnou core.matrix nejlépe prozkoumáme přímo s využitím REPLu, tj. interaktivního rozhraní, v němž ihned po zadání dochází k expanzi maker a vyhodnocování funkcí. Pro tyto účely vytvoříme nový demonstrační příklad:

lein new app matrixtest
Generating a project called matrixtest based on the 'app' template.

Soubor project.clj bude vypadat následovně:

(defproject matrixtest "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.6.0"]
                 [net.mikera/core.matrix "0.34.0"]]
  :main ^:skip-aot matrixtest.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})

Vlastní zdrojový kód projektu je pojat minimalisticky, protože slouží jen pro inicializaci knihoven po spuštění REPLu:

ict ve školství 24

(use 'clojure.core.matrix)
(use 'clojure.core.matrix.operators)
 
(println "Vitejte v Matrixu")

Nyní již můžeme REPL spustit a ihned začít s experimenty:

lein repl
WARNING: * already refers to: #'clojure.core/* in namespace: matrixtest.core, being replaced by: #'clojure.core.matrix.operators/*
WARNING: - already refers to: #'clojure.core/- in namespace: matrixtest.core, being replaced by: #'clojure.core.matrix.operators/-
WARNING: / already refers to: #'clojure.core// in namespace: matrixtest.core, being replaced by: #'clojure.core.matrix.operators//
WARNING: + already refers to: #'clojure.core/+ in namespace: matrixtest.core, being replaced by: #'clojure.core.matrix.operators/+
WARNING: == already refers to: #'clojure.core/== in namespace: matrixtest.core, being replaced by: #'clojure.core.matrix.operators/==
Vitejte v Matrixu
nREPL server started on port 38018 on host 127.0.0.1 - nrepl://127.0.0.1:38018
REPL-y 0.3.5, nREPL 0.2.6
Clojure 1.6.0
OpenJDK 64-Bit Server VM 1.7.0_79-b14
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

Konstrukce vektorů a matic

; vektor
matrixtest.core=> (matrix [1 2 3])
[1 2 3]
 
; vektor
matrixtest.core=> (matrix '(1 2 3))
[1 2 3]
 
; matice
matrixtest.core=> (matrix [[1 2] [3 4]])
[[1 2] [3 4]]
 
; matice
matrixtest.core=> (matrix (range 1 10))
[1 2 3 4 5 6 7 8 9]
 
; matice
matrixtest.core=> (matrix [[1 2 3] [4 5 6] [7 8 9]])
[[1 2 3] [4 5 6] [7 8 9]]

Pretty printing matic a vektorů

matrixtest.core=> (pm (matrix [[1 2] [3 4]]))
[[1.000 2.000]
 [3.000 4.000]]
 
matrixtest.core=> (matrix [[1 2] [3 4]])
[[1 2] [3 4]]
 
; *1 obsahuje výsledek poslední vyhodnocené funkce či symbolu
matrixtest.core=> (pm *1)
[[1.000 2.000]
 [3.000 4.000]]

Konstruktory nulové matice a jednotkové matice

matrixtest.core=> (zero-matrix 2 3)
[[0.0 0.0 0.0] [0.0 0.0 0.0]]
 
matrixtest.core=> (pm *1)
[[0.000 0.000 0.000]
 [0.000 0.000 0.000]]
 
matrixtest.core=> (zero-matrix 4 4)
[[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]]
 
matrixtest.core=> (pm *1)
[[0.000 0.000 0.000 0.000]
 [0.000 0.000 0.000 0.000]
 [0.000 0.000 0.000 0.000]
 [0.000 0.000 0.000 0.000]]
 
matrixtest.core=> (identity-matrix 4 4)
[[1.0 0.0 0.0 0.0] [0.0 1.0 0.0 0.0] [0.0 0.0 1.0 0.0] [0.0 0.0 0.0 1.0]]
 
matrixtest.core=> (pm *1)
[[1.000 0.000 0.000 0.000]
 [0.000 1.000 0.000 0.000]
 [0.000 0.000 1.000 0.000]
 [0.000 0.000 0.000 1.000]]

Konstruktor permutační matice

; vektor udává pozice jedniček na jednotlivých řádcích matice
; rozměry matice jsou získány na základě velikosti tohoto vektoru
matrixtest.core=> (permutation-matrix [1 4 2 3 0])
#NDArray [[0.0 1.0 0.0 0.0 0.0] [0.0 0.0 0.0 0.0 1.0] [0.0 0.0 1.0 0.0 0.0] [0.0 0.0 0.0 1.0 0.0] [1.0 0.0 0.0 0.0 0.0]]
 
matrixtest.core=> (pm *1)
[[0.000 1.000 0.000 0.000 0.000]
 [0.000 0.000 0.000 0.000 1.000]
 [0.000 0.000 1.000 0.000 0.000]
 [0.000 0.000 0.000 1.000 0.000]
 [1.000 0.000 0.000 0.000 0.000]]

Transpozice matice

matrixtest.core=> (def M (matrix [[1 2] [3 4]]))
#'matrixtest.core/M
 
matrixtest.core=> M
[[1 2] [3 4]]
 
matrixtest.core=> (pm *1)
[[1.000 2.000]
 [3.000 4.000]]
 
matrixtest.core=> (transpose M)
[[1 3] [2 4]]
 
; vypíše se hodnota transponované matice, původní matice M se nemění
matrixtest.core=> (pm *1)
[[1.000 3.000]
 [2.000 4.000]]

Unární a binární operace nad 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=> (pm (- M1 M2))
[[-4.000 -4.000]
 [-4.000 -4.000]]
 
matrixtest.core=> (pm (* M1 M2))
[[ 5.000 12.000]
 [21.000 32.000]]
 
matrixtest.core=> (pm (* M1 100))
[[100.000 200.000]
 [300.000 400.000]]
 
; zde se nejdříve vypočte inverzní matice k M1
matrixtest.core=> (pm (/ M2 M1))
[[5.000 3.000]
 [2.333 2.000]]
 
matrixtest.core=> (inverse M1)
#NDArrayDouble [[-1.9999999999999998 1.0] [1.4999999999999998 -0.49999999999999994]]
 
matrixtest.core=> (inverse M2)
#NDArrayDouble [[-4.000000000000002 3.0000000000000013] [3.5000000000000018 -2.5000000000000013]]

Funkce vracející informaci o tom, zda je hodnota skalárem či maticí

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
 
; jen 42 je skalární hodnota
matrixtest.core=> (for [obj [42 v M MD]] (array? obj))
(false true true true)
 
; jen 42 je skalární hodnota
matrixtest.core=> (for [obj [42 v M MD]] (scalar? obj))
(true false false false)

Funkce vracející informace o maticích (počet dimenzí a tvar)

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]]]
 
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]

Přečtení hodnoty prvku matice a získání řezu (slice)

matrixtest.core=> (mget M 0 0)
1
 
matrixtest.core=> (slice v 1)
2
 
; řez 2D maticí
matrixtest.core=> (slice M 1)
[3 4]
 
; řez 3D maticí
matrixtest.core=> (slice MD 1)
[[5 6] [7 8]]
 
; operace nad řezy
matrixtest.core=> (for [slice (slices M)] (apply + slice))
(3 7)
 
; vektorová! operace nad řezy
matrixtest.core=> (apply + (slices M))
[4 6]

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]]

Využití makra → ke kompozici operací

; jedná se o oneliner rozepsaný kvůli větší čitelnosti na čtyři řádky
(-> (matrix (range 1 101))
    (reshape [10 10])
    transpose
    pm)
[[ 1.000 11.000 21.000 31.000 41.000 51.000 61.000 71.000 81.000  91.000]
 [ 2.000 12.000 22.000 32.000 42.000 52.000 62.000 72.000 82.000  92.000]
 [ 3.000 13.000 23.000 33.000 43.000 53.000 63.000 73.000 83.000  93.000]
 [ 4.000 14.000 24.000 34.000 44.000 54.000 64.000 74.000 84.000  94.000]
 [ 5.000 15.000 25.000 35.000 45.000 55.000 65.000 75.000 85.000  95.000]
 [ 6.000 16.000 26.000 36.000 46.000 56.000 66.000 76.000 86.000  96.000]
 [ 7.000 17.000 27.000 37.000 47.000 57.000 67.000 77.000 87.000  97.000]
 [ 8.000 18.000 28.000 38.000 48.000 58.000 68.000 78.000 88.000  98.000]
 [ 9.000 19.000 29.000 39.000 49.000 59.000 69.000 79.000 89.000  99.000]
 [10.000 20.000 30.000 40.000 50.000 60.000 70.000 80.000 90.000 100.000]]
 
; sekvence operací aplikovaných na matici M1
(-> M1
    transpose
    inverse
    (* 10000)
    transpose
    (* M2)
    (+ M1)
    pm)
[[-99999.000  60002.000]
 [105003.000 -39996.000]]

9. Repositář s demonstračními příklady

Oba dva dnes popsané demonstrační příklady byly, podobně jako v minulé i předminulé části tohoto článku, uloženy do GIT repositáře dostupného na adrese https://github.com/tisnik/clojure-examples (dříve popsané příklady budou přidány později). V tabulce zobrazené pod tímto odstavcem naleznete na jednotlivé příklady přímé odkazy:

10. Odkazy na předchozí části seriálu

  1. Leiningen: nástroj pro správu projektů napsaných v Clojure
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure/
  2. Leiningen: nástroj pro správu projektů napsaných v Clojure (2)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-2/
  3. Leiningen: nástroj pro správu projektů napsaných v Clojure (3)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-3/
  4. Leiningen: nástroj pro správu projektů napsaných v Clojure (4)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-4/
  5. Leiningen: nástroj pro správu projektů napsaných v Clojure (5)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-5/
  6. Leiningen: nástroj pro správu projektů napsaných v Clojure (6)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-6/
  7. Programovací jazyk Clojure a databáze (1.část)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-databaze-1-cast/
  8. Pluginy pro Leiningen
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-pluginy-pro-leiningen/

11. Knihy a články o programovacích jazycích APL a J

  1. Ajay Askoolum, „System Building with APL + WIN,
    Wiley, ISBN: 0–470–03020–8, August 2006.
  2. Brown et. al. „APL2 at a Glance,
    Prentice Hall, ISBN 0–13–038670–7.
  3. T. Budd, „An APL Compiler,
    Springer-Verlag.
  4. Maurice Dalois, „Introduction to APL*PLUS PC,
  5. J. Ever and C. Fair, „Guidelines for APL Systems,
    DPD 22 IBM 037301, March 1976.
  6. Gilman and Rose, „APL – An Interactive Approach,
    Wiley, ISBN 220–471–30022–5.
  7. Ulf Grenander, „Mathematical Experiments on the Computer,
    Academic Press, 1982, ISBN 0–12–301750–5.
  8. Kent Haralson, „Useful APL Defined Functions“,
    IBM Technical Report, TR 00.2409, Feb. 8 1973.
  9. Timothy Holls, „APL Programming Guide,
    IBM G320–6103, 1978, and G320–6735, 1981.
  10. IBM, „APL2 Programming: Language Reference
    (Version 2, SH21–1061; Version 1, SH20–9227).
  11. IBM, „The APL Handbook of Techniques“,
    IBM publication number S320–5996, April 1978.
  12. IBM, „The IBM System Journal, V. 30, No. 4 (1991)“,
    Special Issue Devoted to APL.
  13. MicroAPL, „Learning APL with APLX“,
    Version 5.0 July 2009
  14. A.D. Falkoff, K.E Iverson, E.H Sussenguth, „A formal description of System/360,
    The IBM System Journal, V. 3, No. 3 (1964)
  15. K. E. Iverson, „A Programming Language“,
    Wiley, 1962.
  16. 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.
  17. K. E. Iverson, „Elementary analysis“,
    APL press 1976, Preliminary Edition „Elementary Functions
    Copyright 1974 by IBM Corporation ISBN 0–917326–01–6
  18. K. E. Iverson, „An introduction to APL for Scientists and Engineers“,
    APL Press 1976,
    First published by IMB Corporation as Technical Report No 320–3019 March 1973 – ISBN 0–917326–04–0
  19. K. E. Iverson, „APL in exposition“,
    APL Press 1976,
    First published by IBM Corporation as Technical Report No 320–3010 March 1973 – ISBN 0–917326–02–4.
  20. K. E. Iverson, „Introduction To APL“,
    (1984-APL Press Palo Alto) ISBN 0–917326–14–8.
  21. K. E. Iverson, „A personal view of APL,
    IBM Systems Journal,
  22. K. E. Iverson, „Concrete Mathematics Companion“.
  23. S. Kamin, „Programming Languages: An Interpreter-Based Approach,
    contains (among other things) toy implementations of Lisp, APL, Scheme, SASL, CLU, Smalltalk, and Prolog, Addison-Wesley, 1990, ISBN 0–201–06824–9.
  24. Bernard LEGRAND, „Les APL Etendus,
    Masson, Paris, 1994. An introduction to modern APL (French).
  25. Jon McGrew, „An Introduction to APL2,
    IBM (SH20–9229).
  26. James A. Mason, „Learning APL: An Array Processing Language,
    Harper & Row Publishers Inc., New York, 1986, ISBN 0–06–044243–3 260 pp.
  27. Peelle, „APL an Introduction“,
    Holt, Rinehart & Winston, ISBN 0–03–004953–9.
  28. Reiter & Jones, „APL with a Mathematical Accent“,
    Brooks/Cole ISBN 0–534–12864–5, (now being distributed by Chapman & Hall).
  29. C. Reiter, „Fractuals Visualization and J“,
    Iverson Software, Inc, 1995 ISBN 1–895721–11–3.
  30. Adrian Smith, „APL, A Design Handbook for Commercial Systems,
    Wiley series in information processing, Wiley & Sons, 1982, ISBN 0–471–10092–7.
  31. D. Stiers, M.J. Goovaerts, J. De Kerf, „APL – The Language and its Actuarial Applications
  32. Norman D. Thomson, Raymond P. Polivka, „APL2 in Depth,
    Springer-Verlag, 1995, ISBN 0–387–94213–0.
  33. Jerry R. Turner, „APL IS EASY!,
    Manugistics, 1993.
  34. SHARP APL Reference Manual,
    2nd ed., Soliton Associates Limited PC Version: Iverson Software, 1993, ISBN 1–895721–07–5.
  35. A Source Book in APL,
    APL Press, 1981, ISBN 0–917326–10–5.
  36. J Phrases,
    Iverson Software, 1996, ISBN 1–895721–12–1
  37. Exploring Math“, Iverson Software, 1996, ISBN 1–895721–13-X
  38. J Primer,
    Iverson Software, 1996, ISBN 1–895721–14–8
  39. Linda Alvord and Norman Thomson, „Easy-J: An Introduction to the World's most Remarkable Programming Language
    October 2002

12. Odkazy na Internetu

  1. The Clojure Toolbox
    http://www.clojure-toolbox.com/
  2. Neanderthal
    http://neanderthal.uncomplicate.org/
  3. Hello world project
    https://github.com/uncompli­cate/neanderthal/blob/mas­ter/examples/hello-world/project.clj
  4. vectorz-clj
    https://github.com/mikera/vectorz-clj
  5. vectorz – Examples
    https://github.com/mikera/vectorz-clj/wiki/Examples
  6. gloss
    https://github.com/ztellman/gloss
  7. HTTP client/server for Clojure
    http://www.http-kit.org/
  8. Array Programming
    https://en.wikipedia.org/wi­ki/Array_programming
  9. Discovering Array Languages
    http://archive.vector.org­.uk/art10008110
  10. no stinking loops – Kalothi
    http://www.nsl.com/
  11. Vector (obsahuje odkazy na články, knihy a blogy o programovacích jazycích APL, J a K)
    http://www.vector.org.uk/
  12. APL Interpreters
    http://www.vector.org.uk/?a­rea=interpreters
  13. APL_(programming_language
    http://en.wikipedia.org/wi­ki/APL_(programming_langu­age
  14. APL FAQ
    http://www.faqs.org/faqs/apl-faq/
  15. APL FAQ (nejnovější verze)
    http://home.earthlink.net/~swsir­lin/apl.faq.html
  16. A+
    http://www.aplusdev.org/
  17. APLX
    http://www.microapl.co.uk/
  18. FreeAPL
    http://www.pyr.fi/apl/index.htm
  19. J: a modern, high-level, general-purpose, high-performance programming language
    http://www.jsoftware.com/
  20. K, Kdb: an APL derivative for Solaris, Linux, Windows
    http://www.kx.com
  21. openAPL (GPL)
    http://sourceforge.net/pro­jects/openapl
  22. Parrot APL (GPL)
    http://www.parrotcode.org/
  23. Learning J (Roger Stokes)
    http://www.jsoftware.com/hel­p/learning/contents.htm
  24. Rosetta Code
    http://rosettacode.org/wiki/Main_Page
  25. Why APL
    http://www.acm.org/sigapl/whyapl.htm
  26. java.jdbc API Reference
    https://clojure.github.io/java.jdbc/
  27. Hiccup
    https://github.com/weavejester/hiccup
  28. Clojure Ring na GitHubu
    https://github.com/ring-clojure/ring
  29. A brief overview of the Clojure web stack
    https://brehaut.net/blog/2011/rin­g_introduction
  30. Getting Started with Ring
    http://www.learningclojure­.com/2013/01/getting-started-with-ring.html
  31. Getting Started with Ring and Compojure – Clojure Web Programming
    http://www.myclojureadven­ture.com/2011/03/getting-started-with-ring-and-compojure.html
  32. Unit Testing in Clojure
    http://nakkaya.com/2009/11/18/unit-testing-in-clojure/
  33. Testing in Clojure (Part-1: Unit testing)
    http://blog.knoldus.com/2014/03/22/tes­ting-in-clojure-part-1-unit-testing/
  34. API for clojure.test – Clojure v1.6 (stable)
    https://clojure.github.io/clo­jure/clojure.test-api.html
  35. Leiningen: úvodní stránka
    http://leiningen.org/
  36. Leiningen: Git repository
    https://github.com/techno­mancy/leiningen
  37. leiningen-win-installer
    http://leiningen-win-installer.djpowell.net/
  38. Clojure 1: Úvod
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/
  39. Clojure 2: Symboly, kolekce atd.
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/
  40. Clojure 3: Funkcionální programování
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-3-cast-funkcionalni-programovani/
  41. Clojure 4: Kolekce, sekvence a lazy sekvence
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-4-cast-kolekce-sekvence-a-lazy-sekvence/
  42. Clojure 5: Sekvence, lazy sekvence a paralelní programy
    http://www.root.cz/clanky/clojure-a-bezpecne-aplikace-pro-jvm-sekvence-lazy-sekvence-a-paralelni-programy/
  43. Clojure 6: Podpora pro paralelní programování
    http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/
  44. Clojure 7: Další funkce pro paralelní programování
    http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/
  45. Clojure 8: Identity, stavy, neměnné hodnoty a reference
    http://www.root.cz/clanky/programovaci-jazyk-clojure-8-identity-stavy-nemenne-hodnoty-a-referencni-typy/
  46. Clojure 9: Validátory, pozorovatelé a kooperace s Javou
    http://www.root.cz/clanky/programovaci-jazyk-clojure-9-validatory-pozorovatele-a-kooperace-mezi-clojure-a-javou/
  47. Clojure 10: Kooperace mezi Clojure a Javou
    http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/
  48. Clojure 11: Generátorová notace seznamu/list comprehension
    http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/
  49. Clojure 12: Překlad programů z Clojure do bajtkódu JVM I
    http://www.root.cz/clanky/programovaci-jazyk-clojure-12-preklad-programu-z-clojure-do-bajtkodu-jvm/
  50. Clojure 13: Překlad programů z Clojure do bajtkódu JVM II
    2) http://www.root.cz/clanky/programovaci-jazyk-clojure-13-preklad-programu-z-clojure-do-bajtkodu-jvm-pokracovani/
  51. Clojure 14: Základy práce se systémem maker
    http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/
  52. Clojure 15: Tvorba uživatelských maker
    http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/
  53. Clojure 16: Složitější uživatelská makra
    http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/
  54. Clojure 17: Využití standardních maker v praxi
    http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/
  55. Clojure 18: Základní techniky optimalizace aplikací
    http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/
  56. Clojure 19: Vývojová prostředí pro Clojure
    http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/
  57. Clojure 20: Vývojová prostředí pro Clojure (Vimu s REPL)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-20-vyvojova-prostredi-pro-clojure-integrace-vimu-s-repl/
  58. Clojure 21: ClojureScript aneb překlad Clojure do JS
    http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/

Autor článku

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