Obsah
1. Array programming a specializované programovací jazyky určené pro zpracování matic
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
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
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
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).
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/mikeranderson/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:
(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:
# | Příklad | Github |
---|---|---|
1 | matrix1 | https://github.com/tisnik/clojure-examples/tree/master/matrix1 |
2 | matrixtest | https://github.com/tisnik/clojure-examples/tree/master/matrixtest |
10. Odkazy na předchozí části seriálu
- Leiningen: nástroj pro správu projektů napsaných v Clojure
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure/ - 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/ - 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/ - 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/ - 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/ - 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/ - Programovací jazyk Clojure a databáze (1.část)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-databaze-1-cast/ - 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
- Ajay Askoolum, „System Building with APL + WIN,“
Wiley, ISBN: 0–470–03020–8, August 2006. - Brown et. al. „APL2 at a Glance,“
Prentice Hall, ISBN 0–13–038670–7. - T. Budd, „An APL Compiler,“
Springer-Verlag. - Maurice Dalois, „Introduction to APL*PLUS PC,“
- J. Ever and C. Fair, „Guidelines for APL Systems,“
DPD 22 IBM 037301, March 1976. - Gilman and Rose, „APL – An Interactive Approach,“
Wiley, ISBN 220–471–30022–5. - Ulf Grenander, „Mathematical Experiments on the Computer,“
Academic Press, 1982, ISBN 0–12–301750–5. - Kent Haralson, „Useful APL Defined Functions“,
IBM Technical Report, TR 00.2409, Feb. 8 1973. - Timothy Holls, „APL Programming Guide,“
IBM G320–6103, 1978, and G320–6735, 1981. - IBM, „APL2 Programming: Language Reference“
(Version 2, SH21–1061; Version 1, SH20–9227). - IBM, „The APL Handbook of Techniques“,
IBM publication number S320–5996, April 1978. - IBM, „The IBM System Journal, V. 30, No. 4 (1991)“,
Special Issue Devoted to APL. - MicroAPL, „Learning APL with APLX“,
Version 5.0 July 2009 - A.D. Falkoff, K.E Iverson, E.H Sussenguth, „A formal description of System/360,“
The IBM System Journal, V. 3, No. 3 (1964) - K. E. Iverson, „A Programming Language“,
Wiley, 1962. - 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. - K. E. Iverson, „Elementary analysis“,
APL press 1976, Preliminary Edition „Elementary Functions“
Copyright 1974 by IBM Corporation ISBN 0–917326–01–6 - 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 - 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. - K. E. Iverson, „Introduction To APL“,
(1984-APL Press Palo Alto) ISBN 0–917326–14–8. - K. E. Iverson, „A personal view of APL,“
IBM Systems Journal, - K. E. Iverson, „Concrete Mathematics Companion“.
- 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. - Bernard LEGRAND, „Les APL Etendus,“
Masson, Paris, 1994. An introduction to modern APL (French). - Jon McGrew, „An Introduction to APL2,“
IBM (SH20–9229). - James A. Mason, „Learning APL: An Array Processing Language,“
Harper & Row Publishers Inc., New York, 1986, ISBN 0–06–044243–3 260 pp. - Peelle, „APL an Introduction“,
Holt, Rinehart & Winston, ISBN 0–03–004953–9. - Reiter & Jones, „APL with a Mathematical Accent“,
Brooks/Cole ISBN 0–534–12864–5, (now being distributed by Chapman & Hall). - C. Reiter, „Fractuals Visualization and J“,
Iverson Software, Inc, 1995 ISBN 1–895721–11–3. - Adrian Smith, „APL, A Design Handbook for Commercial Systems,“
Wiley series in information processing, Wiley & Sons, 1982, ISBN 0–471–10092–7. - D. Stiers, M.J. Goovaerts, J. De Kerf, „APL – The Language and its Actuarial Applications“
- Norman D. Thomson, Raymond P. Polivka, „APL2 in Depth,“
Springer-Verlag, 1995, ISBN 0–387–94213–0. - Jerry R. Turner, „APL IS EASY!,“
Manugistics, 1993. - „SHARP APL Reference Manual,“
2nd ed., Soliton Associates Limited PC Version: Iverson Software, 1993, ISBN 1–895721–07–5. - „A Source Book in APL,“
APL Press, 1981, ISBN 0–917326–10–5. - „J Phrases,“
Iverson Software, 1996, ISBN 1–895721–12–1 - „Exploring Math“, Iverson Software, 1996, ISBN 1–895721–13-X
- „J Primer,“
Iverson Software, 1996, ISBN 1–895721–14–8 - Linda Alvord and Norman Thomson, „Easy-J: An Introduction to the World's most Remarkable Programming Language“
October 2002
12. Odkazy na Internetu
- The Clojure Toolbox
http://www.clojure-toolbox.com/ - Neanderthal
http://neanderthal.uncomplicate.org/ - Hello world project
https://github.com/uncomplicate/neanderthal/blob/master/examples/hello-world/project.clj - vectorz-clj
https://github.com/mikera/vectorz-clj - vectorz – Examples
https://github.com/mikera/vectorz-clj/wiki/Examples - gloss
https://github.com/ztellman/gloss - HTTP client/server for Clojure
http://www.http-kit.org/ - Array Programming
https://en.wikipedia.org/wiki/Array_programming - Discovering Array Languages
http://archive.vector.org.uk/art10008110 - no stinking loops – Kalothi
http://www.nsl.com/ - Vector (obsahuje odkazy na články, knihy a blogy o programovacích jazycích APL, J a K)
http://www.vector.org.uk/ - APL Interpreters
http://www.vector.org.uk/?area=interpreters - APL_(programming_language
http://en.wikipedia.org/wiki/APL_(programming_language - APL FAQ
http://www.faqs.org/faqs/apl-faq/ - APL FAQ (nejnovější verze)
http://home.earthlink.net/~swsirlin/apl.faq.html - A+
http://www.aplusdev.org/ - APLX
http://www.microapl.co.uk/ - FreeAPL
http://www.pyr.fi/apl/index.htm - J: a modern, high-level, general-purpose, high-performance programming language
http://www.jsoftware.com/ - K, Kdb: an APL derivative for Solaris, Linux, Windows
http://www.kx.com - openAPL (GPL)
http://sourceforge.net/projects/openapl - Parrot APL (GPL)
http://www.parrotcode.org/ - Learning J (Roger Stokes)
http://www.jsoftware.com/help/learning/contents.htm - Rosetta Code
http://rosettacode.org/wiki/Main_Page - Why APL
http://www.acm.org/sigapl/whyapl.htm - java.jdbc API Reference
https://clojure.github.io/java.jdbc/ - Hiccup
https://github.com/weavejester/hiccup - Clojure Ring na GitHubu
https://github.com/ring-clojure/ring - A brief overview of the Clojure web stack
https://brehaut.net/blog/2011/ring_introduction - Getting Started with Ring
http://www.learningclojure.com/2013/01/getting-started-with-ring.html - Getting Started with Ring and Compojure – Clojure Web Programming
http://www.myclojureadventure.com/2011/03/getting-started-with-ring-and-compojure.html - Unit Testing in Clojure
http://nakkaya.com/2009/11/18/unit-testing-in-clojure/ - Testing in Clojure (Part-1: Unit testing)
http://blog.knoldus.com/2014/03/22/testing-in-clojure-part-1-unit-testing/ - API for clojure.test – Clojure v1.6 (stable)
https://clojure.github.io/clojure/clojure.test-api.html - Leiningen: úvodní stránka
http://leiningen.org/ - Leiningen: Git repository
https://github.com/technomancy/leiningen - leiningen-win-installer
http://leiningen-win-installer.djpowell.net/ - Clojure 1: Úvod
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/ - Clojure 2: Symboly, kolekce atd.
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/ - 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/ - 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/ - 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/ - Clojure 6: Podpora pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/ - Clojure 7: Další funkce pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/ - 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/ - 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/ - Clojure 10: Kooperace mezi Clojure a Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/ - Clojure 11: Generátorová notace seznamu/list comprehension
http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/ - 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/ - 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/ - Clojure 14: Základy práce se systémem maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/ - Clojure 15: Tvorba uživatelských maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/ - Clojure 16: Složitější uživatelská makra
http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/ - Clojure 17: Využití standardních maker v praxi
http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/ - Clojure 18: Základní techniky optimalizace aplikací
http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/ - Clojure 19: Vývojová prostředí pro Clojure
http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/ - 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/ - Clojure 21: ClojureScript aneb překlad Clojure do JS
http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/