Incanter: operace s maticemi

30. 10. 2018
Doba čtení: 29 minut

Sdílet

V úvodním článku o projektu Incanter jsme si řekli, že základní datovou strukturou, s níž se pracuje, jsou matice. Projekt Incanter samozřejmě nabízí uživatelům prakticky všechny užitečné funkce pro práci s maticemi.

Obsah

1. Incanter: operace s maticemi

2. Konstruktory matic

3. Jednotkové matice

4. Diagonální matice

5. Symetrické matice

6. Operace prováděné nad všemi prvky matic

7. Broadcasting

8. Maticové operace: maticový součin, transpozice a stopa

9. Maticový součin zapsaný infixovým operátorem v makru $=

10. Výpočet determinantu

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

15. Rozklad matic: LU rozklad

16. Rozklad matic: QR rozklad

17. Choleského dekompozice

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

19. Předchozí články o programovacím jazyku Clojure a jeho knihovnách

20. Odkazy na Internetu

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)
Poznámka: v nejnovější verzi Incanteru je tato funkce označena jako deprecated s tím, že se namísto ní má použít funkce se stejným jménem, ovšem ze jmenného prostoru clojure.core.matrix. Nicméně všechny příklady i testy používající původní funkci identity-matrix budou stále bez problémů pracovat.

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]]
Poznámka: samozřejmě je jednodušší vytvořit poslední matici pomocí příkazu identity-matrix, než kombinací diag a repeat. Pokud by však měly mít prvky na hlavní diagonále odlišnou hodnotu, může to být výhodné.

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]]
Poznámka: kupodivu není možné mocninu určit pro každý prvek zvlášť pomocí další matice, ale skutečně se musí jednat o číslo, konkrétně o typ Number.

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
Poznámka: stopa je vypočtena součtem hodnot všech prvků na hlavní diagonále matice.

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]]
Poznámka: matice byly definovány v rámci předchozí kapitoly.

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
Poznámka: povšimněte si, že se při výpočtu někdy vrátí záporná nula. To je v pořádku, neboť v normě IEEE 754 se rozlišuje znaménko i u nulové hodnoty.

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.

Poznámka: složitější soustava rovnic a její řešení bude popsána ve třinácté kapitole.
Poznámka2: pokud funkci solve předáte jedinou matici, provede se výpočet odpovídající inverzní matice, samozřejmě za předpokladu, že taková matice existuje:
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:

  1. :L – dolní trojúhelníková matice s jedničkami na celé hlavní diagonále
  2. :U – horní trojúhelníková matice s nenulovými prvky na hlavní diagonále
  3. :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]]}
Poznámka: v posledním výsledku je pěkně vidět, jak vypadá matice R.

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:

ict ve školství 24

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:

# Demonstrační příklad Popis Cesta
1 01_matrix_contructors.clj různé konstruktory matic https://github.com/tisnik/incanter-examples/blob/master/incanter-1/01_matrix_contructors.clj
2 02_matrix_item_operations.clj operace prováděné nad prvky matic https://github.com/tisnik/incanter-examples/blob/master/incanter-1/02_matrix_item_operations.clj
3 03_matrix_operations.clj operace prováděné s celými maticemi https://github.com/tisnik/incanter-examples/blob/master/incanter-1/03_matrix_operations.clj
4 04_matrix_solve_A.clj řešení lineární rovnice https://github.com/tisnik/incanter-examples/blob/master/incanter-1/04_matrix_solve_A.clj
5 05_matrix_solve_B.clj řešení soustavy lineárních rovnic https://github.com/tisnik/incanter-examples/blob/master/incanter-1/05_matrix_solve_B.clj
6 06_matrix_decomp.clj dekompozice matic https://github.com/tisnik/incanter-examples/blob/master/incanter-1/06_matrix_decomp.clj
7 07_matrix_subset.clj čtení podmatic https://github.com/tisnik/incanter-examples/blob/master/incanter-1/07_matrix_subset.clj
8 08_view_matrix.clj zobrazení matic v samostatném okně s GUI https://github.com/tisnik/incanter-examples/blob/master/incanter-1/08_view_matrix.clj

19. Předchozí články o programovacím jazyku Clojure a jeho knihovnách

  1. Clojure 1: Úvod
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/
  2. Clojure 2: Symboly, kolekce atd.
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/
  3. 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/
  4. 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/
  5. 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/
  6. Clojure 6: Podpora pro paralelní programování
    http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/
  7. Clojure 7: Další funkce pro paralelní programování
    http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/
  8. 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/
  9. 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/
  10. Clojure 10: Kooperace mezi Clojure a Javou
    http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/
  11. Clojure 11: Generátorová notace seznamu/list comprehension
    http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/
  12. 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/
  13. 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/
  14. Clojure 14: Základy práce se systémem maker
    http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/
  15. Clojure 15: Tvorba uživatelských maker
    http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/
  16. Programovací jazyk Clojure – triky při práci s řetězci
    http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-retezci/
  17. Programovací jazyk Clojure – triky při práci s kolekcemi
    http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-kolekcemi/
  18. Programovací jazyk Clojure – práce s mapami a množinami
    http://www.root.cz/clanky/programovaci-jazyk-clojure-prace-s-mapami-a-mnozinami/
  19. Programovací jazyk Clojure – základy zpracování XML
    http://www.root.cz/clanky/programovaci-jazyk-clojure-zaklady-zpracovani-xml/
  20. Programovací jazyk Clojure – testování s využitím knihovny Expectations
    http://www.root.cz/clanky/programovaci-jazyk-clojure-testovani-s-vyuzitim-knihovny-expectations/
  21. 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/
  22. Enlive – výkonný šablonovací systém pro jazyk Clojure
    http://www.root.cz/clanky/enlive-vykonny-sablonovaci-system-pro-jazyk-clojure/
  23. 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/
  24. Novinky v Clojure verze 1.8.0
    http://www.root.cz/clanky/novinky-v-clojure-verze-1–8–0/
  25. 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/
  26. 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/
  27. 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/
  28. Vytváříme IRC bota v programovacím jazyce Clojure
    http://www.root.cz/clanky/vytvarime-irc-bota-v-programovacim-jazyce-clojure/
  29. Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
    https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/
  30. Multimetody v Clojure aneb polymorfismus bez použití OOP
    https://www.root.cz/clanky/multimetody-v-clojure-aneb-polymorfismus-bez-pouziti-oop/
  31. 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/
  32. Clojure 16: Složitější uživatelská makra
    http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/
  33. Clojure 17: Využití standardních maker v praxi
    http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/
  34. Clojure 18: Základní techniky optimalizace aplikací
    http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/
  35. Clojure 19: Vývojová prostředí pro Clojure
    http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/
  36. 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/
  37. Clojure 21: ClojureScript aneb překlad Clojure do JS
    http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/
  38. Leiningen: nástroj pro správu projektů napsaných v Clojure
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure/
  39. 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/
  40. 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/
  41. 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/
  42. 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/
  43. 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/
  44. Programovací jazyk Clojure a databáze (1.část)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-databaze-1-cast/
  45. Pluginy pro Leiningen
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-pluginy-pro-leiningen/
  46. 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/
  47. 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/
  48. 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/
  49. 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/
  50. Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure
    http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure/
  51. 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/
  52. 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/
  53. Programovací jazyk Clojure a práce s Gitem
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem/
  54. Programovací jazyk Clojure a práce s Gitem (2)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem-2/
  55. 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/
  56. Pixie: lehký skriptovací jazyk s „kouzelnými“ schopnostmi
    https://www.root.cz/clanky/pixie-lehky-skriptovaci-jazyk-s-kouzelnymi-schopnostmi/
  57. Programovací jazyk Pixie: funkce ze základní knihovny a použití FFI
    https://www.root.cz/clanky/pro­gramovaci-jazyk-pixie-funkce-ze-zakladni-knihovny-a-pouziti-ffi/
  58. Novinky v Clojure verze 1.9.0
    https://www.root.cz/clanky/novinky-v-clojure-verze-1–9–0/
  59. 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/
  60. 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/
  61. 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/
  62. 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

  1. Stopa (algebra)
    https://cs.wikipedia.org/wi­ki/Stopa_(algebra)
  2. Matrix calculator
    https://matrixcalc.org/en/
  3. Incanter is a Clojure-based, R-like platform for statistical computing and graphics.
    http://incanter.org/
  4. Evolution of incanter (Gource Visualization)
    https://www.youtube.com/wat­ch?v=TVfL5nPELr4
  5. Questions tagged [incanter] (na Stack Overflow)
    https://stackoverflow.com/qu­estions/tagged/incanter?sor­t=active
  6. Data Sorcery with Clojure
    https://data-sorcery.org/contents/
  7. Back to the Future: Lisp as a Base for a Statistical Computing System
    https://rd.springer.com/chap­ter/10.1007/978–3–7908–2084–3_2
  8. Incanter Cheat Sheet
    http://incanter.org/docs/incanter-cheat-sheet.pdf
  9. Back to the Future: Lisp as a Base for a Statistical Computing System (celá verze článku)
    https://www.researchgate.net/pu­blication/227019917_Back_to_the_Fu­ture_Lisp_as_a_Base_for_a_Sta­tistical_Computing_System
  10. Lisp-Stat Information
    http://homepage.cs.uiowa.e­du/~luke/xls/xlsinfo/
  11. Sample Plots in Incanter
    https://github.com/incanter/in­canter/wiki/Sample-Plots-in-Incanter#line
  12. vectorz-clj
    https://github.com/mikera/vectorz-clj
  13. vectorz – Examples
    https://github.com/mikera/vectorz-clj/wiki/Examples
  14. Array Programming
    https://en.wikipedia.org/wi­ki/Array_programming
  15. Discovering Array Languages
    http://archive.vector.org­.uk/art10008110
  16. no stinking loops – Kalothi
    http://www.nsl.com/
  17. Vector (obsahuje odkazy na články, knihy a blogy o programovacích jazycích APL, J a K)
    http://www.vector.org.uk/
  18. Colt
    http://dst.lbl.gov/ACSSoftware/colt/
  19. Parallel Colt: Open Source Libraries for High Performance Scientific and Technical Computing in Java
    http://incanter.org/docs/pa­rallelcolt/api/
  20. Processing
    https://www.processing.org/
  21. The R Project for Statistical Computing
    https://www.r-project.org/
  22. Humane test output for clojure.test
    https://github.com/pjstadig/humane-test-output
  23. iota
    https://github.com/juxt/iota
  24. 5 Differences between clojure.spec and Schema
    https://lispcast.com/clojure.spec-vs-schema/
  25. Schema: Clojure(Script) library for declarative data description and validation
    https://github.com/plumatic/schema
  26. Zip archiv s Clojure 1.9.0
    http://repo1.maven.org/ma­ven2/org/clojure/clojure/1­.9.0/clojure-1.9.0.zip
  27. Clojure 1.9 is now available
    https://clojure.org/news/2017/12/08/clo­jure19
  28. Deps and CLI Guide
    https://clojure.org/guides/dep­s_and_cli
  29. Changes to Clojure in Version 1.9
    https://github.com/clojure/clo­jure/blob/master/changes.md
  30. clojure.spec – Rationale and Overview
    https://clojure.org/about/spec
  31. Zip archiv s Clojure 1.8.0
    http://repo1.maven.org/ma­ven2/org/clojure/clojure/1­.8.0/clojure-1.8.0.zip
  32. Clojure 1.8 is now available
    http://clojure.org/news/2016/01/19/clo­jure18
  33. Socket Server REPL
    http://dev.clojure.org/dis­play/design/Socket+Server+REPL
  34. CLJ-1671: Clojure socket server
    http://dev.clojure.org/jira/browse/CLJ-1671
  35. CLJ-1449: Add clojure.string functions for portability to ClojureScript
    http://dev.clojure.org/jira/browse/CLJ-1449
  36. Launching a Socket Server
    http://clojure.org/referen­ce/repl_and_main#_launchin­g_a_socket_server
  37. API for clojure.string
    http://clojure.github.io/clo­jure/branch-master/clojure.string-api.html
  38. Clojars:
    https://clojars.org/
  39. Seznam knihoven na Clojars:
    https://clojars.org/projects
  40. Clojure Cookbook: Templating HTML with Enlive
    https://github.com/clojure-cookbook/clojure-cookbook/blob/master/07_webapps/7–11_enlive.asciidoc
  41. An Introduction to Enlive
    https://github.com/swannodette/enlive-tutorial/
  42. Enlive na GitHubu
    https://github.com/cgrand/enlive
  43. Expectations: příklady atd.
    http://jayfields.com/expectations/
  44. Expectations na GitHubu
    https://github.com/jaycfi­elds/expectations
  45. Lein-expectations na GitHubu
    https://github.com/gar3thjon3s/lein-expectations
  46. Testing Clojure With Expectations
    https://semaphoreci.com/blog/2014/09/23/tes­ting-clojure-with-expectations.html
  47. Clojure testing TDD/BDD libraries: clojure.test vs Midje vs Expectations vs Speclj
    https://www.reddit.com/r/Clo­jure/comments/1viilt/cloju­re_testing_tddbdd_librari­es_clojuretest_vs/
  48. Testing: One assertion per test
    http://blog.jayfields.com/2007/06/tes­ting-one-assertion-per-test.html
  49. Rewriting Your Test Suite in Clojure in 24 hours
    http://blog.circleci.com/rewriting-your-test-suite-in-clojure-in-24-hours/
  50. Clojure doc: zipper
    http://clojuredocs.org/clo­jure.zip/zipper
  51. Clojure doc: parse
    http://clojuredocs.org/clo­jure.xml/parse
  52. Clojure doc: xml-zip
    http://clojuredocs.org/clojure.zip/xml-zip
  53. Clojure doc: xml-seq
    http://clojuredocs.org/clo­jure.core/xml-seq
  54. Parsing XML in Clojure
    https://github.com/clojuredocs/guides
  55. Clojure Zipper Over Nested Vector
    https://vitalyper.wordpres­s.com/2010/11/23/clojure-zipper-over-nested-vector/
  56. Understanding Clojure's PersistentVector implementation
    http://blog.higher-order.net/2009/02/01/understanding-clojures-persistentvector-implementation
  57. Understanding Clojure's PersistentHashMap (deftwice…)
    http://blog.higher-order.net/2009/09/08/understanding-clojures-persistenthashmap-deftwice.html
  58. Assoc and Clojure's PersistentHashMap: part ii
    http://blog.higher-order.net/2010/08/16/assoc-and-clojures-persistenthashmap-part-ii.html
  59. Ideal Hashtrees (paper)
    http://lampwww.epfl.ch/pa­pers/idealhashtrees.pdf
  60. Clojure home page
    http://clojure.org/
  61. Clojure (downloads)
    http://clojure.org/downloads
  62. Clojure Sequences
    http://clojure.org/sequences
  63. Clojure Data Structures
    http://clojure.org/data_structures
  64. 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
  65. 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
  66. Clojure – Functional Programming for the JVM
    http://java.ociweb.com/mar­k/clojure/article.html
  67. Clojure quick reference
    http://faustus.webatu.com/clj-quick-ref.html
  68. 4Clojure
    http://www.4clojure.com/
  69. ClojureDoc (rozcestník s dokumentací jazyka Clojure)
    http://clojuredocs.org/
  70. Clojure (na Wikipedia EN)
    http://en.wikipedia.org/wiki/Clojure
  71. Clojure (na Wikipedia CS)
    http://cs.wikipedia.org/wiki/Clojure
  72. SICP (The Structure and Interpretation of Computer Programs)
    http://mitpress.mit.edu/sicp/
  73. Pure function
    http://en.wikipedia.org/wi­ki/Pure_function
  74. Funkcionální programování
    http://cs.wikipedia.org/wi­ki/Funkcionální_programová­ní
  75. Čistě funkcionální (datové struktury, jazyky, programování)
    http://cs.wikipedia.org/wi­ki/Čistě_funkcionální
  76. 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
  77. Clojure Macro Tutorial (Part II: The Compiler Strikes Back)
    http://www.learningclojure­.com/2010/09/clojure-macro-tutorial-part-ii-compiler.html
  78. Clojure Macro Tutorial (Part III: Syntax Quote)
    http://www.learningclojure­.com/2010/09/clojure-macro-tutorial-part-ii-syntax.html
  79. Tech behind Tech: Clojure Macros Simplified
    http://techbehindtech.com/2010/09/28/clo­jure-macros-simplified/
  80. Fatvat – Exploring functional programming: Clojure Macros
    http://www.fatvat.co.uk/2009/02/clo­jure-macros.html
  81. Eulerovo číslo
    http://cs.wikipedia.org/wi­ki/Eulerovo_číslo
  82. List comprehension
    http://en.wikipedia.org/wi­ki/List_comprehension
  83. List Comprehensions in Clojure
    http://asymmetrical-view.com/2008/11/18/list-comprehensions-in-clojure.html
  84. Clojure Programming Concepts: List Comprehension
    http://en.wikibooks.org/wi­ki/Clojure_Programming/Con­cepts#List_Comprehension
  85. Clojure core API: for macro
    http://clojure.github.com/clo­jure/clojure.core-api.html#clojure.core/for
  86. cirrus machina – The Clojure for macro
    http://www.cirrusmachina.com/blog/com­ment/the-clojure-for-macro/
  87. Riastradh's Lisp Style Rules
    http://mumble.net/~campbe­ll/scheme/style.txt
  88. Dynamic Languages Strike Back
    http://steve-yegge.blogspot.cz/2008/05/dynamic-languages-strike-back.html
  89. Scripting: Higher Level Programming for the 21st Century
    http://www.tcl.tk/doc/scripting.html
  90. Java Virtual Machine Support for Non-Java Languages
    http://docs.oracle.com/ja­vase/7/docs/technotes/gui­des/vm/multiple-language-support.html
  91. Třída java.lang.String
    http://docs.oracle.com/ja­vase/7/docs/api/java/lang/Strin­g.html
  92. Třída java.lang.StringBuffer
    http://docs.oracle.com/ja­vase/7/docs/api/java/lang/Strin­gBuffer.html
  93. Třída java.lang.StringBuilder
    http://docs.oracle.com/ja­vase/7/docs/api/java/lang/Strin­gBuilder.html
  94. StringBuffer versus String
    http://www.javaworld.com/ar­ticle/2076072/build-ci-sdlc/stringbuffer-versus-string.html
  95. Threading macro (dokumentace k jazyku Clojure)
    https://clojure.github.io/clo­jure/clojure.core-api.html#clojure.core/->
  96. Understanding the Clojure → macro
    http://blog.fogus.me/2009/09/04/un­derstanding-the-clojure-macro/
  97. clojure.inspector
    http://clojure.github.io/clo­jure/clojure.inspector-api.html
  98. The Clojure Toolbox
    http://www.clojure-toolbox.com/
  99. Unit Testing in Clojure
    http://nakkaya.com/2009/11/18/unit-testing-in-clojure/
  100. Testing in Clojure (Part-1: Unit testing)
    http://blog.knoldus.com/2014/03/22/tes­ting-in-clojure-part-1-unit-testing/
  101. API for clojure.test – Clojure v1.6 (stable)
    https://clojure.github.io/clo­jure/clojure.test-api.html
  102. Leiningen: úvodní stránka
    http://leiningen.org/
  103. Leiningen: Git repository
    https://github.com/techno­mancy/leiningen
  104. leiningen-win-installer
    http://leiningen-win-installer.djpowell.net/
  105. Clojure.org: Vars and the Global Environment
    http://clojure.org/Vars
  106. Clojure.org: Refs and Transactions
    http://clojure.org/Refs
  107. Clojure.org: Atoms
    http://clojure.org/Atoms
  108. Clojure.org: Agents as Asynchronous Actions
    http://clojure.org/agents
  109. Transient Data Structureshttp://clojure.or­g/transients

Autor článku

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