Interfaccia grafica per model checker NuSMV

Transcript

Interfaccia grafica per model checker NuSMV
UNIVERSITÀ DEGLI STUDI DI FIRENZE
Facoltà di Ingegneria - Dipartimento di Sistemi e Informatica
Tesi di Laurea in Ingegneria Informatica
Interfaccia grafica per model
checker NuSMV
Candidato
Relatori
Silvia Lorenzini
Prof. Alessandro Fantechi
Prof. Giacomo Bucci
Co-relatore
Ing. Alessio Ferrari
Anno Accademico 2008/2009
Ai miei genitori.
Indice
Introduzione
1
1 Concetti base
4
1.1
1.2
Macchina a stati niti . . . . . . . . . . . . . . . . . . . . . . . . .
4
1.1.1
Denizioni . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
1.1.2
Classicazione . . . . . . . . . . . . . . . . . . . . . . . . .
5
1.1.3
Implementazione
. . . . . . . . . . . . . . . . . . . . . . .
7
1.1.4
Applicazioni . . . . . . . . . . . . . . . . . . . . . . . . . .
8
Model Checking . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
1.2.1
11
Logica temporale
. . . . . . . . . . . . . . . . . . . . . . .
Linear Temporal Logic
. . . . . . . . . . . . . . . . . . . .
11
. . . . . . . . . . . . . . . . . . .
12
Computation Tree Logic
1.2.2
Il processo del model checking
. . . . . . . . . . . . . . . .
13
1.2.3
Applicazioni odierne . . . . . . . . . . . . . . . . . . . . . .
16
BDD-based model checking . . . . . . . . . . . . . . . . . .
16
SAT-based model checking . . . . . . . . . . . . . . . . . .
17
iii
Indice
iv
2 Il tool NuSMV2
2.1
2.2
2.3
2.4
18
Introduzione al tool
. . . . . . . . . . . . . . . . . . . . . . . . . .
18
2.1.1
Funzionamento del sistema . . . . . . . . . . . . . . . . . .
19
2.1.2
Architettura del sistema . . . . . . . . . . . . . . . . . . . .
20
Formalismo di descrizione dei modelli . . . . . . . . . . . . . . . . .
22
2.2.1
Panoramica dei tipi
. . . . . . . . . . . . . . . . . . . . . .
22
2.2.2
Denizione di FSM
. . . . . . . . . . . . . . . . . . . . . .
22
2.2.3
Speciche
. . . . . . . . . . . . . . . . . . . . . . . . . . .
24
Utilizzo del tool NuSMV2 . . . . . . . . . . . . . . . . . . . . . . .
24
2.3.1
Lettura e costruzione di un modello
. . . . . . . . . . . . .
24
2.3.2
Controllo delle speciche
. . . . . . . . . . . . . . . . . . .
25
2.3.3
Simulazione e tracce
. . . . . . . . . . . . . . . . . . . . .
26
Esempi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
2.4.1
Inverter Ring . . . . . . . . . . . . . . . . . . . . . . . . . .
27
2.4.2
Mutual Exclusion
30
. . . . . . . . . . . . . . . . . . . . . . .
3 Mappatura FSM - NuSMV
35
3.1
Stati e transizioni
. . . . . . . . . . . . . . . . . . . . . . . . . . .
35
3.2
Azioni sugli stati . . . . . . . . . . . . . . . . . . . . . . . . . . . .
37
3.2.1
Azione Onentry
. . . . . . . . . . . . . . . . . . . . . . . .
38
3.2.2
Azione Onexit . . . . . . . . . . . . . . . . . . . . . . . . .
40
3.2.3
Azione During . . . . . . . . . . . . . . . . . . . . . . . . .
41
Transizioni non deterministiche . . . . . . . . . . . . . . . . . . . .
43
3.3
4 Graphic User Interface
4.1
4.2
Un po' di storia
48
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
48
4.1.1
I primi anni
. . . . . . . . . . . . . . . . . . . . . . . . . .
49
4.1.2
Gli anni '70
. . . . . . . . . . . . . . . . . . . . . . . . . .
50
4.1.3
Interfacce grache dagli anni '80 ad oggi . . . . . . . . . . .
52
Fondamenti dello sviluppo di una GUI
. . . . . . . . . . . . . . . .
55
Indice
v
4.2.1
Stile di progettazione
. . . . . . . . . . . . . . . . . . . . .
55
4.2.2
Design pattern . . . . . . . . . . . . . . . . . . . . . . . . .
56
Model View Controller
. . . . . . . . . . . . . . . . . . . .
57
Observer . . . . . . . . . . . . . . . . . . . . . . . . . . . .
59
Composite . . . . . . . . . . . . . . . . . . . . . . . . . . .
60
Strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . .
61
5 Analisi e specica dei requisiti
5.1
5.2
Analisi del progetto
63
. . . . . . . . . . . . . . . . . . . . . . . . . .
5.1.1
Ciclo di vita del software
5.1.2
Prototyping
. . . . . . . . . . . . . . . . . . .
64
. . . . . . . . . . . . . . . . . . . . . . . . . .
65
Denizione dei requisiti
5.2.1
. . . . . . . . . . . . . . . . . . . . . . . .
Analisi dei requisiti
Scenario generale
67
. . . . . . . . . . . . . . . . . . . . . . .
68
. . . . . . . . . . . . . . . . . . .
69
. . . . . . . . . . . . . . . . . . . . . .
69
Denizione variabili d'istanza . . . . . . . . . . . . . . . . .
69
Denizione FSM . . . . . . . . . . . . . . . . . . . . . . . .
70
Modica componenti FSM
. . . . . . . . . . . . . . . . . .
70
Verica modello . . . . . . . . . . . . . . . . . . . . . . . .
71
Specica dei requisiti
. . . . . . . . . . . . . . . . . . . . .
72
. . . . . . . . . . . . . . . . . . . . . .
72
Requisiti non funzionali di interfaccia . . . . . . . . . . . . .
76
Denizione variabili
Requisiti funzionali
6 Implementazione
78
6.1
Denizione del modello
6.2
Sviluppo di modello e vista
6.2.1
66
. . . . . . . . . . . . . . . . . . . . . .
Implementazione graca
5.2.2
63
. . . . . . . . . . . . . . . . . . . . . . . .
78
. . . . . . . . . . . . . . . . . . . . . .
80
Moduli . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
80
Frame Module . . . . . . . . . . . . . . . . . . . . . . . . .
80
FSM Module
82
. . . . . . . . . . . . . . . . . . . . . . . . .
Indice
vi
6.2.2
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
83
Variabili d'istanza . . . . . . . . . . . . . . . . . . . . . . .
84
Variabili locali . . . . . . . . . . . . . . . . . . . . . . . . .
84
Variabili di ingresso
. . . . . . . . . . . . . . . . . . . . . .
85
Variabili di uscita
. . . . . . . . . . . . . . . . . . . . . . .
86
Stati e transizioni
. . . . . . . . . . . . . . . . . . . . . . .
86
Stati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
86
Transizioni . . . . . . . . . . . . . . . . . . . . . . . . . . .
87
Ulteriori dettagli implementativi
. . . . . . . . . . . . . . .
87
. . . . . . . . . . . . . . . . . . . . .
87
Project tree
. . . . . . . . . . . . . . . . . . . . . . . . . .
88
Altri widget
. . . . . . . . . . . . . . . . . . . . . . . . . .
89
Comunicazione vista-modello . . . . . . . . . . . . . . . . .
90
Salvataggio e caricamento . . . . . . . . . . . . . . . . . . . . . . .
91
6.3.1
XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
93
L'interfaccia DOM XML
. . . . . . . . . . . . . . . . . . .
94
. . . . . . . . . . . . . . . . . . . . .
95
6.2.3
6.2.4
Variabili
Passaggio di variabili
6.3
6.4
Generazione del le NuSMV
6.4.1
Traduzione Frame Module
. . . . . . . . . . . . . . . . . .
96
6.4.2
Traduzione FSM Module
. . . . . . . . . . . . . . . . . . .
96
6.5
Verica del modello . . . . . . . . . . . . . . . . . . . . . . . . . .
97
6.6
Sviluppi futuri . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
98
6.6.1
Linguaggio NuSMV . . . . . . . . . . . . . . . . . . . . . .
98
6.6.2
Estensione della verica . . . . . . . . . . . . . . . . . . . .
99
6.6.3
Simulazione interattiva
6.6.4
Inserimento formule . . . . . . . . . . . . . . . . . . . . . . 100
6.6.5
Estensione ad altri tool per model checking
7 Conclusioni
. . . . . . . . . . . . . . . . . . . . 100
. . . . . . . . . 101
102
Indice
vii
A Il framework Qt
104
A.1
Segnali e slot
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
A.2
Scena graca e vista . . . . . . . . . . . . . . . . . . . . . . . . . . 105
A.3
Implementazione undo/redo . . . . . . . . . . . . . . . . . . . . . . 107
B Design e utilizzo del tool
B.1
108
Pulsanti e menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
B.1.1
Operazioni sulle nestre . . . . . . . . . . . . . . . . . . . . 110
Vista di un Frame module
Vista di un FSM module
. . . . . . . . . . . . . . . . . . 112
. . . . . . . . . . . . . . . . . . . 114
Stato . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Transizione
Variabile
B.2
B.3
. . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Esempi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
B.2.1
Inverter ring . . . . . . . . . . . . . . . . . . . . . . . . . . 116
B.2.2
Mutual exclusion
Utilizzo del programma
B.3.1
B.4
. . . . . . . . . . . . . . . . . . . . . . . . . . 115
. . . . . . . . . . . . . . . . . . . . . . . 118
. . . . . . . . . . . . . . . . . . . . . . . . 121
Requisiti . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
File generati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
B.4.1
Esempio inverter ring
. . . . . . . . . . . . . . . . . . . . . 122
B.4.2
Esempio mutual exclusion . . . . . . . . . . . . . . . . . . . 127
Ringraziamenti
135
Bibliograa
137
Elenco delle gure
1.1
1.2
visione insiemistica delle gerarchie di Chomsky.
. . . . . . . . . . .
Semplice macchina a stati niti rappresentata mediante tabella di
transizione e diagramma di stato. . . . . . . . . . . . . . . . . . . .
1.3
6
7
Esempio di protocollo di comunicazione per lo scambio di messaggi,
realizzato mediante FSM.
. . . . . . . . . . . . . . . . . . . . . .
9
1.4
Esempi di proprietà espresse con la logica CTL.
. . . . . . . . . . .
12
1.5
Esempio di modellazione con macchina a stati niti di una lavatrice.
14
1.6
Esempio di trasformazione da binary decision tree a BDD.
. . . . .
16
2.1
Struttura interna di NuSMV2.
. . . . . . . . . . . . . . . . . . . .
20
2.2
Codice NuSMV del modello Inverter Ring. . . . . . . . . . . . . . .
27
2.3
Codice NuSMV del modello Mutual Exclusion. . . . . . . . . . . . .
30
3.1
Rappresentazione di una macchina a stati niti con n stati e della
variabile corrispondente denita secondo il linguaggio NuSMV. . . .
36
3.2
Esempio di macchina a stati niti con transizioni deterministiche. . .
36
3.3
Esempio di macchina a stati niti con azione onentry. . . . . . . . .
38
3.4
Macchina a stati niti con azioni onexit. . . . . . . . . . . . . . . .
40
3.5
Esempio di macchina a stati niti con azione during.
42
viii
. . . . . . . .
Elenco delle gure
ix
3.6
Esempio di macchina a stati niti con transizioni non deterministiche. 43
3.7
Modello di Figura 3.6 con aggiunte della variabile v. . . . . . . . . .
45
4.1
Memex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
4.2
Dispositivo oN-Line System.
. . . . . . . . . . . . . . . . . . . . .
50
4.3
Dispositivo d'ingresso per NLS. . . . . . . . . . . . . . . . . . . . .
51
4.4
Lo Xerox Alto. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
52
4.5
Ambiente di sviluppo a GUI Smalltalk. . . . . . . . . . . . . . . . .
53
4.6
(a) Macintosh System 1; (b) Windows 1.0; (c) Amiga Workbench;
(d) NexTSTEP.
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
4.7
Schema di Model-View-Controller.
. . . . . . . . . . . . . . . . . .
58
4.8
Struttura del pattern Observer. . . . . . . . . . . . . . . . . . . . .
59
4.9
Strutture del pattern Composite. . . . . . . . . . . . . . . . . . . .
60
4.10 Struttura del pattern Strategy.
. . . . . . . . . . . . . . . . . . . .
61
5.1
Tre framework basilari nello sviluppo di un software. . . . . . . . . .
64
5.2
Diagramma del caso d'uso scenario generale. . . . . . . . . . . . .
68
5.3
Diagramma del caso d'uso implementazione graca
. . . . . . . .
69
5.4
Diagramma del caso d'uso denizione variabili. . . . . . . . . . . .
70
5.5
Diagramma del caso d'uso denizione variabili d'istanza.
. . . . .
71
5.6
Diagramma del caso d'uso denizione FSM.
. . . . . . . . . . . .
71
5.7
Diagramma del caso d'uso modica componenti FSM. . . . . . . .
72
5.8
Diagramma del caso d'uso verica modello.
. . . . . . . . . . . .
73
6.1
Denizione del modello del sistema.
. . . . . . . . . . . . . . . . .
81
6.2
Vista di un Frame Module.
. . . . . . . . . . . . . . . . . . . . . .
82
6.3
Vista di un FSM Module. . . . . . . . . . . . . . . . . . . . . . . .
83
6.4
Vista delle variabili di istanza: a sinistra istanza di un Frame Module,
a destra istanza di un FSM Module.
6.5
. . . . . . . . . . . . . . . . .
84
Vista delle variabili: (a) variable locale; (b) variabile di ingresso; (c)
variabile di uscita. . . . . . . . . . . . . . . . . . . . . . . . . . . .
85
Elenco delle gure
6.6
Vista delle variabili di ingresso e di uscita relative all'istanza di un
modulo.
6.7
x
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
85
Vista di uno stato: lo stato A è impostato come iniziale; nello stato
B sono state inserite delle azioni. . . . . . . . . . . . . . . . . . . .
86
6.8
Vista di una transizione tra due stati. . . . . . . . . . . . . . . . . .
87
6.9
Passaggio di variabili tra moduli.
. . . . . . . . . . . . . . . . . . .
88
. . . . . . . . . . . . . . . . . . . . . . . . . .
88
6.10 Albero di progetto.
6.11 Altre viste del modello:
(a) lista dei moduli; (b) dettaglio delle
variabili; (c) informazioni sui vincoli del modulo. . . . . . . . . . . .
90
6.12 Diagramma di usso per la modica del nome di un modulo. . . . .
90
6.13 Diagramma delle classi per l'oggetto Modulo e le relative viste. . . .
91
6.14 Diagramma di sequenza per l'operazione di salvataggio. . . . . . . .
92
6.15 Formato del le di salvataggio. . . . . . . . . . . . . . . . . . . . .
92
6.16 Organizzazione delle classi principali DOM.
95
. . . . . . . . . . . . .
6.17 Esempio di traduzione delle variabili di un modulo Frame da modello
graco a le NuSMV .
. . . . . . . . . . . . . . . . . . . . . . . .
96
6.18 Esempio di traduzione delle variabili di una macchina a stati niti da
modello graco a le NuSMV.
. . . . . . . . . . . . . . . . . . . .
97
6.19 Widget dei comandi per la verica. . . . . . . . . . . . . . . . . . .
97
A.1
Comunicazioni tra oggetti per via di segnali e slot. . . . . . . . . . . 105
B.1
Pulsanti e menu della schermata principale.
B.2
Finestra di un modulo FSM.
B.3
Denizione di tre variabili e navigazione dei moduli istanziati. . . . . 111
B.4
Modica di una variabile locale. . . . . . . . . . . . . . . . . . . . . 112
B.5
Azioni sulle variabili d'istanza.
B.6
Finestra relativa a FSM Module.
. . . . . . . . . . . . . . . . . . . 115
B.7
Creazione modello inverter ring.
. . . . . . . . . . . . . . . . . . . 116
B.8
Modica dei nomi di variabili e modulo.
B.9
Le operazioni sulla nestra del main sono state completamente ese-
. . . . . . . . . . . . . 109
. . . . . . . . . . . . . . . . . . . . . 110
. . . . . . . . . . . . . . . . . . . . 113
. . . . . . . . . . . . . . . 117
guite. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Elenco delle gure
xi
B.10 Implementazione della macchina a stati niti inverter. . . . . . . . 118
B.11 Comandi selezionati per il modello inverter.
B.12 Modulo main del modello mutual exclusion.
B.13 Stati del processo user.
. . . . . . . . . . . . 119
. . . . . . . . . . . . . 120
. . . . . . . . . . . . . . . . . . . . . . . . 121
B.14 Macchina a stati completa di azioni e transizioni.
. . . . . . . . . . 122
B.15 Inserimento formule di verica. . . . . . . . . . . . . . . . . . . . . 123
Elenco delle tabelle
6.1
Vista degli elementi nell'albero di progetto.
xii
. . . . . . . . . . . . .
89
Introduzione
Il model checking è una tecnica di verica automatica per sistemi concorrenti a stati
niti che permette di denire un modello del sistema con una notazione formale,
specicare secondo una logica temporale le proprietà che tale sistema deve avere e
inne consente di vericare le speciche denite. Avere un modello astratto del sistema permette di non considerare gli aspetti implementativi; questo è un vantaggio
poiché è possibile manipolare il modello senza dover eettuare un'implementazione
vera e propria del sistema che poi, in presenza di errori, andrebbe riprogettato in
parte o totalmente.
Il processo del model checking si basa su tre punti fondamentali: la denizione di
un modello del sistema, la specica di un insieme di proprietà mediante logiche
temporali CTL ed LTL [Eme94] e inne la verica delle speciche mediante appositi
+
tool (NuSMV [CCB ], SPIN [Spi], UPPAAL [Upp], PRISM [Pri], ecc...).
Nonostante costituisca ad oggi il metodo più ecace ed eciente per rilevare errori
di progetto prima dell'implementazione di un sistema, il model checking è di scarso
utilizzo in ambito extra-accademico a causa della complessità dei linguaggi utilizzati
e del dicile utilizzo dei tool esistenti.
Da qui nasce la necessità di sviluppare
un'interfaccia user-friendly, per facilitare la penetrazione nell'industria di questa
tecnologia.
NuSMV è un tool di verica formale tramite model checking molto diuso, soggetto
a sperimentazioni sia in ambito accademico che industriale [Mil08], pertanto è naturale la necessità di svilupparne un'interfaccia graca che ne semplichi l'utilizzo.
Come ogni model checker, anche per NuSMV è necessario denire un modello di
sistema secondo un formalismo proprio, ed è su questo punto che è fondata questa
1
INTRODUZIONE
2
tesi: utilizzare il formalismo graco delle macchine a stati niti per descrivere il
modello di un determinato sistema, tradurre tale modello nel linguaggio proprio del
model checker ed eettuare inne la verica formale del modello tradotto. Lo scopo
è quello di astrarre l'utente dal formalismo utilizzato dal tool così che si possa occupare solo di descrivere il sistema secondo un modello la cui denizione si appoggia
alle macchine a stati niti.
Una volta denito un formalismo graco per descrivere un modello, un punto fondamentale riguarda la traduzione dal modello graco stesso nel linguaggio supportato
dal tool NuSMV, il cui utilizzo è necessario per la verica delle speciche che il sistema deve rispettare. L'operazione di mappatura si appoggia principalmente al meccanismo che lega stati, transizioni e azioni sugli stati, così da descrivere l'evoluzione
del sistema ad ogni step e per ogni variabile coinvolta.
Altro aspetto fondamentale nell'implementazione dell'interfaccia è capire quali requisiti essa debba soddisfare, ovvero quali funzionalità essa deve prevedere. Al ne
di ottenere un insieme di requisiti il più esaustivo possibile, è stato realizzato un prototipo del programma, il quale riassumeva le funzioni più importanti; tale prototipo
è stato testato anche dal team di sviluppo di NuSMV che ha poi fornito importanti
suggerimenti per l'implementazione del programma nale.
Grazie al prototipo realizzato è stato quindi possibile denire un insieme di requisiti
che caratterizzano completamente il software nale; sulla base di essi si è sviluppata
la costruzione dell'intero sistema.
In una prima fase è stato importante creare
un visione macroscopica del programma che racchiudesse tutte le caratteristiche
desiderate, senza scendere nei dettagli di implementazione, dopodiché ogni aspetto
è stato volta volta analizzato e approfondito in dettaglio.
Appoggiandosi al concetto di architectural pattern MVC [Bur87], come prima cosa
si è suddivisa la parte costituente il modello del sistema, da tutto quello che è la vista
(ovvero la parte di interfaccia con cui l'utente interagisce), che è stata implementata
in seguito, una volta denito correttamente il modello. La comunicazione tra queste
due parti è un aspetto fondamentale che si basa sul design pattern Observer e
che è stato adattato al framework Qt utilizzato per la realizzazione dei widget
dell'interfaccia.
Oltre alla rappresentazione graca del modello e quindi alla generazione in automatico del le NuSMV, è stata prevista anche una parte di specica delle formule in
logica temporale e (interfacciandosi al tool NuSMV stesso) di verica del modello,
mediante la quale è possibile ottenere, se ci sono, controesempi relativi alle formule
denite ed eettuare una simulazione non interattiva.
Nel Capitolo 1 verranno introdotti i concetti teorici che stanno alla base dello sviluppo di questa tesi:
le macchine a stati niti ed il processo di model checking;
INTRODUZIONE
3
dopodiché verrà data, nel Capitolo 2, un'introduzione al tool NuSMV, in particolare a quegli aspetti che hanno avuto un maggiore impatto nello sviluppo della
tesi.
Il Capitolo 3 descrive il processo di mappatura dal modello graco di macchina a
stati denito dall'utente al modello formale del tool NuSMV, e costituisce quindi il
punto centrale di questa tesi, su cui è basata tutta l'implementazione.
Nel Capitolo 4 verrà descritto il concetto di interfaccia graca, mostrando la sua
evoluzione nel corso della storia e quindi l'importanza e l'impatto che essa ha avuto nell'utilizzo dei software, dopodiché verranno descritte le tecniche utilizzate e
maggiormente sviluppate per l'implementazione di una GUI.
Il Capitolo 5 descrive la fase iniziale di progetto, in cui vengono deniti i requisiti
del sistema, e dà quindi uno sguardo alla teoria che sta dietro l'analisi del progetto stesso; nel Capitolo 6 verranno invece mostrati i dettagli implementativi, dalla
denizione del modello allo sviluppo di ogni sua singola parte, prestando particolare
attenzione alle scelte fatte ed agli strumenti utilizzati per la sua realizzazione.
Inne nel Capitolo 7 vengono esposte le conclusioni e gli sviluppi futuri del tool
realizzato.
In appendice vengono descritti il framework Qt scelto per lo sviluppo dell'interfaccia
e il design e l'utilizzo del programma realizzato, in cui vengono mostrati anche alcuni
esempi.
CAPITOLO
1
Concetti base
Il progetto realizzato si appoggia a dei concetti importanti e ben noti nell'ambito della modellazione e verica dei sistemi. In questo capitolo introdurremo tali concetti,
in particolare la teoria di base relativa agli automi a stati niti ed alla tecnologia del
model checking.
1.1 Macchina a stati niti
macchina a stati niti (FSM), detta anche automa a stati niti, o più
semplicemente macchina a stati, è un sistema dinamico, invariante e discreto,
Una
ovvero:
ˆ
dinamico: evolve nel tempo passando da uno stato all'altro in funzione dei
segnali d'ingresso e dello stato precedente;
ˆ
invariante :
a parità di condizioni iniziali il comportamento del sistema è
sempre lo stesso;
ˆ
discreto: le variabili d'ingresso, di stato e di uscita, possono assumere solo
valori discreti.
Inoltre in tale sistema i possibili valori di ingresso e di uscita costituiscono insiemi
niti.
4
CAPITOLO 1.
CONCETTI BASE
5
1.1.1 Denizioni
Una macchina a stati niti può essere descritta semplicemente come un numero
nito di stati, un insieme di transizioni fra tali stati e delle azioni.
Lo stato corrente riette i cambiamenti dallo stato iniziale al momento attuale; una
transizione indica un cambiamento di stato ed è descritta da una condizione che
deve essere soddisfatta dall'ingresso per attivare la transizione.
Un'azione è una
descrizione di un'attività che si verica in determinate circostanze; ci sono diversi
tipi di azioni:
ˆ
Entry actions: si vericano ogniqualvolta si entra in uno stato;
ˆ
Exit actions: vengono eseguite quando si esce da uno stato;
ˆ
During actions: sono azioni eettuate quando si rimane nello stato corrente.
Un utilizzo comune delle FSM è l'elaborazione dei linguaggi regolari [HMU00],
ovvero quei linguaggi che possono essere generati da una grammatica regolare,
(tipo 3 nella gerarchia di Chomsky [Kor85], Figura 1.1).
Una grammatica regolare è una quadrupla
ˆ
G =< N, Σ, P, S >,
dove:
N è l'insieme dei simboli non terminali;
ˆ Σ
è l'insieme dei simboli terminali;
ˆ
S∈
ˆ
P è l'insieme di regole di produzione, indicate con
N
è detto assioma ed è il simbolo non terminale di partenza;
α ∈ (N
S
Σ) ◦ N ◦ (N
β ∈ (N
S
Σ)
∗
∗
S
∗
Σ)
α → β,
dove
è un simbolo non terminale,
può essere qualunque cosa.
1.1.2 Classicazione
automi a stati
automi a stati niti non deterministici; la dierenza
Una prima classicazione per le macchine a stati niti è quella tra
niti deterministici
e
sostanziale tra i due tipi di automi è che nei primi, in qualunque stato ci si trovi e
per qualunque input ci sarà una sola transizione possibile, mentre nei secondi esiste
almeno uno stato da cui sono possibili diverse computazioni per determinati ingressi.
È comunque sempre possibile passare dall'uno all'altro tipo eettuando operazioni
sugli stati. Formalmente:
CAPITOLO 1.
CONCETTI BASE
6
Figura 1.1: visione insiemistica delle gerarchie di Chomsky.
ˆ
un automa a stati niti deterministico
A =< I, U, S, f, g >
è denito come una quintupla
dove
I(t) = {i1 , i2 , ..., in }
è l'insieme nito dei possibili simboli d'ingresso;
U (t) = {u1 , u2 , ..., um }
S(t) = {s1 , s2 , ..., sh }
è l'insieme nito dei possibili simboli d'uscita;
è l'insieme nito degli stati;
f : I(t) × S(t) → U (t) è la funzione che collega l'uscita al valore attuale
dell'ingresso e dello stato,
g : I(t) × S(t) → S(t)
U (t) = f (I(t), S(t));
è la funzione di transizione, che all'ingresso
attuale e allo stato attuale collega lo stato immediatamente successivo:
S(t + 1) = g(I(t), S(t)).
ˆ
Un automa a stati niti non deterministico è denito come una quintupla
A =< I, U, S, f, g >
dove
I(t) = {i1 , i2 , ..., in }
è l'insieme nito dei possibili simboli d'ingresso;
U (t) = {u1 , u2 , ..., um }
S(t) = {s1 , s2 , ..., sh }
è l'insieme nito dei possibili simboli d'uscita;
è l'insieme nito degli stati;
f : I(t) × S(t) → U (t) è la funzione che collega l'uscita al valore attuale
dell'ingresso e dello stato,
U (t) = f (I(t), S(t));
g : I(t) × S(t) → P (S(t))
è la funzione di transizione parziale, che
all'ingresso attuale e allo stato attuale collega un sottoinsieme di S.
Un'altra distinzione può essere fatta tra
macchina di Moore e macchina di Mealy;
nella prima l'uscita dipende solo dallo stato attuale, mentre nella seconda l'uscita è
CAPITOLO 1.
CONCETTI BASE
7
determinata sia dallo stato attuale che dall'ingresso. Nella pratica sono spesso usati
modelli misti dei due.
Una rappresentazione comune delle macchine a stati niti deterministiche è quella che utilizza una tabella di transizione, dove alle righe sono associati gli stati,
alle colonne i simboli di ingresso; gli elementi della tabella rappresentano lo stato
all'istante successivo raggiunto con la transizione.
Un'altra rappresentazione molto comune è quella dei diagrammi di stato, dove l'automa è rappresentato tramite un grafo orientato, dove i nodi rappresentano gli stati
e gli archi le transizioni, etichettati col simbolo (o condizione) di ingresso che attiva
la transizione.
Vediamo in Figura 1.2 un esempio di entrambe le rappresentazioni.
Figura 1.2: Semplice macchina a stati niti rappresentata mediante tabella di transizione
e diagramma di stato.
1.1.3 Implementazione
È possibile realizzare macchine a stati niti sia a livello hardware che software;
vediamo di seguito alcune implementazioni di entrambi i tipi.
Implementazione hardware
In un circuito digitale, una FSM può essere costruita utilizzando un dispositivo
logico programmabile (PLD), un controllore logico programmabile (PLC), porte
logiche e ip op (o relays).
Più specicatamente un'implementazione hardware
richiede un registro in cui memorizzare le variabili di stato, un blocco logico per
determinare le transizioni ed un secondo blocco per le uscite della FSM. Una delle
classiche implementazioni hardware è il Richards controller [L.73].
Implementazione software
Come primo esempio consideriamo la
programmazione basata su automi
(automata-based programming [Sha03]), che rappresenta un tipo di programmazione
CAPITOLO 1.
CONCETTI BASE
8
in cui il programma o parte di esso rappresenta un modello di macchina a stati niti.
Introduciamo il concetto di step di automazione, ovvero una sezione di codice che
ha un unico punto di ingresso e che è sempre la stessa per un determinato step; tale
sezione può essere rappresentata da una funzione, da un ciclo o da un'altra routine.
È possibile comunicare tra diversi step unicamente attraverso un preciso insieme di
variabili, dette di stato: a seconda dello stato in cui ci troviamo viene eseguita una
determinata sezione di codice.
Nei sistemi di controllo di macchine complesse è spesso utilizzata una tecnologia
chiamata
Virtual Finite State Machine (VFSM [Wag92]).
Essa si basa sulle pro-
prietà di controllo delle variabili (valori rilevanti al ne del controllo del sistema) e
sul concetto di ambiente virtuale, denito mediante tre tipi di insiemi di nomi:
ˆ
input : rappresentato dalle proprietà di controllo di tutte le variabili disponibili
e serve a determinare le transizioni tra gli stati;
ˆ
output : rappresentato da tutte le azioni disponibili sulle variabili e attiva le
azioni (onentry, onexit, ecc..);
ˆ
state : denito come per gli stati delle FSM.
1.1.4 Applicazioni
Le macchine a stati niti sono ampiamente utilizzate in molti campi e per svariati
ni; di seguito vedremo alcuni casi di applicazione più comune.
Analisi sintattica
Un processo molto comune in informatica è
l'analisi sintattica
un testo al ne di determinare la sua struttura grammaticale.
(o
parsing)
di
Il primo passo da
compiere è la generazione di tokens (o analisi lessicale) secondo cui lo stream di
caratteri in ingresso è suddiviso in simboli signicativi deniti tramite una grammatica di espressioni regolari; dopodiché il parser verica che i tokens (uno di seguito
all'altro) formino un'espressione ammissibile. In pratica l'analisi sintattica può essere vista come un processo che costruisce un albero sintattico (parse tree ), dove
i nodi costituiscono simboli non terminali e le foglie invece rappresentano i simboli
terminali.
Possiamo classicare i parser secondo due tipologie: top-down parser e bottom-up
parser : il primo legge i tokens da sinistra verso destra e ogni volta che incontra
un simbolo non terminale applica la rispettiva regola di produzione denita dalla
grammatica delle espressioni regolari. Questo procedimento continua no a che non
CAPITOLO 1.
CONCETTI BASE
9
si sono sostituiti tutti i simboli non terminali con quelli terminali. In pratica il parse
tree viene generato a partire dalla radice, scendendo no alle foglie.
Il bottom-up parser invece parte del simbolo ricevuto e cerca di riscriverlo no
al simbolo iniziale, cercando cioè di determinare il simbolo più elementare, quindi
gli elementi che lo contengono e così via. L'albero sintattico viene cioè generato
partendo dalle foglie e risalendo no alla radice.
È facile capire come un parser possa essere implementato utilizzando le FSM, in
particolare se facciamo riferimento alla programmazione basata su automi [AVV97],
è immediato realizzare un programma che eettua l'analisi sintattica di un determinato stream in input.
Event-driven programming
È un tipo di programmazione in cui la sequenza di controllo non è predetta,
ma cambia in base agli input che non seguono un preciso e determinato ordine;
in risposta ad ogni ingresso si deve vericare un determinato evento in risposta,
così da far evolvere il sistema. È possibile quindi schematizzare il sistema con una
FSM, dove uno stato rappresenta il sistema in un determinato momento, e in base
ad un certo input avviene una transizione verso un altro stato, che rappresenterà
il sistema aggiornato in seguito al vericarsi dell'evento corrispondente all'ingresso
[WSWW06].
Un problema di questo tipo di programmazione è la cosiddetta esplosione degli
stati, cioè in sistemi particolarmente complessi il numero di stati cresce in maniera
spropositata ed una rappresentazione di questo tipo diventa impossibile, però per
sistemi semplici è molto intuitiva e permette di considerare ogni tipo di eventualità.
Figura 1.3: Esempio di protocollo di comunicazione per lo scambio di messaggi, realizzato
mediante FSM.
Protocolli di comunicazione
Un sistema di comunicazione è composto da:
CAPITOLO 1.
Un
CONCETTI BASE
10
ˆ
una sorgente che genera il dato da trasmettere;
ˆ
un trasmettitore che converte il dato in segnale in modo che sia trasferibile;
ˆ
un sistema di trasmissione che trasmette il segnale;
ˆ
un ricevitore che trasforma il segnale in dato;
ˆ
una destinazione.
protocollo
è un insieme di regole usate da più entità di un sistema per imple-
mentare i possibili servizi di comunicazione. Un processo che rappresenti il protocollo
di comunicazione tra sorgente e destinazione può essere formalmente rappresentato
tramite le macchine a stati niti; vediamo in Figura 1.3 un esempio.
1.2 Model Checking
Il model checking è una tecnica di verica automatica per sistemi concorrenti a stati
niti che permette di denire un modello del sistema con una notazione formale,
specicare secondo una logica temporale le proprietà che tale sistema deve avere e
inne consente di vericare queste ultime.
Avere un modello astratto del sistema permette di non considerare gli aspetti implementativi; questo è un vantaggio poiché è possibile manipolare il modello senza
dover eettuare un'implementazione vera e propria del sistema che poi, in presenza
di errori, andrebbe riprogettato totalmente o comunque in parte. Inoltre per alcuni sistemi si utilizzano componenti costosi, quindi eettuare test o simulazioni sul
sistema reale può essere decisamente dispendioso in termini economici.
La procedura del model checking utilizza una ricerca esaustiva sullo spazio degli
stati per vericare se una specica proprietà è vera o meno sul modello; con risorse
sucienti otterremo sempre una risposta positiva o negativa.
Come formalismo di denizione del modello vengono utilizzate le strutture di Kripke
[Smi04, Gup93]; una struttura di Kripke su un insieme di proposizioni atomiche AP
è una quadrupla
ˆ S
M =< S, S0 , R, L >,
dove:
è un insieme nito di stati;
ˆ S0 ⊂ S
è l'insieme degli stati iniziali;
ˆ R ⊂ S×S
che esiste
è una relazione totale di transizione, cioè
0
R(s, s ).
∀s ∈ S, ∃s0 ∈ S
tale
CAPITOLO 1.
CONCETTI BASE
ˆ L : S → 2AP
11
è una funzione che ad ogni stato associa un'etichetta che
contiene le proposizioni vere in quello stato.
Denendo secondo tale formalismo un modello, abbiamo una rappresentazione del
sistema che rispetta le speciche dichiarate.
Tali speciche possono essere rap-
presentate secondo una logica temporale, in modo da vericare che il modello le
rispetti.
1.2.1 Logica temporale
La logica temporale è utilizzata per rappresentare proposizioni relative a tempi diversi, senza introdurre il concetto di tempo in maniera esplicita [Ven01, Eme94],
ovvero è una logica in cui le formule possono essere arricchite da dei quanticatori
temporali (always, eventually,..) che non hanno alcuna misura dell'istante temporale. I due tipi di logiche temporali più comunemente utilizzati sono:
Temporal Logic) e
CTL
LTL
(Linear
(Computation Tree Logic).
Linear Temporal Logic
La logica LTL è un tipo di logica che non considera l'evoluzione del sistema dallo
stato iniziale a quello attuale; il futuro è visto come una sequenza di stati.
La sintassi della logica LTL è basata su:
ˆ
un insieme di variabili proposizionali
ˆ
i connettori logici usuali: and
ˆ
un insieme di operatori temporali modali:
(∧),
p1 , p2 , ...
or
(∨),
not
(q),...
n ext ;
X ( o N):
G: always ( lobally);
F: eventually (in the
U:
u ntil ;
R:
r elease;
g
Date due proposizioni
ϕ
e
ψ,
f uture);
la semantica degli operatori è denita nel seguente
modo:
ˆ
Xϕ:
ϕ
deve vericarsi nel prossimo stato;
ˆ
Gϕ:
ϕ
deve essere vera per ogni stato futuro;
CAPITOLO 1.
ˆ
Fϕ:
ϕ
CONCETTI BASE
12
deve vericarsi in almeno uno stato futuro;
ˆ ψ Uϕ: ψ
deve esser vera almeno nché non si verica
ˆ ψ Rϕ: ϕ deve esser vera nché non diventa vera ψ ;
vera allora
ϕ
ϕ;
se questa non diventa mai
deve rimanere vera per sempre.
Gli operatori possono combinarsi per formare espressioni logiche del tipo FGϕ (ϕ è
vera innitamente spesso) o GFϕ (ϕ è sempre vera a partire da un certo istante in
poi).
Computation Tree Logic
Con la logica CTL è possibile esprimere formule logiche su cammini a partire da
un determinato stato iniziale. Il nome deriva dal fatto che il modello temporale è
schematizzabile con una struttura ad albero e il futuro non è determinato, cioè a
partire da un certo stato ci possono essere più percorsi possibili.
Figura 1.4: Esempi di proprietà espresse con la logica CTL.
Gli operatori utilizzabili in questo tipo di logica sono i seguenti:
ˆ
gli operatori logici usuali: and
ˆ
operatori temporali:
Xϕ (ne t):
x
Gϕ ( lobally):
ϕ
(∧),
or
(∨),
not
(q),...
deve vericarsi nel prossimo stato;
g
ϕ
deve essere vera per ogni stato futuro;
Fϕ (f inally): ϕ
deve vericarsi in almeno uno stato futuro;
ψ Uϕ (until): ψ
deve esser vera almeno nché non si verica
ϕ;
ψ Wϕ (weak until o unless): ϕ deve esser vera nché non diventa vera ψ ;
se questa non diventa mai vera allora
ˆ
quanticatori di cammino:
ϕ
deve rimanere vera per sempre.
CAPITOLO 1.
CONCETTI BASE
Eϕ (exists):
13
esiste almeno un cammino in cui si verica
a
Aϕ ( ll): in tutti i cammini
ϕ
ϕ;
è vera.
In Figura 1.4 vediamo due esempi di formule esprimibili con la logica CTL: la prima
gura (a) è la rappresentazione graca della formula AFϕ, ovvero asserisce che in
ciascun cammino percorribile dallo stato iniziale, la proprietà
ϕ si verica in almeno
uno stato. La seconda gura (b) rappresenta l'espressione EGϕ ed indica che esiste
almeno un percorso in cui la proprietà
ϕ
è sempre vericata.
Come si può notare, la distinzione principale tra le due logiche è proprio il riferimento
ai cammini, che nella logica LTL non compare.
In realtà cercare di fare un paragone tra i due tipi di logica è piuttosto dicile: hanno
caratteristiche dierenti e alcune formule esprimibili in CTL non lo sono in LTL (e
viceversa) [Maz]. Ad esempio, non esiste modo in CTL di rappresentare l'espressione
LTL FGϕ, perché ci si deve riferire ad un intero cammino; allo stesso modo non è
possibile con la logica LTL esprimere una formula CTL del tipo AG(EFϕ) poiché
sono presi in considerazione tutti i cammini futuri .
D'altra parte l'algoritmo di verica del model checking deve vericare una formula
ϕ
rispetto a un determinato modello; per poter confrontare formula e struttura
è necessario per la logica LTL rappresentare anche la formula stessa tramite un
automa a stati niti, in modo tale che la procedura di verica cerchi intersezioni
tra i due automi: se ve ne sono allora il modello soddisfa la formula, altrimenti
la verica fallisce.
Il tempo di esecuzione di un algoritmo per la verica di una
formula LTL è esponenziale rispetto alla dimensione della formula e lineare rispetto
alla dimensione del modello (che solitamente è esponenziale rispetto alla dimensione
degli stati), quindi in termini di ecienza presenta qualche dicoltà.
La logica CTL è meno potente in termini di formule esprimibili, ma il tempo di
esecuzione di un algoritmo di verica di una formula CTL è lineare sia rispetto alla
dimensione della formula che rispetto al numero degli stati.
È quindi dicile fare un paragone e determinare quale delle due logiche sia migliore;
entrambe hanno degli aspetti che le rendono indispensabili al ne della verica di
un modello.
1.2.2 Il processo del model checking
I passi di un processo di verica tramite model checking sono i seguenti:
ˆ
denizione di un modello del sistema;
CAPITOLO 1.
CONCETTI BASE
14
ˆ
specica di un insieme di proprietà mediante logiche temporali CTL ed LTL;
ˆ
verica delle speciche mediante appositi tool (NuSMV, SPIN, PRISM, ecc...).
Modellazione
In questa fase si richiede di rappresentare il sistema secondo un modello formale; il
primo passo è quello di determinare tutte le caratteristiche che il modello deve avere
per ottenere da esso un funzionamento corretto. Possiamo cercare di descrivere il
sistema in termini di stati, dove uno stato rappresenta una descrizione del sistema in
un determinato istante di tempo; è anche necessario capire come cambia il sistema
al vericarsi di particolari eventi. Tali evoluzioni possono essere descritte in termini
di transizioni tra due stati. Per quanto detto è facile capire che una modellazione
formale del sistema può avvenire grazie all'utilizzo di una struttura di Kripke.
Consideriamo un esempio per capire come possiamo utilizzare le strutture di Kripke
per modellare un semplice sistema reale; prendiamo in considerazione una lavatrice
che può avere quattro possibili congurazioni (stati):
S0 : la lavatrice è spenta e con l'oblò aperto e non ha ricevuto alcun comando;
S1 : la lavatrice viene accesa ma l'oblò è aperto;
S2 : viene chiuso l'oblò ma la lavatrice non riceve alcun comando di accensione;
S3 : la lavatrice è chiusa e accesa. Entra quindi in funzione e vi rimane nché
non termina il lavaggio.
Il modello che rappresenta le suddette speciche è rappresentato in Figura 1.5.
Figura 1.5: Esempio di modellazione con macchina a stati niti di una lavatrice.
CAPITOLO 1.
CONCETTI BASE
15
Specica
Prima di vericare il modello di sistema denito al passo precedente, è necessario
capire quali proprietà tale sistema deve soddisfare, e quindi esprimerle secondo una
logica che, solitamente, è quella temporale.
Le logiche temporali permettono di esprimere proprietà relative all'evoluzione del
sistema nel tempo; le proprietà di maggiore interesse in questo tipo di verica sono
solitamente le seguenti:
ˆ
safety : sono proprietà che dicono che una condizione deve sempre vericarsi,
oppure che una certa condizione di pericolo non deve mai vericarsi per la
sicurezza del sistema. Nell'esempio della lavatrice potremmo esprimere, secondo le due logiche, la proprietà che indica che se la lavatrice sta lavando,
allora l'oblò deve essere stato chiuso e deve essere rimasto chiuso ntanto che
la lavatrice lava:
ˆ
CTL:
AG
LTL:
G
(washing
(washing
⇒A(closed U
⇒closed U
washing);
washing);
fairness : sono proprietà che indicano che determinate azioni devono vericarsi innitamente spesso. Nell'esempio possiamo cercare di vericare che la
lavatrice si riporti nello stato iniziale in qualunque stato ci troviamo:
ˆ
CTL:
AG AF(qstart ∧ qclosed);
LTL:
GF (qstart ∧ qclosed);
liveness : sono proprietà spesso riconducibili alle prime due e che esprimono che
una determinata condizione deve vericarsi in futuro. Sono spesso utilizzate
per individuare degli errori in fase di specica, un comportamento atteso che
non si verica.
Nel caso d'esempio possiamo formulare una proprietà che
indica che la lavatrice prima o poi entra in funzione:
CTL:
AF
LTL:
F
washing;
washing;
Verica
La parte di verica permette inne di constatare se il modello soddisfa o meno
le speciche considerate. Questa parte di model checking è svolta in automatico
da un apposito tool (una volta tradotto il modello secondo il formalismo utilizzato
dal programma scelto), da parte dell'utente è richiesta un'analisi dei risultati della
verica, soprattutto quando la risposta è negativa.
In tal caso viene fornita una
CAPITOLO 1.
CONCETTI BASE
16
traccia d'errore o un controesempio così da aiutare il modellatore a capire dove è
stato commesso un errore; d'altra parte la risposta negativa può essere anche un
falso negativo, nel senso che può esser stata formulata male una qualche specica
oppure la modellazione è errata.
Inne possiamo avere un'esplosione di stati nel
modello e quindi la verica potrebbe terminare a causa della dimensione dello stesso
senza una risposta.
1.2.3 Applicazioni odierne
Oggigiorno il model checking è uno strumento molto utilizzato per la verica dei
sistemi; esistono molti programmi per il model checking, ognuno dei quali si basa su
tecniche diverse. Un problema comune riguarda l'esplosione degli stati; è necessario
risolvere questo problema se si vogliono vericare sistemi che rispecchino la realtà
e sono stati trovati diversi approcci.
Di seguito ne vedremo due:
l'utilizzo dei
BDDs (Binary Decision Diagrams) e di tecniche di soddisfacibilità proposizionale,
entrambe utilizzate da NuSMV, strumento di model checking oggetto del lavoro di
questa tesi.
BDD-based model checking
Un BDD è una struttura dati utilizzata per rappresentare funzioni booleane; possiamo vedere tale struttura come una rappresentazione compressa di un insieme di
relazioni e le operazioni vengono eettuate direttamente sui dati compressi.
Figura 1.6: Esempio di trasformazione da binary decision tree a BDD.
CAPITOLO 1.
CONCETTI BASE
17
Una funzione booleana può essere rappresentata come un grafo aciclico orientato, costituito da nodi di decisione e due nodi terminali chiamati terminale-0 e
terminale-1.
Ogni nodo di decisione è etichettato da una variabile booleana ed
ha due gli nodi, uno basso e l'altro alto; l'arco verso un foglio basso (alto)
rappresenta un assegnamento della variabile pari a 0 (1). Un BDD è detto ordinato
se più variabili compaiono nello stesso ordine in tutti i percorsi dalla radice, mentre
è detto ridotto se unisce ogni sotto-grafo isomorfo e se elimina ogni nodo i cui due
gli sono isomor.
In Figura 1.6 vediamo un albero binario di decisione e una tabella di verità della
funzione
f (x1 , x2 , x3 ) = −x1 · −x2 · −x3 + x1 · x2 + x2 · x3 .
Nell'albero a sinistra
il valore può essere determinato assegnando ad una variabile un valore e seguendo
il percorso corretto (linea tratteggiata se 0, linea intera se 1).
A destra invece
è rappresentato l'albero binario di decisione ridotto secondo le due regole.
Già
dall'esempio si capisce che un BDD risulta più compatto rispetto ad una tabella
di verità o ad un albero di decisione; in generale si può arrivare ad ottenere una
riduzione esponenziale della dimensione del grafo, e da questo fatto si intusce il
legame con il problema dell'esplosione degli stati.
SAT-based model checking
Nella teoria della complessità, un problema di soddisfacibilità (SAT) è un problema
decisionale, il cui scopo è istanziare un'espressione booleana utilizzando solo AND,
OR, NOT, variabili e parentesi; il problema è se, data una espressione, esiste una
qualche combinazione di assegnamenti VERO/FALSO alle variabili che renda l'intera
espressione vera.
Una formula espressa in logica proposizionale è detta soddisfacibile se possono essere
assegnati dei valori logici alle variabili in modo tale che a formula risulti vera.
Il
problema della soddisfacibilità booleana è NP-completo.
Ci sono due classi di algoritmi molto ecienti per la risoluzione di problemi SAT: la
prima utilizza una variante moderna dell'algoritmo DPLL, come Cha o GRASP, la
seconda classe utilizza algoritmi di ricerca stocastica, come WalkSAT.
Un DPLL-SAT-solver impiega una procedura di ricerca all'indietro per esplorare lo
spazio (di dimensione esponenziale) degli assegnamenti delle variabili per trovare un
assegnamento che soddis l'espressione [Bau00].
CAPITOLO
2
Il tool NuSMV2
Lo sviluppo di questa tesi è basato sulla necessità di rendere più semplice l'utilizzo
del model checker NuSMV. Lo sviluppo di un'interfaccia graca per questo tool necessita una conoscenza dello strumento per sfruttare tutte le funzionalità di maggior
rilievo che lo caratterizzano.
In questo capitolo verrà data una panoramica generale del tool e saranno sottolineati
quegli aspetti che si sono dimostrati fondamentali nello sviluppo del progetto.
2.1 Introduzione al tool
NuSMV è un model checker simbolico originato a partire dalla reingegnerizzazione,
reimplementazione ed estensione di SMV, l'originale model checker basato su BDD
(Binary Decision Diagram) sviluppato alla Carnegie Mellon University [McM93].
La prima versione di NuSMV (cui faremo riferimento con NuSMV1) sostanzialmente implementa un model checking simbolico basato su BDD, mentre l'ultima
versione (NuSMV2 in seguito) eredita tutte le funzionalità della versione precedente
e le estende in diverse direzioni: la novità principale che ritroviamo in NuSMV2
è l'integrazione di tecniche di model checking basata su soddisfacibilità proposizionale (SAT). Le tecniche BDD e SAT per il model checking riescono a risolvere
classi diverse di problemi e per questo possono anche essere considerate tecniche
complementari.
18
CAPITOLO 2.
IL TOOL NUSMV2
19
NuSMV2 è distribuito con una licenza OpenSource [Ope], è quindi utilizzabile gratuitamente da chiunque sia interessato ed è possibile contribuire al suo sviluppo;
lo scopo del progetto OpenSource NuSMV è quello di realizzare una comunità
per la ricerca, l'implementazione ed il confronto di tecniche per il model checking.
NuSMV2 è stato rilasciato a Novembre 2001 e da allora è in continuo sviluppo.
2.1.1 Funzionamento del sistema
NuSMV elabora le scritti nell'estensione del linguaggio SMV; in tale linguaggio è
possibile descrivere macchine a stati niti per mezzo di meccanismi di istanziazione e
dichiarazione di moduli e processi, che rappresentano rispettivamente composizioni
sincrone e asincrone; i requisiti sono specicati secondo le logiche temporali LTL e
CTL.
+
Un le SMV è elaborato in diverse fasi [CCG 02].
La prima fase richiede di analizzare il le d'ingresso così da costruire una rappresentazione interna del sistema. Partendo da una descrizione modulare di un modello
M
e da un insieme di proprietà
P1 , ..., Pn
il primo passo è quello di rappresentare
l'istanziazione dei tipi di modulo, creando cioè moduli e processi, e produrre un modello
Mf
sincrono e piatto, dove ogni variabile data ha un nome assoluto (modulo
attening in Figura 2.1).
Il modello ottenuto è dunque mappato su un altro modello booleano
M f b , passando
attraverso la fase di codica booleana che provvede ad eliminare le variabili scalari.
Lo stesso procedimento è applicato a tutte le proprietà
Pi , ottenendo così la versione
Pif b .
Inne per ridurre il problema di esplosione degli stati è possibile restringere l'analisi
di ogni proprietà alle parti rilevanti del modello
M f b (Pif b ),
mediante la riduzione
del cono di inuenza [BSC98].
Questa prima fase è svolta indipendentemente dal tipo di model checking utilizzato
per la verica e una volta terminata l'utente può decidere se applicare model check-
+
ing basato su tecnologia BDD o SAT [CGP 02].
Nel primo caso possono essere
applicate diverse strategie di verica: analisi di raggiungibilità, CTL model checking, LTL model checking via riduzione a CTL model checking, calcolo quantitativo
delle caratteristiche del modello.
Nel caso di SAT-based model checking NuSMV2 costruisce una rappresentazione
interna del modello base su una versione semplicata di Reduced Boolean Circuit
(RBC), un meccanismo di rappresentazione per formule proposizionali [ABE00]. È
quindi possibile ottenere SAT model checking di formule LTL, cioè dato un margine
di lunghezza del controesempio, un problema di model checking LTL viene codicato
CAPITOLO 2.
IL TOOL NUSMV2
20
come un problema SAT. Se viene trovato un modello proposizionale, allora esso
corrisponde al controesempio del problema originale di model checking.
2.1.2 Architettura del sistema
L'architettura interna è ben denita e organizzata secondo diversi componenti, se-
+
parati in moduli, ognuno con una funzionalità ben precisa [CGP 02]. In Figura 2.1
vediamo uno schema della struttura interna di NuSMV2.
Figura 2.1: Struttura interna di NuSMV2.
L'architettura è composta dai seguenti moduli:
Flattening :
implementa il parsing del modello, ne controlla la consistenza in modo
da garantire la fondatezza delle denizioni e crea un modello piatto e
scalare eliminando moduli e processi.
Encoding :
è responsabile di mappare il modello ottenuto al passo precedente in un
modello booleano. Questo richiede l'introduzioni di variabili booleane
adeguate che dipendono dal range di variabili scalari che devono essere
manipolate; quindi per ogni proposizione atomica, viene costruita la
corrispondente espressione booleana.
CAPITOLO 2.
IL TOOL NUSMV2
Cone of Inuence :
21
riduce l'analisi del modello ad una FSM ridotta, contenente
solo le variabili rilevanti per ogni proprietà; tale riduzione è disponibile
sia per BDD che per SAT model checking.
BDD-based Model Construction :
implementa la macchina a stati niti corrispon-
dente al le in ingresso, in termini di BDD.
BDD-based Verication :
implementa l'analisi di raggiungibilità, LTL e CTL mo-
del checking e un'analisi quantitativa in termini di strutture dati della FSM; Il CTL model checking è implementato direttamente, mentre
LTL è ricondotto a CTL mediante una particolare costruzione, descritta
in [CGH94].
BDD Package :
si occupa delle funzionalità per la manipolazione e la memoriz-
zazione dei Binary Decision Diagrams; tale modulo è basato sul pacchetto Colorado University Decision Diagram (CUDD) [Som].
Reduced Boolean Circuit (RBC):
è un pacchetto che implementa una versione
semplicata della struttura dati RBC e delle primitive associate per la
memorizzazione e la manipolazione di formule proposizionali [ABE00].
Viene fornito con una routine di attraversamento depth-rst, che permette di navigare l'RBC, applicando una data funzione ad ogni nodo
visitato. Questa funzione è alla base del convertitore CNF (Conjunctive
Normal Form) [Cnf].
Bounded Model Checker :
fornisce le funzionalità per il SAT-based model checking;
interagisce con il pacchetto RBC per generare una rappresentazione di
modello basata sulla struttura RBC; a basso livello è denita una corrispondenza tra variabili di stato a dierenti istanti di tempo e variabili
RBC. Una volta generato il modello il Bounded Model Checker può
costruire il problema SAT corrispondente alla data formula; in particolare durante la costruzione si tiene conto di tutti i componenti del
modello. Il problema è generato in RBC, convertito in formato CNF e
mandato in ingresso al SIM SAT Solver. Se viene trovato un modello
proposizionale, allora viene restituito al Bounded Model Checker che
avvia la costruzione del controesempio.
SIM SAT Solver :
SIM è un SAT solver è basato sull'algoritmo DPLL [Bau00];
le sue caratteristiche permettono un'accelerazione complessiva del SAT
+
checker, e quindi dell'intero sistema [CFF 01].
Simulation/Trace Manipulation :
permette la simulazione interattiva e randomi-
ca del comportamento del modello processato ed è compatibile con
entrambe le rappresentazioni BDD e SAT.
CAPITOLO 2.
IL TOOL NUSMV2
22
2.2 Formalismo di descrizione dei modelli
NuSMV utilizza un proprio linguaggio per la denizione dei modelli da vericare;
di seguito mostreremo gli aspetti più importanti del formalismo utilizzato, ovvero
quegli aspetti indispensabili per l'implementazione del progetto. Per qualsiasi ap-
+
profondimento si veda [CCJ ].
2.2.1 Panoramica dei tipi
NuSMV riconosce diversi tipi di elementi:
boolean:
integer:
include due interi (0 e 1) o i loro equivalenti simbolici (false e true);
rappresenta qualsiasi numero intero, positivo o negativo, compreso tra
−232 + 1
enumeration:
e
232 − 1;
è un tipo rappresentato dall'enumerazione di tutti i valori che il tipo
comprende; tutti gli elementi devono essere unici, mentre l'ordine non ha
nessuna importanza. È possibile un ulteriore suddivisione in symbolic enum
(gli elementi sono unicamente simboli costanti e non numeri), integer-andsymbolic enum (comprende sia numeri che simboli) e integer enum (un elenco
di interi);
word[•]:
è utilizzato per modellare array di bit (boolean) che permettono operazioni
bit-a-bit logiche e aritmetiche;
array:
rappresenta un vettore e devono essere specicati indice inferiore, indice
superiore e tipo.
2.2.2 Denizione di FSM
NuSMV considera una macchina a stati niti in termini di variabili di stato, variabili
di ingresso (che possono assumere valori diversi in diversi stati), di una relazione di
transizione e di vincoli di Fairness.
La
denizione di una variabile
avviene tramite l'identicatore (nome della varia-
bile), la specica del tipo ed eventualmente i valori assunti; la lista delle variabili
denite deve essere preceduta dalla keyword VAR.
Il valore iniziale, i vincoli sugli stati e la relazione di transizione possono essere
deniti in due modi diversi:
CAPITOLO 2.
IL TOOL NUSMV2
1. Assignment style.
23
Assegna esplicitamente un valore iniziale alle variabili e
denisce la relazione di transizione considerando ogni caso:
(a)
init(id_var) := simple_expression
per assegnare il valore iniziale
ad una variabile;
(b)
next(id_var) := next_expression
per assegnare lo stato futuro.
Le assegnazioni sono precedute dalla keyword ASSIGN. Sono inoltre presenti
alcune regole da rispettare, ovvero: ogni variabile può essere assegnata una
sola volta e un insieme di equazioni non deve avere cicli.
2. Constraint style. Permette di denire il modello specicando vincoli su stati
e transizioni nel seguente modo:
(a) vincolo INIT: l'insieme degli stati iniziali è determinato da un'espressione
booleana preceduta dalla keyword INIT e non può contenere l'operatore
next().
(b) vincolo INVAR: l'insieme degli stati invarianti può essere specicato
da un'espressione booleana preceduta dalla keyword INVAR e non può
contenere l'operatore next().
(c) vincolo TRANS: la relazione di transizione di un modello costituita
da un insieme di coppie stato corrente/stato futuro.
Un'espressione
booleana introdotta dalla parola chiave TRANS determina se una coppia
è contenuta o meno in questo insieme.
Gli svantaggi di questo tipo di denizione è che è possibile ottenere un modello non consistente, ad esempio senza uno stato iniziale, oppure avere una
relazione di transizione non totale. Può anche vericarsi un non determinismo
sulle transizioni nascosto nel vincolo.
Si osservi che è molto semplice passare dallo stile Assignment a quello Constraint,
mentre non è vero il viceversa, anzi può risultare molto complicato se non addirittura
impossibile.
Un
vincolo di fairness
restringe l'attenzione solo su percorsi di esecuzione cor-
retti, ovvero su quei percorsi di esecuzione lungo i quali una data formula è vera
innitamente spesso.
Inne la
dichiarazione di un modulo rappresenta una collezione di denizioni, vin-
coli e speciche; si può confrontare un modulo con una classe nella programmazione
ad oggetti. È possibile istanziare un modulo ed accedere alle variabili denite; istanziando un modulo con la keyword
modulo stesso.
process
si ottiene un'esecuzione asincrona del
CAPITOLO 2.
IL TOOL NUSMV2
24
2.2.3 Speciche
Le speciche da vericare su una FSM sono espresse in termini di logiche temporali,
come CTL ed LTL estese con determinate funzionalità; è anche possibile analizzare
caratteristiche di una macchina a stati niti specicando formule CTL real-time.
Le speciche possono essere inserite senza riferimento a un modulo preciso, nel qual
caso sono preprocessate per rinominare le variabili in accordo al loro contesto.
Quando una formula è valutata come non vera, NuSMV genera un controesempio
che ne dimostra la falsità.
2.3 Utilizzo del tool NuSMV2
NuSMV è eseguito principalmente da riga di comando; l'utente può inserire i comandi di sistema con varie opzioni. Un comando è una sequenza di parole, di cui
la prima specica il comando che deve essere eseguito e le restanti parole sono
argomenti che il comando invoca. Più comandi separati da ';' sono eseguiti sequenzialmente; la shell di NuSMV attende nché non è terminato il turno di esecuzione
di un comando.
È anche possibile permettere a NuSMV di leggere ed eseguire una sequenza di
comandi da un le attraverso l'opzione
-load.
Di seguito mostreremo alcuni dei comandi più importanti, classicati in varie categorie.
2.3.1 Lettura e costruzione di un modello
Vedremo di seguito alcuni comandi necessari per il parsing e la compilazione del
modello nel BDD.
ˆ read_model [-h] [-i model-file]:
legge un le NuSMV; se l'opzione -i
non è specicata, legge dal le specicato nella variabile d'ambiente input-le,
altrimenti legge il le specicato.
ˆ flatten_hierarchy [-h]:
appiattisce la gerarchia dei moduli.
ˆ show_vars [-h] [-s] [-i] [-m | -o output-file]:
stampa le varia-
bili di stato e di ingresso con i rispettivi valori; è possibile stampare unicamente
uno dei due tipi e reindirizzare l'output su output-le o su un programma
specico, a seconda dell'opzione scelta.
CAPITOLO 2.
IL TOOL NUSMV2
25
ˆ encode_variables [-h] [-i order-file]:
costruisce le variabili BDD
necessarie a compilare il modello.
ˆ build_model [-h] [-f] [-m Method]:
compila la gerarchia appiattita nel
BDD utilizzando il metodo specicato dall'utente o dalla variabile d'ambiente
corrispondente.
ˆ go [-h] [-f]:
inizializza il sistema per la verica; è equivalente alla sequen-
za di comandi read_model; atten_hierarchy; encode_variables; build_model.
ˆ process_model [-h] [-f] [-r] [-i model-file] [-m Method]:
esegue
il gruppo di step e ritorna il controllo alla shell.
ˆ write_flat_model [-h] [-o filename]:
scrive il modello SMV attual-
mente caricato nel le specicato, dopo averlo appiattito.
I processi sono
eliminati e viene stampato il modello equivalente.
ˆ write_boolean_model [-h] [-o filename]:
scrive il modello SMV at-
tualmente caricato nel le specicato, dopo averlo appiattito e booleanizzato.
I processi sono eliminati e viene stampato il modello equivalente.
2.3.2 Controllo delle speciche
I seguenti comandi consentono di eettuare la verica (BDD.based) di un modello
NuSMV:
ˆ compute_reachable [-h]:
calcola l'insieme degli stati raggiungibili.
ˆ print_reachable_states [-h] [-v]:
stampa il numero di stati raggiun-
gibili del modello. Con l'opzione -v stampa anche gli stati raggiungibili.
ˆ check_fsm [-h] [-m | -o output-file]:
verica se la relazione di tran-
sizione è totale e in caso contrario è mostrato un potenziale stato di deadlock.
ˆ print_fsm_states [-h] | [-m] | [-o output-file]:
mostra le infor-
mazioni relative agli stati e ad ogni cluster.
ˆ check_invar [-h] [-m | -o output-file] [-n number | -p invar
-expr [IN context]]:
esegue il model checking degli stati invarianti del
modello.
ˆ check_ctlspec [-h] [-m | -o output-file] [-n number | -p ctl
-expr [IN context]]:
esegue CTL model checking anche rispetto ad
un'unica formula specicandone il contesto.
CAPITOLO 2.
IL TOOL NUSMV2
26
ˆ check_ltlspec [-h] [-m | -o output-file] [-n number | -p ltl
-expr [IN context]]:
esegue model checking delle formule LTL dopo
averle riportate in CTL.
ˆ compute [-h] [-m | -o output-file] [-n number | -p compute-
expr [IN context]]:
è in grado di determinare la lunghezza del più corto
o del più lungo percorso tra uno stato iniziale e uno nale; se esiste un
percorso innito che inizia da uno stato e non arriva mai allo stato nale,
allora è ritornato innity ; se lo stato iniziale o nale è vuoto allora è ritornato
undened.
ˆ check_property [-h] [-n number] | [( -c | -l | -i | -s | -q )
[-p formula [IN context]]]:
verica una proprietà data la lista delle
proprietà correnti, oppure una nuova specicata dall'utente.
ˆ add_property [-h] [( -c | -l | -i | -s | -q )-p formula [IN
context]]:
aggiunge una proprietà alla lista.
2.3.3 Simulazione e tracce
Verranno descritti i comandi che permettono di simulare una specica NuSMV e di
manipolare le tracce.
Una traccia è una sequenza di coppie stato-ingresso corrispondente ad una possibile
esecuzioni del modello; ogni coppia contiene l'ingresso che causa la transizione al
nuovo stato, ed il nuovo stato stesso.
Lo stato iniziale non ha input specicato
poiché non dipende da nessun valore dell'ingresso.
Le tracce sono create da NuSMV quando viene trovata una formula falsa, oppure
create da una simulazione. Ogni traccia ha un numero, e le coppie input-stato sono
numerate dentro la traccia.
ˆ pick_state [-h] [-v] [-r | -i [-a]] [-c constraints]:
sceglie
un elemento dall'insieme degli stati iniziali e lo imposta a stato corrente.
ˆ simulate [-h] [-p | -v] [-r | -i[-a]] [-c constraints] steps:
gene-
ra una sequenza di step di stati, iniziando da quello corrente; la simulazione
può essere di tre tipi:
deterministica, random o interattiva.
La sequenza
risultante è memorizzata in una traccia indicizzata.
ˆ print_current_state [-h] [-v]:
denito.
stampa il nome dello stato corrente, se
CAPITOLO 2.
IL TOOL NUSMV2
27
ˆ show_traces [-h] [-v] [-t] [-m | -o output-file] [-a | trace number]
[-p plugin-no]:
mostra le tracce correntemente memorizzate nel sistema, se
esistono.
ˆ read_traces [-h] [-i file-name]:
carica delle tracce precedentemente
salvate.
2.4 Esempi
In questa sezione mostreremo degli esempi di interesse, mostrati nel Tutorial di
+
NuSMV [CCK ].
Gli stessi esempi saranno poi ripresentati con il programma
realizzato (B.2).
2.4.1 Inverter Ring
Il seguente programma rappresenta un anello costituito da tre invertitori ed è
mostrato in Figura 2.2.
MODULE inverter(input)
VAR
output : boolean;
ASSIGN
init(output) := 0;
next(output) := !input;
FAIRNESS running
MODULE main
VAR
gate1 : process inverter(gate3.output);
gate2 : process inverter(gate1.output);
gate3 : process inverter(gate2.output);
Figura 2.2: Codice NuSMV del modello Inverter Ring.
Fra tutti i moduli istanziati con la keyword
process,
uno è scelto in modo non
deterministico e gli assegnamenti dichiarati in quel processo sono eseguiti in parallelo. È implicito che se una data variabile non è assegnata dal processo allora il suo
valore rimane immutato.
Poiché il sistema non forza l'esecuzione di un determinato processo, l'output di una
data porta può rimanere costante, indipendentemente dall'input.
CAPITOLO 2.
IL TOOL NUSMV2
28
Per forzare l'esecuzione di un processo innitamente spesso si utilizza il vincolo
di fairness, che restringe l'esecuzione del model checker solo su quei percorsi di
esecuzione lungo i quali una data formula è vera innitamente spesso.
Eseguendo la simulazione sull'esempio mostrato si ottiene il seguente output:
***
***
***
***
This is NuSMV 2.4.3 (compiled on Sun Jan 18 09:51:57 UTC 2009)
For more information on NuSMV see <http://nusmv.irst.itc.it>
or email to <[email protected]>.
Please report bugs to <[email protected]>.
NuSMV > go
NuSMV > pick_state -r
NuSMV > simulate -r 5
******** Simulation Starting From State 1.1
********
NuSMV > show_traces -v
<!-- ################### Trace number: 1 ################### -->
Trace Description: Simulation Trace
Trace Type: Simulation
-> State: 1.1 <gate1.output = 0
gate2.output = 0
gate3.output = 0
-> Input: 1.2 <_process_selector_ = gate1
running = 0
gate3.running = 0
gate2.running = 0
gate1.running = 1
-> State: 1.2 <gate1.output = 1
gate2.output = 0
gate3.output = 0
-> Input: 1.3 <_process_selector_ = gate3
running = 0
gate3.running = 1
gate2.running = 0
gate1.running = 0
-> State: 1.3 <gate1.output = 1
CAPITOLO 2.
->
->
->
->
->
->
IL TOOL NUSMV2
29
gate2.output = 0
gate3.output = 1
Input: 1.4 <_process_selector_ = gate1
running = 0
gate3.running = 0
gate2.running = 0
gate1.running = 1
State: 1.4 <gate1.output = 0
gate2.output = 0
gate3.output = 1
Input: 1.5 <_process_selector_ = gate2
running = 0
gate3.running = 0
gate2.running = 1
gate1.running = 0
State: 1.5 <gate1.output = 0
gate2.output = 1
gate3.output = 1
Input: 1.6 <_process_selector_ = gate3
running = 0
gate3.running = 1
gate2.running = 0
gate1.running = 0
State: 1.6 <gate1.output = 0
gate2.output = 1
gate3.output = 0
In Appendice B.4.1 sono presenti il le NuSMV ed i risultati della verica relativi
allo stesso esempio il cui modello di sistema è stato realizzato con l'interfaccia
sviluppata.
CAPITOLO 2.
IL TOOL NUSMV2
30
2.4.2 Mutual Exclusion
Il seguente programma è un altro esempio di modello asincrono; utilizza una variabile
semaforo per implementare la mutua esclusione tra due processi asincroni.
Ogni processo ha quattro stati: idle, entering, critical ed exiting; lo stato entering
indica che un processo vuole accedere alla sezione critica, in cui si può entrare solo
se la variabile semaforo è libera. Entrando nello stato critical la variabile è settata
ad uno ed entrando dello stato exiting il semaforo è liberato.
Il programma è mostrato in Figura 2.3.
MODULE main
VAR
semaphore : boolean;
proc1
: process user(semaphore);
proc2
: process user(semaphore);
ASSIGN
init(semaphore) := 0;
SPEC AG ! (proc1.state = critical & proc2.state = critical);
SPEC AG (proc1.state = entering -> AF proc1.state = critical);
MODULE user(semaphore)
VAR
state : {idle, entering, critical, exiting};
ASSIGN
init(state) := idle;
next(state) :=
case
state = idle
: {idle, entering};
state = entering & !semaphore : critical;
state = critical
: {critical, exiting};
state = exiting
: idle;
1
: state;
esac;
next(semaphore) :=
case
state = entering : 1;
state = exiting : 0;
1
: semaphore;
esac;
FAIRNESS
running
Figura 2.3: Codice NuSMV del modello Mutual Exclusion.
Eseguendo come per l'esempio precedente il programma NuSMV su tale le si
ottiene il seguente output:
CAPITOLO 2.
***
***
***
***
IL TOOL NUSMV2
31
This is NuSMV 2.4.3 (compiled on Sun Jan 18 09:51:57 UTC 2009)
For more information on NuSMV see <http://nusmv.irst.itc.it>
or email to <[email protected]>.
Please report bugs to <[email protected]>.
NuSMV > go
NuSMV > pick_state -r
NuSMV > simulate -r 5
******** Simulation Starting From State 1.1
********
NuSMV > show_traces -v
<!-- ################### Trace number: 1 ################### -->
Trace Description: Simulation Trace
Trace Type: Simulation
-> State: 1.1 <semaphore = 0
proc1.state = idle
proc2.state = idle
-> Input: 1.2 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
-> State: 1.2 <semaphore = 0
proc1.state = idle
proc2.state = idle
-> Input: 1.3 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
-> State: 1.3 <semaphore = 0
proc1.state = idle
proc2.state = entering
-> Input: 1.4 <_process_selector_ = main
running = 1
proc2.running = 0
proc1.running = 0
CAPITOLO 2.
IL TOOL NUSMV2
-> State: 1.4 <semaphore = 0
proc1.state = idle
proc2.state = entering
-> Input: 1.5 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
-> State: 1.5 <semaphore = 1
proc1.state = idle
proc2.state = critical
-> Input: 1.6 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
-> State: 1.6 <semaphore = 1
proc1.state = idle
proc2.state = exiting
NuSMV > check_ctlspec
-- specification AG !(proc1.state = critical &
proc2.state = critical) is true
-- specification AG (proc1.state = entering ->
AF proc1.state = critical) is false
-- as demonstrated by the following execution sequence
Trace Description: CTL Counterexample
Trace Type: Counterexample
-> State: 2.1 <semaphore = 0
proc1.state = idle
proc2.state = idle
-> Input: 2.2 <_process_selector_ = proc1
running = 0
proc2.running = 0
proc1.running = 1
-- Loop starts here
32
CAPITOLO 2.
IL TOOL NUSMV2
-> State: 2.2 <proc1.state = entering
-> Input: 2.3 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
-> State: 2.3 <proc2.state = entering
-> Input: 2.4 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
-> State: 2.4 <semaphore = 1
proc2.state = critical
-> Input: 2.5 <_process_selector_ = proc1
running = 0
proc2.running = 0
proc1.running = 1
-> State: 2.5 <-> Input: 2.6 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
-> State: 2.6 <proc2.state = exiting
-> Input: 2.7 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
-> State: 2.7 <semaphore = 0
proc2.state = idle
33
CAPITOLO 2.
IL TOOL NUSMV2
34
Anche l'esempio Mutual Exclusion è mostato in Appendice B.4.2: sono presenti il
le NuSMV ed i risultati della verica relativi al modello di sistema, realizzato con
l'interfaccia sviluppata.
CAPITOLO
3
Mappatura FSM - NuSMV
Esiste un legame tra un modello denito secondo il formalismo di NuSMV e la FSM
che lo rappresenta; in questo capitolo verrà descritto come è possibile passare da
una descrizione tramite FSM a un modello in linguaggio NuSMV.
In generale un modulo NuSMV può rappresentare più macchine a stati niti contemporaneamente (o annidate o che lavorano in parallelo), ma per mantenere una certa
consistenza si è deciso di mappare una FSM per modulo NuSMV, così da non complicare eccessivamente il processo di traduzione.
Questa decisione non comporta
alcun tipo di restrizione nella denizione del modello nale.
3.1 Stati e transizioni
In NuSMV non esistono stati e transizioni così come siamo soliti considerarli: ogni
elemento denito all'interno di un modulo è una variabile.
Di ogni variabile può
essere denito il valore iniziale e il valore successivo all'attuale, che può variare a
seconda delle condizioni che si vericano.
Mettendo a confronto una macchina a stati niti ed il linguaggio NuSMV il primo passo è quello di capire come possono essere rappresentati gli stati secondo il
programma; poiché ogni elemento è una variabile, anche gli stati dovranno rappresentare in qualche modo una variabile. In particolare se una FSM è costituita da n
35
CAPITOLO 3.
MAPPATURA FSM - NUSMV
36
Figura 3.1: Rappresentazione di una macchina a stati niti con n stati e della variabile
corrispondente denita secondo il linguaggio NuSMV.
stati diversi, la variabile che verrà denita avrà n possibili valori, ognuno coincidente
con uno stato (Figura 3.1); quindi la variabile che denisce gli stati della FSM sarà
di tipo
symbolic enum
+
[CCJ ].
Una volta decisa la mappatura degli stati da FSM a NuSMV, ci interessa capire
come denire le transizioni tra gli stati: NuSMV utilizza due tecniche distinte per
denire valore iniziale e valori successivi delle variabili: la regola ASSIGN oppure
INIT/INVAR/TRANS (Capitolo 2.2.2). Per evitare di denire modelli inconsistenti
si è preferito utilizzare il primo tipo di assegnazione; inoltre è più diretta la traduzione
da transizione di una FSM al costrutto
next(var)
presente in ASSIGN.
Figura 3.2: Esempio di macchina a stati niti con transizioni deterministiche.
Consideriamo per il momento solo macchine a stati niti con transizioni deterministiche, ovvero in cui ogni transizione ha una condizione denita; in questo caso
denire i cambiamenti della variabile di stato è immediato. Consideriamo l'esempio
in Figura 3.2: la variabile di stato corrispondente è
cui valore iniziale è dato da
ˆ
stato attuale:
state:={s0, s1, s2, s3}
init(state):=s0;
a seconda dei casi si ha:
s0
se si verica
c01
lo stato futuro sarà
s1 ;
se si verica
c02
lo stato futuro sarà
s2 ;
il
CAPITOLO 3.
ˆ
ˆ
stato attuale:
37
s1
se si verica
c12
il prossimo stato sarà
se si verica
c13
lo stato successivo sarà
stato attuale:
ˆ
MAPPATURA FSM - NUSMV
s3 ;
s2
se si verica la condizione
stato attuale:
s2 ;
c23
allora lo stato futuro sarà
s3 ;
s3
al vericarsi della condizione
c30
lo stato successivo sarà
s0 .
La traduzione nel linguaggio NuSMV è immediata; infatti si ha:
next(state) :=
case
state = s0
state = s0
state = s1
state = s1
state = s2
state = s3
1 : state;
esac;
&
&
&
&
&
&
c01
c02
c12
c13
c23
c30
:
:
:
:
:
:
s1;
s2;
s2;
s3;
s3;
s0;
Il caso di default (espresso con 1 in linguaggio NuSMV) è trattato sempre allo stesso
modo per tutte le variabili, assegnando come stato futuro quello attuale; come si
vede dall'esempio la traduzione dell'intero modello è in questo caso immediata.
D'altra parte è vero che una macchina a stati niti di questo tipo è molto semplice
e poco utile; per denire sistemi più complessi è necessario utilizzare anche le azioni
sugli stati.
3.2 Azioni sugli stati
Le azioni sugli stati permettono di denire determinate attività in base alle circostanze; abbiamo tre tipi di azioni:
ˆ
Onentry actions: si vericano ogni volta che si entra in uno stato;
ˆ
During actions: si vericano quando si rimane nello stato;
CAPITOLO 3.
ˆ
MAPPATURA FSM - NUSMV
38
Onexit actions: si vericano tutte le volte che si esce da uno stato.
In NuSMV non c'è niente che si ricolleghi a questo tipo di elemento, che è infatti strettamente legato al concetto di macchina a stati niti.
Per eettuare la
traduzione delle azioni in linguaggio NuSMV è stato necessario denire più regole
rispetto al caso precedente, in cui invece la mappatura era immediata. Ci chiediamo
che tipo di operazioni sono supportate dalle azioni descritte sopra, quali variabili
coinvolgono e inne come possono essere legate a NuSMV.
Come prima cosa possiamo sicuramente aermare che tali azioni non dovranno
coinvolgere in nessun modo gli stati della FSM: esse infatti modicheranno esclusivamente le altre variabili coinvolte nella denizione del modello e da cui possono
dipendere le condizioni delle transizioni.
Ognuna delle azioni ha un meccanismo di mappatura diverso; per capire meglio
come verranno tradotte è utile appoggiarsi a qualche semplice esempio.
3.2.1 Azione Onentry
Consideriamo il caso illustrato in Figura 3.3: abbiamo due stati (A e
variabile
a
(supponiamo che
nché la variabile
a
a
B
ed una
possa variare tra 0 e 10). Si rimane nello stato
è minore di dieci, dopodiché si passa nello stato
variabile è azzerata; da
B)
si torna sempre in
A
B,
A
in cui la
.
Figura 3.3: Esempio di macchina a stati niti con azione onentry.
Osserviamo che si ha un cambiamento di valore sia per la variabile di stato che per
la variabile
a;
per lo stato il procedimento è lo stesso descritto prima. È naturale
chiedersi in funzione di cosa è espresso il cambiamento della variabile
sappiamo che quando si entra nello stato
mentre quando si passa allo stato
B
A
a,
ad esempio
la variabile è incrementata di uno,
la variabile
a
è posta uguale a zero. L'unico
CAPITOLO 3.
MAPPATURA FSM - NUSMV
39
modo per tradurre questo comportamento in termini di NuSMV è quello di esprimere
l'azione di ingresso in uno stato in termini di stato di partenza e di transizione
avvenuta; in altri termini:
ˆ
stato attuale:
se
A
a = 10
allora lo stato successivo è
B;
entrando si attiva l'azione
a = 0;
ˆ
se
a < 10 allora lo stato successivo è sempre A (esco e rientro); entrando
in
A
si attiva l'azione
stato attuale:
a = a + 1;
B
lo stato successivo è
A;
entrando in
A
si attiva l'azione
a = a + 1.
Ragionando in questi termini è possibile denire secondo il linguaggio NuSMV sia
come variano gli stati che come cambia la variabile, a seconda dello stato in cui
ci troviamo e delle condizioni che si vericano; infatti il corrispondente modello in
linguaggio NuSMV è il seguente:
next(state) :=
case
state = A &
state = A &
state = B &
1 : state;
esac;
next(a) :=
case
state = A &
state = A &
state = B &
1 : a;
esac;
a < 10 : A;
a = 10 : B;
1 : A;
a < 10 : a+1;
a = 10 : 0;
1 : a+1;
In sostanza le variabili coinvolte nelle azioni onentry subiscono variazioni ogni volta
che si entra nello stato in questione; è quindi naturale esprimere tali variazioni in
termini di stati e azioni che portano allo stato considerato.
CAPITOLO 3.
MAPPATURA FSM - NUSMV
40
3.2.2 Azione Onexit
Il principio che sta alla base della traduzione delle azioni onexit in linguaggio NuSMV
è lo stesso di quello che coinvolge le azioni onentry: le modiche subite dalle variabili
in seguito al vericarsi di un'azione onexit possono essere espresse sempre in termini di stati e condizioni sulle transizioni, in questo caso però verranno considerate
tutte le condizioni che permettono di uscire dallo stato considerato. Consideriamo
l'esempio descritto in Figura 3.4.
Figura 3.4: Macchina a stati niti con azioni onexit.
Come nell'esempio precedente si hanno due stati (A e
B)
ed una variabile
a,
che
assume valori da zero a dieci ed il cui meccanismo è esattamente lo stesso. L'unico
cambiamento evidente sta nel fatto che le azioni sugli stati
AeB
sono di tipo onexit
e quindi il comportamento dell'automa risulta leggermente diverso dal precedente.
L'azione viene eseguita solo quando si esce dallo stato quindi una prima dierenza
B
sta nel fatto che dallo stato
(mentre prima passando da
B
allo stato
ad
A
A
la variabile viene posta pari a zero
la variabile a assumeva valore uguale ad uno),
inoltre anche le condizioni di transizione devono essere cambiate: infatti lasciando
a = 10
sulla transizione da
A
a
B
ed uscendo dal primo stato,
a
sarebbe stata
incrementata di uno, arrivando così ad undici, che è un valore che la variabile non
può assumere.
Il meccanismo di traduzione è sostanzialmente lo stesso:
considerato uno stato
avente un'azione di tipo onexit, si applicano le variazioni alle variabili coinvolte per
ogni transizione uscente da quello stato. Possiamo riscrivere l'esempio nel seguente
modo:
ˆ
Stato attuale
se
A
a = 9 si passa allo stato B ;
uscendo da
A si attiva l'azione a = a + 1;
CAPITOLO 3.
ˆ
se
MAPPATURA FSM - NUSMV
a < 9 si esce e si rientra in A; uscendo da A si attiva l'azione a = a+1;
Stato attuale
41
B
lo stato successivo è
A
ed uscendo da
B
si attiva l'azione
a = 0;
A questo punto la traduzione è immediata e in linguaggio NuSMV si ottiene:
next(state) :=
case
state = A & a < 9 : A;
state = A & a = 9 : B;
state = B & 1 : A;
1 : state;
esac;
next(a) :=
case
state = A & a < 9 : a+1;
state = A & a = 9 : a+1;
state = B & 1 : 0;
1 : a;
esac;
3.2.3 Azione During
L'ultimo tipo di azione sugli stati che andiamo a considerare è l'azione during, che
si verica solo quando si rimane nello stato stesso (diverso dal caso del cappio, in
cui si esce e si rientra nello stesso stato).
Anche per l'azione during è possibile
esprimere le variazioni delle variabili coinvolte in termini di stati e di transizioni, così
da tradurle in linguaggio NuSMV, anche se in questo caso il procedimento è un po'
più complesso. Consideriamo l'esempio in Figura 3.5 che è una nuova rappresentazione della macchina a stati niti descritta negli esempi precedenti. L'evoluzione
degli stati è sempre la stessa e anche la variabile
a
assume sempre gli stessi valori
e le variazioni sono le stesse, sono però espresse in termini di azione during (nello
stato
A)
e onexit (nello stato
B ).
Non è presente il cappio sullo stato
la variabile cambia rimanendo nello stato
A
A
in quanto
ntanto che non raggiunge il valore
necessario ad attivare la transizione verso lo stato
B.
Se scriviamo il modello in forma testuale, in termini di stati e transizioni si ottiene:
ˆ
Stato attuale
A
CAPITOLO 3.
MAPPATURA FSM - NUSMV
42
Figura 3.5: Esempio di macchina a stati niti con azione during.
ˆ
se
altrimenti si rimane in
a = 10
Stato attuale
lo stato successivo è
A
B;
e si attiva l'azione
a = a + 1;
B
si passa allo stato
A
e si attiva l'azione
a = 0;
Si noti che nello scrivere la condizione di attivazione dell'azione during si devono
considerare prima tutte le transizioni uscenti dallo stato attuale; se nessuna condizione si verica allora si rimane nello stato e l'azione during si attiva. In termini
di traduzione a linguaggio NuSMV è necessario eettuare l'and logico di tutte le
negazioni delle condizioni sulle transizioni uscenti.
Per il nostro esempio si ottiene:
next(state) :=
case
state = A & a = 10 : B;
state = B & 1 : A;
1 : state;
esac;
next(a) :=
case
state = A & !(a = 10): a+1;
state = B & 1 : 0;
1 : a;
esac;
CAPITOLO 3.
MAPPATURA FSM - NUSMV
43
3.3 Transizioni non deterministiche
Fin'ora abbiamo considerato i casi in cui le condizioni sulle transizioni sono esplicitamente espresse.
Però non è sempre detto che in una macchina a stati niti le
transizioni siano deterministiche, o comunque in alcuni casi sarebbe comodo non
dover scrivere le condizioni, ad esempio se consideriamo gli esempi in Figura 3.3, 3.4
e 3.5, la transizione che porta dallo stato
B
allo stato
A ha specicata la condizione
1; in una situazione di questo tipo si potrebbe evitare di inserire tale condizione,
poiché è ovvio che una volta in
B
necessariamente si passa allo stato
A.
Un'altra situazione è quella in cui eettivamente non si hanno condizioni che determinano un passaggio di stato; se consideriamo l'esempio in Figura 3.6 possiamo
Figura 3.6: Esempio di macchina a stati niti con transizioni non deterministiche.
osservare che l'unica condizione presente è quella relativa alla transizione che porta dallo stato
stato
C,
A
allo stato
dallo stato
verica la condizione
to
C.
C
c1
B.
Infatti dallo stato
si passa allo stato
A
B
si passa necessariamente allo
ed inne dallo stato
si può rimanere nello stato
A
A,
se non si
oppure andare nello sta-
Questo scenario si può vericare in innumerevoli casi, è quindi importante
considerare eventualità come la suddetta.
In linguaggio NuSMV non è un problema scrivere le transizioni sugli stati e sulle
variabili per casi come quello esposto; nel nostro caso invece dobbiamo considerare le
azioni sugli stati, le quali sono espresse proprio in termini di stati e condizioni delle
transizioni; pertanto, se le condizioni non sono espresse, non è sempre possibile
esprimere il cambiamento delle variabili.
abbiamo:
ˆ
Stato attuale
A
Infatti, relativamente al nostro esempio
CAPITOLO 3.
MAPPATURA FSM - NUSMV
se
altrimenti, o si va in
a = 10
si passa allo stato
attiva l'azione
ˆ
Stato attuale
ˆ
B;
oppure si esce e si rientra in
A
e in tal caso si
a = a + 1;
B
C
il prossimo stato è
Stato attuale
C
44
e si attiva la condizione
a = 0;
C
si passa allo stato
A,
attivando l'azione
a = a + 1;
La traduzione in NuSMV non è in questo caso possibile, infatti otteniamo:
next(state) :=
case
state = A & a = 10 : B;
state = A & !(a = 10) : {A, C};
state = B & 1 : A;
1 : state;
esac;
next(a) :=
case
state = B : 0;
state = C : a + 1;
state = A : ???;
1 : a;
esac;
Il problema riguarda sostanzialmente la transizione sulle variabili coinvolte in un'azione
sullo stato attivata da una transizione non deterministica. Nel nostro esempio se ci
troviamo nello stato
andare in
C,
A,
potendo scegliere senza condizione se tornare in
non è possibile capire quando si attiva la condizione
A
oppure
a = a + 1.
Questa è una forte limitazione al modello, infatti l'utente che utilizza un tool per la
modellazione di sistemi tramite FSM deve avere la possibilità di inserire transizioni
non deterministiche.
Supponiamo per il momento di aggiungere una nuova variabile
v
al modello (Figura
3.7); in questo modo la nuova variabile condiziona le transizioni, e quindi permette
di capire quando attivare l'azione
modello in alcun modo.
Infatti si ha:
a = a+1
dallo stato
A,
pur non modicando il
CAPITOLO 3.
MAPPATURA FSM - NUSMV
45
Figura 3.7: Modello di Figura 3.6 con aggiunte della variabile v.
ˆ
ˆ
Stato attuale
se
a = 10
si passa allo stato B;
se
a 6= 10
e
v=1
si esce e si rientra in
A
se
a 6= 10
e
v=2
lo stato successivo è
C;
Stato attuale
ˆ
A
a = a + 1;
B
il prossimo stato è
Stato attuale
e si attiva l'azione
C
e si attiva la condizione
a = 0;
C
si passa allo stato
A,
attivando l'azione
a = a + 1;
La traduzione in questo modo è immediata, ovviamente si deve anche considerare
che le transizioni attivate da
uscenti da
A
v
si vericano solo quando non si vericano le altre
(nel nostro caso ne è presente una sola, ma se ce ne fosse più di una
dovremmo considerare l'and logico delle negazioni di ognuna); inoltre deve essere
aggiunto il cambiamento della nuova variabile. Otteniamo:
next(state) :=
case
state = A &
state = A &
state = A &
state = B &
1 : state;
a =
!(a
!(a
1 :
10 : B;
= 10) & v = 1 : A;
= 10) & v = 2 : C;
A;
CAPITOLO 3.
MAPPATURA FSM - NUSMV
46
esac;
next(a) :=
case
state = A & !(a = 10) & v = 1: a+1;
state = B : 0;
state = C : a + 1;
1 : a;
esac;
next(v) :=
case
state = A & !(a = 10) & v = 1: {1, 2};
state = C : {1, 2};
1 : v;
esac;
Si osservi che ogni volta che si entra nello stato
A
è necessario assegnare a
v
un
valore (casuale!) tra 1 e 2, così da permettere comunque il non determinismo della
transizione, pur avendo specicato le condizioni che attivano i cambiamenti dallo
stato
A.
D'altra parte chiedere all'utente di fare esplicitamente tutti i suddetti passaggi è
poco naturale a livello di implementazione di macchina a stati, questo è un problema
che ha a che fare solo con la traduzione del modello in le NuSMV, pertanto
l'utente non deve occuparsi di tali operazioni.
La variabile
v
ipotizzata è creata
automaticamente in fase di traduzione con un nome e dei valori più signicativi, in
modo tale che nella fase di verica sia comunque comprensibile . La sintassi è:
nondet_choice_nomeStato = {end_state_1, ..., end_state_n}
dove
ˆ
nomeStato rappresenta il nome dello stato da cui partono le transizioni non
deterministiche;
ˆ
end_state_i rappresenta il nome dello stato stato raggiungibile dalla transizione i-esima.
Nell'esempio avremo:
nondet_choice_A = {A, C}
Nel caso più banale in cui la transizione non deterministica uscente da uno stato è
unica, viene automaticamente messa la condizione 1, sempre in fase di traduzione.
CAPITOLO 3.
MAPPATURA FSM - NUSMV
47
È gestito anche il caso in cui da uno stato si hanno due transizioni uscenti con la
medesima condizione: in questa situazione viene comunque creata la variabile di
scelta e la condizione verrà aggiunta a quella già presente.
CAPITOLO
4
Graphic User Interface
In questo capitolo verrà fornita una panoramica sulla teoria che sta alla base dello
sviluppo delle interfacce grache; la prima parte descriverà lo sviluppo e l'inuenza
che le interfacce hanno avuto nel corso della storia, dando quindi un signicato ben
preciso al tipo di lavoro svolto in questa tesi. Dopodiché descriveremo le tecniche
principali di sviluppo di una GUI soermandoci in particolare sulle caratteristiche
utilizzate per lo sviluppo del progetto.
4.1 Un po' di storia
Al giorno d'oggi la maggior parte delle persone interagisce con computer o dispositivi elettronici quotidianamente, per svago, studio, lavoro o per altre necessità;
qualunque individuo si trovi davanti un tale apparecchio si aspetta di trovare un'interfaccia graca che sia semplice e intuitiva da utilizzare per comunicare col dispositivo in questione; nel caso di un personal computer se muovo il mouse mi aspetto
che il puntatore si muova in un certo modo, se apro un editor di testo e premo la
lettera 'A' sulla tastiera mi aspetto che compaia la stessa lettera sul monitor. Meccanismi simili valgono anche per telefoni cellulari, o comunque per qualsiasi altro
apparecchio elettronico che richiede l'interazione da parte di un utente esterno.
Ovviamente non è sempre stato così; è normale chiedersi come sono nate le interfacce grache e come si sono evolute nel corso della storia.
48
CAPITOLO 4.
GRAPHIC USER INTERFACE
49
4.1.1 I primi anni
La prima intuizione di interfaccia graca nacque ancora prima di avere le tecnologie
adatte alla sua realizzazione. L'idea venne ad uno scienziato statunitense di nome
Vannevar Bush, che negli anni '30 immaginò di realizzare un dispositivo capace
di archiviare, organizzare e visualizzare libri, testi, immagini, comunicazioni, ecc...
Diede al dispositivo il nome di Memex (dall'unione di memory e index); in Figura
4.1 vediamo un'immagine di come avrebbe dovuto essere in base alle descrizioni
riportate.
Figura 4.1: Memex
Pur sapendo che la sua macchina non era ancora realizzabile immaginò come la
tecnologia del suo tempo avrebbe potuto evolversi ed unirsi ed ipotizzò anche le
conseguenze che un apparecchio simile avrebbe potuto avere; nel 1945 pubblicò
l'articolo As We May Think [Bus45] in cui parlava del Memex e dove scriveva: compariranno nuovi tipi di enciclopedie confezionate con una rete di percorsi
associativi che le collegano, pronte ad essere inserite in memex e qui ampliate .
Il Memex non venne mai realizzato, ma ispirò trenta anni dopo l'uomo considerato
come il pioniere dell'interazione tra uomo e macchina: Douglas Engelbart. Negli
anni '50 - '60 gli unici computer esistenti erano dei mainframes giganteschi in cui
venivano inserite delle schede forate in base al problema che si voleva analizzare e
solitamente veniva fornita una risposta soltanto dopo diverse ore o addirittura giorni.
Engelbart, dopo aver letto con molto interesse la pubblicazione di Bush, studiò i
CAPITOLO 4.
GRAPHIC USER INTERFACE
50
computer e, grazie alla sua esperienza di tecnico radar, capì che le informazioni
potevano essere visualizzate su monitor; nel 1955 diede così via al suo lavoro presso
lo Stanford Research Institute.
Nel 1962 pubblicò l'articolo Augmenting Human Intellect: a Conceptual Framework [HMU00], dove immaginava il computer come uno strumento per accrescere
l'intelletto umano e non per sostituirlo; uno degli esempi ipotetici descritti fu un
qualcosa che aiutasse un architetto a progettare i suoi disegni, un qualcosa di molto
simile al moderno software graco CAD.
La sua ricerca suscitò grande interesse presso l'agenzia ARPA (Advanced Research
Projects Agency, poi rinominata DARPA: DefenseARPA) che nanziò il suo progetto, così nel 1968 Douglas ed il suo sta mostrarono pubblicamente i risultati di 6
anni di ricerca in un sistema chiamato NLS (oN-Line System, Figura 4.2).
Figura 4.2: Dispositivo oN-Line System.
L'apparecchio era comandato da tre dispositivi di input: una tastiera standard, una
tastiera a corde con 5 elementi (per produrre
25
diversi input, necessari per le
lettere dell'alfabeto) e una piccola scatola rettangolare, con tre pulsanti in alto,
collegata al computer da un lo, ovvero quello che oggigiorno viene comunemente
chiamato mouse. Vediamo in Figura 4.3 i tre dispositivi.
Con l'invenzione del mouse venne l'invenzione del puntatore, rappresentato da una
linea verticale dell'altezza del carattere e inizialmente chiamato bug; quando
un'oggetto era selezionato il bug lasciava un punto sullo schermo per marcare
tale azione.
4.1.2 Gli anni '70
La dimostrazione di Douglas aprì gli occhi a molte persone, facendo capire che
in un lontano futuro sarebbe stato possibile comunicare con documenti elettronici
CAPITOLO 4.
GRAPHIC USER INTERFACE
51
Figura 4.3: Dispositivo d'ingresso per NLS.
visualizzati su monitor di computer e trasmettere informazioni istantaneamente. Un
tale futuro non appariva così roseo a una compagnia che basava la sua fortuna sulla
vendita di fotocopiatrici.
Così l'amministrazione della compagnia Xerox, temendo la scomparsa della propria
azienda in vista di un futuro senza carta, decise di prendere il controllo della situazione per quanto riguardava quel campo e fondò, nel 1970, la Palo Alto Research
Center, o PARC.
Uno dei primi prodotti inventati fu la stampante, ma tale invenzione richiedeva
una metodologia migliore per creare documenti che poi venissero stampati e poiché
ancora non c'erano computer in grado di fare ciò, PARC, e in particolare Butler
Lampson, inventò il proprio e lo completò nel 1973, nominandolo Alto (Figura 4.4).
Lo Xerox Alto era dotato di 128 KB di memoria centrale espandibile a 512 KB, di
un hard disk su cartuccia removibile di 2,5 MB ed era grande quanto un frigorifero.
Non fu mai messo in commercio, ma la sua produzione durò per circa dieci anni;
una parte dei computer fu data in dotazione a università e centri di ricerca, dando
così il via all'industria informatica.
La prima interfaccia graca realizzata per Alto fu Smalltalk, nato da un gruppo di
ricerca diretto da Alan Kay, è stato concepito come un linguaggio di programmazione
che sostenesse la simbiosi tra uomo e calcolatore [Kay93] e fu il primo esempio
di programmazione orientata agli oggetti. Insieme al linguaggio nacque, nel 1974,
anche l'ambiente di sviluppo smalltalk (Figura 4.5), la prima interfaccia graca di
tipo WIMP (Window, Icon, Menu, Pointing device), oggi in uso nella maggior parte
dei computer.
Nel 1976, Steve Jobs, Steve Wozniak, and Ronald Wayne fondarono in un garage
CAPITOLO 4.
GRAPHIC USER INTERFACE
52
Figura 4.4: Lo Xerox Alto.
una piccola azienda chiamata Apple Computer con lo scopo di assemblare e vendere
computer; il primo prodotto fu l'Apple I, che visualizzava sia graca che testo, ma
aveva una tradizionale interfaccia a linea di comando. Nel 1979 Jobs e alcuni suoi
dipendenti visitarono la Xerox PARC per vedere lo Xerox Alto, così Jobs si convinse
che tutti i computer futuri avrebbero dovuto avere un'interfaccia graca, iniziò così
lo sviluppo della GUI Apple Lisa. Venne introdotto il concetto di icona, di menu a
cascata, di scorciatoia da tastiera, e ancora la disattivazione da menu delle opzioni
non disponibili, drag & drop e altre ancora.
4.1.3 Interfacce grache dagli anni '80 ad oggi
Apple Lisa venne messo in vendita soltanto nel 1983, ma l'alto costo e la dicoltà
di sviluppo di nuovo software ne limitarono le vendite, così nacque l'idea di produrre
un computer graco a basso costo e venne avviato il progetto Macintosh che nel
1984 venne messo in vendita.
A partire da quel momento molte aziende cominciarono a sviluppare interfacce
grache per personal computer; nel 1983 la VisiCorp produsse il software VisiOn
per PC IBM da cui Bill Gates prese spunto, impegnandosi a produrre un prodotto
competitivo, inizialmente chiamato Interface Manager e poi rinominato Windows; fu
rilasciato nel 1985 e aveva tutte la caratteristiche della GUI introdotta da Apple Lisa.
CAPITOLO 4.
GRAPHIC USER INTERFACE
53
Figura 4.5: Ambiente di sviluppo a GUI Smalltalk.
Nell'ultima metà degli anni '80 vennero prodotti altri software come DeskMate per
Tandy Computers, il GEM introdotto dalla Digital Research, i computer Commodor
Amiga (che avevano una propria GUI: Amiga Workbench).
In seguito venne rilasciato il GEOS, che entrò in competizione con Windows, aggiornata nel 1987 alla versione 2.0; nel 1987 la Acorn Comupters introdusse la sua
prima GUI che introduceva alcune novità: un ripiano (o dock ) posto in basso sullo schermo che conteneva delle icone per lanciare velocemente i programmi, e la
funzionalità di anti-aliasing assieme alla modalità a 16 colori.
Il 1988 vide la nascita di NexTSTEP, la nuova GUI per il computer NeXT di Steve
Jobs, che fu il suo principale progetto dopo aver lasciato la Apple nel 1985. Aveva
la caratteristica del dock (movibile) per le shortcuts e in più introdusse un look 3D
per tutti i componenti e il simbolo X per la chiusura delle nestre.
Poco prima della ne degli anni '80 cominciarono ad apparire nuove GUI per le workstation Unix prodotte da AT&T, Sun, DEC e HP eseguite su una nuova architettura
chiamata X, ideata nel 1984 da Bob Scheier and Jim Gettys.
La losoa di X
era separare meccanismo e gestione, cioè dati gli strumenti base per manipolare
nestre e oggetti graci, l'aspetto nale dell'interfaccia dipendeva dal programma
individuale. Per fornire un'interfaccia consistente fu aggiunto un secondo strato di
codice chiamato window manager, il cui scopo era quello di visualizzare e posizionare
correttamente le nestre. In seguito venne aggiunto un ulteriore strato chiamato
desktop environment che completava il concetto di GUI, potevano essere create
CAPITOLO 4.
Figura 4.6:
GRAPHIC USER INTERFACE
54
(a) Macintosh System 1; (b) Windows 1.0; (c) Amiga Workbench; (d)
NexTSTEP.
delle librerie che, appoggiandosi alle librerie X, aggiungevano funzionalità grache
mancanti e semplicavano la programmazione di applicazioni grache per X.
All'inizio degli anni '90 gli unici superstiti della guerra delle GUI erano Microsoft e
Macintosh, e nel 1992 la release di Microsoft Windows 3.0 raggiunse una popolarità
mai vista prima. Anche se non aveva tutte le caratteristiche del Macintosh, le icone
avevano un bell'aspetto ed era molto diretto, così ne furono vendute milioni di copie.
Con l'avvento di Windows 95 la Microsoft è diventata l'azienda leader nella vendita
di GUI ed il software è stato uno dei più popolari di tutti i tempi.
Nel 1990 intanto la IBM si fa carico dello sviluppo di OS/2 (Operative System 2)
e nel 1991 rilascia la sua prima versione apportando delle modiche alla precedente
(che fu sviluppata in collaborazione con Microsoft), come uno swap più eciente,
diversi nuovi driver, un sistema di installazione più semplice e font di sistema ridisegnati. Nel '92 esce la versione 2.0, il primo vero e proprio sistema operativo per PC
a 32-bit; lo sviluppo va avanti no al 2006, quando IBM consiglia ai clienti OS/2
di passare al sistema operativo GNU/Linux.
Nel frattempo, basandosi sul Sistema X11, nacquero le librerie Kde e Gnome, che
determinarono la svolta di X: venne avviato un progetto per rendere le librerie di
X più snelle, modulari e con nuove funzionalità molto richieste dagli utenti, come
l'antialiasing e la graca 3D.
Anche la Apple creò una nuova GUI, chiamata Aqua, per il nuovo sistema operativo
CAPITOLO 4.
GRAPHIC USER INTERFACE
55
Mac OS X, portando nuovi miglioramenti, soprattutto riguardo il movimento delle
nestre.
Nell'ultimo decennio sono state realizzate moltissime versioni di GUI per diversi
sistemi operativi, visto il largo utilizzo che si fa oggi dei computer; lo scopo è sempre
quello di rendere più semplice e intuitivo l'utilizzo dei nuovi apparecchi elettronici
prodotti, e anche di rendere più gradevole all'occhio umano l'aspetto dei software
utilizzati.
4.2 Fondamenti dello sviluppo di una GUI
Possiamo vedere un'interfaccia di un programma come l'insieme dei modi con cui
esso può comunicare con l'utente e con altri programmi [Ray03]; abbiamo visto
come si sono evolute le GUI nel corso della storia e l'importanza che esse hanno
assunto al giorno d'oggi. È quindi importante capire come sia possibile realizzare
una buona interfaccia graca evitando numerose false partenze e perdite di tempo
dovute alla riprogettazione del software.
Una buona regola da seguire è quella della minima sorpresa: è un principio generale
per la buona progettazione di tutti i tipi di interfacce ed è una conseguenza del fatto
che l'uomo comincia a prestare attenzione a una sola cosa per volta [Ras00]. Se
in un interfaccia ci sono troppe sorprese, l'attenzione viene focalizzata su di esse
anziché sul compito che l'interfaccia deve svolgere. Quindi l'idea alla base della progettazione è quella di non disegnare un modello d'interfaccia totalmente nuova ma
cercare di prendere spunto da altri programmi conosciuti che hanno caratteristiche
simili a quello che si vuole progettare.
4.2.1 Stile di progettazione
Un passo importante nella progettazione di un'interfaccia è quello di decidere il tipo
di stile da adottare. Possiamo utilizzare cinque parametri per classicare lo stile:
ˆ concisione :
un programma d'interfaccia si dice conciso quando la lunghezza
e la complessità delle azioni richieste non sono mai troppo elevate (la misura
di tali prestazioni può essere fatta in base al tempo, al numero di battiture,
ecc..).
ˆ espressività :
un'interfaccia è espressiva se può essere facilmente usata per
compiere una ampia varietà di azioni. Con massima espressività si intende la
possibilità di controllare diverse combinazioni di azioni non previste da chi ha
CAPITOLO 4.
GRAPHIC USER INTERFACE
56
progettato il programma, ma che nonostante questo danno all'utente risultati
utili e consistenti.
ˆ semplicità :
è inversamente proporzionale al numero di cose che l'utente deve
ricordarsi per poter utilizzare l'interfaccia. Ad esempio le interfacce a riga di
comando hanno un alto carico mnemonico e sono meno semplici da utilizzare,
mentre interfacce con pulsanti o azioni etichettate sono più immediate e più
facili da usare per qualsiasi utente.
ˆ trasparenza :
la trasparenza di un interfaccia indica con quanta facilità un
utente tiene traccia dello stato del problema e dei dati durante l'utilizzo della
stessa.
Un alto grado di trasparenza si ha quando è naturalmente visibile
un risultato intermedio del problema, quando si hanno notiche di errori su
azioni non permesse, quando si ha una risposta ad una determinata azione
che l'utente compie, ecc... Le cosiddette interfacce WYSIWYG (What You
See Is What You Get) sono quelle che massimizzano la trasparenza.
ˆ scriptability :
indica la facilità con cui un interfaccia può essere manipolata
da altri programmi. Programmi scriptabili sono facilmente utilizzabili come
componenti esterni da altri programmi, riducendo così il costo necessario ad
implementare tutte le funzionalità di un software.
A seconda del software che si vuole progettare e in particolare degli utenti a cui è
destinato, sarà opportuno fare un compromesso tra le caratteristiche sopra descritte.
È quindi importante capire prima di tutto le funzionalità che un programma deve
avere e il tipo di utente che le deve utilizzare, su queste basi sarà inne possibile
scegliere lo stile che l'interfaccia deve avere.
4.2.2 Design pattern
Non è facile scrivere correttamente un software senza doverlo modicare o riprogettare in alcune sue parti; molto spesso non si riescono a considerare tutti i problemi, e comunque le soluzioni che si trovano non sempre sono le migliori. D'altra
parte una volta trovata una soluzione che funziona bene per un determinato problema è sempre possibile riutilizzarla per risolvere problemi dello stesso tipo che si
presentano più volte.
Ovviamente buone soluzioni si trovano col tempo, ma è
sempre possibile appoggiarsi all'esperienza di altri sviluppatori che hanno dovuto
arontare gli stessi ostacoli.
L'idea è quella di rendere disponibili idee e soluzioni funzionanti a chi ne ha bisogno per progettare un software riusabile, senza la necessità di reimplementarlo più
volte. I design pattern [GHJV94] stanno alla base di tale concetto e permettono al
CAPITOLO 4.
GRAPHIC USER INTERFACE
57
programmatore di prendere in considerazione diverse alternative nella fase di progettazione di un software e soprattutto permettono di ottenere un'implementazione
corretta molto più velocemente.
Ogni pattern descrive un problema che occorre più e più volte nel nostro ambiente,
e quindi descrive il cuore della soluzione a tale problema, così che si possa utilizzare
tale soluzione anche un milione di volte, senza dover fare la stessa cosa due volte [AIS97].
In generale un pattern è costituito da quattro elementi essenziali:
ˆ
il nome del pattern, che deve rappresentare il problema, la soluzione e le
conseguenze in una parola o due;
ˆ
il problema, che descrive quando il pattern deve essere applicato; deve essere
una spiegazione sia del problema che del contesto;
ˆ
la soluzione descrive gli elementi che compongono il modello, come sono
messi in relazione tra di loro tali elementi e come funzionano. Ovviamente,
poiché il pattern può essere applicato in diverse situazioni, non si avrà mai
una descrizione concreta dell'implementazione del modello.
ˆ
Le conseguenze sono i risultati e i compromessi dovuti all'applicazione del
pattern. È importante capire cosa si ottiene dopo aver implementato un determinato pattern, perché sarà sempre possibile fare un confronto tra pattern
diversi per scegliere quello le cui conseguenze sono le migliori.
Model View Controller
Per capire meglio cosa signica il termine pattern, consideriamo il modello MVC
(Model-View-Controller) utilizzato per costruire la prima interfaccia in Smalltalk-80
[KP88, Bur87].
L'MVC è un architectural pattern e consiste in tre tipi di oggetti: il modello rappresenta l'informazione che si vuole rappresentare; la vista è la tipologia di rappresentazione del modello e inne il controllore denisce il modo in cui l'interfaccia
reagisce ai cambiamenti del modello.
La caratteristica principale dell'MVC è il
disaccoppiamento del modello da tutte le sue possibili viste.
Si capisce che per
l'implementazione di interfacce grache rappresenta la soluzione ideale, infatti è
possibile denire un modello che rappresenta i dati dell'interfaccia, una vista che
fornisce all'utente l'informazione visiva di tali dati e un controllore che reagisce agli
input forniti dall'utente. Inoltre dato un modello è possibile implementare quante
più viste dello stesso, senza andare a toccare niente che riguardi l'informazione pura.
CAPITOLO 4.
GRAPHIC USER INTERFACE
58
Figura 4.7: Schema di Model-View-Controller.
Il funzionamento è mostrato in Figura 4.7:
ogni volta che un dato del modello
cambia, il modello notica il cambiamento a tutte le sue viste, in modo tale che
esse si aggiornino correttamente e rimangano sincronizzate con il modello. D'altra
parte quando un utente fornisce un input, la vista delega al controllore il compito
di modicare opportunamente il modello in base all'input ricevuto, così il modello
informa le viste della modica avvenuta.
Il problema del disaccoppiamento vista-modello è molto comune nelle interfacce, e
la soluzione a tale problema è fornito dal design pattern
Observer .
Un'altra caratteristica dell'MVC è l'annidamento delle viste: possiamo considerare
una vista di un modello generico in cui i suoi elementi sono rappresentati a loro
volta da altre viste contenute nella prima, e così via. Questo tipo di modello può
essere applicato a moltissimi altri esempi ed è rappresentabile mediante il design
pattern
Composite .
Se andiamo a considerare vista e controllore si capisce che ci possono essere innumerevoli tecniche per implementare la relazione che lega i due elementi; il design
pattern
Strategy
è un oggetto che rappresenta un algoritmo ed è utile quando si
hanno diverse varianti di algoritmi e se ne deve scegliere uno, oppure quando un
algoritmo ha una struttura dati complessa e la si vuole incapsulare.
In realtà ci sono molti altri design pattern che si possono applicare per implementare
caratteristiche diverse, anche se i tre introdotti sopra sono quelli che maggiormente
caratterizzano l'MVC; andiamo a vederli più in dettaglio.
CAPITOLO 4.
GRAPHIC USER INTERFACE
59
Observer
Nella progettazione di un sistema in cui si ha la cooperazione di diverse classi, è
importante mantenere la consistenza tra oggetti correlati, è importante avere un
certo disaccoppiamento tra oggetti così da assicurarne la riusabilità.
Se consideriamo l'esempio delle interfacce grache, è importante mantenere separate
modello e vista di un'informazione, così se vogliamo cambiare la rappresentazione
del modello (o aggiungerne una diversa) non dobbiamo andare a toccare il modello
stesso.
Il meccanismo che mette in relazione una vista e il suo modello è implementato dal pattern Observer/Observable: gli oggetti chiave di questo pattern sono il
soggetto e l'osservatore.
Un soggetto può avere un numero qualsiasi di osserva-
tori e questi non sono a conoscenza dell'esistenza degli altri, sono collegati solo al
modello (rappresentato dal soggetto). In gura 4.8 vediamo come è strutturato il
pattern.
Figura 4.8: Struttura del pattern Observer.
Ogni observer riceve una notica quando il soggetto viene modicato; in risposta
ogni observer interroga il soggetto per sincronizzarsi al suo stato attuale; questo
comporta che lo stato del soggetto deve essere consistente quando viene inviata
la notica, proprio perché l'observer ha bisogno delle informazioni dello stato per
sincronizzarsi correttamente.
Osserviamo che ogni subject sa di avere una lista di osservatori, ma non conosce
la classe concreta di nessuno, questo comporta un accoppiamento minimo tra
soggetto e observer; inoltre le notiche che vengono inviate non hanno bisogno di
uno specico destinatario, il messaggio è diuso automaticamente a tutti gli oggetti
interessati, ed il soggetto osservato non deve preoccuparsi di chi riceve la notica;
questo permette di aggiungere o rimuovere osservatori in qualunque momento oppure di consentire che una notica sia ignorata da un observer. È necessario prestare
attenzione al fatto che modicare un soggetto che ha diversi osservatori, può comportare un enorme lavoro per aggiornare tutti gli observer collegati nonché gli oggetti
CAPITOLO 4.
GRAPHIC USER INTERFACE
60
dipendenti da essi. È quindi buona norma capire prima le funzionalità che un subject
deve avere e poi implementare i vari observers.
In alcune situazioni può avere senso per un observer dipendere da più di un soggetto;
in questo caso è necessario estendere la funzionalità di update() in modo tale da
sapere quale dei soggetti osservati ha inviato la notica.
Composite
Quando si ha a che fare con applicazioni grache spesso un utente si trova a creare
diagrammi od oggetti complessi raggruppando insieme componenti base più semplici. Gli oggetti nali a livello implementativo sono trattati diversamente dalle classi
principali, anche se in realtà l'utente interagisce con entrambi allo stesso modo; di
conseguenza, dovendo distinguere tra questi due componenti, l'applicazione diventa
molto complessa.
Il pattern Composite è un pattern che descrive una composizione ricorsiva in modo
tale che chi utilizza l'applicazione non deve distinguere tra oggetti base e oggetti
composti; in Figura 4.9 vediamo la struttura di tale pattern.
Figura 4.9: Strutture del pattern Composite.
La classe astratta Component rappresenta sia l'elemento base che il contenitore;
il primo è implementato dalla generica classe Leaf, mentre un oggetto composto
è implementato dalla classe Composite. La classe astratta denisce le operazioni
base per i componenti primitivi, mentre per gli oggetti aggregati sono denite anche
operazioni che permettono di aggiungere o rimuovere elementi, ed altre per accedere
ai gli. L'utente interagisce con la classe Component, senza sapere se è un oggetto
CAPITOLO 4.
GRAPHIC USER INTERFACE
61
primitivo o un'aggregazione di oggetti diversi: l'operazione è eseguita direttamente
se l'oggetto è una foglia, altrimenti viene eseguita su tutti gli elementi gli che
compongono l'oggetto.
L'utilità di tale pattern è immediato se si pensa che un insieme di oggetti base può
essere composto più e più volte per ottenere un oggetto complesso qualunque senza
che chi utilizza tale oggetto si debba preoccupare di cosa si trova sotto mano; in
più il client può utilizzare la struttura composta come se fosse un oggetto unico e
questo semplica notevolmente il codice.
Aggiungere nuovi componenti base è sempre possibile e semplice in quanto non
è necessario modicare niente dell'implementazione corrente; in realtà questa caratteristica comporta qualche problema se vogliamo che una particolare struttura
contenga solo determinati elementi base.
Non è possibile infatti impedire di ag-
giungere un particolare oggetto, così elementi strutturati diversi devono avere implementazioni di Components diverse.
A livello implementativo è importante che un oggetto Component mantenga il riferimento ai propri gli e in realtà è utile anche mantenere il riferimento al proprio
elemento padre, così da rendere più semplice la gestione della struttura.
Strategy
Durante l'implementazione di un software può accadere che una determinata operazione possa essere espressa da algoritmi diversi e la scelta dell'algoritmo più adatto
può variare a seconda del contesto:
ad esempio possiamo denire più algoritmi
ognuno dei quali riette un compromesso spazio/tempo diverso, e in base alla situazione può essere più vantaggioso uno rispetto ad un altro. Oppure un algoritmo
può variare a seconda della struttura dati che si sta considerando o ancora può
essere utile applicare algoritmi diversi per diverse funzionalità di una classe.
Tutti questi problemi possono essere evitati utilizzando il pattern Strategy (in Figura
4.10 la struttura) che permette di denire classi che utilizzano algoritmi diversi a
Figura 4.10: Struttura del pattern Strategy.
CAPITOLO 4.
GRAPHIC USER INTERFACE
62
seconda della necessità.
La classe astratta Strategy denisce un'interfaccia comune per tutti gli algoritmi
supportati; tali algoritmi sono implementati dalle rispettive classi ConcreteStrategy
e l'oggetto Context può accedere all'algoritmo utilizzando tale interfaccia. Startegy
e Context interagiscono tra di loro per la scelta dell'algoritmo: il context può passare
tutti i dati necessari all'algoritmo o può passare se stesso come argomento delle
operazioni di Strategy.
CAPITOLO
5
Analisi e specica dei requisiti
La parte forse più importante nello sviluppo di un software è quella che permette
di denire quali caratteristiche il programma dovrà avere.
Ci sono diversi passi
da percorrere nello sviluppo di un progetto ed è importante prestare attenzione a
ciascuno di essi, per non sprecare tempo e risorse.
In questo capitolo verranno descritte le metodologie più comuni per l'implementazione di un progetto; in particolare verranno descritti gli step fondamentali utilizzati per denire il sistema nale. Alla ne del capitolo verrà fornito l'elenco dei
requisiti del programma e delle funzionalità che esso deve implementare sulla base
di quanto studiato.
5.1 Analisi del progetto
Come abbiamo già introdotto nel Capitolo 4, lo sviluppo di un'interfaccia graca o
di un software in generale, presenta diverse dicoltà: è dicile, se non impossibile,
pretendere di iniziare a implementare il programma senza aver analizzato attentamente quali caratteristiche esso debba avere e quali sono le strategie migliori da
utilizzare.
63
CAPITOLO 5.
ANALISI E SPECIFICA DEI REQUISITI
64
5.1.1 Ciclo di vita del software
Il ciclo di vita di un software (SDLC: Software Development Life Cycle) è un processo
che si appoggia a framework già esistenti che permettono di pianicare, strutturare
e controllare lo sviluppo del sistema; non è detto che ognuna di queste tecniche
sia applicabile a tutti i tipi di progetto, a seconda del tipo di sistema che si vuole
realizzare è necessario scegliere la metodologia di sviluppo più appropriata [dev05];
Figura 5.1: Tre framework basilari nello sviluppo di un software.
in Figura 5.1 vediamo una schematizzazione di alcuni modelli più utilizzati per
rappresentare il ciclo di vita di un sistema.
In generale, qualunque sia il modello che si sceglie di utilizzare, i passi principali che
ci si trova a dover arontare sono i seguenti:
ˆ specica dei requisiti :
in questa fase si cercano di individuare gli obiettivi
del sistema e le funzionalità che esso deve avere. È utile l'aiuto di diagrammi
specici per analizzare il sistema anche dal punto di vista dell'utente. È una
rappresentazione di cosa il sistema deve fare.
ˆ design :
rappresenta la prima fase d'implementazione del sistema vera e pro-
pria; si cerca di descrivere il sistema come un insieme di moduli, ognuno con
CAPITOLO 5.
ANALISI E SPECIFICA DEI REQUISITI
65
un compito diverso. Rappresenta quindi l'architettura macroscopica del software; si cerca cioè di determinare come il sistema farà quanto stabilito nella
fase precedente.
ˆ implementazione :
una volta determinata la struttura del progetto, è pos-
sibile iniziare la creazione dei moduli deniti al passo sopra, utilizzando un
linguaggio di programmazione scelto dallo sviluppatore.
ˆ verica :
in questa fase vengono eseguiti dei test per vericare il corretto
funzionamento dei moduli sviluppati e più in generale del comportamento
complessivo del sistema.
ˆ manutenzione :
comprende tutte le attività volte a migliorare, estendere e
correggere il sistema.
5.1.2 Prototyping
Il modello utilizzato nello sviluppo del progetto è detto modello evolutivo (o software prototyping): viene realizzato un modello semplicato del sistema con cui sia
possibile sperimentare le funzionalità più importanti così che si possano determinare
opportune modiche dei requisiti o una revisione del progetto generale; inoltre è
importante permettere all'utente di interagire con il prototipo realizzato, così da
ottenere importanti feedback per lo sviluppo nale [Dav92, Ber05].
Il software prototyping ha molte varianti, che comunque si appoggiano a due tipi
principali: throwaway prototyping e evolutionary prototyping.
Il primo è basato sul concetto che il prototipo costruito sarà scartato ed il sistema
nale sarà costruito sulle basi di esso; lo scopo dell'evolutionary prototyping è invece
quello si implementare un prototipo robusto, ben strutturato e in continua fase di
rinitura, così che costituisca il cuore del sistema nale su cui verranno applicati
miglioramenti nali.
L'approccio seguito nell'implementazione dell'interfaccia graca segue il principio
del throwaway prototyping, specialmente per i vantaggi che esso ore: in primo
luogo permette una realizzazione veloce di un prototipo, senza troppe riniture, dato
che al momento opportuno verrà messo da parte. Questo permette di concentrarsi
maggiormente sugli aspetti delle funzionalità che l'interfaccia deve avere, anziché
sul design, l'utilizzo e altri aspetti che comunque sono sì importanti nello sviluppo
di una GUI, ma non così fondamentali nella fase iniziale in cui si devono capire i
requisiti del sistema. Un'altro punto di forza di questo approccio è che, anche avendo
un modello di sistema non completamente rinito, è possibile eseguire dei test sul
CAPITOLO 5.
ANALISI E SPECIFICA DEI REQUISITI
66
prototipo per capire quali funzionalità debbano essere migliorate, quali aggiunte e
quali tolte.
I passi seguiti in questo tipo di approccio sono i seguenti:
1. Specica (preliminare) dei requisiti: si cerca di individuare le funzionalità più
importanti del sistema, considerando poi un'eventuale estensione.
2. Design del prototipo: dà una prima forma al sistema. Non necessariamente
il prodotto nale manterrà il design scelto ma sarà possibile determinarne i
punti di forza e gli svantaggi.
3. Esperienza da parte di utenti: è un test eettivo sul prototipo. Permette di
capire cosa va bene e cosa no; a partire da questo tipo di analisi vengono
rideniti i requisiti del sistema ed il design.
4. Ripetere i primi tre passi, se necessario.
5. Specica nale dei requisiti.
6. Sviluppo del prodotto nale.
Il vantaggio di aver seguito questo tipo di approccio è che lo sviluppo del sistema
nale è stato molto semplice e pulito, perché era già ben chiaro tutto quello che
andava fatto.
5.2 Denizione dei requisiti
La prima fase nello sviluppo di un software è costituita dalla denizione dei requisiti
del sistema, ovvero da ciò che il sistema deve fare.
È importante prestare molta
cura a questa fase in quanto caratterizza l'intero sviluppo del software e spesso un
errore comporta la riprogettazione di una parte del sistema.
Nella fase iniziale dello sviluppo del progetto, la denizione dei requisiti è stata fatta
pensando alla realizzazione di un prototipo che aiutasse a valutare concretamente
quali funzionalità il sistema dovesse avere, quali erano le problematiche più importanti e anche quale fosse il miglior approccio visivo con l'utente. Il prototipo è stato
provato da più utenti, tra cui gli sviluppatori del tool NuSMV stesso i quali hanno
fornito importanti consigli e suggerimenti sulle modiche da apportare al progetto;
sono stati così deniti i requisiti nali del sistema in base ai feedback ricevuti. Molte
problematiche non erano chiare n dall'inizio pertanto lo sviluppo di un prototipo è
stato molto utile ai ni del corretto sviluppo del sistema nale.
CAPITOLO 5.
ANALISI E SPECIFICA DEI REQUISITI
67
5.2.1 Analisi dei requisiti
Al ne di ottenere un insieme di requisiti esaustivi e corretti è necessario cercare
di analizzare il sistema dal punto di vista dell'utente, cioè senza preoccuparsi degli
aspetti implementativi, ma solo di quelli che riguardano l'utilizzo del sistema.
In
questo tipo di approccio si vede il sistema come una scatola nera in cui è possibile
osservare solo i comportamenti dall'esterno; questo tipo di punto di vista corrisponde
al modello dei casi d'uso, che rappresentano appunto i modi in cui il sistema può
essere utilizzato. Inoltre sono un importante punto di partenza per la progettazione
del sistema, per la denizione dei test nali e danno un'idea di come il sistema potrà
evolversi in futuro.
I diagrammi dei casi d'uso rappresentano una mappa visuale, molto sintetica, degli
utilizzi del sistema ; la parte importante è rappresentata dal testo, che descrive le
modalità di interazione con il sistema.
Gli elementi del modello sono i seguenti:
ˆ casi d'uso:
sono le funzionalità che il sistema mette a disposizione degli
utenti; la rappresentazione graca è quella di una ellisse.
ˆ attori:
sono i soggetti che interagiscono con il sistema tramite messaggi,
richieste, ecc.. Un attore è solitamente rappresentato da un omino stilizzato.
ˆ sistema di riferimento:
rappresenta un conne tra ciò che sta dentro al
sistema e ciò che sta fuori; è spesso indicato anche con il termine subject
ed è rappresentato da un rettangolo che contiene tutti i casi d'uso che lo
descrivono.
ˆ relazioni tra gli elementi del modello:
ogni caso d'uso è collegato agli
attori tramite delle associazioni, inoltre è possibile avere relazioni anche tra i
casi d'uso stessi; queste possono essere di:
generalizzazione/specializzazione : associa ad un caso d'uso generale uno
o più casi d'uso specializzati. Sono rappresentate da una linea continua
con una punta di freccia triangolare bianca.
inclusione : mette in relazione un caso d'uso con i passi necessari al suo
adempimento; è rappresentata da una linea tratteggiata con lo stereotipo
<<include>> con una punta di freccia aperta indirizzata dal caso d'uso
includente a quello incluso.
estensione : permette di estendere un caso d'uso base con il comportamento denito da un altro caso d'uso in particolari circostanze (è quindi
un caso opzionale); la rappresentazione è la stessa che per l'inclusione,
CAPITOLO 5.
ANALISI E SPECIFICA DEI REQUISITI
ma con lo stereotipo
<<extend>>,
68
dal caso d'uso d'estensione a quello
base.
Di seguito elencheremo i casi d'uso più importanti realizzati per la progettazione
del nostro sistema.
Scenario generale
L'utente può interagire con il sistema creando un modello che rappresenti un sistema di macchine a stati niti e poi vericando tale modello (Figura 5.2). Il modello
Figura 5.2: Diagramma del caso d'uso scenario generale.
sarà realizzato mediante un'implementazione graca dello stesso, seguendo un formalismo ben preciso. Una volta ottenuto il modello graco l'utente potrà generare
il le .smv da utilizzare con il tool NuSMV, oppure avviare una verica del modello
stesso, che utilizzerà comunque il tool NuSMV, ma in maniera del tutto trasparente
all'utente.
L'utente può salvare un modello e caricarlo successivamente, in questo modo anziché
iniziare a modellare un sistema dal principio, l'utente può caricare un modello
precedentemente salvato ed apportarvi delle modiche.
Inne l'utente può stampare il modello nel suo intero o può scegliere di stampare
solo le parti a lui necessarie.
CAPITOLO 5.
ANALISI E SPECIFICA DEI REQUISITI
69
Figura 5.3: Diagramma del caso d'uso implementazione graca
Implementazione graca
L'utente può implementare un modello graco mediante la creazione di moduli; tali
moduli sono navigabili ed è possibile cambiare la visuale del sistema (da modulo a
sottomodulo). Nella denizione di un modulo l'utente può aggiungere variabili, può
denire una macchina a stati niti, può aggiungere vincoli relativi al model checking
e può denire speciche secondo una logica temporale (LTL e CTL).
Ogni componente è rappresentato da un oggetto graco che lo contraddistingue.
In Figura 5.3 vediamo il diagramma del caso d'uso descritto.
Denizione variabili
L'utente può scegliere di aggiungere a un modulo un qualsiasi numero di variabili;
queste sono classicate a seconda del loro signicato e del loro utilizzo: le variabili locali rappresentano quelle variabili utilizzate solo a livello locale del modulo.
L'utente denisce variabili d'istanza quando vuole istanziare un modulo, mentre le
variabili di in/out rappresentano sempre variabili utilizzate internamente dal modulo,
ma permettono all'utente di creare un qualche collegamento tra i moduli istanziati.
Denizione variabili d'istanza
L'utente può decidere di istanziare un modulo in qualunque momento a partire da
un modulo già esistente, oppure creandone uno nuovo; una volta denita la variabile
d'istanza l'utente può denire gli ingressi e le uscite che il modulo deve avere e inne
CAPITOLO 5.
ANALISI E SPECIFICA DEI REQUISITI
70
Figura 5.4: Diagramma del caso d'uso denizione variabili.
può creare i collegamenti tra le variabili del modulo corrente eettuando così un
passaggio di variabili tra moduli istanziati e elementi del modulo che l'utente sta
denendo.
Un modulo istanziato può essere copiato così che l'utente possa crearne uno nuovo a
partire da uno già esistente; inoltre una variabile d'istanza può anche essere duplicata
così che si abbia una nuova variabile che istanzia sempre lo stesso modulo.
Denizione FSM
Assieme ai moduli, l'utente può anche denire macchine a stati niti aggiungendo
i componenti che la caratterizzano, ovvero stati, azioni sugli stati, transizioni con
relative condizioni per l'attivazione e variabili (locali, d'ingresso e di uscita). Ogni
componente ha il suo corrispondente oggetto graco con cui l'utente può interagire
e ognuno di questi oggetti può essere modicato o rimosso dal sistema secondo le
necessità.
Modica componenti FSM
L'utente può agire sulle transizioni modicandone le condizioni; può modicare le
variabili cambiando nome, tipo, valori ammissibili e valore iniziale.
L'utente può modicare uno stato cambiandone il nome, aggiungendo azioni sugli
stati, modicando o rimuovendo tali azioni e può decidere se impostare uno stato
come iniziale per la macchina a stati niti corrente.
CAPITOLO 5.
ANALISI E SPECIFICA DEI REQUISITI
71
Figura 5.5: Diagramma del caso d'uso denizione variabili d'istanza.
Figura 5.6: Diagramma del caso d'uso denizione FSM.
Verica modello
L'utente può vericare un modello ben denito scegliendo i comandi per la verica
da fornire al tool NuSMV. I risultati della verica saranno salvati su un le testuale
immediatamente accessibile su richiesta dell'utente.
Si noti che con questa congurazione l'utente non interagisce minimamente con il
tool NuSMV.
Un'altra alternativa è quella di generare il le .smv che rappresenta il modello e poi
utilizzare il tool NuSMV per la verica a parte.
CAPITOLO 5.
ANALISI E SPECIFICA DEI REQUISITI
72
Figura 5.7: Diagramma del caso d'uso modica componenti FSM.
5.2.2 Specica dei requisiti
Requisiti funzionali
REQUISITO N° 1
ˆ
Introduzione : il sistema deve permettere l'implementazione graca di un modello di una o più macchine a stati niti. Il modello dovrà essere tradotto in
linguaggio NuSMV.
ˆ
Output : modello graco realizzato.
REQUISITO N° 2
ˆ
Introduzione : il sistema deve permettere il caricamento di un modello graco
e la modica dello stesso.
ˆ
Input : modello graco esistente.
ˆ
Output : modello graco caricato ed eventualmente modicato.
REQUISITO N° 3
ˆ
Introduzione : il sistema deve permettere il salvataggio del modello graco.
ˆ
Input : modello graco.
ˆ
Output : le .xml relativo al modello graco.
CAPITOLO 5.
ANALISI E SPECIFICA DEI REQUISITI
73
Figura 5.8: Diagramma del caso d'uso verica modello.
REQUISITO N° 4
ˆ
Introduzione : il sistema deve permettere la creazione di un le testuale .smv
relativo ad un modello graco di macchiana a stati.
ˆ
Input : modello graco.
ˆ
Output : le .smv relativo allla macchina a stati rappresentata dal modello.
REQUISITO N° 5
ˆ
Introduzione :
il sistema deve permettere la verica formale tramite model
checking del le .smv generato a partire dal modello graco.
ˆ
Input : le .smv.
ˆ
Processing : il sistema si interfaccia con il tool NuSMV per eseguire i comandi
di verica del le.
ˆ
Output : le log.txt con i risultati della verica.
REQUISITO N° 6
ˆ
Introduzione : il sistema deve prevedere l'inserimento da parte dell'utente dei
comandi di verica per il tool NuSMV relativi al le .smv generato.
ˆ
Output : le testuale contenente i comandi di verica da eseguire.
CAPITOLO 5.
ANALISI E SPECIFICA DEI REQUISITI
74
REQUISITO N° 7
ˆ
Introduzione : il sistema deve permetter l'inserimento di formule per la verica
del modello.
ˆ
Output : visualizzazione all'interno del modello delle formule specicate.
REQUISITO N° 8
ˆ
Introduzione : il sistema deve prevedere la denizione di uno o più moduli da
parte dell'utente.
ˆ
Output : rappresentazione graca del modulo.
REQUISITO N° 9
ˆ
Introduzione :
il sistema deve permettere di denire variabili locali di un
modulo.
ˆ
Output : rappresentazione graca delle variabili locali all'interno di un modulo.
REQUISITO N° 10
ˆ
Introduzione :
il sistema deve permettere di denire input e output di un
modulo.
ˆ
Output : rappresentazione graca di variabili di ingresso e variabili d'uscita.
REQUISITO N° 11
ˆ
Introduzione : il sistema deve permettere il passaggio di variabili fra moduli.
ˆ
Output : rappresentazione graca dei passaggi di variabili.
REQUISITO N° 12
ˆ
Introduzione : il sistema deve permettere l'inserimento di stati.
ˆ
Output : rappresentazione graca degli stati all'interno di un modulo.
CAPITOLO 5.
ANALISI E SPECIFICA DEI REQUISITI
75
REQUISITO N° 13
ˆ
Introduzione : il sistema deve prevedere la denizione di transizioni tra due
stati.
ˆ
Output : rappresentazione graca della transizione.
REQUISITO N° 14
ˆ
Introduzione : il sistema deve prevedere l'inserimento di azioni sugli stati.
ˆ
Output : azioni visibili all'interno dello stato.
REQUISITO N° 15
ˆ
Introduzione : il sistema deve permettere la modica di tutti gli oggetti creati
all'interno del modello.
ˆ
Output : modello modicato in base al cambiamento eettuato sull'oggetto.
REQUISITO N° 16
ˆ
Introduzione : il sistema deve permettere la cancellazione di qualunque oggetto
creato all'interno del modello.
ˆ
Output : modello graco modicato dall'eliminazione dell'oggetto.
REQUISITO N° 17
ˆ
Introduzione : il sistema deve prevedere un meccanismo di undo/redo sulle
azioni eettuate dall'utente.
ˆ
Output: annullamento o ripristino dell'ultima azione visibile su modello graco.
REQUISITO N° 18
ˆ
Introduzione : il sistema deve permettere all'utente la navigazione all'interno
dei moduli generati.
ˆ
Output : visualizzazione del modulo selezionato dall'utente.
CAPITOLO 5.
ANALISI E SPECIFICA DEI REQUISITI
76
REQUISITO N° 19
ˆ
Introduzione : il sistema deve permettere lo zoom del modello graco.
ˆ
Output : visualizzazione del modulo con lo zoom desiderato.
REQUISITO N° 20
ˆ
Introduzione : il sistema deve permettere la stampa dei moduli creati e dell'intero modello.
ˆ
Output : stampa dei moduli.
Requisiti non funzionali di interfaccia
REQUISITO N° 21:
REQUISITO N° 22:
il tool deve essere un'applicazione a nestre.
il tool deve prevedere la visualizzazione di un albero di
progetto navigabile.
REQUISITO N° 23:
il tool deve permettere di interagire con ogni oggetto graco,
rappresentante un elemento del linguaggio NuSMV.
REQUISITO N° 24:
l'utente deve poter modicare il layout del tool a proprio
piacimento.
Requisiti non funzionali architetturali
REQUISITO N° 25:
il sistema deve interfacciarsi con il tool NuSMV per la ve-
rica formale tramite model checking del le .smv generato, relativo al modello
graco.
Requisiti non funzionali di estendibilità
REQUISITO N° 26:
il sistema deve poter essere esteso al ne di rappresentare
gracamente l'intero linguaggio denito dal tool NuSMV.
REQUISITO N° 27:
il sistema deve poter essere esteso così da esportare in
modello graco ogni le testuale .smv.
CAPITOLO 5.
ANALISI E SPECIFICA DEI REQUISITI
REQUISITO N° 28:
su modello graco.
77
il sistema dovrà integrare una verica visibile e navigabile
CAPITOLO
6
Implementazione
Grazie al prototipo realizzato è stato possibile denire un insieme di requisiti che
caratterizzano completamente il software nale; sulla base di essi si è sviluppata
la costruzione dell'intero sistema.
In una prima fase è stato importante creare
un visione macroscopica del programma che racchiudesse tutte le caratteristiche
desiderate, senza scendere nei dettagli di implementazione, dopodiché ogni aspetto
è stato volta volta analizzato e approfondito.
Appoggiandosi al concetto di MVC (Capitolo 4.2.2), come prima cosa si è suddivisa
la parte costituente il modello del sistema, da tutto quello che è la vista (ovvero la
parte di interfaccia con cui l'utente interagisce), che è stata implementata in seguito,
una volta denito correttamente il modello. La comunicazione tra queste due parti
è un aspetto fondamentale che si basa sul design pattern Observer e che è stato
adattato al framework Qt utilizzato per la realizzazione dei widget dell'interfaccia.
In questo capitolo verrà descritto l'intero piano di sviluppo del software, prestando
particolare attenzione agli aspetti più importanti e signicativi.
6.1 Denizione del modello
Lo scopo di questa fase è quello di denire un modello che permetta di avere
un prodotto nale consistente e facilmente utilizzabile dall'utente. Sulla base del
78
CAPITOLO 6.
IMPLEMENTAZIONE
79
linguaggio di input di NuSMV si è ritenuto opportuno eettuare una suddivisione
tra i componenti (moduli e variabili) di tale linguaggio al ne di ottenere un modello
che racchiudesse tutte le funzionalità necessarie senza creare confusione nell'utilizzo
del software. Tale distinzione è stata denita in base alle variabili che un modulo
può o meno contenere.
Mentre in NuSMV non si ha una categorizzazione delle variabili, nel programma
le variabili sono state suddivise in più categorie:
ˆ
variabili di stato: rappresentano, ognuna, una FSM (Finite State Machine):
i valori assunti da tali variabili sono i possibili stati raggiungibili; è possibile
denire un valore iniziale che rappresenta lo stato iniziale della FSM. Di queste
variabili devono essere specicate (gracamente) le transizioni. Questo tipo
di variabili, poiché uniche per ogni FSM module, hanno un nome unico e
ssato uguale a state .
ˆ
variabili locali : rappresentano variabili denite all'interno del modulo; sono
assegnati un insieme di valori, un valore iniziale, un tipo, ma non è specicata
alcuna transizione.
ˆ
variabili d'istanza: sono quelle variabili, denite all'interno del modulo, che
creano un'istanza di un altro modulo;
ˆ
variabili di input : quando si deniscono delle variabili d'istanza, il modulo
istanziato può dichiarare dei parametri d'ingresso; specicando tali ingressi si
vanno automaticamente a creare gli input del modulo.
ˆ
variabili di output : sono variabili locali, utilizzate come input per altre istanze
di moduli.
Vedremo in seguito che questa distinzione è fondamentale per creare un formalismo
graco da rispettare all'interno del programma. Si noti inoltre che non è possibile
denire variabili di stato come variabili d'output; chiariremo in seguito le varie
restrizioni.
Per quanto riguarda la suddivisione dei moduli, sono state denite due diverse
categorie:
ˆ
Frame module :
d'ora in avanti con questo termine faremo riferimento ai
moduli che possono esclusivamente denire variabili locali, variabili d'istanza
e input/output di queste ultime, e che inoltre gestiscono il passaggio delle
variabili fra i moduli istanziati e le variabili presenti.
CAPITOLO 6.
ˆ
IMPLEMENTAZIONE
80
FSM module : sono quei moduli che rappresentano una macchina a stati niti;
possono dunque denire un'unica variabile di stato (che rappresenta la FSM),
le transizioni tra gli elementi di tale variabile, e inne possono denire variabili
locali, d'ingresso e di uscita al modulo stesso.
Il modulo main (che deve sempre esistere) rappresenta un Frame module; si
capisce quindi che un qualunque modello generato dal programma conterrà almeno
un Frame module e un FSM module.
Ovviamente non potranno mai esserci solo Frame module: possiamo immaginare
la struttura del modello come un albero, dove i nodi rappresentano moduli, in
particolare il main è la radice e ogni nodo glio rappresenta un modulo istanziato
nel modulo padre; le foglie saranno tutte FSM modules, mentre tutti gli altri nodi
rappresentano Frame modules.
Sulla base di questa suddivisione è stato possibile denire il modello nale del
sistema, mostrato in Figura 6.1.
6.2 Sviluppo di modello e vista
Il passo successivo alla denizione del modello è lo sviluppo delle sue parti, prendendo
in considerazione l'interazione con l'utente, ovvero le viste di ogni componente. Di
seguito verranno descritte le classi fondamentali del software che costituiscono il
modello e le viste di ogni elemento del sistema.
6.2.1 Moduli
Ogni modulo è rappresentato da una nestra, che varia il suo aspetto e le sue
funzionalità a seconda del tipo di modulo che essa rappresenta: un modulo può
essere di tipo Frame o di tipo FSM, dove nel primo è possibile istanziare altri moduli,
mentre un FSM Module rappresenta, come dice il nome stesso, una macchina a stati
niti. Ogni modulo è caratterizzato da un nome (che deve essere unico) e contiene
un insieme di variabili locali, di ingresso e di uscita, inoltre saranno presenti altri
elementi che caratterizzano il tipo di modulo.
Ogni modulo inne può contenere un insieme di vincoli di fairness, utili al ne della
verica del modello.
Frame Module
Oltre alle suddette variabili, un Frame module contiene un insieme di variabili di
istanza, suddivise a seconda che si istanzi un FSM Module o un Frame Module.
CAPITOLO 6.
IMPLEMENTAZIONE
81
Figura 6.1: Denizione del modello del sistema.
La nestra che rappresenta questo tipo di modulo deve permettere all'utente di
aggiungere, rimuovere o modicare ogni tipo di elemento che denisce il modulo
Frame.
Un aspetto importante è quello che riguarda la navigazione dei moduli:
aggiungendo alla nestra una variabile di istanza di un determinato modulo, è possibile tramite questo oggetto accedere alla nestra del modulo istanziato, così da
permettere la navigazione tra tutti i moduli.
Un modulo può essere denito dall'utente soltanto all'interno di un modulo Frame
in diversi modi:
ˆ
istanziando un modulo tramite una variabile;
ˆ
copiando un modulo già istanziato;
CAPITOLO 6.
IMPLEMENTAZIONE
82
ˆ
creando direttamente un modulo senza denire nessuna variabile di istanza;
ˆ
copiando un modulo non ancora istanziato e creato come al punto sopra.
Ogni modulo Frame ha ovviamente un riferimento a tutti gli altri moduli creati, così
da poter aggiungere una variabile di istanza di un qualsiasi modulo.
Figura 6.2: Vista di un Frame Module.
La nestra che rappresenta un modulo di questo tipo è rappresentata in Figura 6.2.
Un ultimo aspetto che caratterizza un Frame Module è quello di poter denire un
insieme di formule secondo una logica temporale.
La schermata principale visualizzata all'avvio del programma rappresenta il modulo
main, e contiene un elemento aggiuntivo rispetto agli altri moduli Frame: l'albero
di progetto, di cui parleremo più avanti.
FSM Module
Un FSM module rappresenta una macchina a stati niti, pertanto al suo interno
non è possibile istanziare alcun modulo, si possono solo aggiungere (oltre alle variabili locali, di ingresso e di uscita) elementi che rappresentano stati e transizioni;
ovviamente ogni elemento può essere modicato e rimosso dall'utente in qualsiasi
momento.
La nestra che rappresenta un FSM Module è rappresentata in Figura 6.3; possiamo
notare che gli elementi a comune tra i due moduli, sono a comune anche tra le due
CAPITOLO 6.
IMPLEMENTAZIONE
83
Figura 6.3: Vista di un FSM Module.
nestre e che invece le dierenze sostanziali sono rappresentate dagli oggetti che
l'utente può inserire all'interno del modulo.
Un'altra dierenza tra le due viste riguarda la rappresentazione delle variabili locali,
di ingresso e di uscita; per i moduli FSM che devono rappresentare macchine a stati
niti si è ritenuto necessario dover rappresentare gracamente solo gli elementi che
la compongono ovvero stati e transizioni. Le variabili utilizzate all'interno della FSM
non sono visualizzate gracamente per non confondere l'utente e vi si può accedere
dall'apposito widget.
6.2.2 Variabili
Le variabili sono state suddivise in quattro categorie principali: variabili d'istanza
(suddivise a loro volta tra variabili che istanziano un Frame Module e variabili che
istanziano un FSM Module), variabili locali, variabili di ingresso e variabili di uscita.
Ognuno di questi elementi ha una sua rappresentazione graca ben precisa e delle
funzionalità che lo caratterizzano.
Una condizione importante è che all'interno di uno stesso modulo più variabili
devono necessariamente avere nomi diversi.
CAPITOLO 6.
IMPLEMENTAZIONE
84
Variabili d'istanza
Gli elementi che caratterizzano una variabile di questo tipo sono il modulo istanziato,
il nome della variabile ed un attributo che indica se il modulo è istanziato con la
keyword process di NuSMV, ovvero se l'esecuzione del modulo è sincrona o
meno.
Una variabile d'istanza può essere creata in diversi modi:
ˆ
tramite il relativo pulsante, aggiungendo direttamente l'oggetto sulla nestra;
in questo modo si istanzia un nuovo modulo.
ˆ
istanziando un modulo già denito;
ˆ
creando una copia di un'istanza già aggiunta alla nestra corrente; si viene
così a creare una copia del modulo precedentemente istanziato, che permette
di apportarvi modiche senza cambiare l'originale;
ˆ
duplicando una variabile d'istanza già denita; si creano così due o più istanze
di uno stesso modulo: ogni modica di una variabile si ripercuote sulle variabili
che istanziano il medesimo modulo.
Figura 6.4: Vista delle variabili di istanza: a sinistra istanza di un Frame Module, a destra
istanza di un FSM Module.
L'oggetto graco che rappresenta la variabile di istanza è rappresentato in Figura
6.4 e varia a seconda del tipo di modulo istanziato; il testo che compare all'interno
dell'oggetto graco segue la sintassi:
nome_variabile:<<nome_modulo>>.
Attraverso le variabili di istanza è possibile modicare il modulo istanziato: si possono aggiungere ingressi e uscite al modulo e cambiarne il nome, inoltre la caratteristica fondamentale è quella che permette la comunicazione tra i moduli creati
tramite il passaggio delle variabili.
Variabili locali
Le variabili locali possono essere denite all'interno di ogni modulo e sono caratterizzate da quattro attributi principali:
il nome della variabile, il tipo (Integer,
CAPITOLO 6.
IMPLEMENTAZIONE
85
Boolean, Enumeration), i valori che la variabile può assumere e il valore iniziale
della variabile. L'elemento graco che rappresenta una variabile locale all'interno di
un modulo Frame è mostrato in Figura 6.5 (a) e può essere collegata (ovvero data
in ingresso) a uno o più moduli istanziati nella stessa nestra.
Figura 6.5: Vista delle variabili: (a) variable locale; (b) variabile di ingresso; (c) variabile
di uscita.
Variabili di ingresso
Come le variabili locali, le variabili di ingresso possono essere denite all'interno di
ogni tipo di modulo, ma può essere denito solo il nome e il tipo della variabile,
infatti, poiché rappresentano gli ingressi di un modulo, possono variare in termini
di valori assunti e di valore iniziale; ad esempio a due istanze dello stesso modulo
posso passare due variabili locali diverse (ma dello stesso tipo).
L'elemento graco che rappresenta una variabile di ingresso è mostrato in Figura
6.5 (b) e anche in questo caso può essere collegata a sua volta ad uno o più moduli
istanziati all'interno del modulo che la contiene.
Un'altra vista della variabile di ingresso è relativa alle istanze del modulo che la
contengono (Figura 6.6): il triangolino rivolto verso l'interno che la rappresenta è
il punto di collegamento per una variabile che vuole essere passata in ingresso al
modulo istanziato.
Figura 6.6: Vista delle variabili di ingresso e di uscita relative all'istanza di un modulo.
CAPITOLO 6.
IMPLEMENTAZIONE
86
Variabili di uscita
Sostanzialmente le variabili di uscita sono variabili locali, cioè denite all'interno del
modulo, che però possono essere utilizzate come uscita del modulo stesso, pertanto
hanno le stesse caratteristiche di una variabile locale.
In Figura 6.5 (c) è mostrato l'oggetto graco che le rappresenta e, come per la
variabili di ingresso, esiste la vista relativa all'istanza del modulo cui la variabile
appartiene (Figura 6.6).
Il triangolino può essere collegato a più ingressi di altri
moduli istanziati, così da simulare il passaggio di variabili da un modulo a un'altro.
6.2.3 Stati e transizioni
Questi elementi caratterizzano una macchina a stati niti e pertanto appartengono
esclusivamente ai moduli FSM.
Stati
Uno stato è un elemento fondamentale delle macchine a stati niti ed è caratterizzato da un nome (che deve essere unico all'interno della stessa FSM), da delle
azioni sullo stato, da un insieme di transizioni entranti nello stato ed uscenti dallo
stesso e da un simbolo che identica lo stato come iniziale o meno.
In Figura 6.7 vediamo l'elemento graco che rappresenta lo stato con diverse
caratteristiche.
Figura 6.7: Vista di uno stato: lo stato A è impostato come iniziale; nello stato B sono
state inserite delle azioni.
Le azioni onentry, onexit e during possono essere aggiunte, modicate o rimosse
dall'utente in ogni momento.
CAPITOLO 6.
IMPLEMENTAZIONE
87
Transizioni
Le transizioni rappresentano il passaggio da uno stato ad un altro, eventualmente
sotto determinate condizioni; sono caratterizzate da uno stato di partenza, da uno
stato di arrivo e da una condizione che le attiva.
La rappresentazione è quella classica delle FSM, ovvero di una freccia orientata. In
Figura 6.8 è mostrato un esempio di transizione tra due stati.
Figura 6.8: Vista di una transizione tra due stati.
6.2.4 Ulteriori dettagli implementativi
Abbiamo dato una prima descrizione del tool progettato in base alla denizione del
modello, senza approfondire determinati aspetti che risultano comunque importanti
e che saranno descritti di seguito.
Passaggio di variabili
Durante la descrizione del modello si è più volte accennato al collegamento fra
moduli e al passaggio di variabili. Vediamo in Figura 6.9 un esempio concreto di
quanto detto e cerchiamo di spiegarne le implicazioni pratiche; al modulo Module_1
è passata in ingresso la variabile locale v_2 e la variabile out_1 di Module_1
è passata come ingresso alla FSM Module_2.
Nel rettangolo rosso vediamo il
dettaglio di Module_1: le due variabili in_1 e out_1 denite sopra sono date come
ingresso al modulo Module_3.
Quest'ultimo modulo rappresenta una macchina a stati niti che esegue delle operazioni sulle variabili che gli sono state passate in ingresso; d'altra parte la variabile out_1 è utilizzata anche dal modulo Module_2 che rappresenta una diversa
macchina a stati niti che elabora comunque la stessa variabile.
CAPITOLO 6.
IMPLEMENTAZIONE
88
Figura 6.9: Passaggio di variabili tra moduli.
Questo esempio rappresenta dunque un sistema composto da due distinte FSM che
lavorano in parallelo sulla stessa variabile; in sostanza una variabile denita in un
modulo può essere utilizzata da qualunque altro modulo tramite il collegamento
descritto sopra.
Figura 6.10: Albero di progetto.
Project tree
Per tener traccia del modello denito all'interno del programma è stato inserito nella
schermata principale (rappresentante il modulo main) un albero di progetto (Figura
6.10).
CAPITOLO 6.
IMPLEMENTAZIONE
89
La radice dell'albero contiene il nome del progetto, e i gli diretti della radice
rappresentano tutti i moduli deniti all'interno del modello; ogni modulo può essere
espanso per analizzare i componenti che vi sono deniti. Accanto ad ogni elemento
dell'albero vi è un'icona che rappresenta l'elemento gracamente; in Tabella 6.1
sono riassunte tali rappresentazioni.
È possibile interagire con gli elementi dell'albero per modicare o eliminare i corrispondenti oggetti deniti all'interno del modello, pertanto oltre alle viste descritte
n'ora, per ogni elemento è presente un'ulteriore vista con cui l'utente può interagire.
Frame Module
FSM Module
Frame Module instance variable
FSM Module instance variable
Local variable
Input variable
Output variable
State
Tabella 6.1: Vista degli elementi nell'albero di progetto.
Altri widget
Oltre all'albero di progetto, ogni nestra contiene altri widget che rappresentano
altre viste di oggetti deniti nel modello. Abbiamo già parlato del fatto che ogni
modulo mantiene un riferimento a tutti i moduli deniti all'interno del sistema;
tale lista è visualizzata all'interno del widget Modules (Figura 6.11_a) da cui è
possibile creare, eliminare, istanziare e copiare moduli.
Un'altra vista utile riguarda le variabili locali, di ingresso e di uscita, infatti risulta
comodo avere a portata di mano le informazioni di ogni variabile denita, che non
risulta immediatamente visibile dall'elemento graco aggiunto alla nestra; anche
in questo caso dal widget relativo (Figura 6.11_b) è possibile modicare o eliminare
la variabile selezionata.
Inne per quanto riguarda i vincoli di fairness di un modulo e le speciche temporali
utili alla verica è presente una tabella, mostrata in Figura 6.11_c, che riassume
tali elementi relativi al modulo considerato.
CAPITOLO 6.
IMPLEMENTAZIONE
90
Figura 6.11: Altre viste del modello: (a) lista dei moduli; (b) dettaglio delle variabili; (c)
informazioni sui vincoli del modulo.
Comunicazione vista-modello
Rispettando il principio che sta alla base dell'architectural pattern MVC, vista e
modello sono completamente separati e il meccanismo di comunicazione è implementato tramite Observer/Observable; in particolare, utilizzando il framework Qt
per la realizzazione dell'interfaccia graca, tale meccanismo è fornito attraverso il
concetto di Signal e Slot (Appendice A.1). Gli oggetti che costituiscono il modello
non conoscono quali sono le loro viste, mentre ogni vista ha un riferimento al modello che rappresenta. Quando l'utente modica il modello interagendo con la vista,
Figura 6.12: Diagramma di usso per la modica del nome di un modulo.
viene emesso un segnale catturato dal modello stesso, così che il parametro interes-
CAPITOLO 6.
IMPLEMENTAZIONE
91
sato sia aggiornato; il modello a sua volta emette un segnale e le viste interessate si
aggiornano in base alla modica avvenuta. Vediamo in Figura 6.12 un diagramma
che rappresenta quanto appena detto nel caso di esempio in cui l'utente decida di
modicare il nome di un modulo dalla tabella contenente la lista dei moduli presenti.
Figura 6.13: Diagramma delle classi per l'oggetto Modulo e le relative viste.
In Figura 6.13 è invece mostrato il diagramma delle classi relativo all'oggetto Module
ed alle sue viste. Sono stati riportati i metodi principali, comunque si può notare
che solo le viste hanno un riferimento al modulo, mentre non vale il viceversa; la
comunicazione avviene unicamente tramite i segnali sopra descritti.
6.3 Salvataggio e caricamento
Il salvataggio e il caricamento di un modello sono un aspetto molto importante del
programma, in quanto permettono di modicare un modello già creato in precedenza
o di crearne uno nuovo a partire da un già denito.
Per ricostruire correttamente il modello è necessario prendere nota sia delle informazioni riguardanti i dati del sistema che di quelli che rappresentano il layout nale
CAPITOLO 6.
IMPLEMENTAZIONE
92
del modello graco realizzato; inoltre devono essere salvate anche le informazioni
necessarie alla generazione del le NuSMV.
In Figura 6.14 è mostrato il diagramma di sequenza della procedura di salvataggio,
considerando macroscopicamente vista e modello. In generale una volta inseriti i
dati di un determinato modello (variabile, modulo, ecc..), lo stesso invia un segnale
alle rispettive viste che mandano così le informazioni di layout alla classe che si
occupa del salvataggio.
Figura 6.14: Diagramma di sequenza per l'operazione di salvataggio.
La struttura più naturale per il salvataggio di questo tipo di informazioni è quella
dell'albero mostrato in Figura 6.15 (e che è la stessa dell'albero di progetto). La
Figura 6.15: Formato del le di salvataggio.
CAPITOLO 6.
IMPLEMENTAZIONE
93
radice rappresenta il nome del progetto e i gli tutti i moduli deniti (non necessariamente instanziati); ogni modulo ha come gli tutti gli elementi che lo costituiscono:
per i moduli Frame saranno salvate le variabili di istanza, le variabili locali, di input
e di output e inne i vincoli e le speciche per la verica. Nei moduli FSM invece
compariranno gli stati, le transizioni, le variabili di ingresso, di uscita e locali e i
vincoli di fairness.
Ogni nodo dell'albero (esclusa la radice che non rappresenta di per sé un oggetto del
modello) ha un riferimento ai dati dell'elemento che rappresenta ed alle informazioni
di layout che lo caratterizzano, così che sia possibile ricostruire il modello in modo
preciso.
Nella fase di caricamento viene eettuata la scansione del le di salvataggio e viene
ricostruito l'intero progetto.
Come prima cosa si crea la parte relativa ai dati,
ovvero si ricostruisce il modello; dopodiché si generano tutte le viste relative ai dati
recuperati.
L'approccio più semplice per le operazioni di salvataggio e di caricamento è stato
quello di utilizzare il metalinguaggio XML.
6.3.1 XML
XML è un metalinguaggio di markup utilizzato per denire altri linguaggi di markup;
di per sé costituisce un insieme standard di regole sintattiche (speciche) per modellare la struttura di documenti e dati. Le speciche uciali sono state denite dal
W3C (World Wide Web Consortium) [W3C].
Lo standard delle regole garantisce l'indipendenza da una specica piattaforma hardware e software o da uno specico produttore.
Pertanto, denendo un linguag-
gio di markup tramite XML siamo sicuri che esistono già strumenti per le diverse
piattaforme in grado di comprendere ed elaborare correttamente tale linguaggio.
Un documento XML è, in pratica, un le di testo che al suo interno contiene tag,
attributi e testo secondo regole sintattiche ben denite ed è caratterizzato da una
struttura gerarchica. Esso è composto da
elementi,
ognuno dei quali rappresenta
un componente logico del documento e può contenere a sua volta altri elementi
(sottoelementi) o del testo; un elemento può avere associate altre informazioni,
chiamate
attributi,
che ne descrivono le proprietà.
Possiamo rappresentare gracamente la struttura di un documento XML tramite
un albero, generalmente noto come document tree ; la radice di tale albero è un
particolare nodo che contiene l'insieme degli altri elementi del documento.
La struttura logica del documento XML (ovvero la struttura del document tree)
varia a seconda delle scelte di progetto e non esistono regole precise per la sua
CAPITOLO 6.
IMPLEMENTAZIONE
94
organizzazione; viene tradotta in una struttura sica composta da elementi sintattici
detti
tag.
Tutti i documenti XML devono essere ben formati (well formed ); questo concetto
è assimilabile in qualche modo alla correttezza ortograca di una lingua ed è un
principio a cui i documenti XML non possono sottrarsi.
Perché un documento XML sia ben formato deve rispettare le seguenti regole:
ˆ
ogni documento XML deve contenere un unico elemento di massimo livello
(root) che contenga tutti gli altri elementi del documento. Le sole parti di
XML che possono stare all'esterno di questo elemento sono i commenti e le
direttive di elaborazione (per esempio, la dichiarazione della versione di XML);
ˆ
tutti gli elementi devono avere un tag di chiusura o, se vuoti, possono prevedere
la forma abbreviata (/>);
ˆ
gli elementi devono essere opportunamente nidicati, cioè i tag di chiusura
devono seguire l'ordine inverso dei rispettivi tag di apertura;
ˆ
XML fa distinzione tra maiuscole e minuscole, per cui i nomi dei tag e degli
attributi devono coincidere nei tag di apertura e chiusura anche in relazione
a questo aspetto;
ˆ
i valori degli attributi devono sempre essere racchiusi tra singoli o doppi apici.
La violazione di una qualsiasi di queste regole fa in modo che il documento risultante
non venga considerato ben formato.
L'interfaccia DOM XML
Per integrare XML con la programmazione ad oggetti al ne di creare documenti
weel formed , l'ente W3C ha denito un'interfaccia chiamata DOM (Document
Object Model) basata su classi a più livelli. In Figura 6.16 vediamo le classi principali
dell'interfaccia e il modo in cui sono organizzate:
Node
è la classe più importante e comprende qualunque elemento dell'albero XML
(radice, ramo, foglia); i suoi attributi permettono di denire nome, tipo e
valore di un nodo, il legame con gli altri nodi (se ha nodi gli o genitori) e gli
attributi del nodo.
NodeList
è un vettore di elementi con un indice numerico, ed è utilizzato quando
si hanno più occorrenze di uno stesso elemento.
CAPITOLO 6.
IMPLEMENTAZIONE
95
Figura 6.16: Organizzazione delle classi principali DOM.
NamedNodeMap
possiede le stesse proprietà di NodeList ed in più permette di
individuare gli elementi con dei nomi oltre che con l'indice.
Document
è una sottoclasse di Node e rappresenta il documento XML stesso;
solo tramite questa classe è possibile creare e aggiungere all'albero nuovi nodi
utilizzando gli appositi metodi.
Element
rappresenta l'elemento dell'albero e con tale classe è possibile gestire i
suoi attributi.
Attribute
è la classe relativa agli attributi di un elemento, e grazie ad essa è
possibile recuperare le informazioni memorizzate nel campo descritto.
CharacterData
si occupa di gestire testo e commenti all'interno dell'albero.
Nello sviluppo del progetto è stato utilizzato il package com.trolltech.qt.xml, che
implementa le classi sopra descritte (e tutte le altre).
6.4 Generazione del le NuSMV
Con il salvataggio del modello graco vengono rese disponibili tutte le informazioni
necessarie alla creazione del le NuSMV; ovviamente tutto ciò che riguarda l'aspetto
graco non sarà considerato, verranno utilizzate solo le informazioni relative ai dati
del modello.
Vengono mappati via via i moduli deniti seguendo la sintassi del linguaggio NuSMV,
recuperando le informazioni necessarie, distinguendo il caso in cui si stia traducendo
un modulo Frame oppure un modulo FSM.
CAPITOLO 6.
IMPLEMENTAZIONE
96
6.4.1 Traduzione Frame Module
Recuperata l'informazione relativa al nome del modulo in questione, si verica se
esso contiene variabili di ingresso che in tal caso vengono specicate sul le secondo
+
la sintassi [CCJ ]. Il passo successivo è quello di denire le variabili ed eventualmente il loro valore iniziale. Per le variabili locali e di uscita si riportano il nome e i
valori che la variabile può assumere; per le variabili di istanza vanno considerati diversi aspetti: oltre al nome della variabile devono essere considerate le informazioni
sul modulo istanziato. Prima di tutto, se l'esecuzione è asincrona, va riportata la
keyword
process,
dopodiché va trascritto il nome del modulo e inne gli ingressi
relativi. Ovviamente se il modulo ha degli ingressi, a seconda dell'istanza considerata questi possono variare, è quindi necessario recuperare le informazioni relative
alle variabili d'ingresso all'istanza del modulo che si sta considerando; vediamo un
esempio di modello graco e relativa traduzione in Figura 6.17.
Figura 6.17: Esempio di traduzione delle variabili di un modulo Frame da modello graco
a le NuSMV .
Le transizioni in questo tipo di moduli non sono specicate, pertanto le uniche altre
informazioni da aggiungere sono quelle relative ai vincoli di fairness e alle speciche.
6.4.2 Traduzione FSM Module
Anche in questo caso le prime informazioni da recuperare sono quelle riguardanti
il nome e gli ingressi del modulo; dopodiché si deniscono le variabili, compresa la
variabile di stato che rappresenta gli stati della FSM. La parte più complessa della
traduzione di un modulo FSM riguarda l'assegnazione dei valori futuri delle variabili.
La mappatura da FSM a linguaggio NuSMV è già stata trattata (Capitolo 3), pertanto non stiamo a riportarla nuovamente. In Figura 6.18 è mostrato un esempio
CAPITOLO 6.
IMPLEMENTAZIONE
di traduzione da modulo FSM a modulo NuSMV, dove la variabile
97
in
rappresenta
un ingresso al modulo che contiene la FSM.
Figura 6.18: Esempio di traduzione delle variabili di una macchina a stati niti da modello
graco a le NuSMV.
6.5 Verica del modello
Una volta tradotto il modello graco in le NuSMV è possibile utilizzare il tool con
tale le, altrimenti il programma permette di impostare alcuni comandi e lanciare
una verica non interattiva. È possibile scegliere quali opzioni di verica far eseguire
Figura 6.19: Widget dei comandi per la verica.
CAPITOLO 6.
IMPLEMENTAZIONE
98
impostandoli dal widget mostrato in Figura 6.19; i comandi possibili sono:
ˆ
Check CTL specications :
verica le formule CTL impostate; è possibile
vericare una formula precisa o tutte quelle specicate.
ˆ
Check LTL specications : equivalente al comando precedente ma relativo alle
formule espresse in LTL.
ˆ
Check FSM : verica le totalità della relazione di transizione: se non è totale
viene fornito un esempio di deadlock state.
ˆ
Print reachable states : stampa il numero e la lista di tutti gli stati raggiungibili
del modello.
ˆ
Pick state options : sceglie randomicamente uno stato dall'insieme degli stati
iniziali; se è selezionata l'opzione Set constraint, la stringa immessa determina una restrizione sugli stati che possono essere scelti.
ˆ
Show variables : mostra l'insieme delle variabili presenti, oppure solo quelle di
input o di output.
ˆ
Print current states : stampa il nome dello stato corrente denito.
ˆ
Number of simulation steps : imposta il numero dei passi di simulazione.
L'insieme dei comandi scelti viene riportato sul le command.txt che è poi dato
come ingresso al tool NuSMV. I risultati della verica sono stampati su un le log.
6.6 Sviluppi futuri
Verranno di seguito descritte le caratteristiche da implementare al ne di ottenere
un tool nale completo sotto ogni punto di vista.
6.6.1 Linguaggio NuSMV
Il tool realizzato non copre tutte le funzionalità di NuSMV: in primo luogo non sono
stati utilizzati tutti i tipi di variabili disponibili, infatti oltre a Boolean, Integer ed
Enumeration, NuSMV prevede la denizione di word e di array; anche le espressioni
costanti sono state omesse dall'implementazione.
Per la dichiarazione delle variabili è utilizzata unicamente la notazione
var_declaration ::
VAR var_list;
CAPITOLO 6.
IMPLEMENTAZIONE
99
mentre per l'assegnazione del valore iniziale e delle transizioni è usato il vicolo
ASSIGN,
evitando le keyword
INIT, INVAR
e
TRANS.
I vincoli di fairness sono dichiarati utilizzando solo la sintassi:
fairness_constraint ::
evitando
JUSTICE
e
FAIRNESS simple_expr;
COMPASSION.
Le speciche per le formule da vericare comprendono solo la logica LTL e CTL.
Una prima estensione futura del tool potrà quindi prevedere di estendere il modello graco inserendo tutte le parti mancanti del linguaggio, o comunque quelle di
primaria importanza.
Sempre in relazione al linguaggio NuSMV, potrebbe essere interessante prevedere
anche una traduzione in senso contrario, ovvero da le di testo a modello graco.
Il procedimento dovrebbe comprendere come prima cosa una riorganizzazione del
le secondo la classicazione dei moduli Frame e FSM; una volta denito un modello compatibile con quello graco andrebbero salvati tutti i dati relativi a moduli,
variabili, stati e transizioni su le XML nello stesso secondo lo stesso formalismo.
Un problema potrebbe essere quello relativo al posizionamento degli oggetti graci:
andrebbe creato un metodo di posizionamento automatico degli oggetti che vari a
seconda del numero e al tipo di elemento.
In realtà questo aspetto del tool potrebbe anche essere evitato, una volta implementate tutte le funzionalità del linguaggio NuSMV, la rappresentazione del modello
dovrebbe avvenire in maniera diretta; d'altra parte vanno considerati gli innumerevoli
modelli già deniti in forma testuale e quindi per un mantenere un certo livello di
compatibilità potrebbe risultare interessante una funzione di import che permetta
questo tipo di traduzione.
6.6.2 Estensione della verica
Attualmente la verica del modello graco realizzato, fornisce un le testuale con
i risultati ottenuti da NuSMV sulla base di pochi comandi scelti.
Il primo passo
da compiere in questo senso è quello di fornire all'utente la possibilità di inserire
tutti i comandi per la verica previsti da NuSMV: può essere esteso il widget già
creato oppure prevedere un meccanismo diverso in modo che risulti più funzionale
e intuitivo.
Il le contenente i risultati della verica riporta fedelmente l'output di NuSMV;
controllare il modello in questo modo può risultare piuttosto faticoso e poco pratico,
la soluzione ottimale sarebbe quella di utilizzare l'interfaccia realizzata anche per
CAPITOLO 6.
IMPLEMENTAZIONE
la fase di verica.
100
Un'aspetto importante che può essere ampliato, riguarda la
visualizzazione dei controesempi per il fallimento di una o più formule: utilizzando il
modello graco, potrebbero essere evidenziate le variabili coinvolte per ogni step del
controesempio e la visualizzazione potrebbe evolvere nel tempo automaticamente o
per mano dell'utente in modo da permettere un'analisi più approfondita a seconda
delle necessità. In ogni caso vedere rappresentato un controesempio gracamente
seguendo una determinata evoluzione temporale è molto più immediato e pratico
per chi deve analizzare i risultati della verica.
6.6.3 Simulazione interattiva
Una caratteristica molto importante del tool NuSMV è la simulazione interattiva
da parte dell'utente che vuole vericare un determinato modello. Ovviamente, per
com'è realizzato attualmente il programma, questo tipo di verica non è possibile,
infatti la simulazione è eettuata randomicamente, sia nella scelta degli stati di
partenza che nell'avanzamento della simulazione stessa.
Sarebbe molto interessante estendere questa caratteristica all'interfaccia, permettendo all'utente di eettuare una simulazione interagendo con il modello graco
costruito, ad esempio selezionando manualmente gli stati di partenza, evidenziando
le scelte possibili direttamente sulla nestra coinvolta e permettendo di eettuare
le scelte di avanzamento della simulazione cliccando sulle parti interessate.
Possiamo paragonare la procedura al concetto di debug di un programma: l'esecuzione delle istruzioni avviene passo passo permettendo così l'ispezione interattiva
delle variabili. Allo stesso modo si può pensare di avviare una simulazione da un
determinato punto di interesse così da osservare il comportamento del modello permettendo all'utente di scegliere la transizione fra quelle non deterministiche coinvolte
ad ogni passo. La simulazione dovrebbe essere interrompibile, senza la necessità di
ssare un numero di passi preciso; l'utente dovrebbe poter scegliere quando fermare
l'esecuzione, o quando mandare avanti la simulazione no ad un determinato punto,
o addirittura si potrebbe pensare di tornare indietro per prendere strade diverse.
Si capisce che avere il modello graco sotto mano permette di vericare lo stesso
con maggiore semplicità, risparmiando così molto tempo.
6.6.4 Inserimento formule
La parte del programma relativa all'inserimento delle formule consente di specicare una formula CTL o LTL, scrivendola secondo il linguaggio formale denito da
NuSMV.
CAPITOLO 6.
IMPLEMENTAZIONE
101
Potrebbe essere interessante creare un apposito widget per l'inserimento delle formule, da cui sia possibile esprimerle più facilmente, anche da parte di un utente meno
esperto: come prima cosa potrebbero essere inseriti dei pulsanti relativi agli operatori temporali ed alcuni che rappresentino le congurazioni più comuni e importanti.
Inoltre avendo a disposizione il modello graco denito, si potrebbe permettere di
selezionare le variabili coinvolte selezionandole dall'interfaccia stessa.
6.6.5 Estensione ad altri tool per model checking
Per come è stato pensato, questo tool si interfaccia esclusivamente a NuSMV;
esistono però molti programmi per il model checking di un modello, ognuno con
caratteristiche diverse.
Il processo del model checking ha dei passi ben precisi:
denizione di un modello, specica delle proprietà che il modello deve avere e verica
di tali speciche.
Il programma realizzato permette l'esecuzione di tutti gli step
descritti, quindi ci possiamo chiedere se il processo di traduzione sviluppato rispetto
al tool NuSMV possa essere esteso ad altri programmi, così da scegliere il tipo di
verica da eettuare a seconda delle necessità.
In generale la risposta a questa
domanda dipende dall'implementazione dei model checker che vogliono essere presi
in considerazione; in denitiva anche appoggiarsi esclusivamente al tool NuSMV
permette di realizzare un tool graco completo ed eciente per il model checking.
CAPITOLO
7
Conclusioni
Il progetto realizzato consente di costruire un modello graco di sistema utilizzando
il formalismo degli automi a stati niti, dopodiché far eseguire ad un model checker
(NuSMV nel nostro caso) determinate veriche su tale modello.
I vantaggi nell'utilizzare uno strumento del genere sono svariati:
ˆ
rappresentare un sistema in termini di macchine a stati niti è abbastanza
semplice e comodo (soprattutto una rappresentazione graca), l'approccio da
parte di un utente è abbastanza immediato una volta capito il formalismo; in
più i modelli rappresentabili con tale strumento sono innumerevoli;
ˆ
la separazione dello strumento che denisce il modello e di quello che invece
ne esegue la verica permette di estendere notevolmente l'utilizzo del tool
graco a molti programmi per il model checking, l'unica necessità è quella di
sviluppare appositi traduttori;
ˆ
lo sviluppo del tool può avvenire in diverse direzioni, no ad ottenere un
programma esclusivamente graco che si appoggia ad un programma di model
checking esterno.
In conclusione, abbiamo unito la potenza del model cheker NuSMV con la semplicità
del formalismo delle macchine a stati niti insieme alla praticità di un'interfaccia
102
CAPITOLO 7.
CONCLUSIONI
103
graca, per ottenere un punto di partenza per un model checker graco completo,
che si possa appoggiare a diversi motori a seconda delle necessità.
Denendo un processo di mappatura tra modello FSM e linguaggio NuSMV è stato
possibile permettere all'utente che vuole utilizzare il programma di ragionare direttamente in termini di automi a stati niti, senza dover necessariamente conoscere il
linguaggio NuSMV; in particolare le azioni sugli stati e le transizioni non deterministiche semplicano notevolmente la denizione di un modello, e tutte le operazioni
di traduzione verso le NuSMV avvengono in maniera completamente trasparente.
Per l'implementazione del tool si è seguito l'architectural pattern MVC, così da
rendere la struttura ben separata in tutti i suoi componenti; la comunicazione attraverso segnali fra modello e vista permette un funzionamento sicuro e corretto,
inoltre, essendo ogni oggetto ben caratterizzato e separato dagli altri oggetti presenti, apportare modiche o eventuali estensioni è molto semplice:
è suciente
individuare quali componenti debbano essere coinvolti nelle modiche, lasciando
stare tutto il resto del programma.
Il lavoro svolto per la denizione dei requisiti di sistema è stato molto accurato:
dopo la realizzazione di un prototipo che riassumeva tutte le caratteristiche più
importanti del programma e che è stato provato da più utenti, tra cui gli sviluppatori
di NuSMV, grazie ai feedback ricevuti è stato possibile descrivere chiaramente quali
caratteristiche e funzionalità l'interfaccia doveva avere; inoltre il lavoro fatto nella
realizzazione del prototipo è stato in parte riutilizzato nell'implementazione nale,
ad esempio la denizione del modello e parte delle viste sono state mantenute
praticamente identiche, permettendo un notevole guadagno in termini di tempo.
Riassumendo, possiamo in conclusione aermare che il prodotto nale:
ˆ
è molto intuitivo e di semplice utilizzo;
ˆ
è ben strutturato, e quindi ogni modica o estensione è immediata;
ˆ
rispetta i pattern più comuni, su cui basa tutto il suo funzionamento;
ˆ
ha delle funzionalità ben caratterizzate, grazie anche all'aiuto degli sviluppatori di NuSMV;
ˆ
costituisce il punto di partenza per un model checker graco completo.
APPENDICE
A
Il framework Qt
Qt è una libreria multipiattaforma per lo sviluppo di programmi con interfaccia
graca; utilizza principalmente il linguaggio C++ standard con un estensivo uso del
preprocessore C per arricchire il linguaggio, ma esistono interfacce per Java, Python,
C, Perl e PHP. In particolare per lo sviluppo del programma sono state utilizzate le
librerie Qt Jambi per lo sviluppo in linguaggio Java.
Di seguito verranno illustrate le principali caratteristiche utilizzate nello sviluppo del
tool.
A.1 Segnali e slot
La suddivisione tra modello e vista nell'implementazione del programma necessita
di un meccanismo di comunicazione tra le due parti; in particolare quando l'utente
interagisce con l'interfaccia deve essere presente un meccanismo che aggiorna il
modello e tutte le viste coinvolte. Segnali e slot sono il meccanismo utilizzato da
Qt per la comunicazione tra gli oggetti.
In Figura A.1 vediamo un esempio di
comunicazione con segnali e slot.
Un segnale è emesso ogni volta che si verica un particolare evento; i widget di Qt
Jambi hanno svariati segnali predeniti, ma è sempre possibile denirne di propri
estendendo la classe QSignalEmitter. Uno slot è un metodo chiamato in risposta
ad un determinato segnale.
104
APPENDICE A.
IL FRAMEWORK QT
105
Figura A.1: Comunicazioni tra oggetti per via di segnali e slot.
Il meccanismo è sicuro, nel senso che il tipo di segnale emesso deve corrispondere con
il metodo che riceve il segnale; ad esempio un segnale Signal2<Integer, Integer>
non potrà essere connesso ad un metodo che prende come argomento una stringa,
serve necessariamente un metodo che prenda come argomenti due (o meno) interi.
Si dice che segnali e slot sono debolmente accoppiati, ovvero una classe che emette
il segnale non conosce e non si preoccupa di quale metodo riceverà tale segnale.
È possibile connettere più segnali ad un singolo slot e viceversa; è anche possibile
connettere un segnale direttamente ad un altro segnale, così che una volta emesso
il primo verrà automaticamente emesso anche il secondo.
Quando un segnale è emesso, gli slot connessi vengono eseguiti immediatamente;
quando questo accade, il meccanismo è totalmente indipendente da ogni evento
della GUI: l'esecuzione del codice che segue l'emissione del segnale riprende soltanto
quando tutti i metodi slot sono ritornati.
A.2 Scena graca e vista
L'utilizzo dell'interfaccia graca prevede l'interazione con oggetti graci di vario
tipo; Qt mette a disposizione degli strumenti molto comodi a questo scopo e sono
riassunti in tre classi principali: QGraphicsScene, QGraphicsView e QGraphicsItem.
QGraphicsScene
è una classe che fornisce metodi per la gestione di un elevato
numero di oggetti graci 2D; rappresenta in sostanza un contenitore per oggetti
APPENDICE A.
IL FRAMEWORK QT
106
QGraphicsItem. Fornisce anche funzionalità che permettono sia di determinare in
modo eciente la posizione degli oggetti che di rilevare, data una certa area, quali
oggetti vi si trovano dentro.
Di per sé non ha una vista, è solo una classe che gestisce oggetti graci; per
visualizzare la vista è necessario appoggiarsi ad uno o più oggetti QGraphicsView.
Una delle caratteristiche più importanti è quella di determinare la posizione di un
determinato oggetto in modo molto eciente: anche se nella scena sono presenti milioni di oggetti, la posizione di un oggetto particolare è restituita in pochi
millisecondi.
Una responsabilità di questa classe è quella di propagare gli eventi dalla vista: se ad
esempio viene premuto un tasto o un pulsante del mouse, è la scena a determinare
quale oggetto riceverà l'evento.
QGraphicsView
è la classe che fornisce un widget (scroll area) per la visualiz-
zazione di una QGraphicsScene; è possibile spostarsi in ogni punto della scena,
centrare la scena rispetto a un determinato punto o ad un determinato oggetto.
Fornisce metodi per ruotare, scalare, traslare oggetti e permette di interagire con
gli oggetti della scena tramite mouse e tastiera, propagando gli eventi alla scena.
QGraphicsItem
è la classe base di tutti gli oggetti graci in una QGraphicsScene;
Qt fornisce già oggetti di forme più comuni (rettangoli, ellissi, ecc..) ma permette
anche l'implementazione di forme personalizzate.
La classe supporta le seguenti
caratteristiche
ˆ
eventi mouse (press, move, release, double click, ecc..);
ˆ
eventi da tastiera;
ˆ
drag & drop;
ˆ
raggruppamento;
ˆ
rilevamento collisioni;
Tutti gli oggetti graci del progetto sono ereditati da questa classe e utilizzano
molte delle funzionalità messe a disposizione da Qt.
Una descrizione ben dettagliata del funzionamento di vista/scena/oggetti graci è
rilasciata in [QtJ]
APPENDICE A.
IL FRAMEWORK QT
107
A.3 Implementazione undo/redo
Una caratteristica del programma è quella di poter annullare o ripristinare determinate azioni tramite il meccanismo undo/redo. Qt fornisce il Qt's Undo Framework
per la gestione di tale funzionalità, che è un'implementazione del pattern Command,
basato sull'idea che ogni modica in un'applicazione è eseguita creando un'istanza
di oggetti comando. Tali oggetti applicano i cambiamenti al documento e sono
memorizzati in una pila; conoscono i cambiamenti apportati al documento e sanno
ritornare allo stato precedente alla modica eettuata. Più a lungo l'applicazione
utilizza solo comandi per cambiare lo stato del documento, tanto più è possibile
ripercorrere all'indietro la sequenza dei comandi no a tornare allo stato iniziale.
Questo meccanismo permette sia di tornare indietro che di ripristinare un modica.
QUndoCommand
è la classe base per tutti i comandi memorizzati nella pila;
rappresenta una singola modica al documento, come la rimozione di un oggetto.
Applica un cambiamento con il metodo redo() e ripristina lo stato precedente al
cambiamento con il metodo undo().
QUndoStack
è la classe che rappresenta la pila contenente tutti i comandi e per-
mette di scorrere avanti e indietro rispetto ai cambiamenti eettuati sul documento.
APPENDICE
B
Design e utilizzo del tool
In questo capitolo presenteremo il layout dell'interfaccia, vedremo com'è strutturata
gerarchicamente e come è possibile interagire con gli oggetti inseriti nei moduli.
Ogni modulo nel programma è rappresentato da una nestra dove è possibile impostare e modicare il contenuto dello stesso; poiché sono due i tipi di moduli
presenti, è immediato capire che si hanno due tipi diversi di nestre:
uno per i
Frame modules ed un altro per gli FSM modules.
B.1 Pulsanti e menu
La Figura B.1 mostra un dettaglio pulsanti e menu di una nestra rappresentante
un Frame module; analizziamo le azioni che è possibile eettuare.
ˆ
Il gruppo di pulsanti 1 è relativo alle azioni sui le e, da sinistra verso destra,
permette rispettivamente di creare un nuovo modello, caricarne uno esistente,
salvare il modello attuale e inne stampare la nestra corrente. Oltre a queste
azioni nel menu File sono presenti le azioni Save as e Print all, la quale
permette di stampare tutti i moduli deniti nel modello.
ˆ
Il gruppo di pulsanti 2 permette di aggiungere componenti al modulo Frame,
rispettivamente variabili locali, di ingresso, di uscita e variabili d'istanza di
108
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
109
Figura B.1: Pulsanti e menu della schermata principale.
moduli Frame e FSM. Tali azioni possono essere eettuate anche dal menu
Model.
ˆ
Nel gruppo di pulsanti 3 è possibile eseguire undo e redo delle azioni eettuate,
così come da menu Edit.
ˆ
Il gruppo 4 contiene i pulsanti per la generazione del le NuSMV e per la
verica del modello. Una volta generati i le di testo relativi, questi vengono
automaticamente visualizzati, aprendo l'editor di testo predenito del sistema.
ˆ
Inne nel gruppo 5 sono presenti i pulsanti per lo zoom, rispettivamente zoom
in, zoom out e zoom to t.
È mostrato anche il menu a comparsa della nestra, che compare ogni volta che
viene premuto il tasto destro del mouse sullo sfondo. Sono presenti due submenu:
Fairness e Specication. Il primo permette di aggiungere, modicare o rimuovere un
vincolo FAIRNESS al modulo attuale. Il submenu Specication invece permette di
inserire, modicare o rimuovere una formula da vericare tramite il model checker.
È possibile scegliere se inserire una formula LTL o CTL, che comunque deve essere
scritta manualmente con la corretta sintassi.
Vediamo in Figura B.2 un dettaglio di pulsanti della nestra che rappresenta un
modulo FSM.
Nella toolbar i pulsanti sono diversi da quelli presenti nella nestra descritta precedentemente; in particolare:
ˆ
nel primo gruppo compaiono soltanto i pulsanti per il salvataggio e per la
stampa;
ˆ
nel gruppo contenente gli elementi da inserire nel modello non compaiono le
variabili, mentre ci sono i pulsanti relativi all'aggiunta di stati e variabili.
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
110
Figura B.2: Finestra di un modulo FSM.
È presente il submenu Fairness, ma non quello Specication, infatti le formule relative ad un modulo FSM vengono inserite a livello di modulo Frame nel quale è istanziato; per aggiungere, modicare o rimuovere variabili (che non compaiono gracamente), è possibile selezionare l'opzione dal submenu relativo al tipo di variabile
considerata.
B.1.1 Operazioni sulle nestre
Nel capitolo relativo all'implementazione abbiamo visto come sono rappresentati i
moduli e come è possibile modicarli navigando tra le nestre che li deniscono
(Capitolo 6.2.1); vediamo in Figura B.3 un esempio concreto di istanziazione e
modica di moduli Frame e FSM.
Nel modulo main vengono denite tre variabili:
una variabile locale
boolean con valore iniziale 0, una variabile d'istanza
module
M odule1 e una variabile d'istanza v3
v2
v1
di tipo
che istanzia un Frame
che crea un istanza di un FSM module
M odule2.
Dall'esempio si vede inoltre come sono gestite le interazioni tra variabili e moduli:
per ogni variabile d'istanza è sempre possibile aggiungere un input o un output
(vedremo in seguito come) che possono essere modicati o rimossi in qualunque
momento. Quando viene aggiunto un input a un modulo compare un triangolino
rivolto verso il modulo (in,
in1
e
in2
in Figura B.3), invece quando viene aggiunto
un output, compare una nestra che richiede di denire la variabile d'output del
modulo (ricordiamo che le variabili d'output sono variabili locali); una volta denita
la variabile (nel nostro caso di nuovo boolean con valore iniziale 0) compare un
triangolino con la punta rivolta verso l'esterno del modulo (out in Figura B.3).
Una volta deniti gli ingressi e le uscite si possono eettuare i collegamenti. Nel caso
d'esempio a
M odule1
è passata in ingresso la variabile locale, mentre a
M odule2
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
111
Figura B.3: Denizione di tre variabili e navigazione dei moduli istanziati.
è passata sia la variabile locale che la variabile d'output
out
del Frame module
M odule1.
Sempre dall'esempio si vede come le variabili di un modulo compaiono a lato in una
struttura che mostra nome, tipo, valori possibili e valore iniziale; per le variabili di
input è specicato solo il nome ed il tipo in quanto gli altri parametri cambiano di
volta in volta, a seconda della variabile che è passata come ingresso
Quanto descritto n'ora è quello che compare a livello main; per andare a denire i
moduli istanziati è necessario passare al livello gerarchico inferiore. Facendo doppio
click su uno dei due rettangoli compare la nestra che rappresenta quel dato modulo; in Figura B.3 le rispettive nestre sono indicate dalle frecce. Da notare che
non è stato inserito nessun oggetto manualmente, quelli presenti sono stati automaticamente generati nel momento in cui sono stati creati gli input e l'output dei
moduli.
Inne osserviamo che nella nestra del FSM module non compaiono gracamente le
variabili; questo perché non ci sono passaggi di variabili all'interno dei moduli FSM
ma solo macchine a stati niti, quindi non avrebbe senso mettere oggetti diversi da
stati o transizioni; le variabili denite sono mostrate a lato nell'apposito widget.
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
112
Vista di un Frame module
Analizziamo in dettaglio le operazioni che possono essere fatte all'interno di una
nestra relativa ad un Frame module. Come abbiamo visto dall'esempio precedente
è possibile denire variabili locali, variabili d'istanza e passaggi di variabili, ma è possibile eettuare anche altre operazioni. Vediamo quali sono a seconda dell'oggetto
in esame.
Variabili locali
Per aggiungere una variabile locale basta premere il relativo pulsante e cliccare
in un punto dello schermo per far comparire l'oggetto graco.
Di default viene
assegnato un nome (vn , dove n varia a seconda delle variabili inserite), un tipo
boolean, e un valore iniziale pari a 0.
La variabile può essere rimossa selezionandola e premendo il tasto Canc o scegliendo
da menu l'azione Delete, oppure può essere modicata facendo doppio click o
selezionando da menu l'azione Edit.
Figura B.4: Modica di una variabile locale.
La modica viene eettuata inserendo i valori desiderati negli appositi campi; come
tipi sono presenti Boolean, Integer ed Enumeration.
In Figura B.4 è mostrato il
processo di modica di una variabile locale, in relazione all'esempio precedente: a
sinistra vediamo la nestra per la modica della variabile, mentre a destra possiamo
osservare le modiche eettivamente impostate.
Variabili d'istanza
Come per le variabili locali, anche le variabili d'istanza vengono
aggiunte premendo il relativo pulsante e cliccando sulla nestra; le azioni che si
possono eettuare su di esse sono mostrate in Figura B.5:
Rename
permette di rinominare la variabile e il modulo istanziato tramite l'apposito
widget mostrato in gura.
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
113
Figura B.5: Azioni sulle variabili d'istanza.
Copy
fa una copia della variabile che poi viene (eventualmente) incollata con il
comando Paste (dal menu della nestra o con la combinazione Ctrl+V);
è da osservare che la copia ottenuta crea un'istanza di un modulo diverso da
quello istanziato dalla variabile originale, ovvero nel modello viene aggiunto
un nuovo modulo. E' stato previsto questo comando perché si è ritenuto utile
editare un modulo a partire da uno già esistente, apportando poi eventuali
modiche.
Duplicate
crea una un'istanza dello stesso modulo; questo signica che ogni mo-
dica eettuata su di uno dei moduli si ripercuote sull'altro, ad esempio aggiungendo un'input ad una viene automaticamente aggiunto anche all'altra,
oppure rinominando il modulo istanziato, tutti i duplicati di quel modulo modicheranno il nome del modulo; ovviamente modicando il nome dell'istanza
non accade niente ai duplicati.
In particolare si osservi che le due variabili
fanno riferimento alla stessa nestra, cioè rappresentano lo stesso identico
modulo. L'utilità di questo comando è immediata se si pensa ad un modulo
che denisce tre variabili d'istanza dello stesso modulo, passando ogni volta
un ingresso diverso, e comunque sarà vista negli esempi.
Delete
elimina la variabile.
APPENDICE B.
AddInput
DESIGN E UTILIZZO DEL TOOL
114
permette di aggiungere una variabile di ingresso al modulo istanziato;
selezionando l'opzione si può scegliere dove posizionare il triangolo, che in
seguito può essere modicato, spostato o rimosso dal proprio menu.
AddOutput
permette di aggiungere una variabile di uscita al modulo istanziato;
selezionando l'opzione viene chiesto di inserire le proprietà della variabile,
dopodiché si può scegliere dove posizionare il triangolo, che in seguito può
essere modicato, spostato o rimosso dal proprio menu.
Process
permette di aggiungere (se selezionato) la keyword
process
al modulo
istanziato.
Per collegare output o variabili ad un input basta cliccare con il mouse sull'output
o sulla variabile e trascinare la linea no al triangolo che rappresenta l'ingresso del
modulo. Rilasciando il tasto del mouse il collegamento è eseguito.
Vista di un FSM module
Un FSM module implementa una macchina a stati niti e quindi le operazioni
permesse nel modicare tale modulo hanno a che fare con stati, transizioni e variabili
locali, di ingresso e di uscita.
Vediamo in Figura B.6 le caratteristiche di questa
nestra.
Stato
Per aggiungere uno stato è suciente premere il pulsante relativo e posizionare
l'oggetto nel punto desiderato della nestra; ogni stato ha un proprio menu, le cui
azioni sono descritte di seguito:
Rename
permette di modicare il nome dello stato, utilizzando il dialog mostrato
in Figura B.6.
Initial
permette di impostare lo stato come iniziale; viene visualizzato il relativo
simbolo (un tondo con una freccia che punta allo stato). L'opzione è mutualmente esclusiva fra gli stati presenti nel modulo, infatti non possono essere
presenti più stati iniziali contemporaneamente.
AddAction
permette di aggiungere azioni di tipo onentry, during ed onexit sullo
stato.
ModifyAction
mostra tutte le azioni presenti, da cui è possibile sceglierne una da
modicare.
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
115
Figura B.6: Finestra relativa a FSM Module.
RemoveAction
HideAction
elimina un'azione scegliendo tra quelle presenti.
nasconde la vista delle azioni.
Transizione
Per aggiungere una transizione è suciente premere il relativo pulsante, cliccare
sullo stato di partenza e trascinare la linea no allo stato nale, rilasciando dunque
il mouse; dal menu delle transizioni è possibile rimuovere le stesse o impostare la
condizione di attivazione.
Variabile
È possibile aggiungere, modicare o rimuovere variabili locali; come già detto queste
non compaiono gracamente, ma sono visualizzabili nell'apposita struttura a lato.
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
116
B.2 Esempi
Vediamo di seguito due esempi che mostrano, passo passo, come costruire un
modello; in particolare vedremo due esempi presenti nel tutorial di NuSMV.
B.2.1 Inverter ring
Questo programma prevede di creare tre istanze (asincrone) di uno stesso modulo chiamato inverter.
Vediamo quali sono i passi necessari alla creazione di tale
modello.
Figura B.7: Creazione modello inverter ring.
Per prima cosa aggiungiamo alla nestra principale una variabile di istanza che
implementa un FSM Module; il modulo istanziato rappresenta il modulo inverter,
quindi dovrà avere un ingresso che poi restituirà negato in uscita, aggiungiamo
pertanto un input (in) e un output (out). Il risultato si vede in Figura B.7 (a).
Poiché vogliamo tre istanze del modulo inverter, istanziamo altri due moduli duplicando due volte quello appena creato; il risultato ottenuto è mostrato in Figura B.7
(b).
Il passo successivo è quello di rinominare le variabili e il modulo con nomi più
signicativi: chiameremo le istanze
chiamato
gate1 , gate2
e
gate3 ,
mentre il modulo verrà
inverter.
Cambiamo il nome delle istanze e con l'ultima istanza modichiamo anche il nome
del modulo. I passaggi sono mostrati in Figura B.8 (a) e B.8 (b).
È necessario a questo punto collegare input e output dei moduli istanziati dopodiché,
poiché vogliamo che i tre processi siano eseguiti in parallelo, selezioniamo la composizione asincrona dal menu. Il risultato è in Figura B.9.
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
117
Figura B.8: Modica dei nomi di variabili e modulo.
Figura B.9: Le operazioni sulla nestra del main sono state completamente eseguite.
Il bordo tratteggiato del rettangolo sta a indicare appunto che il modulo è istanziato
con la keyword
process;
abbiamo inoltre aggiunto il vincolo
FAIRNESS running
al modulo main, come si vede dalle informazioni del modulo nella scheda Fairness.
Con quest'ultima azione abbiamo completato il main del modello, adesso dobbiamo
occuparci di costruire la macchina a stati che implementa l'inverter.
Facendo doppio click su una delle variabili d'istanza o sul modulo inverter nella
lista dei moduli si apre la nestra relativa dove è possibile costruire la macchina
a stati. Il nostro automa è molto semplice: è costituito da un unico stato che ha
un'unica transizione uscente; ogni volta che la transizione viene eseguita la variabile
d'ingresso
in
viene invertita e il suo valore è passato alla variabile d'uscita
out.
Vediamo in Figura B.10 i passaggi: prima di tutto aggiungiamo uno stato (poiché
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
118
Figura B.10: Implementazione della macchina a stati niti inverter.
è presente un unico stato, non è necessario assegnargli un nome signicativo, pertanto possiamo mantenere quello di default) ed un cappio. Da notare che non è
necessario aggiungere una condizione sulla transizione: in automatico, al momento
della traduzione, verrà assegnata alla transizione la condizione true.
Il passo successivo è quello di aggiungere una condizione (onentry o onexit, è
indierente) che assegni alla variabile out il valore invertito della variabile
in.
A questo punto la macchina a stati è completa e possiamo procedere con la traduzione
del modello graco in le testuale per NuSMV. Il le generato (salvato con il nome
inverter.smv) è mostrato in B.4.1
L'ultimo passo da fare è quello di avviare la verica del le; premendo il pulsante
relativo viene mostrato il pannello dei comandi disponibili. In Figura B.11 vediamo
quelli selezionati per il nostro modello.
Non essendoci formula da vericare non ha importanza selezionare i comandi relativi
al CTL e LTL model checking; allo stesso modo, avendo poche variabili di stato,
non è necessario impostare dei vincoli sulla scelta dello stato iniziale.
Viene quindi lanciato un processo NuSMV sul le dei comandi generato e il suo
output viene stampato su un le, chiamato nel caso d'esempio inverter_log.txt.
Entrambi i le sono mostrati in B.4.1
B.2.2 Mutual exclusion
In questo esempio viene simulato l'accesso ad una zona critica da parte di due
processi concorrenti.
A livello main serve quindi una variabile locale booleana che implementi un semaforo,
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
119
Figura B.11: Comandi selezionati per il modello inverter.
più due variabili che istanzino il modulo rappresentante il processo.
Vediamo in
Figura B.12 il modello graco relativo a quanto detto.
Per prima cosa possiamo aggiungere la variabile locale impostando i suoi parametri
come necessario, dopodiché istanziamo un modulo FSM e aggiungiamogli un input, nominandolo
semaphore,
come la variabile locale. Duplichiamo il modulo e
colleghiamo la variabile locale ai due ingressi; per eseguire questa operazione è suciente cliccare sulla variabile locale quando il cursore assume la forma di una croce e
trascinare la linea no al triangolino relativo (che diventa più grande quando è possibile rilasciare il mouse). Rinominiamo il modulo
proc1
e
proc2 ;
user
e le due variabili d'istanza
inne rendiamo le due istanze asincrone.
Il modulo main è così completato e possiamo passare a costruire la macchina a
stati niti che rappresenta il processo user. La nostra macchina a stati funzionerà
nel seguente modo: il processo rimane in attesa nché non decide di entrare nella
sezione critica, a quel punto deve vericare che non vi sia già presente un altro
processo.
Se la sezione critica è occupata attende che si liberi, quindi attiva il
semaforo ed entra in tale stato. Quando esce dalla sezione critica libera il semaforo
e torna in attesa.
Ci servono quindi quattro stati che implementino quanto appena detto e li chiameremo idle, entering, critical ed exiting, di cui il primo sarà impostato come iniziale.
Vediamo in Figura B.13 i quattro stati.
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
120
Figura B.12: Modulo main del modello mutual exclusion.
A questo punto è necessario aggiungere le transizioni e le azioni sugli stati: dallo
stato idle si può passare allo stato entering o rimanere nello stesso. Questa scelta
è non deterministica, ovvero non vi è alcuna condizione legata alle variabili che
fa scegliere fra le due transizioni possibili, ci aspettiamo quindi il comportamento
descritto in 3.3 riguardo le transizioni non deterministiche.
In particolare per tale esempio verrà creata la variabile
nondet_choice_idle = {idle, entering}
Dallo stato entering si può accedere a critical solo se il semaforo è libero, ovvero se
la variabile di ingresso semaphore è uguale a zero. Lo stato critical per le transizioni
è gestito come lo stato idle : sono presenti due transizioni non deterministiche da
critical in sé e da critical in exiting, verrà quindi creata una seconda variabile
nondet_choice_critical = {critical, exiting}
.
Inne dallo stato exiting si passa automaticamente allo stato idle e in fase di
traduzione verrà assegnata la condizione 1 a tale transizione.
A questo punto per completare la nostra macchina a stati dobbiamo impostare le
azioni in ingresso e in uscita agli stati; vediamo la macchina a stati completa delle
azioni e delle transizioni in Figura B.14.
Come si vede, le uniche azioni di interesse si hanno nello stato critical, dove viene
impostato semaphore a uno, e nello stato exiting, dove invece il semaforo è rilasciato.
L'ultima operazione da eettuare riguarda l'inserimento di due formule da vericare;
vediamo i passaggi in Figura B.15.
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
121
Figura B.13: Stati del processo user.
La prima formula (CTL) chiede di vericare che i due processi non siano mai
simultaneamente nello stato critical ed è la seguente:
AG ! (proc1.state = critical & proc2.state = critical)
mentre la seconda (LTL) verica il fatto che se un processo si trova nello stato
entering prima o poi andrà nello stato critical, ed è scritta come:
G (proc1.state = entering -> F proc1.state = critical)
Quest'ultima formula, come vedremo, non è vericata.
Possiamo quindi salvare il modello, esportarlo in le NuSMV e procedere con la
verica; in questo caso nel pannello dei comandi verranno selezionate anche le
opzioni per la verica delle formule LTL e CTL. I le generati sono mostrati in
B.4.2.
B.3 Utilizzo del programma
Il programma è stato realizzato per i sistemi operativi Windows e Linux.
Per l'esecuzione è suciente eseguire il le .jar.
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
122
Figura B.14: Macchina a stati completa di azioni e transizioni.
B.3.1 Requisiti
Per il corretto funzionamento del programma è necessario installare le seguenti
applicazioni:
- J2SE Runtime Environment 6.0
- NuSMV 2.*
B.4 File generati
Vediamo di seguito i le generati dai due esempi.
B.4.1 Esempio inverter ring
File inverter.smv:
MODULE main()
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
Figura B.15: Inserimento formule di verica.
VAR
gate_1 : process inverter(gate_3.out);
gate_2 : process inverter(gate_1.out);
gate_3 : process inverter(gate_2.out);
ASSIGN
FAIRNESS
running
MODULE inverter(input)
VAR
out : {0, 1};
state : {State_1};
ASSIGN
init(out) := 0;
next(out) :=
case
state = State_1 & 1 :
1 : out;
esac;
!input;
123
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
124
Come si vede dall'immagine del le, la condizione di transizione è stata aggiunta
automaticamente e posta pari a 1 (riga 25).
Vediamo adesso il le command.txt
set input_file /home/silvia/workspace/NuSmvGUI/mutual_exclusion.smv
go
check_fsm
print_reachable_states
show_vars -s -i
pick_state -r
print_current_state -v
simulate -r 5
show_traces -v
quit
e quindi il le il le inverter_log.txt generato eseguendo il processo:
NuSMV -load command.txt
***
***
***
***
This is NuSMV 2.4.3 (compiled on Sun Jan 18 09:51:57 UTC 2009)
For more information on NuSMV see <http://nusmv.irst.itc.it>
or email to <[email protected]>.
Please report bugs to <[email protected]>.
##########################################################
The transition relation is total: No deadlock state exists
##########################################################
##########################################################
system diameter: 3
reachable states: 7 (2^2.80735) out of 8 (2^3)
##########################################################
gate_1.out : boolean
gate_2.out : boolean
gate_3.out : boolean
_process_selector_ : {main, gate_3, gate_2, gate_1}
Current state is 1.1
_process_selector_ = main
gate_1.out = 0
gate_2.out = 0
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
gate_3.out = 0
******** Simulation Starting From State 1.1
********
<!-- ################ Trace number: 1 ################ -->
Trace Description: Simulation Trace
Trace Type: Simulation
-> State: 1.1 <gate_1.out = 0
gate_2.out = 0
gate_3.out = 0
gate_1.state = State_1
gate_2.state = State_1
gate_3.state = State_1
-> Input: 1.2 <_process_selector_ = gate_1
running = 0
gate_3.running = 0
gate_2.running = 0
gate_1.running = 1
-> State: 1.2 <gate_1.out = 1
gate_2.out = 0
gate_3.out = 0
gate_1.state = State_1
gate_2.state = State_1
gate_3.state = State_1
-> Input: 1.3 <_process_selector_ = gate_3
running = 0
gate_3.running = 1
gate_2.running = 0
gate_1.running = 0
-> State: 1.3 <gate_1.out = 1
gate_2.out = 0
gate_3.out = 1
gate_1.state = State_1
gate_2.state = State_1
gate_3.state = State_1
-> Input: 1.4 <_process_selector_ = gate_1
125
APPENDICE B.
->
->
->
->
->
DESIGN E UTILIZZO DEL TOOL
running = 0
gate_3.running = 0
gate_2.running = 0
gate_1.running = 1
State: 1.4 <gate_1.out = 0
gate_2.out = 0
gate_3.out = 1
gate_1.state = State_1
gate_2.state = State_1
gate_3.state = State_1
Input: 1.5 <_process_selector_ = gate_2
running = 0
gate_3.running = 0
gate_2.running = 1
gate_1.running = 0
State: 1.5 <gate_1.out = 0
gate_2.out = 1
gate_3.out = 1
gate_1.state = State_1
gate_2.state = State_1
gate_3.state = State_1
Input: 1.6 <_process_selector_ = gate_3
running = 0
gate_3.running = 1
gate_2.running = 0
gate_1.running = 0
State: 1.6 <gate_1.out = 0
gate_2.out = 1
gate_3.out = 0
gate_1.state = State_1
gate_2.state = State_1
gate_3.state = State_1
126
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
127
B.4.2 Esempio mutual exclusion
Il le mutual_exclusion.smv generato con la traduzione è il seguente:
MODULE main()
VAR
semaphore : {0, 1};
proc1 : process user(semaphore);
proc2 : process user(semaphore);
ASSIGN
init(semaphore) := 0;
CTLSPEC AG !(proc1.state = critical & proc2.state = critical)
LTLSPEC G (proc1.state = entering -> F proc1.state = critical)
MODULE user(semaphore)
VAR
state : {idle, entering, critical, exiting};
non_det_choice_idle : {idle, entering};
non_det_choice_critical : {critical, exiting};
ASSIGN
init(state) := idle;
init(non_det_choice_idle) := idle;
init(non_det_choice_critical) := critical;
next(state) :=
case
state = entering & semaphore=0 : critical;
state = idle & non_det_choice_idle = idle : idle;
state = idle & non_det_choice_idle = entering : entering;
state = critical & non_det_choice_critical = critical : critical;
state = critical & non_det_choice_critical = exiting : exiting;
state = exiting & 1 : idle;
1 : state;
esac;
next(semaphore) :=
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
128
case
state = entering & semaphore=0 : 1;
state = critical & non_det_choice_critical = critical : 1;
state = critical & non_det_choice_critical = exiting : 0;
1 : semaphore;
esac;
next(non_det_choice_idle) :=
case
state = idle & non_det_choice_idle = idle : {idle, entering};
state = exiting & 1 : {idle, entering};
1 : non_det_choice_idle;
esac;
next(non_det_choice_critical) :=
case
state = entering & semaphore=0 : {critical, exiting};
state = critical & non_det_choice_critical = critical
: {critical, exiting};
1 : non_det_choice_critical;
esac;
FAIRNESS
running
Come si vede sono presenti le due variabili per la scelta non deterministica delle
transizioni uscenti dagli stati idle e critical, inoltre gli assegnamenti a stati e variabili
sono tutti ben deniti, nonostante non ci siano condizioni specicate sulle transizioni
nel modello graco.
Compaiono le formule di verica e il vincolo fairness.
Il le command.txt generato al momento della verica è il seguente:
set input_file /home/silvia/workspace/NuSmvGUI/mutual_exclusion.smv
go
check_ctlspec
check_ltlspec
check_fsm
print_reachable_states
show_vars -s -i
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
129
pick_state -r
print_current_state -v
simulate -r 5
show_traces -v
quit
ed il le log generato nel quale viene mostrato il controesempio per le formule
specicate è mostrato sotto:
***
***
***
***
This is NuSMV 2.4.3 (compiled on Sun Jan 18 09:51:57 UTC 2009)
For more information on NuSMV see <http://nusmv.irst.itc.it>
or email to <[email protected]>.
Please report bugs to <[email protected]>.
-- specification AG !(proc1.state = critical
& proc2.state = critical) is true
-- specification G (proc1.state = entering ->
F proc1.state = critical) is false
-- as demonstrated by the following execution sequence
Trace Description: LTL Counterexample
Trace Type: Counterexample
-> State: 1.1 <semaphore = 0
proc1.state = idle
proc1.non_det_choice_idle = idle
proc1.non_det_choice_critical = critical
proc2.state = idle
proc2.non_det_choice_idle = idle
proc2.non_det_choice_critical = critical
-> Input: 1.2 <_process_selector_ = proc1
running = 0
proc2.running = 0
proc1.running = 1
-> State: 1.2 <proc1.non_det_choice_idle = entering
-> Input: 1.3 <_process_selector_ = proc1
running = 0
proc2.running = 0
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
proc1.running = 1
-> State: 1.3 <proc1.state = entering
-> Input: 1.4 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
-> State: 1.4 <proc2.non_det_choice_idle = entering
-> Input: 1.5 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
-> State: 1.5 <proc2.state = entering
-> Input: 1.6 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
-- Loop starts here
-> State: 1.6 <semaphore = 1
proc2.state = critical
proc2.non_det_choice_critical = exiting
-> Input: 1.7 <_process_selector_ = proc1
running = 0
proc2.running = 0
proc1.running = 1
-- Loop starts here
-> State: 1.7 <-> Input: 1.8 <_process_selector_ = main
running = 1
proc2.running = 0
proc1.running = 0
-- Loop starts here
130
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
-> State: 1.8 <-> Input: 1.9 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
-> State: 1.9 <semaphore = 0
proc2.state = exiting
-> Input: 1.10 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
-> State: 1.10 <proc2.state = idle
-> Input: 1.11 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
-> State: 1.11 <proc2.state = entering
-> Input: 1.12 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
-- Loop starts here
-> State: 1.12 <semaphore = 1
proc2.state = critical
-> Input: 1.13 <_process_selector_ = proc1
running = 0
proc2.running = 0
proc1.running = 1
-- Loop starts here
-> State: 1.13 <-> Input: 1.14 <-
131
APPENDICE B.
DESIGN E UTILIZZO DEL TOOL
_process_selector_ = main
running = 1
proc2.running = 0
proc1.running = 0
-> State: 1.14 <##########################################################
The transition relation is total: No deadlock state exists
##########################################################
##########################################################
system diameter: 13
reachable states: 77 (2^6.26679) out of 512 (2^9)
##########################################################
semaphore : boolean
proc1.state : {exiting, critical, entering, idle}
proc1.non_det_choice_idle : {entering, idle}
proc1.non_det_choice_critical : {exiting, critical}
proc2.state : {exiting, critical, entering, idle}
proc2.non_det_choice_idle : {entering, idle}
proc2.non_det_choice_critical : {exiting, critical}
_process_selector_ : {main, proc2, proc1}
Current state is 2.1
_process_selector_ = main
semaphore = 0
proc1.state = idle
proc1.non_det_choice_idle = idle
proc1.non_det_choice_critical = critical
proc2.state = idle
proc2.non_det_choice_idle = idle
proc2.non_det_choice_critical = critical
******** Simulation Starting From State 2.1
********
<!-- ################ Trace number: 2 ################ -->
Trace Description: Simulation Trace
Trace Type: Simulation
-> State: 2.1 <semaphore = 0
proc1.state = idle
proc1.non_det_choice_idle = idle
proc1.non_det_choice_critical = critical
proc2.state = idle
132
APPENDICE B.
->
->
->
->
->
->
DESIGN E UTILIZZO DEL TOOL
proc2.non_det_choice_idle = idle
proc2.non_det_choice_critical = critical
Input: 2.2 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
State: 2.2 <semaphore = 0
proc1.state = idle
proc1.non_det_choice_idle = idle
proc1.non_det_choice_critical = critical
proc2.state = idle
proc2.non_det_choice_idle = idle
proc2.non_det_choice_critical = critical
Input: 2.3 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
State: 2.3 <semaphore = 0
proc1.state = idle
proc1.non_det_choice_idle = idle
proc1.non_det_choice_critical = critical
proc2.state = idle
proc2.non_det_choice_idle = entering
proc2.non_det_choice_critical = critical
Input: 2.4 <_process_selector_ = proc1
running = 0
proc2.running = 0
proc1.running = 1
State: 2.4 <semaphore = 0
proc1.state = idle
proc1.non_det_choice_idle = entering
proc1.non_det_choice_critical = critical
proc2.state = idle
proc2.non_det_choice_idle = entering
133
APPENDICE B.
->
->
->
->
DESIGN E UTILIZZO DEL TOOL
proc2.non_det_choice_critical = critical
Input: 2.5 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
State: 2.5 <semaphore = 0
proc1.state = idle
proc1.non_det_choice_idle = entering
proc1.non_det_choice_critical = critical
proc2.state = entering
proc2.non_det_choice_idle = entering
proc2.non_det_choice_critical = critical
Input: 2.6 <_process_selector_ = proc2
running = 0
proc2.running = 1
proc1.running = 0
State: 2.6 <semaphore = 1
proc1.state = idle
proc1.non_det_choice_idle = entering
proc1.non_det_choice_critical = critical
proc2.state = critical
proc2.non_det_choice_idle = entering
proc2.non_det_choice_critical = exiting
134
Ringraziamenti
Ringrazio prima di tutti il Professor Alessandro Fantechi per la disponibilità e
l'attenzione mostrate nello sviluppo di questa tesi, oltre all'aiuto ed ai consigli forniti.
Un ringraziamento non meno importante va allo sta di NuSMV, in particolare
all' Ing. Marco Roveri e all'Ing. Stefano Tonetta, che si sono mostrati disponibili a
vericare il progetto e che hanno fornito preziosi suggerimenti per lo sviluppo della
versione nale, le cui funzionalità sono state migliorate grazie ai consigli dati.
Per tutto il supporto, la pazienza e l'aiuto fornito nell'arco di tempo in cui ho
sviluppato questa tesi, ringrazio l'Ing. Alessio Ferrari, senza il quale probabilmente
non sarei riuscita ad arrivare in fondo all'opera, o meglio non sarei stata in grado di
iniziarla: grazie per le e-mail lette, per il tempo dedicato in generale e, ovviamente,
per i tè oerti di accompagnamento alle discussioni.
Grazie anche a chi in questi anni di studi mi ha permesso di lavorare, mi ha dato ducia e mi ha fatto capire quanto posso valere:
Mauro, Margherita e tutte
le insegnanti/ginnaste del Poggetto, che considero un po' come la mia seconda
famiglia. E quindi grazie a tutte le mie bimbe che mi hanno fatto urlare, disperare
ma soprattutto divertire: Laura, Elena M., Valentina, Federica, Eleonora, Elena C.,
Tosca, e le altre (abbia pietà chi non è citato).
In tutto il percorso che ho fatto in questi anni e che mi ha portato a questo punto non
posso non ringraziare i miei amici, che mi hanno accompagnato in tutte le dicoltà
e che mi sono stati sempre vicini; un grazie particolare a quelle che considero più
come sorelle che come amiche: Elisa, Rossella, Valentina e Chiara, perché basta
una chiamata per sentire che siete con me.
Come dimenticare poi quelli che ho
avuto vicino nel corso degli studi, con cui ho potuto studiare, condividere ansie da
135
RINGRAZIAMENTI
136
esami, confrontarmi e arontare con serenità il percorso universitario: grazie Andrea,
Dario, Simone, Leonardo R., Riccardo, Matteo, Leonardo P., Alessandro, Barbara e
Jonathan, che mi sostiene in particolare da quasi tre anni con una pazienza ed un
aetto unici e che, nonostante le disavventure, lo stress, il buono e il cattivo tempo,
mi rende felice.
E inne, non certo per importanza, ringrazio la mia famiglia che mi ha accompagnato non solo nel periodo universitario ma per tutta la vita e che so ci sarà sempre:
grazie ai miei zii, Anna e Renzo, che sono soltanto due ma valgono per cento in
aetto, grazie a mia cugina Valentina (e a mio cugino-acquisito-da-matrimonio,
come lo chiamo io, Leonardo!), che davvero considero come una sorella, che è unica
al mondo e nessuno potrà mai sostituire. Grazie ai miei nonni Cosima e Giuseppe
(anche se non c'è più) che mi hanno cresciuto e che ricorderò per il resto della mia vita sempre con aetto.
Per quel che riguarda la mia nuova famiglia mi
tocca ringraziare nuovamente Jonathan e aggiungere chi mi ha accolto e voluto
bene: Sarah e Lodovica grazie di tutto e, per quanto stupido possa sembrare, devo
ringraziare anche il piccolo Diego, che porto nel cuore da due anni e che ormai fa
parte di questa piccola ma grande famiglia. E ovviamente ringrazio innitamente e
con tutto il cuore i miei genitori, senza i quali non sarei qui, senza il cui continuo
sostegno, aetto, pazienza, non sarei diventata la persona che sono, che mi hanno
spronato e appoggiato in tutte le decisioni che ho preso, che non mi hanno mai
negato nulla e che per me sono un punto di riferimento indispensabile.
Grazie in particolare a mio babbo, che ha lottato nessuno sa quanto per esser qui
oggi.
Bibliograa
[ABE00]
Parosh Aziz Abdulla, Per Bjesse, and Niklas Eén. Symbolic Reachability Analysis based on SAT-Solvers. TACAS'00, 2000 Springer-Verlag,
2000.
[AIS97]
Christopher Alexander, Sara Ishikawa, and Murray Silverstain. A Pattern Language:
Towns, Buildings, Construction.
Oxford University
Press, 1997.
[AVV97]
Miguel A. Alonso Pardo, Éric Villemonte de la Clergerie, and Manuel
Vilares Ferro.
Automata-based parsing in dynamic programming
for Linear Indexed Grammars.
In A. S. Narin'yani, editor, Proc.
of DIALOGUE'97 Computational Linguistics and its Applications
International Workshop, pages 2227, Moscow, Russia, June 1997.
[Bau00]
Peter Baumgartner. FDPLL A First-Order Davis-Putnam-LogemanLoveland
Procedure.
In
Proceedings
of
the
17th
International
Conference on Automated Deduction, pages 200219, 2000.
[Ber05]
Larry Bernstein.
Foreword:
Importance of software prototyping.
Journal of Systems Integration, 6(1-2):914, November 2005.
[BSC98]
Sergey Berezin, Campos Sérgio, and Edmund M. Clarke.
Composi-
tional Reasining in Model Checking. CMU TR CMU-CS-98-106 and
appear in Proceedings of the Workshop COMPOS'97, 1998.
[Bur87]
Steve
How
Burbeck.
to
use
Applications
programming
Model-View-Controller
(MVC),
in
1987.
www.cs.uiuc.edu/users/smarch/st-docs/mvc.html.
137
smalltalk-80(tm):
http://st-
BIBLIOGRAFIA
[Bus45]
+
[CCB ]
138
Vannevar Bush. As we may think. The Atlantic Monthly, 1945.
Roberto Cavada, Alessandro Cimatti, Marco Benedetti, Marco Pistore,
Marco Roveri, and Roberto Sebastiani. Nusmv: a new symbolic model
checker. http://nusmv.irst.itc.it/.
+
[CCG 02]
Alessandro Cimatti, Edmund M. Clarke, Enrico Giunchiglia, Fausto
Giunchiglia, Marco Pistore, Marco Roveri, Roberto Sebastiani, and
Armando Tacchella. Nusmv 2: An opensource tool for symbolic model
checking. In CAV, pages 359364, 2002.
+
[CCJ ]
Roberto
Gavin
co
Cavada,
Alessandro
Keighren,
Roveri,
and
Emanuele
Andrei
Cimatti,
Olivetti,
Tchaltsev.
Charles
Marco
NuSMV
A.
Jochim,
Pistore,
2.4
User
Mar-
Manual.
http://nusmv.fbk.eu/NuSMV/userman/index-v2.html.
+
[CCK ]
Roberto Cavada,
Alessandro Cimatti,
Gavin Keighren,
Olivetti, Marco Pistore, and Marco Roveri.
Emanuele
NuSMV 2.2 Tutorial.
http://nusmv.fbk.eu/NuSMV/tutorial/index.html.
+
[CFF 01]
Fady Copty, Limor Fix, Ranan Fraer, Enrico Giunchiglia, Gila Kamhi,
Armando Tacchella, and Moshe Y. Vardi. Benets of Bounded Model
Checking at an Industrial Setting.
In 13th International Conference
on Computer Aided Verication (CAV'2001), volume 2102 of LNCS,
2001.
[CGH94]
E.M. Clarke, O. Grumberg, and K. Hamaguchi. Another look at LTL
model checking. In David L. Dill, editor, Proceedings of the sixth International Conference on Computer-Aided Verication CAV, volume 818,
pages 415427, Standford, California, USA, 1994. Springer-Verlag.
+
[CGP 02]
Alessandro Cimatti, Enrico Giunchiglia, Marco Pistore, Marco Roveri,
Roberto Sebastiani,
and Armando Tacchella.
Integrating BDD-
based and SAT-based Symbolic Model Checking. Proceeding of 4th
International Workshop on Frontiers of Combining Systems, 2002.
[Cnf ]
[Dav92]
Cnf converter. http://www.artima.com/cs/cnf.html.
Alan
M.
Davis.
Operational
prototyping:
A
new
development
approach. IEEE Software, 9(5):7078, September 1992.
[dev05]
Selecting a development approach, 2005.
Human Services.
Department of Healt &
BIBLIOGRAFIA
[Eme94]
139
Allen E. Emerson. Handbook of Theoretical Computer Science, Volume B: Formal Models and Sematics, pages 9951072. North Holland
Co. The MIT Press, 1994.
[GHJV94]
Erich Gamma, Richard Helm, Ralph Johnson, and John M. Vlissides. Design Pattern: Elements of Reusable Object-Oriented Software.
Addison-Wesley Professional, 1994.
[Gup93]
Vineet Gupta.
Concurrent Kripke Structures.
Technical report,
Proceedings of the North American Process Algebra Workshop, 1993.
[HMU00]
John E. Hopcroft, Rajeev Motwani, and Jerey D. Ulmann.
Intro-
duction to Automata Theory, Languages and Computation. Addison
Wesley, 2 edition, 2000.
[Kay93]
Alan C. Kay. The early history of smalltalk, 1993.
[Kor85]
András Kornai. Natural Language and the Chomsky Hierarchy. Proceedings of the 2nd European Conference of the Association for
Computational Linguistics, 1985.
[KP88]
Glenn E. Krasner and Stphen T. Pope. A cookbook for using modelview controller user interface paradigm in smalltalk-80.
Journal of
Object-Oriented Programming, pages 2649, August 1988.
[L.73]
Richards
Charles
L.
An
easy
way
to
design
complex
program
controllers. Electronics, 1:107113, February 1973.
[Maz]
Paolo Mazzoni.
Model Checking Tutorial.
Politecnico di Milano -
Dipartimento di Elettronica e Informazione.
[McM93]
Kenneth L. McMillan. Symbolic Model Checking. Kluwer Academic
Publishers, 1993.
[Mil08]
Steven P. Miller. Will this be formal? In Theorem Proving in Higher
Order Logics, volume 5170, pages 611, October 2008.
[Ope]
The Open Source Organization. http://www.opensource.org.
[Pri]
http://www.prismmodelchecker.org/.
PRISM a Probabilistic Model
Checker.
[QtJ]
The Graphics View Framework.
http://doc.trolltech.com/qtjambi-
4.4/html/com/trolltech/qt/graphicsview.html.
[Ras00]
Jef Raskin. The Human Interface. Addison-Wesley Professional, 2000.
BIBLIOGRAFIA
[Ray03]
140
Eric Steven Raymond. The Art of Unix Programming. Addison-Wesley
Professional, 2003.
[Sha03]
Anatoly Shalyto. Technology of Automata-Based Programming. SaintPetersburg State University of Information Technologies, Mechanics
and Optics Computer Technologies Department, 2003.
[Smi04]
Jan Smith. Kripke Semantics, 2004.
[Som]
Fabio Somenzi. Cudd: Cu decision diagram package. Release 2.4.2.
http://vlsi.colorado.edu/ fabio/CUDD/cuddIntro.html.
[Spi]
Ltl model checking with spin. http://spinroot.com/spin/whatispin.html.
[Upp]
Uppaal. http://www.uppaal.com/.
[Ven01]
Yde Venema. The Blackwell Guide to Philosophical Logic, chapter 10,
pages 203223. Blackwell Publishers, Malden, USA, 2001.
[W3C]
Extensible markup language (XML). http://www.w3.org/XML/.
[Wag92]
Ferdinand Wagner. VFSM Executable Specication. In CompEuro'92.
Computer Systems and Software Engineering, pages 226231, May
1992.
[WSWW06] Ferdinand Wagner, Ruedi Shmuki, Thomas Wagner, and Peter Wolstenholme. Modeling Software with Finite State Machine - A Pratical
Approach. Auerbach Publication, New York, 2006.