F - Dipartimento di Scienze Chimiche, della Vita e della Sostenibilità
Transcript
F - Dipartimento di Scienze Chimiche, della Vita e della Sostenibilità
SVILUPPO DI UN MODELLO DI SIMULAZIONE ABBINATO A UN ALGORITMO QUALITATIVO PER LO STUDIO DEI SISTEMI AMBIENTALI COMPLESSI di Stefano Allesina Tesi presentata per la discussione del diploma di laurea in Scienze Ambientali Facoltà di Scienze Matematiche, Fisiche e Naturali – Università di Parma AA 1999-2000 Relatore: dott. Alessandro Zaccagnini Dipartimento di Matematica Co-Relatore: dott. Antonio Bodini Dipartimento di Scienze Ambientali Abstract SVILUPPO DI UN MODELLO DI SIMULAZIONE ABBINATO A UN ALGORITMO QUALITATIVO PER LO STUDIO DEI SISTEMI AMBIENTALI COMPLESSI di Stefano Allesina Relatore: Dottor Alessandro Zaccagnini Dipartimento di Matematica Co-Relatore: Dottor Antonio Bodini Dipartimento di Scienze Ambientali La tesi si occupa dei metodi informatici e matematici della Loop Analysis, una metodologia per lo studio qualitativo dei sistemi lineari o linearizzabili di equazioni differenziali. Questi sistemi sono importanti nello studio degli ecosistemi e nella valutazione dell'impatto dell'uomo sugli ambienti naturali, in quanto i rapporti tra popolazioni, e tra gli altri fattori biotici, abiotici, culturali e sociali, si possono modellizzare in un sistema di variabili che intrattengono relazioni di indifferenza, competizione, mutualismo, ecc. La Loop Analysis si occupa proprio del segno di queste interazioni, studiando la cosiddetta matrice di comunità, ovvero la matrice Jacobiana, valutata in un punto stazionario, del sistema linearizzato. In realtà, non viene studiata direttamente la matrice, ma le proprietà del grafo orientato che si può univocamente associare alla matrice, individuando cioè i vari percorsi (paths) e cicli (loop) del grafo. Da queste proprietà è possibile valutare la stabilità del sistema, anche se formato da un cospicuo numero di variabili, e fare predizioni sul mutamento dei valori di equilibrio delle variabili in caso di input esterni. Il lavoro si è concretizzato in tre software che sono in grado di creare le matrici e i grafi, fare la Loop Analysis e infine eseguire una simulazione sui vari percorsi. L'utilizzo della simulazione ha lo scopo di individuare il segno prevalente dei cosiddetti percorsi ambigui, ossia i percorsi del grafo che partono da una variabile e arrivano a un'altra dando risultati di segno opposto. Il programma compie questa operazione assegnando, dopo averli normalizzati, valori casuali ai coefficienti della matrice (links del grafo) e calcolando poi la forza dei percorsi. Reiterando questa procedura più volte si ottengono stime approssimate della "probabilità" dei due segni, chiarendo molte delle ambiguità. Inoltre, i tre programmi permettono di analizzare sistemi con un consistente numero di variabili (30), poiché i dati in output sono memorizzati in tabelle di databases e quindi di facile accesso e molto capienti. Questa scelta si è resa necessaria perché il numero di percorsi, e quindi la complessità algoritmica, sale più che esponenzialmente con l'aumentare delle variabili. Un aspetto peculiare di questo studio consiste nella sinergia di due diverse e apparentemente inconciliabili metodologie di analisi: quella qualitativa (Loop Analysis) e quella quantitativa (simulazione). SOMMARIO Capitolo 1 – INTRODUZIONE ....................................................................................1 I modelli matematici: definizioni.........................................................................................2 Modellizzare i sistemi complessi .........................................................................................4 Capitolo 2 - LA LOOP ANALYSIS ...............................................................................6 1. Definizioni.................................................................................................................7 Feedback ............................................................................................................................... 11 Stabilità .................................................................................................................................. 12 Fare predizioni ..................................................................................................................... 14 Le tavole di predizione ....................................................................................................... 15 Capitolo 3 - METODI MATEMATICI DELLA LOOP ANALYSIS .................19 2. Stabilità in Tempi discreti .................................................................................... 20 Le equazioni viste da vicino .............................................................................................. 23 Matrice Jacobiana, autovalori e stabilità.......................................................................... 26 Self-loop................................................................................................................................ 30 Stabilità in più variabili ....................................................................................................... 32 Un esempio .......................................................................................................................... 38 Cambiamento nei valori di equilibrio .............................................................................. 40 Capitolo 4 - LE AMBIGUITA’......................................................................................44 3. Percorsi di segno opposto................................................................................... 44 Ambiguità nel segno di un path o di un loop ................................................................ 46 Il “Lumping” delle variabili .............................................................................................. 47 Simulare................................................................................................................................. 50 Capitolo 5 - TEORIA DEI GRAFI..............................................................................52 4. Rappresentazione e definizioni .......................................................................... 52 Quanti loops?....................................................................................................................... 53 Rappresentazione informatica dei grafi........................................................................... 57 Capitolo 6 – ALGORITMI.............................................................................................59 5. Trovare gli Open Path ......................................................................................... 61 Trovare i loop ...................................................................................................................... 63 Trovare i Feedbacks............................................................................................................ 65 Tavole di predizione ........................................................................................................... 68 Simulare i percorsi ambigui ............................................................................................... 69 Capitolo 7 – RISULTATI................................................................................................72 6. Prestazioni .............................................................................................................. 74 Risolvere tutte le ambiguità?.............................................................................................. 75 BIBLIOGRAFIA ..................................................................................................................................... 79 ii Capitolo 1 INTRODUZIONE “Di ciò, di cui non si può parlare, si deve tacere” L. Wittgenstein – Tractatus Logico-Philosophicus Negli ultimi decenni, si è manifestato un crescente interesse verso la complessità, interesse esplicitatosi in due modi differenti. Da una parte si sono individuate nuove interazioni tra compartimenti che erano sempre stati considerati “stagni”, cioè si sono trovate evidenze sperimentali di sistemi complessi. Dall’altra, con la possibilità di trattare enormi quantità di dati offerta dall’informatica, ci si è spinti verso modelli che comprendono più variabili e parametri: è aumentata la complessità “ideale” dei modelli. Tra i sistemi complessi, hanno acquistato una sempre crescente rilevanza e attualità i sistemi ambientali, che sono caratterizzati da una elevata complessità strutturale - basta pensare alle cosiddette proprietà emergenti - e che hanno richiesto un grande sforzo di analisi e la creazione di appositi strumenti di modellizzazione. Il desiderio di riuscire a maneggiare sistemi complessi non risponde solo a un’esigenza teorico-speculativa, ma anche a richieste sempre più pressanti della società, a fronte degli enormi danni arrecati al patrimonio ambientale anche a causa dell’insufficiente grado di comprensione dei fenomeni naturali. Sono recenti le normative comunitarie per la valutazione di impatto ambientale (85/337/CEE del 27 giugno 1985 e 97/11/CE del 3 marzo 1997), valutazione che non può prescindere da una corretta e completa analisi dei sistemi ecologici, i cui comportamenti possono essere previsti solo mediante l’utilizzo di modelli. Questo lavoro tratta di modelli qualitativi, cioè di modelli che non si basano sulla quantificazione di parametri e valori, ma sul rapporto che intercorre tra le variabili del sistema. Ci si potrebbe chiedere quale sia l’utilità di un’analisi apparentemente così approssimativa quando esistono computer, potenti ed economici, in grado di eseguire calcoli a velocità elevatissime. Si possono trovare almeno due ragioni per l’utilizzo di modelli qualitativi: 1. I metodi qualitativi riescono ad analizzare sistemi complessi senza un’eccessiva spesa di tempo e denaro; 2. I modelli qualitativi sono essenziali come elaborazione a monte di una modellizzazione quantitativa. La prima tesi è semplice da comprendere: se, con l’utilizzo di equazioni differenziali, è possibile descrivere il comportamento di sistemi in 2-3 variabili entro un certo grado di approssimazione, risolvere un sistema di 10 equazioni è impresa molto più ardua, anche sfruttando metodi di calcolo numerico approssimato. Se poi si considerano variabili biologiche, spesso legate a parametri o funzioni difficilmente stimabili, come quelli sociali, economici e legislativi, la quantificazione può diventare uno strumento paradossalmente meno potente: la difficoltà nella formalizzazione delle funzioni e nella stima dei valori dei parametri, unita ai limiti di applicabilità degli strumenti matematici, è tale da rendere i risultati decisamente lontani dalla generalità e dalla precisione a cui le equazioni ci hanno abituato. La seconda tesi non riguarda direttamente la realtà, ma la concettualizzazione che porta alla costruzione del modello. “I modelli sono strutture concettuali che studiamo per non dover studiare la realtà” (Puccia e Levins, 1985), e per comprendere effettivamente la generalità di un modello, e soprattutto la sua verosimiglianza (realismo), è utile disporre di uno strumento che valuti velocemente queste caratteristiche. Quando si costruisce un modello, è fondamentale aver chiaro come le variabili interagiscano tra loro, e come si comporti il sistema nell’eventualità dell’aggiunta o eliminazione di una variabile, o operazioni svolte sui 2 coefficienti delle equazioni. La Loop Analysis, la metodologia qualitativa di cui si occupa questa tesi, permette questa modellizzazione per raffinamenti successivi, e consente di confrontare velocemente diverse ipotesi di modello per uno stesso sistema. 1. I modelli matematici: definizioni Un modello è una rappresentazione della realtà, perciò la sua caratteristica fondamentale dovrebbe essere il realismo, la capacità di rispondere agli stimoli esattamente come il sistema reale. Inoltre, dato che la sua principale funzione è di predire il comportamento del sistema reale, deve dare risposte precise. Un'altra caratteristica auspicabile è quella di essere generale, cioè direttamente applicabile ad altri casi simili: in sostanza non deve essere una soluzione ad hoc. Purtroppo queste tre caratteristiche (generalità, precisione, realismo) non possono essere massimizzate contemporaneamente. Si dovrà quindi operare un trade-off tra le varie priorità, secondo gli obiettivi della ricerca (Levins 1966). Si prospettano tre casi: Realismo Generalità Precisione Fig. 1 Quando si massimizzano generalità e realismo a scapito della precisione (Settore 1), come nel caso della Loop Analysis e delle altre metodologie qualitative, si ottiene un risultato poco preciso, proprio perché non quantitativo. A fronte di questa perdita, si riescono a studiare modelli 3 complessi (realismo), facilmente trasferibili ad altre situazioni simili (generalità). Se si privilegiano precisione e realismo (Settore 2), come avviene in molti modelli di simulazione al computer, è necessario inserire grandi quantità di parametri, misurati di volta in volta. Inoltre questi modelli richiedono una complessa procedura di calibrazione-adattamento per poter essere applicati a situazioni anche molto simili (De Angelis e Gross, 1992). Le metodologie che ricadono nel Settore 3 sono forse quelle più diffuse, poiché a questo caso sono ascrivibili quasi tutti i modelli matematici per la biologia. A fronte di una complessità difficilmente traducibile in set di equazioni, si adottano drastiche semplificazioni, ottenendo soluzioni che, per quanto applicabili a uno stretto range di situazioni, hanno il rigore e la precisione tipiche delle scienze pure. La chiarezza ed eleganza delle equazioni permette di trasportarle direttamente in campi di applicazione anche “non contigui”: ad esempio tutti i modelli per la biologia trovano prima o poi applicazione nelle scienze economiche, e viceversa (un esempio emblematico è la figura di Malthus). Si può fare un’ulteriore distinzione fra le tecniche modellistiche, quella fra modelli deterministici e modelli probabilistici. La Loop Analysis è una metodologia deterministica: lo stesso sistema dà sempre e comunque gli stessi risultati. Una simulazione è di impronta probabilistica: ad ogni reiterazione del calcolo esiste la possibilità di ottenere un risultato diverso dal precedente. In questo lavoro di tesi la simulazione viene utilizzata per integrare la capacità predittiva della Loop Analysis, e quindi si fondono le due classi di modelli per ottenere il risultato. 4 2. Modellizzare i sistemi complessi Il problema fondamentale dell’analisi dei sistemi biologici è riuscire a tenere conto delle forti interdipendenze che si hanno tra le diverse componenti. Infatti i sistemi naturali sono composti da specie che interagiscono tra loro, ma anche da una teoria di fattori fisici, chimici, economici e sociali, i cui effetti sono difficilmente quantificabili e variabili nel tempo. Le specie non possono essere studiate in isolamento le une dalle altre, se non accettando una perdita di informazione spesso critica. Non si riesce cioè a creare quell’uniformità di comportamenti e risposte che caratterizza i sistemi più semplici, che possono essere “controllati”. Il comportamento del sistema spesso non dipende dalla forza (valore assoluto) dei legami tra le componenti, ma dalla struttura del sistema stesso. Due laghi aventi la stessa struttura trofica potranno avere un comportamento molto simile. Al contrario, si possono riscontrare risposte molto diverse a una stessa sollecitazione in laghi che abbiano identici valori per parametri come temperatura, altitudine, precipitazioni, … Inoltre, i problemi che riguardano l’ecologia implicano spesso una componente sociale, i cui effetti sono difficili da valutare. L’analisi qualitativa permette di superare questo scoglio, dato che non richiede una quantificazione, ma semplicemente la descrizione delle relazioni che intercorrono fra le variabili. L’accento viene posto sulla struttura del modello e lo stesso sistema può essere descritto da diverse strutture alternative, tutte ugualmente accettabili: è il confronto con l’osservazione sperimentale che seleziona quale, tra le metaipotesi proposte (modelli), risulta essere la più attendibile. Spesso però, per la rappresentazione dei fenomeni e la loro comunicazione al pubblico, si utilizzano metodi che apparentemente danno risultati più spendibili, ossia valori numerici, grafici, tabelle, anche se le semplificazioni necessarie per ottenerli hanno fortemente intaccato 5 l’attendibilità del modello di riferimento. Parafrasando Wittgenstein, si potrebbe essere tentati di affermare “Di ciò che non si può quantificare, si deve tacere”. La speranza è che questo lavoro contribuisca a sfatare questo luogo comune. 6 Capitolo 2 LOOP ANALYSIS “Fare previsioni è sempre difficile, soprattutto sul futuro.” Niels Bohr La Loop Analysis è una metodologia matematica che utilizza esclusivamente informazioni sui rapporti qualitativi tra le variabili, per descrivere il comportamento di un sistema e prevederne l’evoluzione sotto la spinta di input endogeni ed esogeni. Il suo sviluppo in campo ecologico e ambientale si deve a Levins (1974, 1975) e Puccia (Puccia e Levins, 1985) su basi che si erano venute formando fin dagli anni ‘50 per le applicazioni di robotica e elettrotecnica (Mason, 1953, 1956). Punto di partenza della metodologia è un sistema lineare o linearizzabile (che soddisfa cioè una serie di condizioni particolari) di equazioni differenziali. Queste operazioni descrivono l’evoluzione temporale delle componenti (variabili) di un sistema biologico in funzione della presenza di altre variabili e di parametri dinamici, assunti come costanti. Le equazioni che compongono il sistema possono quindi essere descritte mediante la forma generale dX i = f i (X 1 , X 2 , X n ; c1 , c2 , ck ) dt in cui l’evoluzione temporale di Xi dipende da n variabili e k parametri dinamici. I metodi matematici che sono alla base della Loop Analysis sono analizzati nel capitolo 3, ma si possono fare alcune osservazioni a prescindere dalla forma delle equazioni. Vi sono n equazioni e n variabili, quindi il sistema ammette soluzione. Annullando le derivate si ottengono i punti stazionari, o punti di equilibrio. Nell’intorno di un punto di equilibrio un sistema linearizzabile ha lo stesso comportamento qualitativo del sistema linearizzato. 7 Questo comportamento si può descrivere attraverso una matrice. La Loop Analysis utilizza solo i segni dei coefficienti di questa matrice per prevedere l’evoluzione del sistema sotto la spinta di agenti esterni. Questa matrice si può associare univocamente ad un grafo orientato (digraph), e sarà proprio dalle proprietà del grafo che si riusciranno a ottenere informazioni sul sistema. Nei prossimi paragrafi viene analizzato il modo di rappresentare i sistemi dinamici (§§ 1, 2, 3) e di ottenere previsioni qualitative (§§4, 5). 1. Definizioni Matrice di comunità: E’ una matrice NxN (dove N è il numero di variabili del sistema). Ogni elemento della matrice appartiene all’insieme {0;+α; −α} e rappresenta il segno del relativo coefficiente nella matrice Jacobiana del sistema linearizzato. Ad ogni matrice è associabile univocamente un grafo orientato, che utilizza per i legami una diversa simbologia a seconda che rappresenti un coefficiente positivo o negativo. Se il segno del coefficiente è “+”, allora il legame (link) finirà con una freccia, mentre se il segno del coefficiente è “−” il link finirà con un pallino. Definiremo questi link positivo e negativo rispettivamente. Ovviamente non è presente nessun legame se il coefficiente è 0. Si consideri ad esempio la seguente matrice di comunità: − α AA CM = − α AB α 0 BA in cui ciascun coefficiente αXY significa “legame tra Y (partenza) e X (arrivo)”, ha il corrispettivo nel grafo: 8 A B Questo esempio è la rappresentazione grafica di un sistema preda-predatore con A preda e B predatore. Si può subito individuare il rapporto qualitativo per due variabili: - A influenza positivamente B (se ci sono più prede, i predatori hanno maggiori disponibilità di cibo), - B influenza negativamente A (se ci sono più predatori, la pressione sulla popolazione della preda è maggiore). Il legame da A su A viene chiamato self-link e illustra un comportamento complesso, descritto più ampiamente nel Capitolo 3. Per ora è sufficiente sapere che una variabile con un self-link negativo (es. -αAA) si dice autoregolata in quanto limita l’espressione della sua stessa crescita, mentre un coefficiente positivo (self-enhancing) è rappresentativo di un effetto autostimolante. Nella modellizzazione di sistemi naturali, la presenza di un legame di autocontrollo può essere associata a fenomeni di emigrazione (legame positivo) o immigrazione (legame negativo), oppure descrivere l’apporto continuo dall’esterno del sistema a una variabile che non si autoriproduce (es. negli ecosistemi i nutrienti sono sempre self-damped). I self-effects non si manifestano quando la crescita dipende dall’abbondanza (rimane invariato il tasso), o quando tutte le variabili che influenzano la crescita sono presenti nel sistema. Nella Loop Analysis ogni coefficiente della matrice di comunità (e quindi ogni legame) viene indicato dal segno del coefficiente (− o +), seguito da una lettera dell’alfabeto greco o latino con due lettere in pedice: la variabile di arrivo del link (corrispondente alla colonna della matrice) e la variabile di partenza (riga della matrice). 9 Riprendendo il grafo preda predatore illustrato sopra, il link dalla preda al predatore si indica con αBA, quello dal predatore alla preda con -αAB, mentre il self-link della preda con -αAA. Per estensione di questi concetti, si arriva a stabilire che due legami positivi rappresentano un rapporto di reciproco beneficio tra due variabili, mentre due specie in competizione vengono rappresentate mediante due legami negativi. Open Path: Si definisce open path, o percorso aperto, un qualsiasi percorso che vada da una variabile ad un'altra senza passare due volte per la stessa variabile. Ogni percorso è quindi costituito da una serie di link distinti. Loop: Si definisce loop, o circuito, un qualsiasi percorso che va da una variabile a se stessa, senza passare due volte per variabili intermedie. Un loop è simile a un path, ma la variabile di partenza e quella di arrivo coincidono. Quindi il percorso è chiuso. Da ciò segue che anche il self-link di per sé costituisce un circuito o loop. I circuiti possono essere raggruppati in livelli in funzione del numero di variabili che essi connettono. Tornando all’esempio predapredatore, si nota che è presente un loop di livello 1 (da A ad A, che verrà indicato con [A]), e uno di livello 2 (da A a B, da B ad A, che verrà indicato con [AB]). Per estensione si può definire “path di livello (o lunghezza) n” un percorso che coinvolge n variabili; nel caso di tre variabili, la notazione che da qui in avanti verrà utilizzata per la sua identificazione è del tipo ]ABC[. Si noti che un loop di livello n è formato da n links, mentre un open path dello stesso livello è formato da n-1 links. 10 Loop congiunti e disgiunti: Due loop si dicono congiunti quando hanno almeno una variabile in comune, viceversa si dicono disgiunti. I loop disgiunti sono particolarmente interessanti perché consentono di analizzare il concetto di feedback (cfr. § 2). A qualsiasi circuito disgiunto, infatti, è associato un effetto feedback le cui caratteristiche sono individuate dalla tipologia dei legami che costituiscono il circuito. Di seguito utilizzando come esempio un semplice sistema ecologico, vengono illustrati i concetti fin qui descritti. Sia dato un sistema di tre variabili con le seguenti specifiche: X1: Pianta Coltivata X2: Pianta Infestante X3: Insetto Erbivoro X1 X2 X3 X1 e X2 sono in competizione per lo spazio e per i nutrienti ed entrambe sono autoregolate. L’erbivoro si nutre di X2, ma non di X1, e non è autoregolato, in quanto la sua numerosità dipende esclusivamente dalla quantità di cibo, ed è regolata dal naturale tasso di mortalità. La Matrice di Comunità diventa perciò: − α X1 X1 CM = −α X X 1 2 0 α −α −α X 2 X1 11 X2X2 X 2X3 X3X 2 0 α 0 All’interno del grafo possono essere identificati loop appartenenti a livelli diversi: Di livello 1: X1 (indicato con [X1]), di segno − X2 (indicato con [X2]), di segno − Di livello 2: X1 X2 [X1 X2], di segno + , dato che per trovare il segno di un loop si devono moltiplicare i segni dei legami, X2 [X2 X3] X3 − Di livello 3: Non esistono circuiti che uniscono contemporaneamente tre variabili, per cui si dovrà ricorrere alla combinazione di loop disgiunti di livello inferiore per individuare i circuiti appartenenti a questo livello. Si identificano i seguenti Open Paths: Di lunghezza 1: X1 X2 ] X1 X2 [ 12 + X1 X2 ] X2 X1 [ − … Di lunghezza 2: X1 X2 X3 X1 X2 X3 ] X1 X2 X3 [ − ] X3 X2 X1 [ + 2 . Feedback Il termine “feedback”, o retroazione, viene utilizzato per descrivere situazioni nelle quali un’azione o un’attività iniziata da un agente su un sistema si manifesta con un effetto di ritorno sullo stesso agente dopo un numero finito di passaggi. Si individuano due tipologie di feedback: Feedback positivo: un’alterazione imposta a una variabile porta a una risposta del sistema tale da produrre un’amplificazione degli effetti della variazione. Sono esempi di feedback positivo le reazioni “a catena”, il “circolo vizioso”, ecc… Feedback negativo: si ha quando un’alterazione imposta a una variabile attiva nel sistema una risposta tesa a smorzare gli effetti dell’alterazione. Sono esempi di feedback negativo l’oscillazione smorzata, i meccanismi omeostatici che sono alla base del metabolismo, ecc… In un grafo orientato il segno dei feedback associati ai circuiti si ricava, in linea di principio, moltiplicando i segni dei legami costituenti il loop, con un fattore moltiplicativo aggiuntivo che dipende dal numero di circuiti coinvolti nel feedback. Di ciò sarà data spiegazione dettagliata in seguito. 13 In ciascun sistema possono essere identificati diversi livelli di feedback. Ciò si deve al fatto che questi effetti sono sempre associati alla presenza di circuiti (loop) e, pertanto, si utilizzano le stesse modalità di classificazione che valgono per questi ultimi. Si definisce “feedback di livello 1” (o F1) di un sistema l’insieme di tutti i feedback prodotti da circuiti appartenenti al livello 1 (i self-loop). Per i feedback di livello più alto, si devono individuare tutti i loop appartenenti a quel livello e le combinazioni di loop disgiunti di livello più basso. La rappresentazione formale dei livelli di feedback è data dalla formula seguente: F k k = ∑ (−1) m +1 L (m, k ) m =1 Dove Fk è il feedback di livello k, mentre il termine L(m,k) raggruppa m loop disgiunti con k elementi. Così L(1,5) identifica un unico loop che raggruppa cinque variabili, mentre L(2,5) descrive una situazione in cui le cinque variabili sono suddivise tra due circuiti disgiunti. In ogni caso, il numero di variabili è quello che definisce il livello di feedback. (−1) m +1 è il fattore moltiplicativo che determina il segno del feedback. Se il numero dei loop disgiunti (m) è pari, il segno ottenuto moltiplicando i legami va invertito. La giustificazione di questa semplice regola si ottiene dallo studio del determinante della matrice di comunità, e verrà illustrata nel Capitolo 3. Un’altra equazione viene introdotta per la coerenza matematica dell’analisi, affermando che il feedback di livello 0 vale –1. F 0 ≡ −1 Il feedback di livello massimo di un sistema di n variabili si dice overall feedback ed è formato da tutti i loop di livello n. 14 3. Stabilità Per lo studio dei sistemi biologici è importante determinare se il sistema è stabile. In caso affermativo, se si verifica una perturbazione nel sistema, esso tende a tornare nello stato originario. Se il sistema è instabile, al contrario, anche una piccola alterazione imposta al sistema lo farà allontanare irreversibilmente dal suo stato di equilibrio. Ciò può comportare la riorganizzazione del sistema in relazione al tipo e numero delle componenti. Si può dunque intuire che esiste un rapporto tra stabilità e feedback negativi, da un lato, e tra feedback positivi e instabilità, dall’altro. Infatti, il primo criterio di stabilità per un sistema afferma che devono essere negativi i feedback di ogni livello. Ovvero: F i <0 ∀i La seconda condizione per la stabilità riguarda la forza dei feedback rispetto alla loro lunghezza. E’ infatti importante che i feedback di alto livello non siano più forti di quelli di basso livello. Intuitivamente si può capire che più un percorso è lungo, più lenta sarà la risposta. Percorsi con un grande ritardo potrebbero avere un effetto destabilizzante se avessero forza sufficientemente alta. Un caso pratico può spiegare la situazione: K. compila la dichiarazione dei redditi, e scopre, con sua grande sorpresa, di dovere al fisco solo 1.000.000 £, invece che 5.000.000, come si aspettava. Attende un mese per essere sicuro, poi decide di concedersi un viaggio ai tropici, dato che ha appena finito la tesi ed è un po’ stanco. Tornato a casa con una splendida abbronzatura, trova una raccomandata che gli ingiunge di pagare immediatamente al fisco 4.000.000. Il meccanismo omeostatico di correzione degli errori del fisco è troppo forte rispetto ai feedback più corti che regolano le spese di K. Così, se la notifica dell’errore fosse avvenuta immediatamente, non avrebbe sortito effetti, ma essendo affidata ad un feedback di alto livello, ha un effetto destabilizzante. 15 Tornando al secondo criterio di stabilità, per un sistema di tre variabili l’equazione diventa: F F +F 1 2 3 >0 Ricordando che per il primo criterio di stabilità tutti i feedback sono negativi, l’equazione afferma che |F1F2|>|F3|. La formula generale, basata sul teorema di Routh-Hurwitz, diviene più complicata al crescere del numero di variabili e sarà introdotta nel Capitolo 3. 4. Fare predizioni Una volta acquisiti i rudimenti della rappresentazione grafica e del calcolo della stabilità dei sistemi, è possibile introdurre la problematica dell’utilizzo dei grafi orientati, per formulare previsioni sul comportamento dei sistemi sottoposti a sollecitazioni. Vengono considerate tali quelle alterazioni che determinano un cambiamento permanente nel valore di uno o più parametri che governano le equazioni dinamiche per le variabili del sistema. Un tale tipo di alterazione viene definito input. Si possono considerare input positivi e input negativi: i primi sono quelli che determinano un aumento della velocità di crescita delle variabili; i secondi agiscono in modo esattamente opposto. Quando un input agisce su una variabile si possono avere ripercussioni al di là del bersaglio della perturbazione, per effetto dei legami che quest’ultimo contrae con le altre componenti del sistema. Scopo dell’analisi è quello di prevedere se le variabili del sistema siano attese in aumento o in diminuzione a seguito di un input. Nella metodologia della Loop Analysis questo è possibile studiando le proprietà del grafo. Prima di enunciare l’algoritmo che risponde a questo quesito, è necessario introdurre un nuovo concetto: complementare. 16 quello di sottosistema Il Complementary Subsystem A partire dalla definizione di Open Path, si introduce per coerenza: p (k ) ii ≡ p (1) ii ≡ p (0) ii ≡1 che definisce in modo univoco un percorso che collega una variabile con se stessa. A ciascun open path è possibile associare un sottosistema complementare (Complementary Subsystem), ovvero il sistema formato da tutte le variabili che non partecipano al path e dalle loro connessioni. Il Complementary Subsystem di un Open Path di livello k sarà composto da n-k variabili se in numero totale di variabili è n. Dopo aver definito il feedback di livello n per il sistema, è possibile estendere questo concetto al Complementary Subsystem, indicandolo come il feedback di livello n-k dell’intero sottosistema. F ( comp ) n−k Esempio Riprendendo l’esempio precedentemente introdotto: X1 X2 X3 Si possono individuare alcuni paths e i loro relativi sottosistemi complementari: OPEN PATH COMPLEMENTARY SUBSYSTEM X1 X2 p X3 ( 2) 2←1 ]X1 X2[ 17 [ ] F ( comp) 3− 2 ( comp) = F1 =0 X1 p ( 3) p (1) 3←1 2← 2 X2 X3 [None] F (1) 3← 3 =1 (1) 3← 3 = per definizione F X1 =1 =1 ( comp) 3−1 per definizione ( comp ) 0 e = −1 ( comp) = F2 X3 = (−α 22 ) ⋅ (0) = 0 X1 F p 3−3 ]X1 X2 X3[ F p ( comp ) ( comp) 3−1 per definizione X2 ( comp) = F2 = (α 21 ) ⋅ (−α12 ) = (−) X1 F ( comp) 3−1 ( comp) = F2 X2 = (−α11 ) ⋅ (−α 22 ) ⋅ (−1) = (−) qui si moltiplica per –1 perché ci sono un numero pari di loop disgiunti Scopo dell’analisi è prevedere, ad esempio, come si comporta il sistema quando viene utilizzato un erbicida per limitare la crescita di infestanti. Questo può essere modellizzato come un input negativo su X2, e nel prossimo paragrafo si vedrà quali effetti ha l’erbicida sul sistema. 5. Le Tavole di predizione Per capire l’effetto sui valori di equilibrio delle variabili causato da un input esterno, bisogna innanzitutto individuare quali parametri sono colpiti dall’input e quale è la “direzione di cambiamento”, ovvero il segno dell’input: positivo, se la variabile colpita aumenta il tasso di crescita; negativo, se questo diminuisce. Matematicamente ciò equivale a chiedersi se la derivata parziale della funzione che descrive il comportamento della variabile i (sottoposta all’input), rispetto al cambiamento del parametro c (effetto dell’input) è positiva, negativa o nulla. 18 @f i @c <0 @f i @c @f i @c =0 >0 Per prevedere il nuovo valore di equilibrio della variabile Xj, dovuto al cambiamento del parametro c nella dinamica di Xi (c può comunque essere presente nelle equazioni di più variabili), si utilizza la formula: ∂X * j ∂c ∂ f i (k ) ( comp ) p ji F n−k ∑ i ,k ∂ c = ( F ) n Dove * significa che ad X va sostituito il valore della variabile all’equilibrio; I termini della sommatoria rappresentano: ∂ f i ∂c Æ Segno dell’input, cioè la derivata parziale per il coefficiente c della equazione che regola la dinamica di Xi; ( k ) p ji Æ Path che collega la variabile sottoposta a input (Xi) con quella di cui si vuole calcolare il nuovo valore di equilibrio (Xj); (F ( comp ) n−k ) Æ Feedback di livello massimo del sottosistema complementare dell’Open Path. Al numeratore si trova F n Æ Feedback di livello massimo del sistema (Overall Feedback). Si consideri il caso in cui la crescita delle erbe infestanti (X2) viene limitata mediante l’uso di un erbicida. Questo intervento può essere qualificato come un input negativo su X2 in quanto l’erbicida procurando un aumento della mortalità di X2, ne riduce la velocità di crescita: X1 X2 19 X3 Gli effetti sul raccolto, si possono prevedere utilizzando la formula sopra introdotta. * ∂ X1 ∂c = ∑ (−) p 1,k ( ( comp ) 2←1 F n − k (k ) ) (− ) Il feedback complessivo viene considerato negativo, anche se non tutti i termini che lo compongono sono negativi, in quanto la formula è applicabile solo a sistemi stabili. In questo caso si può individuare un solo open path: ( k ) Æ p 2←1 X1 X2 Con il relativo feedback complementare: F ( comp) 1 Æ * ∂ X1 ∂c = X3 ∑ (−)⋅ (−)⋅ (0) 1,k (− ) =0 Il risultato non era prevedibile se si fossero considerate le specie in isolamento: solo dall’analisi del sistema nel suo complesso si può dimostrare che, in questo caso, una limitazione alla crescita dell’infestante imposta dall’esterno non produce nessun effetto sulla quantità di raccolto. Si può completare lo studio dell’esempio analizzando l’effetto di un qualsiasi input su una qualsiasi variabile, compilando cioè una matrice, che si chiama tavola di predizione, così strutturata: 20 Cambiamento nel livello di equilibrio di ↓ Incremento del X1 Tasso di crescita di X1 Æ X2 X2 X3 X3 Gli input vengono considerati positivi per convenzione. In presenza di input negativi è sufficiente invertire i segni della matrice. Calcolando si ottiene: Open Path che partono da X1 (1)⋅ (+ − ) = (1)⋅ (− ) = + (− ) (− ) (− )⋅ (0) = 0 ] X1 X2 [ Feedback comp: [X3] = 0 Æ (− ) (− + )⋅ (− 1) = (− )⋅ (− 1) = − ] X1 X2 X3 [ Feedback comp: Null Æ (− ) (− ) ]X1[ Feedback comp: [X2X3] Æ Open Path che partono da X2 (− )⋅ (− ⋅0) = 0 (− ) (− )⋅ (0) = 0 Feedback comp: [X3] = 0 Æ (− ) (+ − )⋅ (− ) = − Feedback comp: [X1] Æ (− ) ] X2 [ Feedback comp: [X3] [X3] = 0 Æ ] X2 X1 [ ] X2 X3 [ Open Path che partono da X3 (1)⋅ (+ − ) = + (− ) (1)⋅ (− − )⋅ (− 1) = + Æ (− ) ] X3 [ Feedback comp: [X1 X2] Æ ] X3 [ Feedback comp: [X1][ X2] 21 (− − )⋅ (− 1) = + (− ) (+ − )⋅ (− ) = − (− ) ] X3 X2 X1 [ Feedback comp: null Æ ] X3 X2 [ Feedback comp: [X1] Æ Alla fine del processo si otterrà questa tabella: X1 X2 X3 X1 + 0 − X2 0 0 − X3 + − + Nel caso di input negativi: X1 X2 X3 X1 − 0 + X2 0 0 + X3 − + − Ora che sono stati introdotti i principali strumenti di calcolo. Verranno analizzati nel dettaglio, e verranno chiarite le basi matematiche su cui si fondano. 22 Capitolo 3 I METODI MATEMATICI DELLA LOOP ANALYSIS Karma Police, arrest this man he talks in math, He buzzes like a fridge he’s like a detuned radio Radiohead – Karma Police I sistemi differenziali sono l’espressione matematica di una molteplicità di fenomeni, e hanno applicazioni in tutte le branche della scienza, dalla fisica alla biologia, dalla chimica alla meteorologia. Questo grazie alla possibilità che offrono di fare previsioni sull’evoluzione del sistema con relativamente poche limitazioni, (quasi) universalmente accettate. Si parte da un insieme di equazioni, che si possono rappresentare in un vettore: ! à Y (t) = (y 1(t); y 2(t); :::; y n(t)) Dove ogni variabile yi nel caso di sistemi biologici rappresenta una popolazione, un nutriente o un qualsiasi altro parametro di interesse che sia esprimibile come funzione rispetto al tempo. Il sistema differenziale di ordine n corrispondente è: à ! à ! dY (t) = F( Y (t)) dt se a questo sistema si associa una condizione iniziale: à ! ! à Y (0) = Y 0 ci si trova di fronte a un problema di Cauchy, per cui vale il teorema di esistenza e unicità (locale), ammettendo che la funzione sia definita in Rn e abbia derivate parziali continue rispetto ai suoi argomenti (le funzionipopolazione). Il sistema si dice lineare se la derivata è legata alla funzione con una relazione lineare, ossia se esiste una matrice A, quadrata e di ordine n, tale che: 23 à ! !0 à Y = AY Per ottenere le soluzioni bisogna analizzare gli autovalori della matrice A. (matrice Jacobiana). Tralasciando le dimostrazioni, in questo capitolo verrà analizzato il comportamento qualitativo del sistema secondo il tipo e i segni degli autovalori, e verrà chiarito il significato delle formule per la stabilità e per le predizioni introdotte nel capitolo precedente. 1. Stabilità in tempi discreti A questo punto è utile fare un passo indietro e supporre di avere una sola variabile. Si cerca un’equazione che dica come questa varii nel tempo: si assume che la variabile X prenda valori in R. Si prenda ad esempio l’equazione alle differenze: X ( t + ∆ t ) = X ( t ) + r ∆ t ( X ( t )) indicando con r il tasso di risposta. E’ semplice intuire che se X(0)=0, non ci sarà nessun cambiamento nella variabile, il cui valore resterà costantemente 0. Si dice allora che 0 è un punto stazionario dell’equazione. Altrettanto semplice è il comportamento dell’equazione se X≠ 0 e r >0: se X è positivo, allora aumenterà di una quantità sempre più grande ad ogni passaggio di t; se X è negativo, si allontanerà sempre di più dallo 0 in senso negativo. Il caso più complesso si ha quando r < 0: si possono distinguere tre sottocasi: a) –1 <r <0: in questo caso il sistema ritorna asintoticamente all’equilibrio (X=0). Numericamente, se, al tempo t, X(t) vale 1 e r = −1/2, allora, t 0 1 X 1,000 0,500 24 2 3 4 5 6 n 0,250 0,125 0,063 0,031 0,016 2-n Graficamente: 1,200 1,000 X 0,800 0,600 0,400 0,200 0,000 0 1 2 3 4 5 6 7 8 9 t b) –2 <r <−1: in questo caso il sistema ritorna oscillando all’equilibrio (X=0). Numericamente, se, al tempo t, X(t) vale 1 e r = −3/2, allora, t 0 1 2 3 4 5 6 n X 1,000 −0,500 0,250 −0,125 0,063 −0,031 0,016 (−1)n2-n 25 10 X Graficamente: 1,200 1,000 0,800 0,600 0,400 0,200 0,000 -0,200 -0,400 -0,600 0 1 2 3 4 5 6 7 8 9 10 t c) r <−2: in questo caso il sistema si allontana dall’equilibrio oscillando. Numericamente, se al tempo t , X(t) vale 1 e r = −3, allora, t 0 1 2 3 4 5 6 n X 1,000 −2,000 4,000 −8,000 16,000 −32,000 64,000 (−1)n2n X Graficamente: 80,000 60,000 40,000 20,000 0,000 -20,000 -40,000 -60,000 -80,000 -100,000 0 1 2 3 t 26 4 5 6 Infine, se r =−1 la variabile si annulla immediatamente, mentre se r =−2, X oscilla perpetuamente tra i valori X(0) e –X(0). Questo piccolo esempio dimostra che la condizione del tasso di risposta <0 è condizione necessaria ma non sufficiente per affermare che la variabile ritorna all’equilibrio (0) dopo essere stata perturbata. 2. Le equazioni viste da vicino Le equazioni differenziali con cui sarà espresso l’andamento delle popolazioni sono leggermente diverse da quella del paragrafo precedente. Due sono le principali differenze: l’ipotesi della continuità delle variabili e una differente estensione del dominio. L’ipotesi della continuità per t è una semplice induzione: prendendo ∆t sempre più piccoli, l’andamento dell’equazione si approssima progressivamente a quello dell’equazione differenziale dX = rX dt Ovviamente questo passaggio comporta un’astrazione ulteriore: bisogna supporre che anche X sia continua, il che è decisamente contrario al sentire comune (nessuno infatti ha mai visto π elefanti). Questa situazione paradossale si risolve con un semplice escamotage, valutando X non come numero di individui (e quindi intrinsecamente discreto), ma come biomassa, che può essere pensata continua, almeno a livello macroscopico. L’altra principale differenza sta nell’estensione del dominio, che è ristretto a R0+, in quanto possiamo ammettere individui frazionari, ma addirittura negativi… L’equazione descrive l’andamento della popolazione quando essa si trovi in un sistema isolato, e in assenza di fattori limitanti. Questa equazione è 27 detta Malthusiana, ed è utilizzata per descrivere le rare situazioni di crescita esponenziale. Risolta, infatti, diventa: X (t ) = X (0 ) e rt dove X(0) è il valore iniziale di X (condizione del problema di Cauchy). Queste particolari condizioni non si verificano praticamente mai. Sono state perciò introdotte alcune modifiche che permettono di tenere conto della limitazione delle risorse e della presenza di altre specie. Una prima, semplice modifica è data da: dX = rX ( b − X ) dt In questa equazione, il cui secondo membro si annulla per X=b (punto stazionario, o di equilibrio), non si ha più la crescita esponenziale incontrollata, o meglio si ha un asintoto orizzontale per X=b. Questa equazione, introdotta da Verhulst, si chiama “logistica”, e descrive il comportamento di una popolazione biologica in presenza di risorse limitate: se la popolazione si trova in [0,b] al tempo t0, crescerà asintoticamente a b per poi fermarsi (le risorse sono completamente utilizzate). Se invece la popolazione si trova in [b,∞[ all’istante t0, decrescerà asintoticamente a b e poi rimarrà stazionaria. Si noti che questo può avvenire solo se vi è stata immigrazione o se si è verificata una diminuzione delle risorse. Per una trattazione completa dell’equazione ci si rifaccia alla bibliografia, si riporta soltanto la soluzione: X (t ) = bce brt 1 + ce brt Il secondo passo è quello di considerare più popolazioni che intrattengono rapporti tra loro. Non si tratta più di una sola equazione, ma di un sistema di equazioni differenziali, come nel famoso caso del sistema predapredatore sviluppato indipendentemente da Lotka e Volterra: 28 dX dt = (a − bY )X dY = (− c + dX )Y dt dove a,b,c,d sono coefficienti positivi. Qui il tasso di crescita r diventa, per ogni equazione, una funzione lineare. Ovviamente il comportamento del sistema è più complicato di quelli visti in precedenza, dato che esistono alcune soluzioni stazionarie. Innanzitutto si possono analizzare le equazioni e il significato biologico delle varie componenti. X è la preda. Sono presenti un coefficiente di accrescimento spontaneo (a) e un altro (−b) che viene moltiplicato per la numerosità di entrambe popolazioni: viene solitamente interpretato come “efficacia” degli incontri preda-predatore. Diverso è il comportamento di Y. Infatti il coefficiente di accrescimento è negativo (−c, che valuta la competizione intraspecifica), e la crescita è dovuta esclusivamente al termine dX, ossia la crescita dei predatori è proporzionale al numero di prede. A questo punto si possono già individuare due casi: a) Se X=0, per t=0, allora i predatori seguono l’equazione: dY = − cY dt La numerosità decresce esponenzialmente fino all’estinzione. b) Se Y=0 al tempo t=0, allora le prede seguono una curva Malthusiana: dX = aX dt Cresceranno quindi esponenzialmente. Queste due soluzioni indicano che l’origine degli assi è quella che matematicamente si dice “punto di sella”. Questo risultato si può ottenere anche analizzando la matrice Jacobiana del sistema, valutata nel punto O=(0,0), e calcolandone gli autovalori. Dato che questa matrice ha una 29 particolare rilevanza nella Loop Analysis, prima di cercare tutte le soluzioni del sistema bisogna introdurne il calcolo, sottolineando l’importanza dei suoi autovalori per valutare la stabilità dei sistemi. 3. Matrice Jacobiana, autovalori e stabilità Si torni all’equazione: !0 à à ! Y = AY guardando le soluzioni delle equazioni Malthusiana e logistica, è naturale cercare un vettore v tale che le soluzioni abbiano forma: Y (t ) = v ⋅ e λt da cui, riferendosi all’equazione iniziale, A = λv che semplicemente afferma che, se v è una soluzione del sistema, allora λ è un autovalore della matrice A. Perché questo sia possibile, λ deve essere una soluzione della cosiddetta equazione caratteristica, che per due variabili si scrive: α11 − λ α12 = λ2 − (α11 + α 22 )λ + (α11α 22 − α 21α12 ) = 0 α 21 α 22 − λ In questo caso v è l’autovettore associato a λ. A seconda della natura degli autovalori, si può distinguere il comportamento qualitativo del sistema. Per semplicità verranno descritti i comportamenti di sistemi differenziali con due variabili. Per chiarire qualitativamente la natura delle soluzioni, ad ogni caso sarà associato un grafico. Ovviamente il grafico varierà a seconda dei valori dei coefficienti, ma, grazie al teorema di Jordan, si può associare ad ogni matrice 2x2 una matrice simile, detta canonica. La matrice canonica si può brutalmente definire come la matrice simile “più semplice”, e ha il pregio di chiarire, anche da un punto di vista grafico, la posizione degli autovalori. 30 Caso I: A possiede due autovalori reali λ1, λ2 distinti La soluzione generale ha forma y1 (t ) = ce λ1t v11 + de λ2t v12 λ1t 2 λ2 t 2 y 2 (t ) = ce v1 + de v2 dove c e d sono costanti arbitrarie e v ij sono le componenti degli autovettori. La matrice A sarà simile alla matrice canonica: λ1 0 0 λ2 Secondo il rapporto che intercorre tra gli autovalori, si distinguono tre sottocasi: Se λ1 > λ2 >0, il sistema è instabile: se perturbati, i valori si allontaneranno dal punto stazionario. Il quadro delle fasi si rappresenta con un Nodo Instabile: Nodo Instabile 31 Se λ1 < λ2 <0, il sistema è stabile: i valori si avvicineranno al punto stazionario. Nel quadro delle fasi troveremo un Nodo Stabile: Nodo Stabile L’ultimo caso si ha per autovalori di segno discorde (λ1 < 0 < λ2 ). Il sistema è instabile. Si individua un Punto di Sella: Punto di Sella Concludendo il Caso I si segnalano i sottocasi “limite”: il primo si verifica quando la matrice canonica ha forma λ1 0 0 0 cioè quando è presente un solo autovalore. Per il fine di questo lavoro è sufficiente affermare che se questo unico autovalore è negativo, il 32 sistema è stabile, altrimenti è instabile. Questa condizione di stabilità si verifica anche in presenza di due autovalori coincidenti. Caso II: A possiede due autovalori complessi coniugati λ1=α+iβ , λ2=α-iβ Si può dimostrare, utilizzando la formula di Eulero, che la soluzione generale ha forma: [ [ ] ] [ [ ] ] y1 (t ) = ce αt v11 cos β t − v12 sin β t + de αt v11 cos βt − v12 sin βt 2 2 αt 1 αt 1 y 2 (t ) = ce v 2 cos βt − v 2 sin βt + de v 2 cos βt − v 2 sin βt La matrice A sarà simile alla matrice: α − β β α In questo caso si classificherà il sistema secondo la natura della parte reale degli autovalori: Se Re(λ1) = Re(λ2) >0, il sistema è instabile. Il quadro delle fasi si rappresenta con un Fuoco Repulsivo: y2 y1 Fuoco Repulsivo 33 Se Re(λ1) = Re(λ2) <0, il sistema è stabile. Nel quadro delle fasi si formerà un Fuoco Attrattivo: y2 y1 Fuoco Attrattivo Infine, se Re(λ1) = Re(λ2) =0 il sistema ha un comportamento periodico, e nel piano delle orbite si forma un Centro. Centro Riassumendo e semplificando, si può affermare che il sistema, se perturbato, torna al punto stazionario se e solo se gli autovalori sono negativi o complessi coniugati con parte reale negativa. 34 Questo vale per i sistemi lineari, ma si può estendere la portata dei risultati raggiunti ai sistemi non lineari, se questi soddisfano alcune condizioni (si definiranno questi sistemi linearizzabili). Il teorema di linearizzazione (cfr. Prodi, 1992, p. 151), infatti, afferma che se la matrice Jacobiana ha determinante non nullo e autovalori reali, o complessi coniugati con parte reale diversa da 0, allora nell’intorno del punto stazionario le soluzioni del sistema non lineare hanno lo stesso comportamento di quello del sistema linearizzato. Questo è ottenuto utilizzando lo sviluppo di Taylor per calcolare il comportamento del sistema non-lineare nell’intorno di un punto stazionario, ovvero del sistema lineare in cui la matrice Jacobiana ha come coefficienti le derivate parziali di ogni variabile rispetto alle altre valutate nel punto di equilibrio. Ad esempio, per due variabili: ∂f1 * ∂y J = 1* ∂f 2 ∂y 1 * ∂f 2 ∂y1 * ∂f 2 ∂y 2 dove f1 e f2 sono le equazioni del sistema, y1 e y2 le variabili e il simbolo * significa che il risultato deve essere valutato nel punto stazionario. Ora si può riprendere il sistema preda predatore di Lotka Volterra (che è non-lineare) e ricavare i punti stazionari e il comportamento qualitativo delle soluzioni. dX dt = (a − bY )X dY = (− c + dX )Y dt La matrice Jacobiana sarà: − bx a − by J = − c + dx dy 35 I punti stazionari sono P=(0,0) e Q=(c/d, a/b). Nel caso di P, la matrice J diventa: a 0 J = ⇒ gli autovalori sono a e –c, che hanno segno discorde ⇒ 0 − c punto di sella, come già mostrato esplicitamente nel §1. Nel caso di Q, la matrice diventa: 0 J = da b − bc d ⇒ gli autovalori sono immaginari: 0 λ1 = ac ⋅ i λ 2 = − ac ⋅i Dato che il sistema è non lineare, il risultato potrebbe essere un centro, un fuoco attrattivo o un fuoco repulsivo: infatti, se si prende un centro, con una lieve perturbazione lo si può trasformare in un fuoco (l’esempio più semplice è un disco che gira: le orbite compiute dalla puntina non sono dei cerchi perfetti, ma formano un fuoco attrattivo). Purtroppo queste piccole differenze sono cancellate dalle approssimazioni che caratterizzano lo sviluppo di Taylor utilizzato per la linearizzazione. Il risultato, in questro caso, si ottiene sviluppando l’integrale generale (cfr. Prodi, 1992, p. 163), ma per questo lavoro basta sapere che, una volta risolto, il risultato è un centro: le prede e i predatori oscilleranno periodicamente. 4. Self-Loop Nel Capitolo 2 sono stati introdotti i self-effects, ma come si esprime matematicamente questo concetto? Si hanno self-loop quando sulla diagonale della matrice Jacobiana valutata all’equilibrio esistono coefficienti diversi da zero. Questo avviene se, per una popolazione, la derivata parziale dell’equazione che ne descrive l’andamento nel tempo, calcolata rispetto alla variabile-popolazione, ha valore diverso da 0. 36 Perché questo avvenga, l’equazione deve avere forma: dX i = f i = X i (g i ) dt con g i (X 1 , X 2 ,..., X i ,..., X n , t ) cioè in gi compare Xi, e quindi, in fi , Xi si trova in forma non lineare. Non si hanno self-effects quando ∂g i =0 ∂X i cioè quando in gi non compare Xi. Es. dX 1 = f1 = X 1 (aX 1 + bX 2 + cX 3 ) dt si annulla per X 1 =0, che non è interessante da un punto di vista biolgico, ma anche per (aX 1 + bX 2 + cX 3 ) =0 Il coefficiente della matrice Jacobiana sarà: dX ∂ 1 * dt = ∂f1 = (a( X ) + (aX + bX + cX )) * 1 1 2 3 ∂X 1 ∂X 1 dove si sostituirà poi a X1 il valore d’equilibrio X1*. Si nota subito che l’equazione è diversa da 0, perché quando si annulla (aX 1 + bX 2 + cX 3 ) rimane comunque il primo termine della somma. Questo determina la presenza di un self-loop, il cui segno dipenderà da quello coefficiente a, dato che si suppone X1 maggiore di 0. 37 Se si prende: dX 1 = f1 = X 1 (a + bX 2 + cX 3 ) dt l’equazione si annulla per X 1 =0 e per (a + bX 2 + cX 3 ) =0 Il coefficiente della matrice sarà: dX ∂ 1 * dt = ∂f1 = (a + bX + cX ) * = 0 2 3 ∂X 1 ∂X 1 in quanto nel punto di equilibrio (a + bX 2 + cX 3 ) =0. Immigrazione/Emigrazione Quando si verifica un flusso migratorio sono presenti self-loop, in quanto l’equazione ha forma: dX 1 = f1 = I + X 1 (a + bX 2 + cX 3 + ....) dt con punti stazionari quando: f1 * = 0 = I + X 1 (a + bX 2 + cX 3 + ....) cioè: (a + bX 2 + cX 3 + ....) = − I X1 Dato che X1 è diversa da zero, allora: dX * ∂ 1 dt = ∂f1 = (a + bX + cX + ...) * = − I ≠ 0 2 3 * ∂X 1 ∂X 1 X1 Quindi se I>0 (immigrazione), il self-loop sarà negativo, mentre se I<0 (emigrazione), sarà positivo. Questo risultato era prevedibile: se c’è immigrazione, infatti, aumenta la competizione intraspecifica, se c’è emigrazione aumentano le risorse pro capite, e quindi la probabilità di riprodursi. 38 5. Stabilità in più variabili Mentre è abbastanza semplice trovare le soluzioni di un sistema in due variabili, il lavoro si fa immensamente più arduo al crescere del numero di equazioni, per diventare generalmente impossibile con più di 5 variabili. Proprio in questi casi è utile una metodologia come la Loop Analysis, che riesce a tenere conto della complessità dei sistemi, pur rinunciando alla precisione di altri metodi quantitativi. Il principale problema è che la metodologia si può applicare solo a sistemi stabili, e che quindi bisogna riuscire a valutare la stabilità di sistemi in più variabili. Nel Capitolo 2 si sono introdotte alcune formule che ora, grazie al concetto di equazione caratteristica e allo studio di sistemi in due variabili, si è in grado di giustificare. Si può cominciare con lo sviluppo del determinante di una matrice 3x3: α11 α12 α13 D = α 21 α 22 α 23 = α11α 22α 33 − α11α 32α 23 − α 21α12α 33 + α 21α 32α13 + α 31α12α 23 − α 31α 22α13 α 31 α 32 α 33 Ora, prendendo una matrice di comunità che abbia la stessa struttura, si può associare ad ogni termine dello sviluppo del determinante i percorsi corrispondenti. 39 A B A B C C − α11α 32α 23 α11α 22α 33 A B A B C C α 21α 32α13 − α 21α12α 33 A B A B C C α 31α12α 23 − α 31α 22α13 α11 α12 α13 D = α 21 α 22 α 23 = α11α 22α 33 − α11α 32α 23 − α 21α12α 33 + α 21α 32α13 + α 31α12α 23 − α 31α 22α13 α 31 α 32 α 33 40 Questi sono tutti i loop disgiunti (di livello 3) del grafo. Il segno – nello sviluppo del determinante si ha davanti ai termini associati a loop formati da un numero di circuiti pari. Quindi è possibile scrivere il feedback come determinante della matrice di comunità: Dn = ∑ (− 1) L(m, n ) n−m e quindi: Fk = (− 1) Dk k +1 infine, sostituendo: Fk = ∑ (− 1) m +1 L(m, k ) Con questa notazione è semplice capire perché F 0 ≡ −1 . Si può scrivere l’equazione caratteristica in termini di feedback: F0 λn + F1λn−1 + F2 λn−2 + ... + Fn−1λn + Fn = 0 Un sistema è stabile se e solo se tutti gli autovalori della matrice Jacobiana hanno parte reale negativa (§ 2). Quindi, in realtà, non si è interessati a quantificare gli autovalori, ma solo a sapere se Re(λi) è negativa per ogni i. Il teorema di Routh-Hurwitz (cfr. Cesari, 1959) spiega come sono correlati i coefficienti di una qualsiasi equazione con le radici della stessa. Nel caso in questione, i coefficienti sono rappresentati dai valori di feedback, quindi si può adattare il teorema per individuare quali sono i rapporti tra i feedbacks necessari affinché tutte le radici dell’equazione abbiano parte reale negativa. Nel caso più semplice, un sistema con due variabili, le radici sono λ1 e λ2. L’equazione è perciò della forma: (λ − λ1 )(λ − λ2 ) = λ2 − λ (λ1 + λ2 ) + λ1λ2 = aλ2 + bλ + c = 0 41 Se, per comodità, si pone a=1, allora i coefficienti intrattengono con le radici i seguenti rapporti : a =1 b = − somma radici c = prodotto radici Ora, ammettendo che tutte le radici siano negative, si ottiene che a>0, b>0, c >0. In realtà, si è definito a = -F0 (in quanto si è già dimostrato che F0 = -1) e quindi, nell’esprimere i feedbacks si devono invertire i segni: a = − F0 = 1 ⇒ F0 < 0 b = − F1 = − somma radici ⇒ F1 < 0 c = − F2 = prodotto radici ⇒ F2 < 0 Si è dimostrato che, affinché le radici di un sistema differenziale in due variabili abbiano parte reale negativa, è necessario che i livelli di feedback siano negativi. Lo stesso procedimento si può estendere a n variabili, ad esempio con tre si avrà: (λ − λ1 )(λ − λ2 )(λ − λ3 ) = (λ2 − λ (λ1 + λ2 ) + λ1λ2 )(λ − λ3 ) = λ3 − λ2 (λ1 + λ2 + λ3 ) + λ (λ1λ2 + λ1λ3 + λ2 λ3 ) − λ1λ2 λ3 = aλ3 + bλ2 + cλ + d = 0 In questo caso: a =1⇒ a > 0 b = −∑ radici ⇒b > 0 c = ∑ ( prodotto radici prese due a due) ⇒ c > 0 d = − prodotto di tutte le radici ⇒ d > 0 42 Quindi, se tutti i coefficienti sono positivi (e quindi i feedbacks negativi), l’equazione caratteristica ha radici con parte reale negativa. In realtà, i coefficienti sono strettamente correlati tra loro (essendo composti dalle radici aggregate in diversi modi), perciò si può descrivere l’algoritmo in un modo più conciso secondo la notazione di Routh-Hurwitz. Si può dimostrare che i coefficienti devono soddisfare due condizioni: - Essere tutti positivi (e quindi i feedbacks negativi); - Tutti i determinanti delle matrici di Hurwitz, Hi, ∀i ∈[1..k] devono essere maggiori di 0. Chiamando i coefficienti del polinomio a0..an, le matrici di Hurwitz sono così strutturate: H 1 = a1 a a3 H2 = 1 a0 a 2 ... a1 a3 a5 a0 a 2 a 4 H4 = 0 a1 a3 0 0 a2 a7 a6 a5 a4 ... a1 a0 Hn = 0 0 0 0 ... 0 a3 a2 a1 a0 a5 a4 a3 a2 0 a1 0 a0 ... ... 0 0 a7 ... a6 ... a5 ... a6 ... ... ... ... ... ... ... ... ... a 2 n−1 a2 n−2 a 2 n −3 a2 n−4 a5 ... ... a 4 ... ... ... ... ... 0 ... ... ... ... ... ... ... ... ... an 43 Che, tradotto in termini di feedback, diventa: H 1 = − F1 > 0 ⇒ F1 < 0 − F3 > 0 ⇒ F1 F2 − F0 F3 > 0 ⇒ F1 F2 > F0 F3 − F2 − F1 H2 = − F0 − F1 H 3 = − F0 0 2 − F3 − F2 − F1 − F5 − F4 = − F1F2 F3 + F1 F1 F4 + F3 F3 F0 − 0 − F5 F0 F1 + 0 > 0 − F3 2 ⇒ F1 F4 − F3 + F5 F1 − F1F2 F3 > 0 ... E’ importante sottolineare che si ottiene una nuova matrice per ogni numero dispari di variabili: H1Æ 1 Var, H2 Æ3 Var, H3 Æ5 Var, H4 Æ7 Var… Per un sistema con numero pari di equazioni, si deve prendere in considerazione la matrice H(N°var/2). 6. Un esempio Si prenda il sistema introdotto nel Capitolo 3: −α 11 CM = −α 12 0 −α 0 −α α −α 0 21 22 23 32 Costruzione delle equazioni: Le equazioni per le tre variabili avranno forma: X 1' = I + (a1 − b1 X 2 )X 1 X 2' = I + (b2 − a 2 X 1 − c2 X 3 )X 2 X 3' = (− c3 + b3 X 2 )X 3 In cui si hanno self-loop, dovuti alle limitazioni per fattori esterni al sistema, nelle prime due equazioni, competizione tra X1e X2, predazione di X3 su X2. 44 Stabilità del sistema: Il determinante della matrice è: D3 = F3 = −(− α11 ⋅ α 32 ⋅ −α 23 ) < 0 quindi la parte dell’overall feedback formata da un solo circuito è negativo. Per calcolare gli altri livelli di feedback: F2 = (− 1) D2 = −1D2 2 +1 I determinanti delle matrici sono: D(CM X1 X 2 ) = − α11 − α12 − α 21 = (α11α 22 ) − (α 21α12 ) − α 22 D(CM X 2 X 3 ) = − α 22 − α 23 D(CM X 3 X1 ) = 0 0 =0 0 − α11 − α 32 = (α 23α 32 ) 0 F2 è perciò ambiguo, in quanto c’è il termine positivo (α 21α12 ) . Si suppone che F2 sia negativo, per proseguire nell’analisi, e si calcola F1: F1 = (− 1) D2 = D2 1+1 D(CM X1 ) = − α11 = −α11 D(CM X 2 ) = − α 22 = −α 22 D(CM X 3 ) = 0 = 0 Æ F1 <0 Perché il sistema sia stabile occorre però che sia rispettato il criterio di Routh Hurwitz: il polinomio caratteristico della Jacobiana, scritto in termini di feedback è: F0 λ3 + F1λ2 + F2 λ + F3 = 0 45 il determinante della matrice di Hurwitz: H2 = F1 F0 F3 = F1 F2 − F0 F3 > 0 F2 ⇒ F1 F2 > F0 F3 ⇒ F1 F2 > F3 Cioè: (α11 + α 22 )⋅ ((α11α 22 ) − (α 21α12 ) + (α 23α 32 )) > (α11α 32α 23 ) α 211α 22 − α11α 21α12 + α11α 32α 23 + α11α 2 22 − α 22α 21α12 + α 22α 23α 32 > (α11α 32α 23 ) α 211α 22 − α11α 21α12 + α11α 2 22 − α 22α 21α12 + α 22α 23α 32 > 0 Se, come supposto, F2 è negativo, allora il sistema soddisfa i criteri di RouthHurwitz, ossia le radici dell’equazione caratteristica sono reali negative o immaginarie con parte reale negativa: il sistema è stabile. 7. Cambiamento nei valori di equilibrio Fare predizioni sull’evoluzione del sistema equivale ad individuare il comportamento di ogni variabile quando varia un parametro Ch tale per cui: ∂f i ≠0 ∂C h Si è interessati a sapere come variano i valori di equilibrio di tutte le variabili, il che equivale a calcolare: ∂f i ∂X j j ∂C h ∑ ∂X ∂f i + ∂C h = 0 ovvero a calcolare come cambiano i valori delle varie Xj quando si ha un ∂X j mutamento in fi. Le incognite sono i vari ∂C h , mentre si conosce ossia l’effetto del mutamento nel parametro su fi, e anche 46 ∂f i ∂C h , ∂f i ∂X j , coefficienti della matrice di comunità. Si può quindi scrivere l’equazione in forma vettoriale: a11 ... a1n ∂X 1 / ∂C h − ∂f1 / ∂C h ... ... ... = ... ... an1 ... ann ∂X 2 / ∂C h − ∂f1 / ∂C h Si può dimostrare, ma non verrà fatto in questo testo, che la soluzione si ∂X j ottiene per ogni particolare ∂C h sostituendo la j-esima colonna della matrice di comunità con il vettore che si trova a destra dell’equazione e facendone il determinante, il tutto diviso per il determinante della matrice di comunità (cfr. Lang, 1987 § 6.4): ∂f1 ∂C h ... ... ... ... ∂f ... − n ∂C h a11 ... − ∂X j ∂C h ... = ... an1 ...a1n a ... a1 j 11 ... ... ... ... ⋅ ... ... ... ... an1 ... anj ...a nn ...a1n ... ... ...ann −1 Si è già visto come si può esprimere il determinante della matrice di comunità nel § 5, quindi il denominatore è esprimibile in termini di loop: D n = ∑ (− 1 ) n−m L (m , n ) Il numeratore è invece più difficile da riportare a oggetti grafici interpretabili, quindi risulta utile analizzare un caso concreto. Si prenda la matrice di comunità: α11 α 12 α 13 CM = α 21 α 22 α 23 α 31 α 32 α 33 47 L’equazione, rispetto alla variabile X2 sarà: f ∂C a a a ∂ f − ⋅a a a ∂C a a ∂ f − ∂C a a − 11 ∂X2 = ∂ Ch a a ∂ 1 13 h 11 12 21 22 31 32 a a a 2 21 23 −1 13 h 23 33 3 31 33 h Lo sviluppo del determinante che sta al numeratore è DET [Numeratore] = − f ( ∂C a a ∂ 1 21 h 33 − a 23 a31) − f ( ∂C a a ∂ 2 31 13 h − a11 a33 ) − ∂ f 3 ∂Ch (a a − a a ) 23 11 Si mostra ora il significato grafico delle componenti: − f ∂C ∂ X1 1 f − ∂C f − ∂C ∂ X2 ⋅ h ∂ X1 X2 X3 X3 X1 2 X1 ⋅ h X1 3 X3 X3 X2 X1 X2 ⋅ h X3 X3 Il primo coefficiente, (a 21 a33 − a 23 a31 ) , è dato da tutti i percorsi aperti che vanno da X1 a X2, e loro sottosistema complementare. 48 21 13 (a a − a a ), è formato da tutti i percorsi aperti che Il terzo coefficiente, 23 11 21 13 vanno da X3 a X2, e loro sottosistema complementare. Allo stesso modo si può definire (a a − a a ) come tutti i percorsi aperti 31 13 11 33 che vanno da X2 a X2 (cioè solo quello preso per convenzione) e relativi sottosistemi complementari. Quindi si può scrivere in modo compatto: DET [Numeratore ] = − f ∑P ∂C ∂ 1 (k ) 21 L(2,3 − k ) − h f ∑P ∂C ∂ 2 (k ) 22 L(2,3 − k ) − h f ∑P ∂C ∂ 3 (k ) 23 L(2,3 − k ) h Tornando all’equazione generale per X2: a 11 f ∂C a a ∂ f − ⋅ a ∂C a a ∂ f − ∂C a − ∂ 13 h ∂ X 2 ∂ Ch = a 11 2 21 23 21 h a ∂f i 1 31 a a a 12 22 32 a a a −1 13 23 33 = ∑ ∂C ) P2(ik ) Fn(−comp k h Fn 3 31 33 h Generalizzando la formula, che vale anche per sistemi di più variabili, si ottiene: X ∂C ∂ j h = ∑ ∂fi P ji( k ) F n(−comp k ∂C h Fn ) che è la formula utilizzata nel Capitolo 2 per ottenere i mutamenti dei livelli di equilibrio. Questo capitolo è stato concepito per dare le informazioni necessarie alla comprensione della Loop Analysis. Per approfondire i concetti fin qui esposti, e per le dimostrazioni delle formule utilizzate, si consulti la bibliografia. 49 Capitolo 4 LE AMBIGUITÀ “Something is rotten in the State of Denmatk” William Shakespeare – Hamlet I,4.90 Nei capitoli precedenti sono passate in rassegna la metodologia della Loop Analysis e le basi matematiche su cui essa si fonda. La semplicità dei calcoli maschera però una limitazione implicita: prendendo in considerazione solo i segni dell’interazione si perde tutta l’informazione sul “modulo” del link. Si immagini infatti di ottenere due risultati contrastanti sull’effetto di un input su Xj, calcolato per Xi: si hanno un percorso e il suo sottosistema complementare che indicherebbero come risultato “+”, mentre l’altro indicherebbe “−”. La natura strettamente qualitativa della Loop Analysis fa sì che il risultato sia indecidibile: si è in presenza di una ambiguità. In questo capitolo saranno presi in esame i vari casi in cui si produce ambiguità (§§ 1,2), e si vedrà una tecnica per ridurre il numero di variabili (il “lumping”), che solitamente ha come effetto una semplificazione del sistema, con conseguente diminuzione del numero di ambiguità (§ 3). In ultimo, verrà illustrata la filosofia del software SimLoop, il cui scopo è quello di fare luce, dove possibile, sulle ambiguità del sistema, mediante una simulazione (necessariamente quantitativa). Non si entrerà nel merito degli algoritmi, perché verranno illustrati nel Capitolo 6. 1. Combinazioni di segno opposto Nel caso di combinazioni di segno opposto esistono loop dello stesso livello di feedback che hanno segno opposto, rendendo l’intero livello di feedback ambiguo. Si possono ottenere informazioni valutando il numero di loop che contribuiscono ad ogni segno e la loro lunghezza. Con questa 50 operazione si accetta implicitamente una quantificazione dei coefficienti. Quindi, per risolvere le ambiguità, è necessario tentare di estrapolare informazioni più che qualitative dal sistema. Ad esempio, si prenda un sistema formato da N (Azoto), P (Fosforo), G (Alghe) e B (Cianobatteri). N B P G L’effetto su G di un input su B è ambiguo: ]BNG[ e [P] Æ (+) (−) = (−) Æ diviso per il feedback globale (−) Æ + ]BPG[ e [N] Æ (+) (−) = (−) Æ diviso per il feedback globale (−) Æ + ]BG[ e [N][P] Æ (−) (−) = (+) Æ diviso per il feedback globale (−) Æ − Quindi l’ambiguità del livello F2 si ripercuote sull’ambiguità delle predizioni. Ora si può procedere in due modi. In maniera approssimativa, si può affermare che, se il legame NG è abbastanza forte rispetto agli altri contributi, il risultato di un input positivo su B porterà ad un incremento della numerosità di G. Questo avviene se il processo di azotofissazione da parte dei cianobatteri porta un grande vantaggio alle alghe rispetto all’effetto tossico (BG), e se il fosforo è presente in concentrazioni elevate, il che diminuisce l’impatto della competizione per il nutriente. Un altro approccio si basa sulla forma delle equazioni. Si suppone che: dG = G[α GN N + α GP P − α GB B − µ G ] dt dB = B[α BP P − µ B ] dt 51 dN = I N + α NB B − N [α NG G + κ N ] dt dP = I P − P[α PB B + α PG G + κ P ] dt Dove IX rappresenta l’afflusso di X al sistema (che, come già visto, fa risultare la variabile self-damped), mentre κ X rappresenta la parte di X rimossa dal sistema nell’intervallo dt. Nel caso di variabili-popolazione, questa rimozione viene indicata con µ G (tasso di mortalità istantaneo). Ora si possono “stimare” i vari contributi in funzione delle numerosità delle variabili. I segni si considerano divisi per F4<0: (α NBα GN G )(α PB B + α PG G + κ P ) − (α PB P )(α GP G )(α NG G + κ N ) − (α GB G )(α PB B + α PG G + κ P )(α NG G + κ N ) G è in forma quadratica nel primo e nel secondo termine, mentre nel terzo risulta in forma cubica. Quindi, se si suppone G molto grande, il risultato sarà negativo: un aumento di N provoca un aumento nel valore di G, perciò possono esistere effetti positivi su G da parte di N. 2. Ambiguità nel segno di un path o di un loop Non esistono solo ambiguità nella struttura. Come era da prevedersi, alcune possono sorgere anche quando le variabili assumono determinati valori. Un esempio per chiarire la situazione: P H Questo è un semplice modello preda predatore, dove la pianta P viene predata dall’erbivoro H. P riceve due link negativi: quello che forma il selfloop e quello che lega l’erbivoro alla pianta. L’equazione di P ha forma: dP = P[K − P − f (P )H ] dt dove P f (P )H è la funzione che rappresenta la predazione dell’erbivoro. 52 Se questa funzione ha forma: Pf (P ) = vP K +P allora ∂ dP vHK = −1 + P ∂P dt K + P Questa equazione può essere positiva se P è “piccola” e H “grande”, ossia esistono valori di P, H, K per i quali l’equazione risulta positiva e il sistema instabile. Quindi, oltre alle ambiguità create dai diversi percorsi, ne possono risultare altre da determinate combinazioni nei valori delle variabili. E’ importante sottolineare che queste ambiguità, come quelle già viste, sono l’effetto collaterale della semplificazione operata rendendo i link esclusivamente qualitativi. Si possono trovare soluzioni ad hoc per alcune ambiguità, ma altre rimarranno. La potenza predittiva del modello risulta diminuita da questa presenza, anche se spesso si producono in modo da non recare danni all’analisi: se si analizza un modello di 30 variabili, che dà in output 900 risultati, non è importante che siano tutti ben definiti, ma che risultino chiari quei 10-15 per i quali si è svolta l’analisi. 3. Il “Lumping” delle variabili Con l’aumentare del numero delle variabili, la complessità del calcolo cresce esponenzialmente e, inoltre, aumenta il numero di ambiguità. E’ quindi molto comodo avere la possibilità di semplificare il grafo, mantenendo però le sue proprietà. Questa procedura viene chiamata da Levins e Puccia “Lumping Variables”, ossia accorpare, o, più letteralmente, “aggrumare” le variabili. E’ chiaro che eliminare variabili o raggrupparle non può essere fatto senza 53 produrre effetti. Sperimentalmente si ottiene che la procedura incide notevolmente sulla stabilità del sistema, ma lascia praticamente inalterati i risultati per i mutamenti dei livelli di equilibrio. L’operazione può essere compiuta sulle variabili principalmente per motivi di ordine ecologico o topologico. Verranno ora presi in esame i principali casi in cui si possono aggregare (o eliminare) variabili: a) Aggregazione per tempi Si possono aggregare variabili per tempi di risposta: questa è una motivazione ecologica. Si prenda un sistema in cui interagiscano variabili con tempistiche differenti. In questo caso, si possono aggregare quei sottosistemi che hanno tempi di crescita e di risposta differenti di vari ordini di grandezza rispetto ad altre variabili. Ad esempio, si può tranquillamente ritenere costante la temperatura media giornaliera, se essa va confrontata con la crescita di batteri, mentre va valutato il sistema che la regola nel caso di cicli più lunghi, come la crescita di alberi. E’ quindi una questione di focus: bisogna tarare il sistema anche temporalmente rispetto alle variabili su cui si concentra l’analisi; b) Variabile con singola connessione Una variabile che sia connessa al sistema con un solo link può essere eliminata: non partecipa infatti a nessun loop. Questa è una considerazione di ordine topologico. Si può mantenere l’informazione relativa alla ex-variabile trattandola come un input. Input A Var A Var B Var B 54 c) Variabile “intermedia” Un altro caso in cui si può eliminare una variabile perché non partecipa alle proprietà del sistema si ha quando questa è intermedia tra altre due, e non ha nessun altro link. La variabile deve però essere inclusa se la sua eliminazione, cambiando il segno di uno dei livelli di feedback, fa perdere al sistema la stabilità. Var A Var A Var B d) Sottosistema fortemente connesso Un sottosistema di X variabili legato al resto del sistema con un solo link può essere trasformato in una variabile self-damped. Questa è una proprietà dei grafi in cui si riscontrano distinti sottosistemi fortemente connessi (si veda il Capitolo 5). Ha però un preciso significato biologico: ogni popolazione può essere suddivisa in classi (ad esempio per fasce d’età, o stati fisiologici, …) che intrattengono rapporti le une con le altre. In una popolazione stratificata per età, vi sono n fasce d’età, ognuna collegata con un doppio link alla successiva. Queste classi non si autoriproducono, ma semplicemente gli individui transitano da una all’altra. Questa informazione non è necessaria per fare previsioni, e risulta anzi “dannosa” quando genera ambiguità. Quindi, in assenza di relazioni con le altre variabili (come può essere per una predazione specifica sulle larve o sulle uova), il sottosistemapopolazione può essere ridotto ad una variabile. 55 Uova Larve Adulti Specie e) Variabili “omologhe” Si possono raggruppare variabili che occupano posizioni identiche all’interno del sistema, cioè che intrattengono gli stessi tipi di link con le altre variabili: A B In questo caso si possono aggregare A e B in una nuova variabile C. Oltre a diminuire il numero di variabili, la nuova variabile C=A+B avrà anche una risposta più veloce agli stimoli, perché diminuisce la ridondanza. C 4. Simulare Si è visto come la presenza di ambiguità sia causata dalla natura puramente qualitativa dell’analisi. In effetti, dato un sistema, non è possibile risolvere le ambiguità senza modificarlo o aggiungere informazioni quantitative. La prima strada è quella più semplice: modificare il modello perché risulti “più predittivo”. Questa operazione, però, comporta dei rischi per quanto riguarda la verosimiglianza e la generalità dello stesso. La seconda 56 non ha praticamente nessuna controindicazione dal punto di vista formale, ma si scontra con due difficoltà: - La lunghezza e complessità di calcolo: il numero di operazioni da compiere è altissimo. Per un grafo pesato di sole 10 variabili, il numero di moltiplicazioni è nell’ordine di qualche centinaio di milioni… - La misura dei coefficienti è particolarmente difficile, e in qualche caso impossibile (si pensi alla quantificazione di fattori sociali, o alla valutazione dell’impatto visivo di una costruzione…). Anche nel migliore dei casi, queste stime contengono errori che si vanno a moltiplicare ad ogni passaggio, rendendo il risultato poco significativo. Per ovviare a queste difficoltà, nel software è stato sviluppato un algoritmo di simulazione per risolvere le ambiguità. Esso si basa su due assunti: - vengono simulati solo i percorsi che sono all’origine di ambiguità; - i valori sono scelti a caso e normalizzati per ogni variabile. Si è cercato cioè di sopperire alla mancanza di informazione (ambiguità) solo dove si presentava. In questo modo è minimizzato l’intervento di quantificazione delle interazioni, riducendo il numero di calcoli da effettuare. Inoltre, dato che i valori sono casuali, la simulazione viene reiterata più volte, in modo da prendere in esame il maggior numero di casi possibili. L’algoritmo verrà analizzato in dettaglio nel Capitolo 6. 57 Capitolo 5 TEORIA DEI GRAFI “How many links must a path walk by, before you can call him a loop?” Quando Eulero si poneva il famoso problema dei ponti di Konigsberg, sicuramente non aveva in mente la Loop Analysis. Dato però che i grafi sono così importanti nello sviluppo di questa metodologia, è necessario passare brevemente in rassegna i principali concetti della Teoria dei Grafi, per poi analizzare alcuni aspetti di combinatoria. Infine verrà presa in esame la rappresentazione informatica dei directed graphs (o digraphs), utilizzata per creare i software. 1. Rappresentazione e definizioni Si definisce grafo un insieme finito di punti, detti vertici o nodi, connessi da links chiamati lati o spigoli (edges o anche archi, arcs). Un grafo semplice è dato da N vertici e da M spigoli che uniscono ognuno due vertici, con M>(N-2) quando ogni variabile è connessa almeno a un'altra. I digraphs, o grafi orientati, sono un particolare sviluppo del grafo semplice, con due principali differenze: Ogni link ha una direzione Due vertici possono essere connessi da due spigoli (AÆB e BÆA) Un grafo in cui gli spigoli abbiano un’intensità si dice “pesato” (weighted). I grafi della Loop Analysis sono grafi orientati pesati in cui gli spigoli (i links) prendono valori in {−1; 0; 1}. 58 Alcune definizioni: a) Due vertici connessi da uno spigolo si dicono adiacenti; b) Un percorso è una sequenza di spigoli; la lunghezza del percorso è data dal numero di spigoli attraversati; c) Un ciclo è un percorso che finisce nel vertice da cui comincia, senza passare due volte per la stessa variabile. In questo caso la Loop Analysis utilizza una terminologia leggermente diversa: il ciclo diventa loop, termine che nella teoria dei grafi significa ciclo di lunghezza 1 (self-loop); d) Un grafo si dice completo se ogni vertice è adiacente ad ogni altro; e) Un grafo fortemente connesso è un grafo orientato in cui da ogni vertice A si può andare a un altro vertice B, e da questo ritornare ad A; f) La locuzione grafo completamente connesso verrà utilizzato per descrivere un grafo orientato in cui tutti i vertici sono adiacenti tra loro e in cui ogni vertice possiede un (self) loop; g) Il grado (degree) di un vertice è il numero di spigoli che terminano in quel vertice; in un grafo orientato, il grado viene suddiviso in in-degree, spigoli che terminano nel vertice, e out-degree, spigoli che partono dal vertice; Una volta definiti i principali concetti, è interessante, soprattutto nel caso si debba dimensionare l’output per un software, chiedersi quanti loop, path,… ci siano in un determinato grafo. 2. Quanti Loop? Il primo problema è quello di individuare il numero di loop presenti in un grafo. Si mostrerà come calcolarlo in un grafo completamente connesso di n variabili. Si prendono in considerazione solo i loop, ma è bene ricordare che 59 ai fini della Loop Analysis si devono ricavare i livelli di feedback, quindi tutte le possibili combinazioni di loop disgiunti. Si prenda un grafo completamente connesso di n variabili (vertici). Questo grafo avrà n2 spigoli (links). Si vuole trovare il numero di loop di livello k del grafo per ogni k ≤ n. La formula generale è: L(n, k ) = N/K 1 2 3 4 5 6 7 8 9 10 1 1 2 3 4 5 6 7 8 9 10 2 3 4 5 n! (n − k ) !k 6 7 1 3 2 6 8 6 10 20 30 24 15 40 90 144 120 21 70 210 504 840 720 28 112 420 1.344 3.360 5.760 36 168 756 3.024 10.080 25.920 45 240 1.260 6.048 25.200 86.400 8 9 10 TOT 1 3 8 24 89 415 2.372 5.040 16.072 45.360 40.320 125.673 226.800 403.200 362.880 1.112.083 Nella tabella sono riportati il numero di loop di livello K per un sistema di N variabili. Si vede subito come il numero totale dei loop cresca più che esponenzialmente con l’aumentare delle variabili. L’equazione che ne descrive l’andamento è infatti (se T(n) è il totale): T (n ) ≅ e (n − 1 ) ! Ovviamente il tempo di esecuzione del software avrebbe lo stesso andamento. Per fortuna, i sistemi naturali non hanno mai rappresentazione in un grafo completamente connesso: di solito si riscontra una connectivity (o, secondo la teoria dei grafi, un grado) tra 3 e 4, ossia ogni variabile del sistema è connessa mediamente ad altre 3-4 variabili. 60 Per una analisi più approfondita si sono presi in esame alcuni grafi pubblicati in letteratura, e si è controllato il numero complessivo dei loop: Nome TowerTank Delaware Marine Lake35 n° Var 13 18 21 35 n° Loop 36 85 178 385.647 Connectivity 3,000 3,428 3,277 3,828 Anche il sistema più grande, con 35 variabili, ha “solo” 385.000 loop. Ora si può compiere la stessa operazione per trovare il numero di open paths in un grafo completamente connesso. In realtà, farlo è molto semplice: Per un sistema di una variabile esiste un solo open path. Per un sistema di due variabili ne esistono quattro (A, AÆB, B, BÆA). Si hanno due percorsi (uno di lunghezza 0 e l’altro di lunghezza 1) che partono da ogni variabile. Si consideri un sistema di tre variabili: tutti i percorsi che partono dalla terza variabile non sono altro che quelli trovati per il sistema di due variabili, con l’aggiunta di C, più un nuovo percorso (C). Sistema da due variabili: Percorsi che partono da A: A AÆB Percorsi che partono da B: B BÆA Sistema da tre variabili: Percorsi che partono da C: CÆ (A) C Æ (A Æ B) CÆ (B) 61 CÆ (B Æ A) C (nuovo) Il numero totale di percorsi nel sistema di tre variabili sarà (4+1)∙3=15. Con questo algoritmo si può ricavare il numero di percorsi di un qualsiasi sistema completamente connesso: N° Var N° Paths 1 1 2 4 3 15 4 64 5 325 6 1.956 7 13.699 8 109.600 9 986.409 10 9.864.100 11 108.505.111 12 1.302.061.344 13 16.926.797.485 14 236.975.164.804 15 3.554.627.472.075 16 56.874.039.553.216 17 966.858.672.404.689 18 17.403.456.103.284.400 19 330.665.665.962.404.000 20 6.613.313.319.248.080.000 L’effetto gestaltico piramidale è molto di più di una illusione ottica, è una terribile verità: se i sistemi da analizzare fossero completamente connessi, occorrerebbero tempi geologici per elaborarli, ammesso di possedere delle macchine sufficientemente potenti (e quindi costose). Infatti, se si definisce TP(n) il numero totale di path in un grafo completamente connesso di n variabili allora: TP (n ) = [n!⋅e − 1] cioè la parte intera di (n!e−1). Per 30 variabili TP>71032. 62 Per fortuna il numero di loop e path dei sistemi naturali, o meglio dei grafi con cui essi vengono rappresentati, è decisamente minore. Questo è importante, oltre che per la possibilità di analisi, anche per un altro motivo: ogni sistema di n variabili (con n >2), completamente connesso e con link tutti dello stesso segno, dà origine a una tavola di predizione composta esclusivamente da ambiguità. Inoltre queste ambiguità sono resistenti a qualsiasi simulazione, dato che sono formate da una perfetta simmetria di segni + e − prodotti da percorsi e sistemi complementari esattamente speculari. 3. Rappresentazione informatica dei grafi Tradizionalmente esistono due strategie per trattare i grafi a livello informatico: una utilizza una matrice, l’altra una lista di puntatori. Si è scelta la rappresentazione matriciale del grafo perché rende la progettazione molto semplice, a fronte di un utilizzo della memoria più pesante, ma comunque infinitesimale rispetto alla memoria necessaria all’elaborazione. Questa scelta rende anche particolarmente agile la spiegazione: la rappresentazione del grafo è la matrice di comunità, con alcune differenze. Mentre ogni cella della matrice di comunità contiene un coefficiente, nella rappresentazione che se ne fa ogni cella contiene un record (ossia un set di dati) formato da: Valore del coefficiente: un elemento dell’insieme {-1; 0; 1} Flag (valore che serve a segnalare lo stato di una variabile) che indica se il coefficiente è diverso da 0: elemento dell’insieme {True; False} Segno del coefficiente : elemento dell’insieme {True; False} Se, ad esempio, si analizza la matrice di comunità: 63 − α11 CM = − α 21 0 − α12 0 − α 22 α 23 − α 23 0 questa verrà rappresentata da tre matrici sovrapposte, cioè da una matrice in tre dimensioni 3x3x3: Matrice dei valori: − 1 − 1 0 MV = − 1 − 1 1 0 − 1 0 Matrice booleana dei Flag (True per valori diversi da 0): T T MB = T T F T F T F Matrice dei segni: F MB = F F F T F (In realtà, in quest’ultima matrice, i segni dei coefficienti uguali a 0, che qui non compaiono per chiarezza espositiva, sono automaticamente inizializzati a “False”). Così, una matrice di comunità 10x10 viene rappresentata in una matrice 10x10x3. L’informazione è decisamente ridondante, dato che il valore del coefficiente è univocamente individuato dalla combinazione degli altri dati. D’altronde la scelta di mantenere l’informazione “doppia” rende il programma più veloce: infatti, per trovare i paths e i loop è sufficiente sapere se il link esiste (ovvero se il coefficiente è diverso da 0) e, una volta individuati 64 i link, calcolare il segno “globale” del path o del loop (confrontando i segni dei link). Quindi si possono raccogliere i dati necessari andando ad interrogare variabili di dimensione 1 bit (variabili booleane), invece di prendere in considerazione variabili da 8 bit (valori interi). Mantenere comunque informazioni riassuntive (in questo caso il valore del coefficiente) è utile per la fase di visualizzazione dei dati all’utente, che può così manipolare coefficienti più comprensibili, e nella validazione dei dati immessi dall’utente, cioè nel controllo della coerenza (appartenenza all’insieme {-1;0;1}) dei coefficienti inseriti. 65 Capitolo 6 ALGORITMI “He deals the cards to find the answer, a secret geometry of chance, the hidden law, of a probable outcome, the numbers lead a dance” Sting – Shape of my heart Per calcolare la formula risolutiva illustrata nel Capitolo 2 un programma deve funzionare come una scatola nera che, preso in input il grafo (o meglio la matrice di comunità che il grafo rappresenta), sia in grado di: Trovare gli Open Path; Trovare i Loop; Calcolare il segno dell’Overall Feedback; Associare ogni Open Path al suo (suoi) Complementary Subsystem; Dare in output la tavola di predizione. Tutte queste operazioni sono compiute da Dr.Loop, grazie ad alcuni algoritmi appositamente sviluppati (o adattati). L’idea del programma è molto semplice: Trovare tutti gli Open path; Trovare tutti i Loop; Combinare i Loop in modo da trovare tutti i possibili Complementary Subsystems e l’Overall Feedback; Correlare ogni Open path con il suo Complemetary Subsystem; Produrre così la tavola di predizione; 66 Questo approccio, come tutti, ha vantaggi e svantaggi. I vantaggi principali sono: - E’ semplice da implementare, e una volta scritta una procedura, è facile generalizzarla (estenderla a N variabili); - Una volta trovati i percorsi e i sistemi complementari, il lavoro è praticamente finito (anche in termini di tempo di esecuzione) Per vedere gli svantaggi, bisogna analizzare un altro modello di programmazione, abbastanza intuibile: 1: Cerca il primo open path; 2: Cerca il suo Complementary subsystem; 3: Cerca l’open path seguente; 4: Se esiste l’open path → Torna a 2 Altrimenti → Fine Questo tipo di programmazione ha come principale vantaggio il fatto di ricercare esclusivamente i sottosistemi complementari che hanno un corrispettivo nell’insieme degli open path, mentre nell’algoritmo utilizzato vengono segnalati anche quelli “inutili”. Questo porterebbe indubbiamente ad una diminuzione del tempo di esecuzione per grafi piccoli o con molti selfloop. Il comportamento è però diverso per quanto riguarda i grafi molto grandi: qui lo stesso Complementary Subsystem è correlato a molti open path, e quindi doverlo cercare più (leggi “migliaia di”) volte risulterebbe decisamente estenuante. Il ragionamento che sta alla base della scelta è intuibile: l’utente preferisce una prestazione inferiore quando i grafi sono semplici. Si supponga che l’algoritmo utilizzato sia di molto peggiore dell’altro per grafi di piccole dimensioni: invece di 3 secondi, ne impiegherà 6. Quando invece si parla di decine di minuti, se il secondo algoritmo è meno efficiente anche solo del 10% rispetto a quello da utilizzato, i tempi di esecuzione diventano decisamente più pesanti (su un’ora c’è una perdita di 6 minuti). 67 Il linguaggio con cui sono illustrati gli algoritmi è un Visual Basic semplificato, in modo da renderli più chiari possibile. In realtà, tutto il software è realizzato in Borland Delphi 5.0, un linguaggio ad oggetti basato sull’Object Pascal. 1. Trovare gli open path Per trovare tutti gli open path si è utilizzata una visita al grafo basata sugli alberi. In realtà è un algoritmo molto semplice, una volta chiarito il significato di ricorsione. Si dice che una funzione è ricorsiva quando richiama sé stessa. La funzione viene chiamata la prima volta con determinati parametri, e richiamata all’interno della stessa con parametri diversi. Il processo va avanti fino a una condizione di uscita, e può essere schematizzato con un piccolo programma che controllale parentesi di una equazione: Dim quante As Integer Dim s As String Private Sub PrimaChiamata(ByVal quante_parentesi As Integer) quante = quante_parentesi 'n° di parentesi da creare s = "" par (quante - 1) MsgBox (s) End Sub Private Sub par(ByVal i As Integer) If i >= 0 Then ‘se I è <0 allora esce s = s & "(" par (i - 1) ‘richiama diminuito s = s & ")" End If End Sub 68 se stessa con i Inserendo quante_parentesi il programma ritorna una stringa fatta di parentesi aperte e chiuse. Es: quante_parentesi=4 → il programma ritorna “(((())))” Ora, passando alla Loop Analysis: In input si ha un equivalente della matrice di comunità composta da variabili booleane (true/false): se è presente un coefficiente ≠ da 0 la variabile corrispondente nella nuova matrice sarà True, altrimenti False. Il numero di variabili del sistema è Nvar Type Path(1 To Nvar) As Integer Dim Matrice(1 To Nvar, 1 To Nvar) As Boolean Private Function trovapath(ByVal node As Integer, ByVal liv_ As Integer, ByVal Percorso as Path) Dim x As Integer Dim y As Integer Dim LLoop As Boolean If liv = 0 Then Call segnapath(node, liv, Percorso) End If liv = liv + 1 'percorso di livello incrementato For x = 1 To Nvar LLoop = False If Matrice(x, node) = True Then Percorso(liv) = x For y = 0 To liv - 1 If Percorso(y) = Percorso(liv) Then 'se si passa 2 volte per la stessa var LLoop = True Percorso(liv) = 0 End If If (liv > 0) And (LLoop = False) Then Call segnapath(node, liv, Percorso) If Not (liv >= Nvar) Then Call trovapath(x, liv, Percorso) End If End If Next y Next x End Function 69 Come funziona: Molto semplicemente si parte da una variabile, e si richiama la funzione ogni volta che si trova un link tra questa e un’altra variabile. Quello che si forma man mano che il processo va avanti è un albero, dove ogni percorso che va dalle foglie alla radice rappresenta un open path: infatti ogni volta che viene trovata due volte la variabile nel percorso, il processo si ferma (il ramo si “secca”): si è in presenza di un loop. La funzione viene richiamata per ogni variabile perché, nonostante la perdita di prestazioni, è molto importante avere le tabelle in cui sono organizzati i dati, divise secondo la variabile di partenza. L’organizzazione del database rispecchia questa esigenza. Ci sono 30 tabelle (P1,…,P30), dove per ogni record vengono salvati i dati essenziali alla Loop Analysis: ID: Identificatore unico del percorso Var1: 1° variabile … Var30: 30° variabile (se esiste) Circ: N° di variabili implicate Chiave: Intero a 32 bit che indica quali variabili sono coinvolte (si veda 6.3) Segno: Variabile True/False che indica il segno totale del percorso Fin: Variabile di arrivo. Questa informazione è ridondante ma comoda, dato che la posizione della variabile di arrivo all’interno della tabella dipenderebbe altrimenti dalla lunghezza del path. 2. Trovare i Loop Per trovare i loop si può semplicemente modificare l’algoritmo precedente, in modo che continui la ricerca fino a quando non trova due volte la stessa variabile. Il problema è che così i loop verrebbero trovati in più di una copia (Es. [ABC] = [BCA] =[CBA]), e filtrare i doppi 70 significherebbe una ricerca su tutta la tabella per ogni loop trovato. Considerando le dimensioni delle tabelle, è improponibile. Bisogna cercare di trovare ogni loop una sola volta. Per fare questo l’algoritmo è stato così modificato: a) Trovare tutti i loop che contengono una variabile; b) Modificare il grafo (matrice) eliminando la variabile; c) Ripetere l’operazione sul nuovo grafo con un’altra variabile; d) … e) Fino all’ultima variabile; Con questo processo la prima chiamata alla funzione effettuerà n operazioni per completare l’albero, mentre la seconda chiamata ne effettuerà m, con n>>m, e il numero è destinato a decrescere esponenzialmente. Per facilitare questo processo, dato che il primo albero ha la stessa complessità indipendentemente dalla variabile-radice, è conveniente partire dalla variabile più connessa, in modo che il secondo albero sia molto più piccolo. Prendere le variabili in ordine di connettanza fa diminuire il numero di operazioni di un fattore 10: TowerTank Delaware Marine Lake35 N° Var Std. Pota + Self In ordine N°loop Conn. % risp 13 333 171 84 36 3,000 75% 18 4.183 1.887 479 85 3,428 89% 21 8.710 4.567 852 178 3,277 90% 35 87.884.368 70.807.065 3.721.942 385.647 3,828 96% In questa tabella sono riportati il numero di loop presenti (N° loop) nei sistemi studiati, il numero di variabili da cui sono composti (N° Var), e la loro connettanza (Conn.). E’ poi riportato il numero di “chiamate” alla funzione (Std.), e il numero di chiamate dopo aver raffinato l’algoritmo con alcune procedure (Pota+Self), e dopo aver preso le variabili in ordine di connettanza (In ordine). Si noti che il numero di ricorsioni decresce di un ordine di grandezza. 71 In pseudo-codice l’algoritmo diventa: Type Path(1 To Nvar) As Integer Dim Ordine (1 to Nvar) As Integer Dim Matrice(1 To Nvar, 1 To Nvar) As Boolean Private Function Loop(ByVal node As Integer, ByVal liv As Integer, ByVal Percorso as Path) Dim i As Integer For i=1 to Nvar Trovaloop (Ordine(i)) ‘in questo array le variabili ‘sono in ordine di connettanza Cancella_Var (Ordine(i)) ‘ toglie la variabile dal ‘grafo Next i End Sub Private Function trovaloop(ByVal node As Integer, _ ByVal liv As Integer, ByVal Percorso as Path) Dim x As Integer Dim y As Integer Dim LLoop As Boolean If liv = 0 Then Call segnapath(node, liv, Percorso) End If liv = liv + 1 'percorso di livello incrementato For x = 1 To Nvar LLoop = False If Matrice(x, node) = True Then Percorso(liv) = x For y = 0 To liv - 1 If Percorso(y) = Percorso(liv) Then 'se si passa 2 volte per la stessa var LLoop = True SegnaLoop(liv) = 0 ‘scrive il loop nella giusta tabella End If If (liv > 0) And (LLoop = False) Then If Not (liv >= Nvar) Then Call trovaLoop(x,liv, Percorso) End If End If Next y Next x End Function Anche l’organizzazione dei database è simile a quella degli open path. La principale differenza consiste nel fatto che i loop sono immagazzinati per 72 lunghezza (livello) e non per variabile di partenza, perché questa non esiste. I dati sono contenuti in 30 tabelle (L1,…,L30). Ogni record è composto da: ID: identificatore unico del percorso Var1: 1° variabile … Var N: N-esima variabile Circ: n° di Circuiti (vedi il prossimo paragrafo) Chiave: Intero a 32 bit che indica quali variabili sono coinvolte (vedi 6.3) Segno: Variabile True/False che indica il segno totale del loop 3.Trovare i Feedbacks Il processo ci porta quindi ad avere: Æ Tutti gli Open Path; Æ Tutti i Loop; Il problema successivo è quello di aggregare i loop nei feedback complementari. Anche qui la necessità è di trovare ogni membro di Fn in una sola copia, filtrando gli eventuali doppi. L’assemblaggio dei feedback ricorda da vicino la funzione “partizione di un numero naturale”: infatti F3 è composto da - Loops di livello 3 Æ(3) - Loops di livello l + Loops di livello 2 Æ(1+2) - Loops di livello l + Loops di livello l + Loops di livello l Æ (1+1+1) Così F5 è dato da 5; 4+1; 3+2; 3+1+1; 2+1+1+1;1+1+1+1. Stranamente (o no?), il problema delle partizioni di un numero intero è stato studiato a fondo da Eulero, padre putativo della teoria dei grafi.Il numero di partizioni di un numero naturale è: p (n ) ≅ e k ⋅ n , dove k = π 2 . 3 73 Tornando al problema bisogna sottolineare che i loop che compongono ogni membro di Fn devono essere disgiunti. Il problema può essere quindi scomposto in due distinti sottoproblemi: - Individuare i loop disgiunti; - Combinarli in modo da ottenere tutti i livelli di feedback; Il primo sottoproblema è stato affrontato creando una chiave a 32 bit in questo modo: Chiave Å 0 Se è presente “Var 1” allora ChiaveÅChiave + 2 Se è presente “Var 2” allora ChiaveÅChiave + 22 Se è presente “Var 3” allora ChiaveÅChiave + 23 … Se è presente “Var 30” allora ChiaveÅChiave + 230 In questo modo il valore di Chiave =24 o, in binario, 11000, ci dice che sono presenti nel loop le variabili 3 e 4; con un valore di Chiave = 50 (110010) si ha che il loop è formato dalle variabili 1,4,5. A questo punto si può affermare che due loop sono disgiunti se l’operatore AND bit a bit tra i loro valori di chiave dà risultato 0. Es. 110110 Æ Var1,Var2,Var4,Var5; 001000 Æ Var3; __________ Operatore AND BitWise 000000 Æ I loop sono disgiunti 100110 Æ Var1,Var2,Var5; 111000 Æ Var3,Var4,Var5; __________ Operatore AND BitWise 100000 Æ I loop NON sono disgiunti 74 La Chiave è quindi un vettore booleano, che si legge da destra a sinistra, in cui è immagazzinato uno 0 se la variabile non è presente, un 1 se invece fa parte del loop. Per trovare tutte le combinazioni presenti si è utilizzato un algoritmo più complesso. Dato che all’aumentare del livello di n, il numero di partizioni aumenta considerevolmente, si deve procedere in modo da minimizzare lo spreco di risorse. E’ stata elaborata una procedura che, prese in input tre tabelle, trova le combinazioni dei records (loop) delle prime due e le inserisce nella terza. Così, chiamando Combina(1,1,2), si prendono a due a due tutti i loop disgiunti contenuti nella tabella L1 e li si inseriscono in L2. Questa procedura ha una struttura che può essere così schematizzata: - AÅPrimo record della prima tabella; - BÅPrimo record della seconda tabella; - A e B Sono disgiunti? Se sì, inserisci il record risultante (A+B) nella terza tabella, altrimenti vai avanti; - Spostati in avanti di un record nella seconda tabella e assegnalo a B; - A e B Sono disgiunti? … Il ciclo si ripete fino a quando non sono stati analizzati tutti i records della seconda tabella rispetto al primo record della prima. Fatto questo, ci si sposta avanti di un record nella prima tabella e si ripete tutta la procedura. Si continua fino a quando non sono terminati i records della prima tabella. Ora, dopo aver chiamato Combina (1,1,2), nella tabella L2 sono presenti tutti gli elementi di F2, ovvero tutti i loop di livello 2 e tutte le 75 combinazioni di 2 self-loop disgiunti. Per semplicità si affermerà che in L2 sono presenti {2;1+1}. Chiamando Combina (1,2,3), si ottengono tutti gli elementi di F3, perché si vanno a inserire sia i “2+1” che gli “(1+1)+1”, visto che in L2 sono già presenti le combinazioni di self-loop. Così F3 è completo: {3;2+1;1+1+1}. Il problema però si complica quando si vuole riempire F4. Infatti se si chiamasse solo Combina(1,3,4) si otterrebbero solo gli elementi {4,3+1,2+1+1,1+1+1+1}, ma non {2+2}. Quindi è necessario chiamare Combina due volte, una con argomenti (1,3,4), l’altra con (2,2,4). Generalizzando si può dire che per completare il livello di Feedback N sono necessarie (N−1) /2 chiamate alla funzione se N è dispari, N/2 chiamate quando N è pari. Per riempire tutti i livelli di feedback in un grafo di 30 variabili bastano “solo” 225 chiamate alla funzione, che sono poche rispetto al numero di partizioni (1,2106). 4. Tavole di predizione Lo scopo di tutti gli algoritmi presentati fino a questo punto è quello di trovare tutti gli open paths e di completare tutti i livelli di feedback. Ora, compilare la tavola di predizione è abbastanza semplice: - L’Overall Feedback è dato dalla tabella Ln, dove n è il numero di variabili che compongono il grafo. - L’ ultimo passo è quello di correlare ad ogni path il relativo Complementary Subsystem. Per fare questo, il programma prende in considerazione ogni open path (di lunghezza l), e controlla se esistono records nella tabella L(n−l) che non hanno variabili in comune con il path preso in considerazione. Più precisamente: 76 - Si parte da P1, e si controlla per ogni record se esiste nella tabella L(n−Circ) un record per cui “Chiave Loop” and bitwise “Chiave Path” = 0. - Se esiste, si calcolano i segni e si inserisce il risultato nella cella della tavola di predizione di coordinate (Var1 del Path, Fin del Path), ossia nella riga della variabile d partenza e nella colonna della variabile di arrivo del path. Ovviamente possono esserci più path che vanno dalla variabile X alla variabile Y. Per questo vengono memorizzati due dati per ogni cella della tavola di predizione: risultati positivi e risultati negativi. Dopo aver ripetuto il processo per tutti i path del sistema, si controlla ogni cella. Se contiene solo risultati “+” il risultato finale sarà “+”, se solo “−” allora sarà “−”. Se invece si hanno risultati discordi si sarà in presenza di una ambiguità. La cella conterrà perciò “?”, in accordo con la simbologia della Loop Analysis. 5. Simulare i percorsi ambigui Quando ci si imbatte in percorsi ambigui la Loop Analysis non riesce a dare risposte sull’evoluzione del sistema per particolari variabili. Per sopperire a questa mancanza di informazione si è sviluppato un algoritmo che permette di valutare la forza di ogni percorso che prende parte alla formazione dell’ambiguità. Le tesi di partenza sono: - A ogni passaggio per un link vi è una perdita di energia; - I links che escono da una variabile hanno forza inversamente proporzionale al numero di legami in uscita. Biologicamente queste scelte si possono giustificare: Ad ogni passaggio (fotosintesiÆ produttori primari Æconsumatori Æ…) si ha dissipamento di energia. 77 Una specie specializzata nella predazione di un’altra, avrà un singolo link molto forte, mentre specie che predano più popolazioni – variabili differenti avranno più links di minore intensità. Il grafo diventa equivalente ad una catena di Markov in cui la somma dei links che escono da una variabile è 1. Si può quindi fare un parallelo tra probabilità e legami in uscita: se un “quanto” di energia entra nella variabile X, esce attraverso uno dei links, con probabilità uguale all’intensità relativa del legame. La simulazione è effettuata da un software indipendente, SimLoop, che prende in input la matrice di comunità e una tabella di database in cui sono stati inseriti tutti i percorsi e sottosistemi che stanno alla base delle ambiguità del sistema. Questa tabella, amb.db, è così strutturata: Id: Identificatore unico del record; AmbFrom: Variabile di partenza; AmbTo: Variabile di arrivo; C1: 1° Casella implicata nel percorso / sottosistema ambiguo; V1: Valore di simulazione della casella; C2: 2° Casella implicata nel percorso / sottosistema ambiguo; V2: Valore di simulazione della casella; … … Segno: Segno totale di percorso e sottosistema; Somma: Somma di tutti i valori; Si noti che non vengono esplicitate le variabili implicate nel percorso, come nelle altre tabelle, ma le caselle della matrice di comunità, cioè i links. Ogni casella infatti si può individuare univocamente con una coppia di numeri (coordinate). Queste coordinate, essendo la matrice finita, possono essere sintetizzate in un solo valore, il che equivale a dire che le caselle possono essere numerate. Il numero di casella si ottiene “contando” le celle a partire 78 dall’angolo in alto a sinistra e procedendo sulla stessa riga fino alla fine. Terminata la riga si va a capo e si ripete l’operazione. Es. Sistema con 10 variabili; 3° riga, 2° colonna Æ identificatore della cella = 32; Sistema con 8 variabili; 4° riga, 8° colonna Æ identificatore della cella = 32; In questo modo il lavoro di simulazione risulta facilitato: a) Si assegnano valori casuali alle caselle della matrice di comunità (ovviamente se non è presente il link il valore rimane 0). b) Si normalizzano i valori per riga; c) All’interno di ogni percorso-sottosistema (record) della tabella si inseriscono i valori calcolati per ogni cella, nel relativo campo (Es. Se il valore di C1 è 5 si inserirà in V1 il valore normalizzato contenuto nella 5° casella). d) Si moltiplicano i valori per ogni record e li si assegna al campo “Somma”, associandovi poi il segno contenuto nel campo “Segno”. In realtà non si moltiplicano i valori, ma innanzitutto si inseriscono nel database i logaritmi naturali dei valori normalizzati, dopo di che sommare le celle del record equivale a moltiplicare i valori normalizzati. Il risultato della somma viene poi riconvertito tramite la funzione esponenziale di e. Questa procedura è compiuta per due motivi: - Le operazioni di moltiplicazione in virgola mobile sono molto “faticose” per la CPU; - Il risultato diminuisce di circa un fattore 10 ad ogni passaggio (moltiplicazione), dato che questo viene di volta in volta moltiplicato per un numero inferiore a 1. Sommando si diminuiscono i rischi di underflow. Quando la tabella è stata compilata, si confrontano i records che hanno stessa variabile di partenza e di arrivo. Si sommano i vari risultati e per ogni 79 casella si aggiunge un risultato positivo se la somma di tutti questi records è maggiore di 0, un risultato negativo se invece è inferiore a 0. Reiterando la procedura si ottiene una stima della probabilità dei vari risultati: Es. +/− N A1 A2 H1 H2 C N 15/85 48/52 100/0 A1 80/20 44/56 41/59 34/66 0/100 51/49 A2 66/34 53/47 H1 H2 71/29 89/11 79/21 83/17 21/79 79/21 C 0/100 60/40 26/74 15/85 86/14 46/54 Dove ogni cella contiene Positivi/Negativi. Questo è l’output di un sistema con 6 variabili, dopo una simulazione effettuata 100 volte: è interessante notare che alcune ambiguità sono solo apparenti (ad esempio gli effetti di C su N, N su C, H2 su A1, danno un risultato univoco: su 100 simulazioni il risultato è sempre lo stesso!). Per un’analisi più accurata dei risultati si veda il prossimo capitolo. 80 Capitolo 7 RISULTATI “Legge di Hofstadter Ci vuole sempre più tempo di quanto si pensi, anche tendendo conto della legge di Hofstadter” Douglas R. Hofstadter – Gödel, Escher, Bach: un’Eterna Ghirlanda Brillante Tutto il lavoro è stato impostato su due principali obiettivi: a) Creare dei software in grado di effettuare la Loop Analysis su sistemi di grandi dimensioni; b) Riuscire a simulare quantitativamente i percorsi che causano ambiguità e ampliare così le capacità predittive della metodologia. Questi due obiettivi sono strettamente collegati: è infatti necessario disporre, ai fini della simulazione, di una notevole quantità di dati interpretabili da software. E’ stato quindi naturale creare non un solo programma, ma un pacchetto in grado di gestire autonomamente tutte le fasi della Loop Analysis e della simulazione. Il risultato più tangibile del lavoro è quindi composto da tre software: DrawLoop: Questo programma permette, tramite una semplice interfaccia grafica, di disegnare i grafi orientati, compilando automaticamente la matrice di comunità; Dr. Loop: Prende in input la matrice di comunità e la analizza con i metodi della Loop Analysis, fornendo all’utente la tavola di predizione. Tutte le operazioni avvengono con l’ausilio di un database Paradox, in cui sono immagazzinate le informazioni che vengono via via prodotte. Una tabella di questo database contiene tutti i percorsi che producono ambiguità. 81 SimLoop: Se esistono ambiguità, questo programma assegna dei valori casuali a tutti i coefficienti dei percorsi e sottosistemi complementari che partecipano all’ambiguità. Reiterando questo processo più volte, produce una tavola che stima i rapporti di forza tra i segni che producono l’ambiguità. L’organizzazione Input/Output può essere perciò rappresentata con un grafo: Draw Loop Immagine Dr. Loop Matrice di comunità Tavola di predizione SimLoop Ambiguità L’utente può inserirsi in due diversi “nodi” e ha la possibilità di uscire con diversi risultati. Se è interessato ad avere una rappresentazione grafica del sistema, utilizza DrawLoop e ottiene una immagine bitmap e la matrice di comunità. Se vuole analizzare un grafo che ha già chiaro, può saltare la rappresentazione grafica e inserire manualmente la matrice di comunità in Dr.Loop, ottenendo la tavola di predizione. A questo punto, può accontentarsi del risultato della Loop Analysis “classica” o, in caso di ambiguità, testare come queste reagiscano alla simulazione quantitativa, utilizzando SimLoop. I risultati sono dei files di testo formattati, in modo da essere interpretabili da qualsiasi piattaforma e Word Processor, ma anche semplici da importare in programmi per il trattamento dei dati (come Excel) o in database. 82 Tutto il software è stato realizzato con Borland Delphi 5.0, ed è completamente freeware. Nel CD-ROM allegato è contenuto il codice, che è liberamente distribuibile. Per funzionare, il pacchetto richiede l’installazione del Borland Database Engine (BDE), che è contenuto nei files di installazione e che può essere scaricato gratuitamente dal sito internet della Borland-Inprise www.borland.com. 1. Prestazioni I programmi sono stati testati su piattaforme Microsoft Windows 98 e Windows 2000, ma funzionano su tutte le versioni Windows a 32 bit (95, 98, NT 4 o successive, 2000, ME). I tempi di esecuzione si riferiscono a un PC Pentium III 450 MHz con 128 Mb di RAM. DrawLoop DrawLoop è in grado di disegnare sistemi di 25 variabili al massimo, e salva l’immagine prodotta in una bitmap di 640x480 pixel. Dr.Loop Il programma è in grado di analizzare sistemi di 30 variabili al massimo, ma esiste un limite dettato dal numero di records che una tabella Paradox può contenere: 2∙109. Questo limite impedisce di analizzare sistemi molto connessi formati da più di 10/15 variabili. La connettanza del grafo e il numero di self-loop e loop di basso livello sono i principali fattori che regolano il tempo di esecuzione. Infatti, nell’economia del programma, la parte più complessa è la combinazione dei loop per formare i livelli di feedback: essa, solitamente, occupa circa la metà del tempo di esecuzione. I loop più piccoli si possono combinare in moltissimi modi per formare i feedback di alto livello, aumentando più che esponenzialmente il numero di records da compilare, scrivere e ricombinare. 83 SimLoop Anche in questo caso i tempi di esecuzione sono strettamente correlati alle caratteristiche del sistema. Il programma è concepito in modo da lasciare l’utente libero di dimensionare la simulazione, perché possa agire direttamente sulla lunghezza del tempo di calcolo. Infatti, può scegliere se ripetere il processo 1, 10, 100 o 1000 volte, a seconda del numero di percorsi coinvolti e del numero di variabili del sistema. Provando a simulare una sola volta può rendersi conto di quanto il software impiega per ogni elaborazione, scegliendo poi quante volte ripeterla. E’ inoltre presente una textbox (casella in cui si può scrivere direttamente), in cui è possibile inserire il numero di ripetizioni desiderato (compreso tra 1 e 9999). 2. Risolvere tutte le ambiguità? Il secondo obiettivo è teorico-analitico: il tentativo di risolvere, almeno in parte, le ambiguità che emergono dall’analisi di sistemi sufficientemente connessi. La strada scelta, come già esposto nei Capitoli 4 e 6, è stata quella di simulare quantitativamente i percorsi e i loop che causano questo fenomeno. Dopo una prima analisi dei risultati, sembra possibile suddividere le ambiguità in due grandi classi: Ambiguità formali: Con questo termine si vogliono indicare le ambiguità immediatamente risolte dalla simulazione, e che sono tali in virtù della rigida schematizzazione operata nel supporre i links appartenenti all’insieme {−,0,+}. Nel caso di piccoli sistemi, alcune di queste ambiguità possono essere risolte anche con valutazioni dettate dal buon senso (ad esempio un’ambiguità formata da 10 segni positivi e da un solo segno negativo…). Nel caso di sistemi di discrete dimensioni, questa operazione è molto più 84 complessa e perciò la simulazione torna utile per velocizzare e razionalizzare il procedimento. Un altro aspetto interessante della simulazione è la possibilità di valutare la “forza” del percorso: nella Loop Analysis i path e i loop trasferiscono energia (nel senso più ampio del termine) senza nessun tipo di perdita. Un segno + ottenuto dopo 1000 passaggi (1000 links) è assolutamente equivalente ad un segno + ottenuto dopo 1 passaggio (1 link). Al contrario, nella simulazione si ha solitamente una diminuzione di un ordine di grandezza ad ogni passaggio. Ambiguità strutturali: Si definiscono con questo termine le ambiguità “resistenti” alla simulazione, quelle in cui non si ha la netta prevalenza di un segno dopo n ripetizioni. Queste ambiguità presentano notevoli aspetti di simmetria nella costituzione: percorsi di segno opposto costituiti approssimativamente dallo stesso numero di links, provenienti da nodi con struttura simile. In questi casi non è raro trovare risultati come 499 “+” vs. 501 “−” dopo mille simulazioni. Un risultato simile può suggerire due ipotesi: a) Il sistema è intrinsecamente ambiguo e quindi, se c’è evidenza sperimentale di un comportamento definito, lo si deve ascrivere a variabili che non sono state prese in considerazione. b) Le ambiguità sono in realtà inesistenti, in quanto il contributo dei due segni è identico, e quindi quantitativamente nullo una volta sommato. Questo effetto si può rappresentare come lo scontro tra due onde di pari intensità e lunghezza d’onda ma di fase diversa (es. Sen x e –Sen x). I percorsi non hanno intensità nulla, ma è nullo l’effetto prodotto (la “somma” degli effetti). Quindi non è possibile, con l’ausilio della simulazione, eliminare tutte le ambiguità, a meno che non si corretta giusta l’ipotesi b). 85 Si possono individuare alcune linee di ricerca potenzialmente utili per chiarire la natura formale delle ambiguità e del loro significato nei sistemi reali. Una strada possibile è quella di ampliare la gamma dei rapporti intercorrenti tra le variabili. Al posto del segno, si potrebbe sviluppare una classificazione più articolata, come ad esempio ++, +, 0, −, − − ossia forte interazione positiva, debole interazione positiva, nessuna interazione, debole interazione negativa, forte interazione negativa. Mantenendo la forma delle equazioni differenziali, si potrebbero indicare come “forti interazioni” quei coefficienti che contengano variabili in forma quadratica o superiore (cioè non lineare). Questo si scontra con le assunzioni fatte sulla stabilità (i sistemi devono essere linearizzabili), e quindi sarebbe necessario ricucire ed adattare tutti i metodi di calcolo, per riuscire a giustificare l’ampliamento della gamma di valori per i legami. Un’altra strada è quella della simulazione per i legami non misurabili, e la misura delle interazioni quantificabili. Questo è sicuramente più semplice, ma richiede una grande mole di lavoro sperimentale. Ogni sistema andrebbe infatti studiato nei dettagli, per individuare i rapporti chiave da misurare. Una volta stimati, questi link rimarrebbero fissi, mentre gli altri andrebbero simulati. Il problema che si pone, oltre a quello spesso insormontabile della misurazione, è che le misure fatte per un sistema non hanno nessun valore per un sistema anche simile. Si andrebbe perciò ad intaccare il patrimonio di generalità dei modelli qualitativi. Un’ultima strada è quella di correlare le ambiguità “resistenti” a particolari situazioni topologiche, trovando degli indici che esprimano la “resistenza potenziale” dell’ambiguità. Un esempio molto semplice di indice è quello già utilizzato da Puccia e Grant nel loro software “Loops”, dove si calcola il rapporto tra i segni positivi e negativi che partecipano all’ambiguità: se il rapporto è sbilanciato (c’è una preponderanza di uno dei 86 due segni) è più probabile il segno maggiormente rappresentato. Si possono creare anche indici più raffinati, che tengano conto della connettanza della variabile di arrivo, del numero di variabili implicate, ecc. Questo lavoro ha reso disponibile un software di facile utilizzo per analizzare i sistemi formati da un numero consistente di variabili, e ha introdotto la simulazione come metodologia integrativa, e non sostituiva o alternativa, della Loop Analysis. 87 RIFERIMENTI BIBLIOGRAFICI CAPITOLO 1 DE ANGELIS, D. L., GROSS, L.J. Individual-based models and approaches in ecology, New York, 1992 Chapman and Hall LEVINS, Richard The strategy of model building in population biology, in “American 1966 Scientist”, Vol. 54 No 4, December PUCCIA, Charles J., LEVINS, Richard Qualitative Modeling of Complex Systems, Cambridge, Harvard 1985 University Press CAPITOLO 2 LEVINS, Richard Qualitative Analysis of partially specified systems, in “Annals of the 1974 New York Academy of Sciences” 231/1974 LEVINS, Richard Evolution in communities near equilibrium, in “Ecology and 1975 Evolution of Communities”, a cura di M. Cody, J.M. Diamond, Cambridge, Harvard University Press, MASON, S. Feedback theory - some proprieties of signal flow graphs, in 1953 “Proceedings of the IRE”, 41/1953 MASON, S. Feedback theory - further proprieties of signal flow graphs, in 1956 “Proceedings of the IRE”, 44/1956 CAPITOLO 3 CESARI, Lamberto Asymptotic behavior and stability problems in ordinary differential 1959 equations, Springer-Verlang, Berlin LANG, Serge Linear Algebra, Springer-Verlang, New York 1987 PRODI, Giovanni, Metodi matematici e statistici, Milano, McGraw-Hill, 1992 88 BIBLIOGRAFIA RAGIONATA CAPITOLO 2 La Loop Analysis è trattata sistematicamente in: PUCCIA, Charles J., LEVINS, Richard, Qualitative Modeling of Complex Systems, Cambridge, Harvard University Press, 1985 CAPITOLO 3 Per una trattazione più accurata delle equazioni differenziali e del loro utilizzo in biologia ed ecologia: CAPELO, António C., Modelli matematici in biologia, Padova, Decibel editrice, 1989 PRODI, Giovanni, Istituzioni di matematica, Milano, McGraw-Hill, 1994 PRODI, Giovanni, Metodi matematici e statistici, Milano, McGraw-Hill, 1992 Per una trattazione approfondita delle equazioni differenziali: CONTI, Franco, Calcolo teoria e applicazioni, Milano, McGraw-Hill, 1993 CAPITOLO 5 La teoria dei grafi è trattata in: ORE, Oystein, I grafi e le loro applicazioni, Bologna, Zanichelli, 1979 ROBIN, J. Wilson, Introduzione alla teoria dei grafi, Roma, Cremonese, 1978 Queste pubblicazioni sono piuttosto datate. Molte informazioni si possono trovare in Internet con una query semplice in un qualsiasi motore di ricerca (keywords: “Graph Theory”, “Digraphs”) CAPITOLO 6 Per una esaustiva trattazione degli algoritmi per l’analisi dei grafi: CORMEN Thomas H., LEISERSON, Charles E., Introduction to algorithms, a cura di Ronald L. Rivest Cambridge, MIT Press, 1990 89 RINGRAZIAMENTI Desidero ringraziare innanzitutto il dott. Alessandro Zaccagnini e il dott. Antonio Bodini, che sono stati un modello (qualitativo e quantitativo) di relatore di tesi. Un ringraziamento particolare va agli sviluppatori di “Loops”, Roger Day e Charles Puccia, per avermi fornito il codice sorgente del software. Grazie anche al prof. Rossi e al dott. Bagnara per le consulenze in campo informatico. Un ultimo, ma meritatissimo ringraziamento va ad Elena Rizzo, per aver pazientemente e diligentemente corretto le mie bozze, e per tutto il resto. Carpi, Aprile 2001 Stefano Allesina 90