il file pdf degli appunti - Dipartimento di Matematica, Tor Vergata

Transcript

il file pdf degli appunti - Dipartimento di Matematica, Tor Vergata
Universita` di Roma Tor Vergata
Corso di Laurea Magistrale
in Matematica Pura e Applicata
Appunti per il corso di
Laboratorio di Calcolo
anno 2013-14
Paolo Baldi
Indice
PRIMA PARTE: INTRODUZIONE A SCILAB
1. Primi passi
5
1.1 Primi passi: le matrici
.
1.2 Primi passi: un po’ di grafica
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
2. scilab
.
5
11
13
2.1 Comandi di sistema . . . . . .
2.2 Tipi di dati: numerici
.
.
.
.
.
2.3 Ancora sul calcolo di matrici
.
.
.
2.4 Numeri complessi
.
.
.
.
.
.
2.5 Tipi di dati: caratteri
.
.
.
.
.
2.6 Input e output
.
.
.
.
.
.
.
2.7 Tipi di dati: logici
.
.
.
.
.
.
2.8 Programmazione
.
.
.
.
.
.
2.9 Grafica in scilab . . . . . .
2.10 Grafica avanzata: personalizzare il grafico
2.11 scilab e C
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
13
14
17
20
21
23
24
26
32
34
36
SECONDA PARTE: APPLICAZIONI E CASE STUDIES
3. Analisi multivariata
3.1
3.2
3.3
3.4
3.5
3.6
43
Statistica Descrittiva
.
.
.
.
.
Dati multidimensionali . . . . .
Statistica descrittiva in scilab
.
.
Analisi in componenti principali
.
.
Analisi discriminante
.
.
.
.
.
Approfondimenti sulla gestione della grafica
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4. Esplorazioni numeriche
4.1 Equazioni differenziali
.
43
47
48
53
65
71
73
.
.
.
.
.
.
.
.
.
.
.
.
.
.
73
ii
4.2
4.3
4.4
4.5
4.6
4.7
Fourier
.
.
.
.
.
.
.
.
.
.
.
Integrazione numerica: le somme di Riemann .
Polinomi d’interpolazione e il metodo di Simpson
Un’altro approccio: simulazione
.
.
.
.
Esercizi sull’integrazione numerica . . . .
Probabilità e simulazione in scilab
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5. Simulazione, processi e EDP
5.1
5.2
5.3
5.4
5.5
5.6
5.7
Simulazione . . . . . . . . . .
La simulazione del moto browniano
.
.
.
Moto browniano e EDP . . . . . . .
La simulazione della distribuzione d’uscita . .
Il problema di Dirichlet e la distribuzione d’uscita
Gli autovalori del laplaciano
.
.
.
.
.
L’equazione del calore
.
.
.
.
.
.
.
78
82
85
88
92
94
99
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
99
101
103
108
111
113
120
6. Esempi Freefem
129
Indice analitico
133
Introduzione
Questi appunti riguardano un corso di Laboratorio di Calcolo per studenti di Matematica.
Qual è lo scopo di questo corso ? Non è proprio facile spiegarlo: le motivazioni che hanno
guidato la redazione di questi appunti sono comunque tre.
• Innanzitutto avvicinare lo studente alla risoluzione di problemi concreti. Già al secondo
anno lo studente di questo corso di laurea ha acquisito una mole di conoscenze in matematica
abbastanza rilevante, molto più che uno studente più anziano di altri corsi di laurea. Però è in
genere poco cosciente delle applicazioni che queste conoscenze gli permettono di affrontare.
Anche se l’impostazione del corso di laurea in Matematica resta soprattutto diretta alla comprensione ed all’approfondimento teorico, è utile essere coscienti della portata degli strumenti
che si sono acquisiti.
• Reciprocamente, la pratica della risoluzione di problemi applicativi porta sempre ad
una migliore comprensione della teoria. Non si contano le volte che il risultato di un calcolo
o di una simulazione risulta inatteso e costringe a riflettere e a meglio comprendere gli aspetti
teorici sottostanti.
• Infine, una familiarità con lo strumento numerico è uno strumento potente anche nell’ap-
proccio a un problema di ricerca. Spesso un calcolo numerico o una simulazione danno
informazioni importanti sul problema. Naturalmente al ricercatore resta poi da fare la dimostrazione. Quella il computer non la fa. . .
2
Introduzione
Roma dicembre 2013
PRIMA PARTE:
INTRODUZIONE A SCILAB
1
Primi passi
In questo primo capitolo vediamo insieme i primi elementi che permetteranno comunque di
fare i primi calcoli e i primi grafici. Nei capitoli successivi vedremo gli stessi argomenti in
maniera più sistematica e approfondita.
1.1 Primi passi: le matrici
Le matrici sono l’elemento di base di scilab. In questo ambiente di calcolo tutto è matrice.
Cominciamo con gli elementi di base di questo linguaggio. Una cosa utile: che si possono
richiamare i comandi precedenti con i tasti ↑, ↓.
La regola generale in scilab è che tutti gli oggetti sono matrici. Cominciamo con le
operazioni elementari. Definire un vettore (riga)
-->vv=[.2 .9]
vv
=
.2
.9
La regola è che le coordinate si possono separare con uno spazio vuoto (come qui) oppure con
una virgola. Per definire una matrice: le righe sono separate da;
-->pp=[1/3 2/3;1/2 1/2]
pp
=
.3333333
.6666667
.5
.5
Paolo Baldi
Corso di Laboratorio di Calcolo
Tor Vergata 2013-14
6
Capitolo 1. Primi passi
Moltiplicare un vettore per una matrice
-->pp*vv
--error
10
inconsistent multiplication
Ooops le dimensioni non andavano bene: vv è un vettore riga e quindi pp ha un numero
di colonne che non è uguale al numero di righe di vv; per sistemare le cose si può fare il
trasposto di vv, che si fa con un apostrofo: vv’è il trasposto di vv; vv’ è dunque un vettore
colonna ed ora
-->pp*vv’
ans =
.6666667
.55
Avremmo anche potuto moltiplicare vv per pp da destra :
-->vv*pp
ans =
.5166667
.5833333
Moltiplicare delle matrici
-->pp*pp
ans
=
.4444444
.5555556
.4166667
.5833333
Fare la potenza di una matrice
-->ppˆ10
ans
=
.4285714
.5714286
1.1 Primi passi: le matrici
.4285714
7
.5714286
Le operazioni * e ˆ s’intendono sempre nel senso del prodotto righe per colonne. Se si
scrive .* oppure .ˆ (con un puntolino davanti), s’intende invece nel senso di termine a
termine
-->pp.ˆ10
ans
=
.0000169
.0173415
.0009766
.0009766
Il puntolino si usa anche per fare un quoziente termine a termine tra due vettori. v./w produce
il vettore che ha come coordinate i quozienti delle coordinate di v e di w. Naturalmente
occorre che i due vettori (o matrici) abbiano le stesse dimensioni. Attenzione però: se si dà il
comando 2./(2:4), ad esempio, scilab dà una risposta inattesa. Probabilmente perché
il punto dopo una cifra indica anche l’inizio di uno sviluppo decimale. Occorre in questo
caso scrivere (2)./(2:4)mettendo la cifra incriminata tra parentesi ed evitando così ogni
ambiguità.
Altre operazioni elementari sui vettori e le matrici: la somma delle coordinate:
-->xx=[1 2 3 4 5 6 7 8 9 10];
-->sum(xx)
ans
=
55.
il massimo e il minimo delle coordinate
-->min(pp),max(pp)
ans
=
0.3333333
ans
=
0.6666667
8
Capitolo 1. Primi passi
Come si vede in una stessa riga si possono dare più comandi, separandoli con un punto e
virgola o una virgola, a seconda che se ne voglia visualizzare o no il risultato.
Come estrarre un elemento da una matrice ? Quello di posto (1,2), ad esempio
-->pp(1,2)
ans
=
.6666667
Come estrarre una colonna da una matrice; la seconda ad esempio
-->pp(:,2)
.6666667
.5
o la prima riga
-->pp(1,:)
.3333333
.6666667
Alcuni modi speciali di definire una matrice oppure un vettore: con dei valori in progressione
-->1:10
ans
=
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
oppure lo stesso con degli incrementi diversi da 1
-->1:.1:10
ans
=
column
1.
1.9
1.1
1 to 10
1.2
1.3
column 11 to 20
1.4
1.5
1.6
1.7
1.8
1.1 Primi passi: le matrici
2.
2.9
2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8
3.4
3.5
3.6
3.7
3.8
4.4
4.5
4.6
4.7
4.8
5.4
5.5
5.6
5.7
5.8
9
column 21 to 30
3.
3.9
3.1
3.2
3.3
column 31 to 40
4.
4.9
4.1
4.2
4.3
column 41 to 50
5.
5.9
5.1
5.2
5.3
column 51 to 60
[More (y or n ) ?] n
Osserviamo che quando si dà un comando il programma restituisce immediatamente sullo
schermo il risultato dell’operazione. Qualche volta, come nel caso appena visto, il risultato
occuperebbe troppo spazio sullo schermo. Per evitarlo basta terminare il comando con ;. È
quello che faremo spesso d’ora in avanti. Ci sono anche comandi per produrre una matrice di
tutti uni.
-->ones(2,2)
ans
=
1.
1.
1.
1.
o di tutti zeri
-->zeros(2,2)
ans
0.
=
0.
10
Capitolo 1. Primi passi
0.
0.
-->zeros(3,1)
ans
=
0.
0.
0.
Matrici con 1 sulla diagonale principale e zero fuori
-->eye(3,3)
ans
=
1.
0.
0.
0.
1.
0.
0.
0.
1.
-->eye(5,3)
ans
=
1.
0.
0.
0.
1.
0.
0.
0.
1.
0.
0.
0.
0.
0.
0.
I comandi sum, max e min possono operare selettivamente sulle righe e sulle colonne. Ad
esempio
-->sum(pp,2)
ans =
1.2 Primi passi: un po’ di grafica
11
1.
1.
Più precisamente sum(pp,2) produce un vettore colonna, con tante righe quante quelle
della matrice pp le cui coordinate sono le somme degli elementi delle righe. Analogamente
sum(pp,1) avrebbe prodotto un vettore riga contenente le somme degli elementi delle
colonne.
Sotto scilab sono disponibili le principali funzioni elementari: seno (sin), coseno (cos),
esponenziale (exp), logaritmo (in base e: log). . . Inutile elencarle tutte, dato che non è
difficile scoprirne il nome. Quello che è importante osservare è che queste funzioni operano
direttamente su matrici e vettori: se mm è una matrice e si scrive, ad esempio
-->exp(mm)
allora si ottiene una matrice che ha gli elementi che sono gli esponenziali dei corrispondenti
elementi di mm. Vedremo più in là come si calcola l’esponenziale di una matrice.
1.2 Primi passi: un po’ di grafica
Il comando più semplice per fare un grafico è plot. L’idea è semplice, ma vedremo più
tardi che il controllo di tutte le opzioni può essere difficile da ricordare. Vediamo di disegnare
il grafico della funzione seno tra 0 e 2π. Prima ci procuriamo dei numeri compresi tra 0 e
2π, regolarmente spaziati ed i valori della funzione seno in corrispondenza. La costante π in
scilab si chiama %pi, mentre e è %e.
-->xx=(0:.02:1)*2*%pi;
-->yy=sin(xx);
e poi diamo il comando grafico
-->plot(xx,yy)
Se volessimo aggiungere al grafico quello della funzione coseno, basterebbe calcolare i valori
della funzione coseno e ridare il comando plot:
-->yy2=cos(xx);
-->plot(xx,yy2)
Quindi nuovi comandi grafici aggiungono elementi nuovi al grafico vecchio. Se invece avessimo voluto disegnare il grafico ex novo, avremmo prima dovuto cancellare il vecchio. Il
comando è
12
Capitolo 1. Primi passi
-->clf()
Non era facile da immaginare. . . Il vecchio comando xbasc() è obsoleto. Uno sguardo ai
grafici di poco fa mostra che le unità di misura lungo le ordinate e le ascisse erano diverse.
Scilab sceglie le coordinate in modo da sfruttare al meglio lo schermo. Questo è sgradevole
talvolta; ad esempio volendo disegnare un cerchio, basta chiedere il grafico dei punti di
coordinate sin(xx) e cos(xx), che abbiamo memorizzato nelle variabili yy e yy2. Ma se
diamo il comando
-->plot(yy,yy2)
il risultato non è proprio quello che si vorrebbe. Il comando plot ha molte opzioni che
discuteremo in dettaglio più tardi; per ora ci limitiamo a considerare le opzioni più semplici
ad esempio:
a) il colore; per default le curve dei grafici sono in blu. Per disegnare una curva in rosso,
ad esempio si deve scrivere
-->plot(xx,yy,"r")
dove r sta per ‘‘red’’, rosso in inglese. Altri colori disponibili immediatamente sono k
(nero), g (verde), y (giallo), c (ciano), m (magenta) e w (bianco, talvolta utile, cercate di
immaginare quando. . . ). Altri colori sono disponibili o si possono definire.
b) il tipo di tratto. Per default i punti vengono tracciati con tratto continuo. Ci sono altre
possibilità, per ora limitiamoci a considerare quella che consiste nel disegno dei singoli punti
con le ascisse in xx e le ordinate in yy. Per questo si possono usare vari simboli. Ad esempio
-->plot(xx,yy,".")
userà dei punti (un po’ cicciottelli), "*" userà degli asterischi, "o" userà dei cerchi vuoti e così
via.
Forse è il momento di imparare dove recuperare queste informazioni: scilab dispone di
uno help in linea che si ottiene scrivendo nella riga comandi help seguito da uno spazio e
dal nome del comando. Nel nostro caso:
-->help plot
Si tratta di una sorgente d’informazioni importante ma, come si vede, non sempre di facile
uso. Comunque dalla pagina d’informazioni di plot, cliccando LineSpec si può trovare
la lista completa dei colori e dei simboli. Per ogni altra informazione rinviamo a più tardi
quando analizzeremo dettagliatamente plot e gli altri comandi grafici.
2
scilab
2.1 Comandi di sistema
Questo paragrafo contiene le informazioni generali riguardanti la gestione della memoria,
delle variabili, e del loro display sullo schermo. Molte di queste informazioni sono premature
per un lettore che si trovi agli inizi dell’uso di scilab e possono essere tralasciate in prima
lettura.
In una sessione lunga e in cui si sono definite molte variabili può succedere di voler vedere
quali variabili sono state definite ed avere informazioni su di loro. Il comando who fa la
lista delle variabili attualmente definite. Compariranno però anche le variabili predefinite
di scilab e quindi la lista risulta sempre piuttosto lunga e le variabili che v’interessano
risulteranno sempre mischiate a quelle predefinite.
Il comando whos() (ricordarsi di scrivere anche le parentesi) ha un risultato simile, ma
produce anche delle informazioni utili, come ad esempio il tipo della variabile e lo spazio che
occupa in memoria. Quando si eseguono dei calcoli molto lunghi ed è opportuno disporre di
tutto lo spazio possibile in memoria conviene cancellare le variabili che non servono più con
il comando clear: clear mm (senza parentesi) cancellerà dalla memoria la variabile mm.
In effetti non è raro di trovarsi ad effettuare dei calcoli e di ricevere da scilab il messaggio
stacksize exceeded!, che indica che l’operazione che si sta cercando di effettuare
richiede troppa memoria. In questo caso conviene cancellare le variabili non più utilizzate. È
anche possibile aumentare la memoria utilizzabile da scilab con il comando stacksize
(vedi lo help di scilab per maggiori informazioni).
scilab effettua tutte le operazioni usando 22 cifre decimali, e dovrebbe quindi essere abbastanza preciso. Però scrive sullo schermo i valori numerici usando 10 cifre (comprese quelle
prima della virgola), allo scopo di non intasare lo schermo con un eccesso d’informazioni. Se
si vuole cambiare questo parametro ed avere allo schermo più informazioni (oppure meno)
c’è il comando format: format(’v’,7) istruisce il sistema di scrivere i valori numerici
usando 7 cifre solamente. Il parametro ’v’ indica che si richiede un formato ‘‘variabile’’.
Ciò significa che scilab sceglierà se scrivere il numero nel formato usuale oppure, se esso è
Paolo Baldi
Corso di Laboratorio di Calcolo
Tor Vergata 2013-14
14
Capitolo 2.
scilab
particolarmente grande o molto piccolo, in formato esponenziale. L’alternativa è il parametro
’e’ che forza la scrittura in forma esponenziale in ogni caso. Esempi
-->x=0.5148455718211526477290;
-->x
x =
0.5148456
-->format(’v’,15);
-->x
x =
0.514845571821
-->format(’e’,15);
-->x
x =
5.14845572D-01
2.2 Tipi di dati: numerici
Abbiamo detto che l’elemento di base in scilab è la matrice. Gli elementi di una matrice
possono essere di tre tipi diversi
a) numerici (interi, reali o complessi)
b) caratteri (alfanumerici)
c) booleani o logici (cioè Vero-Falso)
Per ognuno di questi tipi di variabili ci sono delle operazioni possibili. Abbiamo visto nel
capitolo precedente un certo numero di operazioni che si possono fare sulle variabili di tipo
numerico (somme, prodotti, potenze,. . . ). Vedremo ora che ci sono molti altri operatori utili
sui vettori numerici. I seguenti due operatori operano su qualunque tipo di variabili e sono
molto utili.
size(xx) produce un vettore di dimensione due, la cui prima coordinata fornisce il numero
di righe della matrice xx, mentre la seconda il numero di colonne.
length(xx) dà la dimensione del vettore xx. Se xx è una matrice, il risultato è il numero
totale di elementi (=numero di righe moltiplicato per numero di colonne). Esempi:
-->xx=[1,2,3,4];length(xx)
ans =
2.2 Tipi di dati: numerici
15
4.
-->xx=[1,2,3;4,5,6];si=size(xx),length(xx)
si =
2.
ans =
3.
6.
Tornando alle matrici/vettori numerici, passiamo in rivista i comandi principali. Alcuni di
questi sono già stati visti, ma necessitano un approfondimento. Per questi esempi ci serviremo
del comando rand: rand(m,n,"n") produce una matrice m × n di numeri scelti a caso
con distribuzione normale N (0, 1). Se invece dell’opzione "n" avessimo dato l’opzione
"u" i numeri sarebbero stati scelti a caso con distribuzione uniforme su [0, 1]. Prima di
servirsi di questo comando occorre però inizializzare il generatore:
-->rand("seed",9071948)
(al posto del numero 9071948, usate un numero di vostra scelta). Se non si dà questo comando
il generatore produce sempre la stessa sequenza di numeri. Vedremo più tardi in dettaglio le
questioni della generazione dei numeri a caso e delle loro applicazioni. Per ora però ci
serviremo di questo comando per produrre rapidamente delle matrici o dei vettori per i nostri
esempi. Passiamo in rivista i comandi più utili.
-->[m,lm]=min(xx)
Il comando min, che abbiamo già incontrato in realtà produce due valori: il valore m del
minimo delle coordinate del vettore xx ed l’indice lm della coordinata in cui il minimo
viene raggiunto (si tratta di un doppio indice se xx è una matrice). Ricordiamo che se xx
è una matrice, allora è possibile cercare il minimo riga per riga o colonna per colonna. Ad
esempio min(xx,"c") produrrà un vettore colonna, con tante righe quante sono le righe
di xx ed avente come coordinate i valori del minimo delle singole righe. Ad esempio
-->xx=rand(4,4,"n")
xx =
0.1034169
0.8915736
1.2429914
- 1.3925211
0.2044185
- 0.7414362
- 0.7437914
- 0.2589642
-->min(xx,"c")
0.3501626
1.0478272
- 1.3218008
- 1.4061926
- 1.0384734
- 1.7350313
0.5546874
- 0.2143931
16
Capitolo 2.
ans
-
scilab
=
1.0384734
1.7350313
1.3218008
1.4061926
-->min(xx,"r")
ans=
- 1.3925211
- 0.7437914
- 1.4061926
- 1.7350313
Simile la sintassi del comando max. Questa possibilità di operare separatamente per righe e
per colonne, con le opzioni "c" e "r" è tipica di molti comandi che operano su vettori e
matrici.
Un altro comando utile
-->yy=cumsum(xx);
che produce le somme cumulative del vettore xx: yy(1)=xx(1), yy(2)=xx(1)+xx(2)e
così via fino a yy(n)=xx(1)+...+xx(n). Questo comando si può applicare anche ad
una matrice. Se xx è una matrice, le somme cumulative si fanno per colonne. Vedi lo help di
scilab per i dettagli. Simile comportamento per il comando cumprod, che fa i prodotti
cumulativi.
Naturalmente scilab provvede tutte le funzioni elementari che agiscono sui valori numerici:
sin, cos, tan, asin, acos, atan,..., exp, log
sono le solite funzioni seno, coseno,. . . exp e log sono in base e. Si tratta di funzioni
che agiscono su vettori e matrici: se m è una matrice di elementi mij , allora exp(m) è la
matrice di elementi emij e lo stesso per la altre funzioni. È bene precisare che queste funzioni
si possono applicare anche a variabili complesse, come vedremo meglio più in là.
Altre funzioni utili
abs: valore assoluto
floor: la funzione parte intera, cioè floor(x) è il più grande intero che sia ≤ x.
ceil(x) invece è il più piccolo intero che sia ≥ x e round(x) è l’intero più vicino a x.
(in inglese ‘‘floor’’ vuole dire pavimento, mentre ‘‘ceiling’’ è il soffitto. . . ).
Un’altro tipo di comandi utile in molte applicazioni è quello che riguarda il riordinamento dei
valori di un vettore. Ad esempio
-->xx=rand(1,5,"n")
xx =
2.3 Ancora sul calcolo di matrici
0.2044185
- 0.7437914
- 0.2589642
0.3501626
17
1.0478272
-->[ss k]=sort(xx)
k =
5.
ss =
4.
1.0478272
1.
3.
0.3501626
2.
0.2044185
- 0.2589642
- 0.7437914
Dunque, dato un vettore numerico xx, il comando [ss k]=sort(xx) genera due nuovi
vettori. Il primo, ss, contiene le coordinate di xx riordinate in ordine decrescente (quindi
ss(1) è il valore più grande, ss(2) il secondo in classifica. . . ) mentre il vettore k contiene la permutazione che è stato necessario effettuare per passare da xx a ss. sort riordina
in ordine decrescente. Per riordinare in ordine crescente avremmo dovuto usare il comando
[ss k]=gsort(xx,"g","i").
Infine ricordiamo due comandi utili per ottenere informazioni sulle dimensioni dei vettori:
length(xx) produce la dimensione del vettore xx: nel caso di una matrice si tratta del
numero totale di coordinate presenti, cioè numero di righe moltiplicato per il numero delle
colonne. size(xx) invece produce un vettore di lunghezza due, la prima coordinata dà il
numero di righe, la seconda il numero di colonne. Con il vettore xx di poco fa
-->length(xx)
ans =
5.
-->size(xx)
ans =
1.
5.
-->
2.3 Ancora sul calcolo di matrici
Vediamo di approfondire il calcolo matriciale in scilab approfittando per mettere in evidenza alcune proprietà ben note (ma poi neanche tanto. . . ). Costruiamo una matrice a caso.
-->mm=rand(6,6,’n’)
Paolo Baldi
Corso di Laboratorio di Calcolo
Tor Vergata 2013-14
18
Capitolo 2.
scilab
ricordiamo che mm è dunque una matrice 6 × 6 a coefficienti scelti a caso con legge normale
e indipendenti. Calcoliamone gli autovalori.
-->spec(mm)
Verosimilmente avrete trovato che alcuni degli autovalori sono complessi. Vediamo di farne
il grafico sul piano complesso; real(zz) e imag(zz) sono i comandi che danno rispettivamente la parte reale e quella immaginaria del numero (o del vettore) complesso zz.
-->zz=spec(mm)
-->clf();plot(real(zz),imag(zz));
Osservate che se un numero λ è autovalore, anche il suo coniugato lo è, come ben noto (esame
di coscienza. . . ). Se vogliamo lavorare con una matrice simmetrica è facile procurarsene una
-->m1=(mm+mm’)/2
-->spec(m1)
Naturalmente ora gli autovalori sono tutti reali. Oppure
-->m2=mm*mm’
Anche m2 è simmetrica.
-->spec(m2)
Cosa osservate degli autovalori di m2 ? Sapreste dimostrare che tutti gli autovalori di m2 sono
necessariamente positivi ?
Vediamo come si calcolano gli autovettori e si diagonalizza la matrice.
-->[dg,cb,dim]=bdiag(m1);
dg è la matrice dopo la diagonalizzazione (cioè è una matrice diagonale con gli autovalori
sulla diagonale), mentre cb è la matrice del cambio di base. Dunque le colonne di cb sono
gli autovettori di m1. Verifichiamolo:
-->m1*cb(:,1)./cb(:,1)
Si vede che il vettore formato dalla prima colonna della matrice cb viene trasformato da
m1 in se stesso moltiplicato per una costante (che quindi è uno degli autovalori). Proprietà importante degli autovettori di una matrice simmetrica: gli autovettori sono ortogonali.
Verifichiamolo: il prodotto scalare dei vettori che costituiscono le prime due colonne è
Esercizi
19
-->sum(cb(:,1).*cb(:,2))
(Osservare il puntolino prima dell’*). Oppure anche
-->cb(:,1)’*cb(:,2)
Questa verifica si può fare in maniera più intelligente moltiplicando cb per la sua trasposta:
-->cb*cb’
Si vede anzi che scilab sceglie gli autovettori in modo che abbiano modulo uguale a 1.
Esempio 2.1 Data una matrice simmetrica (reale) A, esisterà una matrice simmetrica (reale)
B tale che BB = A ? Cioé, si può fare la radice quadrata di A ?
Se si considera il caso che la dimensione sia uguale a 1, si vede subito che la risposta in questi
termini è no: basta considerare il caso A = −1. Se però tutti gli autovalori sono positivi. . .
Se tutti gli autovalori sono positivi, allora la risposta è facile se A è diagonale (si fanno le
radici quadrate degli elementi sulla diagonale). Altrimenti, basta prendere la relazione di
diagonalizzazione A = U DU −1 . La matrice diagonale D ha tutti gli elementi sulla diagonale
che sono positivi (sono gli autovalori di A). Possiamo quindi fare la radice quadrata, diciamo
D1 , di D e porre B = U D1 U −1 . Verifichiamo che effettivamente B è la radice quadrata di
A che stavamo cercando: B 2 = BB = U D1 U −1 U D1 U −1 = U D1 D1 U −1 = U DU −1 = A.
Vediamo come si fa in concreto a realizzare questi calcoli con scilab, considerando la
matrice m2
di poco fa, che è definita positiva.
-->[dg2,cb2,dim]=bdiag(m2);
-->b=cb2*sqrt(dg2)*cb2’;
Verifica
-->m2,b*b
E2.1 a) Generare a caso più volte due matrici di ordine 5 simmetriche. Verificare che il loro
prodotto non è, in generale, una matrice simmetrica e nemmeno diagonalizzabile.
b) Verificare sperimentalmente, generando ripetutamente delle matrici a caso, che se una
delle due è definita positiva, allora il loro prodotto non è in generale una matrice simmetrica
ma risulta sempre diagonalizzabile. Non è una prova formale ma almeno è un buon indizio.
Sapreste produrre una dimostrazione formale di questo fatto ?
c) Verificare che, per le matrici diagonalizzabili trovate come in b) (prodotto di due matrici simmetriche di cui una definita positiva) in generale gli autovettori non sono ortogonali.
20
Capitolo 2.
scilab
Sapreste dimostrare che una matrice diagonalizzabile avente auovettori ortogonali è necessariamente simmetrica ?
E2.2 Ricordiamo che la traccia di una matrice quadrata è la somma degli elementi sulla
diagonale.
a) Generare a caso una matrice quadrata e calcolarne la traccia.
b) Calcolare, della stessa matrice, la somma degli autovalori. Cosa osservate ?
c) Date due matrici quadrate A e B aventi lo stesso ordine, mostrare che tr(AB) = tr(BA).
d) Sapreste dimostrare che la traccia di una matrice è sempre uguale alla somma degli
autovalori (contati con la loro molteplicità) ?
2.4 Numeri complessi
Come abbiamo detto, scilab è capace di fare i conti con numeri complessi. L’unità immaginaria
si indica %i:
-->ww=3+4*%i
ww
=
3. + 4.i
-->zz=1/ww
zz
=
.12 -
.16i
ww moltiplicato per il suo inverso fa. . .
-->zz*ww
ans
=
1. - 5.551E-17i
quasi 1.
Esempio 2.2 Consideriamo il numero complesso eit con t =
-->zz=cos(%pi/7)+%i*sin(%pi/7)
zz
=
π
7
2.5 Tipi di dati: caratteri
.9009689 +
21
.4338837i
e mettiamo in un vettore tutte le sue potenze da 1 a 200. Naturalmente si tratta di numeri di
modulo uguale a 1.
-->zz2=zzˆ[1:200];
Disegniamo sul piano il numero complesso zz e le sue potenze. Ricordiamoci di usare
l’opzione "." per disegnare i punti senza congiungerli con un segmento.
-->plot(real(zz2),imag(zz2),".");
Si osserverà che nel grafico compaiono pochi punti. In effetti zz14= 1 e poi i punti si
ripetono.
Se invece scegliamo il numero complesso
-->zz=cos(%pi*%pi/7)+%i*sin(%pi*%pi/7)
zz
=
.1601601 +
.9870911i
il cui argomento è un multiplo irrazionale di π, e poi facciamo le potenze e le disegniamo sul
piano,
-->zz2=zzˆ[1:200];
-->clf();plot(real(zz2),imag(zz2),".");a=gca();a.isoview="on";
si vede che le cose vanno diversamente. Avreste una idea di un teorema che viene suggerito
da questo grafico ?
2.5 Tipi di dati: caratteri
Un vettore o una matrice possono avere le loro componenti di tipo ‘‘carattere’’. Ad esempio
-->vc=["Ugo";"Ciro";"Massimiliano";"3"]
vc =
!Ugo
!
!Ciro
!
!Massimiliano
!
!
!
!
!
!
!
22
Capitolo 2.
scilab
!3
!
In generale i valori di un vettore di tipo carattere sono indicati tra apici: " " oppure ’ ’.
Inoltre un carattere può essere una lettera, oppure un carattere diverso, come #, @ oppure un
numero. In questo caso naturalmente il numero viene trattato come un carattere (e quindi non
gli si possono applicare le usuali operazioni aritmetiche).
Operazioni sui caratteri. Concatenazione
-->"3"+"4"
ans =
34
-->"Nel "+"mezzo "+"del "+"cammin"+"..."
ans =
Nel mezzo del cammin...
Aggiunta di coordinate
-->lista1=["nome","voto";"Arduini","23";"Belli","25"]
lista1 =
!nome
!
!Arduini
!
!Belli
voto
23
25
!
!
!
!
!
-->lista2=["Bollero","19"];lista1=[lista1;lista2]
lista1 =
!nome
!
!Arduini
!
!Belli
!
!Bollero
voto
23
25
19
!
!
!
!
!
!
!
Numeri si possono convertire nei corrispondenti caratteri e viceversa:
-->string(3)+string(4)
ans =
Esercizi
23
34
-->evstr("3")+evstr("4")
ans =
7.
Molti altri comandi sono disponibili per la manipolazione di caratteri, ma quelli visti saranno
sufficienti per i nostri scopi.
2.6 Input e output
Ogni linguaggio di programmazione dispone di comandi che permettono di leggere o di
scrivere dei file esterni. Si tratta in genere della parte più noiosa da imparare. . . Ci sono
molti comandi di input-output sotto scilab, che permettono di scrivere e leggere dai file in
formato ascii e binario, di aggiungere a file già esistenti nuovo materiale etc. Noi ci limiteremo
al minimo indispensabile per la realizzazione dei progetti che vedremo più tardi.
Supponiamo che dei dati si trovino nel file ascii filemio.txt e che si tratti di una matrice
(numerica) di tre righe e 216 colonne. Il comando
-->xx=read("filemio.txt",216,3);
legge i valori numerici e li dispone in una variabile xx di scilab del tipo matrice 216 × 3. Il
nome del file è una stringa e quindi va indicato tra " " oppure ’ ’. Se il file filemio.txt
non si trova nella directory di lavoro (vedi p. 13), occorre specificare tutto il cammino:
-->xx=read("C:\dida\lc2\filemio.txt",216,3);
ad esempio. Il numero di colonne nel comando precedente deve essere sempre specificato,
mentre indicando come numero di righe -1 il comando read leggerà tutte le righe fino
all’ultima. Ad esempio se il file filemio.txt conteneva 300 righe il comando precedente
avrebbe letto solo le prime 216 mentre
-->xx=read("filemio.txt",-1,3)
le avrebbe lette tutte. il comando read può anche leggere una matrice di caratteri, ma
in questo caso bisogna specificare che il formato dei dati da leggere non è numerico. Se
filemio.txt contenesse un tre righe di testo, le si potrebbe leggere con il comando
-->cc=read("filemio.txt",-1,1,’(a)’)
Ora avremmo a disposizione un vettore cc composto da tre righe di testo.
E2.3 Importate in scilab il testo contenuto nel file prova3.txt.
24
Capitolo 2.
scilab
In parallelo con read, il comando write scrive un file sul disco. Ad esempio
-->write("file2.txt",xx)
avrebbe scritto il contenuto della variabile xx nel file file2.txt. Talvolta scilab
protesta e risponde con il messaggio d’errore
File file2.txt already exists or directory write access denied
Non è il caso di farsi prendere dal panico. In genere semplicemente un file con quel nome esiste
già e il comando write non ha il diritto di sovrascrivere un file esistente. Ricordate che un
file può esistere ed essere vuoto (magari prodotto da un precedente tentativo con write).
Il write può essere usato anche per scrivere dati che non siano di numeri reali aggiungendo
il formato ’(a)’, come si faceva con il comando read.
E2.4 Il file exspec1 contiene una matrice simmetrica 77 × 77. Leggerla in scilab e
stabilire se essa sia definita positiva o no.
2.7 Tipi di dati: logici
I dati di tipo logico permettono di controllare e di fare operazioni sulle variabili. Una variabile logica può prendere i valori T (True=vero) o F (=falso). Una matrice a valori logici
può essere definita o assegnando i valori vero/falso, che in scilab sono definiti %t e %f
rispettivamente. Di solito però verrà definita mediante gli operatori logici che, applicati ad
una matrice numerica o di caratteri producono una matrice logica. Ad esempio
-->xx=(1:7);yy=(xx>=3)
ans =
F F T T T T T
Il vettore yy è a valori logici: le sue coordinate prendono i valori T o F a seconda che la
corrispondente coordinata di xx sia ≥ 3 o no.
Altri operatori che producono valori logici ed il cui significato è più o meno evidente sono
==
<
<=
>=
Da notare che l’operatore logico di uguaglianza è == e non =. A questi si aggiungono gli
operatori & (et) | (or) e ˜ (not). Ad esempio
-->xx=(1:7);(xx>=3)&(xx<=6)
ans =
2.7 Tipi di dati: logici
25
F F T T T T F
-->xx=(1:7);(xx>=6)|(xx<=3)
ans =
T T T F F T T
Vediamo degli esempi di applicazione delle variabili logiche. Ad esempio
-->xx=(1:7);yy=(xx>=3)&(xx<=6);xx2=xx(yy)
xx2 =
3.
4.
5.
6.
Quindi abbiamo estratto dal vettore xx i soli valori che soddisfacevano alla condizione logica
(xx>=3)&(xx<=6).
Esempio 2.3 Supponiamo che il vettore xx contenga i risultati (voti) ottenuti ad un esame,
mentre il vettore di caratteri yy contenga l’informazione del sesso dello studente. Vorremmo
calcolare la media dei voti separatamente per maschi e femmine. Supponiamo che i dati siano
-->xx=[21 23 14 27 29 28 26];
-->yy=[’M’,’F’,’M’,’M’,’F’,’M’,’F’];
Allora le medie cercate sono
-->mean(xx(yy==’F’))
ans =
26.
-->mean(xx(yy==’M’))
ans =
22.5
Una proprietà molto utile delle variabili logiche è che esse possono essere utilizzate nei calcoli
numerici, poiché in questo caso scilab le converte automaticamente in valori numerici con
le conversioni %t→ 1, %f→ 0. Ad esempio, generiamo 512 numeri a caso con distribuzione
N(0, 1). Quanti di essi risulteranno più grandi di 21 ?
-->xx=rand(512,1,"n");sum(xx>=.5)
ans =
26
Capitolo 2.
scilab
153.
Cioè, in presenza di un’operazione numerica (sum) i valori del vettore logico (xx>=.5)
sono stati convertiti in valori numerici con la regole indicata prima. In un certo senso le
variabili logiche possono quindi funzionare come delle funzioni indicatrici.
2.8 Programmazione
Finora abbiamo visto come usare scilab dando dei comandi uno dopo l’altro nella finestra
comandi. Ma si può anche usare questo software come un vero e proprio linguaggio di
programmazione.
Ci sono due modi per farlo. Il primo è quello di realizzare uno script: si scrive una sequenza
di comandi in un file esterno, diciamo il file script1.sci, e poi lo si esegue mediante il
comando exec scrivendo
-->exec(’script1.sci’)
oppure invocando il comando exec dal pop-up menu ‘‘file’’ in alto a sinistra della finestra
comandi. scilab allora esegue tutti i comandi del file script1.sci uno dopo l’altro.
scilab
prevede dei costrutti con i quali si possono scrivere dei veri programmi: in particolare vedremo che sono possibili cicli e istruzioni condizionali come nei normali linguaggi di programmazione. Occorre però ricordare che scilab
è comunque un linguaggio interpretato e quindi di esecuzione più lenta rispetto ai programmi
realizzati con linguaggi compilati come C o FORTRAN .
Ad esempio, volendo risolvere il problema del calcolo della radice quadrata di una matrice
simmetrica, come visto a p. 19, si scriverà un file con le due istruzioni
[dg2,cb2,dim]=bdiag(m2);
b=cb2*sqrt(dg2)*cb2’;
dopo di che, eseguendo questo file con il comando exec, si troverà nella variabile b la radice
quadrata richiesta. La matrice m2 naturalmente andrà preventivamente definita nella finestra
comandi.
Questa procedura è particolarmente comoda quando si devono ripetere più volte delle lunghe
sequenze di comandi.
Un secondo modo di sfruttare le possibilità di programmazione di scilab è di scrivere una
funzione. La sintassi è la seguente
function [a1,a2...]=acp(x1,x2,...)
... (comandi scilab)
2.8 Programmazione
27
endfunction
Le variabili a1,a2,... costituiscono lo output della funzione, mentre x1, x2,...sono
gli argomenti; acp è il nome che abbiamo deciso di dare alla funzione. Per poter usare una
funzione occorrerà
• scriverla in un file, diciamo fun.sci.
• caricarla in scilab, sempre con il comando exec.
A questo punto la funzione è disponibile. Ad esempio, se la funzione è la seguente
function b=sqrmat(m2)
[dg2,cb2,dim]=bdiag(m2);
b=cb2*sqrt(dg2)*cb2’;
endfunction
Ora, dopo avere eseguito le operazioni precedenti (salvataggio in un file e caricamento in
scilab del file), scrivendo
-->smm=sqrmat(mm)
si otterrà la radice quadrata della matrice mm. Da notare che il nome della funzione e quello del
file in cui essa è salvata possono essere diversi, ma che per caricarla in scilab occorre fare
exec("nome del file") mentre per invocarla occorre scrivere il nome della funzione.
Del resto in uno stesso file è possibile scrivere molte funzioni.
Ricordare che una funzione deve essere sempre essere caricata con il comando exec e, se
viene modificata occorre caricare la nuova versione. È tipico di correggere una funzione e
poi invocarla senza prima caricarla, per poi disperarsi vedendo che le modifiche apportate non
danno l’effetto sperato.
Se la funzione è composta da una sola istruzione, allora la si può definire direttamente dalla
riga comandi di scilab senza dover aprire l’editor e poi caricare la funzione in scilab.
Il comando è deff. Ad esempio una funzione che dia la densità di una gaussiana centrata e
ridotta può essere definita mediante
-->deff("y=ga(x)","y=exp(-x.ˆ2/2)/sqrt(2*%pi)")
Dopo avere dato questo comando la funzione ga è equivalente a
1 2
1
x → √ e− 2 x .
2π
Il cuore di un programma è dato naturalmente dalle istruzioni che permettono di realizzare
dei loop o dalle scelte condizionate.
Le due istruzioni principali per realizzare un loop sono i costrutti for ... end; e while
...end;. Vediamo come funzionano in un esempio concreto: supponiamo di voler calcolare
la somma di sin k per k che va da 1 a 106 . Prima possibilità:
28
Capitolo 2.
scilab
ll=0;
for i=(1:10ˆ6)
ll=ll+sin(i);
end;
Seconda possibilità
ll=0;i=1;
while (i<=10ˆ6)
ll=ll+sin(i);
i=i+1;
end;
In altre parole l’istruzione for esegue le istruzioni che seguono fino allo end per tutti
i valori assegnati della variabile i, che non è necessariamente intera o formata da numeri
consecutivi. Invece while costruisce un loop durante il quale tutte le istruzioni fino allo
end successivo vengono eseguite fintanto che una certa condizione logica è vera.
Conviene usare il costrutto for oppure while?
In generale il primo è più semplice se si tratta di effettuare una stessa operazione un numero
prefissato di volte. Qualche volta il ciclo però deve essere effettuato un numero di volte che
dipende dal risultato dei calcoli effettuati fino ad allora e in questo caso solo while può
essere utilizzato. Vedremo delle applicazioni nel capitolo sulla simulazione.
Ma ci sono altre osservazioni importanti da fare su questo punto. Prima di tutto provate a fare
lo stesso calcolo ma fino a n = 107 . Trovereste che, usando for, scilab vi risponde che il
calcolo richiede troppa memoria. Cos’è successo ? Il fatto è che con for il programma deve
prima generare effettivamente il vettore 1:10ˆ7 che è così lungo che finisce per occupare
tutta la memoria. Il comando while non ha bisogno di effettuare questa operazione e con
questo costrutto il calcolo può essere effettuato senza problemi. Questa questione si presenta
regolarmente quando si fa una simulazione molto lunga. In realtà la memoria di scilab si
può aumentare, ma è chiaro che con while la memoria sarebbe comunque meno intasata e
utilizzata in maniera più efficiente.
Riprendendo l’esempio precedente ci sono però altre due osservazioni da fare. Intanto lo
stesso risultato si sarebbe potuto ottenere con il comando
sum(sin(1:10ˆ6))
Provate a misurare il tempo che s’impiega con il comando for e con la procedura precedente.
Per misurare il tempo impiegato ad eseguire una serie d’istruzioni bisogna fare precedere il
comando timer(); e poi seguire il comando timer() (senza ;). Vedrete che for è
una trentina di volte più lento:
Esercizi
29
-->timer();ll=0;for i=(1:10ˆ6),ll=ll+sin(i);end;timer()
ans =
5.390625
-->timer();sum(sin(1:10ˆ6)),timer()
ans =
0.15625
In altre parole, i due costrutti for e while vanno usati solo quando non ci sono altre
possibilità e invece bisogna sempre cercare di utilizzare le capacità di calcolo vettoriale e
matriciale che sono il punto di forza di scilab. Questa è la principale differenza tra la
filosofia di programmazione in scilab ed i principali linguaggi di programmazione come
C e FORTRAN.
Occorre però anche osservare che il comando sum(sin(1:10ˆ6)), anch’esso è limitato
dalla capacità della memoria: sum(sin(1:10ˆ7)) produrrebbe lo stesso segnale d’errore
di prima. Ma anche in questo caso si può sfruttare le capacità di calcolo vettoriale di scilab
nel modo seguente
ll=0;
for i=(0:9)
ll=ll+sum(sin((1:10ˆ6)+i*10ˆ6);
end;
In questo modo il calcolo si svolge in soli 10 cicli (invece che in 107 ) in ognuno dei quali
vengono sommati 106 numeri.
E2.5 Esercizio Confrontate il tempo che s’impiega per calcolare sin 1 + . . . + sin(107 ) con
un ciclo while
(potete prevedere di farvi un caffé nell’attesa. . . ) e con la procedura precedente.
Infine, beh forse non c’era proprio bisogno di mettere scilab a fare tutti questi conti. Come
si potrebbe calcolare la somma della funzione seno su tutti gli interi da 1 a 106 , senza ridursi
a fare numericamente la somma di un milione di numeri ? Ricordate la definizione della
funzione esponenziale complessa
eiθ = cos θ + i sin θ
che gode della proprietà di moltiplicazione della funzione esponenziale eiθ eiφ = ei(θ+φ) .
Dunque (formula di una somma geometrica)
1 + ei + e2i + . . . + ein =
1 − ei(n+1)
1 − ei
30
Capitolo 2.
scilab
e dunque
i
sin 1 + . . . + sin n = Im 1 + e + . . . + e
Ma
in
= Im
1 − ei(n+1) 1 − ei
.
(1 − ei(n+1) )(1 − e−i ) 1 − ei(n+1) − e−i + ein 1 − ei(n+1) − e−i + ein
=
=
2 − 2 cos 1
(1 − ei )(1 − e−i )
1 − ei − e−i + 1
e dunque
sin 1 + . . . + sin n =
− sin(n + 1) − sin 1 + sin n
·
2 − 2 cos 1
Software di alto livello come scilab sono spesso preziosi, ma sono anche una continua
tentazione e si finisce per servirsene anche quando non ce ne sarebbe proprio bisogno.
In conclusione,
1) i costrutti che creano dei cicli di istruzione come for...end;e while...end
vanno usati solo dopo avere riflettuto se non sia possibile ottenere lo stesso risultato usando i
comandi vettoriali di scilab;
2) software di alto livello come scilab non sono un’alternativa al ragionamento matematico (o un’incitazione alla pigrizia. . . ) e devono essere usati invece per estendere le capacità
di calcolo a propria disposizione. O anche per verificare numericamente un calcolo svolto a
mano, se si teme di avere fatto degli errori di conto.
Un altro elemento tipico dei linguaggi di programmazione sono le istruzioni condizionali. Un
esempio tipico è il comando if...else, la cui sintassi più precisamente è
if (espressione logica1) then (istruzioni1)
elseif (espressione logica2) then (istruzioni2)
...
else (istruzioni)
end;
Se (espressione logica1) è vera allora le (istruzioni1) vengono eseguite, altrimenti si passa alla (espressione logica2), se essa è vera vengono eseguite le
(istruzioni2) e così via. Se nessuna delle variabili logiche risulta vera, allora vengono
eseguite le istruzioni successive a else. Da notare che i comandi elseif
e else sono opzionali.
Esempio 2.4 Una funzione di uso frequente in teoria del segnale è la funzione seno cardinale,
definita da
sin x
sinc x =
x
con l’intesa sinc 0 = 1. Come fare per definire la funzione sinc in scilab? Ci sono varie
possibilità: usando if...else:
function y=sinc1(x)
y=ones(x);
Esercizi
31
if (x˜=0) then y=sin(x)./x;
end;
endfunction
La funzione così definita funziona, ma ha il difetto di non essere vettoriale. Cioè, se x è un
vettore, sinc1(x) potrebbe non produrre il risultato desiderato, poiché la condizione logica
(x˜=0) produrrebbe un vettore logico e if considera allora che la condizione logica è vera
solo se tutte le coordinate di questo vettore sono uguali a T. Provate, ad esempio, a calcolare
sinc1([-.2,0]). Il comando if è quindi da evitare con delle condizioni vettoriali.
Seconda possibilità: con un po’ di astuzia, combinando le variabili logiche.
function y=sinc2(x)
y=(x˜=0).*sin(x)./(x+(x==0))+(x==0)
endfunction
Occorre ricordare che le variabili logiche vengono convertite nelle espressioni numeriche ai
valori 1 quando sono vere e 0 quando sono false. Si comportano quindi come delle funzioni indicatrici d’insieme, in un certo senso. Quindi il termine (x˜=0).*sin(x)./(x+(x==0))è
sempre ben definito, poiché il denominatore ora non si può annullare. Questo termine dà il
valore sinx x se x 6= 0, ma vale 0 in 0. Dunque aggiungendo (x==0) che vale 1 per x = 0, si
ottiene la funzione seno cardinale,
Da notare comunque che sinc è una funzione già prevista in scilab. È quindi possibile
andare a vedere come essa è definita, leggendo il file C:\Program Files\scilab4.1.2\macros\elem\sinc.sci. Si trova
function y=sinc(x)
y=ones(x)
kz=find(x<>0)
y(kz)=sin(x(kz))./(x(kz));
endfunction
Quando si scrive una funzione è sempre molto opportuno fare in modo che il risultato accetti un
argomento vettoriale. Ad esempio, volendo programmare la funzione x sin x, si può scrivere
-->deff("y=xsin(x)","y=x*sin(x)")
Ora scrivendo xsin(%pi/5)si ottiene effettivamente il numero π5 sin π5 , ma se poniamo
x=[%pi/3,%pi/5]e poi scriviamo xsin(x)scilab darà un messaggio di errore, invece di calcolare x sin x per x = π3 e x = π5 . Questo non sarebbe successo se avessimo
scritto
deff("y=xsin(x)","y=x.*sin(x)")
(cioè con un puntino in più).
32
Capitolo 2.
scilab
Talvolta però non è possibile scrivere la funzione che interessa in maniera che possa accettare
come argomento un vettore di valori. In questo caso, se poi occorre effettivamente calcolare la
funzione ottenuta su un vettore di valori, scilab dispone del comando feval. Supponiamo
ad esempio di avere definito una funzione fun1 e di volerla calcolare sui valori contenuti in
un vettore x. Ciò si può fare dando il comando
-->y=feval(x,fun1)
Il vettore y ora contiene i valori di fun1 calcolati in x. Questo comando è equivalente a
y=fun1(x)se la funzione fun1 accetta valori vettoriali (e in questo caso questo secondo
modo è sicuramente più veloce e preferibile).
Il comando feval può anche essere usato, ed è molto utile, per funzioni di due variabili. Se
fun2 è una funzione di due variabili e x e y sono vettori, allora con il comando
-->z=feval(x,y,fun2)
si ottiene una matrice z che al posto ij contiene il valore di fun2 calcolata in (xi , yj ).
E2.6 Scrivere una funzione scilab che, dato un punto del piano in coordinate cartesiane,
ne calcoli modulo e argomento in coordinate polari.
2.9 Grafica in scilab
Uno dei grandi vantaggi dei linguaggi di alto livello come scilab, matlab, R o Splus è la
facilità di accesso alla grafica.
Come vedremo le cose sono veramente facili se ci si limita ai comandi di base accettando i
default di scilab ma diventano un po’ più delicate se si comincia a voler personalizzare il
risultato.
Cominciamo con un esempio. Il comando base per fare un grafico è plot. L’idea è semplice:
vediamo come si disegna il grafico della funzione seno tra 0 e 2π. Prima ci procuriamo dei
numeri compresi tra 0 e 2π, regolarmente spaziati (diciamo spaziati di un cinquantesimo) ed
i valori della funzione seno in corrispondenza. La costante π in scilab si chiama %pi.
-->xx=(0:.02:1)*2*%pi;
-->yy=sin(xx);
e poi diamo il comando grafico
-->plot(xx,yy)
Se volessimo aggiungere al grafico quello della funzione coseno, basterebbe calcolare i valori
di quest’ultima ridare il comando plot:
-->yy2=cos(xx);
2.9 Grafica in scilab
33
-->plot(xx,yy2)
Quindi ulteriori invocazioni di plot aggiungono al grafico elementi nuovi. Se invece avessimo voluto disegnare il grafico ex novo, avremmo prima dovuto cancellare il vecchio grafico.
Il comando è
-->clf()
che non era proprio facile da immaginare. . . Per generare il grafico simultaneamente delle due
funzioni seno e coseno, con colori diversi, c’era comunque un metodo più veloce. Sarebbe
bastato fare
-->y=[yy;yy2]
-->plot(xx,y)
Infatti ora il vettore y contiene due righe, la prima con i valori della funzione seno, la seconda
con i valori di coseno. Quando si dà come secondo argomento in plot una matrice viene fatto
il grafico di tutte le righe, ogni grafico cambiando di colore, secondo uno schema prestabilito
di colori (che l’utilizzatore coraggioso può anche cercare di personalizzare). Nel comando
plot è possibile quindi dare come argomenti x e y quindi non solo dei vettori ma anche
delle matrici con vari risultati. Non entreremo nel dettaglio, chi avesse bisogno di queste
informazioni può andare a vedere lo help del comando plot.
Vediamo ora le opzioni elementari del comando plot. Le opzioni vengono indicate con una
stringa di caratteri (quindi tra " ") dopo i nomi delle variabili. Come si è visto nell’esempio
precedente, come default plot disegna i punti di cui gli si danno le coordinate collegandoli
l’uno all’altro con un segmento. Se si desidera che essi siano invece indicati con un simbolo
e senza essere collegati l’uno all’altro, basta specificare il simbolo. Se si vuole che il grafico
venga eseguito con un colore diverso dal blu, che è il default, si può indicare il colore. Ad
esempio: fare un grafico di dati, in rosso e usando un punto per indicare i valori:
-->plot(xx,yy,".r")
dove ‘‘.’’ indica che si vuole usare il punto come simbolo, mentre r è l’abbreviazione di
red. Si tratta solo di una comodità: plot(xx,yy,".red")avrebbe prodotto lo stesso
risultato. I simboli ed i colori disponibili sono illustrati nelle tabelle che si trovano nello help
del comando plot , nel sottomenù Linespec.
Qualche volta ad un grafico è opportuno aggiungere dei dettagli: un titolo ad esempio:
-->tt=[-1:.01:1]*%pi;plot(tt,sin(tt));
-->xtitle("la funzione seno");
Paolo Baldi
Corso di Laboratorio di Calcolo
Tor Vergata 2013-14
34
Capitolo 2.
scilab
Da notare che questo comando aggiunge il titolo alla pagina corrente e che il comando può
essere dato in un secondo momento rispetto al grafico. Quando si disegnano più curve su un
medesimo grafico, magari si vorrebbe indicare cosa rappresenta ognuna delle curve: i comandi
-->tt=[-1:.01:1]*%pi;plot(tt,sin(tt));plot(tt,cos(tt),"r");
-->legend(’seno’,’coseno’)
produrranno i due grafici delle funzioni seno e coseno con una leggenda che spiega che il
grafico in blu è quello del seno e quello in rosso quello del coseno (provare).
Ulteriori approfondimenti sul comando plot vengono fatti in §3.6.
2.10 Grafica avanzata: personalizzare il grafico
Quando si dà il comando plot scilab disegna il grafico scegliendo opportunamente la
scala delle ascisse, quella delle ordinate, le tacche da segnare sugli assi, la posizione degli
assi stessi. Talvolta però queste scelte del sistema non vanno e l’utilizzatore deve cambiarli.
Come fare ?
Ci sono due modi, entrambi basati sul fatto che ogni grafico di scilab ha degli attributi
che si possono modificare, anche dopo che il grafico è stato disegnato. Il primo modo utilizza
il modo edit che si trova in alto a sinistra della finestra grafica. Ad esempio, supponiamo di
voler disegnare la circonferenza unitaria. Un modo per farlo consiste nel disegnare sul piano
i punti di coordinate (cos θ, sin θ). Ciò si può fare con i comandi
-->tt=[0:.01:1]*2*%pi;yy2=sin(tt);
-->yy1=cos(tt);clf();plot(yy1,yy2)
Se provate a dare questi comandi si ottiene una cosa che non sembra proprio una circonferenza.
Questo è dovuto al fatto che lo schermo del PC non è quadrato e scilab cerca sempre di
sfruttare al massimo lo spazio disponibile, per cui usa unità di misura diverse sull’asse delle
ascisse e su quelle delle ordinate. Per rimettere le cose a posto cliccate su Edit nella finestra
grafica e selezionate Figure properties e poi Axes e infine Aspect. Nella finestra
che compare a questo punto c’è una finestrella che si chiama isoview. Selezionatela e
vedrete che la circonferenza diventa una circonferenza vera.
Un secondo modo apparentemente più complicato consiste nel recuperare gli handles della
figura e editarli direttamente dalla riga comandi. Il comando che produce gli handles del
grafico corrente è gca():
-->a=gca();
Se ora scrivete
-->a
2.10 Grafica avanzata: personalizzare il grafico
35
compaiono tutti gli handles. Tra di questi vi è l’attributo isoview. Se date il comando
-->a.isoview="on"
scilab ridisegna il grafico e le unità di misura sui due assi diventano uguali. In maniera
abbastanza intuitiva si capisce come fare per modificare, se necessario, gli altri attributi. Ad
esempio se si vuole disegnare gli assi coordinati facendoli passare dall’origine, occorrerà
cambiare i valori dei parametri x_location e y_location, che per default sono posti
rispettivamente uguali a left e bottom e porli uguali a middle. Ricordando che le
stringhe di caratteri vanno sempre indicate tra apici o virgolette, il comando da dare sarà
quindi
-->a.x_location="middle";a.y_location="middle";
Può capitare di avere bisogno di numerosi grafici simultaneamente. scilab può aprire
simultaneamente diverse finestre grafiche. Quando si dà un comando grafico per la prima
volta scilab sceglie di realizzare il grafico nella finestra numero 0. Se si vuole che i grafici
successivi vengano effettuati nella finestra numero 1 occorrerà dare il comando scf(1)
(scf=select current figure). Dopo questo comando, tutti i comandi grafici verranno indirizzati
alla finestra numero 1. Per tornare alla finestra iniziale occorrerà scrivere scf(0), per aprire
un’altra nuova finestra si dovrà scrivere scf(i) dove i è un numero intero.
In questo modo è possibile disporre simultaneamente di più grafici. Qualche volta invece si
desidera realizzare più grafici sulla stessa finestra. Supponiamo ad esempio di voler suddividere la finestra grafica corrente in quattro e di disegnare in ognuna delle sottofinestre un
grafico diverso. Il comando
-->subplot(2,2,1);
indica che la finestra grafica è suddivisa in 2 righe ciascuna formata da 2 sottofinestre. Inoltre che d’ora in avanti tutti i comandi grafici andranno indirizzati alla prima di queste sottofinestre (quella in alto a sinistra). Per passare alle altre sottofinestre basterà dare i comandi
subplot(2,2,2);, subplot(2,2,3);e subplot(2,2,4);che passeranno a considerare rispettivamente la sottofinestra 2 (in alto a destra, la 3 (in basso a sinistra) e la 4
(l’ultima, in basso a destra).
Esempio 2.5 Qual è il risultato dei comandi seguenti ?
-->tt=[-1:.01:1]*%pi;scf(1);subplot(2,2,1);
-->plot(tt,sin(tt));xtitle("la funzione seno");subplot(2,2,2);
-->plot(tt,cos(tt));xtitle("la funzione coseno");
36
Capitolo 2.
scilab
-->tt=[-1:.01:1];scf(1);subplot(2,2,3);plot(tt,sinh(tt),"r");
-->xtitle("la funzione seno iperbolico");
-->tt=[-1:.01:1];scf(1);subplot(2,2,4);plot(tt,cosh(tt),"r");
-->xtitle("la funzione coseno iperbolico");
È abbastanza facile: viene selezionata la finestra grafica numero 1 che poi viene suddivisa
in quattro. Nelle due finestre superiori vengono disegnati i grafici delle funzioni seno e
coseno, nelle due finestre inferiori quelli delle corrispondenti funzioni seno iperbolico e coseno
iperbolico.
E2.7 Com’è fatta l’immagine dell’asse reale mediante l’applicazione z− > (z − i)/(z + i) ?
E l’immagine della retta Im z = a, a > 0 ?
2.11 scilab e C
Può essere utile usare insieme Scilab ed un linguaggio compilato tradizionale, come FORTRAN oppure C. Questi linguaggi compilati sono di esecuzione molto più rapida, mentre
scilab è chiaramente più potente e flessibile quando si tratta di fare trattamenti grafici.
In particolare questo è molto evidente quando si fanno lunghe simulazioni, nelle quali non è
possibile evitare costrutti come for. . . end oppure while. . . end. In questi casi si effettuerà la
simulazione in C, ad esempio, mentre l’analisi statistica, gli istogrammi. . . etc verranno effettuati in scilab. È possibile chiamare da scilab un programma esterno in C, e quindi
acquisire i risultati della simulazione, che poi verranno analizzati con scilab. Vediamo
come si fa. Vedremo che la cosa richiede un po’ di pazienza. Inoltre il modo di collegare i due
programmi dipende dal sistema operativo e dal compilatore che si usano. Quindi quanto segue
vale solo per il sistema Windows e per il compilatore mingw . Per altri compilatori alcune
dettagli potrebbero essere diversi, mentre per i sistemi Unix le differenze sono sostanziali (ma
abbastanza ben descritte nei manuali scilab, che invece non spiegano niente per chi lavora
sotto Windows).
Per prima cosa si deve installare il compilatore: vedi in
http://atoms.scilab.org/toolboxes/mingw/0.9.3/files/gcc-4.6.364.exe
se si ha un sistema a 64 bit,
http://atoms.scilab.org/toolboxes/mingw/0.9.3/files/gcc-4.6.332.exe
altrimenti. Dopo avere eseguito il file e quindi installato il compilatore occorre riavviare il
computer, lanciare scilab ed eseguire i comandi
2.11 scilab e C
37
atomsInstall("mingw");atomsLoad("mingw");
Vediamo ora come si deve operare, usando come esempio un programma per la generazione
di numeri aleatori di legge esponenziale di media 1. Da un punto di vista algoritmico, la cosa
è molto semplice: ricordiamo che, se X è una variabile aleatoria uniforme su [0, 1], allora
– log X è esponenziale di media 1. Il programma per realizzare un vettore di lunghezza n di
numeri aleatori indipendenti di legge esponenziale di media 1 è quindi
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <time.h>
#include <math.h>
#define STRICT
#define pig 4*atan(1)
double nrandom (void)
{return ((double)rand()/(double)RAND_MAX);}
/*il programma seguente genera n numeri aleatori
indipendenti con distribuzione esponenziale*/
void rexp(unsigned int *n,double x[])
{
unsigned int ii;
double z1;
for (ii=0;ii<*n;++ii)
{
z1=nrandom();
x[ii]=-log(z1);
}
}
Guardiamo più da vicino la riga
void rexp(unsigned int *n,double x[])
e mettiamo in evidenza un paio di cosette importanti. Intanto le funzioni C che si possono
chiamare da scilab devono essere del tipo void, cioè non devono restituire un valore, ma
solo cambiare il valore degli argomenti in ingresso. Inoltre notiamo che gli argomenti della
funzione rexp devono essere dei puntatori. Questo è un punto importante che si deve tenere
38
Capitolo 2.
scilab
da conto nella realizzazione del programma. Anche la variabile x è un puntatore, anche se
non compare la stellina, perché in C sono puntatori tutte le array.
Il corpo del programma produce un vettore di lunghezza *n di numeri aleatori indipendenti
di legge esponenziale di parametro 1. Il programma così scritto deve essere poi compilato e
collegato (linkato, come si dice) a scilab con i comandi
ilib_for_link("rexp","fun1.c",[],"c")
exec loader.sce
dove fun1.c è il nome del file in cui avremo salvato il programma (assicurarsi che si trovi
nella directory corrente, altrimenti occorre indicarne il percorso). Dovendo effettuare più
volte questa operazione si può definire una funzione per semplificare la scrittura. Ad esempio
function y=cl(ep,nomefile)
//ricordare: argomenti tra " "
y=ilib_for_link(ep,nomefile,[],"c");
exec loader.sce
endfunction
Una volta caricata la funzione cl in scilab, per fare la compilazione della nostra funzione
rexp basterà scrivere
cl("rexp","fun1.c")
Attenzione: occorrerà mettere i nomi degli argomenti tra apici ’ ’ o virgolette " ". A questo
punto la nostra funzione rexp è caricata in scilab. Se vogliamo servircene per generare
100 numeri a caso, dobbiamo scrivere
-->nn=100;xx=call("rexp",nn,1,"i","out",[1 nn],2,"d");
La sintassi della funzione call è un po’ complessa. Il primo argomento indica il nome
della funzione da chiamare. Seguono poi le descrizioni delle variabili di input della funzione.
Qui ce n’è una sola, il numero di valori simulati: nn è il valore della variabile, 1 il posto
che occupa nell’ordine di chiamata, "i" indica che è una variabile di tipo intero. "out"
indica che ora comincia l’indicazione delle variabili di output, nel nostro caso il vettore di nn
numeri aleatori. [1 nn] indica che si tratta di un vettore riga di nn elementi, 2 che la
variabile in questione si trova al secondo posto nell’ordine di chiamata, "d" che si tratta di
una variabile in doppia precisione. Dovendo chiamare la funzione esterna più volte e volendo
risparmiarsi questa sintassi arzigogolata anche qui si può definire una funzione che faccia il
lavoro per noi. Ad esempio
function xx=genexp(nn)
xx=call("rexp",nn,1,"i","out",[1 nn],2,"d");
endfunction
2.11 scilab e C
39
Una volta caricata con exec, genexp(nn) produrrà i nostri nn numeri aleatori usando il
programma esterno.
Se si vogliono generare dei numeri aleatori di legge diversa, si possono utilizzare risultati sulle
trasformazioni delle leggi di probabilità che si vedono di solito nei corsi di base. Ad esempio:
1) Per simulare dei numeri aleatori di legge esponenziale di parametro λ, basta simularli
con parametro 1 e poi dividerli per λ.
2) per generare dei numeri con distribuzione Gamma(n, 1), basterà ricordare che, se
X1 X2 , . . . , Xn sono v.a. esponenziali di media 1, allora X1 + X2 + . . . + Xn è appunto
Gamma(n, 1).
Una discussione a parte merita la generazione di numeri aleatori di legge N(0, 1), per i
quali bisogna sviluppare metodi appositi. L’idea consiste nell’osservare che se X e Y sono
v.a. indipendenti e N(0, 1), allora X2 + Y 2 segue una legge esponenziale di parametro 21 .
Cercheremo di generare la v.a. congiunta (X, Y ) in coordinate polari; questo si chiama
l’algoritmo di Box-Muller. Abbiamo già visto come si fa a simulare il √
modulo del vettore
(X, Y ): si simula una v.a. esponenziale, Z, di parametro 1 e poi si prende 2Z. L’argomento
del vettore è invece evidentemente uniforme su [0, 2π]. In conclusione, se Z è esponenziale
di parametro 1 e U è uniforme su [0, 1], le due v.a.
√
2Z cos(2π U ) e
√
2Z sin(2π U )
sono indipendenti ed hanno legge N(0, 1).
Osservazioni 2.6 Alcuni fatti utili.
a) Talvolta al comando ilib_for_link("ep","nomefile.c",[],"c") si ha
come risposta il messaggio
!--error 999
ilib_for_link: Wrong value for input argument #2: existing
file(s) expected.
at line
22 of function ilib_for_link called by :
at line
3 of function cl called by :
cl("ep","nomefile.c")
Questo significa semplicemente che scilab non ha trovato il file nomefile.c, probabilmente perché quest’ultimo non si trova nella directory corrente.
b) Fare molta attenzione a scrivere correttamente il comando call. Un errore nell’ordine
delle variabili o nel loro tipo o dimensione può provocare reazioni ‘‘sdegnate’’ da parte di
scilab che può anche chiudersi inopinatamente oppure produrre dei risultati erratici (Inf,
NaN. . . ).
c) Attenzione quando una delle variabili è una matrice. scilab e C hanno modi diversi
di codifica delle matrici. In entrambi i sistemi i valori vengono registrati in un vettore e poi
distribuiti nella matrice. Solo che in C i valori vengono messi nella matrice una colonna dopo
l’altra, mentre in scilab una riga dopo l’altra. Il programmino
40
Capitolo 2.
scilab
void psm(int c[][3])
{
int ii,jj;
for(jj=0;jj<3;++jj)
{
for(ii=0;ii<5;++ii)
{
ct[ii][jj]=jj;
}}}
che pensereste che dovrebbe produrre la matrice

0
0

0

0
0
invece produrrà
1
1
1
1
1

2
2

2

2
2


0 2 1
1 0 2


2 1 0


0 2 1
1 0 2
E2.8 Generare, usando il programma in C appena sviluppato, nn= 512 numeri aleatori di
legge esponenziale e verificare la bontà del generatore effettuando istogrammi e test grafico
dei quantili. Fare il test dei quantili confrontando il campione prodotto con i quantili di una
legge di student t(3) e poi con una t(9). Cosa si osserva ?
E2.9 Modificare il programma C di poco fa per la generazione a caso di numeri aleatori
con distribuzione Gamma e t di student. Modificare il programma del grafico dei quantili per
verificare la bontà dei nuovi generatori.
(i comandi scilab per ottenere i quantili delle leggi gamma e delle t di Student sono
cdfgam e cdft rispettivamente).
È inoltre utile segnalare che, quando si fa una simulazione bisogna sempre accertarsi che il
generatore di numeri a caso che si usa (sia che la simulazione venga fatta sotto scilab che
sotto C) abbia un periodo abbastanza lungo. Infatti un generatore aleatorio è sempre periodico,
cioè produce un numero fissato di numeri, dopo di che ricomincia da capo. Quindi occorre
sempre verificare, prima di una simulazione che il numero di numeri aleatori di cui si ha
bisogno sia inferiore al periodo del generatore. Informazioni sui “generatori buoni” e sul loro
periodo si trovano nello help del comando scilab grand. Per dare un’idea, i generatori
aleatori che si trovano di solito, come rand di scilab, oppure nrandom di C, hanno un
Esercizi
41
periodo dell’ordine di 109 . In pratica si tratta di generatori semplici, buoni per operazioni d
poco impegno. Per lavori di simulazione impegnativi occorrerà ricorrere al comando grand
oppure, sotto C, a generatori più raffinati come quello di Marsaglia o di Knuth (vedi §5.2).
SECONDA PARTE:
APPLICAZIONI E CASE STUDIES
Paolo Baldi
Corso di Laboratorio di Calcolo
Tor Vergata 2013-14
3
Analisi multivariata
3.1 Statistica Descrittiva
In questo primo capitolo vedremo dei metodi di analisi di insiemi di dati. Vedremo che queste
tecniche si riconducono essenzialmente a delle questioni di algebra e di geometria, che si
acquisiscono tipicamente nei primi due anni di corso. Cominciamo con un insieme di dati
semplice: vengono osservati n individui e per ciascuno di essi viene osservata una quantità
numerica. Il ricercatore si trova quindi di fronte a n numeri x1 , . . . , xn .
Si chiama media del campione la quantità
n
1
1X
xi .
x̄ = (x1 + . . . + xn ) =
n
n
(3.1)
i=1
La media di un campione è uno di quelli che si chiamano indici di centralità. In altre parole
la media indica il centro del campione.
Si vede subito che se poniamo yi = axi + b con a, b ∈ R, allora la media ȳ del campione
y1 , . . . , yn è uguale a a x̄ + b. In altre parole la media è invariante per un cambio di unità di
misura: fare un cambio di scala e poi la media è lo stesso che calcolare la media e poi fare il
cambio di scala. Infatti
1 X 1 X
1X
1X
yi =
(axi + b) = a
xi +
b=
ȳ =
n
n
n
n
n
n
i=1
i=1
= a x̄ + b .
Si chiama varianza del campione la quantità
n
(3.2)
1X
(xi − x̄)2 .
n
i=1
Paolo Baldi
Corso di Laboratorio di Calcolo
Tor Vergata 2013-14
n
n
i=1
i=1
44
Capitolo 3. Analisi multivariata
La varianza si indica σ 2 , oppure σx2 per indicare che si tratta della varianza del campione
x = {x1 , . . . , xn }, nel caso si stia lavorando con più di un campione e ci sia pericolo di
confusione. La radice quadrata σ (oppure σx ) della varianza è lo scarto quadratico o deviazione
standard.
La varianza è un indice di dispersione: essa misura se i valori del campione siano o no lontani
dal loro baricentro x̄. Valori grandi della varianza indicano che vi sono valori del campione
lontani da x̄. Viceversa se σ 2 = 0 allora tutti gli xi sono necessariamente uguali a x̄, perché
ciò vorrebbe dire che nella somma della formula (3.2) tutti i termini sono nulli.
Se b ∈ R e yi = xi + b, allora σx2 = σy2 . Infatti sappiamo già che ȳ = x̄ + b e dunque σy2 è
uguale a
n
n
n
i=1
i=1
i=1
1X
1X
1X
(yi − ȳ)2 =
(xi + b − x̄ − b)2 =
(xi − x̄)2 = σx2 .
n
n
n
Del resto, intuitivamente, sommare b a tutti gli elementi del campione significa spostare di b
anche il baricentro x̄, ma ciò non cambia la dispersione del campione rispetto al baricentro.
È anche facile verificare che se yi = a xi allora σy2 = a 2 σx2 .
Un’altra espressione per la varianza si ottiene sviluppando il quadrato nella (3.2):
n
n
n
1 X 2 2x̄ X
1X
2
(xi − x̄) =
xi −
xi + x̄ 2 =
n
n
n
i=1
=
1
n
i=1
n
X
i=1
i=1
xi2 − x̄ 2 .
Media e varianza danno quindi delle indicazioni utili sui dati: ne indicano il valore centrale e
una misura della dispersione dei valori rispetto al valore centrale.
Vediamo ora cosa si può dire quando su ogni individuo vengono fatte due misurazioni. Nel
prossimo paragrafo affronteremo invece il caso, più complesso e interessante, in cui, per ogni
individuo, vengono invece misurate n quantità numeriche.
In questo caso quindi i dati si presentano sotto forma di vettori (x1 , y1 ), (x2 , y2 ), . . . , (xn , yn ).
Chiediamoci se vi sia una relazione di tipo lineare tra i due caratteri, ovvero se esistano due
numeri a e b tali che, grosso modo, si abbia yi = axi + b, i = 1, . . . , n. Dobbiamo cioè cercare
la retta ax + b = y che approssima meglio y come funzione di x (e la chiameremo la retta
di regressione). Più precisamente: in generale non esisteranno dei numeri a, b ∈ R tali che
si abbia esattamente yi = axi + b per ogni i = 1, . . . , n. Esisterà però una retta che rende
minimi gli scarti tra i valori yi e axi + b, in un certo senso la retta che meglio delle altre spiega
i valori yi come funzione lineare-affine degli xi .
Cerchiamo dunque due numeri a, b ∈ R in maniera che la quantità
S(a, b) =
n
X
i=1
(yi − axi − b)2
3.1 Statistica Descrittiva
45
sia minima. Conviene sommare e sottrarre le medie all’interno del quadrato, cioè
S(a, b) =
n
X
i=1
((yi − ȳ) − a(xi − x̄) + (ȳ − b − a x̄))2 .
Sviluppando il quadrato si trova
=
S(a, b) =
n
X
2
2
(yi − ȳ) + a
(xi − x̄)2 +
n
X
i=1
+n(ȳ − b − a x̄)2 − 2a
+(ȳ − b − a x̄)
n
X
i=1
|
i=1
n
X
i=1
(yi − ȳ)(xi − x̄)+
n
X
(yi − ȳ) −2a(ȳ − b − a x̄)
(xi − x̄) .
{z
i=1
}
=0
Le due quantità indicate sono nulle perché, ad esempio,
n
X
i=1
(yi − ȳ) =
n
X
i=1
|
{z
=0
}
yi − nȳ = nȳ − nȳ = 0 .
Se poniamo
n
(3.3)
σxy
1X
(xi − x̄)(yi − ȳ),
=
n
i=1
allora si può scrivere
1
S(a, b) = σy2 + a 2 σx2 − 2aσxy + (ȳ − b − a x̄)2 .
n
Poiché b compare unicamente nell’ultimo termine, è chiaro che, per ottenere il minimo, deve
essere b = ȳ − a x̄. Basta quindi trovare il valore di a che rende minimo il trinomio
a → a 2 σx2 − 2aσxy + σy2 .
Derivando e uguagliando a 0 si trova 2aσx2 − 2σxy = 0. Dunque,
(3.4)
a=
σxy
,
σx2
b = ȳ −
σxy
x̄ .
σx2
La retta y = ax + b si chiama la retta di regressione del carattere y sul carattere x. In realtà
i valori di a e b appena calcolati sono solo dei valori nei quali le derivate parziali di S si
46
Capitolo 3. Analisi multivariata
annullano (cioè quello che si chiama un punto critico) e ciò in generale non garantisce che
si tratti di un punto di minimo (potrebbe anche essere di massimo o di sella o altro ancora).
Non è difficile però vedere che se la variabile (a, b) tende all’infinito, allora anche il valore
di S tende all’infinito. Inoltre sappiamo che una tale funzione, continua e che vale infinito
all’infinito, possiede necessariamente un minimo ed inoltre che tale punto è necessariamente
un punto critico. Poiché il punto (a, b) calcolato in (3.4) è l’unico punto critico di S, se ne
deduce che esso è anche l’unico punto di minimo della funzione S.
La quantità σxy si chiama la covarianza di x e y. Sviluppando i prodotti nella (3.3), si trova
l’espressione equivalente
n
1X
xi yi − x̄ ȳ .
σxy =
n
i=1
σ
Osserviamo che il coefficiente angolare a = xy2 della retta di regressione ha lo stesso segno
σx
della covarianza σxy . Se dunque σxy > 0, ciò indica che y tende a crescere al crescere di x.
Ci si può aspettare qualcosa del genere, ad esempio, se x e y fossero rispettivamente il peso
e l’altezza di individui. Se invece σxy < 0, l’effetto di x su y sarà antagonista: al crescere dei
valori di x i valori di y tenderanno a decrescere.
•
•
•
•
•
•
•
• • •
•• ••
•
• •
••
• •
• •
•
•
•
•
•
•
•
••
••
•
•
•
•
•
•
• ••
•• • •
•
•
•
•• •• • • • •
•
• •••• •• • • •• ••
••
•• • ••
• •
•
•
••
•
•
••
•
•
•
• • •
• ••
• •
• •
• •
• •
•• •
•
•
•
•
•
•
•
•
•
••
• • ••• •
• ••
•• • • •• •
•
•
•
•
•
•
•
•
• • • • ••
• •••
•
• •• • •• •
•••
••
••
•
• •
• ••
• • •
•• • • •
•
••
•
•
•
•
•
•
•
•
•
•
•
•
•
•
Figura 3.1 Esempio di grafico di due caratteri con una correlazione positiva, con la relativa retta di
regressione.
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
• • •••
•
•
••
.....................
••
• •
.............•....•....•
•
•
••
•
•
..........•....•....•..•
•
••
• • ................•.....•.........
•
•
•
•
.
•
.
.
.
.
.
.
.
.
.
•
•
• •• ................ •
• •
••
•
•
•••
• •• • •• • • •....•......•.................•................. • ••••
• •
.
• •
.
.
.
•
.
.
•• • •
•
.
.
.
•
•
.
.
.
•
.
.
•
.
.
.
•
.•..•...•
•
•
...................•..
•
•
•
•
•
..........•...•........ •
•
•
••
•• •
•
...••
.....................•
•
• • • •• ••
••
..•
• • ••
....•................. • •• •
•
•
•
• • •
• .•.......•...............•.............
•• •
•
• • •
•
•
•
.....................
•
• ••
••
•
......
••
•
•
•
•
•
•
•
•
• ••
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
Figura 3.2 Qui, invece, la correlazione è negativa.
3.2 Dati multidimensionali
47
Si chiama coefficiente di correlazione dei caratteri x e y la quantità
ρx,y =
σxy
·
σx σy
Si può dimostrare che si ha sempre −1 ≤ ρx,y ≤ 1. Un valore di ρx,y vicino a 0 indica scarsa
correlazione tra i due caratteri. Viceversa valori di ρx,y vicini a −1 indicheranno una forte
correlazione antagonista e valori vicini a 1, al contrario, una forte correlazione all’unisono.
Il pregio del coefficiente ρx,y , rispetto alla covarianza, è che esso è insensibile ai cambiamenti
di scala: se tutti i valori di xi vengono moltiplicati per uno stesso numero a > 0 ed i valori
di yi per uno stesso numero b > 0, il coefficiente di correlazione non cambia. Infatti σxy
risulterebbe moltiplicato per ab, σx per a e σy per b.
E3.1 Scrivere una funzione scilab che, date due variabili, ne fa il plot e aggiunge al
grafico la loro retta di regressione.
3.2 Dati multidimensionali
Si può dire che lo scopo della statistica descrittiva è di estrarre dai dati raccolti le informazioni
più rilevanti che essi contengono.
Nella situazione più semplice, in cui i dati consistono nel rilevamento di un singolo carattere
per ogni individuo di un campione, media e varianza forniscono delle informazioni semplici sul
baricentro e sulla dispersione dei valori osservati. In presenza di 2 caratteri un’informazione
supplementare è data dalla covarianza (o dal coefficiente di correlazione), che misura la dipendenza tra i caratteri.
Sono però possibili situazioni più complesse in cui occorre considerare più di 2 caratteri per
individuo. In questo caso infatti è più difficile tenere conto delle dipendenze tra i caratteri e
non è più possibile fare un grafico dei dati come nelle figure del paragrafo precedente.
In questo capitolo svilupperemo dei metodi di analisi di più caratteri. A differenza dei casi
semplici del capitolo precedente, in cui calcoli e grafici si sarebbero potuti fare con un po’
di pazienza anche a mano, per i metodi di questo capitolo sarà inevitabile l’uso di calcolatori
e di software specializzato. Lo studio della teoria dovrà dunque avanzare di pari passo con
l’acquisizione della capacità di utilizzare questi strumenti di calcolo.
In generale supporremo che i dati siano della forma seguente. Vengono osservati n individui,
per ciascuno dei quali sono rilevati p caratteri (o variabili) che supporremo tutti numerici.
Siamo quindi in presenza di p variabili che indicheremo X (1) , . . . , X(p) .
Rappresenteremo i dati nella forma della matrice
X = (xij ) i=1,...,n
j =1,...,p
in cui le righe corrispondono agli individui e le colonne ai caratteri: xij sarà dunque il valore
del carattere j -esimo misurato sull’individuo i-esimo.
I dati si possono anche vedere come una nuvola di n punti in Rp (sono i punti le cui coordinate
sono date dalle righe della matrice X dei dati). Indicheremo con x1 , . . . , xn questi vettori.
Viceversa ognuna delle colonne della matrice X contiene i valori assunti da una delle variabili
X (1) , . . . , X(p) .
48
Capitolo 3. Analisi multivariata
1a var.
↓

x11
1◦ individuo →
2◦ individuo →  x21






...





◦
n individuo →
xn1
...
...
...
...
...
p a var.
↓

x1p
x2p 











xnp
Figura 3.3 Il tipico aspetto di una matrice dei dati: con molte righe (quanti sono gli individui recensiti)
rispetto alle colonne. Ognuna delle righe può essere pensata come un vettore di Rp (p è il numero delle
variabili).
Possiamo iniziare l’analisi calcolando per ciascuna delle variabili le medie, che indicheremo con x̄·1 , . . . , x̄·p , e le varianze e poi le covarianze di ognuna delle variabili con le altre.
Chiameremo baricentro dei dati considerati il vettore x̄ di cui i numeri x̄·1 , . . . , x̄·p sono le
coordinate.
Si chiama matrice di covarianza delle variabili X(1) , . . . , X(p) la matrice p × p che ha come
elemento di posto ij la covarianza tra la variabile X(i) e la variabile X (j ) . Si tratta quindi di
una matrice che ha sulla diagonale le varianze delle singole variabili (la covarianza di X(i) con
se stessa non è altro che la varianza di X(i) ) mentre riporta fuori della diagonale le covarianze
delle variabili tra di loro. Si tratta chiaramente di una matrice simmetrica, poiché la covarianza
di X(i) con X (j ) è la stessa di quella di X(j ) con X (i) .
Numericamente gli elementi della matrice di covarianza, che indicheremo con 0, sono espressi
in termini della matrice X dei dati da
n
n
h=1
h=1
1X
1X
(xhi − x̄·i) (xhj − x̄·j ) =
xhi xhj − x̄·i x̄·j .
0ij =
n
n
Analogamente si definisce la matrice di correlazione: sarà la matrice che ha come elemento
di posto ij il coefficiente di correlazione tra la variabile X (i) e la variabile X (j ) . Naturalmente
gli elementi sulla diagonale della matrice di correlazione sono tutti = 1, perché il coefficiente
di correlazione tra una variabile e se stessa vale sempre 1.
3.3 Statistica descrittiva in scilab
Cominciamo a vedere i comandi che manipolano dei dati. Per prima cosa bisogna ‘‘importarli’’. Prendiamo per cominciare i dati sulla concentrazione di ozono che si trovano
nel file dei dati http://160.80.10.11/ processi/lc2data.htm . Occorre catturare i dati e fare
un copia/incolla su un editor ascii. Quindi salvarli (solo i numeri) in un file. Diciamo
c:\dida\lc2\ozono.txt.
Per acquisirlo sotto scilab il comando è
-->xx=read(’c:\dida\lc2\ozono.txt’,-1,4);
3.3 Statistica descrittiva in scilab
49
Ricordiamo che nel comando read , bisogna prima dare il nome del file nel quale si trovano
i dati (tra ’ ’ o " "), poi il numero di righe che si vuole leggere (-1 indica fino all’ultima) ed il
numero di colonne (qui sono 4). I dati della concentrazione di ozono si trovano nella prima
colonna. Quindi, per mettere i dati relativi in un vettore,
-->oz=xx(:,1);
Ora il vettore oz contiene i dati che ci interessano. Calcolare la media è facile:
-->mean(oz)
ans
=
42.099099
Per la varianza e la deviazione standard bisogna sempre fare attenzione. Una possibilità
consiste nel farsela a mano. Per la varianza basta fare
-->s2oz=mean((oz-mean(oz)).ˆ2)
s2oz
=
1097.3145
Mentre la deviazione standard si ottiene facendo la radice quadrata
-->sqrt(s2oz)
ans
=
33.125738
Per la deviazione standard ci sarebbe un comando apposta
-->st_deviation(oz)
ans
=
33.275969
Che dà però un risultato un po’ diverso. In effetti spesso la varianza viene definita dividendo
per n − 1 invece che per n. Si tratta di una scelta motivata dall’uso che si fa della deviazione
standard in statistica inferenziale, ed è in effetti la scelta di scilab. Verifichiamolo
Paolo Baldi
Corso di Laboratorio di Calcolo
Tor Vergata 2013-14
50
Capitolo 3. Analisi multivariata
-->st_deviation(oz)*sqrt(length(oz)-1)/sqrt(length(oz))
ans
=
33.125738
Un altro comando utile è mvvacov, che produce la matrice di varianza-covarianza:
-->mvvacov(xx)
ans
=
1097.3145
1047.0647
- 71.857982
219.52504
1047.0647
8233.8886
- 40.873225
253.16614
- 71.857982
- 40.873225
12.543294
219.52504
253.16614
- 16.7053
- 16.7053
90.00211
avremmo anche potuto usarlo per calcolare la varianza
-->mm=mvvacov(oz)
ans
=
1097.3145
È opportuno sottolineare che mvvacov usa la normalizzazione che ci interessa (dividendo
per n). Qualche volta avremo bisogno della matrice di correlazione, cioè di quella che ha al
posto ij il coefficiente di correlazione tra i caratteri xi e xj . Come la si può ottenere ? Due
possibilità. La prima usa un elemento il costrutto for ... end:
-->for ii=1:4,for jj=1:4,mcor(ii,jj)=mm(ii,jj)/sqrt(mm(ii,ii))
/sqrt(mm(jj,jj));end;end;
-->mcor
mcor
=
1.
.3483417
.3483417
1.
- .6124966
.6985414
- .1271835
.2940876
3.3 Statistica descrittiva in scilab
- .6124966
- .1271835
.6985414
.2940876
1.
- .4971897
51
- .4971897
1.
Il secondo metodo è il migliore ed usa il comando diag. Questo comando è multiforme.
• applicato ad una matrice m produce un vettore contenente gli elementi sulla diagonale
di m.
• applicato a un vettore produce una matrice diagonale, con sulla diagonale le coordinate
del vettore.
Dunque diag(diag(m)) è la matrice diagonale con la stessa diagonale di m. Un attimo
di riflessione indica che la matrice di correlazione si ottiene anche con il comando
-->sqrt(diag(diag(mm)))ˆ(-1)*mm*sqrt(diag(diag(mm)))ˆ(-1)
ans
=
1.
.3483417
.3483417
1.
- .6124966
- .1271835
.6985414
.2940876
- .6124966
.6985414
- .1271835
.2940876
1.
- .4971897
- .4971897
1.
Osserviamo che la variabile v1 (concentrazione di ozono) è leggermente correlata con la v2
(irraggiamento solare), fortemente correlata con la v4 (temperatura) e fortemente correlata
negativamente con la v3 (forza del vento).
Nell’analisi di dati unidimensionali uno strumento utile sono gli istogrammi. Dato un insieme di misurazioni, il loro istogramma si ottiene suddividendo le osservazioni in intervalli
e costruendo sopra ognuno di questi intervalli dei rettangoli le cui aree siano proporzionali
al numero di osservazioni che cadono nell’intervallo. Per tracciare un istogramma scilab
prevede il comando histplot:
-->clf();histplot(21,xx)
produce l’istogramma dei valori contenuti nel vettore xx suddividendoli in 21 intervalli (di
uguale ampiezza). Da notare che sta all’operatore di decidere il numero d’intervalli in cui
suddividere i dati. Il problema di stabilire in quante classi bisogna suddividere i dati sembra
stupido ma ha in realtà una lunghissima storia. Sono state proposte molte formule per decidere
il numero di classi. Occorre infatti trovare un giusto mezzo tra troppe classi (che fanno
comparire dettagli senza importanza) e troppo poche. La formula a cui si fa riferimento di
solito è quella di Sturges: il numero di classi k è
k = 1 + blog2 nc
52
Capitolo 3. Analisi multivariata
dove b c indica la funzione parte intera e n è il numero di osservazioni. Si tratta di una regoletta
semplice e molto rozza, ma una discussione su questo punto richiederebbe troppo tempo e
regole più raffinate sono di uso più complicato.
Anche qui sono possibili molte opzioni (ad esempio si possono suddividere i dati in intervalli
che non sono di eguale ampiezza). Anche qui è meglio rinviare allo help di scilab
piuttosto che disperdersi in dettagli. C’è però una opzione che è utile indicare. I due comandi
-->histplot(21,xx)
e
-->histplot(21,xx,normalization=%f)
producono due istogrammi simili che differiscono solo per la scala delle ordinate. Nel secondo
normalization=%f) sulle ordinate compaiono gli effettivi, cioè i numeri di osservazioni
che appartengono alle varie classi. Nel primo invece compare la proporzione di individui
appartenenti alle varie classi. Dunque se xx contiene 1000 osservazioni di cui 82 nella prima
classe, lo istogramma con l’opzione normalization=%f produrrà il primo rettangolo alto
82, altrimenti si otterrebbe un rettangolo alto 0.082 = 82/1000. I due istogrammi sembrano
identici perché scilab comunque provvede a riscalare le unità di misura sugli assi per
approfittare al massimo dello schermo del computer.
E3.2 Generare un campione di 512 numeri casuali con distribuzione N(0, 1), farne l’istogramma e poi sovrapporre al grafico ottenuto quello della densità della legge N(0, 1).
E3.3 Definire una funzione scilab che, dato un insieme di osservazioni produce un istogramma con un numero di classi calcolato automaticamente con la regola di Sturges.
E3.4 I dati del file xx2006 contengono i risultati di un test a risposte multiple composto da
30 domande (le colonne) al quale hanno partecipato 530 studenti (le righe): 1=risposta giusta,
0=risposta sbagliata, il voto finale di ognuno essendo il numero totale di risposte giuste. Il file
è composto di 530 righe (gli individui) e 30 colonne (le risposte).
a) Importare i dati sotto scilab.
b) Per ogni esercizio calcolare la media di risposte giuste. Qual esercizio sembra essere il
più facile ? Quale il più difficile ?
c) Produrre la lista dei voti dei 530 studenti. Qual è lo studente più bravo ? E il più
scadente ? Qual è la media dei voti ? E la mediana ? Il voto di superamento era fissato a 16.
Quanti studenti hanno superato il test ? Fare un istogramma dei voti.
d) Per l’esercizio n.11 calcolare la media delle risposte tra gli studenti con voto finale ≥ 24,
quelli tra 16 et 23 e quelli con voto ≤ 15.
e) Per ognuno dei 30 esercizi calcolare la correlazione con il voto finale. Quale degli
esercizi è probabilmente poco adatto a fornire una valutazione efficace delle capacità degli
studenti ?
f) Quale degli esercizi invece pare più adatto a discriminare gli studenti bravi da quelli
meno validi ? Calcolare per questo esercizio la media di soluzioni esatte tra gli studenti che
3.4 Analisi in componenti principali
53
hanno la sufficienza (voto finale≥ 16) e tra gli altri. Ripetere questa operazione per l’esercizio
individuato in e) e confrontare.
3.4 Analisi in componenti principali
In questo paragrafo e nel prossimo vedremo dei metodi di analisi di dati multidimensionali.
L’idea dell’analisi multivariata è di proiettare i punti su un piano ed osservare il grafico dei
punti proiettati. Naturalmente facendo così si perde dell’informazione: punti che appaiono
vicini nella proiezione possono in realtà essere molto distanti tra di loro. Per questo sarà
importante
a) innanzitutto cercare il piano migliore su cui effettuare la proiezione;
b) essere in grado di stimare quanto si è perso facendo la proiezione, in modo da valutare
quanto i punti della proiezione siano una rappresentazione fedele dei punti originali.
Discutiamo ora il punto a), partendo dal caso più semplice della proiezione degli n punti su
una retta per l’origine. Cerchiamo cioè la retta ‘‘migliore’’ su cui proiettare i punti, ricordando
che la proiezione di un punto x su una retta è il punto della retta che si trova più vicino a x.
Osserviamo intanto che una retta per l’origine può essere individuata da un vettore v ∈ Rp
di lunghezza 1: dato un tale vettore l’insieme dei punti di Rp della forma tv, al variare di
t ∈ R descrive una retta, e d’altra parte ogni retta passante per l’origine è di questa forma.
Osserviamo comunque che, data una retta per l’origine, questo vettore non è unico, dato che
v e −v individuano la stessa retta.
La proiezione di un punto x ∈ Rp sulla retta individuata dal vettore unitario v è il punto tv
(un punto della retta, quindi) dove t è pari al prodotto scalare hx, v i.
Ricordiamo infatti che il prodotto scalare hx, y i di due vettori di Rp è il numero |x ||y | cos θ,
dove θ è l’angolo compreso tra i due vettori x e y. Poiché nel nostro caso supponiamo
|v | = 1, dunque hx, v i = |x | cos θ. La Figura 3.4 illustra questo rapporto tra prodotto scalare
e proiezione di un punto su una retta.
•x
.......
... .....
...
...
.
.
.
...
...
...
...
...
.
.
...
.
.
.
...
.
.
.
...
.
.
.
...
.
.
.
...
.
.
.
...
.
. ...
.
.
.
.......... . .... ...
.
.
.
....
.
.
.
.
.
.
.
.... .
...
. ....
........
........
... .......
.
.
.
.
.
.
.
.
.
...
.
.....
..
...
.......
................
...
.
...
.
.
.
.
.
.
.
.
.
.
......
...
........
...
.......
... ..............
.
.
.. ......
.........
. ...
. ...
.
.
.
..
θ
•v
•
-
0
Figura 3.4 Se |v| = 1, il valore del prodotto scalare dei vettori x e v è dato dalla distanza tra l’origine
ed il punto segnato con una freccia. Quest’ultimo è anche la proiezione di x sulla retta individuata da v.
Si tratta chiaramente del punto della retta che si trova più vicino a x.
Il prodotto scalare di due vettori x e v si esprime facilmente anche in termini delle loro
54
Capitolo 3. Analisi multivariata
coordinate. Si può infatti mostrare che vale la formula
hx, y i =
(3.5)
p
X
xi yi .
i=1
In particolare il prodotto scalare è lineare, cioè si ha
hx, αy + βzi = α hx, y i + β hx, zi
per ogni α, β ∈ R e x, y, z ∈ Rp .
Tornando agli n punti x1 , . . . , xn in Rp , quale sarà il vettore unitario v tale che la loro proiezione
sulla retta individuata da v sia la più fedele possibile ? Ricordando il significato intuitivo
della nozione di varianza, una proiezione sarà tanto più fedele quanto più grande sarà la
dispersione dei punti ottenuti dalla proiezione sulla retta, ovvero quanto più grande sarà la
varianza dell’insieme di punti hv, x1 i, . . . , hv, xn i, che ora costituiscono un campione di numeri
reali. Osserviamo comunque che, grazie alla (3.5), possiamo vedere questi punti come i valori
di una nuova variabile (o carattere). Si tratterà del carattere che nell’osservazione i-esima
prende il valore
v1 xi 1 + . . . + vp xip
e che quindi è combinazione lineare delle variabili X (1) , . . . , X(p) con i coefficienti v1 , . . . , vp .
Cominciamo col calcolare la media µ(v) di questi valori: poiché il prodotto scalare è lineare,
n
n
k=1
k=1
1X 1X
µ(v) =
xk = hv, x̄ i .
hv, xk i = v,
n
n
Dunque la media µ(v) dei punti proiettati non è altro che la proiezione sulla retta individuata
da v del baricentro x̄ dei punti x1 , . . . , xn . Calcoliamone la varianza. Anzi cerchiamo una
formula per trovare la covarianza dei punti proiettati su due direzioni v e w, che indicheremo
σ (v, w). Poiché hxk , v i − hx̄, v i = hxk − x̄, v i, si ha
n
1X
(hxk , v i − hx̄, v i)(hxk , wi − hx̄, wi) =
σ (v, w) =
n
2
=
k=1
n
X
1
n
k=1
hxk − x̄, v ihxk − x̄, w i .
Sviluppando il prodotto
p
p
X
X
(xki − x̄·i )vi
(xkj − x̄·j )wj =
hxk − x̄, v ihxk − x̄, w i =
i=1
=
p
X
j =1
(xki − x̄·i )(xkj − x̄·j )vi wj .
i,j =1
3.4 Analisi in componenti principali
55
e riprendendo il calcolo e scambiando le due somme vediamo apparire dei termini legati alla
matrice di covarianza 0;
p
n
1XX
(xki − x̄i )(xkj − x̄j )vi wj =
σ (v, w) =
n
2
k=1 i,j =1
p
X
1
vi wj
=
n
i,j =1
|
n
X
k=1
(xki − x̄i )(xkj − x̄j ) =
{z
}
=0ij
p
X
0ij vi wj .
i,j =1
Quest’ultima espressione si può scrivere in maniera compatta
p
X
i,j =1
0ij vi wj =
p
X
i=1
vi
p
X
j =1
0ij vj = h0v, wi .
| {z }
(0v)i
In conclusione (la matrice 0 è simmetrica)
σ 2 (v, w) = h0v, wi = h0w, v i .
Scegliendo v = w si ha dunque che la varianza dei punti proiettati nella direzione v è
σ 2 (v) = h0v, v i .
Poiché una varianza è sempre ≥ 0, si ottiene dunque che, per ogni vettore v (unitario o no),
h0v, v i ≥ 0 .
Dunque la matrice di covarianza 0 è sempre semidefinita positiva e tutti i suoi autovalori
sono ≥ 0. Quindi il problema di trovare il vettore unitario v lungo il quale la nuvola di punti
considerata abbia la massima dispersione equivale a trovare il vettore unitario v per il quale
la quantità h0v, v i sia massima.
È abbastanza facile vedere che il vettore v di modulo 1 per cui la quantità h0v, v i è massima
è il vettore v1 , autovettore relativo all’autovalore più grande λ1 di 0. Proveremo questo fatto
in due modi diversi e che fanno uso di due tipi di ragionamento completamente diversi.
1◦ modo. Indichiamo con v1 , . . . , vn gli autovettori di 0, che possiamo scegliere di modulo
unitario e a due a due ortogonali. Essi costituiscono una base e, se v è un vettore tale che
|v | = 1, allora si può scrivere
p
X
v=
αi v i .
i=1
56
Capitolo 3. Analisi multivariata
Poiché supponiamo |v | = 1, deve essere
Pp
2
i=1 αi
2
p
1 = |v | = hv, v i =
=
p
X
i,j =1
= 1. Infatti
X
αi vi ,
p
X
j =1
i=1
αi αj hvi , vj i =
p
X
αj vj =
αi2 .
i=1
Infatti i vettori v1 , . . . , vp sono a due a due ortogonali e hvi , vj i = 0 se i 6= j , mentre hvi , vi i =
|vi |2 = 1). D’altra parte poiché 0vi = λi vi
p
h0v, v i =
X
αi 0vi ,
j =1
i=1
p
=
X
i,j =1
p
X
λi αi αj hvi , vj i =
αj vj =
p
X
λi αi2 .
i=1
Se supponiamo α1 = 1, α2 = . . . = αp = 0, e cioè v = v1 , allora
h0v, v i = λ1 .
Per ogni altro vettore v di modulo 1 d’altra parte si ha, poiché λ1 è il più grande degli autovalori,
h0v, v i =
p
X
i=1
λi αi2
≤ λ1
p
X
i=1
αi2 = λ1 .
In conclusione la quantità h0v, v i è sempre ≤ λ1 ed è = λ1 solo se |α1 | = 1, cioè se v = v1
oppure v = −v1 . Dunque v = v1 e v = −v1 sono i vettori di modulo 1 per cui la quantità
σ 2 (v) = h0v, v i è massima.
In realtà siamo stati un po’ inesatti nel ragionamento appena fatto. Perché ?
2◦ modo. Il problema considerato non è altro che la determinazione del massimo della funzione
F (u) = h0u, ui sulla sfera di raggio 1. Si tratta quindi di un problema di massimo vincolato,
che si può affrontare col metodo dei moltiplicatori di Lagrange. La sfera si può indicare come
{G = 1}, dove G(u) = |u|2 . Poiché sappiamo che la sfera è compatta e F è continua, esiste
sicuramente un punto di massimo di F su {G = 1} ed il metodo dei moltiplicatori di Lagrange
assicura che questo punto di massimo u deve essere soluzione di
F 0 (u) + λG0 (u) = 0 .
(3.6)
Calcoliamo il gradiente F 0 . Scrivendo in coordinate si ha
(3.7)
p
p
X
∂ X
∂F
=
0ij ui uj =
(0`i ui + 0i` ui ) = (20u)`
∂u` ∂u`
i,j =1
i=1
Esercizi
57
ovvero, dato che 0 è simmetrica,
F 0 (u) = 20u .
Se ne deduce che anche G0 (u) = 2u, dunque l’equazione dei moltiplicatori (3.6) diventa
0u + λu = 0
ed ha soluzione se e solo se −λ è un autovalore di 0 ed u è l’autovettore corrispondente. Se
ui è l’autovettore associato a λi , allora
F (ui ) = λi .
Il massimo è quindi raggiunto in corrispondenza dell’autovettore associato al più grande degli
autovalori ed il massimo è appunto il più grande degli autovalori.
Abbiamo dunque visto una caratterizzazione del più grande autovalore di una matrice simmetrica 0 come il massimo della forma quadratica u → h0u, ui sulla sfera unitaria. Questa
caratterizzazione (che è valida anche se la matrice non è definita positiva come le matrici di
covarianza) è un risultato d’interesse generale.
Sottolineiamo comunque che questo risultato vale solo se la matrice è simmetrica: la simmetria
di 0 è stata utilizzata nella (3.7).
E3.5 Sapreste esprimere in termini di autovalori la quantittà
sup hAu, ui
|u|=1
quando la matrice A non è simmetrica ?
Una volta stabilito che la direzione individuata da v1 è quella per cui la proiezione dei punti
ha dispersione massima, si può dimostrare allo stesso modo che v2 è il vettore per cui h0v, v i
è massima, tra i vettori che sono ortogonali a v1 , che v3 è la direzione ortogonale sia a v1 che
a v2 per cui h0v, v i è massima e così via.
I vettori v1 , . . . , vp si chiamano anche le direzioni principali. Anzi v1 è la prima direzione
principale, v2 la seconda e così via. In conclusione il piano individuato dalle direzioni v1 e
v2 è quello cercato: la proiezione della nuvola di punti su questo piano è quella nella quale i
punti proiettati hanno la massima dispersione. Questo piano si chiama anche il primo piano
principale; anche gli altri piani individuati da coppie di direzioni principali vi , vj vanno tenuti
in considerazione e le proiezioni relative possono fornire informazioni utili; le proiezioni su
questi (che chiameremo piani principali) possono infatti dare informazioni complementari a
quelle fornite dalla proiezione sul primo piano principale.
Prima di vedere degli esempi concreti poniamoci la questione di valutare quanto i valori
proiettati siano una immagine fedele dei dati: come abbiamo già osservato è possibile che
punti in realtà distanti tra di loro appaiano vicini nella proiezione.
58
Capitolo 3. Analisi multivariata
Chiameremo dispersione totale dei dati la quantità
n
1X
|xi − x̄ |2 .
n
i=1
Osserviamo che, se (vi )i=1,...,p è una base formata da vettori ortogonali e di modulo uguale a
1, allora si ha, per ogni z ∈ Rp ,
2
|z | =
(3.8)
p
X
j =1
hz, vj i2 .
Infatti (vj )j =1,...,p costituisce una base ortonormale per cui si ha
z=
p
X
j =1
hz, vj ivj .
Dunque
2
|z| = hz, zi =
p
DX
i=1
hz, vi ivi ,
p
=
X
E
p
X
j =1
hz, vi ihz, vj ihvi , vj i =
i,j =1
hz, vj ivj =
p
X
i=1
hz, vi i2
da cui segue la (3.8) osservando che i prodotti scalari hvi , vj i sono uguali a 0 per i 6= j e uguali
a 1 per i = j . Torniamo al calcolo della dispersione:
n
n
p
1 XX
1X
|xi − x̄ |2 =
hxi − x̄, vj i2 =
n
n
i=1 j =1
i=1
=
p
n
X
1X
n
j =1
|
i=1
2
hxi − x̄, vj i =
{z
}
p
X
λj .
j =1
=dispersione del carattere vj =λj
Dunque la dispersione totale è sempre uguale alla somma degli autovalori della matrice
di covarianza. Quanto vale la dispersione dei punti proiettati sul piano principale ? Basta
osservare che la loro matrice di covarianza è
λ1 0
h0v1 , v1 i h0v1 , v2 i
.
0̃ =
=
0 λ2
h0v1 , v2 i h0v2 , v2 i
Per il calcolo appena fatto dunque la dispersione dei punti proiettati sul primo piano principale
è uguale alla traccia di 0̃, e dunque a λ1 + λ2 . Più in generale, la dispersione della proiezione
Esercizi
59
sul piano principale formato dai caratteri vh e vk è uguale a λh + λk . Definiremo la fedeltà della
proiezione su un piano come il rapporto tra la dispersione dei punti proiettati e la dispersione
totale. Per la proiezione sul primo piano principale la fedeltà vale dunque
λ1 + λ2
·
λ1 + . . . + λp
Si tratta di un numero sempre compreso tra 0 e 1 (gli autovalori sono tutti ≥ 0 e quindi
il denominatore è sempre più grande del numeratore), e che si usa come indicatore della
bontà della proiezione: tanto più la fedeltà risulta prossima a 1, tanto più i punti proiettati
costituiscono una immagine fedele dei dati originali.
Esempio 3.1 Vediamo in concreto come si fa unaACP. Cominciamo
con i dati delle conchiglie. Si tratta delle 4 misurazioni delle
conchiglie a torciglione (sphaeronassa mirabilis) della figura.
Lo scopo dell’ACP in questo caso è di studiare la forma delle
conchiglie per risalire alle proprietà della popolazione.
Dopo averli copiati e salvati come indicato prima, importiamoli
-->xx=read(’c:\dida\lc2\conchiglie.txt’,-1,4);
Calcoliamo la matrice di covarianza
-->mm=mvvacov(xx)
mm
=
.3242297
.2599237
.1985919
.2110335
.2599237
.2099856
.1608542
.1708110
.1985919
.1608542
.1249035
.1307719
.2110335
.1708110
.1307719
.1413012
Osserviamo che le 4 variabili sono tutte correlate positivamente. Se calcoliamo la matrice di
correlazione otteniamo
-->mmcor=sqrt(diag(diag(mm)))ˆ(-1)*mm*sqrt(diag(diag(mm)))ˆ(-1)
mmcor
=
1.
.9961500
.9961500
1.
.9868426
.9859437
.9932308
.9916267
60
Capitolo 3. Analisi multivariata
.9868426
.9932308
.9859437
.9916267
1.
.9843606
.9843606
1.
Da cui si vede che la correlazione è elevatissima (molto vicina a 1) per tutte le variabili.
Calcoliamo autovalori e autovettori
-->[dg,cb,dim]=bdiag(mm);cb,dg
cb
=
- .6371866
.6743886
- .3275909
.1785423
- .5135296
- .0457869
.8512392
- .0978913
- .3937586
- .3322839
- .3456081
- .7842809
- .4186105
- .6577925
- .2205243
.5860404
0.
0.
0.
0.
dg
=
.7950754
0.
0.
.0028923
0.
0.
0.
0.
.0003981
0.
0.
.0020541
I due autovalori principali sono il primo e il secondo. Procuriamoci una matrice 4 × 2 avente
come colonne i due autovettori principali.
-->vv=cb(:,1:2)
vv
=
- .6371866
.6743886
- .5135296
- .0457869
- .3937586
- .3322839
Esercizi
- .4186105
61
- .6577925
Le coordinate delle proiezioni sul piano generato da questi due autovettori si ottengono con
-->xxp=xx*vv
Infatti con questo comando si ottiene una matrice, xxp, che è n × 2, e che contiene, nella
prima colonna i prodotti scalari delle osservazioni con il primo autovettore (che si trova nella
prima colonna di vv) e nella seconda i prodotti scalari con il secondo autovettore. Il grafico
dei punti proiettati si può a questo punto ottenere, come sappiamo, con
-->clf();plot(xxp(:,1),xxp(:,2),".")
Vediamo come si può interpretare questa analisi. Intanto i due autovalori principali spiegano
la maggior parte della variabilità dei dati. La fedeltà della proiezione è infatti
-->(dg(1,1)+dg(2,2))/sum(dg)
ans
=
.9969364
Cioé una proporzione del 99.69%. È chiaro inoltre che dei due autovettori principali di gran
lunga il più rilevante è il primo. Osserviamo che si tratta di un vettore le cui componenti hanno
tutte lo stesso segno, con valori tutti vicini a − 21 . Si tratta dunque di una variabile che misura
la dimensione. Nel grafico, dunque, si trovano a sinistra le conchiglie grandi (che hanno tutte
le misurazioni con valori elevati), mentre a destra ci sono quelle piccole.
Il secondo autovettore invece mette in opposizione la prima variabile soprattutto con la terza e
la quarta. Si tratta dunque di una variabile di forma, che dà valori grandi a conchiglie strette e
lunghe e valori piccoli a conchiglie larghe e strette. Questa variabile però mostra una piccola
variabilità. Essenzialmente le conchiglie considerate hanno tutte la stessa forma e possono
essere solo un po’ più grandi o un po’ più piccole.
Supponiamo ora di sapere (come è in realtà) che le ultime 9 misurazioni si riferiscano a
conchiglie diverse (con 5 giri, invece di 6, come nella figura). Come si può fare un grafico
dei dati sul piano principale, che faccia apparire in modo diverso i punti relativi ai primi 22
individui e quelli relativi agli ultimi 9 ?
Basterà dare prima il comando
-->clf();plot(xxp(:,1),xxp(:,2),".")
in maniera che ora tutti i punti sono indicati con un pallino blu. E poi
-->plot(xxp(23:31,1),xxp(23:31,2), ".g")
62
Capitolo 3. Analisi multivariata
Quindi ora gli ultimi 9 punti vengono disegnati in verde nella stessa finestra grafica. Quindi
il grafico riporta i primi 22 punti in blu e gli ultimi 9 in verde (il verde copre il blu con cui
erano stati disegnati prima).
L’analisi in componenti principali, così come l’abbiamo introdotta finora, ha però l’inconveniente di dipendere in maniera artificiosa dalle unità di misura. Se, ad esempio, avessimo
deciso di misurare la prima delle quattro variabili (l’altezza) in decimi di millimetro, la matrice
di covarianza sarebbe stata diversa, così pure come autovalori e autovettori. Ed è chiaro che
un metodo di analisi corretto dovrebbe essere insensibile a dei cambiamenti di unità di misura.
Da un altro punto di vista, se tra le variabili considerate ce ne fosse una che presenta dei valori
molto superiori numericamente rispetto alle altre, allora il risultato dell’analisi risulterebbe
influenzato indebitamente dai valori di questa variabile e terrebbe poco conto delle altre.
Per questo motivo è opportuno effettuare, prima dell’analisi, una normalizzazione dei dati.
La cosa naturale consiste nel centrare le singole variabili e poi dividere ciascuna di esse per
la sua deviazione standard, in maniera che, alla fine, esse abbiano tutte una varianza uguale a
1. Questa operazione evidentemente eliminerà ogni effetto del tipo cambio di unità di misura
a cui abbiamo accennato sopra. Nel caso dei dati delle conchiglie questa operazione non era
proprio necessaria, dato che i valori numerici delle quattro variabili erano più o meno dello
stesso ordine. Ma in genere questa operazione di normalizzazione è indispensabile.
Procediamo ad un’analisi in componenti principali per i dati dell’ozono. Per prima cosa
dobbiamo procurarci i dati centrati e ridotti. Prima togliamo le medie: il comando center(xx,1) sottrae a ciascuna delle colonne la sua media (center(xx,2) avrebbe tolto
la media a ciascuna delle righe)1center
-->xx2=center(xx,1)
Verifichiamo che ora le variabili hanno media nulla
-->mean(xx2,1)
ans
=
1.0E-13 *
.0633727
- .3021407
.0793759
- .0256051
Ricordiamo infatti che il comando mean(xx2,1) produce le medie delle colonne della
matrice xx2. Analogamente mean(xx2,2) produce le medie delle righe.
Per dividere ogni colonna per la deviazione standard corrispondente il modo più elegante è di
calcolare la matrice di covarianza
-->mm=mvvacov(xx2);
e poi fare
Esercizi
63
-->xx2=xx2*sqrt(diag(diag(mm)))ˆ(-1);
Con questa operazione infatti viene divisa ogni colonna della matrice dei dati per la radice
quadrata della varianza relativa. È facile vedere (verificare!) che la matrice di covarianza
dei dati normalizzati xx2 è uguale alla matrice di correlazione dei dati originali xx. Ora
possiamo analizzare gli autovalori e gli autovettori della matrice di correlazione.
-->[dg,cb,dim]=bdiag(mcor);cb,dg
cb
=
- .5890040
- .7974891
.1146414
.0627912
- .3169087
.1233953
- .2777312
- .8984474
.4970366
- .3017048
.6905372
- .4302177
- .5528090
.5076996
.6579370
.0613370
dg
=
2.3598986
0.
0.
.2696752
0.
0.
0.
0.
0.
0.
0.
0.
.4757499
0.
0.
.8946763
I due autovalori più grandi sono il primo ed il quarto. Calcoliamo la proiezione sul piano
generato dai due autovettori principali (cioè quelli associati ai due autovalori più grandi) dei
dati. Il modo più elegante consiste nel formare una matrice 4 × 2, avente come colonne i due
autovettori. Trasponendo due volte. . .
-->vv=[cb(:,1)’;cb(:,4)’]’
vv
=
-
.5890040
.0627912
-
.3169087
-
.8984474
.4970366
-
.4302177
64
Capitolo 3. Analisi multivariata
-
.5528090
.0613370
Le coordinate delle proiezioni si ottengono quindi moltiplicando
-->xxp=xx2*vv
Possiamo ora fare il grafico nel piano dei punti proiettati.
-->clf();plot(xxp(:,1),xxp(:,2),".")
Un errore tipico a questo punto è quello di proiettare i dati originali, xx, invece di quelli normalizzati xx2. Lo si individua spesso facilmente perché il plot non risulta avere l’andamento
caratteristico delle variabili non correlate. Ricordate, infatti, che le variabili relative alle
direzioni principali sono tra loro non correlate.
Per valutare la fedeltà della proiezione facciamo il rapporto tra la somma dei due autovalori
principali e la somma di tutti gli autovalori (che è uguale a 4, dato che la somma degli autovalori
è uguale alla traccia e la matrice di correlazione ha tutti uni sulla diagonale).
-->(dg(1,1)+dg(4,4))/4
ans
=
.8136437
Cioé la fedeltà è uguale all’81.36%.
Prima di procedere con l’analisi di altri esempi di dati sarà opportuno scrivere una funzione che
realizzi una dopo l’altra le operazioni che abbiamo effettuato in linea nell’esempio dell’ozono.
Un problema che s’incontra nella redazione di una funzione che effettui l’analisi in componenti
principali viene dal fatto che il comando bdiag fornisce gli autovalori in ordine sparso ed
occorrerà, nel programma che ci accingiamo a scrivere, riordinarli per prendere i più grandi.
Ricordando il funzionamento del comando sort, come si fa, dopo avere dato il comando
bdiag, a ricavare l’autovettore relativo all’autovalore più grande ? Voilà:
-->[dg,cb,dim]=bdiag(mcor);
-->dg2=diag(dg);
-->[s,k]=sort(dg2);
-->v1=cb(:,k(1));
Infatti, k(1) è la posizione in cui l’autovalore più grande si trova nella matrice dg. Dunque
ora v1 è l’autovettore (colonna) associato all’autovalore più grande.
3.5 Analisi discriminante
65
E3.6 Fare un’analisi in componenti principali dei dati dei passeri di Bumpus. La storia dice
che il reverendo Bumpus raccolse, nel febbraio 1898, 49 passeri un po’ malconci dopo una
tempesta. Li curò, ma alcuni di essi non sopravvissero (nella base dati sono gli ultimi 28).
Il buon reverendo prese 4 misurazioni da ciascun animale, cercando poi di vedere se ci fosse
una relazione tra le dimensioni e la capacità di sopravvivenza. Fare un’analisi in componenti
principali dei dati dei passeri di Bumpus e farne il grafico, distinguendo con colori diversi le
due popolazioni.
E3.7 Fare le analisi in componenti principali per i dati sulla qualità del vino di Bordeaux. In
questo set di dati vengono confrontati alcune misurazioni meteorologiche del mese di aprile
e la qualità del vino della vendemmia successiva. Fare il grafico dei dati sul piano principale
usando come simbolo il ‘‘voto’’, in maniera da mettere in evidenza eventuali dipendenze tra
la qualità ed il clima nel mese di aprile precedente. Questi dati verranno analizzati anche con
i metodi dell’analisi discriminante, in questo caso forse più appropriati.
3.5 Analisi discriminante
Supponiamo di essere in presenza di misurazioni multidimensionali, come nel paragrafo precedente, ma provenienti da più popolazioni. Cioè le osservazioni sono suddivise in gruppi corrispondenti a popolazioni diverse (e lo studioso sa a quale popolazione appartenga ognuna
delle osservazioni).
Vi è una differenza tra le misurazioni di individui appartenenti a popolazioni diverse ? È
possibile decidere, solo a partire dalle misurazioni, a quale popolazione appartenga un singolo
individuo ? Ovvero è possibile determinare una regola che ad ogni individuo, in funzione delle
sue misurazioni, associ la popolazione a cui esso appartiene ?
Rispondere a queste domande ha un indubbio interesse sia pratico che teorico. Ad esempio
se le misurazioni fossero le osservazioni cliniche su un gruppo di pazienti ed i gruppi fossero
due, composti da coloro che sono affetti da una certa malattia e da quelli sani rispettivamente,
si potrebbe determinare una procedura automatica che a partire dalle misurazioni stabilisca se
un nuovo paziente sia malato o no.
Da un punto di vista teorico, invece, è interessante determinare il carattere (cioè la funzione
delle misurazioni) che meglio permette di discriminare tra i vari gruppi.
Supporremo ancora che i dati siano della forma di matrice
X = (xij ) i=1,...,n
j =1,...,p
dove xij indica la misurazione della variabile j -esima per lo i-esimo individuo; n è ancora il
numero totale di individui e p il numero di variabili.
Supporremo però che vi siano m popolazioni (o gruppi) presenti e che i primi n1 individui
appartengano alla popolazione 1, che quelli con indice compreso tra n1 + 1 e n1 + n2 appartengano alla seconda e così via fino a quelli con indice compreso tra n1 + . . . + nm−1 + 1
e n1 + . . . + nm−1 + nm , che apparterranno alla m-esima popolazione. Quindi n1 è l’effettivo
della prima popolazione, n2 quello della seconda e così via. Per semplicità indicheremo con
Paolo Baldi
Corso di Laboratorio di Calcolo
Tor Vergata 2013-14
66
Capitolo 3. Analisi multivariata
Ik l’insieme degli indici compresi tra nk−1 + 1 e nk (e quindi corrispondenti agli individui
della k-esima popolazione).
Cominceremo col chiederci se non vi sia una direzione u che discrimini il meglio possibile le
diverse popolazioni. Ovvero tale che nella proiezione nella direzione u le varie popolazioni
appaiano il più possibile ben separate tra di loro. Si tratta, come si vede, di un problema non
molto diverso da quello del paragrafo precedente, anche se ancora dobbiamo chiarire come
si possa caratterizzare matematicamente una tale direzione u. Anche qui la soluzione verrà
dall’analisi della matrice di covarianza 0.
Ricordiamo che il baricentro dei dati x̄ è stato definito nel paragrafo precedente come il vettore
le cui coordinate x̄·j sono date da
n
1X
xij .
x̄·j =
n
i=1
Possiamo però considerare anche i baricentri delle singole popolazioni, cioè i vettori ȳ1 , . . . , ȳm
le cui coordinate sono
ȳ1j =
1 X
1 X
1 X
xij , ȳ2j =
xij , . . . , ȳmj =
xij .
n1
n2
nm
i∈I1
i∈I2
i∈Im
La matrice di covarianza 0 si può ora scrivere
n
0hk
(3.9)
1X
(xih − x̄·h )(xik − x̄·k ) =
=
n
1
=
n
i=1
m hX
X
j =1 i∈Ij
i
(xih − x̄·h )(xik − x̄·k )
dove abbiamo semplicemente spezzato la somma tra le varie popolazioni. Studiamo più da
vicino le somme all’interno delle parentesi quadre. Sommando e sottraendo la media della
popolazione j -esima e sviluppando abbiamo
X
(xih − x̄·h )(xik − x̄·k ) =
i∈Ij
X
(xih − ȳj h + ȳj h − x̄·h )(xik − ȳj k + ȳj k − x̄·k ) =
=
i∈Ij
=
+
X
i∈Ij
(xih − ȳj h )(xik − ȳj k ) +
X
i∈Ij
X
(ȳj h − x̄·h )(ȳj k − x̄·k )+
i∈Ij
X
(ȳj h − x̄·h )(xik − ȳj k ) +
(xih − ȳj h )(ȳj k − x̄·k ) .
i∈Ij
3.5 Analisi discriminante
67
Le ultime due somme nella relazione precedente sono nulle. Infatti, poiché il termine ȳj h − x̄·h
non dipende da i,
X
i∈Ij
(ȳj h − x̄·h )(xik − ȳj k ) = (ȳj h − x̄·h )
X
(xik − ȳj k ) =
i∈Ij
hX
i
xik − nj ȳj k = 0
= (ȳj h − x̄·h )
i∈Ij
(la quantità tra parentesi quadre è nulla, ricordando la definizione dei baricentri ȳj k ). Sostituendo nella (3.9) abbiamo
0hk
m
i
1 XhX
=
(xih − x̄·h )(xik − x̄·k ) =
n
j =1 i∈Ij
m
i
1 XhX
=
(xih − ȳj h )(xik − ȳj k ) +
n
j =1 i∈Ij
{z
}
|
=Dhk
m
i
1 XhX
+
(ȳj h − x̄·h )(ȳj k − x̄·k ) .
n
j =1 i∈Ij
{z
}
|
=Thk
Uno sguardo alle somme che definiscono la matrice D mostra che quest’ultima non è altro che
la somma delle covarianze Dentro le singole popolazioni, mentre T descrive l covarianze Tra
le singole popolazioni rispetto al baricentro generale x̄. Più precisamente, D si può scrivere
m
1X
D=
nj 0 (j )
n
j =1
P
(j )
dove 0hk
= n1j
i∈Ij (xih − ȳj h )(xik − ȳj k è la matrice di covarianza della j -esima popolazione.
T è invece la matrice di covarianza della nuvola di punti che si ottiene sostituendo ad ogni
osservazione il baricentro della popolazione alla quale essa appartiene.
La decomposizione
(3.10)
0 =D+T
che abbiamo appena ottenuto si chiama formula di Huygens. Se ora u è una direzione, abbiamo
visto nel paragrafo precedente che la dispersione lungo la direzione u è data da
h0u, ui = hDu, ui + hT u, ui .
68
Capitolo 3. Analisi multivariata
La separazione delle popolazioni lungo la direzione u sarà dunque tanto più grande quanto
più è piccola la dispersione interna delle popolazioni hDu, ui e grande la dispersione esterna
hT u, ui. Tenendo conto che comunque deve essere
hDu, ui hT u, ui
+
=1
h0u, ui
h0u, ui
la direzione lungo la quale la separazione tra le popolazioni è la più grande sarà quella per cui
la quantità
hDu, ui
h0u, ui
è minima.
Mostriamo che un tale vettore u è l’autovettore relativo al più piccolo autovalore della matrice
0 −1 D.
La funzione F (u) = hDu,ui
h0u,ui è omogenea di grado 0, cioè tale che F (αu) = F (u) per ogni
α > 0. Dunque il problema di determinarne il minimo è equivalente a quello del minimo di
v → hDv, v i con il vincolo h0v, v i = 1; dopo di che basterà scegliere
u=
v
|v |
per avere un vettore di lunghezza 1.
Abbiamo già visto come si usano i moltiplicatori di Lagrange per questo tipo di problemi.
Poiché sappiamo già che i gradienti delle funzioni G(v) = h0v, v i e F (v) = hDv, v i sono
uguali rispettivamente a G0 (v) = 20v e F 0 (v) = 2Dv rispettivamente, l’equazione dei moltiplicatori di Lagrange diviene
Dv + λ0v = 0
ovvero
0 −1 Dv = −λv .
Dunque v deve essere autovettore della matrice 0 −1 D. Inoltre, poiché si ha
hDv, v i = −λh0v, v i = −λ
il vettore v per cui il minimo di hDv, v i è raggiunto tra quelli per cui h0v, v i = 1 è necessariamente l’autovettore relativo al più piccolo autovalore della matrice 0 −1 D.
Per completare la nostra analisi occorre studiare gli autovalori di 0 −1 D, che non è in generale
una matrice simmetrica, anche se sia 0 −1 che D lo sono. Il prodotto di due matrici simmetriche
non è una matrice simmetrica, a meno che le due matrici commutino.
L’analisi spettrale di 0 −1 D si può però ricondurre a quella di una matrice simmetrica. Sappiamo infatti che esiste una matrice, che indicheremo con D 1/2 , che è simmetrica e tale che
D 1/2 D 1/2 = D
nel senso del prodotto di matrici. Moltiplicando a sinistra ambo i membri nella relazione
0 −1 Dv = −λv
3.5 Analisi discriminante
69
per la matrice D 1/2 otteniamo
D 1/2 0 −1 Dv = −λD 1/2 v
ovvero
(D 1/2 0 −1 D 1/2 )D 1/2 v = λD 1/2 v .
In conclusione se v è autovettore per l’autovalore −λ della matrice 0 −1 D allora D 1/2 v è
autovettore della matrice simmetrica D 1/2 0 −1 D 1/2 rispetto allo stesso autovalore e viceversa
(veramente questo ragionamento è incompleto: perché ?). Inoltre poiché
hD 1/2 0 −1 D 1/2 v, v i = h0 −1 D 1/2 v, D 1/2 v i ≥ 0
gli autovalori sono tutti ≥ 0.
Abbiamo dunque mostrato che la matrice 0 −1 D ha tutti i suoi autovalori reali e positivi. Altre
direzioni discriminanti si ottengono considerando gli autovettori associati agli autovalori via
via più grandi di 0 −1 D . Si tratta di direzioni lungo le quali la discriminazione tra le varie
popolazioni diminuisce man mano che si considerano autovalori più grandi, ma che possono
sempre dare informazioni utili.
L’analisi discriminante quindi procede come l’ACP: si calcolano i due autovettori, w1 e w2 ,
associati ai due più piccoli autovalori di 0 −1 D, e si proiettano i dati sul piano generato da w1 e
w2 . Sarà ragionevole all’inizio centrare e ridurre le variabili, . Ora però c’è una complicazione
supplementare: a differenza di quanto accadeva per l’ACP, w1 e w2 non sono ortogonali. Come
fare allora per calcolare la proiezione ortogonale ?
Basterà cercare due vettori ortogonali che individuino lo stesso piano. Ad esempio v1 più un
altro vettore w, ortogonale a v1 e complanare a v1 e v2 . La scelta naturale è w = v2 −hv1 , v2 iv1 .
Essendo una combinazione lineare di v1 e v2 , w si trova nello stesso piano di v1 e v2 ed inoltre
hv1 , w i = hv1 , v2 i − hv1 , v2 i hv1 , v1 i = 0 .
| {z }
=1
Dunque w e v1 sono ortogonali. Il piano discriminante è quindi individuato da questi due
vettori, che sono per di più di modulo 1 se si sostituisce w con w/|w|.
La realizzazione di uno script scilab che effettui l’analisi discriminante presenta delle
difficoltà simili a quelle dell’ACP, ma è nettamente più delicata. Occorre infatti produrre una
funzione che faccia le operazioni seguenti
1) Innanzitutto bisogna centrare e ridurre le variabili, per evitare distorsioni dovute alla
scelta di unità di misura e/o al fatto che per certe variabili i valori misurati siano troppi. Per
questo si usa prima il comando center (che toglie le medie alle variabili); date però prima
un’occhiata allo help di questo comando, che ha un paio di opzioni. Poi occorre ridurre i
dati, in maniera che tutte le variabili abbiano varianza uguale a 1. Le analisi successive si
intendono tutte effettuate sui dati normalizzati.
2) Occorre poi calcolare la matrice di covarianza interna. A questo scopo occorrerà, a
meno di idee brillanti, fare un ciclo for...end calcolando le matrici di covarianza delle
singole popolazioni.
70
Capitolo 3. Analisi multivariata
3) Poi bisogna trovare gli autovettori relativi ai più piccoli autovalori della matrice 0 −1 D.
Si procederà come descritto sopra per la determinazione degli autovettori relativi ai più grandi
autovalori della matrice di covarianza (o di correlazione) per l’ACP. Può essere utile il comando
gsort(xx,”g”,”i”), che opera come sort, ma fa un ordinamento dei numeri che si
trovano in xx in ordine crescente.
4) Infine, quando si proietta sul piano determinato dagli autovettori relativi ai due più
piccoli autovalori di 0 −1 D, non bisogna dimenticare che questi non sono ortogonali. . .
5) Per quanto riguarda la realizzazione del grafico con i punti proiettati sarebbe utile potere
disegnare i punti usando per ogni popolazione un simbolo diverso, che permetta di distinguere
facilmente, per ogni punto, a quale popolazione appartenga. Ci sono due possibilità. Se si
vuole indicare ogni individuo con un numero, il comando è
--> xnumb(x,y,nums)
dove nel vettore x si trovano le ascisse dei punti, in y le ordinate e in nums i numeri che
verranno disegnati nei punti di coordinate x e y .
Prima di utilizzare questo comando, a differenza di comandi come plot, occorre però definire
la finestra grafica. Ad esempio con i comandi
-->clf();plot(xx,yy,"w")
-->xnumb(xx,yy,nums)
prima viene fatto un grafico in cui i punti appaiono con un puntino in colore bianco (e quindi
viene definita la finestra grafica senza disegnare niente) e poi vengono aggiunti i numeri dei
punti.
Si può usare anche il comando xstring:
-->xstring(x,y,"strin")
disegna nel punto di coordinate (x,y) la stringa di caratteri strin. Il comando xstring
però non è vettoriale, cioè può disegnare solo un punto alla volta. Occorrerà dunque pensare a
un ciclo for...end (o magari due) per disegnare i punti. Anche per questo comando sarà
necessario definire prima una finestra grafica vuota con plot.
E3.8 Fare un’analisi discriminante sui dati delle iris. È possibile distinguere le tre specie di iris
sulla base delle quattro misurazioni (lunghezza e larghezza) di petali e sepali ? Storicamente
si tratta della prima applicazione di questo tipo di tecniche (Fisher, R. A. (1936) The use of
multiple measurements in taxonomic problems. Annals of Eugenics, 7, Part II, 179–188).
E3.9 Fare una analisi discriminante dei dati dei teschi egizi. Si tratta di misurazioni (vedi
Figura 3.5 ) del cranio di individui appartenenti a diverse epoche dell’antico Egitto.
Disegnare i punti sul piano discriminante. Disegnare anche le coordinate dei baricentri della
popolazioni. Cosa si può dire dell’evoluzione della forma del cranio, con l’andare del tempo ?
3.6 Approfondimenti sulla gestione della grafica
71
Figura 3.5
E3.10 Fare una analisi discriminante dei dati dei cani tailandesi. Si può affermare che
qualcuna delle razze di cani selvatici (sciacallo dorato, lupo indiano, cuon) costituisca un
punto di passaggio tra il cane preistorico ed il cane moderno ?
Dalla prima analisi si vede che due di questi gruppi sono lontani si dal cane moderno che dal
cane preistorico. Eliminarle dai dati ed effettuare un’analisi discriminante considerando solo
gli ultimi tre gruppi. Cosa si può concludere ?
3.6 Approfondimenti sulla gestione della grafica
L’analisi discriminante richiede un maggiore controllo dei parametri grafici. Ad esempio,
come fare per disegnare i valori osservati usando colori diversi per le singole popolazioni ?
Come farlo usando un ciclo for...end?
A questo scopo è opportuno approfondire le possibilità del comando plot. La descrizione
che ne abbiamo fatta nel §2.9 riguarda una versione semplificata del comando. Proviamo ad
esempio
-->tt=[0:.1:1]*2*%pi;plot(tt,sin(tt),’colo’,[.7 .13 .13],
’linest’,’none’,’marker’,’.’,’markersize’,4,’clip’,’off’)
Esso produce il grafico di alcuni punti lungo il grafico della funzione seno con le seguenti
caratteristiche:
• usa il colore caratterizzato da .7, .13, .13 in formato rgb (= red, blue, green).
• il line style è posto a ‘‘none’’ (cioè nessuno): i punti non sono collegati da segmenti.
• i punti sono indicati dal simbolo ‘‘.’’ (puntolino).
• i puntolini hanno dimensione di 4 punti (il punto è una unità di misura tipografica
= 0.035146 cm)
• il parametro clip posto uguale a off impone che quando un simbolo (puntolino in
questo caso) si trova ai bordi della finestra grafica esso venga disegnato intero e non ne venga
eliminata la porzione che si trova fuori della finestra grafica.
Come si vede con questa sintassi estesa il comando plot dà un controllo molto maggiore
all’utente che può gestire con maggiore precisione lo output grafico. La sintassi consiste in
72
Capitolo 3. Analisi multivariata
una sequenza di ‘‘PropertyName’’ seguiti dai rispettivi valori. I PropertyName più utili sono
quelli precedenti, cioè
• color: determina il colore con cui il simbolo verrà disegnato. I valori possibili di
questo parametro sono i nomi dei colori predefiniti (red, blue,. . . ), tra apici o virgolette come
al solito, oppure un vettore di lunghezza 3 che dà la composizione del colore nel modo rgb; il
colore .7, .13, .13 è una specie di arancio.
Volendo disegnare i punti di p popolazioni conviene definire un vettore di colori, cioè una
matrice p × 3, in cui ogni riga definisce un colore. Se questa matrice, ad esempio, si chiama
cmap basterà usare un ciclo for...end e indicare di usare il colore cmap(i,:) per la
i-esima popolazione. scilab possiede un vettore di 32 colori di default le cui composizioni
si possono ottenere dando il comando cmap=get(sdf(),"color_map");. Dopo che
questo comando è stato dato, la variabile cmap conterrà una matrice 32 × 3 con le definizioni
dei colori che potrà essere utilizzata come indicato sopra. Con il comando help colormap
si ottengono informazioni per produrre altri vettori di colori.
Altri colormap (cioè matrici di colori) si possono ottenere con i comandi hotcolormap e
jetcolormap . Ad esempio
-->cmap2=hotcolormap(5)
produrrà un colormap di cinque colori. Si tratterà di una matrice 5 × 3. jetcolormap fa
la stessa cosa ma con una diversa scelta di colori (vedi lo help relativo).
• linestyle: lo stile del grafico. Può prendere i valori ’-’ (tratto solido), ’--’ (a
trattini), ’:’ (a puntini), ’-.’ (trattini e puntini), ’none’ (nessun tratto). Attenzione che
il default è -, quindi se non si vogliono collegare i punti con un segmento occorre specificare
’linest’,’none’.
• marker: il simbolo che si vuole usare per segnare i punti ’.’ è il punto pieno, ’o’
è invece un cerchio con solo il bordo colorato. Per la lista completa dei simboli vedi lo help
di GlobalProperty.
• markersize: la dimensione del simbolo in punti. Utile ad esempio per disegnare
con dei puntolini un po’ più piccoli di quelli di default (che sono a 6 pt).
In ogni caso ricordare che non è indispensabile scrivere il nome completo del PropertyName: si
può scrivere ’colo’ invece di ’color’ oppure linest invece di linestyle, basta
che non ci sia ambiguità. Inoltre minuscole o maiuscole non sono rilevanti.
Ci sono altri PropertyName possibili, vedi sempre lo help di GlobalProperty.
4
Esplorazioni numeriche
4.1 Equazioni differenziali
Vediamo ora come si può usare Scilab per studiare dei sistemi di equazioni differenziali.
Il comando di base è ode. Supponiamo di volere ottenere numericamente la soluzione
dell’equazione
y 0 = f (t, y)
con le condizioni y(t0) = y0. Questo si può fare con il comando
-->y=ode(t0,y0,tt,f)
In questo comando t0, y0sono le condizioni iniziali, come indicato prima, mentre tt sono i
valori della variabile nei quali si vuole calcolare la soluzione. Perché la cosa funzioni, l’utente
dovrà definire la funzione f come funzione scilab. Vediamo un esempio concreto:
y0 = y2 − t .
Per questa equazione, che non è lineare, non è possibile trovare delle soluzioni esplicite.
Occorrerà definire la funzione f . Per definire funzioni che comprendono una sola istruzione
non è necessario scriverle in un file separato. Si può usare il comando deff. Ad esempio:
-->deff("yprim=fu1(t,y)","yprim=y.ˆ2-t");
Supponiamo di cercare la soluzione nell’intervallo [0,10]. Definiremo allora
-->tt=[0:.1:10];
e poi daremo le condizioni iniziali, ad esempio
Paolo Baldi
Corso di Laboratorio di Calcolo
Tor Vergata 2013-14
74
Capitolo 4. Esplorazioni numeriche
-->t0=0;y0=0;
A questo punto i valori della soluzione si ottengono con
-->yy=ode(y0,t0,tt,fu1);
-->clf();plot(tt,yy)
Da notare che nel comando ode il primo argomento è la posizione iniziale e il secondo è il
tempo iniziale, mentre nella definizione della funzione fu1 tempo e posizione sono dati in
ordine inverso.
Quando si è in presenza di un sistema differenziale, spesso l’interesse si porta non tanto sul calcolo del valore effettivo delle soluzioni, ma sul loro comportamento asintotico. Nell’esempio
precedente il grafico ottenuto suggeriva che la soluzione ottenuta converga a −∞ per t → +∞.
Per questo occorrerà una dimostrazione formale. Intanto però ci si può chiedere se per altri
valori delle condizioni iniziali il comportamento sia lo stesso. A questo scopo scilab fornisce il comando champ, che permette di disegnare il campo di vettori associato al sistema,
che può dare un’idea. La sintassi è
-->champ(t1,y1,ct,cy)
Il risultato del comando precedente è di disegnare nella posizione (t1,y1) un vettore (sotto
forma di freccetta) di coordinate (ct,cy). Vediamo come si può disegnare il campo di vettori
del sistema differenziale precedente per t1 in [−3, 5] e y in [−3, 3]. Intanto definiamo le
coordinate dei punti in cui vogliamo disegnare il campo
-->t1=[-3:5];y1=[-2:3];
Il campo ad ognuno di questi punti sarà un vettore di coordinate 1 e f (t1, y1). Occorrerà
dunque calcolare il valore della nostra funzione fu1 in tutti i punti di ascissa –3, −2, . . . , 5
e ordinata –3, −2, . . . , 3. Dato che appare complicato calcolare la funzione su un vettore di
tempi e un vettore di posizioni, conviene usare il comando fevalche è stato introdotto a
pag.p. 32:
-->cy=feval(t1,y1,fu1);
mentre evidentemente ct sarà un campo di tutti uni:
-->ct=ones(length(t1),length(y1));
possiamo ora disegnare il campo del sistema differenziale precedente:
-->clf();champ(t1,y1,ct,cy);
4.1 Equazioni differenziali
75
È abbastanza evidente dalla forma del campo che esiste una curva tale che, se le condizioni
iniziali (t0,y0) si trovano a sinistra di essa, allora la soluzione tenderà a +∞, mentre se si
trovano a destra essa tenderà a −∞. Possiamo verificare questa intuizione disegnando, oltre
al campo alcune soluzioni con diverse condizioni iniziali. Ad esempio
-->clf();champ(t1,y1,ct,cy);
-->t0=-1.5;tt=[t0:.01:.5];yy=ode(y0,t0,tt,fu1);plot(tt,yy)
disegnerà un pezzo di traiettoria che tenderà a divergere positivamente. Possiamo sovrapporre
al grafico altre soluzioni, con altre condizioni iniziali, usando colori diversi:
-->clf();
-->t0=-1.45;tt=[t0:.01:.5];yy=ode(y0,t0,tt,fu1);plot(tt,yy)
-->t0=-1.45;tt=[t0:.01:.5];yy=ode(y0,t0,tt,fu1);plot(tt,yy,"g")
-->t0=-1.43;tt=[t0:.01:1.5];yy=ode(y0,t0,tt,fu1);plot(tt,yy,"r")
-->t0=-1.42;tt=[t0:.01:1.5];yy=ode(y0,t0,tt,fu1);plot(tt,yy,"c")
-->t0=-1.41;tt=[t0:.01:2.5];yy=ode(y0,t0,tt,fu1);plot(tt,yy,"m")
Naturalmente i grafici mettono in evidenza un fenomeno che necessita comunque un trattamento analitico.
Prima di vedere altri esempi, sottolineiamo un paio di punti utili per l’uso del comando ode:
1) Nella definizione della funzione f è sempre necessario indicare tra i valori in ingresso la
variabile t, anche quando il sistema è della forma y 0 (t) = f (y(t)), cioè omogeneo nel tempo.
2) Il comando odesi può usare anche per un sistema in dimensione più grande di 1. In
questo caso la variabile yprim restituita dalla funzione fu1 dovrà essere un vettore della
dimensione appropriata.
Vediamo ad esempio come si possono usare le potenzialità di scilab per studiare il classico
sistema preda-predatore:
y1 0 (t) = ay1 (t) − by1 (t)y2 (t)
y2 0 (t) = −dy2 (t) + cy1 (t)y2 (t)
dove a, b, c, d sono tre numeri fissati e strettamente positivi. Qui y1 , y2 modellizzano la
consistenza in un ecosistema di due specie: y1 (t) indica la consistenza della specie 1 preda,
y2 (t) quella della specie 1, predatore. La prima equazione indica che la derivata di y1 è
la risultante di due fattori diversi: ay1 (t) è l’accrescimento dovuto alla riproduzione della
specie, mentre il termine −by1 (t)y2 (t) dà conto del fatto che la specie 1 viene cacciata dalla
specie 2. Dunque i suoi effettivi subiranno una perdita tanto più grande quanto più è grande
la consistenza della specie 2. In maniera simile la seconda equazione indica che il predatore
tenderà a decrescere quanto più la sua consistenza è numerosa (più predatori ci sono e meno
76
Capitolo 4. Esplorazioni numeriche
cibo c’è a disposizione) e quanto più è ridotta la consistenza della preda, che costituisce il suo
cibo.
Per studiare questo sistema occorrerà definire la funzione f , ad esempio definendo in un file
esterno
function yprim=fvolt(t,y)
yprim(1)=a*y(1)-b*y(1)*y(2);
yprim(2)=c*y(1)*y(2)-d*y(2);
endfunction
Da notare che ora non è possibile usare il comando deff perché per definire la funzione
occorre più di una riga.
Per disegnare il campo del sistema, per sistemi bidimensionali come questo, è prevista una
funzione apposita, fchamp. vediamo come disegnare il campo di vettori del sistema nella
finestra [0, 8] × [0 : 6]: se scegliamo come parametri a = 3, b = 1, c = 1, d = 2, ad esempio,
-->a=3;b=1;c=1;d=2;
-->cx=[0:.5:8];cy=[0:.5:6];fchamp(fvolt,0,cx,cy);
Ora per ottenere la soluzione del sistema preda-predatore con dato iniziale (1, 1) basterà dare
il comando
-->y0=[1;1];t=[0:.01:5];yy=ode(y0,0,t,fvolt);
Da notare che occorre che la condizione iniziale sia un vettore colonna. Dato che siamo in
dimensione 2 non è possibile visualizzare l’andamento della traiettoria in funzione del tempo,
bisognerà accontentarsi di vedere la curva che ne è l’immagine:
-->plot(yy(1,:),yy(2,:))
E4.1 Risolvere l’equazione differenziale ordinaria
y 0 (t) = max(y(t), t)
e tracciare i grafici delle soluzioni con le condizioni iniziali t0 = −1 e
y0 = .1
y0 = −.1
y0 = −.5
y0 = −1.1
E4.2 Completare lo studio del comportamento del sistema preda-predatore aggiungendo al
grafico altre traiettorie al variare della posizione iniziale. Cosa si osserva ? Al variare del
tempo che tipo di comportamento hanno i valori delle due variabili ? Osservare che esiste
Esercizi
77
una condizione iniziale di equilibrio y∗ , cioè tale che, se y0 = y∗ , allora la costante y ≡ y∗
è soluzione. Calcolare questo valore e aggiungere al grafico ottenuto precedentemente il
disegno di questo punto.
E4.3 Qualche volta, per descrivere il sistema preda-predatore, si usa il sistema un po’ più
sofisticato
y1 0 (t) = ay1 (t)(ρ − y1 (t)) − by1 (t)y2 (t)
y2 0 (t) = −dy2 (t) + cy1 (t)y2 (t)
dove il termine ρ − y1 (t) viene aggiunto per tenere conto che, anche in assenza del predatore,
la preda non può crescere all’infinito, perché la sua crescita sarebbe comunque frenata dal fatto
che le risorse alimentari non sono illimitate. Il parametro ρ indica la dimensione massima a
cui la preda può arrivare. Effettuare per il nuovo sistema l’analisi indicata nei punti 1) e 2)
precedenti, scegliendo ρ = 8, disegnando il nuovo campo e traiettorie con diverse posizioni
iniziali. Cosa sembra essere cambiato nel comportamento del sistema ? Mostrare che anche
per questo secondo sistema esiste una posizione di equilibrio, calcolarla e riportarla sul grafico.
E4.4 In una reazione chimica vi sono quattro componenti. Si suppone che il componente 1
si trasformi nel componente 2 in misura proporzionale alla quantità di componente 1 presente.
Allo stesso modo i componenti 2 e 3 si trasformano nei componenti 3 e 4 rispettivamente con
la stessa regola. Infine il componente 4 si trasforma nel componente 1 ad con un tasso proporzionale alla quantità di componente 4 presente. Dunque si può descrivere il comportamento
del sistema, determinato dalle quantità presenti di ciascuno dei 4 componenti, y1 , y2 , y3 , y4 ,
mediante il sistema
y1 0 (t) = −α1 y1 (t) + α4 y4 (t)
y2 0 (t) = −α2 y2 (t) + α1 y1 (t)
y3 0 (t) = −α3 y3 (t) + α2 y2 (t)
y4 0 (t) = −α4 y4 (t) + α3 y3 (t)
ovvero
y 0 (t) = Ay(t)
dove

−α1
 α
A= 1
0
0
0
−α2
α2
0
0
0
−α3
α3

α4
0 

0
−α4
1) Mostrare (analiticamente) che esiste un punto di equilibrio, cioè una condizione iniziale
y0 tale che se il sistema inizia con questa condizione iniziale allora y rimane costante y ≡ y0 .
Cosa significa questo in termini dello spettro della matrice A ?
2) Risolvere il sistema, mediante il comando ode scegliendo dei valori numerici per i
parametri. Cosa suggeriscono i grafici, per quanto riguarda il comportamento asintotico del
sistema ? Il punto equilibrio sembra essere stabile ? O no ? Cosa significa l’esistenza di un
equilibrio stabile in termini dello spettro della matrice A ?
78
Capitolo 4. Esplorazioni numeriche
4.2 Fourier
Si sa dai corsi di Analisi Matematica che data una funzione f continua a tratti e di periodo T ,
la sua serie di Fourier
∞
X
an cos( 2Tπ nx) + bn sin( 2Tπ nx)
a0 +
n=1
converge, per n → ∞, puntualmente a f in tutti i suoi punti di continuità, mentre converge
alla semisomma dei limiti destro e sinistro nei punti di discontinuità. In questo paragrafo
vediamo alcuni aspetti di questo risultato e mettiamo in evidenza qualche fenomeno inatteso.
Naturalmente, ricordiamo che
Z
Z
Z
1 b
2 b
1 b
2π
a0 =
f (x) dx, an =
f (x) cos( T nx) dx, bn =
f (x) sin( 2Tπ nx) dx
T a
T a
π a
dove [a, b] è un intervallo di ampiezza b − a = T . Consideriamo la funzione
n
−1 se −π < x ≤ 0
f (x) =
1
se 0 < x ≤ π
(cioè a = −π, b = π e T = 2π). Poiché si tratta di una funzione dispari, an = 0, n = 0, 1, . . .,
mentre
4
Z
2 π
se n è dispari
bn =
sin nx dx = nπ
π 0
0
se n è pari
In altre parole
∞
4X 1
sin((2k + 1)x)
f (x) =
π
2k + 1
k=0
con l’intesa che la somma della serie vale 0 per x = 0.
E4.5 Scrivete una funzione scilab che faccia il grafico di f e che aggiunga il grafico
l’approssimazione con la serie di Fourier troncata al grado 2n + 1.
Come si vede (Figure 4.1 e 4.2), il grafico delle somme parziali di Fourier presenta un picco
al di sopra del livello 1 che non sembra ridursi per n → ∞.
Vediamo come si può giustificare analiticamente questo comportamento. Se indichiamo con
sn la somma della serie fino alla frequenza n, allora
n−1
n−1 Z
4X 1
4X x
sin((2k + 1)x) =
cos((2k + 1)t) dt =
s2n−1 (x) =
π
2k + 1
π
0
k=0
k=0
=
4
π
Z
0
n−1
xX
k=0
cos((2k + 1)t) dt
Si ha però
n−1
X
k=0
cos((2k + 1)t) =
1 sin(2nt)
2 sin t
Esercizi
79
....... ..... ..... .... .... ...
.... ...
.... .. ..
..... .. .....
...
... ... ....... ........... ....... .. ................ ....... ........
....................................................................................... .... ..... ...
.............................
.. .......... ........................
.. ... ....... .......... ............ ......... ..........
..
...... ...
....
. .. . ..
.
.. ...
.... ........... .... .... ...
.. ...
..
... ..
.. ...
.. ..
.....
....
.....
...
......
..
.....
.....
....
.....
...
....
.
..
..
.
...
...
..
...
.
..
.....
...
....
....
.....
...
....
......
....
.
.. .
....
.. ..
.....
.. .
.
.
.. .
.. ..
.. ..
.. .
.. ..
.. .....
.............. ......... ....
..
... ... .. ................... ........ .................. ....... ......
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
........... .......... ......... ......... ......... .... .. ... .
..... ......... ..............
.. ... .......... ........ .................... ........ .........
....
..... ..... ..
.. .. .. ..
.... .....
.... ...
1
0
−1
−π
π
0
Figura 4.1 . Grafico della funzione f con le approssimazioni di Fourier fino a n = 11 (puntini) e n = 31
(tratto continuo).
1.2
...
.........
......
.. ..
..
..
. ..
.. ...
..
..
.
..
... .... ...
..
..
. .
..
..
.
... .... ...
.
..
..
.
.. .. .
.
..
..
.
.. ... ..
.
..
..
.
.. .. ..
.
..
.. ... .
..
.
.
..
.. .....
.
... ......
.........
.
..
.
.. ...
.
.
.
.
.
.
....
.
.
..
.
..
..
. .
.
.
.
. ...
.
.
.
.
.
..
..
...
.... ... ..
. ... .
..
.... ...
.
.
.
.
.
.
.
.
.
.
.
..
.
.
... ..
... .. ... ... ..
.. ..
......
.
.......
.
...
..
... .
.. . ...... ......... ........... ........
... .. ..
.
..
....
.
..
.. .. .
....
..... . ...
....
.... ..
.
... ....
. ..
.
...............
.. ...
..........
.. . ..
..
...... ...
....
..
.... ..
.. .. ...
..
.. ......
.... ...... ...
... ... .... ...
.
... .............
.
. ...
..
. . . .
. ..
..
..
.. . ... ..
.. ..
.
..
.. . .. ..
...
... ...
...
... ... ........
..
... ...
..
.. .. ..
.. .
...
.
..
..
1
0
Figura 4.2 . Questo è un ingrandimento della figura precedente con le approssimazioni di Fourier fino
a 2n + 1 = 11 (puntini) e 2n + 1 = 31 (trattini) e 2n + 1 = 71 (tratto continuo). Come si vede il picco
si sposta sempre più verso lo 0 ma la sua altezza non tende a diminuire.
Come si può dimostrare per induzione. È facile ora trovare i punti di massimo della somma
parziale s2n−1 : la derivata
2 sin(2nx)
s 02n−1 (x) =
π sin x
si annulla per x = nk π, k ∈ Z. La soluzione positiva più piccola è dunque x =
corrispondenza di questo valore
2
s2n−1 ( πn ) =
π
Z
π/n
0
π
n
sin(2nt)
dt
sin t
Si ha però
2
π
Z
π/n
0
sin(2nt)
2
dt =
sin t
π
Z
0
π/n
sin(2nt)
2
dt +
t
π
Z
π/n
0
1
1
sin(2nt)
−
dt
sin t t
ed in
80
Capitolo 4. Esplorazioni numeriche
Il secondo integrale tende a 0 per n → ∞, dato che l’integrando è limitato (verificare!). Il
primo integrale invece non dipende da n, dato che
Z
0
Dunque, per n → ∞,
π/n
sin(2nt)
dt =
t
Z
2
=
π
Z
lim s2n−1 ( πn )
n→∞
π
sin s
ds
s
π
sin s
ds
s
0
0
Un calcolo numerico (vedi anche i prossimi paragrafi. . . ) dà per quest’ultima quantità il valore
1.17897 . . ., quindi all’incirca 0.18 al di sopra del livello 1, in accordo con i grafici delle figure.
Questo fenomeno (la serie converge puntualmente a f nei punti di continuità ma per ogni n ci
sono sempre dei punti x in corrispondenza dei quali lo scarto resta minorato da una costante)
si chiama il fenomeno di Gibbs.
E4.6 Calcolare i coefficienti di Fourier della funzione che si ottiene prolungando per periodicità la funzione f (x) = x, x ∈ [−π, π] (la funzione a denti di sega) e poi fare il grafico delle
somme parziali per diversi valori di n. Confrontare infine i risultati con quelli della funzione
dell’Esercizio 4.5.
E4.7 Stessa cosa per la funzione che si ottiene prolungando per periodicità la funzione
f (x) = |x |, x ∈ [−π, π].
scilab prevede delle routine che effettuano il calcolo numerico di un integrale. Ad esempio
-->deff("y=f(x)","y=1./x");intg(1,2,f)
produrrà un valore approssimato (molto bene. . . ) dell’integrale tra 0 e 1 di x1 (cioè log 2).
Vedremo nel prossimo paragrafo quali sono i metodi numerici su cui routine come intg sono
basate. Intanto però sfruttiamo questa potenzialità per approfondire la nostra esplorazione del
comportamento delle serie di Fourier. Mettiamo però prima in evidenza un punto delicato per
l’uso di intg. Questo comando effettua una serie di approssimazioni sempre più accurate
dell’integrale e si arresta quando l’errore assoluto rispetto al valore esatto dell’integrale è
stimato ≤ 10−16 e l’errore relativo è ≤ 10−8 . Quando l’integrale vale 0 questo provoca un
messaggio di errore (convergence problem ...) dato che l’errore relativo, che è
uguale a (valore approssimato-vero valore)/vero valore, risulterà sempre infinito. Per aggirare
questo inconveniente conviene ricordare che intg prevede delle opzioni:
-->intg(a,b,f,ea,er)
impone a scilab di fornire un’approssimazione con un errore assoluto pari ad ea ed un
errore relativo pari a er. Nel caso sia possibile che il valore dell’integrale sia uguale a 0
converrà scrivere
-->intg(a,b,f,10ˆ(-16),%inf)
Esercizi
81
(%inf è la specificazione dell’infinito in scilab).
E4.8 a) Usare il comando intg per calcolare numericamente i coefficienti dello sviluppo
in serie di Fourier della funzione
f (x) =
p
|x |,
x ∈ [−π, π]
e poi prolungata per periodicità.
b) Disegnare il grafico della funzione e aggiungere quello dell’approssimazione di Fourier
fino alla frequenza n = 5.
c) Per vedere meglio cosa succede vicino all’origine, disegnare il grafico della funzione
nell’intervallo [−0.3, 0.3] e aggiungere quello delle approssimazioni di Fourier per le frequenze n = 5, 25, 45.
E4.9 Consideriamo la funzione
f (x) = x(1 − x),
x ∈ [0, 1]
a) Modificare lo script scilab dell’Esercizio 4.8 che calcoli lo sviluppo di Fourier di f
(ovvero del suo prolungamento per periodicità) fino alla frequenza n e fare il grafico di f e
dello sviluppo per n = 3 e n = 7. (Attenzione: in questo esempio il periodo T è uguale a 1).
b) Per ottenere un’approssimazione di f con una serie di funzioni trigonometriche si può
anche procedere prolungando f ad una funzione dispari, cioè
fe(x) =
x(1 − x)
−x(1 − x)
se 0 ≤ x ≤ 1
se −1 ≤ x ≤ 0
1
..............
.......................................
.......
....
..........
.......
....
4
....
.
......
.......
.
.
.......
...
......
..
.
.
.
.
.
.
.
......
...
..
.
.
.
.
.
.
.
......
.
...
.
.
.
.
.
.
.
.....
.
.
...
..
.
.
.
.....
.
.
.
..
..
..
.....
.
.
.
.
..
.
.
.
.....
.
.
.
.
..
..
....
.
..
.
.
.
.
.. ....
....
.
.
...
.....
......
.
.
.
....
.
.
..
....
.
.
.
.....
..
.
.
.
.....
....
.....
.....
......
.....
......
.....
.
.
.
.......
.
.
....
......
......
.......
......
.........
..............................................
−1
0
1
Figura 4.3 Grafico di fe. A puntini la periodizzata di f .
Si può ora prolungare questa funzione ad una funzione periodica di periodo 2. Come in a),
calcolare lo sviluppo in serie di Fourier di fe. Attenzione, ora si tratta di una funzione di
periodo 2 e dispari.
E4.10 Possiamo ora tornare a considerare la funzione dell’Esercizio 4.6, per la quale si
osservava una convergenzapparticolarmente lenta della serie. Potremmo pensare di prolungare la funzione f (x) = (x) in maniera da renderla dispari, ma questo produrrebbe una
discontinuità (vedi Figura 4.4 ).
Paolo Baldi
Corso di Laboratorio di Calcolo
Tor Vergata 2013-14
82
Capitolo 4. Esplorazioni numeriche
...
....
1
...
........
...
.......
...
.......
.
.
.
.
.
...
.
.....
...
......
...
.....
...
......
.
.
.
.
..
...
..
.....
..
.....
..
....
.
..
.
.
..
....
..
...
..
..
..
..
.
.
..
..
..
..
..
..
.
..
..
..
..
..
..
.
.
..
−3
−...2.
−1
1
..
..
..
.
..
.
.
.
..
.
..
..
...
..
....
..
...
.
..
.
.
..
....
..
....
...
....
.....
...
.
.
.
.
...
...
......
...
......
...
.......
.
.
.
...
.
.
.
...
.....
... ..............
.....
−1
Figura 4.4 Grafico dei prolungamenti della funzione radice quadrata.
Per evitarlo si può allora prolungarla ulteriormente (vedi il grafico a puntini nella Figura
2.4). Si può quindi cercare uno sviluppo in serie di Fourier di questa nuova funzione. La
serie ottenuta, ristretta all’intervallo [0, 1] produrrà una serie di funzioni trigonometriche che
√
converge uniformemente alla funzione x → x.
Modificare gli script scilab realizzati precedentemente in modo da calcolare numerica√
mente gli sviluppi indicati. Fare il grafico della funzione x → x con gli sviluppi per n = 2
e n = 4. In questo caso a = −3, b = 1, T = b − a = 4.
4.3 Integrazione numerica: le somme di Riemann
Quali sono i metodi numerici che i programmi come scilab usano per calcolare gli integrali ? Il primo metodo che viene in mente sono chiaramente le somme di Riemann. Nei
corsi di Analisi Matematica si dimostra che, se una funzione f è continua, allora le somme
di Riemann convergono all’integrale. Più precisamente, se f : [a, b] → R è una funzione
continua e suddividiamo l’intervallo [a, b] in n intervallini di ampiezza n1 (b − a), allora una
somma di Riemann associata a questa suddivisione è la quantità
n
X
1
Sn (f ) = (b − a)
f (ξk )
n
k=1
dove ξi è un punto qualunque nello k-esimo intervallino Ik = [a + nk (b − a), a + k+n 1 (b − a)],
k = 0, . . . , n − 1. Qual è l’errore che si commette se si approssima l’integrale con una somma
di Riemann ?
Vediamo di stimare, per cominciare, l’errore nel primo intervallino. Per semplicità supporremo
a = 0 e indicheremo h = n1 (b − a) l’ampiezza di questi intervallini. Usando il teorema di
Lagrange, lo scarto tra l’integrale su [0, h] ed il valore hf (ξ ) è
Z h
Z h
f (x) dx − hf (ξ ) = f (x) − f (ξ ) dx =
0
0
Z h
0
=
f (cx )(x − ξ ) dx .
0
4.3 Integrazione numerica: le somme di Riemann
83
dove cx è un punto compreso tra x e ξ . Ora, se poniamo
M1 = sup |f 0 (x)| ,
a≤t≤b
si ha
Z h
Z h
0
|f 0 (cx )(x − ξ )| dx ≤
f (cx )(x − ξ ) dx ≤
0
0
Z h
Z h
Z ξ
≤ M1
|x − ξ | dx = M1
(ξ − x)| dx =
(x − ξ ) dx +
0
= M1
0
1
1
ξ 2 + (h − ξ )2 .
2
2
ξ
Si vede facilmente che, al variare di ξ ∈ [0, h], la quantità ξ 2 + (h − ξ )2 può valere al massimo
h2 , per cui abbiamo trovato che
Z
1
f (x) dx − hf (ξ ) ≤ M1 h2 .
2
h
0
Ora, ricordando che h = n1 (b − a),
Z
b
a
≤
f (x) dx − h
n Z
X
k=1
n
X
k=1
f (ξk ) ≤
1
f (x) dx − f (ξk ) ≤ M1 h2 · n =
2
Ik
=
1
M1 (b − a)2 .
2n
Quindi l’errore tende a 0 come n1 (n = numero di intervallini). Questa stima vale qualunque
sia il punto ξ scelto all’interno di ogni intervallino. Osserviamo però che se la funzione è
crescente, scegliendo come ξ l’estremo sinistro la somma di Riemann fornirà comunque una
minorazione, mentre con l’estremo destro darà una maggiorazione.
Abbiamo visto che l’errore tende a 0 come n1 . Non è un granché. Si può fare di meglio ?
In effetti se si sceglie come ξ il punto di mezzo di ogni intervallino, succede qualcosa. Ritorniamo a considerare l’intervallino [0, h]. Se ξ = h2 e supponiamo f due volte derivabile,
Z
h
f (x) dx
0
− hf ( h2 )
Z h
h
=
(f (x) − f ( 2 )) dx =
0
Z h
0 h
h
h 2
1 00
=
(f ( 2 )(x − 2 ) + 2 f (cx )(x − 2 ) ) dx 0
84
Capitolo 4. Esplorazioni numeriche
dove abbiamo fatto uno sviluppo di f attorno a h2 fino al second’ordine e cx è sempre un punto
compreso tra x e ξ . Ora
Z h
f 0 ( h2 )(x − h2 ) dx = 0
0
per cui, scrivendo M2 = supa≤t≤b |f 00 (x)|,
Z h
Z h
1 00
h h 2
f (x) dx − hf ( 2 ) = 2 f (cx )(x − 2 ) dx ≤
0
0
Z h
1
1
M 2 h3 .
(x − h2 )2 dx =
≤ M2
2
24
0
Quindi in ogni intervallino l’errore è maggiorato da
Z
b
a
f (x) dx − h
≤
n
X
k=1
1
24
M 2 h3 e l’errore globale invece
n Z
X
f (ξk ) ≤
f (x) dx − f (ξk ) ≤
k=1
Ik
1
1
M2 (b − a)3
M2 h3 · n =
2
24
24n
che è un risultato molto migliore.
Un terzo metodo: si potrebbe anche pensare di migliorare l’approssimazione approssimando
la funzione f con una funzione lineare a tratti.
............................
....... ........... ...
.........................
.
.
..
.
.
........
......
...
........ ...
.
.
..
.
..... .
....... ..
.
...
.
.... ..
.
.
.. ..
..
...
.......
.
.
..
..
..
........
...
.
.
.
.
.
.
.
..
...
...
........
.
.
...
...
........
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
..
.
.
......... .. ........
..
......
................... ........... ............
.
.
.
.
.
.
...
.
.
.
.
...... ....
.. ..... .
.
.
.
.
.
.
.
.
.
.
...... ....
.. ...
...
...
...
...... ....
........
.
..... ........
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.........
. .
... .. .
...
...
...
.........
.............
.............. ...
.
.
.
.
.
.
.
.
.
..
.
.
.
.. .
.. ..
.......................
..
..
..
.................
.
...........
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
...
.
.
.
.
.
.
....... ...........
.........
.
.....
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
........................................
....
...
...
...
...
...
..
..
...
..
..
..
..
...
...
...
...
...
...
...
...
...
...
...
...
...
...
..
..
..
..
..
..
..
x0
x1
x2
x3
x4
x5
x6
Figura 4.5 Il metodo dei trapezi.
La superficie corrispondente ad ogni intervallino [xi−1 , xi ]è un trapezio le cui basi sono alte
f (xi−1 ) e f (xi ) rispettivamente. Dunque ognuno di questi trapezi ha area
1
(b − a)(f (xi−1 ) + f (xi ))
2n
e l’approssimazione dell’integrale è
n
n−1
1
X
X
1
1
1
(b − a)
I∼
f (xi ) + f (b) .
f (xi−1 ) + f (xi ) = (b − a) f (a) +
2n
n
2
2
i=1
i=1
4.4 Polinomi d’interpolazione e il metodo di Simpson
85
(ricordare che a = x0 , b = xn ). Lasciamo in sospeso la stima dell’errore di questo metodo
4.4 Polinomi d’interpolazione e il metodo di Simpson
A pensarci bene le somme di Riemann si possono vedere come una approssimazione della
funzione integranda f mediante una funzione costante a tratti, facile da integrare. Ma ci sono
anche altre funzioni facili da integrare: i polinomi. L’idea quindi è: approssimiamo f con un
polinomio e approssimiamo l’integrale di f su ogni intervallino con l’integrale del polinomio
approssimante. Il metodo dei trapezi rientra in questo tipo di metodi, quando il polinomio
approssimante è di grado 1.
Siano f una funzione e x0 , x1 , . . . , xn numeri reali. Si chiama polinomio interpolante di f di
ordine n (associato a x0 , x1 , . . . , xn ) un polinomio P di grado n che coincida con f nei punti
x0 , x1 , . . . , xn . Due questioni
a) Esiste sempre ?
b) È unico ?
L’unicità è immediata, dato che se P e Q fossero polinomi interpolanti di f di ordine n, allora
il polinomio P − Q si annullerebbe nei punti x0 , . . . , xn . Ma un polinomio di ordine n non si
può annullare in n + 1 punti distinti senza essere identicamente nullo. Quindi necessariamente
P = Q.
Anche l’esistenza è facile da stabilire, dato che è facile costruire esplicitamente il polinomio
interpolante. Per ogni i = 0, . . . , n, il polinomio
Qi (x) =
(4.1)
Y x − xj
xi − xj
j 6=i
è di grado n e si annulla nei punti xj , j 6= i, mentre è immediato che Qi (xi ) = 1. Dunque il
polinomio
n
n Y
X
X
x − xj
Qi (x)f (xi ) =
f (xi )
P (x) =
xi − xj
i=0
i=0 j 6=i
è di grado n ed è tale che P (xi ) = f (xi ).
Sia ora f una funzione definita su un intervallo [0, h]. Il suo polinomio d’interpolazione di
ordine 2 associato ai punti 0, h2 , h è
P (x) = Q0 (x)f (0) + Q1 (x)f ( h2 ) + Q2 (x)f (h)
dove Q0 , Q1 , Q2 sono i polinomi (4.1) associati ai punti x0 = 0, x1 =
esplicitamente
2
Q0 (x) = 2 (x − h2 )(x − h)
h
4
Q1 (x) = − 2 x(x − h)
h
2
Q0 (x) = 2 x(x − h2 ) .
h
h
2,
x2 = h. Più
86
Capitolo 4. Esplorazioni numeriche
1
.
....
......... ..............
.
.
.....
......
...
....
....
.
.
.
.
.
....
.
.
.
.
.
....
.
....
..
...
.
...
...
...
.
...
.
.
.
.
.
...
.
...
...
..
.
.
...
..
..
...
.
.
.
.
.
.
.
.
.
.
...
..
...
...
.
..
... ..
. ...
... ...
.
. ..
...
.
..
...
......
.. .
.
.
. .
. ....
.
.
...
.
..
.
..
...
.
.
...
...
..
.
.
.
.
...
.
..
.
...
.
..
.
.
.
...
.
.
.
...
..
.
.
.
.
...
.
.
.
.
.
.
.
...
.
.
.
...
.
.
.
.
.
.
.
...
.
.
...
...
.
.
.
.
.
..
.
..
.
.
...
.
...
.
..
...
.
.
...
.
.
.
...
. ......
...
..
..
....
.
...
.
.
.
..
.
.
.
.
......
.
.
.
.
.
.
...
.
. .
.......
. .
. . . . . .
....... ....... ......
0
1
Figura 4.6 Grafico dei tre polinomi Q0 (puntini), Q1 e Q2 (trattini) per h = 1
1
0
...........................................................
...............
.............
..............
..........
.
.
.
.
.
..........
.
..................
...........
........
.
.
.
.
.............
...........
.
.......
.
.
.
.
.
.
..... ....
.........
........
.
.
.
.
.
.
.
..... ...
.........
.........
.
.
.
.
.
.
.
..... .
............
..........
.
.
.
......
.
.
..... ...
.............
.........
.
.
.......
.
.....
.
.
......
..........
..
.......
.
.
.
.
.
.
......
......
.
.
.......
..
.
.
.
.
.....
....
0
π
Figura 4.7 Grafico della funzione seno con il suo polinomio approssimante di ordine 2 (trattini).
L’integrale
Z
h
f (x) dx
0
verrebbe quindi approssimato con
Z
f (0)
Z
h
Q0 (x) dx
0
+ f ( h2 )
h
0
Z
Q1 (x) dx + f (h)
h
Q2 (x) dx .
0
Con pazienza calcoliamo
Z
h
0
= 2h
Z
2
Q0 (x) dx = 2
h
Z
h
0
(x − h2 )(x − h) dx =
1
(x −
0
1
2 )(x
− 1) dx = 2h
2h( 13
3
4
+
4
Q1 (x) dx = − 2
h
Z
=
−
Z
1
0
1
2)
=
(x 2 − 23 x + 21 dx =
h
6
mentre
Z
0
h
0
h
x(x − h) dx =
4.4 Polinomi d’interpolazione e il metodo di Simpson
= −4h
Z
1
0
x(x − 1) dx = −4h
=
e
Z
−4h( 13
h
0
Q2 (x) dx =
−
Z
1
2)
=
Z
1
0
2
3
x 2 − x dx =
h
h
0
87
Q0 (x) dx =
h
.
6
Dunque l’approssimazione è
Z
h
0
f (x) dx ' h
1
6
f (0) + 23 f ( h2 ) + 16 f (h) .
Questa è l’approssimazione di Simpson.
Supponiamo ora di volere approssimare l’integrale di f su un intervallo [a, b]. Suddividiamo
questo intervallo in n sottointervalli di uguale ampiezza e indichiamo con a = x0 < x1 <
. . . < xn = b le estremità di questi sottointervalli. Indichiamo poi con y1 , . . . yn i punti di
mezzo di questi sottointervalli. Dunque yi = 21 (xi−1 + xi ). L’approssimazione di Simpson
dell’integrale di f sull’intervallino [xk−1 , xk ] è
Z xk
1
f (x) dx ' (b − a) 61 f (xk−1 ) + 23 f (yk ) + 16 f (xk )
n
xk−1
mentre, sommando i contributi dei singoli intervallini,
Z
b
a
f (x) dx '
n−1
n
1
1
1X
2X
f (xk ) +
f (yk ) .
' (b − a) (f (a) + f (b)) +
n
6
3
3
k=1
k=1
Insomma è come se si mettesse un peso pari a 61 sugli estremi dell’intervallo, un peso pari
a 13 sugli altri estremi degli intervallini ed infine un peso pari a 23 sui punti di mezzo degli
intervallini.
Quanto è buona l’approssimazione di Simpson ?
Teorema. 4.1 L’errore dell’approssimazione di Simpson è maggiorato da
1
M4 (b − a)5
2880 n4
dove M4 = supx∈[a,b] |f (4) (x)|.
Dunque l’approssimazione di Simpson è molto buona se f è almeno 4 volte derivabile e con
una derivata quarta non troppo grande.
88
Capitolo 4. Esplorazioni numeriche
Esempio 4.2 Cerchiamo un’approssimazione di
Z 2
1
dx .
log 2 =
1 x
L’approssimazione di Simpson con n = 1 dà
log 2 '
1 22 1 1
+
+
= 0.6944 .
6 33 6 2
Il Teorema 4.1 dice che l’errore è minore di 24/1780 = 0.008 (qui è facile vedere che M4 = 24).
In realtà log 2 = 0.6931 e | log 2 − 0.6944| = 0.0012.
Osservazioni 4.3 a) I metodi d’integrazione con i punti a sinistra e a destra sono in generale
più lenti. Osservare però che se la funzione è monotona crescente, il metodo col punto a
sinistra fornisce una minorazione mentre il metodo del punto a destra dà una maggiorazione.
Se la funzione è monotona decrescente succede il viceversa.
b) Sia il metodo dei trapezi che quello del punto di mezzo danno un risultato esatto se la
funzione è lineare tra due punti della discretizzazione. I trapezi danno una minorazione se
la funzione è concava ed una maggiorazione se è convessa. Il punto di mezzo, al contrario
dà una maggiorazione per le funzioni concave ed una minorazione per le convesse. In entrambi i casi basta che la funzione sia concava o convessa rispettivamente tra due punti della
discretizzazione.
c) È evidente che il metodo di Simpson dà un risultato esatto se la funzione è un polinomio di grado due tra due punti della discretizzazione, dato che in questo caso il polinomio
interpolante coinciderà con la funzione stessa. Meno evidente è che esso fornisce un risultato
esatto anche se la funzione è un polinomio di grado 3 tra due punti della discretizzazione.
4.5 Un’altro approccio: simulazione
5 Sia f : [0, 1] → R una funzione integrabile (senza nessuna ipotesi di regolarità) e sia (Xn )n
una successione di v.a. indipendenti uniformi su [0, 1]. Allora la successione di v.a. (f (Xn ))n
è ancora formata da v.a. indipendenti, tutte di media E(f (X1 )); per la legge dei grandi numeri
quindi
n
(4.2)
1X
f (Xk )
n
k=1
P
→
n→∞
D’altra parte sappiamo che
E(f (X1 )) =
Z
E(f (X1 )) .
1
f (x) dx .
0
Queste osservazioni suggeriscono un metodo di calcolo numerico dell’integrale di f : basterà
disporre di un generatore aleatorio X1 , X2 , . . . di legge uniforme su [0, 1] e quindi calcolare
n
1X
f (Xk ) .
n
k=1
4.5 Un’altro approccio: simulazione
89
Questa quantità per n grande è un’approssimazione di
Z
1
f (x) dx .
0
Più in generale, se f è una funzione integrabile su un aperto limitato D ⊂ Rd , allora l’integrale
di f su D si può approssimare numericamente in modo simile: se X1 , X2 , . . . è un generatore
aleatorio uniforme su D, allora
n
1X
f (Xk )
n
k=1
P
→
n→∞
1
|D |
Z
f (x) dx .
D
Ad esempio, sappiamo che se (Xn )n una successione di v.a. indipendenti uniformi su [0, 1]
e a < b, allora Zn = a + (b − a)Xn è una successione di v.a. indipendenti e uniformi
sull’intervallo [a, b]. Dunque, se f è una funzione integrabile su [a, b], allora
n
1X
f (Zk )
n
k=1
to
n→∞
E[f (Z1 )] =
1
b−a
Z
b
f (x) dx
a
Questo algoritmo per il calcolo d’integrali o di medie è un tipico esempio di quelli che si
chiamano metodi Montecarlo. Vedremo ora di sperimentarlo su alcune situazioni concrete,
per vedere quali sono i suoi vantaggi ed i suoi difetti.
Esempio 4.4 Come fare per calcolare con il metodo Monte Carlo l’integrale
Z π
sin x dx ?
0
(che sappiamo beve essere uguale a 2) ? Prima di procedere occorre apprendere l’uso dei
generatori aleatori in scilab. Questo sarà l’oggetto del prossimo paragrafo. per ora accontentiamoci di sapere che il comando
-->xx=rand(10000,1,"u")
produce un vettore xx di numeri aleatori e uniformi su [0, 1] dunque con i comandi
-->yy=%pi*xx;app=%pi*mean(sin(yy))
vengono ottenuti prima i numeri yy che sono uniformi su [0, π] e poi il valore app che è
appunto l’approssimazione Monte Carlo dell’integrale. Provate ora a
• Fare questa operazione e controllare il risultato.
• Ripetere questa operazione 200 volte mettendo i valori ottenuti in un vettore e fare poi
l’istogramma dei risultati. Quanto vale la varianza dei numeri ottenuti ?
• Ripetere l’operazione, ma stavolta facendo la media su 40 000 numeri aleatori ogni volta.
Come si è comportata la varianza ?
90
Capitolo 4. Esplorazioni numeriche
Come si può valutare la velocità di convergenza ? Come si può paragonare questo metodo
con quelli numerici dei paragrafi precedenti. Vedremo che I metodi Monte Carlo sono molto
lenti, ma hanno anche dei vantaggi di altro tipo.
Lo strumento di base per valutare la velocità di convergenza è il Teorema Limite Centrale.
Infatti, se indichiamo Yi = (b − a)f (Xi ) e con Y n = n1 (Y1 + . . . + Yn ) l’approssimazione
dell’integrale, per il Teorema Limite Centrale
√
(4.3)
Y1 + . . . + Yn − nµ
∼ N (0, σ 2 )
√
n
n (Y n − µ) =
Rb
dove abbiamo indicato con µ = E(Y1 ) = a f (x) dx l’integrale da approssimare e con σ 2 la
varianza delle v.a. Yi . Quest’ultima si può calcolare facilmente, almeno in teoria, dato che
E[Y12 ]
2
= E[(b − a) f (a + (b − a)Xi )] = (b − a)
per cui
2
σ = (b − a)
Z
b
2
a
f (x) dx −
Z
Z
f (x)2 dx
a
b
f (x) dx
a
b
2
.
Per ottenere σ 2 occorre quindi calcolare degli integrali, tra cui proprio quello che speravamo
di ottenere con il metodo Monte Carlo. In realtà vedremo che si può fare a meno del valore
esatto di σ 2 , di cui basta avere una maggiorazione. √
La (4.3) permette di scrivere che, per n grande, la v.a. σn (Y n − µ) segue approssimativamente
una legge N(0, 1). Dunque se indichiamo con Z una v.a. N (0, 1), per δ > 0 e n grande si ha
δσ
P |Y n − µ| ≥ √
' P(|Z | ≥ δ) .
n
Ma
P(|Z | ≥ δ) = P(Z ≤ −δ) + P(Z ≥ δ) = 8(−δ) + 1 − 8(δ) =
= 2(1 − 8(δ)) .
In conclusione
P |Y n − µ| ≥
δσ
√
n
' 2(1 − 8(δ)) .
Rb
Se vogliamo che Y n approssimi µ = a f (x) dx con un errore che è ≤ ε con probabilità α,
possiamo procedere nel modo seguente. Prima scegliamo δ in maniera che
2(1 − 8(δ)) = α
ovvero δ deve essere tale che 8(δ) = 1 − α2 . Il che è lo stesso che richiedere δ = φ1−α/2 ,
quantile di ordine 1 − α2 della legge N(0, 1). Dopo di che n dovrà essere scelto in modo che
δσ
√
≤ ε.
n
4.5 Un’altro approccio: simulazione
91
Esempio 4.5 (continuazione dell’Esempio 4.4) Quanto deve essere grande n perché Y n approssimi l’integrale con un errore che è ≤ 10−3 con una probabilità del 99% ?
Qui α = 0.99 e quindi 1 − α2 = 0.995. Dalle tavole si ricava φ.995 = 2.576. n dovrà dunque
essere tale che
2.576σ
≤ 10−3
√
n
ovvero
n ≥ 106 · 2.5762 · σ 2 .
Resta da determinare il valore di σ 2 . Come indicato prima, in realtà basta una maggiorazione,
che in questo caso potrebbe essere
Z π
2
f (x)2 dx ≥ π 2
σ ≥π
0
si ottiene dunque che deve essere
n ≥ 106 · 2.5762 · π 2 ≥ 65 492 484
che è un valore molto grande, se paragonato con i metodi numerici dei paragrafi precedenti.
2
Anche il vero valore di σ 2 , che qui è π2 − 4 = 0.935, si sarebbe ottenuto n ≥ 6 203 138, che
è sempre un numero molto grande.
C’è un altro modo di stimare σ 2 , ancora a partire dalla Legge dei Grandi Numeri. In effetti
sappiamo che
n
1X
(Yi − Y n )2 → σ 2 .
n→∞
n
i=1
È quindi possibile, calcolando la varianza empirica dei risultati della simulazione ricavare
una stima di σ 2 , che può permettere di ridurre l’effetto della maggiorazione, come si vede
nell’Esempio 4.5.
In realtà occorre molta precauzione quando si sostituisce il valore stimato della varianza a
quello vero come in questo caso. Qui però il valore di n è in genere talmente elevato da
giustificare questa operazione.
Osserviamo però che questo metodo di stima della varianza (a partire dai risultati della simulazione) non permette di stabilire a priori quanto debba essere grande n, dato che il valore
approssimato di σ 2 sarà noto solo alla fine. Come si vede dall’Esempio 4.5 il numero di simulazioni richiesto per ottenere una approssimazione ragionevole è comunque molto elevato. I
metodi Monte Carlo sono quindi inferiori come prestazioni a quelli dei paragrafi precedenti.
Hanno però due vantaggi
• Convergono sempre anche se la funzione da integrare non è regolare (mentre le stime che
avevamo ottenuto per i metodi del paragrafo precedente richiedevano comunque l’esistenza
di un certo numero di derivate).
• Funzionano anche per gli integrali in dimensione più grande di 1 (la stima della velocità
di convergenza è esattamente la stessa), laddove gli altri metodi numerici diventano molto più
complicati.
92
Capitolo 4. Esplorazioni numeriche
4.6 Esercizi sull’integrazione numerica
4.11 Sia
2
(4.4)
f (x) = ex .
Vogliamo calcolare
Z
1
f (x) dx .
0
a) Determinare un’approssimazione di I con i metodi delle somme di Riemann con punto
a destra, a sinistra, di mezzo e trapezi, per n = 5.
b) Calcolare per n = 10, 20, 50, 100 le stesse approssimazioni di a).
b1) produrre e stampare una matrice avente come prima colonna il valore di n, come seconda
l’approssimazione ottenuta, come terza colonna la maggiorazione teorica dell’errore (tranne
che per i trapezi) e come quarta colonna l’errore numerico (=valore approssimato-valore
dell’integrale, ottenuto con il comando intg di scilab)
b2) Disegnare un grafico con n in ascisse e le approssimazioni ottenute in ordinate. Aggiungere al grafico la retta orizzontale di ordinata uguale al e le stime degli errori dei due
metodi. (Per il calcolo delle quantità M1 = sup0≤t≤1 |f 0 (t)| e M2 = sup0≤t≤1 |f 00 (t)| si potrà
ammettere che la funzione f ha le derivate di tutti gli ordini che sono delle funzioni crescenti
c) Quale evidenza si può ricavare sull’errore con il metodo dei trapezi ? (confrontando con
i metodi con i punti di mezzo e quello con i punti agli estremi.
Vogliamo ottenere numericamente un’approssimazione di I con un errore in modulo ≤ 10−4 .
Che valore di n bisogna scegliere se si usano i metodi
1. punto di sinistra
2. punto di destra
3. punto di mezzo.
d) Scrivere una funzione scilab che, in funzione di n, effettua le operazioni precedenti.
E4.12 Sia f la funzione
f (x) =
1
x
di cui vogliamo calcolare l’integrale da 1 a 2.
Determinare quanto grande deve essere n per ottenere un’approssimazione dell’integrale con
un errore ≤ 10−4 con i metodi
a) delle somme di Riemann con punto a sinistra
b) delle somme di Riemann con punto a destra
c) delle somme di Riemann con punto di mezzo
d) dei trapezi
e) di Simpson. Con quest’ultimo metodo, qual è l’errore che si commette con n = 1 e con
n = 2?
E4.13 Ripetere le operazioni precedenti per le funzioni
a)
Z
π
I=
sin x dx .
0
Esercizi
b)
I=
Z
π
e−x
2 /2
93
sin(12 x) dx
0
(per questa funzione si potranno ammettere le approssimazioni M1 = 1, M2 ' 134.)
c)
Z
π
I=
√
x sin x dx .
0
E4.14 Per le funzioni degli Esercizi 4.11 e 4.13 calcolare le approssimazioni con il metodo
di Simpson e confrontare per n = 5 e n = 10 e confrontare con i risultati degli altri metodi.
E4.15 Trovare una stima del valore dell’integrale
Z π
sin t
dt
t
0
con un errore inferiore a 10−5 (con un metodo a vostra scelta. . . ).
E4.16 Vogliamo calcolare numericamente l’integrale
I=
Z
π2
√
sin x dx .
0
a) In quanti sottointervalli occorrerebbe suddividere l’intervallo [0, π 2 ] perché si possa essere
sicuri che l’errore commesso sia ≤ 10−2 con il metodo del punto di sinistra ? Et del punto di
mezzo ? E dei trapezi ? E di Simpson ?
b) Decidiamo piuttosto di calcolare l’integrale per simulazione:
N
X
1
I ' π2
f (Xi ) := IN
N
i=1
dove le v.a. Xi sono uniformi su [0, π 2 ].
b1) A priori, come si deve scegliere N perché l’errore dello stimatore IN sia ≤ 10−2 con
probabilità 99% ?
b2) Calcolare IN per N = 25000 et determinare qual è l’errore, sempre ad un livello 99%,
prima con la maggiorazione delle varianza e poi stimando la varianza a partire dai dati. In
questo caso, confrontare il risultato con quello dei vicini.
c) Improvvisamente una illuminazione! Con un cambio di variabile si ha
I=
Z
0
π2
√
sin x dx = 2
Z
π
y sin y dy .
0
Se si è disposti ad una maggiorazione grossolana della derivata quarta della funzione y →
y sin y, in quanti sottointervalli bisogna suddividere [0, π] perché l’errore sia ≤ 10−2 con il
metodo di Simpson ?
94
Capitolo 4. Esplorazioni numeriche
d) Rispondere alle domande di b) per il calcolo dell’integrale
J=
Z
1/π 2
0
sin √1x dx .
E4.17 Calcolare con il metodo Montecarlo l’integrale
Z
e−(x
2 +y 2 )/2
dx dy
A
dove A è
a) il quadrato [−1, 1] × [−1, 1];
b) il cerchio di raggio 1 e di centro l’origine. In questo secondo caso confrontare i risultati
ottenuti con il valore esatto.
4.7 Probabilità e simulazione in scilab
scilab ha varie funzioni per gli aspetti numerici della Probabilità e della Statistica e le
simulazioni.
Prima di tutto ci sono i calcoli relativi alle funzioni di ripartizione. Ad esempio per le leggi
gaussiane il comando cdfnor produce la funzione di ripartizione ed i quantili delle leggi
gaussiane. L’uso di questi comandi non è proprio amichevole. Vediamo un po’. Se viene dato
il comando
-->[P,Q]=cdfnor("PQ",x,mu,sigma)
P sarà il valore della funzione di ripartizione di una legge gaussiana di media mu e deviazione standard sigma calcolato in x . Il secondo valore restituito dal programma, Q è
semplicemente uguale a 1-P . Attenzione agli aspetti seguenti:
• sigma è la deviazione standard e non la varianza.
• x può essere un vettore e in questo caso anche P e Q saranno dei vettori. Per approfittare
di questa possibilità però anche mu e sigma devono essere dei vettori, anche se le medie e
le varianze sono tutte uguali. Ad esempio per avere i valori della funzione di ripartizione di
una N(0, 1) nei valori 1, 1.5, 2 occorrerà scrivere
-->x=[1,1.5,2];
-->[P,Q]=cdfnor("PQ",x,zeros(x),ones(x));
Cambiando la sintassi il comando cdfnor produce i quantili: scrivendo
-->x=[1,1.5,2];
-->x=cdfnor("X",0,1,P,Q);
4.7 Probabilità e simulazione in scilab
95
il valore ottenuto x sarà il quantile corrispondente alla probabilità P (qui come prima Q deve
essere uguale a 1-P ). Come prima il comando è vettoriale, nel senso che P può essere un
vettore. In questo caso anche tutti gli altri argomenti devono essere dei vettori aventi la stessa
dimensione.
Per distribuzioni diverse dalla normale esistono i comandi appropriati:
cdfbet (leggi beta)
cdfbin (binomiali)
cdfchi (chiquadrato)
cdfchn (chiquadrato decentrato)
cdfgam (gamma)
cdff (F )
cdffnc (F decentrata)
cdfnbn (binomiale negativa)
cdfpoi (Poisson)
cdft (t di student)
La loro sintassi è simile a quella di cdfnor, sia per il calcolo delle funzioni di ripartizione
che per quello dei quantili.
Per la simulazione esistono due generatori aleatori in scilab
Esempio 4.6 (Il grafico dei quantili) Siano X1 , . . . , Xn delle v.a. indipendenti, aventi tutte la
stessa legge (continua o discreta, poco importa). Indichiamo con F la loro f.r. Se poniamo
At =] − ∞, t], allora si vede subito che
E(1At (X1 )) = P(X ≤ t) = F (t) .
Quindi per la (4.2) applicata alla funzione f = 1At si ha
n
1X
1At (Xk )
n
(4.5)
k=1
P
→
n→∞
E(1At (X1 )) = F (t) .
Indichiamo con F̄n (t) il termine a sinistra nella (4.5), cioè
n
F̄n (t) =
1X
1
1At (Xk ) = × numero di indici k tali che Xk ≤ t .
n
n
k=1
La funzione F̄n (t) è una funzione di t che si chiama funzione di ripartizione empirica . Un
altro modo, per certi versi più semplice, di vedere la f.r. empirica è il seguente. Indichiamo
con X(1) , . . . , X(n) i numeri X1 , . . . , Xn riordinati in senso crescente: in particolare X(1) è il
valore più piccolo e X(1) ≤ X(2) ≤ . . . ≤ X(n) . Allora è chiaro che si ha anche

0 se t < X(1)



k
F̄n (t) =
se X(k) ≤ t < X(k+1) , k = 1, . . . , n − 1

n


1 se X(n) ≤ t .
96
Capitolo 4. Esplorazioni numeriche
Infatti se X(k) ≤ t < X(k+1) , ciò vuol dire che vi sono esattamente k indici i tali che Xi ≤ t e
dunque
n
1X
k
1At (Xk ) = ·
n
n
k=1
Osserviamo comunque che, per ogni valore di t, F̄n (t) è una quantità aleatoria, dato che
dipende dai valori X1 , . . . , Xn . Dunque la (4.5) non fa che affermare che, per ogni t fissato,
la f.r. empirica converge in probabilità alla f.r. F .
•
1
.•. .
. . .
... .
........ . . . .
•
...
•
..
..
...
...
..
.
.
..
..
x(1) x(2) x(3)
...
..
•. . .
..
x (4 )
..
.
•. . . .
..
...
x(5)
..
.
...
. . . . ..
. ...
. . .
. . .•
x(6)
......
x(7)
Figura 4.8 Esempio di funzione di ripartizione empirica per un campione di rango 7 di una legge
N(0, 1), a confronto con la funzione di ripartizione teorica (a puntini).
Queste osservazioni hanno delle conseguenze pratiche interessanti. Talvolta in presenza di dati
sperimentali X1 , . . . , Xn è interessati a stabilire se essi seguano una distribuzione assegnata,
N(0, 1) ad esempio. Se n è abbastanza grande, per la Legge dei Grandi Numeri, la differenza
tra la f.r. empirica F̄n e quella teorica F è piccola. Poiché sappiamo che F̄n assume il valore ni
nel punto X(i) , ciò vuol dire che i numeri ni e 8(X(i) ) devono essere molto vicini. Applicando
la funzione 8−1 , che è continua, ai due numeri ni e 8(X(i) ), otteniamo che anche i due valori
8−1 ( ni )
e
X(i)
devono trovarsi vicini tra loro. Il punto 8−1 ( ni ) è il numero in cui la f.r. 8 prende il valore ni
e dunque non è altro che il quantile φi/n . Ciò significa che se si disegnano sul piano i punti di
coordinate X(i) e φi/n , essi si devono disporre lungo la bisettrice del primo e terzo quadrante.
Questa osservazione fornisce un metodo per valutare ‘‘ad occhio’’ (è il caso di dirlo) se le
osservazioni seguano o no una legge N(0, 1). Esso naturalmente può essere applicato anche
ad altre distribuzioni continue (esponenziali, χ 2 ,. . . ), semplicemente sostituendo ai quantili
φi/n quelli della f.r. appropriata.
L’interesse di questo metodo grafico è però ancora limitato perché esso permette di vedere se
le osservazioni seguano una prefissata distribuzione, mentre spesso si è interessati piuttosto a
vedere se esse seguono una distribuzione di una determinata famiglia, ad esempio se esse sono
normali N(µ, σ 2 ) per qualche valore ignoto di µ e σ 2 . Gli argomenti precedenti possono però
essere perfezionati per ricavare un metodo grafico per trattare questo problema più complesso
(anche se ci limiteremo, qui, al caso di leggi normali). Basta per questo ricordare la relazione
tra i quantili di una legge N(µ, σ 2 ) e quelli di una N (0, 1), dati dalla (‘tre.188’): il quantile
4.7 Probabilità e simulazione in scilab
97
di ordine ni di una N(µ, σ 2 ) è uguale a σ φi/n + µ Riprendendo il ragionamento precedente,
se le osservazioni seguono una distribuzione N (µ, σ 2 ), allora i numeri
σ φi/n + µ
e
X(i)
devono essere vicini tra loro; in altre parole i punti di coordinate X(i) e φi/n devono allinearsi
lungo la retta di equazione x = σy + µ. Basta quindi disegnare questi n punti sul piano e poi
vedere se essi si dispongono lungo una retta o no (ora non più necessariamente la bisettrice
del primo e terzo quadrante).
.. . . .
.
.
.
.
.
.
.
.....
..............
.
.
.
.
.
.
.
.
.
.
.
.
..........
............
.
.
.
.
.
.
.
.
.
.
.
. . ....
. . .
.
Figura 4.9 Grafico dei quantili per un campione ottenuto per simulazione di una legge normale.
Il grafico dei punti (X(i) , 8−1 ( ni )) si chiama, nel gergo della statistica il grafico quantili contro
quantili, poiché si tratta di confrontare i quantili della distribuzione empirica F̄n contro quelli
della N(0, 1). La sua realizzazione manuale può risultare laboriosa, ma di solito tutti i software
statistici hanno prevedono questa operazione.
.
.
..
.
.
.
.
.
.
.
..
....
.
.
.
.
.
.
.
.
.
.
....
.........
.
.
.
.
.
.
......
........
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. . . ..
.
Figura 4.10 Grafico dei quantili per un campione ottenuto per simulazione di una legge χ 2 (4).
L’andamento si discosta da una retta.
Vediamo come si può realizzare il grafico dei quantili. Cominciamo col procurarci dei dati sui
quali effettueremo l’analisi. Generiamo 100 numeri aleatori indipendenti con distribuzione
N(0, 1).
-->xx=rand(1,100,’n’);
Dobbiamo poi procurarci i valori dei quantili corrispondenti alle probabilità
tanto mettiamo questi numeri in un vettore
-->p=(1:100)/100;
Il comando per il calcolo dei quantili è
Paolo Baldi
Corso di Laboratorio di Calcolo
Tor Vergata 2013-14
2
1
100 , 100 , . . .
In-
98
Capitolo 4. Esplorazioni numeriche
-->cdfnor("X",med,devst,p,1-p)
dove med e devst sono rispettivamente la media e la deviazione standard della legge
gaussiana, nel nostro caso 0 e 1, naturalmente. Occorre però che med e devst siano
vettori della stessa dimensione di p. Il comando dunque è
-->zz=cdfnor("X",zeros(p),ones(p),p,1-p);
Il programma dà un messaggio d’errore perché tra i valori dei quantili da calcolare c’è anche
quello per p = 1, cioè +∞. Conviene allora correggere i valori di p di un po’:
-->p=(1:100)/100-1/200;
Si vede subito che, per la legge dei grandi numeri, il plot dei quantili si comporta allo stesso
modo se invece delle probabilità nk si considerano le nk + 21n .
-->zz=cdfnor("X",zeros(p),ones(p),p,1-p);
Occorre poi riordinare i numeri aleatori in senso crescente e farne il grafico mettendoli in
ascissa, con i quantili in ordinata
-->xx=gsort(xx,"g","i");
-->clf();plot(xx,zz,".");
Per completare il grafico e mettere in evidenza se i punti sono allineati, si può aggiungere la
retta di regressione di zz rispetto a xx. Si tratta della retta di equazione y = ax + b, dove a
è uguale al quoziente tra la covarianza di xx e zz divisa per la varianza di xx, mentre b è
uguale alla media di zz meno a moltiplicato per la media di xx. Cioé
-->mm=mvvacov([xx’ zz’])
-->a=mm(1,2)/mm(1,1);b=mean(zz)-a*mean(xx);
-->x1=[min(xx) max(xx)];y1=a*x1+b;
-->plot(x1,y1)
E4.18 scrivere una funzione scilab che, dato un set di dati, effettui il plot dei quantili per
confrontare con la distribuzione gaussiana.
5
Simulazione, processi e EDP
5.1 Simulazione
Il punto di partenza dei metodi di simulazione è la Legge dei Grandi Numeri: se (Xn )n è una
successione di v.a. i.i.d. aventi speranza matematica finita, allora
Xn :=
1
(X1 + . . . + Xn )
n
q.c.
→
n→∞
E(X1 ) .
Una prima applicazione è data dall’integrazione numerica: se f : [0, 1] → R è una funzione
integrabile e (Xn )n una successione di v.a. i.i.d. uniformi su [0, 1], allora anche le v.a. f (Xn )
sono tra loro indipendenti e identicamente distribuite. Dunque per la Legge dei Grandi Numeri
Z 1
1
q.c.
f (x) dx .
(f (X1 ) + . . . + f (Xn )) → E(f (X1 )) =
n→∞
n
0
Dunque volendo calcolare l’integrale di f si potrà semplicemente istruire un computer a
produrre n numeri aleatori i.i.d. uniformi su [0, 1] ed a calcolare la media aritmetica dei
valori f (Xi ) ottenuti. Si tratta di un metodo molto semplice da applicare. Negli esempi
seguenti vediamo di mettere in evidenza pregi e inconvenienti. Si ricorda che il comando per
generare numeri aleatori indipendenti uniformi su [0, 1] in scilab è rand(n,m,"u"),
che produce una matrice n × m di numeri aleatori con queste proprietà.
Esempio 5.1 Scegliamo f (x) = x 2 . Sappiamo quindi che l’integrale di f su [0, 1] vale 13 .
a) Dare un’approssimazione dell’integrale di f su [0, 1] usando la legge dei grandi numeri
con n = 1000, usando scilab.
b) Dare un’approssimazione dell’integrale di f su [0, 1] usando la legge dei grandi numeri
con n = 100000, usando scilab.
c) Dare un’approssimazione dello stesso integrale approssimandolo con una somma di
Riemann, suddividendo l’intervallo [0, 1] in 10 sotto-intervalli. Quale dei due metodi vi
sembra meglio ?
Paolo Baldi
Corso di Laboratorio di Calcolo
Tor Vergata 2013-14
100
Capitolo 5. Simulazione, processi e EDP
d) Scrivere un programmino che effettua per 100 volte il calcolo approssimato come in a)
e poi fare l’istogramma dei risultati ottenuti.
e) Ripetere le simulazioni come in a) e b) e calcolare l’intervallo di fiducia della stima
dell’integrale al livello 95%. Ricordiamo che si tratta dell’intervallo
i
h
s
s
Z n − √ t0.975 (n − 1), Z n + √ t0.975 (n − 1)
n
n
dove indichiamo con Zi = f (Xi ) i valori simulati, con Z n la loro media e con
2
s =
1
n−1
n
X
(Zi − Z n )2
i=1
la varianza empirica dei valori Zi = f (Xi ). Inoltre t0.975 (n − 1) è il quantile di ordine 0.975
della legge t di Student con n − 1 gradi di liberta‘. Per valori di n così grandi i quantili della
t di Student coincidono con quelli della N(0, 1). Il comando scilab per ottenere questo
quantile è cdfnor("X",0,1,0.975,1-0.975).
Naturalmente il metodo di simulazione si applica anche al calcolo d’integrali su domini più
generali che [0, 1]. Ad esempio siano D ⊂ Rd un dominio di misura finita e (Xn )n una
successione di v.a. i.i.d. uniformi su D. Ciò vuol dire che Xi ha densità
1
g(x) = mis(D) se x ∈ D
0
altrimenti .
Dunque, se f : D → R è una funzione integrabile, allora
1
(f (X1 ) + . . . + f (Xn ))
n
q.c.
→
n→∞
1
E(f (X1 )) =
mis(D)
Z
f (x) dx .
D
Esempio 5.2 Scegliamo f (x) = sin x e D = [0, π]. Sappiamo quindi che l’integrale di f su
D vale 2.
a) Dare un’approssimazione dell’integrale di f su [0, π] usando la legge dei grandi numeri
con n = 1000, usando scilab.
c) Dare un’approssimazione dello stesso integrale approssimandolo con una somma di
Riemann, suddividendo l’intervallo [0, 1] in 10 sotto-intervalli. Quale dei due metodi vi
sembra meglio ?
1
2
2
Esempio 5.3 Poniamo f (x) = e− 2 (x +y ) .
a) Dare un’approssimazione dell’integrale di f sul quadrato D = {(x, y); |x | ≤ 1, |y | ≤ 1}
usando la legge dei grandi numeri con n = 10000 e n = 1000000, sempre usando scilab.
Confrontare con il valore esatto che si può ricavare dalle tavole della legge N (0, 1) (che si
ricavano con il comando cdfnor)
b) Stessa cosa con D = {(x, y); x 2 + y 2 ≤ 1} e confrontare con il valore esatto calcolando
l’integrale in coordinate polari.
5.2 La simulazione del moto browniano
1
101
2
c) Dare un’approssimazione dell’integrale di f (x) = e− 2 |x| su D = {x ∈ R4 ; |x | ≤ 1}
usando la legge dei grandi numeri con n = 1000, n = 10000, n = 100000 , n = 1000000,
sempre usando scilab e determinare i relativi intervalli di fiducia. Confrontare ancora con
il valore esatto (sempre riconducendosi alla funzione di ripartizione della legge N(0, 1).
Gli esempi precedenti mettono in evidenza i due aspetti fondamentali dei metodi di simulazione:
a) richiedono valori di n molto elevati per dare risultati soddisfacenti;
b) sono molto semplici da implementare e rimangono molto semplici anche quando la
dimensione cresce e altri metodi numerici come le somme di Riemann non sono più disponibili
oppure diventano molto complicati.
5.2 La simulazione del moto browniano
Un moto browniano è un processo, cioè una famiglia di v.a. (Bt )t , t > 0, con le proprietà
seguenti.
• Per ogni ω l’applicazione t → Bt (ω) è continua.
• Gli incrementi sono indipendenti, cioè per ogni s1 < t1 < s2 < t2 < . . . sk < tk le v.a.
Bt1 − Bs1 , Bt2 − Bs2 , . . . , Btk − Bsk sono indipendenti.
• Se s ≤ t, Bt − Bs ha legge N(0, t − s).
Un moto browniano m-dimensionale è un processo (Bt )t , t > 0 a valori Rm dove Bt =
(B1 (t), . . . Bm (t)) e i processi (Bi (t))t , t > 0 sono moti browniani lineari (cioè unidimensionali) indipendenti.
Prima di procedere osserviamo che il MB gode di alcune proprietà interessanti:
• Se (Bt )t è un MB. allora anche (−Bt )t è un MB. Infatti le tre proprietà indicate sopra
rimangono vere per (−Bt )t (ricordare che se X è una v.a. gaussiana centrata, allora X e −X
hanno la stessa legge).
• Più in generale, se (Bt )t è un MB m-dimensionale e O è una matrice ortogonale m ×
m, allora (OBt )t è ancora un MB m-dimensionale. Anche qui si tratta di una proprietà
d’invarianza delle leggi gaussiane.
Tra breve vedremo dei problemi in cui occorrerà simulare delle traiettorie del moto browniano. Con scilab questa simulazione è abbastanza semplice, dato che basta simulare delle
v.a. N(0, 1), rinormalizzarle per ottenere gli incrementi e poi addizionarli (con il comando
cumsum) per ottenere le posizioni successive della traiettoria.
Ad esempio, per simulare una traiettoria bidimensionale di un moto browniano per t ∈ [0, 1]
e per tracciarne il grafico si daranno i seguenti comandi
ns=100;
// 1/ns e‘ l’ampiezza della discretizzazione della traiettoria
xw=rand(ns,2,"n")/sqrt(ns);
// xw e‘ una matrice con ns righe e 2 colonne contenente
// gli incrementi del processo
102
Capitolo 5. Simulazione, processi e EDP
xw=cumsum(xw,"r")
// cumsum( ,"r") effettua le somme cumulative lungo le righe.
// xw ora contiene le posizioni della traiettoria simulata
// la prima colonna quelle della prima coordinata
// la seconda quelle della seconda
xw=[[0,0];xw]
// ora aggiungiamo l’origine che e‘ il punto iniziale
plot(xw(:,1),xw(:,2));a=gca();a.isoview="on";
// ecco il grafico
Quando però occorre simulare numerose traiettorie per risolvere i problemi di EDP che incontreremo non è opportuno usare scilab, dato che si tratta di un linguaggio interpretato,
quindi lento nelle simulazioni ‘‘vere’’ (quando occorre simulare tantissime traiettorie). Per
questo è opportuno imparare a simulare delle traiettorie del moto browniano in C. La programmazione nei due linguaggi si effettua in modi molto diversi, dato che scilab ha la capacità
di manipolare direttamente dei vettori, mentre la simulazione in C va fatta passo passo.
Per realizzare in C una traiettoria del moto Browniano occorre rivedere per prima cosa come
si chiama un programma in questo linguaggio da scilab come viene spiegato nel §2.11.
Un’altra precauzione da prendere quando si fanno delle simulazioni in un linguaggio come
C è di procurarsi un generatore aleatorio valido. Quello già presente nel linguaggio non è
buono: ha un ciclo di circa 2.1 · 109 : dopo circa due miliardi di numeri aleatori ricomincia
da capo a produrre gli stessi numeri, che quindi aleatori non sono più. Il listato che segue
presenta uno schema di programma pronto per simulare delle v.a. gaussiane.
Utilizza una subroutine knuth (che non compare nel listato) che produce numeri aleatori con
distribuzione uniforme su [0, 1]. Inoltre una subroutine BM che, a partire dalle v.a. uniformi
produce numeri aleatori con distribuzione gaussiana
se X1 , X2
p
pcon l’algoritmo di Box-Muller:
sono v.a. uniformi su [0, 1] e indipendenti, allora −2 log X1 cos(2π ) e −2 log X1 sin(2π)
sono entrambe N(0, 1) e indipendenti. Più precisamente produce due vettori, c1, c2, contenenti delle v.a. N(0, 1) indipendenti.
#define STRICT
#include <windows.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
#define pig 4*atan(1)
double knuth(void) {
/*...programma di generazione di v.a. uniformi su [0,1] */
}
void BM(unsigned int *nn,double c1[], double c2[])
{
unsigned int jj;
5.3 Moto browniano e EDP
103
double z1,z2;
for(jj=0;jj<*nn;++jj)
{
z1=knuth();
z2=knuth();
c1[jj]=sqrt(-2*log(z1))*cos(2*pig*z2);
c2[jj]=sqrt(-2*log(z1))*sin(2*pig*z2);
}
}
Esercizio 5.4 Compilare il programma precedente, linkarlo con scilab. Effettuare l’istogramma dei valori ottenuti per ciascuno dei due vettori e confrontarlo con la densità N (0, 1).
Disegnare sul piano i punti che hanno le ascisse in c1 e le ordinate in c2.
Esercizio 5.5 Modificare il programma precedente per produrre una traiettoria di un moto
browniano bidimensionale e disegnarla con scilab. Basterà modificare l’ultima parte del
programma in
double gg(void)
{
double z1,z2;
z1=knuth();
z2=knuth();
return sqrt(-2*log(z1))*cos(2*pig*z2);
}
void BM(unsigned int *nn,double c1[],double c2[])
{
unsigned int jj;
c1[0]=0.;
c2[0]=0.;
for(jj=1;jj<*nn;++jj)
{
c1[jj]=c1[jj-1]+gg()/sqrt(*nn);
c2[jj]=c2[jj-1]+gg()/sqrt(*nn);
}
}
5.3 Moto browniano e EDP
In questo paragrafo e nei successivi esploreremo il rapporto tra questo processo ed alcuni
problemi alle derivate parziali da un punto di vista numerico. Questo fornirà dei metodi di
104
Capitolo 5. Simulazione, processi e EDP
risoluzione di questi problemi mediante delle tecniche di simulazione che paragoneremo con
i metodi (elementi finiti. . . ) analitici.
Sia D ⊂ Rm un dominio limitato e indichiamo
4=
∂2
∂2
+
.
.
.
+
2
∂x12
∂xm
il Laplaciano. Il primo problema è
(5.1)
1
2
4u = −1 in D
u=0
su ∂D
che si può rappresentare (sotto ipotesi di regolarità per ∂D. . . )
(5.2)
u(x) = E(τx )
dove τx è il tempo d’uscita di (x + Bt )t , t > 0 da D, cioè
τx = inf {t, x + Bt ∈ ∂D }
(questo è un teorema). Ora vogliamo fare le cose seguenti, considerando D = {|x | ≤ 1}, la
palla unitaria di Rm .
• Simulare traiettorie del moto browniano per vari valori del punto iniziale, ottenendo
quindi un’approssimazione numerica della soluzione u del problema (5.1).
• Risolvere (in dimensione 2) il problema (5.1) con il metodo degli elementi finiti (usando
freefem).
• Confrontare i risultati ottenuti con il risultato esatto. Infatti non è difficile vedere che
u(x) =
1
(1 − |x |2 )
m
è soluzione (ricordare che m è la dimensione). In particolare, per x = 0, vediamo che il tempo
medio d’uscita del moto browniano dalla palla unitaria partendo dall’origine è 1 diviso per la
dimensione.
Le prime sperimentazioni: indicheremo con m la dimensione e con ns il numero d’intervallini
in cui suddividiamo l’intervallo temporale [0, 1].
Esercizio 5.6 Per m= 2, x=(0,0)e ns= 100, modificare il programma precedente (che
simulava una singola traiettoria) in maniera che ora ne simuli molte e di ciascuna calcoli il
tempo d’uscita dalla palla di raggio 1. Simulare 1000 traiettorie e calcolarne la media dei
tempi d’uscita. Confrontare il risultato ottenuto con il vero valore 21 . Ripetere con ns= 400,
ns= 1600 e ns= 7200. Cosa si osserva ? Quanto velocemente tende a 0 l’errore ?
5.3 Moto browniano e EDP
105
Esercizio 5.7 Modificare il codice C in maniera da poter simulare il moto browniano a partire
da un punto eventualmente diverso da (0, 0). Ad esempio inserendo il codice
void tm(unsigned int *nn,double *hh,double *u,double *v,double
et[])
/*
nn=numero di simulazioni, hh=passo di discretizzazione,
u,v=coordinate iniziali, et=tempi di uscita
*/
{
unsigned int jj;
double c1,c2,ct,sh;
sh=sqrt(*hh);
for(jj=0;jj<*nn;++jj)
{
c1=*u;
c2=*v;
ct=0.;
while (c1*c1+c2*c2<1)
{
c1=c1+gg()*sh;
c2=c2+gg()*sh;
ct=ct+*hh;
}
et[jj]=ct;
}
}
Usarlo poi per calcolare la soluzione di (5.1) a partire da (0, 21 ) e da (0.9, 0) usando come passo
di approssimazione hh= 1/400 e hh= 1/7200. Confrontare con il valore esatto e discutere
la bontà dell’approssimazione.
Esercizio 5.8 Correggere il codice dell’esercizio precedente per calcolare il tempo medio
dalla palla di raggio 1 partendo dal centro in dimensione 5. Ricordare che il valore esatto è 15 .
Esercizio 5.9 Costruiamo una soluzione del problema (5.1) con Freefem e mediante simulazione e confrontiamo i due metodi.
a) Calcolare la soluzione con Freefem dando le istruzioni per scrivere i risultati su un file
esterno per la visualizzazione con scilab. Fare il grafico. Controllare numericamente l’errore
fatto da Freefem nei punti della triangolazione. Un programma Freefem a questo scopo
può essere
border C(t=0,2*pi){x=cos(t); y=sin(t);}
mesh Th = buildmesh (C(50));
106
Capitolo 5. Simulazione, processi e EDP
fespace Vh(Th,P1);
Vh u,v;
func f= 1; // definition of a called f function
real cpu=clock(); // get the clock in second
solve Poisson(u,v,solver=LU) = // defines the PDE
int2d(Th)(0.5*dx(u)*dx(v) + 0.5*dy(u)*dy(v)) // bilinear part
- int2d(Th)( f*v) // right hand side
+ on(C,u=0) ; // Dirichlet boundary condition
plot(u);
cout << " CPU time = " << clock()-cpu << endl;
// to build an output data file
{ ofstream ff("graph.txt");
for (int i=0;i<Th.nt;i++)
{ for (int j=0; j <3; j++)
ff<<Th[i][j].x << " "<< Th[i][j].y<< " "<<u[][Vh(i,j)]<<endl;
ff<<Th[i][0].x << " "<< Th[i][0].y<< " "<<u[][Vh(i,0)]<<endl;
}
}
Per visualizzare in scilab un grafico in formato Freefem, conviene importare i dati in
una variabile, diciamo gr, con il solito comando di lettura di file esterno:
gr=read("nomefile",-1,3);
("nomefile" è il file di output di Freefem, nel nostro caso "graph.txt") e poi eseguire il
programmino
sg=size(gr);nt=sg(1)/4;//nt e‘ il numero di facce triangolari
clf();//cancella la pagina grafica precedente
for i=1:nt
ind=1+4*(i-1);
xt=gr(ind:ind+3,1);
yt=gr(ind:ind+3,2);
zt=gr(ind:ind+3,3);
plot3d(xt,yt,zt);//disegna le triangolazioni una a una
end
a=gca();a.isoview="on";//impone le stesse unita‘ di misura
I dati Freefem sono una successione di pacchetti di 4 righe. Ogni riga è contiene tre coordinate:
le prime tre righe individuano il valore della funzione nei punti di un triangolo, la quarta
‘‘chiude’’ il triangolo ripetendo la prima riga. Il programmino qui sopra disegna uno dopo
l’altro i triangoli che messi insieme costituiscono la superficie.
b) Vediamo ora come si può calcolare la soluzione del problema (5.1) mediante simulazione. Negli esercizi precedenti abbiamo calcolato un’approssimazione della soluzione in
un singolo punto. Per arrivare a fare il grafico occorrerà fare il calcolo in una griglia di punti
5.3 Moto browniano e EDP
107
0.6
0.55
0.5
0.45
0.4
0.35
0.3
Z
0.25
0.2
0.15
0.1
−1
−0.8
0.05
−0.6
−0.4
−0.2
Y
0
0.2
0.4
0.6
0.8
1
1
0.9
0.8
0.7
0.6
0.5
0.4
0.3
0.2
0.1
0
X
−0.1
−0.2
−0.3
−0.4
−0.5
−0.6
−0.7
−0.8
−0.9
0
−1
Figura 5.1 Il grafico della soluzione di (5.1) ottenuta col metodo degli elementi finiti (Freefem). Il
grafico è molto regolare e, facendo un confronto con il valore esatto, anche preciso.
e poi far disegnare a scilab la superficie. Un modo interessante di fare tutto ciò consiste
nel prendere come griglia i punti generati da Freefem (le cui coordinate si trovano nelle
due prime colonne del file "graph.txt". Si tratterà di leggere quel file, calcolare facendo le
simulazioni i valori della soluzione e poi fare il grafico con la stessa tecnica che per la Figura
1. Questo viene fatto con il seguente script:
nn=7200;hh=1/100;
gr=read("graph.txt",-1,3);coord=gr(:,1:2);
ctr=size(coord);
while ctr(1,1)>0
xc=coord(1,1);yc=coord(1,2);
index=find(gr(:,1)==xc&gr(:,2)==yc);
index2=find(coord(:,1)==xc&coord(:,2)==yc);
//trova tutti i punti della griglia che hanno le stesse
//coordinate
et=call("tm",nn,1,"i",hh,2,"d",xc,3,"d",yc,4,"d","out",[nn 1],5,"d");
gr(index,3)=mean(et);
//calcola in un colpo solo la soluzione in
//tutti i punti della griglia che hanno le stesse coordinate
coord(index2,:)=[];//eliminiamo dalla griglia i punti in cui
//la soluzione e‘ stata calcolata
ctr=size(coord)
end
//segue il programma di disegno dei triangoli a uno a uno che
//gia‘ conosciamo
sg=size(gr);nt=sg(1)/4;
clf();
for i=1:nt
ind=1+4*(i-1);
xt=gr(ind:ind+3,1);
yt=gr(ind:ind+3,2);
108
Capitolo 5. Simulazione, processi e EDP
zt=gr(ind:ind+3,3);
plot3d(xt,yt,zt);//disegna le triangolazioni una a una
end
a=gca();a.isoview="on";
Usare questo script per disegnare il grafico della soluzione per i valori nn=400, hh=1/100,
nn=7200, hh=1/100, nn=7200, hh=1/7200.
Che conclusioni trarre ?
1) Il metodo di simulazione è molto impreciso e richiede molte traiettorie e un passo
di discretizzazione molto piccolo per dare risultati affidabili. In realtà ci sono metodi per
migliorare i risultati, ma non siamo in grado di parlarne.
2) Rimane comunque il fatto che la simulazione si può implementare facilmente anche in
dimensione grande, senza grosse difficoltà, quando altri metodi numerici diventano rapidamente molto complicati, o addirittura non sono più disponibili.
3) Da notare che talvolta interessa solo il valore della soluzione in un singolo punto.
A differenza della simulazione, metodi come gli elementi finiti richiedono in ogni caso di
calcolare la soluzione ovunque.
nn=400,hh=1/100
0.6
0.55
0.5
0.45
0.4
0.35
Z
0.3
0.25
0.2
0.15
0.1
0.05
0
−1
−0.9
−0.8
−0.7
−0.6
−0.5
−0.4
−0.3
−0.2
−0.1 Y
0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1
1
0.8
0.6
0.4
0.2
0
X
−0.2
−0.4
−0.6
−0.8
−1
Figura 5.2 Soluzione calcolata per simulazione, con n = 400 traiettorie ogni volta ed un passo h =
1/100. Il grafico è bitorzoluto. Si vede anche che i valori calcolati sono abbastanza più grandi del valore
vero. Ad esempio all’origine questo grafico prende il valore 0.56, con un errore del 12%.
5.4 La simulazione della distribuzione d’uscita
Prima di vedere altri problemi del tipo di (5.1), vediamo come si può simulare la posizione
d’uscita del MB dalla palla di raggio 1. Si tratta di modificare il programma di simulazione
realizzato precedentemente in modo da fargli produrre la posizione al momento dell’uscita
invece che il tempo trascorso.
Occorre però fare attenzione: la traiettoria attraversa infatti la circonferenza ad un istante
compreso tra il primo istante della discretizzazione in cui essa si trova al di fuori e l’istante
immediatamente precedente (vedi Figura 5.5). Per una buona approssimazione del vero punto
in cui la traiettoria esce dal cerchio occorre determinare il punto in cui il segmento che congiunge questi due punti della traiettoria incrocia il cerchio. Un modo è il seguente. Indichiamo
5.4 La simulazione della distribuzione d’uscita
109
nn=7200,hh=1/100
0.6
0.55
0.5
0.45
0.4
0.35
0.3
Z
0.25
0.2
0.15
0.1
−1
0.05
−0.8
−0.6
−0.4
−0.2
Y
0
0.2
0.4
0.6
0.8
1
1
0.9
0.8
0.7
0.6
0.5
0.4
0.3
0.2
0
0.1
X
−0.1
−0.2
−0.3
−0.4
−0.5
−0.6
−0.7
−0.8
−0.9
0
−1
Figura 5.3 Soluzione calcolata per simulazione, ma ora con n = 7200 traiettorie ogni volta ed un passo
h = 1/100. Il grafico è molto migliorato. Si vede però che i valori calcolati sono ancora abbastanza più
grandi del valore vero. Inoltre la superficie ‘‘non si incolla bene’’ al bordo.
nn=7200,hh=1/7200
0.6
0.5
0.4
0.3
Z
0.2
0.1
−1
−0.8
−0.6
−0.4
−0.2
Y
0
0.2
0.4
0.6
0.8
1 1
0.8
0.6
0.4
0.2
0
X
−0.2
−0.4
−0.6
−0.8
0
−1
Figura 5.4 Soluzione calcolata per simulazione, con n = 7200 traiettorie ogni volta ed un passo
h = 1/7200. Il grafico è ora abbsatanza buono, anche se ancora meno bello di quello ottenuto con gli
elementi finiti, in particolare il valore al bordo è ancora un po’ ondivago. Ora il valore all’origine è 0.507,
con un errore dell’1.4%: un errore ancora non trascurabile nonostante un passo di discretizzazione molto
piccolo.
con y il punto della discretizzazione immediatamente prima dell’uscita e con x il punto successivo (che dunque sta fuori della palla). Il segmento che congiunge questi due punti si può
parametrizzare
[0, 1] 3 t → t (x − y) + y
Occorre quindi trovare il valore di t per cui si ha
(5.3)
t → |t (x − y) + y |2 = 1
Sviluppando il modulo si trova l’equazione di secondo grado
t 2 |x − y |2 + 2t (hx, y i − |y |2 ) + |y |2 − 1 = 0
Dunque se poniamo
a = |x − y |2 ,
b = hx, y i − |y |2 ,
c = |y | 2 − 1
110
Capitolo 5. Simulazione, processi e EDP
si vede che delle due radici quella con il meno:
t0 =
p
1
(−b − b2 − ac )
a
è compresa tra 0 e 1 (l’altra è più grande di 1) ed è dunque il valore di t cercato. Dunque il
punto d’uscita è approssimato da t0 (x − y) + y.
...
...
...
...
...
...
...
...
...
...
...
...
... ...
...
... ...
...
... ...
...
... ...
... ...
....................................................................
..........
...
...
..
...
..
...
.
k
.
...
..
...
ns
...
..
...
..
.
...
.... ... ...
...
... ... ...
...
...
...
...
..
..
...
..
.
..
..
...
•
•
B(it +
•
•
)
B(it +
•
k+1
ns )
•
Figura 5.5
Esercizio 5.10 Sempre in dimensione 2 simulare n = 200 punti di uscita dalla palla unitaria
partendo dall’origine. Poi fare il grafico della circonferenza e segnare i punti di uscita risultanti
dalla simulazione. Cosa si osserva ?
Ripetere l’operazione per la dimensione 3. Per fare il grafico di una nube di punti tridimensionale il comando scilab è param3d1: se i vettori (riga) xx, yy e zz contengono i valori
delle tre direzioni dei punti ottenuti dalla simulazione, il comando
param3d1(xx,yy,list(zz,zeros(zz)));
disegnerà nello spazio i punti corrispondenti. Ricordare che i vettori devono essere vettori
riga. Se i punti vengono disegnati troppo piccoli, la loro dimensione può essere modificata
con il comando p=get("hdl");p.mark_size=1;.
Sapreste dedurre dalle proprietà d’invarianza del moto browniano che la distribuzione d’uscita
è uniforme sulla circonferenza ? E che, in qualunque dimensione m, è uniforme sulla sfera
Sm−1 di Rm ?
Esercizio 5.11 Ripetere la simulazione della distribuzione di uscita dalla palla unitaria di R2
9
partendo dai punti ( 21 , 0), ( 43 , 0) e ( 10
, 0) (cioè da punti che si trovano sempre più vicini alla
frontiera).
5.5 Il problema di Dirichlet e la distribuzione d’uscita
111
5.5 Il problema di Dirichlet e la distribuzione d’uscita
Possiamo ora affrontare un secondo problema interessante: è il problema di Dirichlet
1
2 4u = 0 in D
(5.4)
su ∂D
u=φ
dove φ è una funzione definita sul bordo e abbastanza regolare. È il problema di Dirichlet.
Più in generale dato il problema
1
su D
2 4u − cu = f
(5.5)
u|∂D = φ.
(che ha soluzione sotto opportune ipotesi di regolarità sulle funzioni f , φ e sul bordo ∂D del
dominio) la soluzione u si può rappresentare
Z τx
h R τx
i
h R τx
i
−
c(x+Bs ) ds
−
c(x+Bs ) ds
0
0
φ(x + Bτx ) − E e
f (x + Bs ) ds .
(5.6)
u(x) = E e
0
Ricordiamo che τx è il primo istante in cui il processo (x + Bt )t esce dalla palla. Dunque
x + Bτx è la posizione in cui avviene l’uscita.
Quindi per il caso particolare del problema (5.4), la soluzione sarà data da
(5.7)
u(x) = E[φ(x + Bτx )]
cioè dalla media di φ fatta rispetto alla distribuzione d’uscita. Più precisamente, indichiamo
con P (x, dy) la legge di uscita cioè la legge della v.a. x + Bτx . Si tratta, per ogni x ∈ D, di
una probabilità sulla frontiera ∂D e la soluzione del problema di Dirichlet risulta essere data
da
Z
φ(y) P (x, dy)
u(x) =
∂D
Come abbiamo messo in evidenza nel paragrafo precedente, se D è una palla in Rm e consideriamo x = 0 (l’origine), allora la probabilità P (0, dy) non è altro che la probabilità uniforme
sulla superficie della sfera.
Esercizio 5.12 a) Calcolare con Freefem la soluzione del problema (5.5) quando D è la
palla unitaria (in dimensione 2) e φ(x) = x2 ∨ 0. Fare il grafico in scilab con la procedura
descritta a p. 106.
b) Determinare, usando la rappresentazione (5.7), la soluzione del problema (5.5) quando
D è la palla unitaria (in dimensione 2) e φ(x) = x2 ∨ 0, usando diversi valori per il numero
di traiettorie nn e il passo di discretizzazione hh. Anche qui usare come punti di partenza
per le simulazioni quelli forniti dalla griglia di Freefem e fare il grafico come descritto a
p. 107. Confrontare il risultato con quello ottenuto con Freefem.
c) Confrontare anche con la soluzione esatta che si può calcolare dato che, se D è la palla
di raggio R in Rm , la soluzione è data da
Z
u(x) =
φ(y)P (x, y) dσm (y)
∂D
112
Capitolo 5. Simulazione, processi e EDP
dove σm è la misura superficiale della sfera di raggio R e P è il nucleo di Poisson
P (x, y) =
1 R 2 − | x |2
Rωm |x − y |m
dove ωm è l’area della superficie sferica della sfera unitaria di Rm . Dunque per m = 2 e R = 1
Z 2π
φ(θ)
1
2
dθ
(1 − |x | )
(5.8)
u(x) =
2π
|x − y(θ)|2
0
dove y(θ) = (cos θ, sin θ). Nel caso della scelta φ(x) = x2 ∨ 0, dunque φ(θ) = sin θ per
0 ≤ θ ≤ π e φ(θ) = 0 altrimenti. Dunque
Z π
1
sin θ
2
(5.9)
u(x) =
dθ
(1 − |x | )
2
2π
0 |x − y(θ)|
Occorrerà dunque considerare la griglia di punti ottenuta con Freefem e per ciascuno di essi
calcolare numericamente con scilab l’integrale della (5.9). Fare il grafico in 3D dell’errore
commesso dalla simulazione.
d) Calcolare, prima con la simulazione ma con un numero elevato di traiettorie e poi
calcolando la soluzione esatta, il valore di u all’origine. Da notare che, tramite la (5.9) oppure
usando la proprietà di media delle funzioni armoniche, il valore di u in 0 si calcola molto
facilmente (= π1 ). Valutare l’errore al variare del numero di traiettorie simulate e del valore
del passo di discretizzazione delle traiettorie (ns nel programma delle pagine precedenti).
Esercizio 5.13 Ripetere le valutazioni dell’esempio precedente, punto d) (confronto tra il
risultato della simulazione ed il valore esatto) all’origine, ma in dimensione 3 e con il dato al
bordo
(5.10)
φ(x, y, z) = z1z>0 .
Si ricorda che le coordinate sferiche sono θ, φ, 0 ≤ θ ≤ π, 0 ≤ φ ≤ 2π dove
z = cos θ
y = sin θ cos φ
x = sin θ sin φ
e che l’elemento di superficie è
σ3 (dθ, dφ) = sin θ dθdφ
Esercizio 5.14 Calcolare la soluzione del problema (5.4) in dimensione 2 per la funzione φ
che vale 1 per x > 0 e zero se no. Si tratta cioè di calcolare la probabilità che la traiettoria
esca dalla palla dalla metà di destra. Da notare che, grazie alla rappresentazione (5.7) ed alle
proprietà d’invarianza del MB, già sappiamo che la soluzione vale 21 per i punti della palla che
si trovano sull’asse y. Come precedentemente, usando la griglia di punti fornita da Freefem,
calcolare per simulazione il valore della soluzione e fare il grafico (con la procedura descritta
a p. 107). Controllare i valori numerici ottenuti e verificare se effettivamente la soluzione vale
1
2 sull’asse delle ordinate. Confrontare il risultato con la soluzione ottenuta con Freefem).
5.6 Gli autovalori del laplaciano
113
Osservazioni 5.15 Le formule di rappresentazione delle soluzioni del problema di Dirichlet
come media di funzionali del moto browniano sono utili per trovare soluzioni approssimate
mediante simulazione, ma hanno anche delle conseguenze teoriche interessanti.
a) Ricordiamo che una funzione u si dice armonica in x se 4u(x) = 0. Ricordiamo
che la distribuzione d’uscita del moto browniano da una sfera partendo dal suo centro è la
distribuzione uniforme. La formula di rappresentazione (5.7) dà quindi immediatamente una
proprietà importante delle funzioni armoniche: se u è armonica in un aperto D, allora u(x)
è uguale alla media di u fatta su ogni sfera di centro x e contenuta in D. Questa proprietà è
anzi caratterizzante delle funzioni armoniche: una funzione u continua su D e che gode della
proprietà di media è necessariamente armonica.
b) Un’altra proprietà importante delle soluzioni di problemi come quello in (5.4) (quindi in
particolare per le funzioni armoniche) è il principio del massimo che afferma che la soluzione
raggiunge il suo valore massimo sul bordo ∂D. Alla luce della formula di rappresentazione
(5.7) questa proprietà è evidente, dato che u appare come una media dei valori che essa assume
sul bordo.
c) Un altro caso particolare del problema (5.5) è dato da
1
2 4u − θu = 0 su D
(5.11)
u|∂D = 1.
La formula di rappresentazione (5.6) qui diviene
(5.12)
u(x) = E[e−θτx ]
Dunque u(x) non è altro che la trasformata di Laplace, calcolata in θ del tempo d’uscita, τx ,
dalla palla unitaria partendo da x. Osserviamo che la formula di rappresentazione (5.12) già
dà delle informazioni sulla soluzione: se θ > 0 ci si aspetterà che la funzione u prenda dei
valori tanto più piccoli quanto più il punto x si trova all’interno di D: infatti in questo caso
più il punto si trova all’interno tanto più il tempo d’uscita τx tenderà ad essere grande e così
pure u(x). Inversamente, se θ < 0, u tenderà ad essere grande tanto più il punto si troverà
all’interno. Se θ = 0 troviamo u ≡ 1, come soluzione evidente.
Esercizio 5.16 Per θ = −1 e θ = 2 risolvere come prima il problema (5.11) con i due metodi,
simulazione ed elementi finiti.
Esercizio 5.17 Studiare il problema (5.11) calcolando la soluzione in x = 0 per una griglia
di valori θ tra −4 e −1 e farne il grafico (in funzione di θ). Osservare che basta fare una
simulazione di tempi d’uscita (si consiglia di provare con 1000000 di traiettorie), a partire
dalla quale si possono trovare tutti i valori di u(0) al variare di θ.
5.6 Gli autovalori del laplaciano
Sia D ⊂ Rm un aperto limitato abbastanza regolare. Cerchiamo dei numeri λ (gli autovalori)
tali che il problema di Dirichlet
1
4u = λu
2
u|∂D = 0
Paolo Baldi
Corso di Laboratorio di Calcolo
Tor Vergata 2013-14
114
Capitolo 5. Simulazione, processi e EDP
abbia delle soluzioni diverse da 0. Si può dimostrare che
• Esiste una successione
. . . λk ≤ . . . ≤ λ2 ≤ λ1 < 0
di autovalori. Che sono dunque tutti strettamente negativi (sapreste farlo vedere ?). Inoltre
limn→∞ λn = −∞ e quindi non ci sono punti di accumulazione.
• Inoltre gli autovalori sono tutti semplici e si può scegliere una famiglia (un )n di autofunzioni in maniera che essi costituiscano una base ortonormale di L2 (D).
Per capire un po’ meglio vediamo come vanno le cose in dimensione 1 per D = [−1, 1]. Per
quali valori di λ esiste una soluzione non nulla di
1 00
u = λu
2
u(−1) = u(1) = 0
Se λ è negativo l’integrale generale dell’equazione 21 u00 = λu è
p
p
c1 cos( −2λx) + c2 sin( −2λx)
Perché tra queste funzioni ce ne sia una che si annulla in 1 e in −1 occorre che ci sia una
soluzione non nulla del sistema (nelle incognite c1 e c2 )
p
p
c1 cos( −2λ ) + c2 sin( −2λ ) = 0
p
p
c1 cos( −2λ ) − c2 sin( −2λ ) = 0
ovvero che si annulli il determinante della matrice
√
√
cos(√−2λ) sin( √−2λ)
cos( −2λ) − sin( −2λ)
√
√
√
0. Poiché il seno si annulla nei punti
cioè −2 cos( −2λ) sin( −2λ) = 2 sin(2 −2λ) = √
x = kπ, gli autovalori sono i numeri λ per cui si ha 2 −2λ = kπ, ovvero
λk = −k 2
π2
8
Si vede che le autofunzioni sono
u1 (x) = cos( π2 x)
u2 (x) = sin(π x)
...
u2m+1 (x) = cos((2m + 1) π2 x)
u2m (x) = sin(m π x)
...
Come indicato sopra si tratta di una base ortonormale di L2 ([−1, 1], dx) (queste funzioni
hanno tutte norma L2 uguale a 1).
5.6 Gli autovalori del laplaciano
115
Esercizio 5.18 Calcolare e disegnare a confronto con l’originale con scilab gli sviluppi
in questa base ortonormale (sull’intervallo [−1, 1]) delle funzioni
a) 1 prendendo la somma dei primi n termini per n = 20, 40, 100;
b) f (x) = 1 − |x | per n = 3, 7, 11;
c) f (x) = 1 − x 2 per n = 2, 3;
d) f (x) = 1 − |x |3/2 per n = 3, 7, 11.
e) f (x) = x(1 − x 2 ).
Da notare che le funzioni in a), b), c) e d) sono pari. Dunque nello sviluppo interverranno solo
i coefficienti dei termini dispari (cos k π2 ). La funzione in e) invece è dispari. . . Per risolvere
questo esercizio si potrà usare la funzione intg di scilab. Ad esempio con il codice
nn=3;tt=linspace(-1,1);
deff("y=fun(x)","y=1-abs(x)")
deff("y=fc(x)","y=cos((2*kk-1)*x*%pi/2).*fun(x)")
ll=zeros(1,nn);for ii=(1:nn),kk=ii;ll(ii)=intg(-1,1,fc);end;
vv=(1:nn);deff("y=f2(x)","y=sum(ll.*cos((2*vv-1).*x*%pi/2))");
yy=feval(tt,f2);
scf(1);plot(tt,yy,"g");
plot(tt,fun(tt),"k");
che risolve il punto b) con n = 3. Per applicarlo alle altre situazioni basterà cambiare la
definizione della funzione fun. La conoscenza di autovalori e autofunzioni permette di
trovare la soluzione del problema di Poisson
(5.13)
1
4u = f
2
u|∂D = 0 .
Infatti se f ∈ L2 (D), vale lo sviluppo (convergente in L2 , per lo meno)
f =
X
ak uk
k
e basta osservare che una soluzione è data da
u=
X ak
k
λk
uk .
Esercizio 5.19 Calcolare numericamente e fare il grafico della soluzione del problema di
Poisson (5.13) in dimensione 1 per D = [−1, 1] e con f data dalle funzioni di a), b), c), d)
dell’Esempio 5.18.
116
Capitolo 5. Simulazione, processi e EDP
Esercizio 5.20 Consideriamo il problema di Dirichlet per il laplaciano sul quadrato Q =
[−1, 1] × [−1, 1].
a) Sapreste indicare delle autofunzioni della forma v(x, y) = v1 (x)v2 (y)? Quali sarebbero
gli autovalori corrispondenti ?
b) Sapreste dimostrare che tutte le autofunzioni sono di questa forma ?
Esercizio 5.21 Calcolare numericamente e fare il grafico della soluzione del problema di
Poisson (5.13) in dimensione 2 per D = il quadrato [−1, 1] × [−1, 1] e per
f (x, y) = (1 − |x |)(1 − |y |) .
Confrontare poi con la soluzione ottenuta con Freefem.
1.0
0.9
0.8
0.7
Z
0.6
0.5
0.4
0.3
0.2
0.1
0.0
−1.0
−0.6
−1.0
−0.6
−0.2
−0.2
0.2
0.2
0.6
Y
0.6
1.0
1.0
X
Figura 5.6 Il grafico dell’autofunzione u1 per D = Q il quadrato. L’autovalore corrispondente è
λ1 = 41 π 2 . Da notare che si tratta di una funzione positiva o meglio di segno costante (anche −u1 è
autofunzione associata allo stesso autovalore).
Vediamo invece, almeno parzialmente, cosa succede quando D = il cerchio, che prenderemo
di raggio 1 per comodità.
Se ci limitiamo a cercare delle autofunzioni che siano funzioni radiali, questi e gli autovalori
corrispondenti sono legati alla funzione di Bessel J0 . Questa funzione speciale è definita come
la soluzione dell’equazione
xw 00 (x) + w0 (x) + xw = 0
ed è anzi l’unica (a meno di costanti moltiplicative, naturalmente) soluzione di questa equazione
che sia limitata (tutte le altre hanno una singolarità in 0). Oltre che a soddisfare l’equazione
ordinaria precedente, J0 è caratterizzata da J0 (0) = 1.
Come conseguenza, la funzione u(x) = J0 (|x |), x ∈ R2 , è un autofunzione dell’operatore di
Laplace. Infatti in coordinate polari il laplaciano di Rd si scrive
4=
d2
d −1 d
+
+ ...
2
ρ dρ
dρ
5.6 Gli autovalori del laplaciano
117
1.0
0.8
0.6
0.4
Z
0.2
0.0
−0.2
−0.4
−0.6
−0.8
−1.0
−1.0
−1.0
−0.6
−0.6
−0.2
−0.2
0.2
0.2
0.6
Y
0.6
1.0
X
1.0
Figura 5.7 Il grafico di un autofunzione per l’autovalore λ = − 58 π 2 per D = Q il quadrato (questo
autovalore ha due autofunzioni indipendenti).
1.0
0.8
0.6
0.4
Z
0.2
0.0
−0.2
−0.4
−0.6
−0.8
−1.0
−1.0
−1.0
−0.6
−0.6
−0.2
−0.2
0.2
0.2
Y
0.6
0.6
1.0
X
1.0
Figura 5.8 Il grafico dell’autofunzione per l’autovalore λ = −π 2 per D = Q il quadrato (anche qui
due autofunzioni indipendenti).
dove . . . indica un operatore differenziale nelle coordinate angolari. Dunque, se u(x) = J0 (|x |)
e d = 2,
1 0
4u(x) = J0 00 (|x |) +
J0 (|x |) = −J0 (|x |) = −u(x)
|x |
e quindi u è autofunzione per l’autovalore λ = −1. Per ottenere una funzione che si annulli
sul bordo di D, occorre sapere che la funzione di Bessel J0 ha una infinità di zeri (vedi il
grafico nella Figura 5.9 ).
Se indichiamo con ζ1 < ζ2 < . . . gli zeri della funzione J0 , allora le funzioni ui (x) = u(ζi x) =
J0 (ζi |x |) sono nulle su ∂D e soddisfano
4ui (x) = ζi2 (4u)(ζi x) = ζi2 u(ζi x) = −ζi2 ui (x) .
118
Capitolo 5. Simulazione, processi e EDP
1
..............
.......
......
.....
.....
.....
.....
.....
.....
.....
.....
..................................
.....
.........
..........
.....
.......
........
.
.....
......
........
.
.
........
.
.
.
..
........
.
.
•..........
•
•...............
.
.
.
........•
..
.
.
.
.
.
.
.
.
.
.
.
......
.
.
.
.
..........
.....
......
......
........10
.............................
0
2
4
6
8
12
......
.......
............ ....................
.......
Figura 5.10 Grafico della funzione di Bessel J0 .
Dunque le ui sono autofunzioni per l’operatore di Laplace con autovalore −ζi2 , o meglio, per
i nostri scopi, autofunzioni per l’operatore 21 4 con autovalore − 21 ζi2 . È chiaro che le funzioni
ui sono le sole autofunzioni del laplaciano che siano funzioni radiali e che si annullano su ∂D.
In pratica per disporre di queste autofunzioni è necessario procurarsi un modo di calcolare la
funzione di Bessel J0 e di determinarne gli zeri. scilab dispone della funzione besselj
che calcola la funzione J0 : besselj(0,x) fornisce i valori di J0 calcolati nei punti del
vettore x. Il comando fsolve dà gli zeri:
deff("y=f(x)","y=besselj(0,x)")
zer=fsolve([2.4,5.8,8,12,15,18,22,25,28,31,34,37,40,44,47,50,
52,56,58,62,65,68,72,75,78,81,84,87,90,93,96,99],f);
produce gli zeri della funzione che sono ‘‘vicini’’ ai punti 2.4, 5.8, , . . . e li mette nella variabile
zer. Per verifica facciamo il grafico di J0 e dei valori degli zeri che abbiamo trovato.
tl=linspace(0,100);scf(21);clf();plot(tl,besselj(0,tl));
plot([0,100],[0,0],"k");plot(zer,zeros(zer),".");
Esercizio. 5.22 Quanto vale il più grande autovalore di
cerchio ? Fare il grafico dell’autofunzione.
1
2
4 per il problema di Dirichlet sul
Esercizio 5.23 Determinare le prime 5 autofunzioni radiali del Laplaciano normalizzate perché abbiano norma L2 uguale a 1 (le funzioni ui (x) = J0 (ζi |x |) introdotte prima sono normalizzate dalla condizione ui (0) = 1 e non dal fatto di avere norma L2 uguale a 1).
Verificare anche, numericamente, che le funzioni così ottenute sono ortogonali in L2 (limitarsi
a un paio di casi). Naturalmente sappiamo già che queste funzioni sono ortogonali in L2 .
Perché ?
Si tratta di fare uso del comando intg di scilab per calcolare norme L2 e prodotti scalari.
Ricordare che stiamo parlando di funzioni sulla palla di raggio 1 e non su [−1, 1].
Esercizio 5.24 Risolvere il problema in dimensione d = 2
1
4u = f
2
u|D = 0
5.6 Gli autovalori del laplaciano
119
dove D è il cerchio (la palla) di raggio 1 e f (x) = 1 − |x |.
a) con Freefem;
b) calcolando lo sviluppo in autofunzioni del laplaciano di f .
c) con la simulazione del moto browniano usando la (5.6).
Esercizio 5.25 Risolvere con Freefem il problema (5.11) con D =il cerchio di raggio 1
per θ = −2, θ = −2.8 e θ = −3. Cosa si osserva ? Sempre per per θ = −2, θ = −2.8 e θ = −3
stimare per simulazione il valore di u(0) = E[e−θτ0 ] (partendo da 0, quindi). Per ognuno di
questi valori di θ fare 20 volte la simulazione con 105 traiettorie ogni volta. Cosa si osserva ?
1.2
1.0
Z
0.8
0.6
0.4
0.2
0.0
−1.0
−0.6
−0.2
0.2
0.6
Y
1.0
1.0
0.8
0.6
0.4
0.2
0.0
−0.2
−0.4
−0.6
−0.8
−1.0
X
Figura 5.11 Il grafico dell’autofunzione u1 per D =il cerchio unitario. Da notare che si tratta
di una funzione positiva.
2.0
1.5
Z
1.0
0.5
0.0
−0.5
−1.0
−1.0
−1.0
−0.6
−0.6
−0.2
−0.2
0.2
Y
0.2
0.6
0.6
1.0
1.0
X
Figura 5.12 Il grafico dell’autofunzione u2 per D =il cerchio unitario. Da notare che eviden-
temente non si può trattare di una funzione positiva (deve essere ortogonale a u1 .
120
Capitolo 5. Simulazione, processi e EDP
5.7 L’equazione del calore
Formule di rappresentazione ed elementi finiti permettono anche di risolvere equazioni paraboliche. Per limitarci al caso del laplaciano il problema è, per un aperto D ⊂ Rd
 2
∂u
σ

 4u − cu +
=f
2
∂t

 u(x, T ) = φ(x)
u(x, t) = g(x, t)
(5.14)
su D × [0, T [
per x ∈ D
su ∂D × [0, T ]
g(x, t)
&
← φ(x)
0
-
T
g(x, t)
Figura 5.13 In un problema parabolico i dati al bordo vengono assegnati solo per i valori finali del
tempo (o solo per i valori iniziali nel caso del problema (5.20).
Nel problema (5.14) naturalmente occorrono delle ipotesi per avere esistenza e unicità. Un
set di ipotesi è ad esempio:
a) g una funzione continua su ∂D × [0, T ] tale che g(x, T ) = φ(x) se x ∈ ∂D;
b) c e f sono funzioni hölderiane D × [0, T [→ R e c ≥ 0.
c) ∂D è C 1 .
Nel seguito vedremo delle situazioni in cui le funzioni g, f, c non dipendono dal tempo. In
questo caso si vede facilmente che se u è soluzione di (5.14), allora la funzione v(x, t) =
u(x, T − t) è soluzione del problema di Cauchy
(5.15)
 2
σ
∂v


4v − cv −
=f
2
∂t

 v(x, 0) = φ(x)
v(x, t) = g(x)
su D ×]0, T ]
su D
su ∂D × [0, T ]
Questo problema modellizza la diffusione del calore nel dominio D, quando al tempo 0 la
distribuzione delle temperature è data da φ(x) e la temperatura del bordo è tenuta fissata a
g(x). Il fatto che nell’operatore di Laplace non compaiano derivate del prim’ordine significa
che non c’è convezione. Il fatto che la matrice dei coefficienti sia un multiplo dell’identità
significa che consideriamo che il calore si possa diffondere in tutte le direzioni allo stesso
modo (cioè che il mezzo che consideriamo sia isotropo). σ 2 è il coefficiente di diffusione e
rappresenta la conducibilità termica: più questo parametro è grande più nel mezzo considerato
il calore si diffonde velocemente.
Nel seguito considereremo tre metodi di risoluzione dell’equazione del calore.
5.7 L’equazione del calore
121
a) Il primo consisterà nel metodo degli elementi finiti, Freefem.
b) Il secondo farà ricorso alla simulazione del moto browniano. Infatti anche per i problemi
(5.14) e (5.15) esistono formule di rappresentazione delle soluzioni in termini di medie di
funzionali del moto browniano. La formula è, nel caso di coefficienti che non dipendono dal
tempo e per σ 2 = 1,
(5.16)
R τx
h
i
−
c(x+Bs ) ds
u(x, t) = E g(Bτx ) e 0
1{τ <T −t} +
R T −t
h
i
−
c(x+Bs ) ds
+ E φ(x + BT −t ) e 0
1{τx ≥T −t} −
R0
hZ τx ∧(T −t)
i
−
c(x+Bu ) du
ds
−E
f (x + Bs ) e t−s
0
per la soluzione u del problema (5.14). Nel caso φ ≡ 1, g ≡ 0, c ≡ 0, f ≡ 0 considerato
nell’Esercizio 5.26 qui sotto, la formula diviene semplicemente
(5.17)
h
i
u(x, t) = E φ(x + BT −t )1{τx ≥T −t} = P(τx ≥ T − t) .
Per la soluzione v della (5.15) si avrà dunque
(5.18)
v(x, t) = u(x, T − t) = P(τx ≥ t) .
Il caso in cui σ 2 è diverso da 1 si ricava facilmente da quanto visto finora osservando che se
v è soluzione di (5.15) con σ 2 = 1, allora
ṽ(x, t) = v(x, σ 2 t)
è soluzione di (5.15). Dunque la formula di rappresentazione per le soluzioni del problema
(5.15) è
(5.19)
ṽ(x, t) = v(x, σ 2 t) = P(τx ≥ σ 2 t) .
Questa relazione è anche utile su un piano intuitivo. Ad esempio si vede subito che se σ 2
cresce, l’evento {τx ≥ σ t } diventa più piccolo e quindi la soluzione ṽ decresce (ricordiamo
che stiamo considerando il problema (5.15), e quindi con φ(x) ≡ 1, g(x) ≡ 0, c = 0 e f = 0.
Questo fatto è abbastanza intuitivo se si pensa al significato fisico del problema (dominio in
cui all’inizio la temperatura è positiva ma è tenuta a 0 sulla frontiera), ma è meno evidente a
partire dal problema (5.15).
Da notare ancora i due vantaggi dei metodi di simulazione: la formula (5.18) permette di
calcolare la soluzione anche in un solo punto (x, t), senza che si sia costretti a trovare la
soluzione dappertutto, ed il fatto che la formula vale in ogni dimensione, oltre alla semplictà
della implementazione. Anche l’errore è lo stesso in qualunque dimensione. Abbiamo però
visto che gli elementi finiti producono una soluzione molto più precisa e sono senz’altro
preferibili in dimensione bassa.
122
Capitolo 5. Simulazione, processi e EDP
c) Lo sviluppo in autofunzioni del Laplaciano può produrre la soluzione del problema in
forma di serie. Se
X
ak uk (x)
φ(x) =
k
è lo sviluppo del dato iniziale φ in autofunzioni di 21 4 con l’assegnato dato al bordo, allora
la funzione
X
2
v(x, t) =
ak eλk σ t uk (x)
k
è soluzione del problema (5.15).
Esercizio 5.26 Realizzare un codice Freefem che produca la soluzione del problema precedente per D = [−1, 1] (quindi in una dimensione), T = 3, φ(x) ≡ 1, g(x) ≡ 0, c = 0 e f = 0.
Usare per la conducibilità i valori σ 2 = .1 e σ 2 = .4.
Il problema (5.15) diventa quindi
(5.20)
 2
σ
∂v


4v −
=0
2
∂t

 v(x, 0) = 1
v(x, t) = 0
su D ×]0, T ]
x∈D
su ∂D × [0, T ]
2
∂ v
(naturalmente, dato che siamo in una dimensione 4v(x, t) = ∂x
2 ). Stiamo quindi considerando una sbarra che al tempo 0 si trova a temperatura 1, ma le cui estremità vengono
tenute a temperatura 0.
La realizzazione del programmino Freefem non è complicata. Si tratterà di adattare uno
dei programmi già realizzati. Si tratterà sempre di un problema EDP di una funzione di due
variabili x e y, solo che ora una delle variabili andrà intesa come il tempo. Il programma
dovrà dunque contenere il solito set d’istruzioni:
a) innanzitutto il bordo andrà definito in quattro pezzi, dato che il dominio è rettangolare
e che inoltre occorrerà assegnare valori diversi su diversi pezzi del bordo stesso;
b) occorrerà dare i soliti comandi per la costruzione della griglia e dello spazio degli
elementi finiti e scrivere il problema in forma variazionale;
d) infine dare le istruzioni per scrivere i risultati su un file esterno per la visualizzazione con
scilab. Quest’ultima si farà meglio, piuttosto che con il comando plot3d, prima importando
i dati in una variabile gr con il solito comando di lettura di file esterno:
gr=read("nomefile",-1,3);
e poi eseguendo il programmino
sg=size(gr);nt=sg(1)/4;//nt e‘ il numero di facce triangolari
clf();//cancella la pagina grafica precedente
for i=1:nt
ind=1+4*(i-1);
xt=gr(ind:ind+3,1);
5.7 L’equazione del calore
123
yt=gr(ind:ind+3,2);
zt=gr(ind:ind+3,3);
plot3d(xt,yt,zt);//disegna le triangolazioni una a una
end
a=gca();a.isoview="on";//impone le stesse unita‘ di misura
Figura 5.14 Grafico della diffusione del calore con conducibilità σ 2 = 0.1.
Esercizio 5.27 Risolvere e fare il grafico del problema dell’esercizio precedente usando il
metodo dello sviluppo in serie di autofunzioni del laplaciano e fare il grafico.
Esercizio 5.28 a) Scrivere un codice scilab che calcoli mediante simulazione la soluzione
di (5.20) usando la rappresentazione (5.18) per x = 0 (e sempre per i valori σ 2 = .1 e σ 2 = .4).
Esercizio 5.29 Fare i grafici sovrapposti delle temperature al tempo T = 3 ottenute sviluppando la soluzione in autofunzioni per i valori σ 2 = .1 e σ 2 = .4.
Esercizio 5.30 Per valutare la precisione della soluzione fornita dalla simulazione, calcolare
la soluzione della equazione del calore al tempo T = 3 e con σ 2 = 0.1 nei punti x =
−0.9, −0.8, . . . , 0.9 usando le tre discretizzazioni ns= 100, 400, 1600. Fare i tre grafici
sovrapposti. Aggiungere al grafico quello della soluzione esatta che è data in forma di serie
∞ X
u(x, t) =
8
n=−∞
+8
√1
σ T −t
√1
σ T −t
(2n + 1 − x) − 8
(−2n − x) − 8
√1
σ T −t
√1
σ T −t
(2n − x) +
(−2n − 1 − x)
124
Capitolo 5. Simulazione, processi e EDP
Figura 5.15 Grafico della diffusione del calore con conducibilità σ 2 = 0.4. Si vede l’effetto del
raffreddamento più veloce a causa dell’aumento della conducibilità.
dove 8 indica la funzione di ripartizione della legge gaussiana N(0, 1). In condizioni normali
i termini per n = −3, −2, . . . , 3 danno il contributo essenziale. Vedi Figura 5.16 . Ricordiamo
che il comando per ottenere i valori della funzione di ripartizione di una legge N (0, 1) in
scilab è
y=cdfnorm("PQ",x,0,1)
Si tratta di un comando vettoriale, quindi l’argomento x può essere un vettore. In questo caso
però anche i valori 0, della media, e 1 della varianza devono essere vettori della stessa dimensione di x. Di fatto quindi occorre scrivere y=cdfnorm("PQ",x,zeros(x),ones(x)).
Data la lunghezza di questo comando, può convenire di definire una funzione che ha il solo
scopo di semplificare la scrittura. Ad esempio
deff("y=cn(x)","y=cdfnor(""PQ"",x,zeros(x),ones(x))")
Dopo di che si può definire una funzione che calcoli i termini per n = −4, . . . , 4 della serie:
deff("y=solheat(x)","y=sum(cn(((2*n+1)-x)/sqrt(T)/sig)cn((2*n-x)/sqrt(T)/sig))sum(cn((-(2*n)-x)/sqrt(T)/sig)-cn((-(2*n+1)-x)/sqrt(T)/sig))")
dopo avere definito il vettore n=[-4:4]. Si potrà infine calcolare la somma della serie per
dei valori di x compresi tra 0 e 1 mediante
5.7 L’equazione del calore
125
n=[-4:4];x=[.01:.01:.99];y=feval(x,solheat);
x=[0,x,1];y=[0,y,0];
plot(x,y,"r")
(la seconda riga di questo programmino serve solo ad estendere i valori calcolati agli estremi
dell’intervallo).
Esercizio 5.31 Confrontare la soluzione esatta al tempo T = 3 descritta nell’esercizio precedente con quella fornita dallo sviluppo in autofunzioni arrestando lo sviluppo ai primi n = 10
termini e poi n = 30 termini.
1.2
1.0
Z
0.8
0.6
0.4
0.2
0.0
0.0
0.5
1.0
1.5
0.0
2.0
0.5
Y
2.5
3.0
1.0
X
Figura 5.16 Il grafici della soluzione dell’equazione del calore (σ 2 = 0.1 per diversi valori della
discretizzazione: ns= 100 (in blu, il grafico più in alto), = 400 (in verde, quello subito sotto), = 1600
(in rosso, quello più sotto ancora). Infine il quarto grafico (in nero, quello più basso di tutti) è quello della
soluzione esatta. Come si vede la simulazione ha un errore abbastanza importante che decresce piuttosto
lentamente all’aumentare della finezza della discretizzazione. È comunque possibile correggere questo
errore con procedure di simulazione più raffinate.
Esercizio 5.32 a) Calcolare per simulazione la soluzione v del problema (5.20) quando
D =palla di raggio 1 di R2 , in modo da produrre il grafico della soluzione al tempo T = 3.
Operare sempre per i due valori σ 2 = 0.1 e σ 2 = 0.4 (Vedi Figura 5.18 ).
b) Calcolare la soluzione e farne il grafico usando lo sviluppo della soluzione in autofunzioni del laplaciano, facendo lo sviluppo con i primi 10 termini e poi con i primi 25.
126
Capitolo 5. Simulazione, processi e EDP
Il codice Freefem++ per la risoluzione dell’equazione del calore (σ 2 = 0.1)
verbosity=0;
//to remove all default output
// boundary
border C1(t=-1,1){x=t;y=0;}
border C2(t=0,3){x=1;y=t;}
border C3(t=1,-1){x=t;y=3;}
border C4(t=3,0){x=-1;y=t;}
// plot(C1(40)+C2(20)+C3(40)+C4(20))
// Triangulated domain Th
mesh Th=buildmesh(C1(10)+C2(30)+C3(10)+C4(30));
plot(Th,wait=1,ps="th1.eps");
fespace Vh(Th,P1);
Vh u,v;
solve Heat(u,v,solver=LU)=
int2d(Th)(0.2*dx(u)*dx(v))+int2d(Th)(dy(u)*v)
+on(C4,u=0)+on(C2,u=0)+on(C1,u=1);
plot(u,wait=1,ps="heat01.eps");
// to build an output data file
{ ofstream ff("graph-heat.txt");
for (int i=0;i<Th.nt;i++)
{ for (int j=0; j <3; j++)
ff<<Th[i][j].x << "
"<< Th[i][j].y<< " "
<<u[][Vh(i,j)]<<endl;
ff<<Th[i][0].x << "
"<< Th[i][0].y<< " "
<<u[][Vh(i,0)]<<endl;
//<<endl
//<<endl;
}
}
5.7 L’equazione del calore
127
0.30
0.25
0.20
0.15
0.10
0.05
0.00
0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0
Figura 5.17 Confronto tra la soluzione esatta dell’equazione del calore (in rosso, quella più grande
delle due) e quella ottenuta con il codice Freefem++.
Figura 5.18 Grafico della soluzione dell’equazione del calore sulla palla unitaria. Metodo usato:
simulazione, n = 1000 traiettorie simulate per ogni punto della griglia. In due dimensioni spaziali
(quindi 3 dimensioni contando il tempo) i metodi numerici diventano meno praticabili.
128
Capitolo 5. Simulazione, processi e EDP
Figura 5.19 Grafico della soluzione dell’equazione del calore sulla palla unitaria. Metodo usato:
simulazione, n = 4000 traiettorie simulate per ogni punto della griglia.
Figura 5.20 Grafico della soluzione dell’equazione del calore sulla palla unitaria (σ 2 = 0.1). Metodo
usato: sviluppo in autofunzioni, n = 10. Uno sviluppo con un numero maggiore di termini non avrebbe
portato a differenze di rilievo. Da notare che la soluzione ottenuta con il metodo di simulazione tende a
sovrastimare
6
Esempi Freefem
L’equazione a cui soddisfa il profilo di una membrana omogenea sottoposta ad una forza −f
è
−4u = f
dove 4 indica l’operatore di Laplace
L=
∂2
∂2
+
∂x 2 ∂y 2
Per applicare Freefem dobbiamo trasformare questo problema in forma variazionale. Ricordiamo la formula di Green: date due funzioni u, v regolari su un aperto U , si ha
−
Z
U
v 4u dx =
Z
U
∇ v∇ u −
Z
∂U
v h∇ u, nE i dσ
dove nE indica la normale esterna a ∂U e σ l’elemento di superficie di ∂U . A questa equazione
occorre aggiungere, se il caso, la condizione alla frontiera. Ad esempio u = 0 su ∂U se la
membrana è vincolata a stare fissa a zero al bordo. In generale il profilo al bordo sarà della
forma u = ψ su 01 ⊂ ∂U , dove ψ : R2 → R2 .
Se in una parte 0 ⊂ ∂U la membrana è lasciata libera, essa rimane però vincolata dalla
condizione h∇ u, nE i = 0, dovuta alla rigidità della membrana. Se u è vincolata su 01 ⊂ ∂U e
la forma variazionale del problema diventa
Z
U
∇ v ∇ u dx =
Z
f v dx
U
a cui bisognerà aggiungere le condizioni al bordo. Per vedere come si presentano le soluzioni
di questo problema cominciamo con il seguente.
Paolo Baldi
Corso di Laboratorio di Calcolo
Tor Vergata 2013-14
Paolo Baldi
Corso di Laboratorio di Calcolo
Tor Vergata 2013-14
130
Capitolo 6. Esempi Freefem
Esempio 6.1 Scrivere un codice Freefem per risolvere il problema della membrana sull’ellisse di equazione parametrica x = a cos θ, y = b sin θ, a = 2, b = 1, con una forza f = −1
(che spinge in su uniformemente) e con la condizione al bordo u = 0. Fare poi il grafico in
scilab.
Il codice Freefem di questo problema si trova in
www.mat.uniroma2.it\ ∼processi\membrana1.edp
Questo codice scrive i valori della funzione nei vertici della triangolazione nel file graphmembrane.txt. scilab non possiede un comando per fare il grafico 3D di una funzione
descritta mediante una triangolazione. Per farlo occorre usare un programmino che trovate in
www.mat.uniroma2.it\ ∼processi\disegno3d-triangolazione
Esempio 6.2 Facciamo pratica di Freefem sviluppando le seguenti variazioni del problema
della membrana:
a) Sempre U =l’ellisse, ma f (x, y) = x.
b) Ora U =il cerchio di raggio 1, f = −1 e condizione u = 0 al bordo solo sulla metà di
destra del bordo.
c) Ora U =il cerchio di raggio 1, f = −1 e condizione u = x al bordo.
d) Ora U =il quadrato [−1, 1] × [−1, 1], f = −1, condizione u = 0 sul bordo.
e) Ora U =il quadrato [−1, 1] × [−1, 1], f = −1, condizione u = 0 sulla metà della
frontiera con le ascisse positive.
L’operatore di Laplace appare anche nella conduzione del calore. Il problema
4u = 0
u|∂D = φ
su un dominio D
dà la distribuzione delle temperature all’equilibrio all’interno di un dominio D, quando la
temperatura al bordo è fissata uguale a φ(x) (x ∈ ∂D). Questo nell’ipotesi di un mezzo
omogeneo.
Esempio 6.3 a) Scrivere un codice Freefem che dia la distribuzione delle temperature
all’equilibrio nella corona circolare D = {.2 ≤ |x | ≤ 1}, con la temperatura imposta uguale a
0 sul bordo esterno e uguale a 1 su quello interno.
b) Stessa cosa ma con il cerchio interno spostato in maniera da avere il centro nel punto
(.3, 0).
c) Come in a) ma con un mezzo non omogeneo, quindi sostituendo il laplaciano con
l’operatore
∂2
∂2
L = σ2 2 + 2
∂x
∂y
con diversi valori di σ 2 (= 8 per cominciare). Ciò significa che la conduzione del calore è
maggiore (se σ 2 > 1) lungo l’asse x rispetto all’asse y.
d) Come in b), ma con un secondo cerchietto di raggio .1 centrato in (−.3, 0).
5.7 L’equazione del calore
131
Ricordare: il bordo deve sempre essere descritto nel verso che lascia il dominio a cui si è
interessati alla sinistra. Quindi il cerchio esterno va dato in senso antiorario, quelli interni in
senso orario. Per il quadrato occorrerà indicare i vari segmenti nell’ordine giusto.
Indice analitico
%e, 11
%f, 27
%i, 22
%pi, 11
%t, 27
acos, 18
asin, 18
atan, 18
bdiag, 21
cdfbet, 100
cdfbin, 100
cdfchi, 100
cdfchn, 100
cdffnc, 100
cdff, 100
cdfgam, 100
cdfnbn, 100
cdfpoi, 100
cdft, 100
champ, 78
clear, 15
cos, 18
cumprod, 18
cumsum, 18
deff, 30
evstr, 25
fchamp, 80
feval, 35
find, 34
format, 15
Paolo Baldi
Corso di Laboratorio di Calcolo
Tor Vergata 2013-14
for, 30
gsort, 19
histplot, 54
if, 33
imag, 20
intg, 85
linespec, 36
max, 7
mean, 28
min, 7, 17
ode, 77
plot, 11, 35
rand, 17
read, 25
real, 20
seed, 17
sin, 18
sort, 19
spec, 20
stacksize, 15
string, 25
tan, 18
timer, 31
while, 30
whos(), 15
who, 15
write, 26
xbasc, 12
xnumb, 73
xstring, 73
134
Capitolo 6. Esempi Freefem
autovalori, 20
matrice di covarianza, 50
coefficiente di correlazione, di due caratteri,
48
covarianza, di due caratteri, 48
parte immaginaria, 20
parte reale, 20
funzione di ripartizione
empirica, 101
Gibbs, fenomeno, 84
regola di Sturges, 54
retta di regressione, 48
Simpson, approssimazione, 92
Sturges,regola, 54