Obsah
1. Incanter: operace s maticemi
6. Operace prováděné nad všemi prvky matic
8. Maticové operace: maticový součin, transpozice a stopa
9. Maticový součin zapsaný infixovým operátorem v makru $=
11. Řešení soustavy lineárních rovnic
12. Výsledky vypočtené ve chvíli, kdy řešení neexistuje nebo je jich nekonečně mnoho
13. Složitější příklad systému lineárních rovnic
14. Poslední příklad: řešení tří rovnic o třech neznámých
18. Repositář s demonstračními příklady
19. Předchozí články o programovacím jazyku Clojure a jeho knihovnách
1. Incanter: operace s maticemi
S tvorbou matic jsme se již ve stručnosti seznámili v úvodním článku, takže si na tomto místě pouze připomeňme, že matice jsou základní homogenní datovou strukturou, se kterou nástroj Incanter pracuje. Dokonce i takzvané datasety, s nimiž se setkáme později, jsou založeny na maticích. Vzhledem k tomu, že je projekt Incanter určen především pro statistické výpočty, setkáme se v něm především s běžnými dvourozměrnými maticemi, taktéž se sloupcovou maticí a samozřejmě i s řádkovým vektorem (což je ovšem struktura odlišná od vektoru programovacího jazyka Clojure).
2. Konstruktory matic
Připomeňme si, že matici lze vytvořit z běžného vektoru obsahujícího jako své prvky další vektory. Kromě vektoru je samozřejmě možné použít libovolnou sekvenci podporovanou programovacím jazykem Clojure a převést ji na matici konstruktorem matrix.
incanter.irepl=> (doc matrix) ------------------------- incanter.core/matrix ([data] [data ncol] [init-val rows cols]) Returns a matrix or vector, in a valid core.matrix format. You can use the slices function to access the rows. Equivalent to R's matrix function. Examples: (def A (matrix [[1 2 3] [4 5 6] [7 8 9]])) ; produces a 3x3 matrix (def A2 (matrix [1 2 3 4 5 6 7 8 9] 3)) ; produces the same 3x3 matrix (def B (matrix [1 2 3 4 5 6 7 8 9])) ; produces a vector with 9 elements ; since (plus row1 row2) adds the two rows element-by-element (reduce plus A) ; produces the sums of the columns ; and since (sum row1) sums the elements of the row (map sum A) ; produces the sums of the rows
Přitom víme, že sekvence se tvoří například funkcí range, ale též funkcí repeat:
(ns matrix-constructors (:use (incanter core))) ; matice 3x3 prvky (def M1 (matrix [[1 2 3] [4 5 6] [7 8 9]])) ; matice s jedním řádkem (def M2 (matrix [1 2 3 4 5 6 7 8 9])) ; matice s jedním sloupcem (def M3 (matrix [1 2 3 4 5 6 7 8 9] 1)) ; matice 4x4 s nulovými prvky (def M4 (matrix (repeat 16 0) 4)) ; matice 5x5 (def M5 (matrix (range 25) 5)) ; matice 5x5 se všemi prvky nastavenými na jedničku (def M6 (matrix (repeat 25 1) 5))
Jednotlivé matice si můžeme snadno vypsat, a to přímo v interaktivní smyčce REPL:
; matice 3x3 prvky incanter.irepl=> (println M1) #vectorz/matrix [[1.0,2.0,3.0], [4.0,5.0,6.0], [7.0,8.0,9.0]] ; matice s jedním řádkem incanter.irepl=> (println M2) #vectorz/vector [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0] ; matice s jedním sloupcem incanter.irepl=> (println M3) #vectorz/matrix [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0], [7.0], [8.0], [9.0]] ; matice 4x4 s nulovými prvky incanter.irepl=> (println M4) #vectorz/matrix [[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]] ; matice 5x5 incanter.irepl=> (println M5) #vectorz/matrix [[0.0,1.0,2.0,3.0,4.0], [5.0,6.0,7.0,8.0,9.0], [10.0,11.0,12.0,13.0,14.0], [15.0,16.0,17.0,18.0,19.0], [20.0,21.0,22.0,23.0,24.0]] ; matice 5x5 se všemi prvky nastavenými na jedničku incanter.irepl=> (println M6) #vectorz/matrix [[1.0,1.0,1.0,1.0,1.0], [1.0,1.0,1.0,1.0,1.0], [1.0,1.0,1.0,1.0,1.0], [1.0,1.0,1.0,1.0,1.0],
Při konstrukci matice z vektoru se samozřejmě provádí kontroly, zda rekurzivně zanořené vektory skutečně tvoří obdélníkovou matici. O případných problémech vás Incanter ihned informuje:
incanter.irepl=> (def MX (matrix [[1 2 3] [4 5 6] [7 8 9 10]])) CompilerException clojure.lang.ExceptionInfo: Can't convert to persistent vector array: inconsistent shape. {}, compiling:(form-init7924884427446760615.clj:1:9)
Popř.:
incanter.irepl=> (def MY (matrix [[1] 2])) CompilerException clojure.lang.ExceptionInfo: Can't convert to persistent vector array: inconsistent shape. {}, compiling:(form-init7924884427446760615.clj:1:9)
3. Jednotkové matice
V prostředí systému Incanter je možné pracovat i s jednotkovými maticemi. Ty jsou vždy čtvercové a kromě hlavní diagonály s hodnotami 1 obsahují všechny ostatní prvky nulu. Díky této vlastnosti jsou jednotkové matice symetrické, ortogonální a samozřejmě i inverzní samy k sobě. Při maticovém násobení hrají jednotkové matice úlohu neutrálního jednotkového) prvku. Jednotkové matice se vytváří konstruktorem identity-matrix:
incanter.irepl=> (doc identity-matrix) ------------------------- incanter.core/identity-matrix ([n]) Returns an n-by-n identity matrix. Examples: (identity-matrix 4)
Příklad vytvoření jednotkových matic s různou velikostí:
(ns matrix-constructors (:use (incanter core))) ; jednotkové matice (def I0 (identity-matrix 0)) (def I1 (identity-matrix 1)) (def I2 (identity-matrix 2)) (def I3 (identity-matrix 3)) (def I4 (identity-matrix 4)) (def I5 (identity-matrix 5))
Výsledné matice vypadají takto (povšimněte si, že není možné vytvořit matici velikosti 0):
incanter.irepl=> (println I0) nil incanter.irepl=> (println I1) #vectorz/matrix [[1.0]] incanter.irepl=> (println I2) #vectorz/matrix [[1.0,0.0], [0.0,1.0]] incanter.irepl=> (println I3) #vectorz/matrix [[1.0,0.0,0.0], [0.0,1.0,0.0], [0.0,0.0,1.0]] incanter.irepl=> (println I4) #vectorz/matrix [[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]] incanter.irepl=> (println I5) #vectorz/matrix [[1.0,0.0,0.0,0.0,0.0], [0.0,1.0,0.0,0.0,0.0], [0.0,0.0,1.0,0.0,0.0], [0.0,0.0,0.0,1.0,0.0], [0.0,0.0,0.0,0.0,1.0]]
Velikost jednotkové matice by měla být přirozené číslo, což se v konstruktoru kontroluje:
incanter.irepl=> (identity-matrix -1) ArrayIndexOutOfBoundsException -1 mikera.matrixx.impl.IdentityMatrix.create (IdentityMatrix.java:33)
4. Diagonální matice
Pro konstrukci diagonálních matic slouží konstruktor nazvaný jednoduše diag. Tomuto konstruktoru se předávají hodnoty prvků umístěných na hlavní diagonále, přičemž ostatní prvky zkonstruované matice budou mít samozřejmě nulovou hodnotu. Počet prvků na hlavní diagonále přímo určuje velikost matice; současně se bude jednat o matici čtvercovou:
incanter.irepl=> (doc diag) ------------------------- incanter.core/diag ([m]) If given a matrix, diag returns a sequence of its diagonal elements. If given a sequence, it returns a matrix with the sequence's elements on its diagonal. Equivalent to R's diag function. Examples: (diag [1 2 3 4]) ; produces diagonal matrix (def A (matrix [[1 2 3] [4 5 6] [7 8 9]])) (diag A) ;; returns elements on main diagonal
Příklad vytvoření tří diagonálních matic o různých rozměrech:
(ns matrix-constructors (:use (incanter core))) ; diagonální matice (def D1 (diag [1 2 3 4])) (def D2 (diag (range 10))) (def D3 (diag (repeat 10 1)))
Výsledky – zkonstruované matice:
; matice o rozměrech 4×4 prvky incanter.irepl=> (println D1) #vectorz/matrix [[1.0,0.0,0.0,0.0], [0.0,2.0,0.0,0.0], [0.0,0.0,3.0,0.0], [0.0,0.0,0.0,4.0]] ; matice o rozměrech 10×10 prvků incanter.irepl=> (println D2) #vectorz/matrix [[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0], [0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0], [0.0,0.0,2.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0], [0.0,0.0,0.0,3.0,0.0,0.0,0.0,0.0,0.0,0.0], [0.0,0.0,0.0,0.0,4.0,0.0,0.0,0.0,0.0,0.0], [0.0,0.0,0.0,0.0,0.0,5.0,0.0,0.0,0.0,0.0], [0.0,0.0,0.0,0.0,0.0,0.0,6.0,0.0,0.0,0.0], [0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.0,0.0,0.0], [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.0,0.0], [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.0]] ; matice o rozměrech 10×10 prvků incanter.irepl=> (println D3) #vectorz/matrix [[1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0], [0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0], [0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0], [0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0], [0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0], [0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0], [0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0], [0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0], [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0], [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0]]
5. Symetrické matice
Další potenciálně užitečnou funkcí je konstruktor symetrických matic. Vzhledem k tomu, že některé prvky symetrických matic mají (již z definice) stejné hodnoty, předává se konstruktoru nazvaném symmetric-matrix menší počet prvků, než odpovídá velikosti matice. Konkrétně je nutné zadat pouze prvky ležící v trojúhelníku vymezeném hlavní diagonálou. Implicitně se jedná o trojúhelník ležící pod diagonálou, ovšem nastavením nepovinného parametru :lower na hodnotu false je možné specifikovat prvky ležící nad hlavní diagonálou:
incanter.irepl=> (doc symmetric-matrix) ------------------------- incanter.core/symmetric-matrix ([data & {:keys [lower], :or {lower true}}]) Returns a symmetric matrix from the given data, which represents the lower triangular elements ordered by row. This is not the inverse of half-vectorize which returns a vector of the upper-triangular values, unless the :lower option is set to false. Options: :lower (default true) -- lower-triangular. Set :lower to false to reverse the half-vectorize function.
Podívejme se nyní na příklady konstrukce symetrických matic:
; matice 1x1 prvek ; | 1 | incanter.irepl=> (symmetric-matrix [1]) #vectorz/matrix [[1.0]] ; matice 2x2 prvky ; | 1 . | ; | 2 3 | incanter.irepl=> (symmetric-matrix [1 2 3]) #vectorz/matrix [[1.0,2.0], [2.0,3.0]] ; matice 3x3 prvky ; | 1 . . | ; | 2 3 . | ; | 4 5 6 | incanter.irepl=> (symmetric-matrix [1 2 3 4 5 6]) #vectorz/matrix [[1.0,2.0,4.0], [2.0,3.0,5.0], [4.0,5.0,6.0]] ; matice 4x4 prvky ; | 1 . . . | ; | 2 3 . . | ; | 4 5 6 . | ; | 7 8 9 10 | incanter.irepl=> (symmetric-matrix [1 2 3 4 5 6 7 8 9 10]) #vectorz/matrix [[1.0,2.0,4.0,7.0], [2.0,3.0,5.0,8.0], [4.0,5.0,6.0,9.0], [7.0,8.0,9.0,10.0]] ; matice 4x4 prvky ; | 1 2 3 4 | ; | . 5 6 7 | ; | . . 8 9 | ; | . . . 10 | incanter.irepl=> (symmetric-matrix [1 2 3 4 5 6 7 8 9 10] :lower false) #vectorz/matrix [[1.0,2.0,3.0,4.0], [2.0,5.0,6.0,7.0], [3.0,6.0,8.0,9.0], [4.0,7.0,9.0,10.0]] ; matice 10x10 prvků incanter.irepl=> (symmetric-matrix (range 55)) #vectorz/matrix [[0.0,1.0,3.0,6.0,10.0,15.0,21.0,28.0,36.0,45.0], [1.0,2.0,4.0,7.0,11.0,16.0,22.0,29.0,37.0,46.0], [3.0,4.0,5.0,8.0,12.0,17.0,23.0,30.0,38.0,47.0], [6.0,7.0,8.0,9.0,13.0,18.0,24.0,31.0,39.0,48.0], [10.0,11.0,12.0,13.0,14.0,19.0,25.0,32.0,40.0,49.0], [15.0,16.0,17.0,18.0,19.0,20.0,26.0,33.0,41.0,50.0], [21.0,22.0,23.0,24.0,25.0,26.0,27.0,34.0,42.0,51.0], [28.0,29.0,30.0,31.0,32.0,33.0,34.0,35.0,43.0,52.0], [36.0,37.0,38.0,39.0,40.0,41.0,42.0,43.0,44.0,53.0], [45.0,46.0,47.0,48.0,49.0,50.0,51.0,52.0,53.0,54.0]] ; matice 10x10 prvků incanter.irepl=> (symmetric-matrix (range 55) :lower false) #vectorz/matrix [[0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0], [1.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0], [2.0,11.0,19.0,20.0,21.0,22.0,23.0,24.0,25.0,26.0], [3.0,12.0,20.0,27.0,28.0,29.0,30.0,31.0,32.0,33.0], [4.0,13.0,21.0,28.0,34.0,35.0,36.0,37.0,38.0,39.0], [5.0,14.0,22.0,29.0,35.0,40.0,41.0,42.0,43.0,44.0], [6.0,15.0,23.0,30.0,36.0,41.0,45.0,46.0,47.0,48.0], [7.0,16.0,24.0,31.0,37.0,42.0,46.0,49.0,50.0,51.0], [8.0,17.0,25.0,32.0,38.0,43.0,47.0,50.0,52.0,53.0], [9.0,18.0,26.0,33.0,39.0,44.0,48.0,51.0,53.0,54.0]]
6. Operace prováděné nad všemi prvky matic
S korespondujícími prvky dvou matic (se stejnými rozměry!) je možné provádět různé aritmetické operace, tj. součet, součin, rozdíl i podíl. Jedná se o velmi jednoduché a snadno pochopitelné operace, takže se jen v rychlosti podívejme na některé příklady:
incanter.irepl=> (println (plus M1 M1)) #vectorz/matrix [[2.0,4.0,6.0], [8.0,10.0,12.0], [14.0,16.0,18.0]] incanter.irepl=> (println (mult M1 M1)) #vectorz/matrix [[1.0,4.0,9.0], [16.0,25.0,36.0], [49.0,64.0,81.0]]
Aby byl zápis čitelnější, je výhodnější použít makro $=, s nímž jsme se ve stručnosti seznámili minule:
; použití makra $= incanter.irepl=> (println ($= M1 + M1)) #vectorz/matrix [[2.0,4.0,6.0], [8.0,10.0,12.0], [14.0,16.0,18.0]] ; použití makra $= incanter.irepl=> (println ($= M1 + M1 + M1)) #vectorz/matrix [[3.0,6.0,9.0], [12.0,15.0,18.0], [21.0,24.0,27.0]]
Při volání všech operací se provádí kontrola, zda mají obě matice shodné rozměry. Pokud tomu tak není, vyhodí se výjimka:
incanter.irepl=> (def M1 (matrix [[1 2 3] [4 5 6] [7 8 9]])) #'incanter.irepl/M1 incanter.irepl=> (def M2 (matrix [1 2 3 4 5 6 7 8 9])) #'incanter.irepl/M2 incanter.irepl=> (plus M1 M2) IllegalArgumentException Can't broadcast Vector with shape [9] to shape: [3,3] mikera.vectorz.impl.AStridedVector.broadcastLike (AStridedVector.java:150)
Zde se pokoušíme sečíst matice s rozdílnými rozměry:
incanter.irepl=> (def M3 (matrix [1 2 3 4 5 6 7 8 9] 1)) #'incanter.irepl/M3 incanter.irepl=> (plus M1 M3) IndexOutOfBoundsException Mismatched sizes: [3,3] vs. [9,1] mikera.matrixx.impl.ARectangularMatrix.checkSameShape (ARectangularMatrix.java:82)
Dále je možné aplikovat běžné funkce typu sin na všechny prvky zdrojové matice. Výsledkem bude nová matice se stejnými rozměry, ovšem (pochopitelně) s jinými hodnotami prvků:
incanter.irepl=> (println (abs M4)) #vectorz/matrix [[0.0,1.0,2.0,3.0,4.0], [5.0,6.0,7.0,8.0,9.0], [10.0,11.0,12.0,13.0,14.0], [15.0,16.0,17.0,18.0,19.0], [20.0,21.0,22.0,23.0,24.0]] incanter.irepl=> (println (exp M4)) #vectorz/matrix [[1.0,2.718281828459045,7.38905609893065,20.085536923187668,54.598150033144236], [148.4131591025766,403.4287934927351,1096.6331584284585,2980.9579870417283,8103.083927575384], [22026.465794806718,59874.14171519782,162754.79141900392,442413.3920089205,1202604.2841647768], [3269017.3724721107,8886110.520507872,2.41549527535753E7,6.565996913733051E7,1.7848230096318725E8], [4.851651954097903E8,1.3188157344832146E9,3.584912846131592E9,9.744803446248903E9,2.648912212984347E10]] incanter.irepl=> (println (sqrt M4)) #vectorz/matrix [[0.0,1.0,1.4142135623730951,1.7320508075688772,2.0], [2.23606797749979,2.449489742783178,2.6457513110645907,2.8284271247461903,3.0], [3.1622776601683795,3.3166247903554,3.4641016151377544,3.605551275463989,3.7416573867739413], [3.872983346207417,4.0,4.123105625617661,4.242640687119285,4.358898943540674], [4.47213595499958,4.58257569495584,4.69041575982343,4.795831523312719,4.898979485566356]] incanter.irepl=> (println (sin M4)) #vectorz/matrix [[0.0,0.8414709848078965,0.9092974268256817,0.1411200080598672,-0.7568024953079282], [-0.9589242746631385,-0.27941549819892586,0.6569865987187891,0.9893582466233818,0.4121184852417566], [-0.5440211108893698,-0.9999902065507035,-0.5365729180004349,0.4201670368266409,0.9906073556948704], [0.6502878401571168,-0.2879033166650653,-0.9613974918795568,-0.7509872467716762,0.14987720966295234], [0.9129452507276277,0.8366556385360561,-0.008851309290403876,-0.8462204041751706,-0.9055783620066238]] incanter.irepl=> (println (cos M4)) #vectorz/matrix [[1.0,0.5403023058681398– 0.4161468365471424– 0.9899924966004454– 0.6536436208636119], [0.28366218546322625,0.9601702866503661,0.7539022543433046– 0.14550003380861354– 0.9111302618846769], [-0.8390715290764524,0.004425697988050785,0.8438539587324921,0.9074467814501962,0.1367372182078336], [-0.7596879128588213– 0.9576594803233847– 0.27516333805159693,0.6603167082440802,0.9887046181866692], [0.40808206181339196– 0.5477292602242684– 0.9999608263946371– 0.5328330203333975,0.424179007336997]]
Zajímavá je funkce pow, které se kromě matice předává i příslušná mocnina:
incanter.irepl=> (println (pow M4 2)) #vectorz/matrix [[0.0,1.0,4.0,9.0,16.0], [25.0,36.0,49.0,64.0,81.0], [100.0,121.0,144.0,169.0,196.0], [225.0,256.0,289.0,324.0,361.0], [400.0,441.0,484.0,529.0,576.0]]
7. Broadcasting
V projektu Incanter je možné využít i takzvaný broadcasting, s nímž jsme se seznámili například při popisu programovacího jazyka Julia. V případě vektorů jsou totiž všechny výše uvedené operace deklarovány takovým způsobem, že jsou prováděny vždy nad prvky vektorů se shodným indexem a pokud je jedním z operandů skalární hodnota a nikoli vektor, je skalár převeden na vektor stejné délky jakou má druhý operand. Toto „rozšíření“ skalární hodnoty na vektor se nazývá broadcast a podobně funguje i „rozšíření“ skalární hodnoty na celou matici (libovolných rozměrů). Tato vlastnost je velmi užitečná, jak ostatně můžeme vidět z následujících příkladů:
incanter.irepl=> (println (plus M1 10)) #vectorz/matrix [[11.0,12.0,13.0], [14.0,15.0,16.0], [17.0,18.0,19.0]] incanter.irepl=> (println (plus M4 12)) #vectorz/matrix [[12.0,13.0,14.0,15.0,16.0], [17.0,18.0,19.0,20.0,21.0], [22.0,23.0,24.0,25.0,26.0], [27.0,28.0,29.0,30.0,31.0], [32.0,33.0,34.0,35.0,36.0]] ; inverze všech prvků matice incanter.irepl=> (println (mult M1 -1)) #vectorz/matrix [[-1.0,-2.0,-3.0], [-4.0,-5.0,-6.0], [-7.0,-8.0,-9.0]]
Samozřejmě opět můžeme využít makro $=, a to následujícím způsobem:
incanter.irepl=> (println ($= M1 + 10)) #vectorz/matrix [[11.0,12.0,13.0], [14.0,15.0,16.0], [17.0,18.0,19.0]] incanter.irepl=> (println ($= M4 - 12)) #vectorz/matrix [[-12.0,-11.0,-10.0,-9.0,-8.0], [-7.0,-6.0,-5.0,-4.0,-3.0], [-2.0,-1.0,0.0,1.0,2.0], [3.0,4.0,5.0,6.0,7.0], [8.0,9.0,10.0,11.0,12.0]] incanter.irepl=> (println ($= M1 * -1)) #vectorz/matrix [[-1.0,-2.0,-3.0], [-4.0,-5.0,-6.0], [-7.0,-8.0,-9.0]] incanter.irepl=> (println ($= M1 * 10 - 100)) #vectorz/matrix [[-90.0,-80.0,-70.0], [-60.0,-50.0,-40.0], [-30.0,-20.0,-10.0]]
Opakem broadcastingu jsou funkce, které z obsahu celé matice vypočtou jedinou skalární hodnotu. Jedná se o funkce sum (součet všech prvků) a prod (součin všech prvků):
incanter.irepl=> (println (sum M1)) 45.0 incanter.irepl=> (println (sum M4)) 300.0 incanter.irepl=> (println (prod M4)) 0.0 incanter.irepl=> (println (prod M1)) 362880.0
8. Maticové operace: maticový součin, transpozice a stopa
Maticový součin je realizován funkcí mmult:
incanter.irepl=> (doc mmult) ------------------------- incanter.core/mmult ([& args]) Returns the matrix resulting from the matrix multiplication of the the given arguments. Equivalent to R's %*% operator. Examples: (def A (matrix [[1 2 3] [4 5 6] [7 8 9]])) (mmult A (trans A)) (mmult A (trans A) A)
Pro test, jaké výsledky dostaneme, jsou použity tyto matice:
; matice 3x3 prvky (def M1 (matrix [[1 2 3] [4 5 6] [7 8 9]])) ; matice s jedním řádkem (def M2 (matrix [1 2 3 4 5 6 7 8 9])) ; matice s jedním sloupcem (def M3 (matrix [1 2 3 4 5 6 7 8 9] 1)) ; matice 5x5 prvků (def M4 (matrix (range 25) 5))
Nyní si již můžeme maticový součin vyzkoušet:
; násobení matic 3x3 prvky ; výsledkem je matice se shodnými rozměry incanter.irepl=> (println (mmult M1 M1)) #vectorz/matrix [[30.0,36.0,42.0], [66.0,81.0,96.0], [102.0,126.0,150.0]] ; vynásobení matice s jedním řádkem maticí s jedním sloupcem ; výsledkem je matice s jediným prvkem incanter.irepl=> (println (mmult M2 M3)) #vectorz/vector [285.0] ; násobení matic 5x5 prvků ; výsledkem je matice se shodnými rozměry incanter.irepl=> (println (mmult M4 M4)) #vectorz/matrix [[150.0,160.0,170.0,180.0,190.0], [400.0,435.0,470.0,505.0,540.0], [650.0,710.0,770.0,830.0,890.0], [900.0,985.0,1070.0,1155.0,1240.0], [1150.0,1260.0,1370.0,1480.0,1590.0]]
Další užitečnou operací je transpozice matice, tj. vzájemná výměna sloupců a řádků matice. Tato operace se provádí funkcí trans:
; transpozice matice 3x3 prvky incanter.irepl=> (println (trans M1)) #vectorz/matrix [[1.0,4.0,7.0], [2.0,5.0,8.0], [3.0,6.0,9.0]] ; transpozice _vektoru_ tvořeného jedním řádkem incanter.irepl=> (println (trans M2)) #vectorz/vector [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0] ; transpozice matice tvořené jedním sloupcem ; výsledkem je matice s jedním řádkem incanter.irepl=> (println (trans M3)) #vectorz/matrix [[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0]] ; transpozice matice 5x5 prvků incanter.irepl=> (println (trans M4)) #vectorz/matrix [[0.0,5.0,10.0,15.0,20.0], [1.0,6.0,11.0,16.0,21.0], [2.0,7.0,12.0,17.0,22.0], [3.0,8.0,13.0,18.0,23.0], [4.0,9.0,14.0,19.0,24.0]]
Poslední operací, s níž se seznámíme v této kapitole, je výpočet stopy matice. K tomuto účelu se používá funkce pojmenovaná trace:
; výpočet stopy matice incanter.irepl=> (println (trace M1)) 15.0 incanter.irepl=> (println (trace M2)) 1.0 incanter.irepl=> (println (trace M3)) 1.0 incanter.irepl=> (println (trace M4)) 60.0
9. Maticový součin zapsaný infixovým operátorem v makru $=
Tato kapitola bude velmi stručná, protože si v ní jen ukážeme, jakým způsobem se zapisuje násobení matic při použití makra $=. V tomto případě pochopitelně není možné použít pouze operátor *, protože ten znamená součin korespondujících prvků matice. Musíme tedy použít jiný operátor, a to konkrétně v tomto tvaru <*>. Podívejme se nyní na způsob jeho použití:
; násobení matic 3x3 prvky ; výsledkem je matice se shodnými rozměry incanter.irepl=> (println ($= M1 <*> M1)) #vectorz/matrix [[30.0,36.0,42.0], [66.0,81.0,96.0], [102.0,126.0,150.0]] ; vynásobení matice s jedním řádkem maticí s jedním sloupcem ; výsledkem je matice s jediným prvkem incanter.irepl=> (println ($= M2 <*> M3)) #vectorz/vector [285.0] ; vynásobení matice velikosti 5×5 prvků sama sebou incanter.irepl=> (println ($= M4 <*> M4)) #vectorz/matrix [[150.0,160.0,170.0,180.0,190.0], [400.0,435.0,470.0,505.0,540.0], [650.0,710.0,770.0,830.0,890.0], [900.0,985.0,1070.0,1155.0,1240.0], [1150.0,1260.0,1370.0,1480.0,1590.0]]
10. Výpočet determinantu
V Incanteru je samozřejmě možné vypočítat i determinant. Pro tento účel slouží funkce pojmenovaná jednoduše det. Determinant lze vypočítat pro jakoukoli čtvercovou matici:
; výpočet determinantu matice incanter.irepl=> (println (det (matrix [[42]]))) 42.0 incanter.irepl=> (println (det (matrix [[1 2] [3 4]]))) -2.0 incanter.irepl=> (println (det (matrix [[1 0 0] [0 5 0] [0 0 1]]))) 5.0 incanter.irepl=> (println (det (matrix [[0 0 1] [0 5 0] [1 0 1]]))) -5.0 incanter.irepl=> (def M4 (matrix (range 1 26) 5)) #'incanter.irepl/M4 incanter.irepl=> (println (det M4)) -0.0
V případě, že matice není čtvercová, vypíše Incanter chybu:
incanter.irepl=> (println (det (matrix [[0 0 1 0] [0 5 0 0] [1 0 1 0]]))) UnsupportedOperationException Matrix should be square but has shape: [3,4] mikera.matrixx.impl.ARectangularMatrix.checkSquare (ARectangularMatrix.java:75) incanter.irepl=> (println (det (matrix [[0 0 1] [0 5 0] [1 0 1] [1 1 1]]))) UnsupportedOperationException Matrix should be square but has shape: [4,3] mikera.matrixx.impl.ARectangularMatrix.checkSquare (ARectangularMatrix.java:75)
11. Řešení soustavy lineárních rovnic
Výše uvedené operace se prakticky používají například při řešení soustavy lineárních rovnic. Tuto operaci ovšem nemusíte ručně programovat, protože ji Incanter už má implementovanou. Podívejme se na zdaleka nejjednodušší příklad, tj. na řešení jediné rovnice s jedinou neznámou. Rovnice má jednoznačné řešení:
7x = 21
Pro vyřešení této rovnice vytvoříme matici s koeficienty z levé části rovnice. Rovnice je jediná, takže matice bude mít jeden řádek a obsahuje jedinou neznámou, takže bude mít i jeden sloupec:
; matice s koeficienty na levé části rovnice (def A (matrix [[7]]))
Dále vytvoříme matici (resp. přesněji řečeno řádkový vektor) obsahující konstanty na pravých stranách rovnice. Opět platí, že v našem případě máme jedinou rovnici a tudíž i matice bude obsahovat jediný prvek:
; matice s výsledky na pravé části rovnice (def B (matrix [21]))
Vlastní výpočet se provede funkcí solve, které se obě matice předají:
; výpočet (println (solve A B)) #vectorz/vector [3.0]
Vidíme, že výsledkem je vektor obsahující vypočtené hodnoty jednotlivých neznámých. V našem případě se opět jedná o jedinou neznámou x, která byla vypočtena.
incanter.irepl=> (println (solve (matrix [[4 3] [3 2]]))) #vectorz/matrix [[-2.0,3.0], [3.0,-4.0]]
12. Výsledky vypočtené ve chvíli, kdy řešení neexistuje nebo je jich nekonečně mnoho
Zkusme si nyní vypočítat rovnici v případě, že řešení neexistuje:
0x = 1
Celý výpočet:
; matice s koeficienty na levé části rovnice (def A (matrix [[0]])) ; matice s výsledky na pravé části rovnice (def B (matrix [1])) ; výpočet (println (solve A B)) nil
V tomto případě se vrátila hodnota nil značící, že jednoznačné řešení neexistuje.
Podobně si můžeme vyzkoušet vyřešit rovnici s nekonečným množstvím řešení:
0x = 0
Celý výpočet:
; matice s koeficienty na levé části rovnice (def A (matrix [[0]])) ; matice s výsledky na pravé části rovnice (def B (matrix [0])) ; výpočet (println (solve A B)) nil
I v tomto případě získáme hodnotu nil. Popravdě – toto není úplně nejlepší chování Incanteru, protože nemůžeme snadno rozhodnout, jestli má rovnice (systém rovnic) více řešení nebo naopak nemá řešení žádné.
13. Složitější příklad systému lineárních rovnic
Zkusme si ukázat nepatrně složitější příklad s dvojicí rovnic o dvou neznámých x a y:
3x + 2y = 8 x + y = 2
Matice A nyní bude velikosti 2×2 a bude obsahovat jednotlivé koeficienty tak, jak jsou zapsány v rovnících:
; matice s koeficienty na levé části rovnic (def A (matrix [[3 2] [1 1]]))
Matice B bude obsahovat dva prvky, a to konkrétně hodnoty z pravých stran rovnic:
; matice s výsledky na pravé části rovnic (def B (matrix [8 2]))
Vlastní výpočet:
(println (solve A B)) #vectorz/vector [3.9999999999999996,-1.9999999999999993]
Výsledkem je tedy x=4 a y=-2.
Výsledek je samozřejmě vhodné ověřit, a to vynásobením matice A vektorem s výsledky. Měli bychom dostat pravé strany rovnic:
incanter.irepl=> (println (mmult A (solve A B))) #vectorz/vector [8.0,2.0]
Pokud se vám nechce kontrolovat hodnoty, můžete si pravou stranu rovnic od kontrolního výpočtu odečíst. Měl by vyjít vektor s nulami:
incanter.irepl=> (println (minus B (mmult A (solve A B)))) #vectorz/vector [0.0,0.0]
Jednodušší je ovšem použití threading makra se stejným kontrolním výsledkem:
incanter.irepl=> (->> (solve A B) (mmult A) (minus B) println) #vectorz/vector [0.0,0.0]
14. Poslední příklad: řešení tří rovnic o třech neznámých
V posledním příkladu na použití funkce solve se pokusíme vyřešit tři rovnice o třech neznámých:
4x + 5y - 2z = -14 7x - y + 2z = 42 3x + y + 4z = 28
Výpočet proběhne naprosto stejným způsobem jako v předchozích příkladech, tedy:
; matice s koeficienty na levé části rovnic (def A (matrix [[4 5 -2] [7 -1 2] [3 1 4]])) ; matice s výsledky na pravé části rovnic (def B (matrix [-14 42 28])) ; výpočet koeficientů (println (solve A B)) #vectorz/vector [4.0,-4.0,5.0]
Vypočtené výsledky:
x = 4 y = -4 z = 5
Kontrola výsledků:
incanter.irepl=> (->> (solve A B) (mmult A) (minus B) println) #vectorz/vector [0.0,0.0,0.0]
Získali jsme vektor obsahující trojici nul, tudíž je výsledek správný (samozřejmě za předpokladu, že věříme operacím mmult a minus.
15. Rozklad matic: LU rozklad
V projektu Incanter nalezneme i několik funkcí pro rozklad (dekompozici) matic. Podporován je především známý LU rozklad, který matici rozdělí na dvě matice, jejichž součinem vznikne matice původní:
; matice 3x3 prvky (def M1 (matrix [[1 2 3] [4 5 6] [7 8 9]])) ; matice 5x5 prvků (def M2 (matrix (range 25) 5))
LU rozklad těchto dvou matic bude vypadat následovně:
incanter.irepl=> (println (decomp-lu M1)) { :L #vectorz/matrix [[1.0,0.0,0.0], [0.14285714285714285,1.0,0.0], [0.5714285714285714,0.5000000000000002,1.0]], :U #vectorz/matrix [[7.0,8.0,9.0], [0.0,0.8571428571428572,1.7142857142857144], [0.0,0.0,0.0]], :P #vectorz/matrix [[0.0,1.0,0.0], [0.0,0.0,1.0], [1.0,0.0,0.0]]} incanter.irepl=> (println (decomp-lu M2)) { :L #vectorz/matrix [[1.0,0.0,0.0,0.0,0.0], [0.0,1.0,0.0,0.0,0.0], [0.5,0.5,1.0,0.0,0.0], [0.75,0.25,0.0,1.0,0.0], [0.25,0.75,0.0,0.0,1.0]], :U #vectorz/matrix [[20.0,21.0,22.0,23.0,24.0], [0.0,1.0,2.0,3.0,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]], :P #vectorz/matrix [[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]]}
Povšimněte si, že výsledkem této funkce je slovník se třemi maticemi:
- :L – dolní trojúhelníková matice s jedničkami na celé hlavní diagonále
- :U – horní trojúhelníková matice s nenulovými prvky na hlavní diagonále
- :P – permutační matice, která se vytváří z matice jednotkové permutací sloupců
16. Rozklad matic: QR rozklad
Dalším rozkladem, který je v projektu Incanter podporován, je takzvaný QR rozklad, který opět z původní matice vytvoří dvě další matice, přičemž matice původní vznikne součinem těchto dvou matic. Jedna z těchto matic je přitom ortogonální a druhá má nenulové hodnoty jen v horním trojúhelníku (nad hlavní diagonálou, včetně této diagonály).
Opět si ukažme příklady:
; matice 3x3 prvky (def M1 (matrix [[1 2 3] [4 5 6] [7 8 9]])) ; matice 5x5 prvků (def M2 (matrix (range 25) 5))
Výsledky QR rozkladu mají opět tvar slovníku s klíči :Q a :R:
incanter.irepl=> (println (decomp-qr M1)) { :Q #vectorz/matrix [[-0.12309149097933259,0.9045340337332904,-0.4082482904638633], [-0.49236596391733084,0.30151134457776413,0.8164965809277258], [-0.8616404368553291,-0.30151134457776385,-0.4082482904638628]], :R #vectorz/matrix [[-8.12403840463596,-9.601136296387953,-11.078234188139945], [0.0,0.9045340337332906,1.809068067466581], [0.0,0.0,-6.661338147750939E-16]]} incanter.irepl=> (println (decomp-qr M2)) { :Q #vectorz/matrix [[0.0,-0.7745966692414818,-0.30512113519655665,0.5539103544817643,-0.009187603292109298], [-0.18257418583505536,-0.5163977794943237,0.24754825162995142,-0.594633690716072,-0.5339762513261572], [-0.3651483716701107,-0.258198889747162,-0.12568824995571656,-0.41734960180272546,0.7810389066481741], [-0.5477225575051661,4.996003610813204E-16,0.7292162858078016,0.40295885782662166,0.07660135385056112], [-0.7302967433402214,0.25819888974716165,-0.5459551522854807,0.05511408021041447,-0.31447640588046855]], :R #vectorz/matrix [[-27.386127875258307,-29.211869733608857,-31.037611591959404,-32.86335345030996,-34.68909530866052], [0.0,-1.2909944487358018,-2.5819888974716023,-3.872983346207408,-5.163977794943221], [0.0,0.0,3.1403075784452076E-15,7.690699366007125E-16,-3.204335410487563E-15], [0.0,0.0,0.0,2.755673002419323E-15,1.1022692009677294E-14], [0.0,0.0,0.0,0.0,-1.5777218104420236E-30]]}
17. Choleského dekompozice
Poslední dekompozicí, kterou si dnes popíšeme, je takzvaná Choleského dekompozice, kterou lze použít pro symetrické matice. Výsledkem jsou opět dvě matice, konkrétně dvě trojúhelníkové matice, přičemž jedna trojuhelníková matice je hermitovsky sdružená k matici druhé (v reálném případě transponovaná). Příklad vstupní matice jsem převzal z Wikipedie:
incanter.irepl=> (def M1 (symmetric-matrix [4 12 37 -16 -43 98])) #'incanter.irepl/M1 incanter.irepl=> M1 #vectorz/matrix [[ 4.0, 12.0,-16.0], [ 12.0, 37.0,-43.0], [-16.0,-43.0, 98.0]] incanter.irepl=> (decomp-cholesky M1) { :L #vectorz/matrix [[ 2.0, 0.0, 0.0], [ 6.0, 1.0, 0.0], [-8.0, 5.0, 3.0]], :L* #vectorz/matrix [[ 2.0, 6.0,-8.0], [ 0.0, 1.0, 5.0], [ 0.0, 0.0, 3.0]]}
Povšimněte si, že skutečně byly vypočteny dvě matice, přičemž druhá je transponovaná matice první. Obě matice jsou současně trojúhelníkové.
18. Repozitář s demonstračními příklady
Zdrojové kódy všech dnes popsaných demonstračních příkladů byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/incanter-examples (stále na GitHubu :-). V případě, že nebudete chtít klonovat celý repositář (ten je ovšem stále velmi malý, dnes má doslova několik kilobajtů), můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:
19. Předchozí články o programovacím jazyku Clojure a jeho knihovnách
- 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:
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/ - Programovací jazyk Clojure – triky při práci s řetězci
http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-retezci/ - Programovací jazyk Clojure – triky při práci s kolekcemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-kolekcemi/ - Programovací jazyk Clojure – práce s mapami a množinami
http://www.root.cz/clanky/programovaci-jazyk-clojure-prace-s-mapami-a-mnozinami/ - Programovací jazyk Clojure – základy zpracování XML
http://www.root.cz/clanky/programovaci-jazyk-clojure-zaklady-zpracovani-xml/ - Programovací jazyk Clojure – testování s využitím knihovny Expectations
http://www.root.cz/clanky/programovaci-jazyk-clojure-testovani-s-vyuzitim-knihovny-expectations/ - Programovací jazyk Clojure – některé užitečné triky použitelné (nejenom) v testech
http://www.root.cz/clanky/programovaci-jazyk-clojure-nektere-uzitecne-triky-pouzitelne-nejenom-v-testech/ - Enlive – výkonný šablonovací systém pro jazyk Clojure
http://www.root.cz/clanky/enlive-vykonny-sablonovaci-system-pro-jazyk-clojure/ - Nástroj Leiningen a programovací jazyk Clojure: tvorba vlastních knihoven pro veřejný repositář Clojars
http://www.root.cz/clanky/nastroj-leiningen-a-programovaci-jazyk-clojure-tvorba-vlastnich-knihoven-pro-verejny-repositar-clojars/ - Novinky v Clojure verze 1.8.0
http://www.root.cz/clanky/novinky-v-clojure-verze-1–8–0/ - Asynchronní programování v Clojure s využitím knihovny core.async
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async/ - Asynchronní programování v Clojure s využitím knihovny core.async (pokračování)
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async-pokracovani/ - Asynchronní programování v Clojure s využitím knihovny core.async (dokončení)
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async-dokonceni/ - Vytváříme IRC bota v programovacím jazyce Clojure
http://www.root.cz/clanky/vytvarime-irc-bota-v-programovacim-jazyce-clojure/ - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - Multimetody v Clojure aneb polymorfismus bez použití OOP
https://www.root.cz/clanky/multimetody-v-clojure-aneb-polymorfismus-bez-pouziti-oop/ - Práce s externími Java archivy v programovacím jazyku Clojure
https://www.root.cz/clanky/prace-s-externimi-java-archivy-v-programovacim-jazyku-clojure/ - 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/ - 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/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi-2/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-2/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (2)
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-2/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (3)
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-3/ - Programovací jazyk Clojure a práce s Gitem
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem/ - Programovací jazyk Clojure a práce s Gitem (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem-2/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (dokončení)
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-dokonceni/ - Pixie: lehký skriptovací jazyk s „kouzelnými“ schopnostmi
https://www.root.cz/clanky/pixie-lehky-skriptovaci-jazyk-s-kouzelnymi-schopnostmi/ - Programovací jazyk Pixie: funkce ze základní knihovny a použití FFI
https://www.root.cz/clanky/programovaci-jazyk-pixie-funkce-ze-zakladni-knihovny-a-pouziti-ffi/ - Novinky v Clojure verze 1.9.0
https://www.root.cz/clanky/novinky-v-clojure-verze-1–9–0/ - Validace dat s využitím knihovny spec v Clojure 1.9.0
https://www.root.cz/clanky/validace-dat-s-vyuzitim-knihovny-spec-v-clojure-1–9–0/ - Použití jazyka Gherkin při tvorbě testovacích scénářů pro aplikace psané v Clojure
https://www.root.cz/clanky/pouziti-jazyka-gherkin-pri-tvorbe-testovacich-scenaru-pro-aplikace-psane-v-nbsp-clojure/ - Použití jazyka Gherkin při tvorbě testovacích scénářů pro aplikace psané v Clojure (2)
https://www.root.cz/clanky/pouziti-jazyka-gherkin-pri-tvorbe-testovacich-scenaru-pro-aplikace-psane-v-nbsp-clojure-2/ - Incanter: prostředí pro statistické výpočty s grafickým výstupem založené na Clojure
https://www.root.cz/clanky/incanter-prostredi-pro-statisticke-vypocty-s-grafickym-vystupem-zalozene-na-clojure/
20. Odkazy na Internetu
- Stopa (algebra)
https://cs.wikipedia.org/wiki/Stopa_(algebra) - Matrix calculator
https://matrixcalc.org/en/ - Incanter is a Clojure-based, R-like platform for statistical computing and graphics.
http://incanter.org/ - Evolution of incanter (Gource Visualization)
https://www.youtube.com/watch?v=TVfL5nPELr4 - Questions tagged [incanter] (na Stack Overflow)
https://stackoverflow.com/questions/tagged/incanter?sort=active - Data Sorcery with Clojure
https://data-sorcery.org/contents/ - Back to the Future: Lisp as a Base for a Statistical Computing System
https://rd.springer.com/chapter/10.1007/978–3–7908–2084–3_2 - Incanter Cheat Sheet
http://incanter.org/docs/incanter-cheat-sheet.pdf - Back to the Future: Lisp as a Base for a Statistical Computing System (celá verze článku)
https://www.researchgate.net/publication/227019917_Back_to_the_Future_Lisp_as_a_Base_for_a_Statistical_Computing_System - Lisp-Stat Information
http://homepage.cs.uiowa.edu/~luke/xls/xlsinfo/ - Sample Plots in Incanter
https://github.com/incanter/incanter/wiki/Sample-Plots-in-Incanter#line - vectorz-clj
https://github.com/mikera/vectorz-clj - vectorz – Examples
https://github.com/mikera/vectorz-clj/wiki/Examples - 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/ - Colt
http://dst.lbl.gov/ACSSoftware/colt/ - Parallel Colt: Open Source Libraries for High Performance Scientific and Technical Computing in Java
http://incanter.org/docs/parallelcolt/api/ - Processing
https://www.processing.org/ - The R Project for Statistical Computing
https://www.r-project.org/ - Humane test output for clojure.test
https://github.com/pjstadig/humane-test-output - iota
https://github.com/juxt/iota - 5 Differences between clojure.spec and Schema
https://lispcast.com/clojure.spec-vs-schema/ - Schema: Clojure(Script) library for declarative data description and validation
https://github.com/plumatic/schema - Zip archiv s Clojure 1.9.0
http://repo1.maven.org/maven2/org/clojure/clojure/1.9.0/clojure-1.9.0.zip - Clojure 1.9 is now available
https://clojure.org/news/2017/12/08/clojure19 - Deps and CLI Guide
https://clojure.org/guides/deps_and_cli - Changes to Clojure in Version 1.9
https://github.com/clojure/clojure/blob/master/changes.md - clojure.spec – Rationale and Overview
https://clojure.org/about/spec - Zip archiv s Clojure 1.8.0
http://repo1.maven.org/maven2/org/clojure/clojure/1.8.0/clojure-1.8.0.zip - Clojure 1.8 is now available
http://clojure.org/news/2016/01/19/clojure18 - Socket Server REPL
http://dev.clojure.org/display/design/Socket+Server+REPL - CLJ-1671: Clojure socket server
http://dev.clojure.org/jira/browse/CLJ-1671 - CLJ-1449: Add clojure.string functions for portability to ClojureScript
http://dev.clojure.org/jira/browse/CLJ-1449 - Launching a Socket Server
http://clojure.org/reference/repl_and_main#_launching_a_socket_server - API for clojure.string
http://clojure.github.io/clojure/branch-master/clojure.string-api.html - Clojars:
https://clojars.org/ - Seznam knihoven na Clojars:
https://clojars.org/projects - Clojure Cookbook: Templating HTML with Enlive
https://github.com/clojure-cookbook/clojure-cookbook/blob/master/07_webapps/7–11_enlive.asciidoc - An Introduction to Enlive
https://github.com/swannodette/enlive-tutorial/ - Enlive na GitHubu
https://github.com/cgrand/enlive - Expectations: příklady atd.
http://jayfields.com/expectations/ - Expectations na GitHubu
https://github.com/jaycfields/expectations - Lein-expectations na GitHubu
https://github.com/gar3thjon3s/lein-expectations - Testing Clojure With Expectations
https://semaphoreci.com/blog/2014/09/23/testing-clojure-with-expectations.html - Clojure testing TDD/BDD libraries: clojure.test vs Midje vs Expectations vs Speclj
https://www.reddit.com/r/Clojure/comments/1viilt/clojure_testing_tddbdd_libraries_clojuretest_vs/ - Testing: One assertion per test
http://blog.jayfields.com/2007/06/testing-one-assertion-per-test.html - Rewriting Your Test Suite in Clojure in 24 hours
http://blog.circleci.com/rewriting-your-test-suite-in-clojure-in-24-hours/ - Clojure doc: zipper
http://clojuredocs.org/clojure.zip/zipper - Clojure doc: parse
http://clojuredocs.org/clojure.xml/parse - Clojure doc: xml-zip
http://clojuredocs.org/clojure.zip/xml-zip - Clojure doc: xml-seq
http://clojuredocs.org/clojure.core/xml-seq - Parsing XML in Clojure
https://github.com/clojuredocs/guides - Clojure Zipper Over Nested Vector
https://vitalyper.wordpress.com/2010/11/23/clojure-zipper-over-nested-vector/ - Understanding Clojure's PersistentVector implementation
http://blog.higher-order.net/2009/02/01/understanding-clojures-persistentvector-implementation - Understanding Clojure's PersistentHashMap (deftwice…)
http://blog.higher-order.net/2009/09/08/understanding-clojures-persistenthashmap-deftwice.html - Assoc and Clojure's PersistentHashMap: part ii
http://blog.higher-order.net/2010/08/16/assoc-and-clojures-persistenthashmap-part-ii.html - Ideal Hashtrees (paper)
http://lampwww.epfl.ch/papers/idealhashtrees.pdf - Clojure home page
http://clojure.org/ - Clojure (downloads)
http://clojure.org/downloads - Clojure Sequences
http://clojure.org/sequences - Clojure Data Structures
http://clojure.org/data_structures - The Structure and Interpretation of Computer Programs: 2.2.1 Representing Sequences
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-15.html#%_sec2.2.1 - The Structure and Interpretation of Computer Programs: 3.3.1 Mutable List Structure
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-22.html#%_sec3.3.1 - Clojure – Functional Programming for the JVM
http://java.ociweb.com/mark/clojure/article.html - Clojure quick reference
http://faustus.webatu.com/clj-quick-ref.html - 4Clojure
http://www.4clojure.com/ - ClojureDoc (rozcestník s dokumentací jazyka Clojure)
http://clojuredocs.org/ - Clojure (na Wikipedia EN)
http://en.wikipedia.org/wiki/Clojure - Clojure (na Wikipedia CS)
http://cs.wikipedia.org/wiki/Clojure - SICP (The Structure and Interpretation of Computer Programs)
http://mitpress.mit.edu/sicp/ - Pure function
http://en.wikipedia.org/wiki/Pure_function - Funkcionální programování
http://cs.wikipedia.org/wiki/Funkcionální_programování - Čistě funkcionální (datové struktury, jazyky, programování)
http://cs.wikipedia.org/wiki/Čistě_funkcionální - 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 - Clojure Macro Tutorial (Part II: The Compiler Strikes Back)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-ii-compiler.html - Clojure Macro Tutorial (Part III: Syntax Quote)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-ii-syntax.html - Tech behind Tech: Clojure Macros Simplified
http://techbehindtech.com/2010/09/28/clojure-macros-simplified/ - Fatvat – Exploring functional programming: Clojure Macros
http://www.fatvat.co.uk/2009/02/clojure-macros.html - Eulerovo číslo
http://cs.wikipedia.org/wiki/Eulerovo_číslo - List comprehension
http://en.wikipedia.org/wiki/List_comprehension - List Comprehensions in Clojure
http://asymmetrical-view.com/2008/11/18/list-comprehensions-in-clojure.html - Clojure Programming Concepts: List Comprehension
http://en.wikibooks.org/wiki/Clojure_Programming/Concepts#List_Comprehension - Clojure core API: for macro
http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/for - cirrus machina – The Clojure for macro
http://www.cirrusmachina.com/blog/comment/the-clojure-for-macro/ - Riastradh's Lisp Style Rules
http://mumble.net/~campbell/scheme/style.txt - Dynamic Languages Strike Back
http://steve-yegge.blogspot.cz/2008/05/dynamic-languages-strike-back.html - Scripting: Higher Level Programming for the 21st Century
http://www.tcl.tk/doc/scripting.html - Java Virtual Machine Support for Non-Java Languages
http://docs.oracle.com/javase/7/docs/technotes/guides/vm/multiple-language-support.html - Třída java.lang.String
http://docs.oracle.com/javase/7/docs/api/java/lang/String.html - Třída java.lang.StringBuffer
http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuffer.html - Třída java.lang.StringBuilder
http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html - StringBuffer versus String
http://www.javaworld.com/article/2076072/build-ci-sdlc/stringbuffer-versus-string.html - Threading macro (dokumentace k jazyku Clojure)
https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/-> - Understanding the Clojure → macro
http://blog.fogus.me/2009/09/04/understanding-the-clojure-macro/ - clojure.inspector
http://clojure.github.io/clojure/clojure.inspector-api.html - The Clojure Toolbox
http://www.clojure-toolbox.com/ - 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.org: Vars and the Global Environment
http://clojure.org/Vars - Clojure.org: Refs and Transactions
http://clojure.org/Refs - Clojure.org: Atoms
http://clojure.org/Atoms - Clojure.org: Agents as Asynchronous Actions
http://clojure.org/agents - Transient Data Structureshttp://clojure.org/transients