Tredicesima lezione

Calcolo degli integrali

Dopo la discussione fatta sulle equazioni differenziali, potrebbe sembrare una perdita di tempo discutere il calcolo degli integrali. Infatti sappiamo che il valore dell'integrale

è uguale al valore y(b) della soluzione di questa equazione differenziale:

per la quale sia posta la condizione iniziale y(a) = 0.

Di conseguenza, è perfettamente lecito calcolare il valore di un integrale utilizzando i metodi di risoluzione delle equazioni differenziali (il metodo di Runge-Kutta con controllo dinamico dell'incremento, che abbiamo imparato, oppure qualcuno dei metodi più sofisticati che si trovano sui libri o nelle librerie matematiche).

Questo caso relativamente più semplice presenta tuttavia (come sempre) qualche metodo di risoluzione "specializzato". Soprattutto il metodo di integrazione "Montecarlo", che vedremo, illustra una possibile applicazione di una delle tecniche più semplici e potenti dell'elaborazione numerica, sulla quale vale la pena di spendere qualche parola in più.
Ma iniziamo con ordine.

Il metodo del punto medio

Il primo metodo che può venire in mente, per calcolare l'integrale

è sperare che la funzione non vari troppo nell'intervallo [a,b], e considerarla costante, con un valore pari a quello nel punto medio. In questo caso la prima approssimazione per il valore dell'integrale è:

L'errore che si commette possiamo valutarlo considerando lo sviluppo in serie della funzione attorno al punto medio (usiamo per maggior chiarezza il resto di Lagrange):

Si può fare di meglio, dividendo l'intervallo in N sottointervalli, ed utilizzando i rispettivi punti medi. In questo modo il valore dell'integrale si approssima con l'area del trapezoide risultante:

Ecco il valore dell'integrale calcolato con questa procedura:

Volendo raffinare ulteriormente le cose, possiamo calcolare il valore dell'integrale ad ordini di accuratezza maggiori; potremmo ancora (ma non lo facciamo) combinare i risultati con opportuni coefficienti che annullino esattamente i corrispondenti termini dello sviluppo in serie. E' possibile anche estrapolare il risultato per un numero di elementi del trapezoide tendente all'infinito, utilizzando (come avevamo mostrato nel caso delle derivate) un metodo di estrapolazione polinomiale. Per l'algoritmo risultante (integrazione di Romberg) ecco di nuovo una implementazione dell'algoritmo da Numerical Recipes in C/C++: romberg.cpp.

Integrazione Montecarlo

Come abbiamo visto, c'è un vasto ventaglio di possibilità, ed una lunghissima storia, riguardo all'integrazione delle funzioni di una variabile. Di per sé non avremmo dunque bisogno di sapere altro, se non fosse per il fatto che il problema può diventare molto più complicato, per esempio quando le dimensioni aumentano. Uno dei possibili metodi (probabilmente il più semplice) per calcolare numericamente integrali in più dimensioni, è il metodo Montecarlo. Vediamo brevemente di cosa si tratta nel caso ad una dimensione:

Supponiamo di individuare un rettangolo che contiene la funzione da integrare nell'intervallo scelto (attenzione a non "tagliare" la funzione: occorre saper valutare bene massimi e minimi). A questo punto scegliamo un certo numero di punti a caso all'interno del rettangolo, e contiamo quanti si trovano sopra, e quanti sotto la funzione. L'integrale cercato è dato dall'area del rettangolo (che conosciamo) moltiplicata per la frazione di punti contati sotto la funzione. Se i numeri casuali che utilizziamo sono casuali per davvero, possiamo andare avanti ad estrarre numeri fino a misurare l'integrale alla precisione della macchina.

Vediamo in questo come calcolare il volume di una calotta sferica con il metodo Montecarlo. L'indeterminazione che grava sulla misura del volume è regolata dalla distribuzione binomiale. La distribuzione binomiale infatti descrive la probabilità di avere n "successi" in N "prove" quando si sollecita un processo caratterizzato dalla probabilità p per un singolo successo:

Non lo dimostriamo, ma la migliore stima del valore di p ottenuta, come nel nostro caso, dal conteggio del numero di successi e di prove totali (la misura del volume è infatti p moltiplicata per il volume totale) è:

e la corrispondente indeterminazione è:

Dal programma di esempio risulta abbastanza immediato come la semplicità di impostazione del metodo si paghi con un costo computazionale piuttosto rilevante. Ovviamente, infatti, sappiamo come calcolare meglio il volume di un solido di rotazione come la calotta sferica.

Esistono tuttavia casi per i quali la complessità del fenomeno o della struttura in esame lascia come unica via d'uscita l'utilizzo di questo sistema che permette di ottenere la precisione desiderata, a patto di possedere una potenza di calcolo (o una quantità di pazienza) sufficiente.

Altre applicazioni del metodo Montecarlo

La strategia di eseguire calcoli utilizzando valori casuali si applica ovviamente bene alla simulazione di qualunque fenomeno che possa essere predetto solo in maniera statistica. Conoscendo la distribuzione di probabilità di un certo fenomeno, è possibile "pescare" numeri casuali che seguano la distribuzione stessa, usando un metodo molto semplice e simile a quello utilizzato per l'integrazione.
Questo mostra come si possono pescare numeri che seguono una distribuzione gaussiana centrata sullo zero:

Questo metodo di generare numeri casuali che seguono una distribuzione si chiama metodo di reiezione, e si dimostra tanto più inefficiente quanto più è grande l'area utilizzata per racchiudere la distribuzione di probabilità che ci interessa (le scelte di numeri "inutili" avverranno con una probabilità proporzionale alla differenza fra tale area e quella sottesa dalla distribuzione).

Vale la pena di notare, per completezza, che esiste un altro metodo (analitico) di generare numeri casuali che seguono una distribuzione, a partire da una distribuzione di numeri casuali "piatta". Tale metodo richiede però di sapere come trovare una primitiva della distribuzione desiderata e come invertirla. Con questo metodo (detto metodo di trasformazione) si possono generare distribuzioni esponenziali, ed anche gaussiane (utilizzando uno stratagemma in due dimensioni). E' quindi quest'ultimo metodo che viene implementato nelle librerie matematiche.

Il metodo Montecarlo si può applicare anche quando non si conosce la distribuzione di probabilità del fenomeno che si desidera simulare. E' possibile infatti operare una scelta casuale fra un campione ben costruito di precedenti incarnazioni del fenomeno (per esempio provenienti da misure sperimentali).

Ma perché porre tanta importanza a metodi di simulazione su computer? La fisica non si basa su misure sperimentali?

Vero, ma nel caso di apparati sperimentali particolarmente complessi, non è possibile "eliminare" nell'apparato le fonti di errore sistematico, ed occorre in qualche modo fattorizzare la risposta dell'apparato e valutare la dipendenza della misura dalle scelte fatte durante la misura stessa. Questa è la codiddetta "misura dell'errore sistematico", e la simulazione al calcolatore dell'apparato sperimentale, fatta con metodi Montecarlo, riveste in questo caso importanza fondamentale.

Esercizio: provare a convertire in un metodo di uso generale la procedura che estrae n numeri casuali "secondo una distribuzione". La definizione della classe corrispondente potrebbe essere:

#include <functional>

template <typename DT>
class DistributedNumbers
{
  public:
    typedef DT value_type;
    typedef DT (*function_ptr_type)(DT); // Normal - nonmember function pointer
    typedef std::function<DT (DT arg)> functor_type;

    // Creator
    DistributedNumbers(functor_type &f);
    DistributedNumbers(function_ptr_type f);

    // Destructor
    ~DistributedNumbers();

    DT get_next_number();
}