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