Sei sulla pagina 1di 11

yaC-Primer: Automi Cellulari

(Rev. 2.0.3)

1 Automi Cellulari

(Rev. 2.0.3)

Gli automi cellulari sono una classe di modelli introdotti originariamente da von Neumann e Ulam nel 1948 come una semplice idealizzazione dellevoluzione delle cellule a livello cellulare. Un automa cellulare pu` o essere pensato come un insieme di cellette il cui stato pu` o assumere un numero nito di stati discreti. Nellipotesi pi` u semplice la celletta pu` o trovarsi in soli due stati: 1 celletta viva o 0 celletta morta. Lo stato delle singole cellette cambia nel tempo a seconda dello stato delle cellette vicine. Ad esempio se ci sono troppe cellette vicine vive, la celletta muore. Questi modelli sono un tipico esempio del processo di riduzione utilizzato in sica nellanalisi di sistemi complessi. Il punto di partenza ` e che fenomeni complicati possano essere originati da poche leggi semplici. Sotto questa ipotesi, si cercano quindi modelli semplici che basati su queste leggi riproducano il comportamento dei sistemi pi` u complicati. Al di l` a della loro rilevanza sica e/o biologica, questi modelli sono un esempio di un sistema dinamico discreto che pu` o essere simulato esattamente su un computer. Pi` u in dettaglio un automa cellulare ` e un sistema dinamico in cui: Lo spazio ` e discretizzato, ossia il sistema ` e denito su un reticolo; Le variabili di interesse sono denite solo sui siti del reticolo e possono assumere solo una sequenza discreta di valori; Il tempo ` e discreto per cui levoluzione avviene ad intervalli regolari; Lo stato delle variabili su ogni sito cambia ad ogni intervallo di tempo con una regola locale che dipende solo dallo stato del sito e dei suoi vicini. Levoluzione ` e parallela, ossia il valore delle variabili viene cambiato simultaneamente in tutti i siti. A causa della sua origine biologica spesso i siti di un automa cellulare sono chiamati celle, noi useremo indierentemente il nome cella o sito. Gli automi cellulari trovano una vasta applicazioni in molti campi della sica che vanno dalla uidodinamica alle galassie.

Automi Cellulari Unidimensionali


Lesempio pi` u semplice di automa cellulare sono gli automi cellulari Booleani Unidimensionali in cui i vicini di un sito sono il sito immediatamente a sinistra e quello immediatamente a destra. Le variabili denite su ogni sito possono assumere solo due valori (automa Booleano) che per comodit` a, e senza perdere di generalit` a, vengono indicati con 0 e 1. Lautoma di evolve nel tempo con una regola di evoluzione denita associando ad ogni congurazione di un sito e dei suoi due primi vicini il nuovo stato del sito:

yaC-Primer: Automi Cellulari


i1 t i

(Rev. 2.0.3)

i+1

rule

t+1

La regola di evoluzione pu` o essere facilmente espressa mediante una tavola che riporti nella prima riga le possibili congurazioni dei tre siti al tempo t e nella seconda il corrispondente lo stato del sito centrale al tempo successivo t + 1, come mostra il seguente esempio t t+1 111 0 110 1 101 0 100 1 011 1 010 0 001 1 000 0

I tre siti possono trovarsi in 8 congurazioni dierenti per cui vi sono 28 = 256 regole diverse. Le dierenti regole sono usualmente indicate con un codice numerico ottenuto scrivendo nella prima riga della tavola della regola i possibili stati dei tre siti ordinati da sinistra a destra in modo che corrispondano alla rappresentazione binaria dei numeri 7, 6, 5, 4, 3, 2, 1, 0 e leggendo ottenuto la seconda riga come rappresentazione binaria di un numero decimale. Il numero cos` rappresenta il codice numerico della regola. Ad esempio nel caso della regola espressa dalla tavola precedente si ha 01011010 0 27 + 1 26 + 0 25 + 1 24 + 1 23 + 0 22 + 0 21 + 0 20 = 90 per cui questa regola viene indicata come la regola 90. Dalla tavola si vede facilmente che questa regola equivale a prendere la somma modulo 2 dei siti vicini per cui questa ` e anche nota come la regola modulo 2, o regola xor perch` e lo stato dello spin al tempo t + 1 ` e1 solo e lo stato di uno solo dei suoi primi vicini ` e 1. Il seguente programma simula un automa cellulare Booleano unidimensionale. Il programma prende come input il codice numerico della regola, il numero di passi che si vuole eettuare ed informazioni sulla congurazione iniziale. Questultima pu` o essere sia random che data . Programma: cell aut-1d.c
/* *************************************************************** - Descrizione : Simulazione di un Automa Cellulare Booleano unidimensionale con condizioni periodiche al bordo. - Input : Numeri di siti dell automa Codice numerico regola Passi di evoluzione temporale

yaC-Primer: Automi Cellulari

(Rev. 2.0.3)

Configurazione iniziale random : seed e probabilita stato 1 Configurazione iniziale data posizioni siti con stato 1 - Output : Sul file OUT_F siti con stato 1 versus tempo - Parametri : OUT_F -> File output - $Id: cell_aut -1d.c v 1.3 14.11.04 AC **************************************************************** */ # include < s t d i o . h> # include <math . h> # include < s t d l i b . h> /* Macros */ # define OUT F " cell_aut .dat" /* sito automa cellulare */ typedef unsigned short int cell_t ; /* automa cellulare */ typedef struct { unsigned int size ; cell_t site ; } cellular_t ; /* Prototipi */ cell_t create_site void table_rule void bit_to_str void init_state void update_state

/* numero sito automa */ /* puntatore al primo sito */

( int n ) ; ( cell_t rule , cell_t rule_code ) ; ( char str , int nchar , int n ) ; ( cellular_t aut , unsigned long seed ) ; ( cellular_t aut , cell_t rule ) ;

int main ( void ) { int i; int n_step ; int step ; cellular_t automata ; cell_t rule [ 8 ] ; cell_t rule_code ; unsigned long seed ; char line [ 8 1 ] ; FILE fp ;

/* /* /* /* /* /* /* /* /*

indice sito automa # intervalli temporali contatore passi temp automa cellulare tavola regola codice numerico regola seme generatore n. r. input buffer puntatore file out

*/ */ */ */ */ */ */ */ */

/* Automa */ automata = ( cellular_t ) malloc ( sizeof ( cellular_t ) ) ;

yaC-Primer: Automi Cellulari

(Rev. 2.0.3)

if ( automata == NULL ) { fprintf ( stderr , "Non enough space for automata \n" ) ; return 1 ; } /* Parametri Automa */ printf ( " Numero siti automa fgets ( line , sizeof ( line ) , stdin ) ; sscanf ( line , "%ud" , &automata >size ) ; printf ( " Codice numerico regola fgets ( line , sizeof ( line ) , stdin ) ; sscanf ( line , "%hu" , &rule_code ) ; printf ( " Passi temporali fgets ( line , sizeof ( line ) , stdin ) ; sscanf ( line , "%d" , &n_step ) ;

: ");

: ");

: ");

printf ( "Seed condizione iniziale (== 0 fissa) : " ) ; fgets ( line , sizeof ( line ) , stdin ) ; sscanf ( line , "%lu" , &seed ) ; /* Tavola della regola */ table_rule ( rule , rule_code ) ; /* Variabili sul reticolo */ automata >site = create_site ( automata >size ) ; /* Inizializzazione Automa */ init_state ( automata , seed ) ; /* File di output */ fp = fopen ( OUT_F , "w" ) ; if ( fp == NULL ) { fprintf ( stderr , "File open failure \n" ) ; return 1 ; } /* Configurazione iniziale */ for ( i = 0 ; i < automata >size ; ++i ) { if ( automata >site [ i ] ) fprintf ( fp , "%d %d\n" , 0 , i + 1 ) ; } /* Evoluzione */ for ( step = 1 ; step <= n_step ; ++step ) { update_state ( automata , rule ) ; for ( i = 0 ; i < automata >size ; ++i ) { if ( automata >site [ i ] ) fprintf ( fp , "%d %d\n" , step , i +1); } } fclose ( fp ) ;

yaC-Primer: Automi Cellulari

(Rev. 2.0.3)

return 0 ; } /* ---* create_site () * */ cell_t create_site ( int n ) { cell_t c ; c = ( cell_t ) malloc ( n sizeof ( cell_t ) ) ; if ( c == NULL ) { fprintf ( stderr , " Memory allocation failure \n" ) ; exit ( 1 ) ; } return c ; } /* ---* table_rule () * */ void table_rule ( cell_t rule , cell_t rule_code ) { int i; char str [ 4 ] ; /* stampa le configurazioni */ fprintf ( stdout , " tavola regola | " ) ; for ( i = 7 ; i >= 0 ; i ) { bit_to_str ( str , 3 , i ) ; printf ( "%s " , str ) ; } printf ( "\n" ) ; fprintf ( stdout , " codice %3d | " , rule_code ) ; /* Tavola */ for ( i = 0 ; i <= 7 ; ++i ) { rule [ i ] = rule_code & 1 ; rule_code >>= 1 ; } /* stampa la tavola */ for ( i = 7 ; i >= 0 ; i ) { printf ( " %1d " , rule [ i ] ) ; } printf ( "\n" ) ; return ; }

yaC-Primer: Automi Cellulari

(Rev. 2.0.3)

/* ---* bit_to_str () * */ void bit_to_str ( char str , int nchar , int n ) { int i; unsigned int mask ; mask = 1 << ( nchar 1 ) ; for ( i = 0 ; i < nchar ; ++i ) { str [ i ] = ( ( n & mask ) != 0 ) ? 1 : 0 ; mask >>= 1 ; } str [ nchar ] = \0 ; return ; } /* ---* init_state () * */ void init_state ( cellular_t aut , unsigned long int seed ) { int i; double r; double p_one ; char line [ 8 1 ] ; if ( seed > 0 ) { /* configurazione random */ printf ( " Configurazione random : %d siti\n" , aut>size ) ; printf ( " Probabilita valore 1: " ) ; fgets ( line , sizeof ( line ) , stdin ) ; sscanf ( line , "%lf" , &p_one ) ; srand ( seed ) ; for ( i = 0 ; i < aut>size ; ++i ) { r = ( double ) rand ( ) / ( RAND_MAX + 1 . 0 ) ; aut>site [ i ] = ( r < p_one ) ? 1 : 0 ; } } else { /* configurazione data */ for ( i = 0 ; i < aut>size ; ++i ) { aut>site [ i ] = 0 ; } printf ( " Configurazione data: %d siti\n" , aut>size ) ;

yaC-Primer: Automi Cellulari

(Rev. 2.0.3)

printf ( " Specificare posizione siti 1\n" ) ; while ( 1 ) { printf ( " Posizione ( =< 0 fine ): " ) ; fgets ( line , sizeof ( line ) , stdin ) ; sscanf ( line , "%d" , &i ) ; if ( i < 1 | | i > aut>size ) break ; if ( ! aut>site [ i 1]) { aut>site [ i 1] = 1 ; } else { printf ( "Sito non valido , gia scelto \n" ) ; } } } return ; } /* ---* update_state () * */ void update_state ( cellular_t aut , cell_t rule ) { int i; /* indice sito int im1 , ip1 ; /* indice sito a sx e dx int conf_index ; /* codice num conf 3 siti cell_t new_site ; /* nuova configurazione aut

*/ */ */ */

/* configurazione temporanea per evoluzione parallela */ new_site = create_site ( aut>size ) ; /* Usiamo condizioni periodiche al bordo /* Vicino a sinistra di 0 e N -1 /* Vicino a destra di N -1 e 0 for ( i = 0 ; i < aut>size ; ++i ) { im1 = ( i1 + aut>size ) % aut>size ; ip1 = ( i +1) % aut>size ; conf_index = 4 aut>site [ im1 ] + 2 + aut>site [ ip1 ] ; new_site [ i ] = rule [ conf_index ] ; } for ( i = 0 ; i < aut>size ; ++i ) { aut>site [ i ] = new_site [ i ] ; } free ( new_site ) ; return ; }  */ */ */

aut>site [ i ]

yaC-Primer: Automi Cellulari

(Rev. 2.0.3)

Il programma utilizza per lautoma cellulare loggetto automata di tipo cellular t che contiene la sia il numero di celle dellautoma, campo size, che il puntatore alla prima cella dellautoma, campo site. Da momento che ciascuna cella pu` o assumere solo il valore 0 o 1 le celle sono di tipo cell t denito come unsigned short int. Le celle dellautoma sono create con la funzione create site()
automata >site = create_site ( automata >size ) ;

che alloca lo spazio di memoria per le automata->size celle dellautoma e ritorna il puntatore alla prima cella. Tavola: funzione table rule() Il programma utilizza direttamente la tavola della regola che associa a ciascuna delle 8 congurazioni di tre siti consecutivi il nuovo valore del sito centrale. Questa scelta non ` e necessariamente la pi` u eciente ma sicuramente ` e la pi` u essibile. La tavola della regola ` e costruita dalla funzione table rule() che trasforma il codice numerico della regola nella tavola corrispondente. Interpretando lo stato di tre celle consecutive come la rappresentazione binaria di un numero intero le 8 congurazioni possibili sono identicate univocamente dal valore di un indice i = 0, . . . , 7 cosicch` e la tavola della regola pu` o essere facilmente codicata con lausilio dellarray di 8 elementi rule assegnando allelemento i-esimo di rule il nuovo valore del sito centrale per la congurazione dei tre siti identicata dal valore dellindice i.
for ( i = 0 ; i <= 7 ; ++i ) { rule [ i ] = rule_code & 1 ; rule_code >>= 1 ; }

Per trasformare il codice numerico della regola nella tavola si utilizza lespressione
rule_code & 1

il cui valore ` e 0 o 1 a seconda che il primo bit a destra, quello meno signicativo, di rule code sia un bit 0 o un bit 1. Gli 8 bits della rappresentazione numerica della regola vengono letti spostando successivamente a destra i bits di rule code,
rule_code >>= 1 ;

Dal momento che si leggono solo i primi 8 bits non ha importanza se lo shift a destra sia logico od aritmetico. Tuttavia sebbene rule code sia un tipo intero senza segno se il codice della regola viene dato in input con un segno negativo il risultato di queste operazioni dipende dalla rappresentazione utilizzata dal computer per i numeri negativi. Ad esempio nella rappresentazione in complemento a due i primi otto bits di rule code conterranno la rappresentazione in complemento a due del codice della regola mentre nella rappresentazione in true magnitude i primi otto bits conterranno la rappresentazione binaria del modulo del codice della regola. Il fatto che rule code sia letto con la direttiva di conversione %hu
sscanf ( line , "%hu" , &rule_code ) ;

yaC-Primer: Automi Cellulari

(Rev. 2.0.3)

non vuol dire infatti che un valore negativo ` e convertito nellequivalente valore positivo ma solo che la rappresentazione binaria del valore negativo ` e interpretata come la rappresentazione binaria di un valore positivo. Di conseguenza se si vuole essere certi che per il codice della regola vengano utilizzati solo valori positivi bisogna aggiungere un controllo esplicito nel programma. In alternativa agli operatori bit-a-bit si pu` o utilizzare
for ( i = 0 ; i <= 7 ; ++i ) { rule [ i ] = rule_code % 2 ; rule_code /= 2 ; }

Anche in questo caso valgono ovviamente considerazioni analoghe alle precedenti se il codice della regola viene dato in input con un segno negativo. Per controllare che la tavola generata corrisponda alla regola voluta la funzione table rule() ne stampa il contenuto utilizzando la funzione
void bit_to_str ( char str , int nchar , int n )

che converte i primi nchar bits della rappresentazione binaria del numero intero n nella stringa puntata da str. Congurazione Iniziale: funzione init state() Il programma permette di scegliere tra una congurazione iniziale random o specicata nel caso il valore del seme seed sia uguale a zero. Nel caso di congurazione random alle celle a p one viene assegnato il valore 1 con probabilit`
for ( i = 0 ; i < aut>size ; ++i ) { r = ( double ) rand ( ) / ( RAND_MAX + 1 . 0 ) ; aut>site [ i ] = ( r < p_one ) ? 1 : 0 ; }

Se il valore di seed ` e 0 la congurazione iniziale deve essere data specicando la posizione delle celle con valore 1.
while ( 1 ) { printf ( " Posizione ( =< 0 fine ): " ) ; fgets ( line , sizeof ( line ) , stdin ) ; sscanf ( line , "%d" , &i ) ; if ( i < 1 | | i > aut>size ) break ; if ( ! aut>site [ i 1]) { aut>site [ i 1] = 1 ; } else { printf ( "Sito non valido , gia scelto \n" ) ; } } }

Le celle vengono inserite utilizzando un ciclo innito

yaC-Primer: Automi Cellulari

(Rev. 2.0.3)

while ( 1 ) { ... }

interrotto dallistruzione break quando viene inserita una posizione non valida. Nel ciclo viene anche controllato che le posizioni non vengano inserite pi` u volte
if ( ! aut>site [ i 1]) { aut>site [ i 1] = 1 ; } else { printf ( "Sito non valido , gia scelto \n" ) ; }

Evoluzione: funzione update state() Lo stato delle cellette deve essere aggiornato simultaneamente, in altre parole il nuovo valore delle cellette al tempo t + 1 deve essere determinato usando per tutte le cellette il valore al tempo t. Questo tipo di evoluzione viene chiamata sincrona o parallela. Il modo pi` u semplice di realizzare una evoluzione sincrona ` e utilizzando un array temporaneo su cui viene memorizzato il nuovo valore delle cellette generato a partire dai valori vecchi. La funzione update state() usa a questo scopo larray temporaneo new site.
cell_t new_site ; ... new_site = create_site ( aut>size ) ;

Quando lo stato di tutte le cellette ` e stato cambiato larray temporanea viene copiata su quella che contiene la congurazione dellautoma
for ( i = 0 ; i < aut>size ; ++i ) { aut>site [ i ] = new_site [ i ] ; }

e lo spazio utilizzato dallarray temporaneo restituito al sistema


free ( new_site ) ;

Luso di un array ausiliario non ` e eciente da un punto di vista dellutilizzo della memoria, ed in eetti levoluzione sincrona dellautoma pu` o essere realizzata utilizzando solo due variabili temporanee ausiliarie. La scrittura dellalgoritmo diventa per` o pi` u complessa e meno trasparente, e viene lasciato come esercizio. Il nuovo valore di ogni cella i viene determinato dalla la tavola della regola rule calcolando il valore dellindice della congurazione dei tre siti adiacenti:
conf_index = + 4 aut>site [ im1 ] + 2 aut>site [ i ] aut>site [ ip1 ] ;

dove im1 e ip1 individuano il vicino si sinistra e di destra del sito i, ed assegnando al sito i il valore ottenuto dalla tavola
new_site [ i ] = rule [ conf_index ] ;

10

yaC-Primer: Automi Cellulari Condizioni al bordo

(Rev. 2.0.3)

Lautoma cellulare vive in uno spazio nito di L siti di conseguenza il primo ed lultimo sito hanno un vicino in meno. Per ovviare a questo inconveniente si usano le Condizioni Periodiche al Bordo associando come vicino di sinistra del primo sito lultimo sito, e come vicino di destra dellultimo sito il primo sito. Geometricamente questo vuol dire che lautoma cellulare vive su un anello:
.....

..

2 1 0 L1 L2 . . .... .

Nel programma questo ` e realizzato con le istruzioni


im1 = ( i1 + aut>size ) % aut>size ; ip1 = ( i +1) % aut>size ;

come ` e facile convincersi considerando, ad esempio, i casi i=0, i=1 e i=aut->size-1. Questo non ` e lunico modo di realizzare le condizioni periodiche al bordo. Ad esempio si potrebbe eseguire il ciclo partendo dalla seconda cella sino no alla penultima e scrivere esplicitamente la regola per la prima e lultima cella. Questo metodo ` e chiaramente pi` u eciente di quello che richiede le operazioni di modulo, ma ha lo svantaggio che se la regola di evoluzione ` e piuttosto complicata, non come in questo caso, ` e pi` u facile fare errori in quanto questa va replicata tre volte: una volta per le celle a ciascun estremo ed una volta per tutte le altre celle. Il numero di repliche inoltre aumenta con il numero di dimensioni del sistema, per cui se sono tre in una dimensione saranno nove in due e cos` via. Un altro metodo ` e quello di utilizzare tavole dei vicini che per ogni sito contengano gli indici dei siti primi vicini, e piuttosto come fatto ad esempio per il Random Walk in due dimensioni. Questo metodo ` essibile e per questo viene utilizzato quando il sistema ` e denito su geometrie particolari o se il numero di vicini pu` o variare nel tempo come ad esempio nelle simulazioni di dimanica molecolare.
c AC 2003

11

Potrebbero piacerti anche