.. highlightlang:: lua .. us.bug translate .. index:: Lua .. _lua: 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. 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 * :ref:`lua-functions` * :ref:`lua-licenses` .. sidebar:: Lua .. image:: S:/uniplot-obj/images/powered-by-lua.* Lua is a powerful, fast, lightweight, embeddable scripting language -- http://www.lua.org/about.html. Kurzer Vergleich zu UniScript ----------------------------- Es sollen zwei Funktionen verglichen werden, die das größte Element in einem Vektor finden. Zunächst die UniScript-Funktion: .. code-block:: us :linenos: // 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 .. code-block:: us * 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. .. code-block:: us * tic(); maximum(r); toc() 56.1462 Betrachten wir nun die Lua-Funktion. .. code-block:: lua :linenos: -- 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. .. code-block:: lua 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. .. image:: S:/uniplot-obj/images/lua-cmd-wnd-maxi.* Nun können die drei Anweisungen eingegeben werden, um die Funktion zu testen. .. code-block:: lua :linenos: > 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 :ref:`maxi`-Funktion aufgerufen werden, die noch ein wenig schneller als die Lua-Funktion ist. .. code-block:: us * a = rand(1e6,1); * tic(); maxi(a); toc() 0.7638 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: .. code-block:: lua 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. .. code-block:: lua 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. .. code-block:: lua 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``: .. code-block:: lua -- 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 .. code-block:: lua up = require"uniplot" mat = require"uniplot.matrix" können folgende UniScript-Operationen in Lua ausgeführt werden: .. list-table:: :header-rows: 1 * - 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. 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. Anmerkungen ----------- * Die LuaJIT-Version ist 2.1-beta vom 2016-01-18 mit ``-DLUAJIT_ENABLE_LUA52COMPAT`` eingeschaltet. Die DLL ``luajit.dll`` ist mit Microsoft Visual 2015 kompiliert mit der C-Runtime-Library ``msvcr120.dll``. Die LuaJIT DLL kann also einfach durch eine selbst erstellte DLL ausgetauscht werden. :sub:`id-1010283`