Robitex's Blog

Ideas in the web

Archivi delle etichette: Lua

Un simpatico effetto funzionale in LuaTeX


La domanda

A volte capita di chiedersi all’improvviso se l’idea che ci è appena balenata in mente può effettivamente esser realizzata.

Stavo esaminando alcune caratteristiche di LuaTeX quando una domanda è sorta spontanea: è possibile creare una macro che accetti una funzione matematica scritta dall’utente e la esegua su un argomento anch’esso variabile?

Si tratta quindi di far eseguire una funzione matematica definita sul momento, in pieno stile functional.

La macro dovrebbe accettare due argomenti: il primo è la funzione da usare e il secondo l’argomento numerico su cui eseguire il calcolo:

\applyfun{<funzione>}{<numero>}

Nel documento troveremo poi il risultato cercato. La cosa interessante è che il primo parametro della macro, la funzione, è concettualmente simile al secondo argomento essendo entrambi dei valori.

Per esempio, vorremmo poter scrivere:

Il quadrato di 10 è \applyfun{function (x) return x*x end}{10}!

LuaTeX della famiglia TeX

LuaTeX è un motore di composizione tipografico della gloriosa famiglia TeX. Questi programmi compilano un file di testo scritto dall’utente per fornire il corrispondente documento pdf.

Nel file di testo — detto sorgente — si adopera una sorta di linguaggio istruendo il programma alla gestione di sommari, riferimenti incrociati, titoli, eccetera.

In molti paesi opera un TUG, un TeX User Group. In Italia è attivo da 15 anni il GuIT Gruppo di utilizzatori Italiani di TeX, il cui sito può darvi tutte le informazioni necessarie.

Dimenticavo di dirvi che il sistema TeX è stato uno dei primi esempi di software libero, perciò siete ancor più liberi di usarlo per scrivere i vostri documenti.

La risposta

Ebbene la risposta è positiva! Si, è possibile e se non ci credete compilate con LuaTeX il codice seguente:

% luatex

% definizione della macro
\def\applyfun#1#2{%
\directlua{
local fun = #1
tex.sprint(fun(#2))
}}

Experimental!

\applyfun{function (x) return math.log(x)+10 end}{12}

Ok.

Il quadrato di $\pi$ vale
\applyfun{function (x) return x*x end}{3.14159}.

End job.
\bye

E mi raccomando, non provate a farlo con Word o LibreOffice…
Alla prossima.
R.

Se SQLite vi sembra lento…


Sommario

Indagine sul perché SQLite fosse così lento ad inserire i dati…
In un progetto di elaborazione dati ho utilizzato un database SQLite per gestire un set di dati abbastanza complesso. Fino ad ora ammettevo che il codice per l’inserimento dei dati fosse molto lento contrariamente all’esecuzione delle query…

Cosa ho vantaggiosamente scoperto

L’inserimento dei dati avviene in SQLite all’interno di transazioni che hanno lo scopo di salvare i dati in modo sicuro. Se eseguo un inserimento tramite la normalissima funzione SQL INSERT, SQLite attende che ogni record inserito sia completamente e con successo salvato fisicamente sul disco.
Questo comportamento è dovuto al fatto che l’istruzione viene inserita automaticamente in una transazione.

Il numero di transazioni che SQLite è in grado di completare è dell’ordine di 10 al secondo, ed ecco spiegato il motivo di quelle strane attese. All’interno di una transazione invece il numero di inserimenti è dell’ordine di 50.000 al secondo.

Soluzioni

Compreso che ogni inserimento crea implicitamente una transazione, le alternative sono due:

  1. non fare niente e lasciare che i dati vengano inseriti con una transazione alla volta per usufruire della massima affidabilità;
  2. rendere le operazioni molto più veloci operando all’interno di un’unica transazione, ma anche meno sicure in caso di guai con il processo client.

…naturalmente ho preferito la seconda…

Giusto per fissare le idee

Giusto per fissare le idee, il codice che ho utilizzato, scritto in Lua e che utilizza la libreria LJSQLite3 scritta per luajit, è il seguente:

-- carico la libreria LJSQLite3
local sql = require "ljsqlite3"

-- creo la connessione
-- (in dbfilename è salvato il nome effettivo del file)
    local conn = sql.open( dbfilename, "rw")

-- abilito il vincolo di chiave esterna
-- per il momento non ON di default per mantenere
-- compatibilità con versione precedenti di SQLite3 versione 3.6
    conn:exec("PRAGMA foreign_keys = ON;")

-- creo una transazione
    conn:exec "BEGIN" -- begin transaction

-- codice per inserire i dati nel database
-- per esempio con un prepared statement
-- (codice esemplificativo con nomi tabella e campi per riferimento)
   local stmt = conn:prepare("INSERT INTO mytable " ..
     .. "(field_1, field_2, ..., field_n)" ..
     .. " VALUES (?, ?, ..., ?);" )
...
...
... eccetera eccetera

-- chiudo la transazione
    conn:exec "END"

-- chiudo la connessione
    conn:close()

Saluti e buona estate.

Iterare su SQLite con Lua


Sommario

Riferendoci alla libreria LJSqlite3 verrà spiegato come iterare facilmente la collezione di dati di un database relazionale attraverso una query. Verranno inoltre messe in evidenza le proprietà dell’iteratore ai fini della pulizia e dell’intuitività del codice Lua.

Effective code

È sempre molto utile scrivere codice che sia espressivo e compatto, qualità che potremo riassumere in un unico termine idiomatico: effective.
Gli iteratori di Lua, che abbiamo già visto in questo post, sono costrutti sintattici che semplificano il nostro codice facendo corrispondere un concetto/entità con un elemento del linguaggio.
Lo sviluppatore costruisce così strutture concettualmente vicine a ciò che asserisce al problema da risolvere.

L’ambiente di lavoro

Utilizzeremo il database SQLite3 per creare, inserire ed interrogare i dati, e la libreria LJSqlite3 per LuaJIT un compilatore Lua, per creare il codice applicativo.
Sul vostro sistema dovranno essere installati sia SQLite3, che LuaJIT, e le librerie Xsys e LJSQLite3 scaricabili dai rispettivi siti e disponibili per quasi tutti i sistemi operativi.

Inoltre lavoreremo con un (semplice) database in modalità in-memory cioé interamente mantenuto nella memoria centrale, così che tutto il codice di esempio possa trovare posto in un unico file.

L’iteratore Lua

Il nostro obiettivo è scrivere un iteratore ‘stateless‘ in Lua che ad ogni ciclo ci metta a disposizione record per record, il risultato di una query.
Chiamando l’iteratore ‘iselect()‘ potremo prevedere per esso due argomenti: la connessione al database e la query da eseguire. Per concretizzare l’idea, lasciando i dettagli ad un secondo momento, il codice per stampare l’intero contenuto della tabella di esempio ‘val‘ con i suoi attributi ‘id‘ e ‘num‘ potrebbe essere il seguente:

for i, tr in iselect(conn, "SELECT * FROM val;") do
    print( 'Row '..i..': ', tr.id, tr.num)
end

L’iteratore ad ogni ciclo del ‘generic for’ ritorna il progressivo del record e la ‘tupla’ (una tabella Lua ovviamente) con i valori dei campi indicizzati con chiavi corrispondenti ai nomi degli attributi della tabella del database.

Passiamo ora al codice completo dell’esempio con l’implementazione dell’iteratore definito precedentemente. Non spiegherò il listato nei dettagli tecnici rimandando il lettore alle documentazioni dei singoli componenti peraltro scritte piuttosto bene. Eseguire il codice con il comando $ luajit nomefile.lua.

-- iterator function
local function nextrec(t, i)
    i = i + 1
    if i <= t.__number_of_records then
        local tr = {}
        local nc = #t[0]
        for col=1, nc do
            local field = t[0][col]
            tr[field] = t[col][i]
        end
        return i, tr
    end
end

-- stateless iterator
local function iselect(connection, query)
    local t, nr = connection:exec(query, 'hi')
    t.__number_of_records = nr
    return nextrec, t, 0
end

-- SQL code

local sql = require "ljsqlite3"
-- Open a temporary in-memory database.
local conn = sql.open("")

-- Execute SQL commands separated by the ';'
conn:exec[[
CREATE TABLE val (id TEXT, num REAL);

INSERT INTO val VALUES('myid1', 260);
INSERT INTO val VALUES('myid2', 200);
INSERT INTO val VALUES('myid3', 200);
INSERT INTO val (id) VALUES('myid4');
INSERT INTO val (num) VALUES(200);
INSERT INTO val VALUES('myid6', 260);
INSERT INTO val VALUES('myid7', 201);
INSERT INTO val VALUES('myid8', 300);
INSERT INTO val VALUES('myid9', 240);
]]

-- user code
for i, tr in iselect(conn, "SELECT * FROM val;") do
    print( 'Row '..i..': ', tr.id, tr.num)
end
conn:close()

Conclusioni

Oltre a confermare l’intuitività e la semplicità degli iteratori in Lua, abbiamo dimostrato come SQLite3 e le librerie LuaJIT per accedervi, siano in grado di fornire una soluzione performante e potente per la creazione di applicativi non di rete.

Un saluto.

Iteratori in Lua


Costruzione di un iteratore in Lua

La costruzione di un iteratore in Lua si basa sulla creazione di una funzione che restituisce uno alla volta gli elementi dell’insieme nella sequenza desiderata. Una volta costruito l’iteratore, questo potrà essere impiegato in un ciclo foreach — che in Lua viene chiamato generic for — in modo molto efficiente.
Se per esempio si volesse iterare la collezione dei numeri pari compresi nell’intervallo da 1 a 10, avendo a disposizione l’apposito iteratore evenNum(first, last) che definiremo in seguito, potrei scrivere semplicemente:

for n in evenNum(1,10) do
   print(n)
end

ottenendo in console:

2
4
6
8
10

Numeri pari

Per definire questo iteratore dobbiamo creare una funzione che restituisce a sua volta una funzione in grado di generare la sequenza dei numeri pari. L’iterazione termina quando giunti all’ultimo elemento, la funzione restituirà il valore nullo ‘nil’, cosa che succede in automatico senza dover esplicitare un’istruzione di return.
Per prima cosa si calcola il numero pari successivo al numero di partenza dell’intervallo. Lo faremo usando la funzione math.ceil() che fornisce il numero arrotondato al primo intero superiore dell’argomento. Poi viene restituita la funzione in sintassi anonima che prima incrementa di 2 il numero pari precedente — ed ecco perché inizialmente viene sottratta la stessa quantità all’indice — e, se questo è inferiore all’estremo superiore dell’intervallo, verrà restituito l’indice corrente, il numero pari della sequenza:

-- iteratore dei numeri pari compresi
-- nell'intervallo [i, e]
function evenNum(i, e)
   -- primo numero pari della sequenza
   i = 2*math.ceil(i/2) - 2
   return function ()
             i = i + 2
             if i<=e then
                return i
             end
          end
end

Tecnicamente il sistema funziona perché ogni volta che viene chiamata una funzione, Lua crea le necessarie variabili in una nuova area di memoria, così che la funzione anonima possa lavorare correttamente. Ulteriori particolari possono essere reperiti nel libro ‘Programming in Lua‘, cosa consigliabile se si devono costruire iteratori in ambienti di produzione.

Naturalmente, l’implementazione data di evenNum() è solo una delle possibili soluzioni, e non è detto che non debbano essere considerate situazioni particolari come quella in cui si passa all’iteratore un solo numero o addirittura nessun argomento.

Stateless iterator

Una seconda versione del generatore di numeri pari può essere un buon esempio di un iteratore in Lua che non necessita di un area di memoria — chiamata closure — per un risultato ancora più efficiente.
Per capire come ciò sia possibile dobbiamo conoscere come funziona il ‘generic for’ in Lua; dopo la parola chiave ‘in’ esso si aspetta tre parametri: la funzione dell’iteratore da chiamare ad ogni ciclo, una variabile che rappresenta lo stato invariante, e la variabile di controllo.
Nel seguente codice la funzione evenNum() provvede a restituire i tre parametri necessari: la funzione nextEven() come iteratore, lo stato invariante che per noi è il numero a cui la sequenza dovrà fermarsi, e la variabile di controllo che è proprio il numero della sequenza dei numeri pari, e con ciò abbiamo realizzato un stateless iterator in Lua.
La funzione iteratrice nextEven() verrà chiamata ad ogni ciclo con nell’ordine lo stato invariante e la variabile di controllo, pertanto fate attenzione, dovete mettere in questo stesso ordine gli argomenti nella definizione.

-- even numbers stateless iterator
local function nextEven(last, i)
   i = i + 2
   if i<=last then
      return i
   end
end

local function evenNum(a, b)
   a = 2*math.ceil(a/2)
   return nextEven, b, a-2
end

-- example of generic for
for n in evenNum(10,20) do
print(n)
end

Lua non finisce mai di stupire…
Alla prossima!

Come mandare Lua in crash


I software sono perfettibili, ed anche Lua, il bellissimo linguaggio di scripting, non è da meno. Guardate infatti cosa succede se si apre una sessione di Lua, digitando il comando lua, e dando l’istruzione seguente:

print(os.date('%G'))

Il formato ‘%G’ infatti non fa parte dei codici accettati per formattare la data di sistema ma… invece di ricevere il classico errore…

The Lua console open on a dangerous istruction...

The Lua console open on a dangerous istruction…

Lua crash Dialog on Windows after command execution

Lua crash Dialog on Windows after command execution


Dalle immagini potete riscontrare che mi trovo in Windows con Lua 5.1.
Buona estate, che finalmente è arrivata!
R.

Click and script


Scarica l’articolo nel formato PDF

Sommario

In questo post impareremo come personalizzare il menù contestuale in Nautilus, il gestore di file incorporato in Gnome, fino a compilare al volo sorgenti LaTeX e compiere moltissime altre operazioni che possono essere ripetitive.

Il menù contestuale

Nelle moderne interfacce grafiche il menù contestuale è un efficace idea che presenta all’utente le operazioni effettuabili su uno specifico oggetto. Se per esempio si tratta di un file compresso il click destro sull’icona che lo simboleggia, attiverà un menù contestuale che presenta le apposite voci per l’estrazione del contenuto.

In Linux, nel Desktop Environment Gnome è possibile associare a questi menù piccoli programmi per lanciarli comodamente dopo aver selezionato i file d’interesse.

Nautilus-scripts

Nautilus è il file manager di Gnome. Grazie al supporto per lo scripting, le operazioni per creare una nuova voce di menù contestuale sono davvero semplici, allo stesso modo di quelle da svolgere per creare un nuovo modello di documento come già illustrato in questo post. Basta creare il file con il codice, assegnargli i permessi di esecuzione e spostarlo nella directory nascosta $HOME/.gnome2/nautilus-scripts.

Menù contestuale su un file compresso in Gnome

Menù contestuale su un file compresso in Gnome

Come è naturale sui sistemi Linux, possiamo scrivere script in molti linguaggi, da Bash a Python. Noi utilizzeremo anche Lua pertanto dovrete assicurarvi che sia installato sul vostro sistema.

I nostri comandi personalizzati

Ecco in concreto, alcune idee di personalizzazione del menù. Ciascun nuovo comando contestuale deriva da esigenze della pratica quotidiana.
Molte altre idee possono essere realizzate per rendere più semplice l’utilizzo del pc, per esempio unire più file di testo o spedire documenti ad un indirizzo di posta elettronica…

Mandare in stampa un documento

Se desidero lanciare la stampa di un file PDF lo apro con un visualizzatore ed eseguo il comando di stampa. Se i PDF da stampare sono molti invece, apro il terminale, posiziono la working directory e lancio la stampa di tutti i PDF presenti con il comando:

$ lpr *.pdf

Con qualche conoscenza in più di Bash (il linguaggio standard per l’amministrazione dei sistemi Linux ma anche di quelli Mac OS X ormai), si costruisce un piccolo e semplicissimo script:

#!/bin/bash

for arg do
    lpr "$arg"
done

Salviamone il contenuto in un file di testo chiamato per esempio goToPrinter, assegniamogli i permessi di esecuzione (anche dal menù Proprietà) e spostiamolo nella directory nascosta $HOME/.gnome2/nautilus-scripts. Di seguito la sequenza dei comandi e l’immagine della sessione corrispondente al terminale:

$ chmod +x goToPrinter
$ mv goToPrinter ~/.gnome2/nautilus-scripts
Sessione al terminale per la creazione del Nautilus script

Sessione al terminale per la creazione del Nautilus script

Elencare file

Modificando un poco lo script precedente possiamo ottenere facilmente un file di testo contenente la lista dei file selezionati sostituendo ad lpr il comando echo e reindirizzandone l’output verso un file. Utilizzeremo poi la libreria zenity per mostrare un dialogo che mostri all’utente il numero dei file conteggiati.

#!/bin/bash

for arg do
    echo "$arg"
done >> listoffiles.txt

zenity --info --width=200 --height=100 \
       --title="Conteggio file elencati" \
       --text="Numero di file elencati: $# "

Compilare un sorgente LaTeX

Compilare un sorgente LaTeX non è un problema se ci si avvale di un editor come TeX Works, oppure direttamente del terminale, ma se lo possiamo fare con un semplice click destro sulla selezione di file è davvero elegante.
Il codice in Lua provvede a filtrare i file selezionati al momento dell’apertura del menù contestuale in base all’estensione solitamente assegnata ai sorgenti LaTeX.

#!/usr/bin/lua

-- ottengo la lista dei file selezionati
-- dalla variabile d'ambiente opportuna
--
local s = os.getenv("NAUTILUS_SCRIPT_SELECTED_FILE_PATHS")

-- per ogni file con estensione .tex
-- procedo alla compilazione
--
for path in string.gmatch(s,"(.-)\n") do
   -- estrazione estensione
   local ext = string.match(path,"%.(.-)$")
   
   -- se l'estensione esiste allora compilo
   -- se è un sorgente .tex
   if ext then
   if string.lower(ext) == "tex" then
      local ps = "(.-)%." .. ext .. "$"
      local name = string.match(path,ps)
      
      os.execute('pdflatex -interaction=nonstopmode "'..name..'"')
      os.remove(name..".log")
      os.remove(name..".aux")
   end
   end
end

-- end of Lua script

Ottenere il pdf di file di testo

Con poche modifiche possiamo adattare il codice precedente per ottenere uno script che converte i file di testo in formato PDF utilizzando LaTeX:

#!/usr/bin/lua

local docsource = [[
\documentclass[a4paper]{article}

\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[italian]{babel}

\usepackage[margin=20mm]{geometry}

\usepackage{inconsolata}

\begin{document}
\ttfamily
%s
\end{document}
]]

-- ottengo la lista dei file
local s = os.getenv("NAUTILUS_SCRIPT_SELECTED_FILE_PATHS")

for path in string.gmatch(s,"(.-)\n") do
   -- estrazione estensione
   local ext = string.match(path,"%.(.-)$")
   
   -- se l'estensione esiste allora creo il pdf con LaTeX
   if ext then
   if string.lower(ext) == "txt" then
      local ps = "(.-)%." .. ext .. "$"
      local filename = string.match(path,ps)
      
      -- lettura del file
      local textfile = io.open(path,"r")
      local content = string.gsub(textfile:read("*all"),"\n","\n\n")
      local sourcetexfile = string.format(docsource,content)
      textfile:close()
      
      -- creazione sorgente
      local sf = io.open(filename..".tex","w")
      sf:write(sourcetexfile)
      sf:close()
      
      os.execute("pdflatex -interaction=nonstopmode "..filename)
      os.remove(filename..".log")
      os.remove(filename..".aux")
      os.remove(filename..".tex")
   end
   end
end

-- end of Lua script

Conclusioni

Il menù contestuale è davvero comodo. In Linux possiamo utilizzare diversi linguaggi di scripting per creare nuove voci di comandi con cui semplificare il lavoro quotidiano analizzando attentamente le nostre necessità.
Un saluto.

Note tecniche

Sul sistema devono essere installati e correttamente configurati i pacchetti e gli eseguibili di un sistema TeX ed un interprete Lua.
Gli esempi potrebbero richiedere leggere modifiche per distribuzioni Linux diverse da Ubuntu 10.04.

%d blogger hanno fatto clic su Mi Piace per questo: