Familiarizzare con Mathematica

Transcript

Familiarizzare con Mathematica
Il contenuto di queste pagine è protetto dalle leggi sul copyright e dalle disposizione dei trattati internazionali. Il titolo
ed il copyright relativi alle pagine sono di proprietà dell'autore. Le pagine possono essere riprodotte ed utilizzate
liberamente dagli studenti, dagli istituti di ricerca, scolastici ed universitari afferenti al Ministero dell'Istruzione,
dell'Università e della Ricerca per scopi istituzionali, non a fine di lucro. Ogni altro utilizzo o riproduzione (ivi incluse,
ma non limitatamente a, le riproduzioni a mezzo stampa, su supporti magnetici o su reti di calcolatori) in toto o in
parte è vietata, se non esplicitamente autorizzata per iscritto, a priori, da parte dell'autore.
L'informazione contenuta in queste pagine è ritenuta essere accurata alla data della pubblicazione. Essa è fornita per
scopi meramente didattici e non per essere utilizzata in progetti di impianti, prodotti, ecc.
L'informazione contenuta in queste pagine è soggetta a cambiamenti senza preavviso. L'autore non si assume alcuna
responsabilità per il contenuto di queste pagine (ivi incluse, ma non limitatamente a, la correttezza, completezza,
applicabilità ed aggiornamento dell'informazione). In ogni caso non può essere dichiarata conformità all'informazione
contenuta in queste pagine. In ogni caso questa nota di copyright non deve mai essere rimossa e deve essere
riportata anche in utilizzi parziali.
Familiarizzare con Mathematica
1.1. Input e output di Mathematica
Una volta eseguito Mathematica, l'utente si trova di fronte a una finestra inizialmente vuota. Questa
finestra è associata ad un notebook, che è la componente di Mathematica deputata a interagire con
l'utente. Come indicato dal nome, un notebook implementa la metafora di un quaderno su cui scrivere,
in forma più o meno elegante. Nonostante siano stati pensati per un utilizzo fortemente orientato a
contenuti di carattere matematico, i notebook di Mathematica si prestano anche a lavorare con
informazione di tipo più eterogeneo. Ad esempio, quello che state leggendo è stato scritto utilizzando
un notebook e non un impaginatore di testi.
l notebook è il programma tramite cui un utente dialoga con il sistema, inserendo richieste e ottenendo
risposte. Un'altra parte del sistema, chiamata kernel, si occupa invece di eseguire tutte le
computazioni necessarie per portare a termine queste richieste, generando (eventualmente) le relative
risposte. Seguendo la terminologia informatica, d'ora in avanti parleremo di input e di output piuttosto
che di richieste e risposte.
Più precisamente, ogni notebook è diviso in tante celle, ognuna tipicamente marcata da una parentesi
quadra chiusa posta alla sua destra, che ne delimita il contenuto (e infatti ci si riferisce a questi
componenti di Mathematica come a dei delimitatori di cella) e che permette di selezionare l'intera
cella (cliccando sulla sua parte verticale), ad esempio per copiarla o cancellarla da un notebook. Un
altro aspetto pratico dei delimitatori di cella è rappresentato dal fatto che le piccole barre orizzontali
poste alle loro estremità permettono di individuare il punto in cui due celle si separano. Ciò è
particolarmente utile quando si vuole inserire una nuova cella in mezzo a due celle esistenti:
posizionando il cursore in un qualunque punto di un notebook compreso tra due delimitatori
successivi, questo cambierà infatti la sua forma (assumendo quella di una linea orizzontale delimitata
da due piccoli segmenti, in pratica l'equivalente ruotato del simbolo, detto caret o i-bean, che lo stesso
cursore assume quando viene posizionato all'interno di un'area di testo in una qualunque interfaccia
grafica), proprio a evidenziare il fatto che cliccando in questa posizione è possibile inserire una nuova
cella.
Quando si scrive qualcosa nella finestra di un notebook, viene automaticamente creata in esso una
cella di input, cioé una cella in cui è possibile inserire dell'input da comunicare al kernel. Le celle di
input sono riconoscibili perché la parte superiore del delimitatore di cella corrispondente è marcata con
posizionando il cursore in un qualunque punto di un notebook compreso tra due delimitatori
successivi, questo cambierà infatti la sua forma (assumendo quella di una linea orizzontale delimitata
2 da due piccoli segmenti, in pratica l'equivalente ruotato del simbolo, detto caret o i-bean, che lo stesso
cap0.nb
cursore assume quando viene posizionato all'interno di un'area di testo in una qualunque interfaccia
grafica), proprio a evidenziare il fatto che cliccando in questa posizione è possibile inserire una nuova
cella.
Quando si scrive qualcosa nella finestra di un notebook, viene automaticamente creata in esso una
cella di input, cioé una cella in cui è possibile inserire dell'input da comunicare al kernel. Le celle di
input sono riconoscibili perché la parte superiore del delimitatore di cella corrispondente è marcata con
un piccolo triangolo. Ogni notebook può poi implementare delle proprie regole di stile per formattare
in modo opportuno celle di tipologia differente. Ad esempio le celle di input in questo notebook sono
caratterizzate da un fondo arancione chiaro e da un font della famiglia Courier, che dovrebbe ricordare
la forma con cui tipicamente gli elaboratori scrivono il codice.
Questa è una cella di input
Tramite le regole di stile è possibile modificare vari aspetti di una cella. In particolare è possibile disabilitare la visualizzazione dei
delimitatori di cella.
L'utente può scrivere in un notebook una generica espressione matematica e richiedere al kernel di
valutarla. La valutazione avviene dopo che si è utilizzata una particolare combinazione di tasti (Û
nella versione per Mac OS, ˜+Á nelle versioni per Linux o MS Windows) o la voce di menù
Kernel/Evaluation/Evaluate cells.
Il kernel riceve l'espressione, la valuta, e infine ritorna l'output relativo al notebook. Quest'ultimo si
occupa di presentarlo in modo opportuno all'utente. Ad esempio
In[208]:=
Out[208]=
1+1
2
Attenzione:
se è la prima volta che valutate una cella, il processo di valutazione potra' richiedere qualche secondo. Questo è
dovuto al fatto che deve essere caricato ed eseguito un Kernel.
L'output fornito da Mathematica appare in una cella il cui stile è molto simile a quello della cella che la
precede, con l'unica differenza che lo sfondo ora è arancione scuro e il delimitatore ha un ulteriore
linea orizzontale al di sotto del triangolo nella sua parte superiore. Questo sta a rimarcare il fatto che
essa è appunto una cella di output. Nonostante sia possibile inserire in un notebook celle di altri tipi
(ad esempio quello che state leggendo in questo istante è il contenuto di una cella di testo), per il
momento noi ci occuperemo principalmente di celle contenenti input e output. Il lettore interessato può
trovare in appendice alcuni approfondimenti relativi ad altri tipi di cella implementati.
E' da notare come un gruppo di celle che siano in qualche modo correlate sia evidenziato da un
ulteriore delimitatore, posto a destra rispetto a quelli delle singole celle, che delimita l'intero gruppo.
Ciò succede ad esempio se andiamo ad esaminare una cella di input e la corrispondente (o le
corrispondenti) celle di output. Gruppi di celle di questo tipo, oltre che creati automaticamente da
Mathematica in opportune occasioni, possono essere creati dall'utente selezionando
Tipicamente, la fase di immissione dei dati viene segnalata dalla pressione del tasto Á. In
Mathematica invece tale tasto serve semplicemente per andare a capo in una cella. Un altro aspetto
non standard è costituito dall'interpretazione degli spazi bianchi (caratteri di spazio, tabulazione e
ritorno a capo). Questi in genere vengono ignorati e il loro uso permette di migliorare la leggibilità di
quanto viene scritto. Mathematica invece li tratta nel modo seguente:
cap0.nb
3
Tipicamente, la fase di immissione dei dati viene segnalata dalla pressione del tasto Á. In
Mathematica invece tale tasto serve semplicemente per andare a capo in una cella. Un altro aspetto
non standard è costituito dall'interpretazione degli spazi bianchi (caratteri di spazio, tabulazione e
ritorno a capo). Questi in genere vengono ignorati e il loro uso permette di migliorare la leggibilità di
quanto viene scritto. Mathematica invece li tratta nel modo seguente:
gli spazi bianchi vengono ignorati;
In[149]:=
1
Out[149]=
2
+
1
le tabulazioni non vengono accettate: provate a inserire una o più tabulazioni in una cella di input e
vedrete che questa operazione non ha alcun effetto su quello che viene effettivamente scritto
nella cella. Solitamente le tabulazioni vengono usate per indentare il codice scritto, una
peculiarità che vedremo essere implementata automaticamente;
i caratteri di "a capo" iniziano una nuova linea all'interno di una cella (senza segnalare, come detto
prima, il termine dell'immissione dei dati). Va rimarcato il fatto che qualora una cella contenga
più linee, queste verranno valutate separatamente e in sequenza dal kernel
In[150]:=
1+1
1+2
1+3
Out[150]=
2
Out[151]=
3
Out[152]=
4
quindi questi caratteri non possono essere utilizzati per spezzare una riga troppo lunga: si
consideri ad esempio la cella seguente
In[153]:=
1
+
1
Out[153]=
1
Out[154]=
1
Mathematica ha interpretato il primo "1" come una riga a sé stante, mentre ha accorpato le due
righe seguenti nell'espressione "+1", per poi valutare le due espressioni separatamente. Il fatto
che le ultime due righe siano considerate come un'unica espressione è evidenziato dal fatto che
la seconda tra queste è indentata rispetto alla prima.
Mathematica spezza in modo generalmente automatico le linee troppo lunghe, tranne quando non
riesce a trovare un punto adeguato in cui dividere il contenuto della cella. In questi casi in ogni
4
cap0.nb
Mathematica ha interpretato il primo "1" come una riga a sé stante, mentre ha accorpato le due
righe seguenti nell'espressione "+1", per poi valutare le due espressioni separatamente. Il fatto
che le ultime due righe siano considerate come un'unica espressione è evidenziato dal fatto che
la seconda tra queste è indentata rispetto alla prima.
Mathematica spezza in modo generalmente automatico le linee troppo lunghe, tranne quando non
riesce a trovare un punto adeguato in cui dividere il contenuto della cella. In questi casi in ogni
linea viene scritto quanto più possibile, e la separazione è marcata a fine linea dal carattere
speciale di separazione (Ö):
In[158]:=
1111111111111111111111111111111111111111111111111111111111111111111111111Ö
111111111111111111111111111111111111111111111111111111
Il processo di valutazione è composto delle seguenti fasi:
La cella in cui si trova il cursore viene etichettata (alla sua sinistra) dalla voce In[n], dove n è un
numero che parte da 1 (quando viene eseguito il kernel) e aumenta progressivamente ogni volta
che viene valutata una cella.
Il contenuto di questa cella viene analizzato per verificare l'eventuale presenza di errori. In caso
non ne vengano trovati, la cella viene valutata e l'eventuale risultato viene stampato in una
nuova cella, automaticamente etichettata dalla voce Out[n], dove n è un numero progressivo
calcolato nello stesso modo di In[n].
In caso vengano trovati degli errori, vengono stampati uno o più messaggi opportuni: se ad
esempio scriviamo un'espressione matematica che non ha senso, come la seguente, otteniamo
In[215]:=
3- * 2
Syntax::sntxf : "3 -" cannot be followed by " * 2".
3 - *2
Kernel e notebook sono due programmi separati che comunicano tra loro e che possono anche essere
eseguiti separatamente.Ad esempio è possibile eseguire più notebook che facciano riferimento a uno
stesso kernel,oppure eseguire un notebook su un computer e il relativo kernel su un altro,sfruttando
una connessione di rete.Ancora,è possibile scindere una computazione complessa proveniente da un
notebook in varie sotto-computazioni da fare eseguire in modo concorrente da altrettanti kernel in
esecuzione su macchine differenti.
1.1.1. Modalità di inserimento per l'input
Mathematica accetta come input una serie di oggetti dal significato differente, come ad esempio
numeri interi, numeri irrazionali, testo, espressioni matematiche con un preciso stile (come ad esempio
l'esecuzione di un'esponenziazione) e così via. Siccome non tutti questi oggetti trovano un
corrispondente sulla tastiera di un computer (come la costante p), si rende necessario poterli inserire
utilizzando delle modalità alternative di immissione dell'input.
cap0.nb
5
Mathematica mette a disposizione le seguenti modalità di immissione:
tramite tastiera, utilizzando una descrizione di tipo testuale. Questa rappresenta la scelta naturale
per molti possibili input (i numeri interi, le quattro operazioni aritmetiche fondamentali, ...) i cui
simboli corrispondenti trovano tipocamente posto nelle tastiere di un computer, mentre richiede
il ricorso a una codifica opportuna per altre informazioni (ad esempio la costante "Pi greco" che
viene indicata tramite la codifica Pi); va notato come questa codifica rimanga visualizzata sul
notebook nella sua forma testuale;
tramite tastiera, inserendo input di tipo complesso tramite un'opportuna codifica che viene
immediatamente trasformata sul notebook in forma grafica; ad esempio è possibile visualizzare
la costante "Pi greco" tramite l'usuale simbolo p premendo il tasto  (azione che viene
confermata dalla comparsa sul notebook del carattere speciale Ç), inserendo la parola "pi" e
premendo nuovamente il tasto Â: il notebook verrà aggiornato sostituendo i caratteri da Ç in
avanti con il simbolo p. Per utilizzare questo tipo di modalità di immissione sono disponibili varie
codifiche (denominate più precisamente alias), tra cui una parzialmente mutuata dal sistema
LaTeX (un sistema di word processing in cui la descrizione dei documenti è fatta in modo
puramente testuale, inserendo appunto dei comandi in un'opportuna codifica per indicare gli stili
da applicare di volta in volta);
tramite il puntatore del mouse e un sistema di palette, cioé di tabelle che contengono vari simboli
che Mathematica inserisce nel notebook quando vengono selezionati. Per visualizzare (o
nascondere) una palette, è sufficiente selezionare la voce di menù File/Palettes. In molti casi,
quando il puntatore del mouse viene posizionato sopra un simbolo all'interno di una palette,
nella parte inferiore di quest'ultima vengono visualizzate le codifiche per inserire il simbolo
corrispondente tramite tastiera.
1.2. Espressioni aritmetiche
La specificazione di espressioni aritmetiche segue più le convenzioni utilizzate più dai matematici che
non dagli informatici. La differenza principale tra i due approcci sta nel fatto che non è necessario
specificare alcun simbolo per indicare la moltiplicazione: basta inserire uno spazio tra i fattori
In[227]:=
Out[227]=
42
8
In ogni caso è possibile specificare esplicitamente l'operazione di moltiplicazione utilizzando il simbolo
*. Questo è utile quando l'uso dello spazio può diminuire la leggibilità del codice Mathematica prodotto:
In[228]:=
Out[228]=
4*2
8
6
cap0.nb
Le rimanenti operazioni aritmetiche vengono specificate utilizzando gli usuali simboli per indicare gli
operatori di addizione (+) e sottrazione (-), a cui si aggiungono quelli relativi a divisione ( /),
elevamento a potenza (^) e calcolo del fattoriale (!).
In[229]:=
Out[229]=
In[230]:=
Out[230]=
In[232]:=
Out[232]=
In[231]:=
4+2
6
4-2
2
4ê2
2
4^2
Out[231]=
16
In[163]:=
4!
Out[163]=
24
Ovviamente è possibile utilizzare le parentesi tonde per variare l'ordine di valutazione predefinito delle
operazioni aritmetiche:
In[63]:=
Out[63]=
3 H4 + 5L
27
Il bello di utilizzare Mathematica sta nella possibilità di effettuare velocemente operazioni che
richiederebbero troppo tempo se eseguite a mano, come ad esempio
In[64]:=
Out[64]=
2 ^ 100
1267650600228229401496703205376
cap0.nb
In[166]:=
Out[166]=
7
30 !
265252859812191058636308480000000
1.3. Numeri interi ed approssimati
Se proviamo a dividere 8 per 6 otteniamo come risultato
In[237]:=
Out[237]=
8ê6
4
ÅÅÅÅ
3
Mathematica ha quindi espresso il risultato della divisione come una frazione, che ha poi semplificato.
In questo modo non viene introdotta alcuna approssimazione nel valore espresso. Analogamente si ha
In[238]:=
Out[238]=
5ê2
5
ÅÅÅÅ
2
Il risultato in questo caso è sempre espresso tramite una frazione, nonostante anche l'espressione
decimale 2.5 fosse corretta. Mathematica è stato progettato per indicare i numeri in forma esatta, cioé
senza introdurre approssimazioni, a meno che non gli venga esplicitamente richiesto di fare il
contrario. Per i numeri decimali, la forma esatta viene indicata tramite la corrispondente frazione
ridotta ai minimi termini: è per questo che il risultato della prima divisione è stato espresso come 4/3.
Ogni volta che viene indicato un numero contentente un punto decimale (non necessariamente
seguito da cifre), questo è inteso come espresso in forma approssimata, in cui tipicamente solo alcune
delle potenzialmente infinite cifre significative vengono elencate. Anche questo è il motivo per cui il
risultato della divisione precedente è stato espresso come 5/2 e non come 2.5. Quest'ultimo numero,
infatti, potrebbe essere ad esempio confuso con l'espressione approssimata di 2.500000000000001.
Ogni volta che un'espressione aritmetica contiene un numero decimale (eventualmente senza alcuna
cifra dopo di esso), l'intera espressione viene valutata in modo approssimato
In[242]:=
Out[242]=
5 ê 2 + 1.5
4.
E' da notare come il risultato di questa somma sia stato espresso con un punto decimale, proprio ad
indicare che esso è approssimato, essendo approssimato uno degli addendi. Pertanto il risultato delle
seguenti operazioni è differente:
8
cap0.nb
In[243]:=
Out[243]=
In[244]:=
Out[244]=
5ê2- 5ê2
0
5 ê 2 - 2.5
0.
Il primo risultato è la differenza tra due numeri uguali, entrambi espressi in forma esatta, che pertanto
è uguale a zero (in forma esatta). Il secondo è la differenza tra due numeri uguali, dei quali uno è
espresso in forma approssiamata, che sarà quindi uguale a zero in forma approssimata, come indicato
dal punto decimale.
Mathematica elabora in modo molto diverso i numeri espressi in forma esatta e quelli espressi in forma approssimata. In particolare, la
valutazione di espressioni complesse contenenti numeri in forma approssimata richiede un tempo tipicamente inferiore rispetto ai
numeri in forma esatta. Tenere a mente questa differenza può portare pertanto a realizzare modelli con tempi di esecuzione ottimizzati.
1.4. Costanti
Una costante rappresenta un valore che non varia nel tempo. Si trovano vari esempi di costanti in
fisica (la velocità della luce, la costante di graviazione universale, ...) e in matematica (il pi greco, ma
anche un qualsiasi numero). Mathematica implementa, tra le altre, le seguenti costanti matematiche:
il pi greco (la lunghezza di una circonferenza di diametro unitario):
In[3]:=
Out[3]=
Pi
p
la costante di Nepero (il valore della somma ‚
In[4]:=
E
Out[4]=
‰
L'unità immaginaria (la radice quadrata di -1):
In[5]:=
I
Out[5]=
Â
+¶
ÅÅÅÅ1ÅÅ
n=0 n!
):
cap0.nb
9
In realtà sono implementate anche molte altre costanti di tipo matematico e fisico, ma non le
prenderemo in considerazione.
1.5. Funzioni
Le funzioni vengono specificate indicando il loro nome seguito da una coppia di parentesi quadre che
ne racchiudono gli argomenti. In un certo senso le costanti possono essere pensate come delle
funzioni che non hanno argomenti (anche se vedremo che ricorrendo alla generazione di numeri
pseudo-casuali è possibile utilizzare Mathematica per costruire delle funzioni senza argomenti che non
realizzano delle costanti). Nel seguito vedremo un breve elenco che illustra come Mathematica possa
calcolare alcune tra le funzioni matematiche più semplici. In realtà il sistema implementa un numero
decisamente più elevato di funzioni, di complessità anche elevata, che noi non tratteremo. Il lettore
interessato ad approfondire questo argomento può consultare The Mathematica Book di Steven
Wolfram.
1.5.1. Funzioni logaritmiche ed esponenziali
La funzione Log[x] indica il logaritmo naturale di x:
In[7]:=
Out[7]=
Log@E ^ 4D
4
Se la funzione Log viene chiamata usando due argomenti, allora il primo rappresenta la base del
logaritmo e il secondo il suo argomento:
In[9]:=
Log@2, 8D
Out[9]=
3
In[93]:=
Log@10, 1000000D
Out[93]=
6
E' anche disponibile la funzione esponenziale Exp[x], nonostante in fase di valutazione venga
direttamente convertita in ‰^x:
In[94]:=
Out[94]=
Exp@2D
‰2
10
cap0.nb
1.5.2. Radicali
La funzione Sqrt determina le radici di un numero. In particolare, se usata con un solo argomento ne
calcola la radice quadrata
In[95]:=
Out[95]=
Sqrt@16D
4
Il calcolo di radici di altro tipo viene effettuato tenuto conto del fatto che
possibile calcolare la radice cubica di 8 come
In[98]:=
Out[98]=
b !
è!!!
x =x 1êb . Ad esempio è
8 ^ H1 ê 3L
2
Mathematica mette a disposizione un simbolo grafico per indicare in forma tradizionale le radici.
Quando un'espressione che lo contiene viene valutata, il simbolo viene convertito nelle espressioni
sopra indicate, come possiamo verificare utilizzando la funzione InputForm (di cui vedremo tra breve il
significato):
In[99]:=
è!!!
InputFormA x E
Out[99]//InputForm=
Sqrt[x]
In[100]:=
b
è!!!
InputFormA x E
Out[100]//InputForm=
x^b^(-1)
Attenzione!
Non fatevi ingannare da quest'ultima espressione, che va letta come x^(b^(-1)) a causa delle regole di
precedenza nella valutazione degli operatori. Per convincervene, provate per esercizio a valutare separatamente, ad esempio, le
espressioni 8^(1/3), 8^3^(-1) e (8^3)^(-1).
1.5.3. Funzioni trigonometriche
Le funzioni Sin, Cos e calcolano rispettivamente il seno, il coseno e la tangente del loro argomento
cap0.nb
11
In[104]:=
Out[104]=
In[105]:=
Out[105]=
Sin@Pi ê 4D
1
ÅÅÅÅÅÅÅÅÅ
è!!!
2
Cos@Pi ê 3D
1
ÅÅÅÅ
2
Mathematica implementa direttamente anche altre funzioni trigonometriche esprimibili in termini di
seno e coseno; ad esempio la funzione Tan calcola la tangente dell'argomento che le viene passato:
In[108]:=
Out[108]=
Tan@Pi ê 3D
è!!!
3
Mathematica semplifica ove possibile le espressioni trigonometriche:
In[112]:=
Out[112]=
Sin@xD ê Cos@xD
Tan@xD
Inoltre sono implementate le funzioni trigonometriche inverse ed esponenziali:
ArcSin e ArcCos calcolano rispettivamente l'inverso delle funzioni seno e coseno
In[118]:=
Out[118]=
In[123]:=
Out[123]=
ArcSin@1D
p
ÅÅÅÅ
2
ArcCos@Sqrt@2D ê 2D
p
ÅÅÅÅ
4
Sinh e Cosh calcolano rispettivamente il seno e coseno iperbolici, mentre ArcSinh e ArcCosh
indicano le corrispondenti funzioni inverse:
12
cap0.nb
In[136]:=
Out[136]=
In[138]:=
Out[138]=
Sinh@0D
0
Cosh@0D
1
1.5.4. Altre funzioni
Le funzioni Abs e Sign ritornano rispettivamente il valore assoluto e il segno di un numero (cioé -1
o 1 a seconda che il rispettivo argomento sia o meno negativo)
In[14]:=
Out[14]=
In[15]:=
Out[15]=
In[16]:=
Out[16]=
In[17]:=
Out[17]=
Abs@4D
4
Abs@-4D
4
Sign@4D
1
Sign@-4D
-1
Attenzione!
Le funzioni
Abs e Sign assumono un significato differente quando i loro argomenti sono numeri complessi. In
questo caso Abs[z] corrisponde al modulo di z e Sign[z] è uguale a z/Abs[z].
In[13]:=
Out[13]=
Sign@3 - ID
3-Â
ÅÅÅÅÅÅÅÅ
ÅÅÅÅ
è!!!!!!
10
cap0.nb
13
La funzione Round arrotonda il suo argomento all'intero più vicino
In[18]:=
Out[18]=
In[19]:=
Out[19]=
[email protected]
3
[email protected]
4
Le funzioni IntegerPart e FractionalPart ritornano rispettivamente le parti intera e frazionaria
di un numero reale
In[26]:=
Out[26]=
In[27]:=
Out[27]=
In[28]:=
Out[28]=
In[29]:=
Out[29]=
[email protected]
4
[email protected]
0.2
[email protected]
-4
[email protected]
-0.2
Attenzione! Se l'argomento di FractionalPart è un numero irrazionale espresso in forma esatta, il risultato sarà anch'esso
espresso in questa forma.
In[30]:=
Out[30]=
FractionalPart@PiD
-3 + p
La funzione Floor ritorna il più grande intero minore o uguale dell'argomento specificato;
analogamente, la funzione Ceiling ritorna il più piccolo intero maggiore o uguale
dell'argomento specificato
14
cap0.nb
In[31]:=
Out[31]=
In[32]:=
Out[32]=
In[33]:=
Out[33]=
In[34]:=
Out[34]=
Floor@PiD
3
Ceiling@PiD
4
Floor@-PiD
-4
Ceiling@-PiD
-3
Le funzioni Quotient e Mod ritornano rispettivamente il quoziente e il resto della divisione intera tra
il primo e il secondo argomento specificato
In[35]:=
Out[35]=
In[36]:=
Out[36]=
Quotient@10, 4D
2
Mod@10, 4D
2
1.6. Notazioni di presentazione degli argomenti
La notazione tipicamente utilizzata per calcolare una funzione viene indicata in una notazione prefissa
in cui il nome della funzione precede gli argomenti, delimitati in modo opportuno (da parentesi tonde
nell'usuale notazione matematica, da parentesi quadre nella sintassi di Mathematica in forma input o
standard). In realtà è possibile fare riferimento ad altre modalità:
una notazione postfissa, utilizzabile con funzioni che hanno un solo argomento. In questo caso
viene specificato prima l'argomento, poi due caratteri di barra capovolta o backslash ( \\) e
infine il nome della funzione
cap0.nb
In[224]:=
Out[224]=
15
x êê Log
Log@xD
questo tipo di notazione risulta indicata per scrivere velocemente un'espressione, quando non si
vuole appesantire un'espressione già complessa con un'ulteriore coppia di parentesi quadre, o
quando si vuole modificare una cella di input usandone il contenuto come unico argomento di
qualche funzione. In quest'ultimo caso è sufficiente aggiungere in coda all'espressione il doppio
backslash e il nome della funzione;
una notazione infissa, utilizzabile con funzioni che hanno due argomenti. In questo caso viene
specificato innanzitutto il primo argomento, seguito da un carattere di tilde ( ~), dal nome della
funzione, da un ulteriore carattere di tilde e dal secondo argomento
In[228]:=
Out[228]=
10 ~ Log ~ 1000
3
una forma alternativa della notazione prefissa per funzioni con un solo argomento, in cui si
indicano semplicemente il nome della funzione e l'argomento separandoli tramite un carattere di
"at" (@)
In[231]:=
Out[231]=
Log ü x
Log@xD
questo tipo di forma permette di scrivere velocemente un'espressione, eliminando il bisogno delle
parentesi quadre.
In generale queste notazioni e le relative abbreviazioni sono state introdotte per rendere più agevole
l'inserimento di espressioni in una cella. In realtà è necessario, di volta in volta, decidere se utilizzarle
o meno anche tenendo conto della misura in cui il loro utilizzo possa andare a migliorare o peggiorare
la leggibilità delle stesse espressioni.
1.7. Forme di visualizzazione dei dati
Consideriamo l'espressione I^Cos[x], indicante cioé il numero complesso ottenuto elevando l'unità
immaginaria al coseno di x. Tale espressione è espressa utilizzando le regole sintattiche di
Mathematica (quelle che stiamo gradualmente imparando), le quali si basano su due caratteristiche
importanti:
permettono di descrivere una qualunque espressione matematica in modo non ambiguo;
possono essere descritte utilizzando esclusivamente una descrizione puramente testuale (nel
senso che il contenuto che esse esprimono è espresso dai caratteri utilizzati e non dal loro stile).
16
cap0.nb
Le espressioni indicate utilizzando questa sintassi vengono dette espressioni in Input Form (o forma
di input); Mathematica implementa la funzione InputForm per convertire espressioni in questa forma:
In[198]:=
I ^ Cos@xD êê InputForm
Out[198]//InputForm=
I^Cos[x]
Nonostante la forma di input rappresenti un'interfaccia tramite cui inserire velocemente espressioni
matematiche all'interno di un notebook, la sua lettura può risultare difficile soprattutto quando non se
ne conosce bene la sintassi. Mathematica è però in grado di esprimere i dati utilizzando altre forme,
tant'è che se proviamo a valutare I+Log[x] otteniamo
In[199]:=
Out[199]=
I ^ Cos@xD
ÂCos@xD
e quindi una cella di output in cui la seconda delle caratteristiche sopra indicate non è più soddisfatta:
in questo caso infatti
l'unità immaginaria è indicata non più tramite la lettera I (che in particolare, essendo una "I"
maiuscola rappresenta un carattere ben preciso), bensì tramite il simbolo  ottenuto applicando
uno stile ben preciso (quello che Mathematica indica come il font di tipo Double Struck) al
carattere i;
l'operazione di elevamento a potenza viene indicata non più dal carattere ^ ma scrivendo
l'esponente come apice della alla base.
Attenzione! Non fatevi ingannare dal fatto che fino ad ora abbiamo indicato l'unità immaginaria utilizzando in ogni caso uno stile
differente (e cioé applicando alla lettera maiuscola "I" il font di tipo Courier): questo è dovuto al fatto che tutti i caratteri di
un'espressione in forma di input sono indicati con questo stile, in modo che queste espressioni risultino visualmente differenziate dal
testo.
Mathematica utilizza quindi una seconda forma di presentazione dei dati (tipicamente per le celle di
output), detta Standard Form o forma standard, in cui mantiene l'univocità della descrizione ma, per
migliorare la leggibilità, utilizza in alcuni casi la formattazione del testo per indicare un significato
particolare: ad esempio per indicare alcune costanti (come I ed E, che vengono rispettivamente
trasformate in  ed ‰) o alcune operazioni (come l'estrazione di radice o l'elevamento a potenza) che
vengono indicate nell'usuale modo tipografico.
La funzione StandardForm permette di convertire un'espressione in forma standard
cap0.nb
In[200]:=
17
I ^ Cos@xD êê StandardForm
Out[200]//StandardForm=
ÂCos@xD
Siccome la forma standard mantiene il requisito di descrivere un'espressione in modo univoco, è
possibile utilizzarla per inserire input in una cella
In[197]:=
Out[197]=
!2 ! 3
!5
Mathematica implementa un'ulteriore forma, detta Traditional Form o forma tradizionale, in cui i dati
vengono presentati in modo molto simile all'usuale notazione matematica: ad esempio le funzioni
vengono indicate utlizzando caratteri minuscoli, le variabili utilizzando lo stile corsivo e gli argomenti di
una funzione sono delimitati da parentesi tonde e non quadre. La funzione TraditionalForm permette
di esprimere un'espressione in forma tradizionale, evidenziata anche da una linea verticale a zig-zag
nel corrispondente delimitatore di cella:
In[201]:=
I ^ Cos@xD êê TraditionalForm
Out[201]//TraditionalForm=
ÂcosHx L
Va notato come la notazione in forma tradizionale possa risultare ambigua da interpretare. Ad
esempio l'espressione a(x+1) può indicare sia il valore che la funzione a assume in corrispondenza
dell'argomento x+1 che il prodotto tra i fattori a e x+1.
In[212]:=
a@x + 1D êê TraditionalForm
Out[212]//TraditionalForm=
aHx + 1L
In[213]:=
a Hx + 1L êê TraditionalForm
Out[213]//TraditionalForm=
a Hx + 1L
Attenzione!
E' possibile modificare la forma di presentazione di una cella anche selezionandone il corrispondente delimitatore e
scegliendo una delle voci del menù Cell/ConvertTo.
18
cap0.nb
Tenuto conto di questo, Mathematica implementa input e standard form in modo da risultare il più
possibile consistente. Il lettore interessato ad approfondire questo concetto può fare riferimento ai
primi capitoli del libro Exploring Mathematics with Mathematica, di John Glynn e Theodore Gray.
Mathematica implementa in realtà anche altre forme di rappresentazione dei dati: alcune, come
MatrixForm o Short, verranno introdotte nel seguito quando si renderanno necessarie; altre, come
TeXForm, non verranno introdotte. Il lettore interessato ad approfondire questo argomento può
consultare il manuale in linea.
1.8. Approssimazione di numeri
Quando si prova a calcolare il logaritmo naturale di 8 si ottiene
In[10]:=
Log@8D
Out[10]=
Log@8D
l'output è esattamente uguale all'input, perché il logaritmo naturale di 8 non è né un numero relativo né
un numero razionale, ma un numero reale non esprimibile in forma esatta se non come il logaritmo
naturale di 8. Per visualizzare questo numero in forma approssimata possiamo
indicare il suo argomento in forma approssimata, aggiungendovi il punto decimale:
In[38]:=
[email protected]
Out[38]=
2.07944
inserirlo in un'espressione matematica in cui compaia almeno un numero in forma approssimata:
In[40]:=
Out[40]=
Log@8D + 0.0
2.07944
Utilizzare la funzione N che, avuto come argomento un numero, calcola il suo valore approssimato:
In[36]:=
Out[36]=
N@Log@8DD
2.07944
Utilizzando la funzione N è possibile calcolare approssimazioni molto precise: infatti è possibile fornire
un secondo argomento che permette di specificare il numero di cifre significative da indicare
nell'approssimazione
cap0.nb
In[89]:=
Out[89]=
19
N@Log@8D, 100D
2.07944154167983592825169636437452970422650040308076576236204002848018086Ö
5909084146817589980989256063
In questo modo è ad esempio possibile scrivere approssimazioni molto accurate di p, ad esempio fino
alla centesima cifra:
In[90]:=
Out[90]=
N@p, 100D
3.14159265358979323846264338327950288419716939937510582097494459230781640Ö
6286208998628034825342117068
o alla millesima
In[91]:=
Out[91]=
N@p, 1000D
3.14159265358979323846264338327950288419716939937510582097494459230781640Ö
628620899862803482534211706798214808651328230664709384460955058223172535Ö
940812848111745028410270193852110555964462294895493038196442881097566593Ö
344612847564823378678316527120190914564856692346034861045432664821339360Ö
726024914127372458700660631558817488152092096282925409171536436789259036Ö
001133053054882046652138414695194151160943305727036575959195309218611738Ö
193261179310511854807446237996274956735188575272489122793818301194912983Ö
367336244065664308602139494639522473719070217986094370277053921717629317Ö
675238467481846766940513200056812714526356082778577134275778960917363717Ö
872146844090122495343014654958537105079227968925892354201995611212902196Ö
086403441815981362977477130996051870721134999999837297804995105973173281Ö
609631859502445945534690830264252230825334468503526193118817101000313783Ö
875288658753320838142061717766914730359825349042875546873115956286388235Ö
3787593751957781857780532171226806613001927876611195909216420199
Attenzione! Nel caso vi facciate prendere la mano, può capitare che chiediate a Mathematica di effettuare delle computazioni che
richiedono un tempo troppo elevato per essere portate a termine. In casi come queste potete terminare in anticipo la computazione
utilizzando la voce di menù Kernel/Abort Evaluation, o la combinazione di tasti CTRL-.
Le funzioni possono venire specificate, oltre che nella modalità seguita finora (detta forma prefissa, in
quanto il nome della funzione viene specificato prima dei suoi argomenti), anche in altre forme. In
particolare è disponibile una forma postfissa per le funzioni che hanno un solo argomento, che
consiste nello specificare prima l'argomento stesso, seguito da un doppio slash (//) e dal nome della
funzione. In altre parole
20
cap0.nb
In[92]:=
Out[92]=
p êê N
3.14159
ha lo stesso effetto di N[p].
Questa forma risulta spesso utile per migliorare la leggibilità di formule molto lunghe in quanto evita di
dover specificare un ulteriore coppia di parentesi quadre.
1.9. Espressioni
Un'espressione di Mathematica è definita nel seguente modo:
una costante (compreso un numero, in forma esatta o approssimata) è un'espressione;
se f è una funzione con un argomento e x è un'espressione che rappresenta un argomento valido
per f, allora f[x] è un'espressione. Analogamente, se g è una funzione con n argomenti e x1,
..., xn sono n espressioni che rappresentano argomenti validi per g (nel senso che x1 è
un'espressione che può rappresentare il primo argomento di g, x2 è un'espressione che può
rappresentare il suo secondo argomento e così via), allora g[x1,...,xn] è un'espressione.
L'ultimo dei due punti precedenti si estende facilmente al caso di operatori cioé funzioni, come la
somma, che vengono tipicamente utilizzati tramite una notazione prefissa o infissa, in cui il simbolo
che descrive l'operatore viene inserito in una posizione particolare e gli argomenti non vengono
delimitati tramite parentesi. Limitandosi agli operatori unari e binari (aventi cioé uno o due argomenti):
se U è un operatore unario e x è un'espressione che può essere considerata un argomento valido
per U, allora Ux è un'espressione: ad esempio -x è un'espressione valida, dove x è un numero e
- indica l'operatore unario di negazione;
se B è un operatore binario e x ed y sono due espressioni che possono essere considerate
argomenti validi per B, allora xBy è un'espressione; ad esempio se x ed y sono due numeri e +
indica la somma, allora x+y è un'espressione valida.
Merita maggiore attenzione il concetto di argomento valido: normalmente a ogni dato è associato un
tipo che ne riassume la natura e le caratteristiche (sono ad esempio tipi diversi i numeri in forma
esatta, quelli in forma approssimata, le parole). Ogni funzione è progettata per accettare argomenti di
un tipo ben definito, o di un definito insieme di tipi. Ad esempio la funzione Log accetta come
argomenti numeri, in forma esatta o approssimata, ma non avrebbe alcun senso pensare di calcolare il
logaritmo della parola "ciao" o della data odierna (e più avanti vedremo come Mathematica possa
trattare anche questi tipi di dati).
Attenzione! In realtà Mathematica implementa gli operatori esattamente come se fossero delle funzioni: ad esempio l'espressione
x+y viene convertita in Plus[x,y] prima di venire inviata al kernel, e la stessa conversione viene fatta in senso opposto per i
risultati che il kernel fornisce al notebook.
cap0.nb
21
Quando un'espressione contiene più funzioni innestate (ovvero funzioni in cui almeno un argomento è
rappresentato dal valore assunto da un'altra funzione), queste vengono valutate nell'unico modo
possibile, cioé partendo da quella più interna a quella più esterna: ad esempio nell'espressione
f@x, g@h@y, zDDD
le funzioni verranno valutate nel seguente ordine:
prima verrà valutata h quando y e z sono rispettivamente il suo primo e secondo argomento;
poi verrà valutata g utilizzando questo valore come argomento;
infine verrà valutata f utilizzando questo valore come secondo argomento e x come primo
argomento.
Quando invece in un'espressione compaiono più operatori, come ad esempio in x+y/z non è chiaro se
debba prima essere valutato l'operatore di divisione o quello di addizione. Per questo motivo si
rendono necessarie delle regole di precedenza che indicano quale debba essere l'ordine di
valutazione in casi come questo. Nell'ordine di valutazione implementato da Mathematica le operazioni
che abbiamo visto finora sono valutate secondo le usuali regole di precedenza:
fattoriale
elevamento a potenza
prodotto e quoziente
somma e sottrazione
E' possibile forzare un diverso ordine di valutazione degli operatori utilizzando le parentesi tonde:
In[258]:=
Out[258]=
In[259]:=
Out[259]=
x +yêz
y
x + ÅÅÅÅ
z
Hx + yL ê z
x+y
ÅÅÅÅÅÅÅÅÅÅÅÅ
z
1.10. Sostituzioni
Codice la cui forma generale è
8prima Ø dopo<
indica una sostituzione. L'operatore /. permette di applicare una sostituzione a una qualunque
espressione
22
cap0.nb
In[190]:=
Out[190]=
a + b ^ 2 + b c ê. 8b Ø 1 ê Pi<
1
c
a + ÅÅÅÅÅÅ
Å + ÅÅÅÅ
p2
p
Le sostituzioni sono tipicamente legate al modo in cui Mathematica presenta i risultati di equazioni.
1.11. Variabili
Nella costruzione di modelli matematici complessi risulta utile spezzare una computazione compelssa
in calcoli relativamente semplici.
aumentare la leggibilità del codice;
generare un risultato una sola volta per riutilizzarlo in molte occasioni;
generare un modello matematico in modo incrementale.
Per potere però utilizzare i risultati di queste computazioni è necessario che questi vengano salvati
una volta prodotti. Mathematica implementa questa funzionalità ricorrendo al concetto di variabile.
Tipicamente le variabili vengono viste come controparte dinamica delle costanti: infatti, mentre una
costante rappresenta un oggetto tramite cui utilizzando un nome simbolico ci si può riferire a un valore
che non varia nel tempo, utilizzando una variabile si utilizza sempre un nome simbolico, ma per riferirsi
a un valore che può variare nel tempo.
Quindi una variabile è accessibile tramite un nome, scelto dall'utente che la crea. Un nome valido è
costituito da una successione di caratteri di arbitraria lunghezza che non inizi con un numero, tenendo
conto che il linguiaggio di Mathematica è case sensitive: un carattere minuscolo e il corrispettivo
maiuscolo sono considerati diversi; quindi sono ad esempio nomi validi di variabili variabile,
Variabile, VARIABILE, vArIAbiLe, variabile1, unaVariabile e unAltraVariabile. In realtà ,
nonostante tutti questi nomi possano essere utilizzati, nella pratica si tiene conte delle cosiddette
regole di stile, in base a cui:
i nomi di una variabile composti da una sola parola sono scritti utilizzando esclusivamente lettere
minuscole. Nomi che iniziano con una lettera maiuscola sono riservati per costanti e funzioni già
implementate in Mathematica;
i nomi di una variabile composti da più parole sono scritti accorpando le varie parole, scritte con
caratteri minuscoli ma utilizzando i caratteri maiuscoli per le iniziali di ogni parola. Unica
eccezione è costituita dalla prima parola, che è composta esclusivamente da caratteri minusoli.
Quindi solo il primo e gli ultimi tre tra i nomi sopra elencati rappresentano nomi validi per una variabile.
Il carattere di uguale (=) viene utilizzato per indicare l'operatore di assegnamento che associa un
valore a una variabile. La sua sintassi è la seguente
nomeVariabile = < espressione >
cap0.nb
23
dove nomeVariabile è un nome valido per una variabile e <espressione> è un'espressione valida.
Durante l'esecuzione di questa oerazione, l'espressione viene valutata ed il suo risultato viene
assegnato alla variabile. Ad esempio l'assegnamento
In[261]:=
Out[261]=
a = 4+2
6
ha come esito l'assegnamento di 6 (il risultato di 4+2) alla variabile a. Si noti che il valore assegnato è
anche l'output corrispondente dell'operazione. Per verificare che l'assegnamento abbia effettivamente
avuto l'esito voluto possiamo valutare il valore di a:
In[264]:=
a
Out[264]=
6
infatti ogni nome di variabile, al pari delle costanti, rappresenta un'espressione valida.
Siccome tipicamente quando un valore viene memorizzato in una variabile non è necessario
visualizzarlo, è possibile inserire un carattere di punto e virgola (;) in coda all'operazione:
In[273]:=
a = 4 + 2;
In questo modo l'assegnamento viene eseguito senza generare alcun output. Mathematica può in
realtà generare due tipi diversi di output:
quello che va a comparire nelle celle di output, viene emesso quando valutando una cella questa
produce uno o più risultati. Questo tipo di output viene generato dalla maggior parte delle
istruzioni implementate da Mathematica, ovviamente a meno che la relativa visualizzazione non
sia disabilitata tramite l'uso del carattere di punto e virgola; E' importante tenere a mente come
questo tipo di output faccia riferimento a delle informazioni che possono essere memorizzate
e/o rielaborate in altre parti del codice.
quello il cui scopo è semplicemente il mostrare nel notebook un messaggio di qualche tipo, che
non viene poi utilizzato per ulteriori computazioni; in altre parole, il concetto di output
tipicamente usato dai programmatori per notificare delle informazioni a un utente. L'outupt di
questo tipo viene generato dall'istruzione Print, il cui argomento è un'espressione che viene
valutata e stampata.
In[93]:=
Print@Pi ^ 3D
p3
24
cap0.nb
Vale la pena di notare come l'output di un'istruzione Print, seppur contenuto in una cella di output,
non abbia dato origine all'emissione di un'etichetta Out, proprio perché non vi è stata alcuna
memorizzazione dell'output stesso.
Per evitare confusione, utilizzeremo la parola output per indicare la prima modalità e la parola
messaggio per indicare la seconda.
Attenzione!
Rimarchiamo un'interessante coincidenza: come abbiamo già detto, la maggior parte delle istruzioni di Mathematica
danno origine a un output. Questo significa che alcune istruzioni vengono eseguite senza generare un output. Un esempio di queste
istruzioni è rappresentato appunto da
Print, che non produce alcun output ma genera un messaggio. Un altro esempio si può
trovare nella funzione Clear, che vedremo tra poco: questa funzione non produce né output né messaggi.
Una volta assegnato un valore ad una variabile, questa è utilizzabile per eseguire altre computazioni:
hanno senso ad esempio le seguenti espressioni
In[279]:=
Out[279]=
In[281]:=
Out[281]=
a+1
6
Log@aD êê N
1.60944
In linea con i moderni linguaggi di programmazione, Mathematica mette a disposizione una serie di
operatori che permettono di abbreviare delle operazioni matematiche di uso comune:
l'operatore di autoincremento, indicato da un doppio segno di addizione ( ++), che applicato a una
variabile ne incrementa il valore di un'unità. Questo operatore può essere utilizzato sia in
notazione prefissa che in notazione postfissa. Pertanto sia ++a che a++ equivalgono
all'assegnamento a=a+1, ma avranno un comportamento differente qualora queste istruzioni
siano contenute in un'espressione. In particolare, qualora un'espressione contenga un'istruzione
di autoincremento prefisso, questa viene eseguita prima di valutare l'espressione: ad esempio
In[19]:=
Out[20]=
a = 5;
++a ê 2
3
In questo caso, la variabile a viene inizializzata al valore 5 e poi viene valutata l'espressione ++a/2.
Siccome questa espressione contiene un'autoincremento prefisso, prima il contenuto di a viene
incrementato di un'unità (assumento pertanto il valore 6), e poi viene valutata l'espressione a/2,
che appunto vale 3. Per conferma, possiamo verificare quale sia il valore contenuto in a:
cap0.nb
25
In[21]:=
a
Out[21]=
6
Quando invece l'espressione contiene un'istruzione di autoincremento postfisso, quest'ultima viene
eseguita solo dopo che l'espressione è stata valutata:
a = 5;
a ++ ê 2
In[22]:=
5
ÅÅÅÅ
2
Out[23]=
infatti, dopo l'inizializzazione a 5, viene prima valutata l'espressione a/2 (che appunto vale 5/2) e
poi il valore di a viene incrementato, come è facilmente verificabile anche in questo caso:
In[24]:=
a
Out[24]=
6
l'operatore di autodecremento, indicato da un doppio segno di differenza ( --), utilizzabile nelle
stesse modalità dell'operatore di autoincremento, che ha come effetto quello di diminuire il
contenuto di una variabile di un'unità:
a = 5;
--a
In[27]:=
4
Out[28]=
gli operatori di incremento e decremento (una generalizzazione degli operatori di autoincremento e
autodecremento), denotati rispettivamente con += e -=, che permettono di aggiungere o
sottrarre una data quantità al contenuto di una variabile. In altre parole, a+=x equivale ad a=a+x
e a-=x equivale ad a=a-x.
a = 1;
a += 2;
Print@aD;
In[1]:=
3
Infine, è possibile "cancellare" una variabile, come se non le avessimo mai assegnato alcun valore,
utilizzando la funzione Clear:
26
cap0.nb
In[29]:=
a = 5;
Clear@aD
In[31]:=
a
Out[31]=
a
Attenzione! E' importante ricordare che Mathematica gestisce le variabili dando loro una visibilità globale , nel senso che, una
volta definita, una variabile può essere letta e modificata in qualunque altra parte del notebook, o anche in altri notebook. Nel caso
capiti che in parti diverse del codice scritto compaiano due variabili con scopi differenti ma stesso nome, la modifica del valore di una di
queste si rifletterà anche sull'altra, con potenziali danni sul corretto funzionamento del codice. E' quindi importante sforzarsi di dare
nomi differenti a variabili differenti, tipicamente attribuendo dei nomi che ricordino il significato per cui ogni variabile è utilizzata. In realtà
è possibile, in alcuni casi, fare anche riferimento a variabili di tipo locale, la cui visibilità è ristretta a una ben precisa porzione di
codice su cui avranno anche effetto le modifiche apportate ai suoi contenuti.
1.12. Costruire nuove funzioni
Un'importante funzionalità di Mathematica consiste nella possibilità di estendere il suo linguaggio
aggiungendo delle funzioni definite dall'utente. Tale possibilità si basa sull'operatore di valutazione
posticipata :=, la cui sintassi nome:=espressione viene interpretata nel modo seguente: ogni qual
volta nel codice seguente si farà riferimento a nome, verrà valutata espressione. Ad esempio, il codice
In[12]:=
multiploPi := n Pi;
definisce multiploPi come valore l'espressione pari a n volte p, dove n è una variabile il cui valore verrà
valutato ogni volta che si farà riferimento a multiploPi:
In[12]:=
Out[13]=
In[14]:=
Out[15]=
n = 1;
multiploPi
p
n = 3;
multiploPi
3p
In realtà l'utilizzo della variabile n in questo caso è potenzialmente scorretto, in quanto potremmo non
essere sicuri che altre parti di codice non facciano riferimento ad essa, modificando implicitamente la
definizione di multiploPi. Per evitare inconvenienti di questo tipo e simultaneamente implementare
più correttamente una funzione come una corrispondenza tra argomenti e valori, Mathematica utilizza
la seguente sintassi
cap0.nb
27
funzione@argomento_D := espressione
dove
funzione è il nome scelto per la funzione;
:= rappresenta l'operatore di valutazione posticipata;
espressione rappresenta l'espressione che verrà valutata per produrre il valore della funzione;
argomento è il nome per l'argomento della funzione. Il carattere di underscore ( _) sta appunto ad
indicare che, quando si farà riferimento a questa nuova funzione specificando un argomento, il
valore di quest'ultimo verrà valutato e inserito all'interno di espressione in corrispondenza di
ogni occorrenza dell'insieme di caratteri argomento. Solo dopo questa operazione il sistema
provvederà a valutare espressione e a ritornare un valore.
Quindi la funzione multiploPi può venire implementata più correttamente nel seguente modo:
In[133]:=
multiploPi@n_D := n p
e valutata indicando i valori attuali del suo argomento tra parentesi quadre:
In[134]:=
Out[134]=
In[135]:=
Out[135]=
multiploPi@1D
p
multiploPi@7D
7p
Attenzione!
Se state eseguendo questo notebook, il sistema potrebbe emettere un errore quando valuta la definizione di
multiploPi, se avevate anche valutato le cella a inizio di questa sezione. Infatti in questo caso il
nome multiploPi è già stato associato a un altro valore. Per poter valutare queste ultime celle
sarà quindi necessario eliminare l'associazione tramite il comando Clear.
Nel caso una funzione abbia più di un argomento, la sintassi della definizione non cambia, a patto di
indicare tutti gli argomenti all'interno delle parentesi quadre separandoli tramite il carattere di virgola:
In[137]:=
logAllaEnne@x_, n_D := Log@xD ^ n
28
cap0.nb
1.13. Vincoli sugli argomenti di una funzione
1.13.1. Argomenti opzionali
E' possibile definire un argomento di una funzione come opzionale, facendo seguire il relativo
carattere di underscore dal carattere di due punti (:) e dal valore predefinito da assegnare
all'argomento qualora questo non venga specificato:
In[156]:=
cosAllaEnne@x_, n_: 2D := Cos@xD ^ n
In[157]:=
cosAllaEnne@x, 3D
Out[157]=
In[158]:=
Out[158]=
Cos@xD 3
cosAllaEnne@xD
Cos@xD 2
1.13.2. Argomenti tipizzati
E' possibile specificare il tipo di un argomento facendo seguire il relativo carattere di underscore da
Integer, Real, o Complex, per indicare rispettivamente che l'argomento deve essere di tipo intero,
reale o complesso.
Ad esempio possiamo definire la funzione fattoriale solo per argomenti interi:
In[159]:=
fattoriale@n_IntegerD := n !
in questo modo la funzione si comporta nel modo usuale quando chiamata con un argomento intero:
In[160]:=
Out[160]=
fattoriale@3D
6
se invece si utilizza un qualunque numero reale come argomento la funzione rimane non computata,
non essendone stato definito il comportamento in questi casi:
cap0.nb
In[161]:=
Out[161]=
29
fattoriale@PiD
fattoriale@pD
Va notato come il seguente comportamento della funzione
In[162]:=
[email protected]
Out[162]=
[email protected]
sia in realtà perfettamente consistente, dal momento che 3. è considerato un numero reale.
1.13.3. Argomenti vincolati
E' possibile specificare per gli argomenti di una funzione dei vincoli più complessi di quelli introdotti
nelle sezioni precedenti, facendo seguire il relativo carattere di underscore dalla sequenza di caratteri
/; e da una condizione. Ad esempio la definizione della funzione fattoriale vista nella precedente
sezione risulta mal definita se l'argomento, seppure intero, è negativo.
In[172]:=
Out[172]=
fattoriale@-4D
ComplexInfinity
Utilizzando /; è possibile fare in modo che la definizione venga applicata solo in caso di argomenti
positivi:
In[168]:=
fattoriale2@n_ ê; n > 0D := n !
In[173]:=
fattoriale2@4D
Out[173]=
24
Nel caso l'argomento fornito sia negativo, la funzione non verrà valutata
In[171]:=
fattoriale2@-4D
Out[171]=
fattoriale2@-4D
30
cap0.nb
Alternativamente l'operatore /; può essere inserito dopo quello di valutazione posticipata, a indicare
che l'applicazione di quest'ultimo è condizionata al soddisfacimento di una condizione. Ad esempio la
funzione fattoriale può essere definita come
In[174]:=
fattoriale3@n_D := n ! ê; n > 0
Naturalmente i vari tipi di vincoli sugli argomenti di una funzione possono essere combinati:
In[177]:=
fattoriale4@n_Integer ê; n > 0D := n !
Mathematica mette a disposizione una serie di funzioni booleane (i.e. funzioni che assumono solo i
valori True o False) che possono essere utilizzate per verificare svariate condizioni:
Less
Greater
LessEqual
GreaterEqual
NumberQ
NumericQ
IntegerQ
EvenQ
OddQ
PrimeQ
Positive
Negative
TrueQ
FreeQ
AtomQ
MatchQ
ValueQ
Ñ
Ñ
Ñ
Ñ
Ñ
Ñ
Ñ
Ñ
Ñ
Ñ
Ñ
Ñ
Ñ
Ñ
Ñ
Ñ
Ñ
Qualora per una funzione siano fatte più definizioni di tipo condizionale, nel momento in cui viene
specificato un argomento, le condizioni sono considerate in ordine cronologico di definizione fino a
quando non se ne trova una che risulta verificata dall'argomento, e viene utilizzata la definizione
corrispondente:
In[197]:=
f@x_D := 1 ê; x > 0;
f@x_D := 2 ê; EvenQ@xD;
In[202]:=
f@3D
Out[202]=
1
cap0.nb
In[203]:=
Out[203]=
In[204]:=
Out[204]=
31
f@2D
1
f@-2D
2
In[205]:=
f@-3D
Out[205]=
f@-3D
1.13.4. Funzioni con un numero variabile di argomenti
E' possibile specificare il comportamento di funzioni che hanno un numero variabile di argomenti,
indicando con un doppio carattere di underscore una sequenza di uno o più argomenti e con un triplo
carattere di underscore una sequenza di zero o più argomenti: ad esempio la definizione
In[246]:=
g@x___, a_, y___, a_, z___D := a
g@a___D := 0
implica che la funzione g, calcolata su un qualunque numero di argomenti, ritorna 0 a meno che due
argomenti abbiano lo stesso valore, che in questo caso coincide con il valore ritornato dalla funzione:
In[250]:=
Out[250]=
In[251]:=
Out[251]=
g@1, 2, 3, 4, 5, 6D
0
g@1, 2, 3, 4, 6, 6D
6
32
cap0.nb
1.13.5. Pattern
In Mathematica la definizione degli argomenti di una funzione rappresenta il caso particolare della
definizione di un pattern, cioé del denotatore di un insieme di espressioni. Il carattere di underscore
viene utilizzato per indicare una qualunque espressione, a cui è possibile assegare un nume di
riferimento, da far precedere al carattere stesso. Ciò permette di riutilizzare lo stesso pattern
una qualunque espressione
la somma di due espressioni
_
_+_
x ^ n_
un' espressione elevata a qualunque potenza
un' espressione elevata a qualunque potenza
il simbolo x elevato a qualunque potenza
f@n_, n_D
la funzione f calcolata su due argomenti identici
_^_
x_ ^ n_
1.13.6. Funzioni pure
Consideriamo la seguente definizione di una semplice funzione:
In[39]:=
f@x_D := x ê 2 + 1
La parte essenziale della definizione consiste nel descrivere come l'argomento viene modificato, e ciò
è indipendente dal nome che si è scelto per la funzione (avremmo potuto chiamarla g, h o
dimezzaEAggiungiUno, e il suo comportamento non sarebbe variato) e ancora di più dal nome che si
è deciso di dare al suo argomento ( x sta infatti ad indicare un valore formale, che verrà di volta in volta
rimpiazzato dal valore effettivamente inserito come parametro). Mathematica permette di definire una
funzione specificando solamente questo tipo di informazione essenziale: ad esempio la precedente
definizione della funzione f è equivalente a
In[42]:=
#ê2+ 1 &
in cui viene definita una funzione pura, in cui cioé non sono specificati nomi per la funzione stessa o
per il suo argomento: questo viene indicato dal carattere di cancelletto ( #), e la definizione è terminata
dal carattere di ampersand (&).
Una funzione pura, una volta definita, può essere usata all'interno di un'espressione: ad esempio
f = #ê2+ 1 &
In questo caso l'assegnamento riguarda l'intera funzione, e quindi permette di salvare la funzione
stessa per poterla riutilizzare in futuro. Oppure è possibile valutare la funzione
cap0.nb
In[44]:=
Out[44]=
33
# ê 2 + 1 &@1D
3
ÅÅÅÅ
2
In realtà le funzioni pure vengono tipicamente utilizzate come funzioni "usa e getta" da specificare
come argomenti di altre funzioni (cfr. ad esempio con la descrizione di Select o di Sort).
Nel caso si volesse definire una funzione pura con più di un argomento sarà sufficiente indicare il
primo argomento con #1, il secondo con #2, il terzo con #3 e così via:
In[43]:=
Out[43]=
#1 ê #2 &@3, 7D
3
ÅÅÅÅ
7
Attenzione!
E' sempre necessario terminare la definizione di una funzione pura utlizzando il carattere di ampersand, che serve
appunto a Mathematica per capire cosa all'interno di un'espressione deve essere interpretato come la descrizione di una funzione e
cosa no. Molti degli errori nel codice che utilizza funzioni pure sono legati all'omissione del carattere di ampersand.
1.14. Opzioni
Nelle precedenti sezioni abbiamo visto come utilizzare degli argomenti opzionali specificando dei
valori predefiniti. La soluzione adottata manteneva il carattere di posizionalità degli argomenti: ad
esempio, nella seguente funzione con quattro argomenti di cui gli ultimi due sono opzionali
In[253]:=
f@arg1_, arg2_, arg3_: 1, arg4_: 2D := 8arg1, arg2, arg3, arg4<
non è possibile specificare un valore esplicito per il quarto argomento utilizzando nel contempo il
valore predefinito per il terzo.
Un'altra possibilità di definire argomenti opzionali prescindendo dalla posizionalità degli stessi consiste
nel fare riferimento ad opzioni aventi un nome prefissato. Tale nome deve essere specificato per
modificare l'opzione corrispondente, in modo da permettere di modificare un qualunque sottoinsieme
delle opzioni possibili, indipendentemente dall'ordine in cui vengono indicate.
Per modificare un'opzione è necessario indicare il relativo nome, seguito dal carattere di freccia ( Ø) o
in alternativa dalla sequenza -> e infine dal valore a cui settare l'opzione. Consideriamo ad esempio la
funzione PrimeQ, che ritorna True se l'argomento passato è un numero primo e False altrimenti.
In[266]:=
Out[266]=
PrimeQ@5D
True
34
cap0.nb
In[276]:=
Out[276]=
PrimeQ@6D
False
Per visualizzare tutte le opzioni di una funzione, unitamente ai corrispondenti valori predefiniti, è
possibile utilizzare la funzione Options:
In[277]:=
Out[277]=
Options@PrimeQD
8GaussianIntegers Ø False<
L'opzione GaussianIntegers permette di verificare la primalità nel modo usuale quando è settata a
False e rispetto alla scomposizione in fattori complessi aventi parti reale e immaginaria intere quando
settata a True.
In[267]:=
Out[267]=
PrimeQ@5, GaussianIntegers Ø TrueD
False
1.15. Dare un nome alle cose
Come abbiamo visto nelle sezioni precedenti, Mathematica può essere esteso definendo dei nuovi
oggetti, che assumono la forma di variabili e di funzioni definite dall'utente. In entrambi i casi è
necessario specificare per questi oggetti un nome univoco, che va scelto rispettando l'unica regola
formale di non andare a utilizzare un nome già esistente. L'esito di questa operazione porterebbe
infatti a cancellare l'associazione tra il nome e il significato già esistente in favore di quello nuovo. In
realtà Mathematica implementa un meccanismo di protezione per i nomi che ne impedisce la
ridefinizione: se infatti proviamo ad esempio a ridefinire la funzione Tan otteniamo il seguente errore
In[125]:=
Tan@x_D := Sin@xD ê Cos@xD;
SetDelayed::write : Tag Tan in Tan@x_D is Protected. More…
che ci avvisa di come il nome Tan sia protetto, e cioé non ridefinibile.
Attenzione!
Il meccanismo di protezione è applicato automaticamente a tutti i comandi definiti da Mathematica ma è necessario
invocarlo esplicitamente per applicarlo a nomi di oggetti definiti dall'utente. Per maggiori informazioni fare riferimento alle funzioni
Protect e Unprotect.
Nella pratica si seguono però altre convenzioni nell'attribuzione dei nomi agli oggetti definiti dall'utente
che, nonostante la loro violazione non venga intercettata e segnalata da Mathematica come un errore,
contribuiscono a migliorare la leggibilià del codice prodotto. In particolare:
E' opportuno assegnare a una variabile o a una funzione l'esatto nome che avrebbe nel linguaggio
matematico. Questa convenzione, utilizzata per tutte le funzioni implementate in Mathematica,
ha il duplice vantaggio di: i) evitare di generare codice ambiguo da interpretare (in alcuni sistemi
Int sta a rappresentare la parte intera di un numero, in altri l'operatore di integrazione;
Mathematica usa rispettivamente IntegerPart e Integrate), e ii) permettere a un utente che
non conosce il nome esatto di una funzione di reperirlo facilmente conoscendo l'operazione
cap0.nb
35
E' opportuno assegnare a una variabile o a una funzione l'esatto nome che avrebbe nel linguaggio
matematico. Questa convenzione, utilizzata per tutte le funzioni implementate in Mathematica,
ha il duplice vantaggio di: i) evitare di generare codice ambiguo da interpretare (in alcuni sistemi
Int sta a rappresentare la parte intera di un numero, in altri l'operatore di integrazione;
Mathematica usa rispettivamente IntegerPart e Integrate), e ii) permettere a un utente che
non conosce il nome esatto di una funzione di reperirlo facilmente conoscendo l'operazione
matematiche che essa implementa.
Mathematica è case sensitive, nel senso che riconosce come differenti le versioni in minuscolo e in
maiuscolo di un carattere. In altre parole la parola log è riconosciuta e interpretata in modo
diverso dalla parola Log. Per convenzione, tutti i nomi definiti in Mathematica sono composti
accostando una serie di parole scritte in caratteri minuscoli, a eccezione delle inziali di ogni
singola parola (sono nomi definiti in Mathematica ad esempio Pi, E, I, Sqrt, InputForm e
FractionalPart). Per rimarcare la differenza tra gli oggetti predefiniti in Mathematica e quelli
aggiunti dall'utente, i nomi di questi ultimi seguono le stesse regole, con l'eccezione che iniziano
sempre con una lettera minuscola (come ad esempio la funzione multiploPi che abbiamo
definito nella sezione precedente).
L'utilizzo di queste regole ha lo svantaggio di generare spesso nomi composti da un elevato numero di
caratteri, che quindi risultano più complessi da immettere tramite la tastiera. Questo inconveniente può
essere evitato usando la funzione di completamento automatico dell'input: scrivendo parzialmente un
comando di Mathematica o il nome di un oggetto definito dall'utente e selezionando la voce di menù
Input/Complete Selection (o le combinazioni di tasti Ì-K su Macintosh, ‚-K su Windows e ‡-K
su Linux), il nome viene completato automaticamente qualora vi sia un solo oggetto che inizia
esattamente nel modo scritto; qualora esistano più alternative, queste vengono visualizzate in una lista
da cui è possibile scegliere il comando da scrivere. Se infine i caratteri immessi non corrispondono ad
alcun oggetto correntemente definito in Mathematica, il sistema tenta di interpretare l'input immesso e
visualizza un elenco di comandi simili a quanto inserito.
Qualora non si conosca esattamente quale sia il nome di una funzione o di una costante predefinite in
Mathematica, o quando non si ricordino esattamente quanti e quali argomenti ha una funzione, è
possibile utilizzare il sistema di help on-line per reperire le informazioni mancanti. Utilizzando la voce
di menù Help/Help browser è possibile visualizzare una finestra in cui:
ricercare informazioni relativamente a un oggetto di cui si conosce il nome, scrivendolo in
un'apposita area di testo: man mano che il testo viene scritto, automaticamente viene
visualizzata, all'interno di un elenco strutturato, la scelta più simile a quanto digitato. La
selezione di una voce in questo elenco permette di ottenere una descrizione dell'oggetto
corrispondente, dei rimandi sia a comandi simili che alla documentazione cartacea e una serie
di esempi di utilizzo;
percorrere l'elenco strutturato alla ricerca di informazioni di un oggetto di cui non si conosce il
nome esatto. La struttura presente permette di consultare, tra le altre cose: degli elenchi
alfabetici e gerarchici degli oggetti implementati che la digitalizzazione della documentazione
cartacea.
36
cap0.nb
Tale strumento di consultazione è anche disponibile su internet collegandosi tramite web browser al
sito http://documents.wolfram.com.
E' infine possibile selezionare una serie di caratteri in un notebook e consultare direttamente la
documentazione utilizzando la voce di menù Help/Find Selected Function (o le combinazioni di
tasti Ì-˜-F su Macintosh, ‚-˜-F su Windows e ‡-˜-F su Linux).
1.16. Stringhe
Una stringa è un insieme di caratteri. In Mathematica le stringhe vengono indicate racchiudendole tra
doppi apici:
In[11]:=
Out[11]=
"questa è una stringa"
questa è una stringa
Qualora fosse necessario inserire in una stringa il carattere di doppio apice, è sufficiente farlo
precedere dal carattere di backslash (\):
In[14]:=
Out[14]=
"questa è una stringa contenente il carattere doppio apice H\"L"
questa è una stringa contenente il carattere doppio apice H"L
Qualora fosse invece necessario inserire in una stringa il carattere di backslash, è sufficiente farlo
precedere da un altro carattere di backslash (\):
In[13]:=
Out[13]=
"questa è una stringa contenente il carattere di backslash H\\L"
questa è una stringa contenente il carattere di backslash H\L
E' essenziale inserire le stringhe entro doppi apici. In caso contrario il contenuto del messaggio verrà
intrepretato in modo differente. Se ad esempio la stringa precedente venisse inserita senza utilizzare i
doppi apici, otterremmo
In[145]:=
questa è una stringa
Out[145]=
è questa stringa una
in cui le singole parole sono state interpretate come simboli particolari (cfr. la sezione seguente sulle
variabili) che sono poi stati visualizzati in ordine alfabetico.
Mathematica implementa, tra le altre, le seguenti funzioni che agiscono su stringhe:
StringLength ritorna la lunghezza di una stringa, cioé il numero di caratteri in essa contenuti
cap0.nb
37
In[280]:=
Out[280]=
In[281]:=
Out[281]=
StringLength@"Stringa"D
7
StringLength@""D
0
StringJoin ritorna la stringa ottenuta giustapponendo le stringhe passategli come argomenti (in
un numero variabile):
In[283]:=
Out[283]=
StringJoin@"Questa ", "è ", "una", " stringa"D
Questa è una stringa
E' possibile utilizzare la sequenza <> come abbreviazione per StringJoin:
In[284]:=
Out[284]=
"Una " <> "stringa"
Una stringa
StringTake estrae una parte della stringa passata come primo argomento; il secondo argomento
determina quale parte estrarre
Formato
StringTake@"stringa",
StringTake@"stringa",
StringTake@"stringa",
StringTake@"stringa",
In[290]:=
Out[290]=
In[291]:=
Out[291]=
Esito
nD
Estrae i primi n caratteri
-nD
Estrae gli ultimi n caratteri
8n<D
Estrae il carattere in posizione n
8n, m<D Estrae i caratteri nelle posizioni dalla n alla m
StringTake@"Una stringa", 3D
Una
StringTake@"Una stringa", -3D
nga
38
cap0.nb
In[293]:=
Out[293]=
StringTake@"Una stringa", 83, 6<D
a st
StringDrop si comporta in modo duale rispetto a StringTake, di cui ha il medesimo formato: i
suoi due argomenti rappresentano rispettivamente una stringa e una serie di caratteri da
eliminare dalla stringa stessa per determinare il valore da ritornare:
In[294]:=
Out[294]=
In[295]:=
Out[295]=
StringDrop@"Una stringa", 3D
stringa
StringDrop@"Una stringa", 83, 6<D
Unringa
StringReplace effettua delle sostituzioni all'interno di una stringa, passata come primo argomento,
sulla base di una o più regole passate come secondo argomento. Una regola ha la forma
stringaoriginale Ø stringamodificata. Nel caso si vogliano specificare più regole è sufficiente
separarle tramite virgole e racchiudere l'intero gruppo in una coppia di parentesi graffe
(vedremo in seguito come questa operazione, a cui ci riferiremo come alla creazione di una
lista, sia altamente usata in tutti gli aspetti di Mathematica).
In[296]:=
Out[296]=
In[297]:=
Out[297]=
StringReplace@"Una stringa", "st" Ø "a"D
Una aringa
StringReplace@"abcde", 8"a" Ø "b", "b" Ø "c", "c" Ø "d", "d" Ø "e", "e" Ø "f"<D
bcdef
ToUpperCase e ToLowerCase ritornano la versione, rispettivamente formate da soli caratteri
maiuscoli e minuscoli, della stringa passata come argomento:
In[10]:=
ToUpperCase@"Stringa"D
ToLowerCase@"Stringa"D
Out[10]=
STRINGA
Out[11]=
stringa
cap0.nb
39
ToString accetta come argomento un'espressione di cui determina il valore che provvede poi a
trasformare in una stringa:
In[17]:=
Out[17]=
ToString@N@PiDD <> "b"
3.14159b
1.17. Liste
Una lista rappresenta un insieme di valori. Per fare riferimento a una lista in Mathematica è necessario
indicare i relativi valori separandoli tramite dei caratteri di virgola (,) e delimitando il tutto tramite una
coppia di parentesi graffe:
In[17]:=
Out[17]=
86, 5, 4, 3, 2, 1<
86, 5, 4, 3, 2, 1<
I valori contenuti in una lista possono avere natura eterogenea
In[18]:=
Out[18]=
81.4, Pi, "ciao"<
81.4, p, ciao<
Per accedere l'elemento di posto i una lista è sufficiente posporre alla lista stessa il numero i entro una
coppia di doppie parentesi quadre:
In[19]:=
Out[19]=
86, 5, 4, 3, 2, 1<@@4DD
3
Sono posizioni valide tutti i numeri interi che vanno da 1 al numero di elementi contenuti nella lista.
Qualora si specifichi come posizione un numero maggiore del numero di elementi nella lista, o un
numero non intero, Mathematica emetterà un errore:
In[24]:=
86, 5, 4, 3, 2, 1<@@10DD
Part::partw : Part 10 of 86, 5, 4, 3, 2, 1< does not exist. More…
Out[24]=
86, 5, 4, 3, 2, 1<P10T
40
cap0.nb
In[21]:=
86, 5, 4, 3, 2, 1<@@4.2DD
Part::pspec :
Part specification 4.2` is neither an integer nor a list of integers. More…
Out[21]=
86, 5, 4, 3, 2, 1<P4.2T
E' possibile specificare come posizione un numero negativo: in questo caso il conteggio delle posizioni
avverrà partendo dall'ultimo elemento e procedendo a ritroso: -1 indica l'ultimo elemento della lista, -2
il penultimo e così via:
In[25]:=
Out[25]=
86, 5, 4, 3, 2, 1<@@-3DD
3
E' infine possibile specificare 0 come posizione all'interno di una lista. Il risultato sarà List
indipendentemente dalla lista utilizzata:
In[26]:=
Out[26]=
In[27]:=
Out[27]=
86, 5, 4, 3, 2, 1<@@0DD
List
81.4, Pi, "ciao"<@@0DD
List
Il motivo di questo comportamento risiede nel modo in cui Mathematica memorizza l'input che gli viene
passato (cfr sezioni successive).
Fino ad ora abbiamo costruito liste in modo
elementi che vi appertenevano. Molto spesso
modo intensivo, indicando una proprietà che
stessa. Mathematica permette di definire liste
funzione Table, la cui sintassi è
estensivo, elencando cioé in modo esplicito tutti gli
è possibile (e anche più succinto) definire una lista in
viene soddisfatta da tutti e soli gli elementi della lista
utilizzando una variante di questa modalità, tramite la
Table@ < espressione >, < iteratore >D
dove
<iteratore> è una lista di tre elementi di cui il primo rappresenta il nome di una variabile e i
rimanenti sono espressioni valide; quindi {i,1,10}, {e,2^x,a} e {q,-a,E^4} sono iteratori
validi, mentre ad esempio {1,2,3} non lo è;
cap0.nb
41
<espressione> è un'espressione valida che tipicamente dipende dalla variabile che compare
nell'iteratore.
Gli elementi della lista costruita dalla funzione Table si ottengono nel seguente modo:
la variabile specificata nell'iteratore viene inizializzata al valore di partenza specificato in seconda
posizione nell'iteratore stesso;
se il valore della variabile non è superiore al valore finale specificato in terza posizione
nell'iteratore, viene valutata l'espressione passata come primo argomento a Table, e il risultato
viene aggiunto alla lista;
il valore della variabile viene incrementato di un'unità e il punto precedente viene nuovamente
eseguito.
Ad esempio
In[139]:=
Out[139]=
In[140]:=
Out[140]=
In[141]:=
Out[141]=
Table@i, 8i, 1, 5<D
81, 2, 3, 4, 5<
Table@2 i, 8i, 1, 5<D
82, 4, 6, 8, 10<
Table@2 ^ i, 8i, 1, 5<D
82, 4, 8, 16, 32<
1.17.1. Forme alternative per gli iteratori
E' possibile fare riferimento alle seguenti forme alternative per definire un iteratore:
Nella forma a quattro elementi, è possibile indicare di quanto incrementare di volta in volta la
variabile. In altre parole la forma {variabile, inizio, fine} inizialmente introdotta equivale a
{variabile, inizio, fine, 1}. Ciò permette ad esempio di inserire i numeri pari in una lista in modo
più intuitivo
In[142]:=
Out[142]=
Table@i, 8i, 2, 10, 2<D
82, 4, 6, 8, 10<
o di effettuare conteggi al contrario
42
cap0.nb
In[143]:=
Out[143]=
Table@i ê 2, 8i, 10, 1, -1<D
9
7
5
3
1
95, ÅÅÅÅ , 4, ÅÅÅÅ , 3, ÅÅÅÅ , 2, ÅÅÅÅ , 1, ÅÅÅÅ =
2
2
2
2
2
Nella forma a due elementi vengono specificati solamente il nome della variabile e il valore finale. Il
valore iniziale e l'incremento vengono implicitamente settati al valore predefinito 1. Pertanto
l'iteratore {variabile, fine} equivale a {variabile, 1, fine}, o equivalentemente a {variabile, 1, fine,
1}.
In[9]:=
Out[9]=
Table@i, 8i, 10<D
81, 2, 3, 4, 5, 6, 7, 8, 9, 10<
Nella forma a un elemento si specifica esclusivamente il valore finale. Anche in questo caso il
valore iniziale e l'incremento sono settati a 1, ma non viene esplicitamente fatto riferimento ad
alcuna variabile. Tale tipologia di iteratore è utile nella definizione di liste costanti:
In[10]:=
Out[10]=
Table@1, 810<D
81, 1, 1, 1, 1, 1, 1, 1, 1, 1<
1.17.2. Funzioni per le liste
Length ritorna il numero di elementi della lista passatagli come argomento:
In[26]:=
Out[26]=
Length@85, 4, 3, 2, 1<D
5
Part è l'equivalente delle doppie parentesi quadre: ritorna parte del contenuto di una lista che gli
viene passata come primo argomento. Quando il secondo argomento è un numero, viene
ritornato l'elemento nella posizione corrispondente; quando è una lista, vengono ritornati gli
elementi nelle posizioni specificatevi, a loro volta racchiuse in una lista:
In[18]:=
Out[18]=
Part@85, 4, 3, 2, 1<, 2D
4
cap0.nb
43
In[21]:=
Out[21]=
Part@85, 4, 3, 2, 1<, 82, 4<D
84, 2<
come per le doppie parentesi quadre, se una posizione negativa indica che il conteggio va fatto a
ritroso a partire dall'ultimo elemento della lista.
First e Last ritornano rispettivamente il primo e l'ultimo elemento di una lista
In[19]:=
First@85, 4, 3, 2, 1<D
Last@85, 4, 3, 2, 1<D
Out[19]=
5
Out[20]=
1
Rest ritorna la lista passata come argomento dopo avervi rimosso il primo elemento:
In[28]:=
Out[28]=
Rest@85, 4, 3, 2, 1<D
84, 3, 2, 1<
Take ritorna i valori di una lista (passata come primo argomento) che occupano posizioni
successive: in particolare, se il secondo argomento è un intero n, verranno ritornati i primi o gli
ultimi n elementi, a seconda che n sia positivo o negativo:
In[22]:=
Out[22]=
Take@85, 4, 3, 2, 1<, 2D
85, 4<
se invece il secondo argomento è {n, m}, con n minore o uguale a m, verranno ritornati tutti gli
elementi dalla m-esima alla n-esima posizione (estremi inclusi)
In[31]:=
Out[31]=
Take@85, 4, 3, 2, 1<, 82, 4<D
84, 3, 2<
Drop elimina da una lista (passata come primo argomento) una o più posizioni (specificate dal
secondo argomento, secondo la stessa codifica usata per Part) e ritorna la lista risultante
44
cap0.nb
In[24]:=
Out[24]=
In[25]:=
Out[25]=
Drop@85, 4, 3, 2, 1<, 2D
83, 2, 1<
Drop@85, 4, 3, 2, 1<, 82, 4<D
85, 1<
Select determina quali elementi di una lista (passata come primo argomento) verificano un
criterio, specificato come secondo argomento nella forma di una funzione che ritorna True o
False. Tale funzione può essere una delle funzioni predefinite di Mathematica
In[45]:=
Out[45]=
Select@81, 2, 3, 4, 5<, EvenQD
82, 4<
In realtà molto spesso è necessario ricorrere dei criteri più sofisticati, che possono essere introdotti
esternamente tramite la definizione di una funzione apposita
In[48]:=
Out[49]=
criterio@x_D := x > 2 && x § 4;
Select@81, 2, 3, 4, 5<, criterioD
83, 4<
in alternativa è possibile introdurre i criteri direttamente all'interno di Select, tramite la definizione
di una funzione pura
In[47]:=
Out[47]=
Select@81, 2, 3, 4, 5<, # > 2 && # § 4 &D
83, 4<
Cases funziona in modo analogo a Select, con la differenza che il criterio viene rappresentato
tramite un pattern piuttosto che tramite una funzione booleana:
In[7]:=
Out[7]=
Cases@82 ^ 2, E ^ 4, 1 ê x, a, x ^ Pi, Log@xD, 1 + x ^ 7<, _ ^ _D
1
9‰4 , ÅÅÅÅ , xp =
x
cap0.nb
45
In[8]:=
Out[8]=
Cases@82 ^ 2, E ^ 4, 1 ê x, a, x ^ Pi, Log@xD, 1 + x ^ 7<, x ^ _D
1
9 ÅÅÅÅ , xp =
x
Attenzione! Il simbolo 2^2 non fa parte dell'output di Cases, in quanto viene semplificato in 4 prima dell'esecuzione.
Il comportamento di Cases è simile a quello di altre due funzioni: Count e Position, che ritornano
rispettivamente il numero e la posizione degli elementi di una lista che combaciano con un dato
pattern:
In[9]:=
Count@82 ^ 2, E ^ 4, 1 ê x, a, x ^ Pi, Log@xD, 1 + x ^ 7<, _ ^ _D
Out[9]=
3
In[10]:=
Position@82 ^ 2, E ^ 4, 1 ê x, a, x ^ Pi, Log@xD, 1 + x ^ 7<, _ ^ _D
Out[10]=
882<, 83<, 85<, 87, 2<<
Prepend e Append inseriscono un elemento in testa e in coda ad una lista, rispettivamente
In[13]:=
Out[13]=
In[14]:=
Out[14]=
Prepend@81, 2, 3<, 0D
80, 1, 2, 3<
Append@81, 2, 3<, 4D
81, 2, 3, 4<
Insert aggiunge un elemento in una lista, specificando la posizione che questo andrà ad
assumere. Delete rimuove da una lista l'elemento in una data posizione. ReplacePart modifica
l'elemento di una lista in una specifica posizione:
In[15]:=
Out[15]=
Insert@81, 2, 3, 4<, 2.5, 3D
81, 2, 2.5, 3, 4<
46
cap0.nb
In[16]:=
Out[16]=
In[17]:=
Out[17]=
Delete@81, 2, 3, 4<, 3D
81, 2, 4<
ReplacePart@81, 2, 3, 4<, 2.5, 3D
81, 2, 2.5, 4<
Join unisce due o più liste:
In[20]:=
Out[20]=
Join@8a, b, c<, 8d, e, f<D
8a, b, c, d, e, f<
Union, Intersection e Complement implementano rispettivamente l'unione, l'intersezione e il
complemento di liste interpretate come se fossero degli insiemi
In[23]:=
Out[23]=
In[21]:=
Out[21]=
In[22]:=
Out[22]=
Union@8a, b, c, d<, 8c, d, e, f<D
8a, b, c, d, e, f<
Intersection@8a, b, c, d<, 8c, d, e, f<D
8c, d<
Complement@81, 2, 3, 4, 5<, 82, 4<D
81, 3, 5<
Sort ordina gli elementi di una lista. Nella sua versione standard, i dati vengono arrangiati in
ordine non decrescente
In[24]:=
Out[24]=
Sort@81, 5, 7, 4, 3, 6<D
81, 3, 4, 5, 6, 7<
è possibile indicare un secondo argomento che specifica un criterio su cui basare l'ordinamento,
consistente una funzione di due argomenti che ritorna True se il primo argomento deve
comparire prima del secondo.
cap0.nb
In[26]:=
Out[26]=
47
Sort@81, 5, 7, 4, 3, 6<, #2 < #1 &D
87, 6, 5, 4, 3, 1<
1.18. Visualizzazione di liste
Consideriamo la seguente lista
In[456]:=
lista = 81, 5, 3, 9, 4, 8<;
e analizziamo i possibili modi di elencarne gli elementi. In generale il contenuto di una lista può essere
visualizzato:
in forma estensiva, elencando i suoi elementi tramite l'usuale notazione
In[457]:=
Out[457]=
lista
81, 5, 3, 9, 4, 8<
in forma tabulare, scrivendo ogni elemento su una riga differente tramite la funzione TableForm
In[270]:=
lista êê TableForm
Out[270]//TableForm=
1
5
3
9
4
8
in forma grafica, usando la funzione ListPlot per rappresentare ogni elemento tramite un punto
che ha come ordinata il valore dell'elemento stesso e come ascissa la sua posizione all'interno
della lista
48
cap0.nb
ListPlot@listaD
In[273]:=
8
6
4
2
Out[273]=
3
4
5
6
Ü Graphics Ü
Attenzione!
La funzione
ListPlot, oltre a produrre e visualizzare un grafico, ritorna il grafico stesso come oggetto (che in
realtà corrisponde a un tipo particolare di lista). E' per questo che in corrispondenza della cella di input è stata prodotta una cella di
output il cui contenuto è - Graphics -. L'uso del carattere di punto e virgola permette di eliminare quest'ultima visualizzazione.
La funzione ListPlot è corredata da un considerevole numero di opzioni:
In[275]:=
Out[275]=
Options@ListPlotD
1
9AspectRatio Ø ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ , Axes Ø Automatic, AxesLabel Ø None,
GoldenRatio
AxesOrigin Ø Automatic, AxesStyle Ø Automatic, Background Ø Automatic,
ColorOutput Ø Automatic, DefaultColor Ø Automatic,
DefaultFont ß $DefaultFont, DisplayFunction ß $DisplayFunction,
Epilog Ø 8<, FormatType ß $FormatType, Frame Ø False, FrameLabel Ø None,
FrameStyle Ø Automatic, FrameTicks Ø Automatic, GridLines Ø None,
ImageSize Ø Automatic, PlotJoined Ø False, PlotLabel Ø None,
PlotRange Ø Automatic, PlotRegion Ø Automatic, PlotStyle Ø Automatic,
Prolog Ø 8<, RotateLabel Ø True, TextStyle ß $TextStyle, Ticks Ø Automatic=
tra queste, l'unica opzione che si riferisce espressamente a ListPlot è PlotJoined, settabile a True
o False, che permette di decidere se il grafico deve essere fatto congiungendo i punti tra di loro:
cap0.nb
49
ListPlot@lista, PlotJoined Ø TrueD;
In[272]:=
8
6
4
2
3
4
5
6
tutte le altre opzioni agiscono sul modo in cui viene prodotto l'oggetto grafico.
1.19. Liste innestate
Una lista può contenere elementi di natura eterogenea: ad esempio la lista
In[31]:=
Out[31]=
8Pi, N@PiD, "Pi"<
8p, 3.14159, Pi<
contiene il valore esatto di p, il suo valore approssimato e la stringa "Pi" rispettivamente in prima,
seconda e terza posizione. Più in generale è possibile costruire liste che annoverino tra i loro elementi
altre liste
In[34]:=
listaInnestata = 8Pi, N@PiD, "Pi", 81, 2, 3<<;
tali liste vengono dette di tipo innestato. I loro elementi vengono acceduti nel modo usuale, tenuto
conto del fatto che ora un elemento può essere una lista
In[37]:=
listaInnestata@@1DD
listaInnestata@@4DD@@1DD
Length@listaInnestata@@4DDD
Out[37]=
p
Out[38]=
1
Out[39]=
3
50
cap0.nb
Qualora l'argomento di ListPlot sia una lista composta esclusivamente da liste di due elementi,
ognuna di queste liste viene interpretata come la descrizione di un punto nel piano (con l'usuale
codifica in cui il primo elemento corrisponde all'ascissa e il secondo all'ordinata).
In[40]:=
listaPunti = 883, 1<, 87, 5<, 88, 3<, 89, 9<, 81, 4<, 82, 8<<;
ListPlot@listaPunti, PlotJoined Ø TrueD;
8
6
4
4
6
8
Il contenuto di una lista innestata è visualizzabile anche in forma tabulare utilizzando la funzione
TableForm:
In[42]:=
listaPunti êê TableForm
Out[42]//TableForm=
3
7
8
9
1
2
1
5
3
9
4
8
Questa funzione ha il vantaggio di poter essere utilizzata anche con liste aventi una struttura più
complessa di quelle utilizzabili con ListPlot:
In[43]:=
listaComplicata = 881, 2, 3, 4<, 8a, b, c, d<, 8A, B, C, D<, 8i, ii, iii, iv<<;
listaComplicata êê TableForm
Out[44]//TableForm=
1
a
A
i
2
b
B
ii
3
c
C
iii
4
d
D
iv
cap0.nb
51
in particolare, la visualizzazione prodotta da TableForm è particolarmente significativa con liste a una
o due dimensioni o livelli. In realtà Mathematica permette di gestire anche liste con più livelli.
In alcuni casi si rende necessario trasformare una lista innestata in una lista semplice, o più in
generale di ridurre il numero di livelli di una lista, "fondendo" assieme i livelli superiori. Questa
operazione viene realizzata in Mathematica dalla funzione Flatten, che riduce qualunque lista
passatagli a una lista a un solo livello:
In[60]:=
Out[60]=
In[64]:=
Out[64]=
Flatten@881, 2, 3<, 8a, b, c<<D
81, 2, 3, a, b, c<
Flatten@888a, b<, 8A, B<<, 88x, y<, 8X, Y<<<D
8a, b, A, B, x, y, X, Y<
Nel caso si voglia fondere solo un determinato numero di livelli, è sufficiente specificare tale numero
come secondo argomento
In[65]:=
Out[65]=
Flatten@888a, b<, 8A, B<<, 88x, y<, 8X, Y<<<, 1D
88a, b<, 8A, B<, 8x, y<, 8X, Y<<
1.20. Matrici e vettori
Le liste vengono frequentemente utilizzate per codificarvi dei vettori.
In[47]:=
vettore1 = 81, 0, 1<;
vettore2 = 81, 1, 0<;
Mathematica predispone una serie di funzioni che agiscono su liste interpretandone il contenuto come
se fossero dei vettori:
Dot e Cross implementano rispettivamente i prodotti scalare e vettore. Dot può essere utilizzando
il simbolo di punto (.) in modalità infissa (cioé tra i due operatori)
In[50]:=
Out[50]=
vettore1.vettore2
1
52
cap0.nb
In[51]:=
Out[51]=
Cross@vettore1, vettore2D
8-1, 1, 1<
Norm calcola la norma Euclidea di un vettore. Se viene specificato come secondo argomento un
numero p, viene calcolata la p-norma (dove p può essere infinito)
In[52]:=
Out[52]=
In[58]:=
Out[58]=
In[59]:=
Out[59]=
Norm@vettore1D
è!!!
2
Norm@vettore1, 5D
21ê5
Norm@vettore1, ¶D
1
Analogamente, liste a due dimensioni possono essere utilizzate per memorizzare delle matrici.
Mathematica mette a disposizione la funzione MatrixForm per visualizzare una lista formattandola nel
modo usato tipicamente per indicare le matrici:
In[66]:=
matr = 881, 0, 1<, 81, 1, 0<, 80, 0, 1<<;
matr êê MatrixForm
Out[67]//MatrixForm=
1 0 1y
i
j
z
j
z
j
j
1 1 0z
z
j
z
j
z
k0 0 1{
Come per il caso dei vettori, è possibile utilizzare una serie di funzioni specializzate nella
manipolazione di matrici:
Gli operatori di somma e sottrazione sono sovraccaricati in modo da funzionare correttamente con
le matrici
cap0.nb
In[68]:=
53
matr + matr êê MatrixForm
Out[68]//MatrixForm=
2 0 2y
i
j
z
j
z
j
j
2 2 0z
z
j
z
j
z
k0 0 2{
analogamente, l'operatore usato per il prodotto scalare tra vettori può essere utilizzato anche per
moltiplicare tra di loro due matrici
In[70]:=
matr.matr êê MatrixForm
Out[70]//MatrixForm=
1 0 2y
i
j
z
j
z
j
j
2 1 1z
z
j
z
j
z
k0 0 1{
e' possibile generare automaticamente le matrici identità di una generica dimensione tramite la
funzione IdentityMatrix
In[79]:=
IdentityMatrix@3D êê MatrixForm
Out[79]//MatrixForm=
1 0 0y
i
j
z
j
z
j
j
0 1 0z
z
j
z
j
z
k0 0 1{
Transpose calcola la trasposta di una matrice
In[72]:=
Transpose@matrD êê MatrixForm
Out[72]//MatrixForm=
1 1 0y
i
j
z
j
z
j
z
j
j0 1 0z
z
j
z
k1 0 1{
Inverse calcola l'inversa di una matrice
In[75]:=
matrInv = Inverse@matrD;
matrInv êê MatrixForm
Out[76]//MatrixForm=
i 1 0 -1 y
j
z
j
z
j
j
-1 1 1 z
z
j
z
j
z
k 0 0 1 {
54
cap0.nb
In[77]:=
matr.matrInv êê MatrixForm
Out[77]//MatrixForm=
1 0 0y
i
j
z
j
z
j
j
0 1 0z
z
j
z
j
z
k0 0 1{
Det calcola il determinante di una matrice
In[80]:=
Out[80]=
Det@matrD
1
Eigenvalues ritorna una lista contenente gli autovalori della matrice passatagli come argomento.
Analogamente Eigenvectors calcola gli autovettori, indicandoli come una lista di vettori (che in
ultima analisi è una lista di liste di due elementi)
In[85]:=
Out[86]=
In[87]:=
Out[87]=
matr1 = 881, 3<, 83, 3<<;
Eigenvalues@matr1D
92 +
è!!!!!!
è!!!!!!
10 , 2 - 10 =
Eigenvectors@matr1D
1
1
è!!!!!!
è!!!!!!
99-1 + ÅÅÅÅ I2 + 10 M, 1=, 9-1 + ÅÅÅÅ I2 - 10 M, 1==
3
3
1.20.1. Una digressione: opzioni per gli oggetti di tipo Graphics
Abbiamo visto come utilizzando ListPlot sia possibile produrre grafici contenenti punti o linee
spezzate. In realtà è possibile utilizzare Mathematica per produrre grafici utilizzando strumenti più
complessi. Quali che siano questi strumenti, è possibile specificare delle direttive che modificano il
modo in cui il grafico viene visualizzato. Ad esempio
PlotRange, che indica quale intervallo degli assi cartesiani debba essere visualizzato. E' possibile
specificare come valore per questa opzione una lista a uno o due livelli. Nel primo caso la lista
contiene due valori che indicano quale intervallo visualizzare per l'asse delle ordinate, nel
secondo la lista contiene due liste che indicano quale intervallo visualizzare rispettivamente per
l'asse delle ascisse e delle ordinate. E' possibile utilizzare al posto di una di queste liste il
simbolo Automatic: in questo caso Mathematica determinerà automaticamente quale intervallo
visualizzare.
cap0.nb
In[129]:=
55
listaPunti = 883, 1<, 87, 5<, 88, 3<, 89, 9<, 81, 4<, 82, 8<<;
ListPlot@listaPunti, PlotJoined Ø TrueD;
8
6
4
4
In[131]:=
6
8
ListPlot@listaPunti, PlotJoined Ø True, PlotRange Ø 80, 10<D;
10
8
6
4
2
4
6
8
56
cap0.nb
ListPlot@listaPunti, PlotJoined Ø True, PlotRange Ø 880, 10<, Automatic<D;
In[132]:=
8
6
4
2
In[133]:=
4
6
8
10
ListPlot@listaPunti, PlotJoined Ø True, PlotRange Ø 880, 10<, 80, 8<<D;
8
7
6
5
4
3
2
1
2
4
6
8
10
AxesOrigin permette di specificare in che punto gli assi cartesiani devono incrociarsi. Può infatti
capitare (come ad esempio visto in alcuni dei grafici precedenti) che il punto di incrocio sia
diverso dall'usuale origine degli assi.
cap0.nb
57
In[134]:=
ListPlot@listaPunti, PlotJoined Ø True, AxesOrigin Ø 80, 0<D;
8
6
4
2
2
4
6
8
va notato come in questo caso la modifica di AxesOrigin porta a un grafico in cui una parte degli
assi cartesiani non viene visualizzata. Questo è dovuto a una precisa scelta degli sviluppatori di
Mathematica. Quando si vogliono visualizzare gli assi cartesiani fino al loro punto di
intersezione, in casi come questo è necessario modificare anche l'opzione PlotRange:
In[135]:=
ListPlot@listaPunti, PlotJoined Ø True,
AxesOrigin Ø 80, 0<, PlotRange Ø 880, 9<, 80, 10<<D;
10
8
6
4
2
2
4
6
8
PlotLabel e AxesLabel permettono di specificare eventuali valori con cui etichettare l'intero
grafico e gli assi cartesiani, rispettivamente, inserendo nel secondo caso i due valori in una lista.
Nel caso non si volesse specificare l'etichetta per un particolare asse, è sufficiente utilizzare il
valore None:
58
cap0.nb
In[136]:=
ListPlot@listaPunti, PlotJoined Ø True,
AxesOrigin Ø 80, 0<, PlotRange Ø 880, 9<, 80, 10<<,
AxesLabel Ø 8x, None<, PlotLabel -> "Una sequenza"D;
Una sequenza
10
8
6
4
2
2
4
6
8
x
Axes e Frame sono opzioni settabili a True o False, che determinano qualora il grafico debba
visualizzare anche gli assi cartesiani e una cornice che lo contorni.
In[137]:=
ListPlot@listaPunti, PlotJoined Ø True,
PlotLabel -> "Una sequenza", Axes Ø False, Frame Ø TrueD;
Una sequenza
8
6
4
2
2
4
6
8
AspectRatio determina quale sarà il rapporto tra l'altezza e la larghezza del grafico
cap0.nb
59
In[138]:=
ListPlot@listaPunti, PlotJoined Ø True, PlotLabel -> "Una sequenza",
Axes Ø False, Frame Ø True, AspectRatio Ø 0.4D;
Una sequenza
8
6
4
2
2
4
6
8
il valore predefinito per AspectRatio è 1/GoldenRatio, il che significa che alcuni grafici possono
risultare "schiacciati". Il valore Automatic, corrispondente a 1, permette di generare grafici in cui
larghezza e altezza hanno le stesse unità di misura.
Ticks permette di specificare i punti sugli assi di cui sarà visualizzato il relativo valore. E'
necessario indicare una lista contenente due liste, ognuna indicante i valori da visualizzare
rispettivamente sull'asse delle ascisse e delle ordinate. Anche in questo caso è possibile
utilizzare None o Automatic per indicare che non si vogliono visualizzare valori o che si lascia a
Mathematica la scelta.
In[139]:=
ListPlot@listaPunti, PlotJoined Ø True, AxesLabel Ø 8x, y<,
Ticks Ø 881, 3, 5, 7, 9<, 82, 3, 4<<, AxesOrigin Ø 81, 1<D;
y
4
3
2
3
5
7
9
x
FrameTicks ha un comportamento analogo a Ticks, ma agisce sui bordi della cornice. Pertanto la
sua specificazione comprende quattro liste al posto di due.
60
cap0.nb
In[140]:=
ListPlot@listaPunti, PlotJoined Ø True,
PlotLabel -> "Una sequenza", Axes Ø False, Frame Ø True,
FrameTicks Ø 88Pi, 2 Pi<, Automatic, None, None<D;
Una sequenza
8
6
4
2
p
2p
Attenzione! I valori specificati in Ticks e FrameTicks possono essere anche numeri reali, come in quest'ultimo esempio.
In alcuni casi queste diretttive vengono usate come valore che modifica l'opzione PlotStyle,
racchiudendole tra parentesi graffe nel caso si voglia indicare più di una direttiva. Tra le direttive
utilizzabili per ListPlot, le più frequentemente utilizzate sono
PointSize, che indica quale debba essere il diametro dei punti utilizzati (se non viene attivata
l'opzione PlotJoined)
In[141]:=
listaPunti = 883, 1<, 87, 5<, 88, 3<, 89, 9<, 81, 4<, 82, 8<<;
ListPlot@listaPunti, PlotStyle Ø [email protected];
8
6
4
4
6
8
cap0.nb
61
Attenzione! Il valore specificato per il diametro va espresso come frazione rispetto all'ampiezza complessiva del grafico. E' quindi
opportuno specificare valori molto piccoli.
GrayLevel permette di specificare il colore del grafico all'interno di una scala di grigi,
indipendentemente dal fatto che questo sia stato prodotto utilizzando dei punti o una linea. Il suo
argomento è un numero tra 0 e 1, dove 0 indica il nero e 1 il bianco.
In[162]:=
listaPunti = 883, 1<, 87, 5<, 88, 3<, 89, 9<, 81, 4<, 82, 8<<;
ListPlot@listaPunti, PlotStyle Ø [email protected], [email protected]<D;
ListPlot@listaPunti, PlotStyle Ø [email protected], PlotJoined Ø TrueD;
8
6
4
4
6
8
4
6
8
8
6
4
RGBColor permette di specificare il colore del grafico indicando le corrispondenti componenti nei
colori fondamentali rosso, verde e blu. Questo viene fatto specificando per ognuna componente
un numero tra 0 e 1.
62
cap0.nb
In[165]:=
ListPlot@listaPunti, PlotStyle Ø [email protected], 0, 0.5D, PlotJoined Ø TrueD;
8
6
4
4
6
8
Dashing permette di specificare come tratteggiare le linee tracciate. Il suo argomento è una lista
che indica la lunghezza di segmenti consecutivi: il primo numero indica quanto deve essere
lungo il primo segmento, il secondo quanto deve essere lungo il primo spazio, il terzo quanto
deve essere lungo il secondo segmento e così via. Quando la lista è terminata si ricomincia a
utilizzarne il primo valore. Tutti i valori sono indicati rispetto all'ampiezza totale del grafico.
In[182]:=
ListPlot@listaPunti, PlotStyle Ø [email protected]<D, PlotJoined Ø TrueD;
ListPlot@listaPunti,
PlotStyle Ø [email protected], 0.02, 0.08<D, PlotJoined Ø TrueD;
8
6
4
4
6
8
cap0.nb
63
8
6
4
4
6
8
Thickness permette di specificare lo spessore delle linee tracciate, rispetto all'ampiezza totale del
grafico.
In[185]:=
ListPlot@listaPunti, PlotStyle Ø [email protected], PlotJoined Ø TrueD;
8
6
4
4
6
8
1.21. Oggetti di tipo grafico
Mathematica è in grado di generare altri tipi di grafici oltre a insiemi di punti e linee spezzate. In
particolare è possibile costruire degli oggetti di tipo grafico contenenti una o più istanze dei seguenti
oggetti fondamentali:
Point[{x,y}] ritorna un punto le cui coordinate sono contenute nella lista usata come argomento.
Line[{{x1,y1},...,{xn,yn}}] ritorna una linea spezzata i cui segmenti sono delimitati dai punti
contenuti nella lista usata come argomento; in particolare quando questa lista contiene solo due
punti viene generato un segmento.
Circle[{x,y},r] ritorna un cerchio i cui centro e raggio sono indicati rispettivamente dal primo e
secondo argomento usati.
64
cap0.nb
La funzione Graphics trasforma questi oggetti in oggetti grafici visualizzabili tramite Show:
In[207]:=
a = Line@880, 1<, 81, 3<, 82, 5<<D;
b = Graphics@aD;
Show@bD;
Va evidenziato che i grafici generati non includono gli assi cartesiani e fanno riferimento al valore
predefinito di AspectRatio. Quest'ultimo aspetto risulta più evidente quando si visualizza un cerchio:
In[210]:=
a = Circle@80, 0<, 1D;
b = Graphics@aD;
Show@bD;
in questo caso otteniamo qualcosa che ha un aspetto diverso da quello che ci saremmo aspettati:
proprio per il fatto che le distanze lungo i due assi cartesiani vengono misurate utilizzando unità
differenti, il cerchio appare "schiacciato" in un'ellissi. Per riparare a questo inconveniente è sufficiente
impostare l'opzione AspectRatio al valore Automatic:
cap0.nb
In[213]:=
65
a = Circle@80, 0<, 1D;
b = Graphics@aD;
Show@b, AspectRatio Ø Automatic, Axes Ø TrueD;
1
0.5
-1
-0.5
0.5
1
-0.5
-1
In realtà Mathematica mette a disposizione anche altri tipi fondamentali di oggetti grafici. Fate riferimento al manuale per scoprire quali
sono.
Per generare un grafico contenente più oggetti fondamentali si possono seguire due strade:
generare singolarmente i vari oggetti e poi mostrarli assieme in un'unica chiamata alla funzione
Show:
66
cap0.nb
In[216]:=
linea = Graphics@Line@880, 0<, 81, 1<<DD;
cerchio = Graphics@Circle@81 ê 2, 1 ê 2<, 1 ê 2DD;
Show@linea, cerchio, AspectRatio Ø AutomaticD;
generare i vari oggetti tramite la stessa istruzione Graphics, che può accettare come argomento
una lista di oggetti fondamentali:
cap0.nb
In[219]:=
67
Show@Graphics@8Line@880, 0<, 81, 1<<D, Circle@81 ê 2, 1 ê 2<, 1 ê 2D<D,
AspectRatio Ø AutomaticD;
E' infine possibile generare oggetti specificando valori non predefiniti per l'opzione PlotStyle, anche
se in modo differente rispetto a quanto visto per ListPlot: in questo caso è necessario specificare in
modo differente l'argomento passato a Graphics, che ora consterà di una lista contenente i valori per
PlotStyle seguiti dall'oggetto o dagli oggetti che si vogliono disegnare
68
In[228]:=
cap0.nb
Show@Graphics@[email protected]<D, [email protected], Circle@80, 0<, 1D<D,
AspectRatio Ø AutomaticD;
Nel caso si voglia produrre un grafico in cui a oggetti differenti sono associati diversi valori per le
opzioni di PlotStyle, è sufficiente utilizzare come argomento di Graphics una lista innestata, i cui
elementi sono le singole liste contenenti le opzioni di PlotStyle:
cap0.nb
In[234]:=
69
Show@Graphics@88RGBColor@0, 1, 0D, [email protected],
Line@880, 0<, 80, 1<, 81 ê 2, Sqrt@3D ê 2<, 80, 0<<D<, [email protected]<D,
[email protected], Circle@80, 0<, 1D<<D, AspectRatio Ø AutomaticD;
1.22. Visualizzare grafici di quantità continue
Mentre la funzione ListPlot ha lo scopo di tracciare il grafico di un insieme discreto di punti, la
funzione Plot ritorna un oggetto di tipo grafico che approssima il grafico di una funzione continua nei
suoi argomenti. Il suo formato è
Plot@espressione, rangeD
dove espressione indica un'espressione, che dipende in modo continuo da una variabile simbolica, di
cui si vuole disegnare il grafico, e range indica il range della variabile relativamente al grafico stesso,
espresso nella forma {variabile, inizio fine}, molto simile a quella di un iteratore.
70
In[145]:=
cap0.nb
Plot@x, 8x, 0, 2 Pi<D;
6
5
4
3
2
1
1
2
3
4
5
6
Qualora il primo argomento di Plot sia una lista di espressioni, i relativi grafici vengono visualizzati nel
medesimo oggetto di tipo grafico:
In[147]:=
Plot@8x, x ^ 2<, 8x, 0, 2<D;
4
3
2
1
0.5
1
1.5
2
E' necessario porre molta attenzione ai grafici prodotti da Plot. Se ad esempio si prova a visualizzare il
2
grafico di e-x tra -5 e 5
cap0.nb
In[155]:=
71
Plot@E ^ H-x ^ 2L, 8x, -5, 5<D;
0.3
0.25
0.2
0.15
0.1
0.05
-4
-2
2
4
si ottiene un grafico troncato nella parte centrale. Questo è dovuto all'algoritmo che Mathematica
utilizza per produrre l'output. L'oggetto grafico ritornato da Plot è infatti una linea spezzata ottenuta
nel seguente modo:
l'intervallo su cui graficare la funzione viene diviso in parti di uguale lunghezza, dove il numero di
parti è specificato dal valore dell'opzione PlotPoints. In ogni punto di divisione viene valutata
la funzione e viene generata una linea spezzata passante per i punti così ottenuti;
ogni volta che l'angolo tra due parti di linea spezzata successive è maggiore del valore specificato
nell'opzione MaxBend, gli intervalli corrispondenti per la variabile indipendente vengono divisi in
due e viene riapplicato l'algoritmo; questo algoritmo adattivo viene applicato in modo che un
intervallo non venga suddiviso in due per più del numero di volte specificato nell'opzione
PlotDivision (per evitare di suddividere all'infinito segmenti al cui interno cade un asintoto
verticale).
E' quindi per questo motivo che il grafico sopra visualizzato non è completo: l'algoritmo di suddivisione
ha erroneamente inferito che nella parte centrale vi fosse un asintoto. In questo caso è possibile
specificare manualmente un valore per l'opzione PlotRange
72
In[156]:=
cap0.nb
Plot@E ^ H-x ^ 2L, 8x, -5, 5<, PlotRange Ø 80, 1<D;
1
0.8
0.6
0.4
0.2
-4
-2
2
4
in alternativa è possibile specificare un valore abbastanza basso per l'opzione MaxBend
In[178]:=
Plot@E ^ H-x ^ 2L, 8x, -5, 5<, MaxBend Ø .1D;
1
0.8
0.6
0.4
0.2
-4
-2
2
4
E' possibile visualizzare quali sono i punti usati da Plot per campionare la funzione? Intuitivamente la
risposta dovrebbe essere sì, a patto di poter estrarre informazioni sulla linea spezzata che approssima
il grafico. Se salviamo l'oggetto grafico prodotto e andiamo a guardarne i contenuti otteniamo
cap0.nb
In[179]:=
73
graph = Plot@x, 8x, 0, 1<D;
Length@graphD
1
0.8
0.6
0.4
0.2
0.2
Out[180]=
In[181]:=
Out[181]=
In[182]:=
Out[182]=
0.4
0.6
0.8
1
2
graph@@0DD
Graphics
graph@@1DD
[email protected] µ 10-8 , 4.16667 µ 10-8 <,
80.040567, 0.040567<, 80.0848088, 0.0848088<, 80.126359, 0.126359<,
80.166318, 0.166318<, 80.208853, 0.208853<, 80.249795, 0.249795<,
80.293313, 0.293313<, 80.335239, 0.335239<, 80.375574, 0.375574<,
80.418484, 0.418484<, 80.459802, 0.459802<, 80.499529, 0.499529<,
80.541831, 0.541831<, 80.582542, 0.582542<, 80.625827, 0.625827<,
80.667521, 0.667521<, 80.707624, 0.707624<, 80.750302, 0.750302<,
80.791388, 0.791388<, 80.835049, 0.835049<, 80.877119, 0.877119<,
80.917597, 0.917597<, 80.96065, 0.96065<, 81., 1.<<D<<
74
In[183]:=
Out[183]=
cap0.nb
graph@@2DD
1
9PlotRange Ø Automatic, AspectRatio Ø ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ ,
GoldenRatio
DisplayFunction ß $DisplayFunction, ColorOutput Ø Automatic,
Axes Ø Automatic, AxesOrigin Ø Automatic, PlotLabel Ø None,
AxesLabel Ø None, Ticks Ø Automatic, GridLines Ø None, Prolog Ø 8<,
Epilog Ø 8<, AxesStyle Ø Automatic, Background Ø Automatic,
DefaultColor Ø Automatic, DefaultFont ß $DefaultFont,
RotateLabel Ø True, Frame Ø False, FrameStyle Ø Automatic,
FrameTicks Ø Automatic, FrameLabel Ø None, PlotRegion Ø Automatic,
ImageSize Ø Automatic, TextStyle ß $TextStyle, FormatType ß $FormatType=
vediamo come l'oggetto ritornato sia in realtà una lista (rappresentante, come sapevamo, un oggetto
grafico) il cui primo elemento è proprio la linea spezzata che ci interessa, e il cui secondo elemento è
un riepilogo delle opzioni grafiche da applicare. Sarà quindi sufficiente estrarre gli argomenti della
funzione List contenuta nel primo elemento e usare ognuno di essi come argomento di funzioni
Point. La funzione Map ci permette di fare tutto ciò in modo agevole.
In[184]:=
plotPoints = Graphics@
Join@8AbsolutePointSize@3D<, Map@Point, graph@@1DD@@1DD@@1DD@@1DDDDD;
Show@graph, plotPointsD;
1
0.8
0.6
0.4
0.2
0.2
0.4
0.6
0.8
1
per poter studiare il comportamento di Plot conviene definire una funzione plotWithPoints che
abbia lo stesso formato di Plot ma che visualizzi anche i punti su cui si basa il grafico prodotto:
In[186]:=
plotWithPoints@f_, range_D := Block@8graph<,
graph = Plot@f, rangeD;
points = Graphics@
Join@8AbsolutePointSize@3D<, Map@Point, graph@@1DD@@1DD@@1DD@@1DDDDD;
Show@graph, pointsD
D
cap0.nb
In[187]:=
75
plotWithPoints@x, 8x, 0, 1<D;
1
0.8
0.6
0.4
0.2
0.2
0.4
0.6
0.8
1
0.2
0.4
0.6
0.8
1
1
0.8
0.6
0.4
0.2
Nonostante la funzione assolva allo scopo che ci eravamo prefissi, ha un fastidioso effetto collaterale:
quando al suo interno viene chiamata Plot, il grafico corrispondente viene sempre visualizzato. Per
evitare la visualizzazione è possibile ridefinire plotWithPoints facendo uso dell'opzione
DisplayFunction, specificabile sia in Plot che in Show: quando questa è settata a Identity l'oggetto di
tipo grafico viene prodotto ma non visualizzato, mentre quando è settata a $DisplayFunction
l'oggetto viene anche visualizzato. E' inoltre opportuno permettere la specificazione di altre opzioni:
In[193]:=
Clear@plotWithPointsD;
plotWithPoints@f_, range_, opts___D := Block@8graph<,
graph = Plot@f, range, opts, DisplayFunction Ø IdentityD;
points = Graphics@
Join@8AbsolutePointSize@3D<, Map@Point, graph@@1DD@@1DD@@1DD@@1DDDDD;
Show@graph, points, DisplayFunction Ø $DisplayFunctionD
D
76
In[195]:=
cap0.nb
plotWithPoints@x, 8x, 0, 1<D;
1
0.8
0.6
0.4
0.2
0.2
0.4
0.6
0.8
1
In questo caso il numero di punti iniziali è sufficiente, in quanto graficando una linea retta i vincoli sugli
angoli tra segmenti successivi sono automaticamente rispettati. Il grafico non sarebbe cambiato nel
caso avessimo usato un valore basso per PlotPoints:
In[202]:=
plotWithPoints@x, 8x, 0, 1<, PlotPoints Ø 3D;
1
0.8
0.6
0.4
0.2
0.2
0.4
0.6
0.8
1
Le cose cambiano se invece si visualizza una funzione non lineare:
cap0.nb
In[171]:=
77
plotWithPoints@Sin@xD, 8x, 0, 2 Pi<D;
1
0.5
1
2
3
4
5
6
-0.5
-1
In[200]:=
plotWithPoints@Sin@xD, 8x, 0, 2 Pi<, PlotPoints Ø 2D;
1
0.5
1
-0.5
-1
2
3
4
5
6
78
In[176]:=
cap0.nb
plotWithPoints@E ^ H-x ^ 2L, 8x, -5, 5<, MaxBend Ø 100D;
1
0.8
0.6
0.4
0.2
-4
-2
2
4
1.23. Altri grafici di quantità continue
ParametricPlot permette di generare il grafico di una funzione espressa in forma parametrica:
In[246]:=
ParametricPlot@8Sin@tD, Cos@tD<,
8t, 0, 2 Pi<, AspectRatio Ø 1, PlotPoints Ø 50D;
1
0.5
-1
-0.5
0.5
1
-0.5
-1
Anche in questo caso è necessario fare attenzione a settare opportunamente il valore dell'opzione
PlotPoints:
cap0.nb
In[266]:=
79
a = ParametricPlot@t 8Sin@tD, Cos@tD<, 8t, 0, 50 Pi<,
AspectRatio Ø Automatic, DisplayFunction Ø IdentityD;
b = ParametricPlot@t 8Sin@tD, Cos@tD<, 8t, 0, 50 Pi<,
AspectRatio Ø Automatic, PlotPoints Ø 20, DisplayFunction Ø IdentityD;
Show@GraphicsArray@8a, b<DD;
150
150
100
100
50
50
-150
-100-50
-50
50 100150
-150
-100-50
-50
-100
-100
-150
-150
50 100150
In questo caso abbiamo usato la funzione GraphicsArray che permette di visualizzare più oggetti
grafici disponendoli in righe e/o in colonne.
La funzione Plot3D funziona in modo analogo a Plot, con la differenza che permette di graficare
funzioni che dipendono da due argomenti. Anche in questo caso è necessario verificare che l'algoritmo
di campionamento che produce il grafico si comporti in modo corretto, modificando i valori per
PlotRange e/o PlotPoints nel caso si ottenesse un risultato falsato:
In[248]:=
Plot3D@E ^ H-Hx ^ 2 + y ^ 2LL, 8x, -5, 5<, 8y, -5, 5<D;
0.004
4
0.002
2
0
0
-4
-2
-2
0
2
-4
4
80
In[269]:=
cap0.nb
Plot3D@E ^ H-Hx ^ 2 + y ^ 2LL, 8x, -5, 5<, 8y, -5, 5<, PlotRange Ø 80, 1<D;
1
0.8
0.6
0.4
0.2
0
4
2
0
-4
-2
-2
0
2
-4
4
In[272]:=
Plot3D@E ^ H-Hx ^ 2 + y ^ 2LL, 8x, -5, 5<,
8y, -5, 5<, PlotRange Ø 80, 1<, PlotPoints Ø 40D;
1
0.8
0.6
0.4
0.2
0
4
2
0
-4
-2
-2
0
2
-4
4
ContourPlot e DensityPlot generano grafici contenenti rispettivamente le curve di livello e i valori di
densità di una funzione di due variabili:
cap0.nb
In[280]:=
81
a = ContourPlot@E ^ H-Hx ^ 2 + y ^ 2LL,
8x, -2, 2<, 8y, -2, 2<, DisplayFunction Ø IdentityD;
b = DensityPlot@E ^ H-Hx ^ 2 + y ^ 2LL, 8x, -2, 2<,
8y, -2, 2<, DisplayFunction Ø IdentityD;
Show@GraphicsArray@8a, b<DD;
2
2
1
1
0
0
-1
-1
-2
-2
-1
0
1
2
-2
-2
-1
0
1
2
1.24. Un'altra digressione: la ruota dei colori
Mathematica mette a disposizione, oltre a RGBColor, un'ulteriore funzione che genera un colore. Hue
permette infatti di generare colori specificando le corrispondenti componenti nella scala HSB (Hue,
Saturation, Brightness) come numeri compresi tra 0 e 1. In particolare il primo di questi valori varia in
modulo 1, nel senso che quando la corrispondente componente vale 0 il colore ritornato fa parte della
scala del rosso e man mano che il valore aumenta, il colore si sposta prima nella scala del verde, poi
in quella del blu, per ritornare infine ancora nella scala dei rossi.
La seguente cella utilizza questa informazione per generare la ruota dei colori. In che modo funziona
(suggerimento: ricordatevi come funziona il passaggio in coordinate polari)?
In[95]:=
stepRho = 100;
stepTheta = 700;
Show@Graphics@Table@8Hue@theta ê H2 PiL, rho, 1D,
AbsolutePointSize@2D, Point@8rho Cos@thetaD, rho Sin@thetaD<D<,
8theta, 0, 2 Pi, 2 Pi ê stepTheta<, 8rho, 0, 1, 1 ê stepRho<DD,
Axes Ø True, AspectRatio Ø AutomaticD;
1.25. Le parentesi
Per quanto visto finora:
le parentesi tonde delimitano una parte di espressione da valutare senza seguire le regole di
precedenza predefinite per gli operatori matematici;
le parentesi quadre delimitano gli argomenti di una funzione;
le parentesi graffe delimitano il contenuto di una lista;
le doppie parentesi quadre delimitano una precisa posizione all'interno di una lista.
82
cap0.nb
1.26. Programmare con Mathematica
Mathematica implementa le seguenti strutture per la programmazione
If[test, istruzione_true,
istruzione_false] realizza la struttura di selezione tra due
alternative;
Switch[espressione, valore_1, istruzione_1, ...] realizza la struttura di selezione tra un
numero finito di alternative, basandosi sui possibili valori assunti da un'espressione;
Which[test1, istruzione_1, ...] realizza una struttura di selezione tra un numero finito di
alternative;
For[inizio, test, incremento, istruzione] realizza una struttura di iterazione enumerata;
Do[espressione, iteratore] realizza una struttura di iterazione enumerata;
While[test, istruzione] realizza una struttura di iterazione condizionata.
Block[{var_locali}, istruzioni] realizza una procedura con una serie di variabili locali. E'
possibile eseguire più iterazioni separandole con il carattere di punto e virgola. L'esito dell'ultima
istruzione senza un carattere di punto e virgola sarà il valore ritornato dalla procedura.
Verificate utilizzando l'help in linea la loro sintassi e la loro semantica e utilizzatele per scrivere dei
semplici algoritmi che agiscono sulle strutture di cui abbiamo parlato. Ad esempio, verificate come
l'istruzione
In[188]:=
Do@ListPlot@Table@Sin@2 Pi ê i jD, 8j, 1, 2 Pi, 0.01<DD, 8i, 1, 10, 0.2<D;
1
0.5
100
-0.5
-1
dia luogo a un'animazione.
200
300
400
500
cap0.nb
83
1.27. Importare ed esportare dati
E' possibile importare dati esterni per elaborarli con Mathematica e, analogamente, esportare risultati
di elaborazioni effettuate. Siccome per effettuare queste operazioni è spesso necessario interagire con
il file system, è necessario capire dove Mathematica legge e scrive documenti su disco. Come in molti
altri programmi, in assenza di informazioni specifiche viene utilizzata una directory predefinita, il cui
nome viene visualizzato quando si esegue la funzione Directory
In[464]:=
Out[464]=
Directory@D
êUsersêmalchiod
e impostato utilizzando la funzione SetDirectory
In[467]:=
SetDirectory@"êUsersêmalchiodêDesktopêDarioêEditoriaêLibriêMathematica"D;
Attenzione!
Ovviamente le directory indicate nei comandi precedenti fanno riferimento a directory presenti nel computer
dell'autore. Pertanto se eseguite il comando senza modificarne l'argomento otterrete con alta probabilità un messaggio di errore.
Il comando Import legge un file e lo interpreta in termini dell'oggetto di Mathematica più opportuno per
descriverne
i
contenuti.
Se
ad
esempio
nella
directory
/Users/malchiod/
Desktop/Dario/Editoria/Libri/Mathematica è presente un file dal nome prova.csv il cui
contenuto è il seguente
1, 2, 3, 4, 5
a, b, c, d, e
in cui ogni riga indica una serie di dati, separati da virgole, che si riferiscono a uno stesso record (e
infatti l'estensione CSV indica il formato comma separated values, cioé "valori separati da virgole"),
l'esito di Import sarà
In[479]:=
Out[479]=
Import@"prova.csv"D
881, 2, 3, 4, 5<, 8a, b, c, d, e<<
e quindi
ogni riga di input è stata interpretata come l'elemento di una lista;
gli elementi di questa lista sono a loro volte liste che contengono tutti i valori indicati in una data
riga.
Nel caso si tentasse di usare Import con un file non esistente nella directory, verrà visualizzato un
messaggio di errore:
84
cap0.nb
Import@"QuestoFileNonEsiste.csv"D
In[469]:=
Import::nffil :
File not found during [email protected], CSVD. More…
Out[469]=
$Failed
in realtà in casi come questo Mathematica effettua la ricerca in una serie di directory il cui nome è
contenuto nella variabile $Path:
In[462]:=
Out[462]=
$Path
8êApplicationsêMathematica 5.0.appêAddOnsêJLink,
êApplicationsêMathematica 5.0.appêAddOnsêNETLink,
êUsersêmalchiodêLibraryêMathematicaêKernel,
êUsersêmalchiodêLibraryêMathematicaêAutoload,
êUsersêmalchiodêLibraryêMathematicaêApplications,
êLibraryêMathematicaêKernel, êLibraryêMathematicaêAutoload,
êLibraryêMathematicaêApplications, ., êUsersêmalchiod,
êApplicationsêMathematica 5.0.appêAddOnsêStandardPackages,
êApplicationsêMathematica 5.0.appêAddOnsêStandardPackagesêStartUp,
êApplicationsêMathematica 5.0.appêAddOnsêAutoload,
êApplicationsêMathematica 5.0.appêAddOnsêApplications,
êApplicationsêMathematica 5.0.appêAddOnsêExtraPackages,
êApplicationsêMathematica 5.0.appêSystemFilesêGraphicsêPackages,
êApplicationsêMathematica 5.0.appêConfigurationêKernel<
Attenzione!
Anche in questo caso l'output del comando dipende fortemente dal particolare computer su cui è stato eseguito il
notebook.
Import è in grado di riconoscere le estensioni di alcuni formati comuni, oltre a quello CSV. E'
comunque possibile specificare un secondo argomento per indicare esplicitamente il formato da
utilizzare. In altre parole, l'istruzione
In[470]:=
Import@"prova.csv", "CSV"D
avrebbe avuto lo stesso esito. E' possibile specificare, tra le altre, le opzioni: EmptyField, che indica
come debba essere intrepretato un dato mancante, FieldSeparator, che indica quale sia il carattere
che separa un dato dall'altro, e Numeric, che indica se le quantità lette che indicano un valore
numerico debbano essere convertite o mantenute come stringhe.
Altri formati supportati sono
Lines, che ritorna una lista contenente un elemento per ogni riga del file letto
cap0.nb
85
In[474]:=
Out[474]=
Import@"prova.csv", "Lines"D
81,2,3,4,5, a,b,c,d,e<
nonostante l'output possa sembrare fuorviante, la lista ritornata contiene solo due elementi: lo
possiamo evincere dal fatto che questi sono separati da una virgola seguita da uno spazio, oppure
procedendo a un'ispezione diretta
In[475]:=
Out[475]=
%@@1DD
1,2,3,4,5
List, che ritorna una lista contenente un elemento per ogni parola del file letto
Table, che funziona in modo simile a List, ma ritorna una lista bidimensionale che per ogni riga
del file letto contiene un elemento, che a sua volta è una lista composta da tutte le parole
contenute nella riga.
TSV, che funziona in modo simile a CSV, ma che separa i dati utilizzando il carattere di tabulazione
al posto della virgola.
In realtà Import riconosce anche tipi di dati non necessariamente numerici o simbolici
In[486]:=
Out[486]=
In[487]:=
Import@"mela.gif"D
Ü Graphics Ü
Show@%D;
86
In[489]:=
cap0.nb
logo = Import@"x.jpg"D;
Show@logoD;
L'elenco dei formati riconosciuti è lungo, e comprende formati per il suono, per l'output di particolari
programmi che manipolano espressioni e dati numerici, e per gestire dati descritti tramite XML. Per un
elenco dettagliato fate riferimento al manuale.
Utilizzando la funzione ImportString è infine possibile importare dati non da un file esterno, ma
interpretando il contenuto di una stringa
In[496]:=
Out[496]=
ImportString@"1,2,3,4,5\n6,7,8,9", "CSV"D
881, 2, 3, 4, 5<, 86, 7, 8, 9<<
E' altresì possibile effettuare l'operazione inversa di esportazione, cioé esportare il risultato di una
computazione di Mathematica. In questo caso si utilizzano le funzioni Export ed ExportString, che
seguono lo stesso formato delle corrispondenti funzioni di importazione.
In[498]:=
Out[498]=
ExportString@Table@i, 8i, 1, 4<, 8j, 1, 2<D, "CSV"D
1,1
2,2
3,3
4,4
cap0.nb
87
In[503]:=
Out[503]=
Export@"prova.jpg", Graphics@Circle@80, 0<, 1DD, "JPG"D
prova.jpg
Nel caso si volessero importare in un notebook dei dati che non seguono alcun formato tra quelli
supportati, è possibile tentare di trasformarli ad esempio nel formato CSV utilizzando le funzioni di
sostituzione automatica di un editor di testi avanzato.
E' poi possibile esportare il risultato di una valutazione in formati utilizzabili da altri linguaggi: ad
esempio TeXForm e CForm producono in output l'esito dell'espressione passata come argomento
espresso in una forma utilizzabile rispettivamente in TEX e in C:
In[518]:=
Sqrt@x z + 1 ê yD êê TeXForm
Out[518]//TeXForm=
{\sqrt{\frac{1}{y} + x\,z}}
In[517]:=
Sqrt@x z + 1 ê yD êê CForm
Out[517]//CForm=
Sqrt(1/y + x*z)
E' infine da segnalare la possibilità di esportare un intero notebook in formato LATEX, HTML e
MATHML, utilizzando la voce di menù File/Save As Special.
1.28. Leggere e scrivere su file
Nella sezione precedente abbiamo visto come Mathematica sia in grado di importare ed esportare dati
utilizzando vari formati di codifica. Spesso è utile invece poter effettuare delle semplici operazioni di
lettura e scrittura su disco, ad esempio per salvare in modo permanente l'esito di un'operazione
complessa per poi rileggerlo in una sessione successiva. I comandi Get e Put, rispettivamente
abbreviati con le sequenze << e >> permettono di effettuare operzioni di questo tipo. Più precisamente:
>> è un operatore preceduto da un'espressione e seguito dal nome di un file. Quando la cella che
lo contiene viene eseguita, l'espressione viene valutata ed il valore ottenuto viene scritto nel file.
Il file risiederà nella directory corrente, ed eventuali suoi contenuti verranno cancellati.
L'operatore PutAppend, abbreviabile tramite la sequenza >>>, ha lo stesso effetto di >> con la
sola differenza che l'output viene scritto in coda a eventuali contenuti del file.
In[505]:=
Table@i, 8i, 1, 10<D >> "provoutput"
<< è un operatore seguito dal nome di un file. Quando la cella che lo contiene viene eseguita, il
contenuto del file viene inserito nella cella stessa al posto dell'operatore e del nome del file, e
successivamente la cella viene valutata.
88
cap0.nb
In[506]:=
Out[506]=
In[513]:=
Out[514]=
<< "provoutput"
81, 2, 3, 4, 5, 6, 7, 8, 9, 10<
tabellaLetta = << "provoutput";
tabellaLetta
81, 2, 3, 4, 5, 6, 7, 8, 9, 10<
1.29. Esercizi
1.29.1. Implementare la serie di Fibonacci
In[191]:=
fib@n_D := fib@n - 1D + fib@n - 2D;
fib@1D = 1;
fib@0D = 1;
In[194]:=
Trace@fib@3DD
Out[194]=
8fib@3D, fib@3 - 1D + fib@3 - 2D,
883 - 1, 2<, fib@2D, fib@2 - 1D + fib@2 - 2D, 882 - 1, 1<, fib@1D, 1<,
882 - 2, 0<, fib@0D, 1<, 1 + 1, 2<, 883 - 2, 1<, fib@1D, 1<, 2 + 1, 3<
1.29.2. Implementare la sostituzione per la somma di logaritmi
In[91]:=
Out[92]=
log@x_ y_D := log@xD + log@yD;
Trace@log@a b c dDD
8log@a b c dD, log@aD + log@b c dD,
8log@b c dD, log@bD + log@c dD, 8log@c dD, log@cD + log@dD<,
log@bD + Hlog@cD + log@dDL, log@bD + log@cD + log@dD<,
log@aD + Hlog@bD + log@cD + log@dDL, log@aD + log@bD + log@cD + log@dD<
cap0.nb
89
1.29.3. Implementare l'algoritmo per le frazioni egiziane
Il problema della scomposizione in frazioni egiziane è il seguente: data una frazione minore di 1,
scomporla come la somma di frazioni aventi il numeratore pari a uno. Il seguente approccio porta a
una scomposizione di questo tipo: partendo dal numero q, la più grande frazione avente forma 1/m
che risulta essere minore o uguale a q è tale che m è il più piccolo intero maggiore di 1/q, che risulta
essere Ceiling[1/q]; trovata tale funzione, è sufficiente reiterare il procedimento sulla quantità residua
q-1/m. Verificare come il seguente codice implementi questo approccio
In[203]:=
In[209]:=
Out[209]=
greedyEF@0D := 8<;
greedyEF@q_D :=
Prepend@greedyEF@q - 1 ê Ceiling@1 ê qDD, Ceiling@1 ê qDD ê; q < 1
greedyEF@2 ê 3D
82, 6<
quale è il significato del contenuto della lista? Suggerimento: la seguente istruzione verifica che il
risultato sia corretto
In[210]:=
Out[210]=
Apply@Plus, 1 ê %D
2
ÅÅÅÅ
3
Verificare il comportamento dell'algoritmo sulle frazioni aventi la forma 1-10^(-i), dove i è un intero
positivo da far variare.
1.29.4. Frazioni continue e rapporti aurei
La funzione NestList costruisce una lista nel seguente modo: considera un valore di partenza (il
primo della lista), e gli applica una funzione ottenendo un valore (il secondo della lista). A questo
valore applica nuovamente la funzione, ottenendo un nuovo valore (il terzo della lista) e così via, per
un numero di volte determinato:
In[213]:=
Out[213]=
NestList@f, x, 10D
8x, f@xD, f@f@xDD, f@f@f@xDDD, f@f@f@f@xDDDD, f@f@f@f@f@xDDDDD,
f@f@f@f@f@f@xDDDDDD, f@f@f@f@f@f@f@xDDDDDDD, f@f@f@f@f@f@f@f@xDDDDDDDD,
f@f@f@f@f@f@f@f@f@xDDDDDDDDD, f@f@f@f@f@f@f@f@f@f@xDDDDDDDDDD<
90
cap0.nb
Applicando NestList alla funzione 1/(1+x) si ottiene un oggetto matematico chiamato funzione
continua:
In[214]:=
Out[215]=
f@x_D := 1 ê H1 + xL;
NestList@f, x, 6D
1
1
1
1
1
1
9x, ÅÅÅÅÅÅÅÅÅÅÅÅ , ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ
ÅÅÅÅÅÅÅÅÅÅ , ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ
ÅÅÅÅÅÅÅÅ
1 ÅÅ , ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ
1ÅÅÅÅÅÅÅ , ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ
1
1 ÅÅÅÅÅ , ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ
1 ÅÅÅÅÅÅÅÅÅ =
1+x
1 + ÅÅÅÅÅÅÅ
1
+
ÅÅÅÅÅÅÅÅ
Å
ÅÅ
Å
1
+
ÅÅÅÅÅÅÅÅ
Å
ÅÅÅÅÅÅ
1
+
ÅÅÅÅÅÅÅÅ
Å
ÅÅÅÅÅÅÅ
Å
Å
1
+
ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ
1
1
1
1 ÅÅÅÅÅÅ
1+x
1+ ÅÅÅÅÅÅÅÅ
1+ ÅÅÅÅÅÅÅÅÅÅÅÅÅ
1+ ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ
1+ ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ
ÅÅÅÅÅÅÅ
1+x
1
1+ ÅÅÅÅ
ÅÅÅÅÅ
1+x
1
1+ ÅÅÅÅÅÅÅÅ
ÅÅÅÅ
1ÅÅÅÅÅ
1+ ÅÅÅÅÅÅÅÅÅÅÅÅ
1+x
1
1+ ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ
1ÅÅÅÅÅÅÅÅ
1+ ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ
1
1+ ÅÅÅÅÅÅÅÅÅÅÅÅ
1+x
Cosa succede se invece specifichiamo un valore preciso come punto di partenza?
In[216]:=
Out[216]=
NestList@f, 1, 20D
1
2
3
5
91, ÅÅÅÅ , ÅÅÅÅ , ÅÅÅÅ , ÅÅÅÅ ,
2
3
5
8
233
377
610
ÅÅÅÅÅÅÅÅÅÅ , ÅÅÅÅÅÅÅÅÅÅ , ÅÅÅÅÅÅÅÅÅÅ ,
377
610
987
8
13
21
34
55
89
144
ÅÅÅÅÅÅÅ , ÅÅÅÅÅÅÅ , ÅÅÅÅÅÅÅ , ÅÅÅÅÅÅÅ , ÅÅÅÅÅÅÅ , ÅÅÅÅÅÅÅÅÅÅ , ÅÅÅÅÅÅÅÅÅÅ ,
13
21
34
55
89
144
233
987
1597
2584
4181
6765
10946
ÅÅÅÅÅÅÅÅÅÅÅÅÅ , ÅÅÅÅÅÅÅÅÅÅÅÅÅ , ÅÅÅÅÅÅÅÅÅÅÅÅÅ , ÅÅÅÅÅÅÅÅÅÅÅÅÅ , ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ , ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ =
1597
2584
4181
6765
10946
17711
Considerate la sequenza dei numeratori e dei denominatori delle frazioni: non notate nulla di strano?
Se invece consideriamo la stessa lista in formato approssimato otteniamo
In[217]:=
Out[217]=
NestList@f, 1, 20D êê N
81., 0.5, 0.666667, 0.6, 0.625, 0.615385, 0.619048, 0.617647,
0.618182, 0.617978, 0.618056, 0.618026, 0.618037, 0.618033,
0.618034, 0.618034, 0.618034, 0.618034, 0.618034, 0.618034, 0.618034<
Sembra che la successione definita dagli elementi della lista tenda a un valore limite. Argomentate
questa asserzione nel modo più convincente possibile e tentate di stabilire una connessione tra questo
limite e il valore della costante
In[219]:=
Out[219]=
GoldenRatio êê N
1.61803