Hlavní navigace

Představení projektu SciLua

5. 10. 2021
Doba čtení: 28 minut

Sdílet

 Autor: Depositphotos
Dnes se začneme věnovat projektu SciLua. Ten lze s určitou dávkou zobecnění považovat za obdobu knihoven Numpy a SciPy, ovšem pro Luu. SciLua je postavena nad interpretrem LuaJIT a numerické algoritmy využívají knihovnu OpenBLAS.

Obsah

1. Představení projektu SciLua

2. Knihovny použité v projektu SciLua

3. Instalace balíčků sci a sci-lang s využitím nástroje ULua

4. Úprava prostředí pro snazší spouštění demonstračních příkladů

5. Práce s vektory a maticemi: specializované jazyky a specializované knihovny

6. Stručné představení projektu OpenBLAS

7. Knihovna sci.alg

8. Import knihovny sci.alg

9. Konstrukce jednorozměrného vektoru

10. Modifikace prvků vektoru

11. Konverze tabulky na vektor, specifikace typu prvků při převodu

12. Zpětný převod vektoru na tabulku

13. Vytvoření nulové matice m×n

14. Konstrukce matice z tabulky

15. Chyby při převodu tabulky obsahující hodnoty neočekávaného datového typu

16. Získání základních informací o matici, převod matice na řetězec

17. Obsah následujícího článku

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

19. Odkazy na relevantní články a seriály na Rootu

20. Odkazy na Internetu

1. Představení projektu SciLua

V dnešním článku o programovacím jazyku Lua se začneme věnovat zajímavému projektu nazvanému SciLua, jehož domovskou stránku naleznete na adrese https://scilua.org/. Tento projekt můžeme s určitou dávkou zobecnění považovat za (prozatím neúplnou) obdobu knihoven Numpy a SciPy určených pro programovací jazyk Python – což je velmi užitečné, zejména z toho důvodu, že práce s klasickými poli jazyka Lua není a nemůže být tak efektivní, jako v případě použití nativních knihoven (což přímo plyne z typového systému jazyka Lua).

Samotný projekt SciLua je rozdělen do několika na sobě nezávislých knihoven, přičemž implementace jednotlivých algoritmů je z menší části napsána přímo v jazyce Lua (tedy ve formě interpretovaných skriptů), z větší části se však volají funkce z nativní (optimalizované a numericky stabilní) knihovny OpenBLAS. To, společně s využitím LuaJITu (a nikoli standardního interpretu Luy), vede k rychlým a paměťově nenáročným výpočtům, a to i při porovnání s jazykem Julia, který je v oblasti lineární algebry a numerických výpočtů považován za velmi rychlý – https://scilua.org/ a https://towardsdatascience.com/r-vs-python-vs-julia-90456a2bcbab.

Dnes se seznámíme se způsobem instalace tohoto projektu a taktéž se základními datovými strukturami, nad nimiž je SciLua postavena. Bližší popis jednotlivých knihoven, z nichž se SciLua skládá, bude uveden v navazujících článcích.

2. Knihovny použité v projektu SciLua

Projekt SciLua se skládá z několika knihoven, přičemž v případě, že budeme chtít nějakou knihovnu využít při výpočtech, je nutné ji explicitně importovat funkcí require. Neexistuje tedy způsob importu všech těchto knihoven současně, což ovšem nemusí být příliš překvapující, neboť to odpovídá minimalistickému pojetí programovacího jazyka Lua i celého ekosystému postaveného okolo tohoto jazyka:

# Jméno knihovny Stručný popis
1 sci.alg konstruktory vektorů a matic, základní operace s těmito strukturami
2 sci.diff algoritmus symbolické derivace funkcí
3 sci.dist funkce pro statistické výpočty
4 sci.fmin optimalizační algoritmus: nalezení hodnot, pro které funkce nabývá minimální hodnoty
5 sci.fmax optimalizační algoritmus: nalezení hodnot, pro které funkce nabývá maximální hodnoty
6 sci.math rozšíření standardní knihovny math o několik dalších funkcí
7 sci.mcmc implementace algoritmu Markov Chain Monte Carlo (MCMC)
8 sci.prng implementace několika generátorů pseudonáhodné sekvence numerických hodnot
9 sci.qrng implementace kvazigenerátoru sekvence náhodných numerických hodnot
10 sci.quad algoritmus numerické integrace funce
11 sci.root algoritmus hledání kořene funkce
12 sci.stat další statistické funkce
Poznámka: dnes si popíšeme většinu funkcí a metod z první zmíněné knihovny – sci.alg.

3. Instalace balíčků sci a sci-lang s využitím nástroje ULua

SciLua je pro potřeby instalace rozdělena do dvou balíčků nazvaných sci a sci-lang (schválně na tomto místě píšu slovo „balíčků“, protože interně se jedná o větší množství knihoven). Pro instalaci těchto balíčků použijeme nástroj ULua, který již byl na stránkách Roota popsán minulý týden. Ihned po instalaci nástroje ULua by mělo být nainstalováno sedm balíčků vypsaných následujícím příkazem:

$ ./upkg status
 
Installed modules:
+ cURL         | cURL: Lua binding to libcurl                                         | 0.3.1-103
+ clib_libcurl | free and easy-to-use client-side URL transfer library                | 7.42.1-3
+ lcurl        | cURL: Lua binding to libcurl                                         | 0.3.1-103
+ lfs          | luafilesystem : File System Library for the Lua Programming Language | 1.6.3-203
+ luajit       | LuaJIT: Just-In-Time Compiler (JIT) for Lua                          | 2.1.head20151128
+ pkg          | ULua package manager                                                 | 1.0.beta10
+ serpent      | serpent : Lua serializer and pretty printer                          | 0.28-103

Přesvědčíme se, jaké balíčky obsahující ve svém názvu či popisu text „sci“ je dostupných, tj. připravených pro instalaci:

$ ./upkg available |grep sci
 
+ adoc_cmd_ext              | adoc_cmd_ext : A library and script to handle AsciiDoc Command language extens.. | 0.1.0-3
+ ascii85                   | lascii85 : An ASCII85 library for Lua                                            | 20120927-103
+ printable_chars           | printable_chars : Functions to get the ascii printable chars from a byte string. | 0.1-403, 0.1-203
+ sci                       | general purpose scientific computing library                                     | 1.0.beta12, 1.0.beta11, 1.0.beta10, 1.0.beta9
+ sci-lang                  | Syntax extensions to LuaJIT for scientific computing                             | 1.0.beta10

Zajímat nás bude především balíček nazvaný sci, o kterém lze získat podrobnější informace takto:

$ ./upkg available sci
 
Module information:
name        : sci
version     : 1.0.beta12
require     : clib_libopenblas~0.2.15, luajit~2.0, xsys~1.0
description : general purpose scientific computing library
homepage    : http://scilua.org
license     : MIT <http://opensource.org/licenses/MIT>

Stejným příkazem, pochopitelně s odlišným parametrem, můžeme získat podrobnější informace o balíčku nazvaném sci-lang:

$ ./upkg available sci-lang
 
Module information:
name        : sci-lang
version     : 1.0.beta10
require     : luajit~2.0, sci~1.0.beta10
description : Syntax extensions to LuaJIT for scientific computing
homepage    : https://github.com/stepelu/lua-sci-lang
license     : MIT/X11

Nyní provedeme instalaci obou balíčků, a to konkrétně příkazem:

$ ./upkg add sci
 
Installing matching module and its requirements:
+ clib_libopenblas | OpenBLAS : An optimized BLAS library         | 0.2.15
+ sci              | general purpose scientific computing library | 1.0.beta12
+ xsys             | extended Lua system                          | 1.0.2
Confirm (y/n)? y
Downloading:
+ /pkg/clib_libopenblas/0.2.15 | 100% of 50729KB
+ /pkg/sci/1.0.beta12          | 100% of 663KB
+ /pkg/xsys/1.0.2              | 100% of 5KB
Done

a:

$ ./upkg add sci-lang
 
Installing matching module and its requirements:
+ sci-lang | Syntax extensions to LuaJIT for scientific computing | 1.0.beta10
Confirm (y/n)? y
Downloading:
+ /pkg/sci-lang/1.0.beta10 | 100% of 54KB
Done

Nyní by měl být seznam nainstalovaných balíčků rozšířen, a to následujícím způsobem:

$ ./upkg status
 
Installed modules:
+ cURL             | cURL: Lua binding to libcurl                                         | 0.3.1-103
+ clib_libcurl     | free and easy-to-use client-side URL transfer library                | 7.42.1-3
+ clib_libopenblas | OpenBLAS : An optimized BLAS library                                 | 0.2.15
+ lcurl            | cURL: Lua binding to libcurl                                         | 0.3.1-103
+ lfs              | luafilesystem : File System Library for the Lua Programming Language | 1.6.3-203
+ luajit           | LuaJIT: Just-In-Time Compiler (JIT) for Lua                          | 2.1.head20151128
+ pkg              | ULua package manager                                                 | 1.0.beta10
+ sci              | general purpose scientific computing library                         | 1.0.beta12
+ sci-lang         | Syntax extensions to LuaJIT for scientific computing                 | 1.0.beta10
+ serpent          | serpent : Lua serializer and pretty printer                          | 0.28-103
+ xsys             | extended Lua system                                                  | 1.0.2
Poznámka: nástroj ULua prozatím nerozlišuje mezi architekturami a operačními systémy. To konkrétně znamená, že balíček je nainstalován pro všechny (jím) podporované architektury. V případě balíčků založených čistě pouze na skriptech naprogramovaných v jazyku Lua je to pochopitelně jedno, protože jeden skript bude v naprosté většině případů shodný pro všechny architektury. Ovšem u balíčků obsahujících nativní knihovny (což je konkrétně případ balíčku clib_libopenblas) budou nainstalovány binární knihovny pro Linux (32bit i 64bit), Windows (taktéž 32bit a 64bit) i MacOS. Pokud chcete ušetřit obsazené místo na disku, lze knihovny pro nepoužívané systémy bez problémů smazat. Zobrazit takové knihovny je snadné, například v případě DLL určených pouze pro Windows:
$ find . -name "*.dll"

Pro Linux na 64bitové architektuře x86–64 by měly stačit tyto knihovny:

$ find . -name "*.so"
 
./0_2_15/Linux/x64/libgfortran.so
./0_2_15/Linux/x64/libquadmath.so
./0_2_15/Linux/x64/libopenblas.so
./0_2_15/Linux/x64/libgcc_s.so

4. Úprava prostředí pro snazší spouštění demonstračních příkladů

Pro zjednodušení spuštění interpretu jazyka Lua popř. správce balíčků a dalších později nainstalovaných utilit si můžete modifikovat proměnnou prostředí PATH, a to následujícím způsobem:

$ export PATH=~/ulua/bin:~/ulua:$PATH

Od této chvíle je možné volat všechny důležité spustitelné soubory (zejména LuaJIT) bez uvedení cesty:

$ lua
 
LuaJIT 2.1.0-beta1 -- Copyright (C) 2005-2015 Mike Pall. http://luajit.org/
JIT: ON SSE2 SSE3 SSE4.1 fold cse dce fwd dse narrow loop abc sink fuse

$ ./scilua
LuaJIT Language Toolkit usage: luajit [options]... [script [args]...].

Available options are:
  -b ...    Save or list bytecode.
  -c ...    Generate Lua code and run.
            If followed by the "v" option the generated Lua code
            will be printed.

Taktéž je vhodné si upravit vámi používaný textový editor či integrované vývojové prostředí takovým způsobem, aby se dal demonstrační příklad spustit vhodnou klávesovou zkratkou. Příklad konfigurace textového editoru Vim:

" Settings for Lua files
"*********************************************************************
augroup __lua__
  au!
  au BufRead,BufNewFile *.lua noremap <F5> :!./lua %<CR>
  au BufRead,BufNewFile *.lua noremap <F6> :!./lua -i %<CR>
augroup END
Poznámka: klávesovou zkratkou F5 se skript spustí v rámci interpretru LuaJITu. Klávesová zkratka F6 taktéž skript spustí, ovšem navíc po jeho dokončení zůstane interpret aktivní, takže lze například dále zkoumat vytvořené vektory či matice.

5. Práce s vektory a maticemi: specializované jazyky a specializované knihovny

Jednou poměrně rozsáhlou (a současně i nejvíce prozkoumanou) oblastí v informatice je zpracování vektorů, matic i tenzorů, protože s těmito strukturami se můžeme setkat v různých disciplínách, například ve finančnictví, pojišťovnictví, statistice, zpracování numerických dat, simulacích, strojovém učení atd. Současně se jedná i o velmi zajímavou oblast, neboť právě kvůli co nejrychlejší práci s velkými (skutečně velkými) maticemi byly vytvořeny speciální výpočetní bloky v některých superpočítačích (příkladem mohou být superpočítače Cray). Současné knihovny dokážou v případě potřeby využít jak některá rozšíření instrukčních sad (SIMD instrukce typu SSEx, původně též MMX či 3DNow!), tak i programovatelné grafické akcelerátory (GPU).

Práce s vektory a maticemi byla (a samozřejmě doposud je) podporována v překladačích FORTRANu, které začaly být po vzniku superpočítačů vybaveny algoritmy, které dokázaly převést některé typy programových smyček na „vektorové operace“. Paralelně vznikly i specializované jazyky určené téměř výhradně pro práci s vektory i maticemi – typickým příkladem z této oblasti jsou jazyky APL a J (oba se stále používají).

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

Do této skupiny patří i nástroj SciLua, který bude popsán v dalším textu i v navazujících článcích. Pochopitelně jsou kromě základní práce s vektory a maticemi podporovány i další operace z oblasti lineární algebry, statistiky atd.

6. Stručné představení projektu OpenBLAS

Projekt OpenBLAS nabízí uživatelům různých programovacích jazyků (C, Julia, Lua, Python atd.) i programátorům knihovnu založenou na GotoBLAS2. Samotná zkratka BLAS přitom znamená Basic Linear Algebra Subprograms; jedná se tedy o různé knihovní funkce z oblasti lineární algebry, které se mj. týkají operací s vektory a maticemi (viz též poměrně podrobnou dokumentaci dostupnou na adrese https://www.netlib.org/blas/). Kromě toho v projektu OpenBLAS najdeme i celou referenční implementaci slavné knihovny LAPACK neboli Linear Algebra Package (ta původně vznikla pro FORTRAN 77, později byla přepsána pro FORTRAN 90). V projektu OpenBLAS je kromě korektnosti algoritmů a jejich numerické stability kladen důraz i na velkou výpočetní rychlost a proto jsou jednotlivé algoritmy optimalizovány na konkrétní hardware.

Podrobnější informace o tomto zajímavém projektu, který tvoří nedílnou součást projektu SciLua, lze získat na adrese https://github.com/xianyi/O­penBLAS/wiki.

7. Knihovna sci.alg

První knihovnou z projektu SciLua, kterou se budeme zabývat, je knihovna nazvaná sci.alg. V této knihovně nalezneme především konstruktory vektorů a matic, dále funkce určené pro konverzní operace mezi tabulkami a vektory/maticemi (i opačně) a v neposlední řadě taktéž některé základní operace s těmito datovými strukturami. Přitom platí, že interní struktura vektorů a matic je vytvořena takovým způsobem, aby byla plně kompatibilní s nativní knihovnou OpenBLAS zmíněnou v předchozí kapitole (a to včetně podpory takových datových typů, které programovací jazyk Lua přímo nepodporuje – například se to týká bajtů, 16bitových celých čísel atd.).

8. Import knihovny sci.alg

V programovacím jazyku Lua se knihovny importují funkcí nazvanou require, viz například oficiální dokumentaci k této funkci dostupnou na adrese http://www.lua.org/manual/5­.4/manual.html#pdf-require. Teoreticky by tedy měl import knihovny sci.alg proběhnout následujícím způsobem:

--
-- Seriál Programovací jazyk Lua
-- https://www.root.cz/serialy/programovaci-jazyk-lua/
--
-- Úvodní článek o knihovně SciLua
--
-- Demonstrační příklad číslo 1:
-- Načtení knihovny "sci.alg" bez přiřazení výsledku do proměnné
--
 
require "sci.alg"
 
-- finito

Ve skutečnosti ovšem knihovna sci-alg, na rozdíl od některých dalších knihoven, nepřidává do globálního jmenného prostoru (resp. přesněji řečeno do prostředí – environment) žádné další symboly a tedy ani žádné nové funkce. O tom se ostatně můžeme velmi snadno přesvědčit výpisem všech globálních symbolů před importem knihovny sci.alg a ihned po importu této knihovny:

--
-- Seriál Programovací jazyk Lua
-- https://www.root.cz/serialy/programovaci-jazyk-lua/
--
-- Úvodní článek o knihovně SciLua
--
-- Demonstrační příklad číslo 2:
-- Výpis globálních symbolů před i po načtení knihovny "sci.alg"
--
 
print "\nBefore 'require'\n"
 
for k, v in pairs(_G) do
    print(k, v)
end
 
require "sci.alg"
 
print "\nAfter 'require'\n"
 
for k, v in pairs(_G) do
    print(k, v)
end
 
-- finito

S tímto výsledkem:

Before 'require'
 
coroutine         table: 0x40809758
assert            function: builtin#2
tostring          function: builtin#18
tonumber          function: builtin#17
io                table: 0x4080ac98
rawget            function: builtin#12
xpcall            function: builtin#21
arg               table: 0x41779508
ipairs            function: builtin#7
print             function: builtin#29
pcall             function: builtin#20
gcinfo            function: builtin#26
module            function: 0x40809e88
setfenv           function: builtin#11
pairs             function: builtin#5
jit               table: 0x4080d618
bit               table: 0x4080d050
package           table: 0x40809af0
error             function: builtin#19
debug             table: 0x4080ca38
loadfile          function: builtin#22
rawequal          function: builtin#14
loadstring        function: builtin#24
rawset            function: builtin#13
unpack            function: builtin#15
table             table: 0x4080a238
require           function: 0x40822580
_VERSION          Lua 5.1
newproxy          function: builtin#28
collectgarbage    function: builtin#27
dofile            function: builtin#25
next              function: builtin#4
math              table: 0x4080bdb8
load              function: builtin#23
os                table: 0x4080b1d8
_G                table: 0x408079a0
select            function: builtin#16
string            table: 0x4080b6b8
type              function: builtin#3
getmetatable      function: builtin#8
getfenv           function: builtin#10
setmetatable      function: builtin#9
 
After 'require'
 
coroutine         table: 0x40809758
assert            function: builtin#2
tostring          function: builtin#18
tonumber          function: builtin#17
io                table: 0x4080ac98
rawget            function: builtin#12
xpcall            function: builtin#21
arg               table: 0x41779508
ipairs            function: builtin#7
print             function: builtin#29
pcall             function: builtin#20
gcinfo            function: builtin#26
module            function: 0x40809e88
setfenv           function: builtin#11
pairs             function: builtin#5
jit               table: 0x4080d618
bit               table: 0x4080d050
package           table: 0x40809af0
error             function: builtin#19
debug             table: 0x4080ca38
loadfile          function: builtin#22
rawequal          function: builtin#14
loadstring        function: builtin#24
rawset            function: builtin#13
unpack            function: builtin#15
table             table: 0x4080a238
require           function: 0x40822580
_VERSION          Lua 5.1
newproxy          function: builtin#28
collectgarbage    function: builtin#27
dofile            function: builtin#25
next              function: builtin#4
math              table: 0x4080bdb8
load              function: builtin#23
os                table: 0x4080b1d8
_G                table: 0x408079a0
select            function: builtin#16
string            table: 0x4080b6b8
type              function: builtin#3
getmetatable      function: builtin#8
getfenv           function: builtin#10
setmetatable      function: builtin#9
Poznámka: snadno lze zjistit, že obě vypsané tabulky s globálními symboly jsou naprosto totožné. Ve skutečnosti je však možné, aby require sci.alg změnilo definici některých funkcí – to již tak snadno nelze zjistit.

Jak se tedy má provést korektní import knihovny sci.alg? Musíme „zachytit“ výsledek volání funkce require a použít symboly, které jsou ve vrácené tabulce obsaženy. Tyto symboly typicky představují volatelné funkce. Opět si to vyzkoušejme na jednoduchém skriptu:

--
-- Seriál Programovací jazyk Lua
-- https://www.root.cz/serialy/programovaci-jazyk-lua/
--
-- Úvodní článek o knihovně SciLua
--
-- Demonstrační příklad číslo 3:
-- Načtení knihovny "sci.alg", uložení a zobrazení vrácené hodnoty
--
 
alg = require "sci.alg"
 
print "Imported symbols\n"
 
for k, n in pairs(alg) do
    print(k,n)
end
 
-- finito

Po spuštění tohoto skriptu se nyní vypíše celkem třináct importovaných symbolů:

Imported symbols
 
pow     function: 0x40726450
vec     function: 0x40696720
arrayct ctype<struct 1520>
prod    function: 0x407264d8
typeof  function: 0x404397f0
mat     function: 0x40696768
tovec   function: 0x40696790
__      table: 0x4073c560
trace   function: 0x407264f8
sum     function: 0x407264b8
tomat   function: 0x406967d8
join    function: 0x41674fa0
mul     function: 0x407313e8
Poznámka: je pochopitelně možné si tyto symboly (resp. funkce) zpřístupnit na globální úrovni přiřazením do tabulky _G, ovšem to může později vést ke konfliktu jmen (ovšem již samotná existence této možnosti napovídá, jak mocný je ve skutečnosti runtime systém programovacího jazyka Lua).

9. Konstrukce jednorozměrného vektoru

Pro konstrukci jednorozměrného vektoru slouží funkce nazvaná vec. Této funkci je nutné předat počet prvků, které má vektor obsahovat. Vytvořený vektor bude v takovém případě obsahovat zadaný počet nulových prvků. Vektor, resp. přesněji řečeno obsah prvků vektoru, lze vypsat standardní funkcí print:

--
-- Seriál Programovací jazyk Lua
-- https://www.root.cz/serialy/programovaci-jazyk-lua/
--
-- Úvodní článek o knihovně SciLua
--
-- Demonstrační příklad číslo 4:
-- Vytvoření (jednorozměrného) vektoru
--
 
alg = require "sci.alg"
 
-- alokace vektoru
vec = alg.vec(10)
 
print "Vector value\n"
print(vec)
 
-- finito

Po spuštění tohoto příkladu by se mělo vypsat deset nulových prvků:

Vector value
 
+0.000000
+0.000000
+0.000000
+0.000000
+0.000000
+0.000000
+0.000000
+0.000000
+0.000000
+0.000000
Poznámka: v tomto případě mají všechny prvky vektoru typ double, ovšem ve skutečnosti mohou být i jiného typu podporovaného přes FFI (rozhraní pro volání funkcí z nativních knihoven).

10. Modifikace prvků vektoru

Pro přístup k prvkům vektoru – a to jak pro čtení, tak i pro zápis – se používají běžné „indexové“ závorky, stejně jako při přístupu k prvkům tabulek (což je v programovacím jazyce Lua jediný strukturovaný datový typ). Musíme však mít stále na paměti, že index prvního prvku vektoru je skutečně roven jedničce. To se sice může zdát poněkud neobvyklé, ovšem ve skutečnosti mnoho jazyků (dovolím si říci, že většina jazyků NEodvozených od céčka) zvolilo stejný přístup: Fortran, Mathematica, R, MATLAB, Julia:

--
-- Seriál Programovací jazyk Lua
-- https://www.root.cz/serialy/programovaci-jazyk-lua/
--
-- Úvodní článek o knihovně SciLua
--
-- Demonstrační příklad číslo 5:
-- Vytvoření (jednorozměrného) vektoru, inicializace prvků
--
 
alg = require "sci.alg"
 
-- alokace vektoru
vec = alg.vec(10)
 
-- naplnění prvků vektoru
for i = 1, 10 do
    vec[i] = 1/i
end
 
print "Vector value\n"
print(vec)
 
-- finito

Výsledkem po spuštění tohoto skriptu by tedy měly být hodnoty deseti prvků vektoru, které již ovšem nejsou nulové:

Vector value
 
+1.000000
+0.500000
+0.333333
+0.250000
+0.200000
+0.166667
+0.142857
+0.125000
+0.111111
+0.100000
Poznámka: některé knihovny a jazyky volí odlišnou strategii – vektory a matice jsou neměnitelné neboli immutable. To však není případ nástroje SciLua.

11. Konverze tabulky na vektor, specifikace typu prvků při převodu

Vektor lze snadno zkonstruovat i konverzí tabulky, tj. základního datového typu programovacího jazyka Lua. V následujícím demonstračním příkladu je nejprve vytvořena tabulka s pěti prvky, která je následně převedena na vektor funkcí tovec:

--
-- Seriál Programovací jazyk Lua
-- https://www.root.cz/serialy/programovaci-jazyk-lua/
--
-- Úvodní článek o knihovně SciLua
--
-- Demonstrační příklad číslo 6:
-- Vytvoření (jednorozměrného) vektoru z tabulky
--
 
alg = require "sci.alg"
 
t = {1, 2, 3, 4, 5}
 
-- vytvoření jednorozměrného vektoru z tabulky
vec = alg.tovec(t)
 
print "Vector value\n"
print(vec)
 
-- finito

S výsledkem:

Vector value
 
+1.000000
+2.000000
+3.000000
+4.000000
+5.000000

Při převodu ovšem můžeme specifikovat datový typ prvků vektoru, což je někdy žádoucí, například při zpracování zvukových dat či obrázků (tedy rastrových dat). K tomuto účelu se používá funkce typeof, které se předá jméno datového typu (podle FFI):

--
-- Seriál Programovací jazyk Lua
-- https://www.root.cz/serialy/programovaci-jazyk-lua/
--
-- Úvodní článek o knihovně SciLua
--
-- Demonstrační příklad číslo 7:
-- Specifikace typů prvků vektoru: 8bitová celá čísla
--
 
alg = require "sci.alg"
 
t = {0, 1, 2, 3, 4, 100, 127, 128, 129, 255}
 
-- konstruktor vektoru daného typu
int8vec = alg.typeof("int8_t").tovec
 
-- vytvoření jednorozměrného vektoru z tabulky
vec = int8vec(t)
 
print "Vector value\n"
print(vec)
 
-- finito

V předchozím příkladu jsme si vynutili použití datového typu int8_t, což vede k přetečení při konverzi některých hodnot:

Vector value
 
+0.000000
+1.000000
+2.000000
+3.000000
+4.000000
+100.0000
+127.0000
-128.0000
-127.0000
-1.000000

Abychom zabránili přetečení při konverzi, můžeme zvolit 16bitová celá čísla (často používáno například u vstupních audio dat):

--
-- Seriál Programovací jazyk Lua
-- https://www.root.cz/serialy/programovaci-jazyk-lua/
--
-- Úvodní článek o knihovně SciLua
--
-- Demonstrační příklad číslo 8:
-- Specifikace typů prvků vektoru: 16bitová celá čísla
--
 
alg = require "sci.alg"
 
t = {0, 1, 2, 3, 4, 100, 127, 128, 129, 255}
 
-- konstruktor vektoru daného typu
int16vec = alg.typeof("int16_t").tovec
 
-- vytvoření jednorozměrného vektoru z tabulky
vec = int16vec(t)
 
print "Vector value\n"
print(vec)
 
-- finito

Nyní bude výsledek odlišný:

Vector value
 
+0.000000
+1.000000
+2.000000
+3.000000
+4.000000
+100.0000
+127.0000
+128.0000
+129.0000
+255.0000

Podporován je i pravdivostní typ bool, čehož se využívá při konstrukci vektorů tvořících nějakou masku:

--
-- Seriál Programovací jazyk Lua
-- https://www.root.cz/serialy/programovaci-jazyk-lua/
--
-- Úvodní článek o knihovně SciLua
--
-- Demonstrační příklad číslo 9:
-- Specifikace typů prvků vektoru: pravdivostní hodnoty
--
 
alg = require "sci.alg"
 
t = {0, 1, 2, 3, 4, 100, 127, 128, 129, 255}
 
-- konstruktor vektoru daného typu
boolvec = alg.typeof("bool").tovec
 
-- vytvoření jednorozměrného vektoru z tabulky
vec = boolvec(t)
 
print "Vector value\n"
print(vec)
 
-- finito

Nyní bude výsledek vypadat odlišně – nulová hodnota je převedena na false, ostatní hodnoty na true:

Vector value
 
    false
     true
     true
     true
     true
     true
     true
     true
     true
     true

12. Zpětný převod vektoru na tabulku

Vektor – ať již vytvořený jakýmkoli způsobem – je možné převést zpět na tabulku, a to konkrétně metodou nazvanou totable (nejedná se tedy o funkci – pozor na odlišnou syntaxi volání):

--
-- Seriál Programovací jazyk Lua
-- https://www.root.cz/serialy/programovaci-jazyk-lua/
--
-- Úvodní článek o knihovně SciLua
--
-- Demonstrační příklad číslo 10:
-- Převod vektoru zpět na tabulku
--
 
alg = require "sci.alg"
 
t = {0, 1, 2, 3, 4, 100, 127, 128, 129, 255}
 
-- vytvoření jednorozměrného vektoru z tabulky
vec = alg.tovec(t)
 
print "Vector value\n"
print(vec)
 
-- převod vektoru zpět na tabulku
t2 = vec:totable()
 
print "Table conent\n"
for k, v in pairs(t2) do
    print(k, v)
end
 
-- finito

Povšimněte si, že výsledná tabulka obsahuje jako své prvky další tabulky:

Vector value
 
+0.000000
+1.000000
+2.000000
+3.000000
+4.000000
+100.0000
+127.0000
+128.0000
+129.0000
+255.0000
 
Table conent
 
1       table: 0x40518418
2       table: 0x405184e0
3       table: 0x40518588
4       table: 0x40518640
5       table: 0x405186e8
6       table: 0x405187c0
7       table: 0x40518868
8       table: 0x40518910
9       table: 0x405189b8
10      table: 0x40518ab0

Aby se zobrazily skutečné hodnoty prvků vektoru převedeného na tabulku (obsahující další tabulky), je nutné zdrojový kód demonstračního příkladu nepatrným způsobem upravit – viz zvýrazněný řádek:

--
-- Seriál Programovací jazyk Lua
-- https://www.root.cz/serialy/programovaci-jazyk-lua/
--
-- Úvodní článek o knihovně SciLua
--
-- Demonstrační příklad číslo 11:
-- Převod vektoru zpět na tabulku, tisk prvního prvku každé podtabulky
--
 
alg = require "sci.alg"
 
t = {0, 1, 2, 3, 4, 100, 127, 128, 129, 255}
 
-- vytvoření jednorozměrného vektoru z tabulky
vec = alg.tovec(t)
 
print "Vector value\n"
print(vec)
 
-- převod vektoru zpět na tabulku
t2 = vec:totable()
 
print "Table conent\n"
for k, v in pairs(t2) do
    print(k, v[1])
end
 
-- finito

Výsledek bude nyní odpovídat očekávání:

Vector value
 
+0.000000
+1.000000
+2.000000
+3.000000
+4.000000
+100.0000
+127.0000
+128.0000
+129.0000
+255.0000
 
Table conent
 
1       0
2       1
3       2
4       3
5       4
6       100
7       127
8       128
9       129
10      255

13. Vytvoření nulové matice m×n

Kromě jednorozměrných vektorů lze v nástroji SciLua pracovat i s maticemi. Ty se zkonstruují funkcí mat, které se předá počet řádků a počet sloupců matice (v tomto pořadí):

--
-- Seriál Programovací jazyk Lua
-- https://www.root.cz/serialy/programovaci-jazyk-lua/
--
-- Úvodní článek o knihovně SciLua
--
-- Demonstrační příklad číslo 12:
-- Vytvoření matice 3x4 prvků
--
 
alg = require "sci.alg"
 
-- alokace matice: 3 řádky, 4 sloupce
mat = alg.mat(3, 4)
 
print "Matrix value\n"
print(mat)
 
-- finito

Výsledná matice bude mít rozměry 3×4 a všechny prvky nulové:

Matrix value
 
+0.000000,+0.000000,+0.000000,+0.000000
+0.000000,+0.000000,+0.000000,+0.000000
+0.000000,+0.000000,+0.000000,+0.000000

Celkový počet prvků matice se získá standardním operátorem #. Vytvořit lze i matici s nulovým počtem řádků:

--
-- Seriál Programovací jazyk Lua
-- https://www.root.cz/serialy/programovaci-jazyk-lua/
--
-- Úvodní článek o knihovně SciLua
--
-- Demonstrační příklad číslo 13:
-- Vytvoření matice 0x4 prvků
--
 
alg = require "sci.alg"
 
-- alokace matice: žádné řádky, (teoreticky) 4 sloupce
mat = alg.mat(0, 4)
 
-- počet prvků
print(#mat)
 
print "Matrix value\n"
print(mat)
 
-- finito

Výsledek:

0
Matrix value

Pracovat lze i s maticemi, které mají nulový počet sloupců (ovšem několik řádků):

--
-- Seriál Programovací jazyk Lua
-- https://www.root.cz/serialy/programovaci-jazyk-lua/
--
-- Úvodní článek o knihovně SciLua
--
-- Demonstrační příklad číslo 14:
-- Vytvoření matice 3x0 prvků
--
 
alg = require "sci.alg"
 
-- alokace matice: tři řádky, (teoreticky) žádné sloupce
mat = alg.mat(3, 0)
 
-- počet prvků
print(#mat)
 
print "Matrix value\n"
print(mat)
 
-- finito

Výsledek:

0
Matrix value
 
 
 
Poznámka: skript korektně vytiskl prázdné řádky.

14. Konstrukce matice z tabulky

Víme již, že s využitím funkce nazvané tovec je možné převést tabulku (tedy základní datový typ programovacího jazyka Lua) na vektor. Podobně existuje i funkce pojmenovaná tomat (ne tomato!) určená pro převod tabulky do matice. Rozměry matice jsou odvozeny od počtu prvků tabulky a taktéž počtu prvků v jednotlivých podtabulkách. Praktické použití je snadné (povšimněte si konstruktoru tabulky):

--
-- Seriál Programovací jazyk Lua
-- https://www.root.cz/serialy/programovaci-jazyk-lua/
--
-- Úvodní článek o knihovně SciLua
--
-- Demonstrační příklad číslo 15:
-- Vytvoření matice z tabulky
--
 
alg = require "sci.alg"
 
-- běžná tabulka jazyka Lua
tbl = {{1,  2,  3,  4},
       {5,  6,  7,  8},
       {9, 10, 11, 12}}
 
-- konverze tabulky na matici
mat = alg.tomat(tbl)
 
-- počet prvků
print(#mat)
 
print "Matrix value\n"
print(mat)
 
-- finito

Výsledkem konverze bude matice s dvanácti prvky, třemi řádky a čtyřmi sloupci:

12
Matrix value
 
+1.000000,+2.000000,+3.000000,+4.000000
+5.000000,+6.000000,+7.000000,+8.000000
+9.000000,+10.00000,+11.00000,+12.00000

15. Chyby při převodu tabulky obsahující hodnoty neočekávaného datového typu

Tabulka je, na rozdíl od vektoru či matice, heterogenní datová struktura, což znamená, že její prvky mohou být libovolného typu. Tato flexibilita je často využívána (tabulky totiž v jazyku Lua slouží i jako náhrada za struktury/záznamy, protože podporují tečkovou notaci), ovšem pokus o převod takové tabulky na vektor nebo matici skončí běhovou chybou, což si ostatně můžeme velmi snadno vyzkoušet:

--
-- Seriál Programovací jazyk Lua
-- https://www.root.cz/serialy/programovaci-jazyk-lua/
--
-- Úvodní článek o knihovně SciLua
--
-- Demonstrační příklad číslo 16:
-- Pokus o vytvoření matice z tabulky, která obsahuje prvek typu řetězec
--
 
alg = require "sci.alg"
 
-- běžná tabulka jazyka Lua
tbl = {{1,  2,  3,  4},
       {5,  6,  7,  8},
       {9, 10, 11, "foobar"}}
 
-- konverze tabulky na matici
mat = alg.tomat(tbl)
 
-- počet prvků
print(#mat)
 
print "Matrix value\n"
print(mat)
 
-- finito

Hodnota „foobar“ zajisté není numerická hodnota a z tohoto důvodu dojde při pokusu o konverzi na matici k běhové chybě:

/home/ptisnovs/ulua/luajit/2_1_head20151128/Linux/x64/luajit: /home/ptisnovs/ulua/sci/1_0_beta12/alg.lua:632: cannot convert 'string' to 'double'
stack traceback:
        /home/ptisnovs/ulua/sci/1_0_beta12/alg.lua:632: in function '__newindex'
        /home/ptisnovs/ulua/sci/1_0_beta12/alg.lua:763: in function 'tomat'
        16_matrix_from_table.lua:19: in main chunk
        [C]: at 0x004057d0

16. Získání základních informací o matici, převod matice na řetězec

O matici (ale i o vektoru) můžeme získat základní informace s využitím standardního operátoru # a taktéž metod (nikoli funkcí!) pojmenovaných nrow a ncol:

# Výraz Stručný popis
1 #mat vrátí celkový počet prvků matice nebo vektoru
2 mat:nrow() vrátí počet řádků matice
3 mat:ncol() vrátí počet sloupců matice

Jen ve stručnosti si nyní ukažme použití těchto tří výrazů pro zkonstruovanou matici:

--
-- Seriál Programovací jazyk Lua
-- https://www.root.cz/serialy/programovaci-jazyk-lua/
--
-- Úvodní článek o knihovně SciLua
--
-- Demonstrační příklad číslo 17:
-- Získání základních informací o matici
--
 
alg = require "sci.alg"
 
-- běžná tabulka jazyka Lua
tbl = {{1,  2,  3,  4},
       {5,  6,  7,  8},
       {9, 10, 11, 12}}
 
-- konverze tabulky na matici
mat = alg.tomat(tbl)
 
-- počet prvků, sloupců a řádků
print("Items:", #mat)
print("Rows: ", mat:nrow())
print("Cols: ", mat:ncol())
 
-- finito

Výsledek získaný po spuštění tohoto skriptu nebude nijak překvapující:

Items:  12
Rows:   3
Cols:   4

Vektory i matice lze převést na řetězec funkcí tostring. Demonstrační příklad s převodem vektoru jsme si již ukázali, takže nám zbývá se podívat na způsob převodu matice na řetězec. Je to snadné:

--
-- Seriál Programovací jazyk Lua
-- https://www.root.cz/serialy/programovaci-jazyk-lua/
--
-- Úvodní článek o knihovně SciLua
--
-- Demonstrační příklad číslo 18:
-- Konverze matice na řetězec
--
 
alg = require "sci.alg"
 
-- běžná tabulka jazyka Lua
tbl = {{1,  2,  3,  4},
       {5,  6,  7,  8},
       {9, 10, 11, 12}}
 
-- konverze tabulky na matici
mat = alg.tomat(tbl)
 
-- konverze na řetězec
s = tostring(mat)
print "Matrix as string\n"
print(s)
 
-- finito

Tento skript po svém spuštění vypíše dva řetězce – zprávu a obsah matice převedený na řetězec:

Matrix as string
 
+1.000000,+2.000000,+3.000000,+4.000000
+5.000000,+6.000000,+7.000000,+8.000000
+9.000000,+10.00000,+11.00000,+12.00000

17. Obsah následujícího článku

Nyní již umíme zkonstruovat vektory i matice, takže si v navazujícím článku ukážeme, jaké operace je možné s těmito velmi důležitými datovými strukturami provádět. Zabývat se v tomto kontextu budeme i knihovnou sci-lang, která rozšiřuje syntaxi (a tím pádem i sémantiku) programovacího jazyka Lua – zavádí totiž do jazyka nové operandy (resp. přetěžuje význam těch existujících) určené právě pro zpracování vektorů a matic.

Linux tip

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

Všechny dnes popsané demonstrační příklady určené pro kombinaci interpretru LuaJIT a projekt SciLua byly uloženy do Git repositáře, který je dostupný na adrese https://github.com/tisnik/scientific-lua. Příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý (dnes prozatím malý) repositář:

# Příklad Stručný popis příkladu Adresa (zdrojový kód)
1 01_bare_require.lua chování příkazu require „sci.alg“ https://github.com/tisnik/scientific-lua/blob/master/article01/01_ba­re_require.lua
2 02_environment.lua výpis globálních symbolů před a po použití příkazu require „sci.alg“ https://github.com/tisnik/scientific-lua/blob/master/article01/02_en­vironment.lua
3 03_require_return_value.lua funkce a další objekty vrácené příkazem require „sci.alg“ https://github.com/tisnik/scientific-lua/blob/master/article01/03_re­quire_return_value.lua
4 04_vector_of_zeros.lua konstrukce vektoru se specifikovaným počtem prvků (prvky jsou nulové) https://github.com/tisnik/scientific-lua/blob/master/article01/04_vec­tor_of_zeros.lua
5 05_vector_values.lua modifikace prvků vektoru standardním „index“ operátorem https://github.com/tisnik/scientific-lua/blob/master/article01/05_vec­tor_values.lua
6 06_vector_from_table.lua konstrukce vektoru z tabulky (konverze) https://github.com/tisnik/scientific-lua/blob/master/article01/06_vec­tor_from_table.lua
7 07_vector_type_int8.lua specifikace typu prvků vektoru a prováděné konverze datového typu int8 https://github.com/tisnik/scientific-lua/blob/master/article01/07_vec­tor_type_int8.lua
8 08_vector_type_int16.lua specifikace typu prvků vektoru a prováděné konverze datového typu int16 https://github.com/tisnik/scientific-lua/blob/master/article01/08_vec­tor_type_int16.lua
9 09_vector_type_bool.lua specifikace typu prvků vektoru a prováděné konverze datového typu bool https://github.com/tisnik/scientific-lua/blob/master/article01/09_vec­tor_type_bool.lua
10 10_vector_to_table.lua konverze prvků vektoru do tabulky https://github.com/tisnik/scientific-lua/blob/master/article01/10_vec­tor_to_table.lua
11 11_print_first_items_of_subtables.lua výpis prvních prvků z podtabulek po konverzi https://github.com/tisnik/scientific-lua/blob/master/article01/11_prin­t_first_items_of_subtables­.lua
12 12_matrix_of_zeros_3×4.lua konstrukce matice 3×4 prvky https://github.com/tisnik/scientific-lua/blob/master/article01/12_ma­trix_of_zeros_3×4.lua
13 13_matrix_of_zeros_0×4.lua konstrukce matice 0×4 prvky https://github.com/tisnik/scientific-lua/blob/master/article01/13_ma­trix_of_zeros_0×4.lua
14 14_matrix_of_zeros_3×0.lua konstrukce matice 3×0 prvky https://github.com/tisnik/scientific-lua/blob/master/article01/14_ma­trix_of_zeros_3×0.lua
15 15_matrix_from_table.lua konstrukce matice z tabulky https://github.com/tisnik/scientific-lua/blob/master/article01/15_ma­trix_from_table.lua
16 16_matrix_from_table.lua konstrukce matice z tabulky pokud prvky mají nevhodný typ https://github.com/tisnik/scientific-lua/blob/master/article01/16_ma­trix_from_table.lua
17 17_matrix_size.lua vytištění velikosti matice, počtu prvků matice atd. https://github.com/tisnik/scientific-lua/blob/master/article01/17_ma­trix_size.lua
18 18_matrix_tostring.lua převod matice na řetězec https://github.com/tisnik/scientific-lua/blob/master/article01/18_ma­trix_tostring.lua

19. Odkazy na relevantní články a seriály na Rootu

S technologiemi souvisejícími s programovacím jazykem Lua, LuaJITem, ale i s jazyky a knihovnami určenými pro práci s vektory, maticemi, lineární algebrou atd. jsme se již na stránkách Roota několikrát setkali. Následují odkazy na více či méně relevantní články k dnes probíranému tématu:

  1. Seriál Programovací jazyk Lua
    https://www.root.cz/seria­ly/programovaci-jazyk-lua/
  2. Seriál Torch: framework pro strojové učení
    https://www.root.cz/serialy/torch-framework-pro-strojove-uceni/
  3. Seriál Programovací jazyk Julia
    https://www.root.cz/seria­ly/programovaci-jazyk-julia/
  4. Seriál Programovací jazyk R
    https://www.root.cz/seria­ly/programovaci-jazyk-r/
  5. Skriptovací jazyk Lua v aplikacích naprogramovaných v Go
    https://www.root.cz/clanky/skriptovaci-jazyk-lua-v-aplikacich-naprogramovanych-v-go/
  6. LuaJIT – Just in Time překladač pro programovací jazyk Lua
    https://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua/
  7. Jupyter Notebook – nástroj pro programátory, výzkumníky i lektory
    https://www.root.cz/clanky/jupyter-notebook-nastroj-pro-programatory-vyzkumniky-i-lektory/
  8. Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
    https://www.root.cz/clanky/pro­gramovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi/
  9. Programování mainframů: jazyk APL
    https://www.root.cz/clanky/pro­gramovani-mainframu-jazyk-apl/
  10. Programovací jazyk APL: programování bez smyček
    https://www.root.cz/clanky/pro­gramovaci-jazyk-apl-programovani-bez-smycek/
  11. Programovací jazyk APL – dokončení
    https://www.root.cz/clanky/pro­gramovaci-jazyk-apl-dokonceni/
  12. 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/
  13. Incanter: operace s maticemi
    https://www.root.cz/clanky/incanter-operace-s-maticemi/
  14. Tvorba jednoduchých grafů v systému Incanter
    https://www.root.cz/clanky/tvorba-jednoduchych-grafu-v-systemu-incanter/
  15. Tvorba grafů v systému Incanter (pokračování)
    https://www.root.cz/clanky/tvorba-grafu-v-systemu-incanter-pokracovani/
  16. Gophernotes: kombinace interaktivního prostředí Jupyteru s jazykem Go
    https://www.root.cz/clanky/gophernotes-kombinace-interaktivniho-prostredi-jupyteru-s-jazykem-go/
  17. Popis vybraných balíčků nabízených projektem Gonum
    https://www.root.cz/clanky/popis-vybranych-balicku-nabizenych-projektem-gonum/

20. Odkazy na Internetu

  1. SciLua: Scientific Computing with LuaJIT
    https://scilua.org/
  2. Knihovna lua-sci na GitHubu
    https://github.com/stepelu/lua-sci
  3. Nástroj lua-sci-lang na GitHubu
    https://github.com/stepelu/lua-sci-lang
  4. ULua: Universal Lua Distribution
    https://ulua.io/index.html
  5. LuaRocks
    https://luarocks.org/
  6. Awesome Lua – A curated list of quality Lua packages and resources.
    https://github.com/LewisJEllis/awesome-lua
  7. LuaJIT
    https://luajit.org/
  8. Running LuaJIT
    https://luajit.org/running.html
  9. LuaJIT na GitHubu
    https://github.com/luajit
  10. Lua Implementations
    http://lua-users.org/wiki/LuaImplementations
  11. Archived | Embed Lua for scriptable apps
    https://developer.ibm.com/tutorials/l-embed-lua/
  12. Embedding Lua
    https://www.oreilly.com/li­brary/view/lua-quick-start/9781789343229/3a6f3daf-f74c-4a25-a125–584da58568e4.xhtml
  13. The R Project for Statistical Computing
    https://www.r-project.org/
  14. An Introduction to R
    https://cran.r-project.org/doc/manuals/r-release/R-intro.pdf
  15. R (programming language)
    https://en.wikipedia.org/wi­ki/R_(programming_language)
  16. The R Programming Language
    https://www.tiobe.com/tiobe-index/r/
  17. Julia (front page)
    http://julialang.org/
  18. Julia – repositář na GitHubu
    https://github.com/JuliaLang/julia
  19. Julia (programming language)
    https://en.wikipedia.org/wi­ki/Julia_%28programming_lan­guage%29
  20. IJulia
    https://github.com/JuliaLan­g/IJulia.jl
  21. Introducing Julia
    https://en.wikibooks.org/wi­ki/Introducing_Julia
  22. Julia: the REPL
    https://en.wikibooks.org/wi­ki/Introducing_Julia/The_REPL
  23. Introducing Julia/Metaprogramming
    https://en.wikibooks.org/wi­ki/Introducing_Julia/Meta­programming
  24. Month of Julia
    https://github.com/DataWo­okie/MonthOfJulia
  25. NumPy Home Page
    http://www.numpy.org/
  26. NumPy v1.10 Manual
    http://docs.scipy.org/doc/num­py/index.html
  27. NumPy (Wikipedia)
    https://en.wikipedia.org/wiki/NumPy
  28. OpenBLAS: An optimized BLAS library
    https://www.openblas.net/