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
9. Konstrukce jednorozměrného 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
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 |
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
$ 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
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/OpenBLAS/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
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
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
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
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
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.
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ář:
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:
- Seriál Programovací jazyk Lua
https://www.root.cz/serialy/programovaci-jazyk-lua/ - Seriál Torch: framework pro strojové učení
https://www.root.cz/serialy/torch-framework-pro-strojove-uceni/ - Seriál Programovací jazyk Julia
https://www.root.cz/serialy/programovaci-jazyk-julia/ - Seriál Programovací jazyk R
https://www.root.cz/serialy/programovaci-jazyk-r/ - Skriptovací jazyk Lua v aplikacích naprogramovaných v Go
https://www.root.cz/clanky/skriptovaci-jazyk-lua-v-aplikacich-naprogramovanych-v-go/ - LuaJIT – Just in Time překladač pro programovací jazyk Lua
https://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua/ - 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/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
https://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi/ - Programování mainframů: jazyk APL
https://www.root.cz/clanky/programovani-mainframu-jazyk-apl/ - Programovací jazyk APL: programování bez smyček
https://www.root.cz/clanky/programovaci-jazyk-apl-programovani-bez-smycek/ - Programovací jazyk APL – dokončení
https://www.root.cz/clanky/programovaci-jazyk-apl-dokonceni/ - 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/ - Incanter: operace s maticemi
https://www.root.cz/clanky/incanter-operace-s-maticemi/ - Tvorba jednoduchých grafů v systému Incanter
https://www.root.cz/clanky/tvorba-jednoduchych-grafu-v-systemu-incanter/ - Tvorba grafů v systému Incanter (pokračování)
https://www.root.cz/clanky/tvorba-grafu-v-systemu-incanter-pokracovani/ - Gophernotes: kombinace interaktivního prostředí Jupyteru s jazykem Go
https://www.root.cz/clanky/gophernotes-kombinace-interaktivniho-prostredi-jupyteru-s-jazykem-go/ - 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
- SciLua: Scientific Computing with LuaJIT
https://scilua.org/ - Knihovna lua-sci na GitHubu
https://github.com/stepelu/lua-sci - Nástroj lua-sci-lang na GitHubu
https://github.com/stepelu/lua-sci-lang - ULua: Universal Lua Distribution
https://ulua.io/index.html - LuaRocks
https://luarocks.org/ - Awesome Lua – A curated list of quality Lua packages and resources.
https://github.com/LewisJEllis/awesome-lua - LuaJIT
https://luajit.org/ - Running LuaJIT
https://luajit.org/running.html - LuaJIT na GitHubu
https://github.com/luajit - Lua Implementations
http://lua-users.org/wiki/LuaImplementations - Archived | Embed Lua for scriptable apps
https://developer.ibm.com/tutorials/l-embed-lua/ - Embedding Lua
https://www.oreilly.com/library/view/lua-quick-start/9781789343229/3a6f3daf-f74c-4a25-a125–584da58568e4.xhtml - The R Project for Statistical Computing
https://www.r-project.org/ - An Introduction to R
https://cran.r-project.org/doc/manuals/r-release/R-intro.pdf - R (programming language)
https://en.wikipedia.org/wiki/R_(programming_language) - The R Programming Language
https://www.tiobe.com/tiobe-index/r/ - Julia (front page)
http://julialang.org/ - Julia – repositář na GitHubu
https://github.com/JuliaLang/julia - Julia (programming language)
https://en.wikipedia.org/wiki/Julia_%28programming_language%29 - IJulia
https://github.com/JuliaLang/IJulia.jl - Introducing Julia
https://en.wikibooks.org/wiki/Introducing_Julia - Julia: the REPL
https://en.wikibooks.org/wiki/Introducing_Julia/The_REPL - Introducing Julia/Metaprogramming
https://en.wikibooks.org/wiki/Introducing_Julia/Metaprogramming - Month of Julia
https://github.com/DataWookie/MonthOfJulia - NumPy Home Page
http://www.numpy.org/ - NumPy v1.10 Manual
http://docs.scipy.org/doc/numpy/index.html - NumPy (Wikipedia)
https://en.wikipedia.org/wiki/NumPy - OpenBLAS: An optimized BLAS library
https://www.openblas.net/