Sinistra <- AmaroK: un'intervista agli sviluppatori - Indice Generale - Copertina - Fedora Core 3: un'installazione difficile -> Destra

Sistemi Liberi


Software libero per il trattamento di problemi scientifici (Parte III - Interfacciamento grafico)

di Francisco Yepes Barrera

L'articolo...

Terza e ultima parte dell'articolo sull'utilizzo del Software Libero in ambiente scientifico. La prima parte dell'articolo è stata pubblicata sul PLUTO Journal numero 43 e la seconda parte, invece, pubblicata sul PLUTO Journal numero 44.


Introduzione

Nelle parti I e II di questo articolo, abbiamo fatto una piccola descrizione delle caratteristiche generali degli applicativi di tipo scientifico, e abbiamo presentato, con l'aiuto di alcune esempi, alcuni programmi interessanti. Resta da trattare un aspetto di rilievo: l'interfacciamento grafico. Quanto segue riporta una discussione sulle caratteristiche desiderabili in una interfaccia grafica dal punto di vista del software matematico-scientifico. Alla fine si riporta il codice di un'applicazione web che implementa un interfacciamento al programma maxima.

Caratteristiche desiderabili in un'interfaccia grafica

L'interfacciamento grafico è un aspetto importante delle applicazioni scientifiche, per due motivi fondamentalmente:

  1. come abbiamo detto nell'introduzione alla Parte I, non tutti gli specialisti in materie scientifiche hanno le competenze informatiche necessarie per poter adoperare i programmi da riga di comando, anche se si tratta della forma migliore e più potente. Altre persone, invece, utilizzano i programmi senza essere specialisti e possono avere difficoltà nel capire il significato dei valori numerici meno intuitivi da inserire nei file di configurazione;
  2. in genere, i software utilizzati vengono resi disponibili a una grande quantità di persone. Un interfacciamento grafico adeguato può facilitare, come vedremo, la diffusione all'interno di una rete o di un dato ambiente di lavoro (permettendo un utilizzo remoto delle applicazioni), anche se, insistiamo, non apporta niente di nuovo per quanto riguarda le funzionalità rispetto all'utilizzo dalla riga di comando. Inoltre, una buona interfaccia grafica può mettere a disposizione delle utilità che vengono richiamate "al volo" per realizzare certe operazioni, come generare grafici e tabelle formattate.

Quindi, l'interfaccia grafica è un optional in principio, che può diventare necessario in alcuni casi. Alcuni programmi hanno la propria interfaccia: maxima, ad esempio dispone di un utilità, xmaxima, che consente l'utilizzo in ambiente X, ma al di là di questo aspetto non offre alcuna funzionalità addizionale. In altri casi si dispongono di moduli per l'integrazione in altri ambienti: maxima e octave hanno dei moduli per emacs che consentono la manipolazione delle espressioni con le sue funzioni di editing; ma in realtà non si può parlare di interfaccia propriamente detta.

Il concetto moderno di interfaccia grafica va ben al di là del semplice concetto di "programma a finestre". Essa, dal mio punto di vista, deve avere le seguenti due caratteristiche:

  1. deve consentire un accesso remoto, cioè, deve permettere l'utilizzo dei programmi da postazioni di lavoro geograficamente delocalizzate rispetto al sistema dove le applicazioni sono effettivamente installate. In più, dovrebbe consentire l'accesso simultaneo di più utenti, allocando le risorse necessarie per ciascuno di essi. Da questo punto di vista, un sistema X potrebbe essere adeguato;
  2. deve essere indipendente dalla piattaforma, cioè deve consentire l'accesso e l'utilizzo del software da qualunque sistema operativo. Da questo punto di vista, invece, il sistema grafico X potrebbe non essere la scelta migliore.

Naturalmente, un'interfaccia che consenta solo il lavoro in locale è comunque una "interfaccia grafica", ma non nel senso esteso dato qui.

La tecnologia web per lo sviluppo di un'interfaccia grafica

Le due proprietà enumerate precedentemente vengono soddisfatte da applicazioni basate sulla tecnologia web. Infatti, il web è nato per l'accesso a informazioni remote, ed è possibile l'utilizzo da qualunque sistema operativo. Inoltre, un web server gestisce molti problemi legati alla sicurezza, e può essere configurato per ottenere un accesso differenziato alle risorse da parte di diversi utenti o tipologie di utenti.

Negli ambienti di lavoro che mi è capitato di conoscere, ho visto sempre l'utilizzo del web in funzione della "messa in rete" delle applicazioni sviluppate. Nel caso di utilizzo di un applicativo in una rete interna, che penso sia quello più comune, una Intranet può permettere un utilizzo esteso con relativamente poco lavoro. Nel futuro penso che il binomio web-software scientifico sia destinato a crescere, soprattutto per l'offerta di servizi scientifici e di calcolo distribuito a pagamento da parte di compagnie private.

Un esempio di interfacciamento web a maxima

Nel mio lavoro, utilizzo abbastanza frequentemente il programma maxima. Mi capita spesso la necessità di rappresentare graficamente le espressioni che genero simbolicamente con il programma. maxima dispone di funzioni per la rappresentazione, o è possibile usare gnuplot, ma ogni volta bisogna impostare le etichette per gli assi, dare i comandi per l'esportazione dell'immagine e altre cose. Sarebbe utile poter fare tutto al volo, a partire da qualche operazione completata.

Di seguito si presenta a modo di esempio un'interfaccia web per il calcolo simbolico di integrali e la loro rappresentazione grafica. La rappresentazione viene fatta con gnuplot, costruendo appropriatamente il file di configurazione e generando il risultato dinamicamente. L'applicazione utilizza lo standard CGI, con perl [1] come linguaggio di scripting. In tutto, ci sono tre script per realizzare tutte le operazioni, schematizzati in nella Figura 1.

[Figura 1]

Figura 1: flusso sequenziale di chiamate degli script CGI dell'interfaccia web per l'integrazione simbolica e la rappresentazione grafica.

La prima cosa da sapere è quante dimensioni (= variabili indipendenti) ha la funzione da integrare, in modo da generare dinamicamente il numero di campi strettamente necessario per l'inserimento dei dati. Nel nostro programma questo viene fatto passando, dalla pagina HTML iniziale, il numero di dimensioni attraverso un campo di testo con il metodo POST:

<form action="/cgi-bin/symbolic_data.pl" method="POST">
...
<input type="text" name="dim" size="3">
...
</form>

Lo script symbolic_data.pl recepisce il valore della variabile dim proveniente dalla pagina HTML e genera dinamicamente i campi necessari per l'inserimento dei dati: funzioni, variabili indipendenti ed eventualmente limiti di integrazione (solo per integrali definiti). Segue il codice di questo script con una buona quantità di commenti. Il programma usa il modulo CGI di perl per la gestione delle variabili richiamate tra i form:

#!/usr/bin/perl 
 
# file 'symbolic_data.pl' 
 
#       Part of Mathweb, an interactive resource for symbolic and
#       numerical calculations
#       Copyright (C) 2004 Francisco Yepes Barrera 
#           <paco.yepes@libero.it>
#
#       This program is free software; you can redistribute it and/or
#       modify it under the terms of the GNU General Public License
#       as published by the Free Software Foundation; either version 2
#       of the License, or (at your option) any later version.
#
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#
#       You can find the complete text of the GNU General Public 
#       License at http://www.gnu.org/copyleft/gpl.html 
 
 
# Questo script raccoglie i dati per l'integrazione simbolica di una
# funzione con un numero arbitrario di variabili indipendenti 
 
# Richiamiamo il modulo CGI per la gestione dei dati dei form HTML. 
# Associamo una nuova istanza CGI alla variabile $qry
use CGI;
$qry = new CGI; 
 
# La variabile $web contiene il nome della DocumentRoot del sito
$web = "http://$ENV{'SERVER_NAME'}/~paco"; 
 
# Intestazione della pagina HTML
print "Content-type: text/html\n\n";
print <<EOF;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
        <title>Calcolo simbolico</title>
        <link rel="StyleSheet" href="$web/webpaco.css" type="text/css">
</head>
<body> 
 
# I dati inseriti nel form vengono passati col metodo POST allo
# script 'symbolic.pl'
<form action="/cgi-bin/symbolic.pl" method="POST"> 
 
<div id="header">
        <br>Mathweb - calcolo simbolico
</div>
<div id="body"> 
 
# Menu della pagina
<div id="menu">
        ...
</div>
EOF 
 
# Leggiamo il valore della variabile 'dim' (numero di dimensioni), 
# passata dalla pagina HTML iniziale
$dim = $qry->param('dim'); 
 
# Se dim > 0, vengono generati i campi per contenere l'integrando
# della funzione, le variabili indipendenti e i limiti superiore
# e inferiore di integrazione, nel caso si voglia fare l'integrale 
# definito
if ($dim <= 0) {
        print "<h1>Numero errato di dimensioni.</h1>\n";
} else {
        print "<h3 align=\"center\">Questo sito usa <i>Maxima 5.9.0</i> per il calcolo simbolico (<a href=\"http://maxima.sourceforge.net/\">
http://maxima.sourceforge.net/</a>).</h3>\n";
        print "<hr>\n";
        print "<table align=\"center\">\n";
        print "<tbody>\n";
        print "<th>Funzione</th>\n";
        print "<tr>\n";
        print "<td valign=\"top\"><textarea name=\"function\" cols=\"60\" rows=\"6\"></textarea></td>\n";
        print "<td>\n";
        print "</td>\n";
        print "</tr>\n";
        print "</tbody>\n";
        print "</table>";
        print "<table align=\"center\">\n";
        print "<tbody>\n";
        print "<th>Variabili indipendenti</th>\n";
        print "<tr><td>\n";
        print "<table>\n";
        print "<tbody>\n";
        print "<th>N</th>\n";
        print "<th>Variabile</th>\n";
        print "<th>Lim. inf.</th>\n";
        print "<th>Lim. sup.</th>\n"; 
 
# Limiti superiore e inferiore
        for ($i = 1; $i <= $dim; $i++) {
                print "<tr>\n";
                print "<td align=\"center\">$i</td>\n";
                print "<td><input type=\"text\" name=\"x$i\" size=\"10\"></td>\n";
                print "<td><input type=\"text\" name=\"xa$i\" size=\"10\"></td>\n";
                print "<td><input type=\"text\" name=\"xb$i\" size=\"10\"></td>\n";
                print "</tr>\n";
        }
        print "</tbody>\n";
        print "</table>\n";
        print "</td></tr>\n";
        print "<tr>\n";
        print "<td align=\"center\">\n";
        print "<input type=\"submit\" name=\"Submit\">\n";
        print "<input type=\"reset\" name=\"Reset\">\n";
        print "</td>\n";
        print "</tr>\n";
        print "</tbody>\n";
        print "</table>\n";
} 
 
# Un campo nascosto passa allo script 'symbolic.pl' il numero di 
# dimensioni dell'integrando
print "<input type=\"hidden\" name=\"dim\"  value=\"$dim\">\n"; 
 
print "</form>\n";
print "</body>\n</html>\n";

Questo script genera una pagina come quella della Figura 2, nella quale, a titolo di esempio, si propone il calcolo dell'integrale indefinito

[Integrale indefinito]

già considerato nella Parte II. Una volta dato l'ordine, i dati vengono mandati con il metodo POST allo script symbolic.pl, che realizza effettivamente l'integrazione, e il cui codice è il seguente:

[Figura 2]

Figura 2: pagina generata da symbolic_data.pl.

#!/usr/bin/perl 
 
# file 'symbolic.pl' 
 
#       Part of Mathweb, an interactive resource for symbolic and
#       numerical calculations
#       Copyright (C) 2004 Francisco Yepes Barrera 
#           <paco.yepes@libero.it>
#
#       This program is free software; you can redistribute it and/or
#       modify it under the terms of the GNU General Public License
#       as published by the Free Software Foundation; either version 2
#       of the License, or (at your option) any later version.
#
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#
#       You can find the complete text of the GNU General Public 
#       License at http://www.gnu.org/copyleft/gpl.html 
 
 
# Questo script realizza l'integrazione simbolica di una funzione con
# un numero arbitrario di dimensioni. I dati vengono passati dal
# programma 'symbolic_data.pl' 
 
# Richiamiamo il modulo CGI per la gestione dei dati dei form HTML. 
# Associamo una nuova istanza CGI alla variabile $qry
use CGI;
$qry = new CGI; 
 
# Variabili contenenti la DocumentoRoot del sito e il percorso di
# maxima
$web = "http://$ENV{'SERVER_NAME'}/~paco";
$maxima_path = "/usr/bin/maxima"; 
 
# Leggiamo i dati per l'integrazione passati da 'symbolic_data.pl'
# con il metodo POST: numero di dimensioni (dim) e integrando
# (function)
$dim = $qry->param('dim');
$int = $qry->param('function'); 
 
# Inizio pagina
print "Content-type: text/html\n\n";
print <<EOF;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"  "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
        <title>Calcolo simbolico</title>
        <link rel="StyleSheet" href="$web/webpaco.css" type="text/css">
</head>
<body>
<div id="header">
        <br>Mathweb - calcolo simbolico
</div> 
 
# Menu della pagina
<div id="menu">
        ...
</div> 
 
# Corpo della pagina
<div id="body">
EOF 
 
# I dati vengono passati con il metodo POST allo script 'gnuplot.pl'
# che realizza la rappresentazione grafica della funzione integrata,
# in 2 o 3 dimensioni. I dati che vengono passati sono: funzione
# integrata, numero di variabili indipendenti, etichette per le
# variabili (le variabili si possono chiamare con nomi arbitrari,
# diversi in generale da 'x' e 'y') e valori massimo e minimo delle
# variabili indipendenti che definiscono il dominio per la
# rappresentazione grafica
print "<form action=\"/cgi-bin/gnuplot.pl\" method=\"POST\">\n"; 
 
print "<h1 align=\"center\">Risultato del calcolo simbolico</h1><hr>\n"; 
 
# Controlliamo che le variabili indipendenti siano definite per una
# funzione integrando con un numero di dimensioni pari a '$dim'.
# Altrimenti viene restituito un messaggio di errore. La variabile
# '$j1' è posta fuori dal loop 'for' perché deve esserci almeno
# una variabile indipendente definita. 
# 
# IMPORTANTE: maxima non è case sensitive. Cioè, le funzioni possono
# essere inserite in maiuscolo o minuscolo, ma lo è per le variabili,
# per cui 'X' è diverso da 'x'. Esempio:
# 
#                 integrate(sin(x), x) = -cos(x)
# 
# ma
#
#                 integrate(sin(X), x) = sin(X) x
if (length($qry->param('x1')) == 0) {
        print "<h1>Variabile 1 non specificata.</h1>\n";
        exit;
} 
 
for ($j = 1; $j <= $dim; $j++) {
        if (length($qry->param("x$j")) == 0) {
                print "<h1>Variabile $j non specificata.</h1>\n";
                exit;
        }
        
        $int = "$com($int, ".$qry->param("x$j"); 
 
# $mm e $MM rappresentano i limiti di integrazione definiti
# per la variabile $j. Se non sono definiti vuole dire che si
# sta facendo un integrale indefinito. L'integrale definito
# può essere improprio se si specificano INF (+infinito) e/o
# MINF (-infinito) come limiti d'integrazione
        $mm = $qry->param("xa$j");
        $MM = $qry->param("xb$j"); 
 
# maxima usa '%PI' come convenzione per il numero PI. Quindi,
# se viene trovato 'PI' o 'pi' viene sostituito con '%PI'
        if (length($mm) > 0 || length($MM) > 0) {
            $mm =~ s/pi/%PI/gi;
            $mm =~ s/%%pi/%PI/gi;
            $MM =~ s/pi/%PI/gi;
            $MM =~ s/%%pi/%PI/gi;
            $int .= ", $mm, $MM";
        }
        $int .= ")";
} 
 
# Costruiamo la espressione finale per maxima, avendo cura di
# usare la rappresentazione adeguata del numero PI, come abbiamo
# fatto per i limiti di integrazione. La espressione calcolata
# viene semplificata e viene fornita anche la espressione FORTRAN
$integrate = "ratsimp($int); fortran(%);";
$integrate =~ s/pi/%PI/gi;
$integrate =~ s/%%pi/%PI/gi; 
 
# Per evitare di dover creare file temporanei, creiamo una pipe
# per recuperare l'output di maxima, che noi leggiamo come se si
# trattassi di un normale file
open (IN, "$maxima_path -batch-string=\"$integrate\"|"); 
 
# Stampiamo il risultato. '<===' è il comando di input dato al
# programma, '===>' è l'output restituito
print "<p  align=\"center\"><textarea cols=\"80\" rows=\"10\" align=\"center\">\n";
while (<IN>) {
        if (/provides bug reporting information/) {
                while (<IN>) {
                        next if (/DONE/ || /^;;/ || /Bye/);
                        if(/\(C2\)/) {
                                print "\nEspressione FORTRAN:\n";
                                $fortran = <IN>;
                                print $fortran;
                                chop($fortran);
                        } else {
                                s/\(C1\)/<===/;
                                s/\(D1\)/===>/;
                                s/\(D2\)/    /;
                                print "$_";
                                chop;
                                $fortran .= $_;
                        }
                }
        }
}
$fortran =~ s/     .   //g;
$fortran =~ s/ //g;
print "</textarea></p>\n"; 
 
# Verifichiamo quante dimensioni ci sono. Se $dim < 3, allora vengono
# generati campi extra per inserire i limiti per la rappresentazione
# grafica, che poi vengono passati allo script 'gnuplot.pl'
if ($dim < 3) {
        print "<input type=\"hidden\" name=\"function\" value=\"$fortran\" size=100000>\n";
        print "<input type=\"hidden\" name=\"nvar\" value=\"$dim\">\n";
        print "<input type=\"hidden\" name=\"x1\" value=\"".$qry->param('x1')."\">\n";
        print "<input type=\"hidden\" name=\"x2\" value=\"".$qry->param('x2')."\">\n";
        print "<input type=\"hidden\" name=\"x3\" value=\"".$qry->param('x3')."\">\n";
        print "<p align=\"center\">Se vuoi rappresentare questa funzione inserisci i limiti:<br>\n";
        print "Xmin<input type=\"text\" name=\"x_min\" size=\"10\" value=\"-10\">  \n";
        print "Xmax<input type=\"text\" name=\"x_max\" size=\"10\" value=\"10\"><br>\n";
        if ($dim == 2) {
                print "Ymin<input type=\"text\" name=\"y_min\" size=\"10\" value=\"-10\">\n";
                print "Ymax<input type=\"text\" name=\"y_max\" size=\"10\" value=\"10\"><br><br>\n";
                print "Numero di linee per la rappresentazione <input type=\"text\" name=\"nsamples\" size=\"3\" value=\"50\"><br>\n";
        }
        print "<br><input type=\"submit\" name=\"Submit\">\n";
} 
 
# Chiudiamo anche la pipe
close (IN); 
 
print "</form>\n";
print "</body>\n</html>\n";

Il risultato di questo script è mostrato in Figura 3. Come si vede, viene restituito il seguente output:

[Figura 3]

Figura 3: pagina generata da symbolic.pl.

<===         RATSIMP(INTEGRATE(INTEGRATE(SIN(x) + COS(y), x), y))
===>                        x SIN(y) - COS(x) y 
 
Espressione FORTRAN:
      x*SIN(y)-COS(x)*y

"<===" identifica l'espressione di input passata effettivamente a maxima; "===>" identifica l'output restituito. L'espressione FORTRAN è utile eventualmente nel caso l'espressione calcolata debba essere importata in un qualche software scientifico o per la rappresentazione grafica. symbolic.pl identifica anche che è possibile realizzare una rappresentazione grafica (il numero di dimensioni è minore di 3), per cui ci propone dei campi per l'inserimento dei limiti inferiore e superiore del dominio per la rappresentazione, con valori di default rispettivamente di -10 e 10. I dati per la rappresentazione vengono finalmente passati allo script gnuplot.pl, che procede a generare, usando il programma gnuplot, una pagina HTML dinamica contenente il grafico della funzione. Il codice di gnuplot.pl è:

#!/usr/bin/perl 
 
# file 'gnuplot.pl' 
 
#       Part of Mathweb, an interactive resource for symbolic and
#       numerical calculations
#       Copyright (C) 2004 Francisco Yepes Barrera 
#           <paco.yepes@libero.it>
#
#       This program is free software; you can redistribute it and/or
#       modify it under the terms of the GNU General Public License
#       as published by the Free Software Foundation; either version 2
#       of the License, or (at your option) any later version.
#
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#
#       You can find the complete text of the GNU General Public 
#       License at http://www.gnu.org/copyleft/gpl.html 
 
 
# Questo script realizza la rappresentazione grafica della funzione 
# integrata proveniente da 'symbolic.pl' 
 
# Associamo una nuova istanza CGI alla variabile $qry
use CGI;
$qry = new CGI; 
 
# Variabili contenenti la DocumentRoot del sito il percorso dove si
# trovano le pagine del sito
$web = "http://$ENV{'SERVER_NAME'}/~paco";
$wwwpath = "/home/paco/public_html";require 'include_webpaco.pl'; 
 
# Inizio pagina
print "Content-type: text/html\n\n";
print <<EOF;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"  "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
        <title>Rappresentazione grafica</title>
        <link rel="StyleSheet" href="$web/webpaco.css" type="text/css">
</head>
<body> 
 
# Intestazione
<div id="header">
        <br>Mathweb - rappresentazione grafica della funzione
</div>
EOF 
 
# Recuperiamo la funzione integrata passata con il metodo POST da
# 'symbolic.pl'
$func = $qry->param('function'); 
 
# maxima è più ricco di funzionalità di gnuplot. Alcune funzioni, come
# secante, cosecante, ecc. non sono supportate, mentre altre, come
# le funzioni di Bessel, hanno sintassi diversa. Ci assicuriamo di
# 'tradurre' nel linguaggio di gnuplot, alcune di queste funzioni
# importanti
$func =~ s/%pi/pi/gi;    # numero PI
$func =~ s/sec/1\/cos/gi;    # seccante (inversa del coseno)
$func =~ s/csc/1\/sin/gi;    # cosecante (inversa del seno)
$func =~ s/cot/1\/tan/gi;    # cotangente (inversa della tangente)
$func =~ s/bessel_j.*\[.*0.*\]/besj0/gi;    # funzione di Bessel di
                                            # prima specie e ordine 0
$func =~ s/bessel_j.*\[.*1.*\]/besj1/gi;    # funzione di Bessel di
                                            # prima specie e ordine 1
$func =~ s/bessel_y.*\[.*0.*\]/besj0/gi;    # funzione di Bessel di
                                            # seconda specie e ordine 0
$func =~ s/bessel_y.*\[.*1.*\]/besj1/gi;    # funzione di Bessel di
                                            # seconda specie e ordine 1 
 
# Recuperiamo il numero di variabili indipendenti e le etichette per
# le variabili (maxima può avere usato variabile diverse dalle solite
# 'x' e 'y'). Trasformiamo la stringa in minuscolo perché gnuplot,
# a differenza di maxima, è case sensitive
$nvar = $qry->param('nvar');
$x1 = $qry->param('x1');
$x1 =~ tr/[A-Z]/[a-z]/;
$x2 = $qry->param('x2');
$x2 =~ tr/[A-Z]/[a-z]/;
$func =~ tr/[A-Z]/[a-z]/; 
 
# gnuplot usa l'operatore '**' per l'esponenziazione. maxima, invece,
# può usare sia '**' che '^', per cui adeguiamo la sintassi in questo 
# ultimo caso
$func =~ s/\^/\*\*/g; 
 
# gnuplot può usare relazioni funzionali che coinvolgono le variabili
# indipendente 'x' e 'y'. Ci assicuriamo che vengano usate questi
# 'nomi' o 'etichette' nei casi in cui maxima ha usato invece
# nomi diversi
if ($x1 ne "x") {$func =~ s/$x1/x/g;}
if ($nvar == 2 && $x2 ne "y") {$func =~ s/$x2/y/g;} 
 
# Generiamo un nome univoco per il file temporaneo che conterrà il
# file con i dati per la rappresentazione che sarà usato da gnuplot.
# Per essere sicuri che il file è unico, usiamo un nome composto
# dall'ID del job in esecuzione e dell'orologio di sistema. Lo
# stesso discorso per il file che conterrà l'immagine PNG generata.
# Questo evita di sovrascrivere i dati e le immagini quando più
# utenti sono collegati contemporaneamente. Immagine e file di
# configurazione vengono scritti su una cartella temporanea (tmp)
# all'interno della DocumentRoot. E' compito del sistema quello
# di pulire periodicamente il contenuto di questa cartella con,
# ad esempio, un cron job
$tmp = $$."-".time();
$gnuplot = $tmp.".gnuplot";
$png = $tmp.".png"; 
 
# Creiamo il file di configurazione per gnuplot
open (GNUPLOT,">$wwwpath/tmp/$gnuplot") || die; 
 
# Recuperiamo i limiti min e max per la rappresentazione, dai dati
# passati da 'symbolic.pl'. Traduciamo tutto in minuscolo per le
# stesse ragioni discusse sopra per quanto riguarda la funzione.
# Inoltre, ci assicuriamo che la sintassi del numero PI sia
# comprensibile a gnuplot
$xmin =  $qry->param('x_min');
$xmin =~ tr/[A-Z]/[a-z]/;
$xmin =~ s/%pi/pi/gi;
$xmax =  $qry->param('x_max');
$xmax =~ tr/[A-Z]/[a-z]/;
$xmax =~ s/%pi/pi/gi; 
 
# File di configurazione di gnuplot. Per rappresentazioni
# tridimensionali è possibile specificare il numero di
# linee utilizzate e viene generato anche la mappa di contorno
# della funzione
print GNUPLOT "set xrange [$xmin:$xmax]\n";
print GNUPLOT "set nokey\n";
print GNUPLOT "set term png medium color\n";
print GNUPLOT "set out '$wwwpath/tmp/$png'\n";
print GNUPLOT "set xlabel '$x1'\n";
if ($nvar == 1) {
        print GNUPLOT "set ylabel 'f($x1)'\n";
        #print GNUPLOT "set title 'Rappresentazione della funzione $func\n";
        print GNUPLOT "plot $func\n";
} elsif ($nvar == 2) {
        $samples = $qry->param('nsamples'); 
 
# Limitiamo il numero di linee a 100. Non vogliamo che
# qualcuno si diverta a generare grafici 3D con 1000000
# di linee che ci blocchi il sistema
        if ($samples <= 0) {
            $samples = 50;
        } elsif ($samples > 100) {
            $samples = 100;
        } 
 
# Traduciamo tutto per la seconda variabile indipendente così
# come abbiamo fatto con la prima (vedi sopra)
        $ymin =  $qry->param('y_min');
        $ymin =~ tr/[A-Z]/[a-z]/;
        $ymin =~ s/%pi/pi/gi;
        $ymax =  $qry->param('y_max');
        $ymax =~ tr/[A-Z]/[a-z]/;
        $ymax =~ s/%pi/pi/gi;
        print GNUPLOT "set yrange [$ymin:$ymax]\n";
        print GNUPLOT "set ylabel '$x2'\n";
        print GNUPLOT "set zlabel 'f($x1, $x2)'\n";
        print GNUPLOT "set hidden3d\n";
        print GNUPLOT "set contour base\n";
        print GNUPLOT "set isosamples $samples\n";
        print GNUPLOT "splot $func\n";
} 
 
# Chiusura file configurazione
close (GNUPLOT); 
 
# Generiamo il grafico. Se c'è qualche problema stampiamo un
# messaggio di errore
if (!system("gnuplot $wwwpath/tmp/$gnuplot")) {
    print "<p align=\"center\"><img src=\"$web/tmp/$png\">\n";
} else {
        print "<br><h1 align=\"center\">La funzione non ha esistenza in nessun punto del dominio selezionato oppure non è possibile rappresentarla</h1><br>\n";
}
print "<p align=\"right\"><a href=\"$web/html/mathweb/functions.html\">Elenco delle funzioni disponibili</a><br>\n";
print "<a href=\"$web/html/mathweb.html\">Torna alla pagina principale di Mathweb</a>\n"; 
 
# Fine
print "</body>\n</html>\n";

La Figura 4 mostra il grafico prodotto da questo script.

Questa procedura per l'integrazione simbolica è disponibile in rete all'URL http://www.enernova.it/~paco/html/mathweb.html. Magari a qualcuno può risultare utile. Inoltre, è possibile realizzare, con un sistema analogo a quello esposto, differenziazioni simboliche, limiti e rappresentazioni grafiche di funzioni arbitrarie in due e tre dimensioni. Spero nel futuro poter attivare ulteriori funzionalità.

[Figura 4]

Figura 4: grafico del risultato dell'integrale generato da gnuplot.pl.

Conclusione

Questo articolo ha cercato, nelle sue tre parti, di fare una panoramica delle possibilità che si hanno nell'utilizzo di software libero in ambiente scientifico. Si è voluto andare oltre la semplice descrizione delle informazioni contenute nelle pagine di manuale, facendo riferimento a una serie di esempi che danno, a mio avviso, una idea della potenzialità degli applicativi, facendo vedere che questi ultimi possono essere usati con profitto a tutti i livelli. In questa ottica sono stati presentati gli esempi di cui sopra, alcuni semplici, altri meno. Per ultimo è stato illustrato un esempio di programmazione, costruendo un'interfaccia web per la realizzazione di alcune operazioni complesse.

Ci sarebbero tanti altri temi da trattare, alcuni riguardanti aspetti implementativi o software particolarmente interessanti. Il presente articolo potrà, forse, servire a scopo introduttivo per abbordare tematiche più approfondite nel futuro.

Bibliografia

1) Randal L. Schwartz - Learning Perl - O'Reilly & Associates Inc. - 1993.


L'autore

Francisco Yepes Barrera, Paco, è socio di ILS ed appassionato per diletto e per lavoro di informatica e di scienze. I suoi interessi riguardano la computazione scientifica, l'intelligenza artificiale e l'utilizzo di software libero nella soluzione di problemi matematici.


Sinistra <- AmaroK: un'intervista agli sviluppatori - Indice Generale - Copertina - Fedora Core 3: un'installazione difficile -> Destra