1. Lua¶
Lua ist eine einfache, aber leistungsfähige Skriptsprache, die ab UniPlot R2016 parallel zu UniScript verwendet werden kann. UniPlot verwendet LuaJIT (http://www.luajit.org) von Mike Pall.
1.1. Weitere Informationen¶
Die erste Auflage des Buchs „Programming in Lua“ by Roberto Ierusalimschy, Lua.org, December 2003, ISBN 8590379817 ist online verfügbar: http://www.lua.org/pil/contents.html
- Hier finden sie das Lua 5.1 Reference Manual: http://www.lua.org/manual/5.1/
- Gute Tutorials finden Sie unter: http://lua-users.org/wiki/TutorialDirectory
- Lua Functions
- Lizenzen
1.2. Kurzer Vergleich zu UniScript¶
Es sollen zwei Funktionen verglichen werden, die das größte Element in einem Vektor finden. Zunächst die UniScript-Funktion:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // Maximum und Index eines Vektors bestimmen
def maximum(a)
{
mi = 1;
m = a[mi];
for (i in 1:len(a)) {
if (a[i] > m) {
mi = i;
m = a[i];
}
}
return [m, mi];
}
|
Die Funktion kann in einem UniPlot-Editor unter einem Namen mit der Endung .ic
gespeichert werden. Mit dem Befehl UniScript=>Save/Execute oder der Taste
F4 kann sie übersetzt werden. Im UniScript-Kommandofenster
(Ansicht=>Kommando-Fenster) kann sie nun ausgeführt werden. Mit
* r = rand(1,1e6)
wird ein Vektor mit 1.000.000 Zufallszahlen im Bereich 0 bis 1 erzeugt. tic()
startet eine Zeitmessung und toc()
gibt die verstrichene Zeit in Millisekunden
aus.
* tic(); maximum(r); toc()
56.1462
Betrachten wir nun die Lua-Funktion.
1 2 3 4 5 6 7 8 9 10 11 12 13 | -- Maximum und Index eines Vektors bestimmen
function maximum(a)
local mi = 1
local m = a[mi]
for i = 1, #a do
if a[i] > m then
mi = i
m = a[i]
end
end
return m, mi
end
|
Die Funktion wird in einer Datei mit der Extension .lua
gespeichert.
In der ersten Zeile befindet sich ein Kommentar. Einzeilige Lua-Kommentare
beginnen mit den Zeichen --
und enden am Zeilenende.
Anstatt mit def
werden Lua-Funktionen mit function
markiert. Anweisungen
werden in UniScript mit den Zeichen { ... }
geschachtelt, in Lua werden
end, do-end oder then-end verwendet.
function ... end
for ... do ... end
if ... then ... end
Die erste Anweisung ist in UniScript mi = 1;
bzw. in Lua local mi = 1
.
In UniScript sind alle Variablen innerhalb von Funktionen lokale Variablen.
Sollen globale Variablen in UniScript-Funktionen verwendet werden, müssen sie am
Anfang der Funktion mit global
deklariert werden.
In Lua müssen alle lokalen Variablen bei der erstmaligen Verwendung in einer
Funktion mit local
markiert werden, sonst werden sie als globale Variablen
verwendet, was meist unerwünscht ist. Siehe auch
http://lua-users.org/wiki/LocalByDefault.
Um die Lua-Funktion auszuführen, wird sie zunächst übersetzt (mit F4 im Editor).
Anschliessend wird das UniScript-Kommandofenster in den Lua-Mode umgeschaltet.
Dazu wird der Befehl .lua
im UniScript-Kommandofenster eingegeben.
Nun können die drei Anweisungen eingegeben werden, um die Funktion zu testen.
1 2 3 4 | > a = {}; for i=1,1e6 do a[i] = math.random() end
> up = require"uniplot"
> up.tic(); maximum(a); print(up.toc())
0.95537533378229
|
Die erste Zeile erzeugt eine Lua-Table mit 1 Millionen Elementen. Dazu wird die
random()
-Funktion aus der Lua math
-Library verwendet, die eine einzelne
Zufallszahl erzeugt.
In Zeile 2 wird die uniplot
-Libray geladen. Die beiden Funktionen
tic()
und toc()
verwenden die Windows-QueryPerformanceCounter
-Funktion
mit der Zeiten genau gemessen werden können.
Die Lua-Funktion braucht nur ca. eine Millisekunde während die UniScript-Funktion über 50 ms gedauert hat. Die Gründe sind: 1.) LuaJIT ist sehr ausgefeilt, 2.) UniScript ist ein Interpreter und bei der Lua-Funktion wird durch LuaJIT kompilierter Code erzeugt und ausgeführt.
In der Praxis wird in UniScript für diese Aufgabe eine C-Funktion verwendet.
Beenden Sie dazu das Lua-Kommandofenster mit dem Befehl exit
. Im UniScript
Kommandofenster kann dann die maxi-Funktion aufgerufen werden, die noch
ein wenig schneller als die Lua-Funktion ist.
* a = rand(1e6,1);
* tic(); maxi(a); toc()
0.7638
1.3. Anbindung an UniScript¶
UniScript-Funktionen werden über die Funktion r = us.call(us_func_name, p1, ...)
aufgerufen. Sie befindet sich in der DLL lua_uniscript.dll
. Beispiel:
us = require "lua-uniscript" -- lua-uniscript.dll laden
m = us.call("sin", 1)
print(m)
0.8414709848079
Da eine UniScript-Funktion eine einzelne Zahl zurück liefert, wird sie in eine
Lua-Number umgewandelt. Ansonsten wird der UniScript-Wert in einem Lua userdata
gespeichert.
x = us.call("linspace", 0, 2*math.pi, 1e5)
print(x)
matrix: 0x22e70660
print(type(x))
userdata
In x
befindet sich ein UniScript-Vektor mit 100.000 Punkten.
y = us.call("sin", x)
us.call("plot", x, y)
Normalerweise wird die us.call()
-Funktion nicht direkt verwendet, sondern es
wird eine Verpackung verwendet. Hier drei Funktionen des Moduls uniplot
:
-- uniplot.lua
local us = require "lua-uniscript"
local mat = require "uniplot.matrix"
local u = {}
u.abs = function(a1)
return mat:new(us.call("abs", a1))
end
u.acos = function(a1)
return mat:new(us.call("acos", a1))
end
u.acosh = function(a1)
return mat:new(us.call("acosh", a1))
end
return u
Mit
up = require"uniplot"
mat = require"uniplot.matrix"
können folgende UniScript-Operationen in Lua ausgeführt werden:
UniScript | Lua | Kommentar |
---|---|---|
a + b |
a + b or mat.add(a, b) |
Die Matritzen müssen gleich groß sein, a oder b kann ein Skalar sein. |
a - b |
a - b or mat.sub(a, b) |
Subtrahieren. |
a * b |
a * b or mat.mul(a, b) |
Matrix-Multiplikation |
a .* b |
mat.emul(a, b) |
Elementweise Multiplikation |
a / b |
a / b or mat.div(a, b) |
|
a ./ b |
mat.ediv(a, b) |
Elementweise Division |
a \ b |
||
a' |
a:trans() |
Transponierung. |
a.' |
a:etrans() |
|
nr(a) |
a:nr() or mat.nr(a) |
Anzahl an Zeilen (rows). |
nc(a) |
a:nc() or mat.nc(a) |
Anzahl an Spalten (columns). |
len(a) |
#a or a:len() or mat.len(a) |
Länge eines Vektors. |
a^-1 or inv(a) |
a^-1 or a:inv() or mat.inv(a) |
Inverse einer Matrix. |
[1,2,3] |
mat.matrix{1,2,3} |
Zeilenvektor |
[1;2;3] |
mat.matrix({1,2,3}):trans() |
Spaltenvektor erzeugen. |
[1,2;3,4] |
up.reshape(mat.matrix{1,2,3,4}, 2, 2):trans() |
Matrix |
[a, b] |
mat.hcat(a,b) |
Matritzen horizontal verketten. |
[a; b] |
mat.vcat(a,b) |
Matrizen vertikal verketten. |
a < b , <= == != > >= |
mat.lt(a, b) , le, eq, ne, gt, ge |
Vergleichsoperatoren für Matrizen und Vektoren. |
a & b, a | b, a@b, ~a, a << b, a >> b |
mat.band(a, b) , bor, xor, not, shl, shr |
Bitweises and, or, exclusiv or, not, shift left, shift right |
1:10 , 1:0.5:3 , 3:1 |
mat.range(1, 10) , mat.range(1,0.5,3) , mat.range(3, 1) |
Sequenzen [1, 2, .. 10] , [1, 1.5, 2, 2.5, 3] , [3, 2, 1] |
b = a[i;j] |
b = a:rowcol(i, j) |
|
a[i;] , a[;j] |
a:row(i) , a:col(j) |
|
a[:] |
reshape(a, 1, #a) | |
c = 1+3i |
c = complex(1, 3) |
Komplexe Zahl oder Matrix erzeugen. |
1.4. Debuggen von Lua-Programmen¶
Der UniScript-Debugger wird zur Zeit erweitert um auch Lua-Programme debuggen zu können. Er wird in einigen Monaten fertig gestellt sein.
1.5. Anmerkungen¶
Die LuaJIT-Version ist 2.1-beta vom 2016-01-18 mit
-DLUAJIT_ENABLE_LUA52COMPAT
eingeschaltet. Die DLLluajit.dll
ist mit Microsoft Visual 2015 kompiliert mit der C-Runtime-Librarymsvcr120.dll
.Die LuaJIT DLL kann also einfach durch eine selbst erstellte DLL ausgetauscht werden.
id-1010283