145
Universit ` a degli Studi di Udine Facolt ` a di Scienze Matematiche Fisiche e Naturali Corso di Laurea Triennale in Informatica Tesi di Laurea Un ambiente di sviluppo per bigrafi diretti Candidato: Patrik Osgnach Relatore: prof. Marino Miculan Anno Accademico 2007/2008 Universit` a degli Studi di Udine Via delle Scienze, 206 33100 Udine Italia

Un ambiente di sviluppo per bigra direttiusers.dimi.uniud.it/~marino.miculan/data/labs/TesiOsgnach.pdf · 1 Introduzione Tra i modelli per rappresentare processi e de nirne il comportamento

  • Upload
    buidien

  • View
    214

  • Download
    0

Embed Size (px)

Citation preview

Universita degli Studi di Udine

Facolta di Scienze Matematiche Fisiche e Naturali

Corso di Laurea Triennale in Informatica

Tesi di Laurea

Un ambiente di sviluppoper bigrafi diretti

Candidato:

Patrik Osgnach

Relatore:

prof. Marino Miculan

Anno Accademico 2007/2008

Universita degli Studi di UdineVia delle Scienze, 206

33100 UdineItalia

Indice

1 Introduzione 1

2 Bigrafi diretti 7

2.1 Place graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.1.1 Definizioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.2 Directed link graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2.2.1 Definizioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2.3 Bigrafi diretti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2.3.1 Algebra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

2.3.2 Bigrafi elementari . . . . . . . . . . . . . . . . . . . . . . . . 16

3 Implementazione dei bigrafi diretti 19

3.1 Linguaggio utilizzato . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

3.2 Struttura dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

3.2.1 Insieme delle signature . . . . . . . . . . . . . . . . . . . . . . 20

3.2.2 Classe directedbg . . . . . . . . . . . . . . . . . . . . . . . . . 20

3.2.2.1 Insieme dei nodi . . . . . . . . . . . . . . . . . . . . 22

3.2.2.2 Insieme degli archi . . . . . . . . . . . . . . . . . . . 22

3.2.2.3 Place graph . . . . . . . . . . . . . . . . . . . . . . . 22

3.2.2.4 Link graph . . . . . . . . . . . . . . . . . . . . . . . 23

3.2.2.5 Lista dei controlli . . . . . . . . . . . . . . . . . . . 24

3.2.2.6 Interfaccia interna . . . . . . . . . . . . . . . . . . . 24

3.2.2.7 Interfaccia esterna . . . . . . . . . . . . . . . . . . . 25

3.3 Operazioni di base . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

3.3.1 Tensore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

3.3.2 Composizione . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

3.3.2.1 Insieme dei nodi . . . . . . . . . . . . . . . . . . . . 26

3.3.2.2 Insieme degli archi . . . . . . . . . . . . . . . . . . . 27

iv INDICE

3.3.2.3 Place graph . . . . . . . . . . . . . . . . . . . . . . . 27

3.3.2.4 Link graph . . . . . . . . . . . . . . . . . . . . . . . 27

3.3.2.5 Lista dei controlli . . . . . . . . . . . . . . . . . . . 28

3.3.2.6 Interfaccia interna . . . . . . . . . . . . . . . . . . . 28

3.3.2.7 interfaccia esterna . . . . . . . . . . . . . . . . . . . 28

3.3.2.8 Il metodo composition . . . . . . . . . . . . . . . . . 28

3.4 Operazioni derivate . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

3.4.1 Sharing products . . . . . . . . . . . . . . . . . . . . . . . . . 29

3.4.1.1 Outer sharing product . . . . . . . . . . . . . . . . . 29

3.4.1.2 Inner sharing product . . . . . . . . . . . . . . . . . 29

3.4.1.3 Sharing product . . . . . . . . . . . . . . . . . . . . 30

3.4.2 Prime sharing products . . . . . . . . . . . . . . . . . . . . . 30

3.4.2.1 Prime outer sharing product . . . . . . . . . . . . . 31

3.4.2.2 Prime sharing product . . . . . . . . . . . . . . . . . 31

3.5 Algebra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

3.5.1 Bigrafi elementari . . . . . . . . . . . . . . . . . . . . . . . . 32

3.5.1.1 Swap . . . . . . . . . . . . . . . . . . . . . . . . . . 32

3.5.1.2 Identita . . . . . . . . . . . . . . . . . . . . . . . . . 32

3.5.1.3 Closure . . . . . . . . . . . . . . . . . . . . . . . . . 33

3.5.1.4 Up-closure . . . . . . . . . . . . . . . . . . . . . . . 33

3.5.1.5 Down-closure . . . . . . . . . . . . . . . . . . . . . . 34

3.5.1.6 Merge . . . . . . . . . . . . . . . . . . . . . . . . . . 34

3.5.1.7 Barren root . . . . . . . . . . . . . . . . . . . . . . . 34

3.5.1.8 Substitution . . . . . . . . . . . . . . . . . . . . . . 35

3.5.1.9 Empty Substitution . . . . . . . . . . . . . . . . . . 35

3.5.1.10 Fusion . . . . . . . . . . . . . . . . . . . . . . . . . . 35

3.5.1.11 Empty Fusion . . . . . . . . . . . . . . . . . . . . . 35

3.5.1.12 Rename . . . . . . . . . . . . . . . . . . . . . . . . . 36

3.5.1.13 Discrete Ion . . . . . . . . . . . . . . . . . . . . . . 36

3.5.2 Forma normale discreta . . . . . . . . . . . . . . . . . . . . . 37

3.5.2.1 Scomposizione in bigrafi primi . . . . . . . . . . . . 40

3.5.3 Uguaglianza tra bigrafi . . . . . . . . . . . . . . . . . . . . . . 40

INDICE v

4 Il linguaggio ed il compilatore 43

4.1 Il linguaggio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

4.1.1 La grammatica . . . . . . . . . . . . . . . . . . . . . . . . . . 43

4.2 Il Compilatore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

4.2.1 L’analizzatore lessicale . . . . . . . . . . . . . . . . . . . . . . 46

4.2.2 Il parser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

4.2.2.1 La signature . . . . . . . . . . . . . . . . . . . . . . 47

4.2.2.2 I bigrafi elementari . . . . . . . . . . . . . . . . . . . 48

4.2.2.3 Le operazioni tra bigrafi . . . . . . . . . . . . . . . . 54

4.2.2.4 Forzare le precedenze . . . . . . . . . . . . . . . . . 62

4.2.2.5 I blocchi let . . . . . . . . . . . . . . . . . . . . . . . 62

4.2.3 L’interfaccia del compilatore . . . . . . . . . . . . . . . . . . 62

4.3 Aspetti implementativi . . . . . . . . . . . . . . . . . . . . . . . . . . 63

4.3.1 L’analizzatore lessicale . . . . . . . . . . . . . . . . . . . . . . 63

4.3.1.1 Intestazione . . . . . . . . . . . . . . . . . . . . . . . 63

4.3.1.2 Definizioni . . . . . . . . . . . . . . . . . . . . . . . 64

4.3.1.3 Regole . . . . . . . . . . . . . . . . . . . . . . . . . 65

4.3.1.4 Differenze per la generazione del programma OCaml 66

4.3.2 Il Parser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

4.3.2.1 Intestazione . . . . . . . . . . . . . . . . . . . . . . . 67

4.3.2.2 Dichiarazioni . . . . . . . . . . . . . . . . . . . . . . 69

4.3.2.3 Regole . . . . . . . . . . . . . . . . . . . . . . . . . 70

4.3.2.4 Differenze per la generazione del programma ocaml 77

4.3.3 L’interfaccia del compilatore . . . . . . . . . . . . . . . . . . 77

5 Il decompilatore 79

5.1 Decompilazione della signature . . . . . . . . . . . . . . . . . . . . . 79

5.2 Decompilazione del bigrafo . . . . . . . . . . . . . . . . . . . . . . . 80

5.2.1 Componente w . . . . . . . . . . . . . . . . . . . . . . . . . . 80

5.2.2 Componente d . . . . . . . . . . . . . . . . . . . . . . . . . . 81

5.3 Funzioni ausiliarie . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83

5.4 Esempo di output . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85

vi INDICE

6 Il visualizzatore 87

6.1 Funzione principale . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

6.2 Codice per il place graph . . . . . . . . . . . . . . . . . . . . . . . . 88

6.3 Posizioni di archi e nomi . . . . . . . . . . . . . . . . . . . . . . . . . 89

6.4 Codice per i link . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91

6.5 Altre funzioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92

6.6 Esempio di output . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96

7 Conclusioni 97

A Sorgenti del compilatore 99

A.1 Generazione delle coppie (signature,bigrafo) . . . . . . . . . . . . . . 99

A.1.1 Analizzatore lessicale . . . . . . . . . . . . . . . . . . . . . . . 99

A.1.2 Parser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100

A.2 Generazione del programma OCaml . . . . . . . . . . . . . . . . . . 107

A.2.1 Analizzatore lessicale . . . . . . . . . . . . . . . . . . . . . . . 107

A.2.2 Parser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109

A.3 Interfaccia del compilatore . . . . . . . . . . . . . . . . . . . . . . . . 116

B Sorgenti Decompilatore 117

C Sorgenti del visualizzatore 125

Bibliografia 139

1Introduzione

Tra i modelli per rappresentare processi e definirne il comportamento i “labelled

transition systems” (LTS) sono molto importanti. Essi specificano le capacita di

interazione di ogni componente tramite “etichette”, che rappresentano cosa puo

essere visto dall’ambiente. Molte metodologie per valutare equivalenze e verificare

proprieta dei processi quali la bisimulazione e il model checking si basano su modelli

di questo tipo.

La difficolta nell’usare questo modello consiste nel fatto che non ci sono metodi

“automatici” per crearli. Infatti gli LTS vengono in genere “fatti a mano” ma la

complessita di questi modelli cresce all’aumentare della complessita dei processi da

rappresentare.

Per ovviare a queste difficolta si e cercato un metodo per derivare gli LTS a

partire da modelli che possono descrivere processi ma che sono piu semplici da ge-

nerare. Purtroppo, in generale, i modelli che riescono a derivare degli LTS, dovendo

rappresentare tutte le interazioni di tutte le etichette in tutti i contesti, generano

LTS molto “grandi” e quindi poco usabili.

Un meta-modello emergente e quello dei bigrafi, descritto da Milner in [7, 8].

Questo modello e importante in quanto supporta un metodo per generare un’insieme

di etichette minimale e dunque generare degli LTS migliori. Questo metodo di

riduzione e l’RPO ovvero relative pushout ed una costruzione per i bigrafi e stata

data da Jensen e Milner in [6]. Un bigrafo e un meta-modello dove sia la localita

che la connettivita sono importanti, e composto da due strutture ortogonali, un

place graph per rappresentare la localita ed un link graph per rappresentare le

connessioni. Con questo tipo di modello si possono rappresentare modelli di calcolo

come il π-calcolo e le reti di Petri.

Un place graph rappresenta le localita, e composto da radici, nodi e siti. Esso

pua essere visto come una foresta di alberi. Ogni albero della foresta e generato da

2 CAPITOLO 1. INTRODUZIONE

L

K

L

L

K

x y

Figure 1: An example of a bigraph

1 IntroductionBigraphical reactive systems (BRSs) [28, 29, 30, 20] are a graphical model of compu-tation in which both locality and connectivity are prominent. Recognising the increas-ingly topographical quality of global computing, they take up the challenge to base alldistributed computation on graphical structure. A typical bigraph is shown in Figure 1.Such a graph is reconfigurable, and its nodes (the ovals and circles) may represent agreat variety of computational objects: a physical location, an administrative region, adata constructor, a !-calculus input guard, an ambient, a cryptographic key, a message,a replicator, and so on.Bigraphs are a development of action calculi [26], but simpler. They use ideas from

many sources: the Chemical Abstract machine (Cham) of Berry and Boudol [2], the!-calculus of Milner, Parrow and Walker [31], the interaction nets of Lafont [22], themobile ambients of Cardelli and Gordon [7], the explicit fusions of Gardner and Wis-chik [16] developed from the fusion calculus of Parrow and Victor [33], Nomadic Pictby Wojciechowski and Sewell [41], and the uniform approach to a behavioural theoryfor reactive systems of Leifer and Milner [24]. This memorandum is self-contained;it builds on preliminary definitions and results put forward by Milner [29], but theapproach here is a lot simpler and developed more fully.The theory of BRSs responds to twin challenges: from application, and from exist-

ing process theory. The former demands greater breadth of concepts, while the latterdemands continuity of ideas. We now discuss these challenges separately.

6

Figura 1.1: Esempio di bigrafo

una radice che come figli puo avere siti o nodi. I siti sono sempre foglie quindi non

possono avere figli, essi rappresentano punti in cui e possibile comporre due place

graph. La composizione di due place graph opera innestando una radice di uno in

un sito dell’altro.

Un nodo puo essere figlio di una radice oppure di un altro nodo e puo contenere

(avere come figli) dei siti.

L’altra struttura che fa parte dei bigrafi e il link graph: una struttura che de-

finisce le connessioni dei nodi alle risorse. Le risorse possono appartenere ad altri

nodi o essere esterne al bigrafo, raggiungibili passando per delle interfacce. Queste

interfacce contengono nomi che le rappresentano risorse esterne.

Place graph e link graph condividono l’insieme dei nodi ma per il resto sono

indipendenti.

Un esempio di bigrafo a rappresentato nella figura 1.1, mentre nelle figura 1.2 si

puo vedere come un bigrafo puo essere scomposto in un place graph ed un link graph.

Questo tipo di bigrafi possono essere modificati per disporre di uno strumento

ancora piu generale. Il modello in questione e quello dei bigrafi diretti introdotti da

Grohmann e Miculan in [4].

I bigrafi diretti mantengono la stessa struttura delle localita dei bigrafi di Milner,

3

Bigrafo G : 〈3, X〉 → 〈2, Y 〉

X = {x0, x1}; Y = {y0, y1, y2}Y = {y0, y1, . . .}X = {x0, x1, . . .}

roots . . . . . . names . . .

inner names . . . . . .sites . . .

link graph GL : X "Yplace graph GP : 3" 2

bigraph G : #3, X$"#2, Y $

r1

v3

v2

v0

r0

v1

v0

v2

v3

v1

v0

v1

v2

v3

r0 r1

s1 s2

y0 y1 y2

s1

y0 y1

x0

s2

y2

x1

s0

s0

x0 x1

Figure 8: Resolving a pure bigraph into a place graph and a link graph

pure bigraph as a combination of two independent mathematical structures — a placegraph and a link graph. Note that this combination is quite distinct from the categoricalcomposition used to insert one bigraph into another (e.g. an agent into a context). But itis simply related to them; to compose two bigraphs categorically, we first resolve theminto their respective place graphs and link graphs, then compose these, and finallycombine the results into a new bigraph.It is helpful to see an example in Figure 8 of how a pure bigraph G can be resolved

into a place graph GP representing locality, and a link graph GL representing connec-tivity. (Controls are not shown in the diagram.) The nodes v0, . . . , v3 are commonto the two structures, which are otherwise independent. Note the bigraph’s interfaces#3,X$"#2, Y $, which are pairs; there is no middle component here, because a purebigraph has no local names. This interface combines the place graph interface 3" 2with the link graph interfaceX"Y ; nothing determines that the names y0, y1, y2 ‘be-long’ to any particular region of the bigraph (= root of the place graph), nor that the

19

Place graph GP : 3→ 2 e link graph GL : X → Y

Y = {y0, y1, . . .}X = {x0, x1, . . .}

roots . . . . . . names . . .

inner names . . . . . .sites . . .

link graph GL : X "Yplace graph GP : 3" 2

bigraph G : #3, X$"#2, Y $

r1

v3

v2

v0

r0

v1

v0

v2

v3

v1

v0

v1

v2

v3

r0 r1

s1 s2

y0 y1 y2

s1

y0 y1

x0

s2

y2

x1

s0

s0

x0 x1

Figure 8: Resolving a pure bigraph into a place graph and a link graph

pure bigraph as a combination of two independent mathematical structures — a placegraph and a link graph. Note that this combination is quite distinct from the categoricalcomposition used to insert one bigraph into another (e.g. an agent into a context). But itis simply related to them; to compose two bigraphs categorically, we first resolve theminto their respective place graphs and link graphs, then compose these, and finallycombine the results into a new bigraph.It is helpful to see an example in Figure 8 of how a pure bigraph G can be resolved

into a place graph GP representing locality, and a link graph GL representing connec-tivity. (Controls are not shown in the diagram.) The nodes v0, . . . , v3 are commonto the two structures, which are otherwise independent. Note the bigraph’s interfaces#3,X$"#2, Y $, which are pairs; there is no middle component here, because a purebigraph has no local names. This interface combines the place graph interface 3" 2with the link graph interfaceX"Y ; nothing determines that the names y0, y1, y2 ‘be-long’ to any particular region of the bigraph (= root of the place graph), nor that the

19

Figura 1.2: Un bigrafo scomposto in place graph e link graph

4 CAPITOLO 1. INTRODUZIONE

Directed link graph A : ({u}, {s, t, w})→ ({z}, {x, y})x y z

w s t u

e0e1 v0

v1

Figura 1.3: Esempio di directed link graph

ovvero il place graph, pero il link graph e sostituito da un directed link graph che e

una sua generalizzazione.

L’idea chiave dei directed link graph e di notare come i nomi non sono risorse

ma solo un modo per indicare risorse esterne. Le risorse sono rappresentate da ar-

chi, rappresentati come oggetti espliciti e non come iper-archi, i nomi e le porte del

bigrafo diretto sono quindi collegati agli archi con archi semplici. In questo caso le

richieste partono dalle porte dei nodi,ed arrivano ad archi interni oppure su nomi

delle interfacce. Nei directed link graph pero un bigrafo puo offrire risorse attraverso

la stessa interfaccia quindi ci possono essere link, che rappresentano richieste ester-

ne, che dai nomi delle interfacce sono mappati su archi interni. Questo permette

di rappresentare flussi di richeste piu generali ovvero le risorse possono sia essere

richieste che fornite attraverso la stessa interfaccia.

Per evitare inconsistenze bisogna pero distinguere la polarita dei nomi di ogni

interfaccia seconda della direzione delle richieste: “verso l’alto” oppure “verso il

basso”.

La figura 1.3 mostra un esempio di directed link graph.

Anche per i bigrafi diretti e stata data una costruzione degli RPO [4] , rendendoli

dunque un modello valido per derivare LTS. Assieme a questo e stata sviluppata

un’algebra ed una forma normale in [3].

Ora, avendo a disposizione la teoria dei bigrafi diretti, e necessario realizzare

degli strumenti che permettano l’uso concreto di questo modello. La realizzazio-

ne degli strumenti deve tenere in considerazione chi saranno i possibili utenti degli

strumenti stessi. Fin da subito possiamo individuare come utenti i programmato-

5

ri di linguaggi concorrenti e le persone interessate alla formalizzazione di sistemi

concorrenti. Queste categorie di utenti hanno esigenze e competenze diverse: i pro-

grammatori preferiscono usare direttamente le strutture dati e le funzioni che queste

offrono mentre chi non e un esperto preferisce lavorare con interfacce intuitive e lin-

guaggi semplici da imparare ed usare. In pratica, per raggiungere questo obiettivo,

e necessario avere a disposizione:

1. Una implementazione del modello dei bigrafi diretti

2. Un insieme di funzioni per manipolare i bigrafi stessi

3. Un linguaggio per scrivere in modo semplice e veloce i bigrafi

4. Un compilatore ed un decompilatore per questo linguaggio

5. Un visualizzatore per poter vedere graficamente come e fatto un bigrafo

6. Una interfaccia grafica per “disegnare” i bigrafi in modo semplice

Attualmente abbiamo a disposizione: l’implementazione del modello e delle fun-

zioni realizzate da Pellarini in [9] e un linguaggio per i bigrafi (puri, non diretti)

realizzato presso l’ITU di Copenhagen [2]

Lo scopo di questo lavoro e di realizzare gli strumenti sopra descritti, in parti-

colare il linguaggio, il compilatore, il decompilatore e il visualizzatore. Il linguaggio

e un linguaggio simile ad un linguaggio di programmazione funzionale e consente

di scrivere bigrafi qualsiasi sotto forma di bigrafi elementari ed operazioni su di es-

si. Il compilatore e stato realizzato usando gli strumenti ocamllex e ocamlyacc che

generano rispettivamente un analizzatore lessicale ed un parser scritti in linguaggio

OCaml. Il compilatore fornisce un insieme di funzioni di interfaccia per essere usa-

to dagli utenti. Il decompilatore permette di ottenere una rappresentazione di un

qualsiasi bigrafo nel linguaggio precedentemente definito. Il visualizzatore permette

di “vedere” graficamente un bigrafo sotto forma di immagine SVG.

Questo volume e cosı suddiviso: Il capitolo 2 presenta la teoria dei bigrafi diretti,

le operazioni su di essi e l’algebra cosı come introdotti da Grohmann e Miculan in

[4, 3]. Il capitolo 3 descrive l’implementazione del modello e delle sue operazioni

realizzato da Pellarini in [9]. Il capitolo 4 descrive il linguaggio per bigrafi diretti, la

sua grammatica e sintassi e il funzionamento del compilatore. Il capitolo 5 descrive

il decompilatore e infine 6 descrive il visualizzatore. Infine gli appendici mostrano i

sorgenti degli strumenti realizzati.

6 CAPITOLO 1. INTRODUZIONE

2Bigrafi diretti

I bigrafi diretti si ottengono componendo un place graph ed un directed link graph

costruiti sugli stessi nodi.

2.1 Place graph

Si introducono in questa sezione i place graph come definiti in [5].

2.1.1 Definizioni

Definizione 1 (place graph). Un place graph A = (V, ctrl, prnt) : m → n ha

un’ampiezza interna m ed un’ampiezza esterna n, entrambi ordinali finiti; un insieme

finito di nodi V con una mappa di controlli ctrl : V → K; ed una parent map

prnt : m ] V → V ] n. La parent map e aciclica , ad es. prntk(v) 6= v per ogni

k > 0 e v ∈ V . Un nodo atomico - ovvero un nodo il cui controllo e atomico - non

puo essere padre. Scriveremo w >A w′, o semplicemente w > w′ per w = prntk(v)

per qualche k > 0.

Le ampiezze m ed n indicano il numero di siti e radici di A rispettivamente. I

siti e nodi - ovvero il dominio di prnt - sono chiamati place.

La condizione di aciclicita fa in modo che la parent map prnt rappresenti una

foresta di n alberi non ordinati. Siti e radici forniscono un metodo per comporre le

foreste di due place graph; ogni radice del primo e innestata in un differente sito del

secondo.

Definizione 2 (composizione). La composizione A1 ◦ A0 : m0 → m2 di due place

graph Ai = (Vi, ctrli, prnti) : mi → mi+1(i = 0, 1) e definita quando i due insiemi

dei nodi sono disgiunti; allora A1 ◦ A0 , (V, ctrl, prnt) dove V = V0 ] V1, ctrl =

ctrl0 ] ctrl1 e prnt = (IdV0 ] prnt1) ◦ (prnt0 ] IdV1). Il place graph identita di grado

m e Idm , (∅, ∅K, Idm) : m→ m.

8 CAPITOLO 2. BIGRAFI DIRETTI

E intuitivo che A ◦ Id = A = Id ◦A, e che la composizione e associativa.

Definizione 3 (barren, sibling, attivo, passivo). Un nodo o una radice e barren

se non ha figli. Due place sono sibling se hanno lo stesso padre. Un sito s di A e

attivo se ctrl(v) e attivo, ovvero se v > s; altrimenti s e passivo. Se s e attivo (risp.

passivo) in A, diciamo che A e attivo (risp. passivo) in s.

Quando si ha a che fare con molti place graph A,B, . . . invece di indicizzare

le loro parent map come prntA, prntB etc., troveremo piu comodo abusare della

notazione ed indicare la parent map di un place graph A con A. Il contesto consente

di prevenire ambiguita; per esempio in B ◦A stiamo parlando di place graph, mentre

in B(A(v)) stiamo parlando delle parent map. Quindi (B◦A)(v) indica la place map

del place graph (B ◦ A) applicata al nodo v. Si noti in particolare che (B ◦ A)(v) e

diverso da B(A(v)); infatti se v ∈ VA allora (B ◦ A)(v) e uguale a A(v) se questo e

un nodo, altrimenti e uguale a B(A(v)).

Definizione 4 (tensore). L’operazione di tensore ⊗ e definita nel seguente modo:

dati due place graph Ai : mi → ni(i = 0, 1) sia A0 ⊗ A1 : m0 + m1 → n0 + n1

definito quando A0 ed A1 hanno insiemi di nodi disgiunti; per la parent map prima

riordinano siti e radici di A1 aggiungendogli m0 e n0 rispettivamente, poi si uniscono

le parent map.

L’operazione di tensore e parziale in quanto e definita quando A0 ed A1 hanno

insiemi di nodi disgiunti, quindi l’insieme dei nodi risultante e V0 ] V1. Intuitiva-

mente l’operazione di tensore su due place graph non fa altro che affiancarli. Queste

operazioni danno luogo ad una precategoria monoidale con supporto; per i dettagli

(pre)categoriali, si veda [8].

2.2 Directed link graph

In questa sezione si presentano i directed link graph come definiti in [4], con le loro

proprieta.

2.2.1 Definizioni

Sia K un insieme di signature di controlli dati.

Definizione 5. Un’interfaccia polarizzata X e una coppia di insiemi disgiunti di

nomi X = (X−, X+); le due componenti sono chiamate faces verso il basso e verso

2.2. DIRECTED LINK GRAPH 9

x y z

w

e

v0 v1

A : ({w}, ∅)→ ({x, y, z}, ∅)x y z

w

e

v0v1

B : (∅, {x, y, z})→ (∅, {w})x y

zw

e

C : (∅, {x, y})→ (∅, {w, z})

Figura 2.1: Esempi di directed link graph

l’alto rispettivamente. Un directed link graph A : X → Y e A = (V,E, ctrl, link)

dove X ed Y sono l’interfaccia interna ed esterna, V e l’insieme dei nodi, E e

l’insieme degli archi, ctrl : V → K e la mappa dei controlli, e link : Pnt→ Lnk e la

mappa dei link, dove le porte, i punti e i link di A sono definiti come segue.

Prt(A) ,∑v∈V

ar(ctrl(v)) Pnt(A) , X+ ] Y − ] Prt(A) Lnk(A) , X− ] Y + ] E

La mappa dei link non puo connettere nomi verso il basso e verso l’alto della stes-

sa interfaccia, la seguente condizione deve essere rispettata: (link(X+) ∩ X−) ∪(link(Y −) ∩ Y +) = ∅.

I directed link graph sono rappresentati graficamente come grafi ordinari, con

la differenza che gli archi sono rappresentati esplicitamente come vertici del grafo,

e non come iper-archi che connettono punti e nomi; i punti e i nomi sono associati

agli archi (o altri nomi) con archi semplici diretti.

Questa notazione mira a rendere chiaro il “flusso delle richieste delle risorse”:

porte e nomi nelle interfacce possono essere associati a risorse interne o esterne. Nel

primo caso porte e nomi sono connessi ad un arco; questi nomi sono detti “verso

l’interno” perche dichiarano al contesto come ottenere risorse interne. Nel secondo

caso, le porte e i nomi sono connessi ad un nome verso l’esterno, che aspetta di

essere mappato dal contesto in una risorsa.

D’ora in poi quando si parlera di “interfaccia” o “link graph” si intendera “in-

terfaccia polarizzata” e “directed link graph” salvo dove indicato diversamente.

Definizione 6 (composizione di link graph). Dati due link graph Ai = (Vi, Ei, ctrli, linki) :

Xi → Xi+1(i = 0, 1), la composizione A1◦A0 : X0 → X2 e definita quando i due link

graph hanno archi e nodi disgiunti. In questo caso A1 ◦A0 = (V,E, ctrl, link), dove

10 CAPITOLO 2. BIGRAFI DIRETTI

V , V0]V1, ctrl , ctrl0]ctrl1, E , E0]E1 e link : X+0 ]X

−2 ]P → E]X−0 ]X

+2

e definita come segue (dove P = Prt(A0) ] Prt(A1)):

link(p) ,

link0(p) se p ∈ X+

0 ] Prt(A0) e link0(p) ∈ E0 ]X−0link1(x) se p ∈ X+

0 ] Prt(A0) e link0(p) = x ∈ X+1

link1(p) se p ∈ X−2 ] Prt(A1) e link1(p) ∈ E1 ]X+2

link0(x) se p ∈ X−2 ] Prt(A1) e link1(p) = x ∈ X−1

Il link graph identita di X e idX , (∅, ∅, ∅K, IdX−]X+) : X → X.

E facile controllare che la composizione e associativa, e che dato un link graph

A : X → Y , la composizione A ◦ idX e idY ◦ A sono definite e uguali ad A. La

definizione di link graph proibisce connessioni tra nomi della stessa interfaccia per

impedire mappe di link indefinite dopo una composizione.

Definizione 7 (Supporto). Il supporto di un link graph A = (V,E, ctrl, link) : X →Y e l’insieme |A| = V ⊕ E.

Definizione 8 (idle, lean, aperto, chiuso, peer). Sia A : X → Y un link graph.

Un link l ∈ Lnk(A) e idle se non appartiene all’immagine della mappa dei link

(l /∈ link(Pnt(A))). Il link graph A e lean se non ci sono link idle.

Un link l e aperto se e un nome interno verso il basso o un nome esterno verso

l’alto (l ∈ X− ∪ Y +); e chiuso se e un arco.

Un punto p e aperto se link(p) e un link aperto, altrimenti e chiuso. Due punti

p1, p2 sono peer se sono mappati allo stesso link, quindi link(p1) = link(p2).

Definizione 9 (Tensore tra link graph). Date due interfacce X, Y se queste so-

no disgiunte allora X ⊗ Y , (X− ] Y −, X+ ] Y +). Dati due link graph Ai =

(Vi, Ei, ctrli, linki) : Xi → Yi(i = 0, 1), se il tensore sulle interfacce e definito e gli

insiemi dei nodi e degli archi sono disgiunti il tensore A0⊗A1 : X0⊗X1 → Y0⊗ Y1

e definito come A0 ⊗A1 , (V0 ] V1, E0 ] E1, ctrl0 ] ctrl1, link0 ] link1).

2.3 Bigrafi diretti

Possiamo ora definire i bigrafi diretti come composizione di place graph e directed

link graph.

Definizione 10 (Interfaccia). Un’interfaccia e composta da un’ampiezza (finita or-

dinale) e da una coppia di insiemi finiti di nomi. Siano I = 〈m,X〉 e J =

〈n, Y 〉 due interfacce. Un bigrafo diretto G con signature K da I in J e G =

2.3. BIGRAFI DIRETTI 11

(V,E, ctrl, prnt, link) : I → J , dove I e J sono le interfacce interna ed esterna ri-

spettivamente, e prnt, ctrl, link sono le mappe dei parent, dei controlli e dei link, in

modo che GP , (V, ctrl, prnt) : m→ n sia un place graph e GL , (V,E, ctrl, link) :

X → Y sia un directed link graph.

Indicheremo G come combinazione di GP e GL con G = 〈GP , GL〉. In questa

notazione un place graph e un directed link graph possono essere messi insieme se e

solo se hanno lo stesso insieme di nodi.

Definizione 11 (Composizione di bigrafi diretti). Siano G : I → J e H : J → K

due bigrafi diretti, con gli insiemi di nodi e archi disgiunti, allora la loro composizione

e definita come composizione delle componenti:

H ◦G , 〈HP ◦GP , HL ◦GL〉 : I → K

Il bigrafo diretto identita di I = 〈m,X〉 e 〈idm, IdX−]X+〉 : I → J .

Definizione 12 (Tensore su bigrafi diretti). Siano I = 〈m,X〉 e J = 〈n, Y 〉 con X

ed Y disgiunti, allora 〈m,X〉⊗〈n, Y 〉 , 〈m+n, (X−]Y −, X+]Y +)〉. Il tensore di

due bigrafi diretti Gi : Ii → Ji e definito quando il tensore sulle interfacce e definito

e gli insiemi di nodi ed archi dei due bigrafi sono disgiunti, allora:

G0 ⊗G1 , 〈GP0 ⊗GP1 , GL0 ⊗GL1 〉 : I0 ⊗ I1 → J0 ⊗ J1

2.3.1 Algebra

Si introduce ora l’algebra dei bigrafi diretti, per maggiori informazioni si consulti

[3].

Introduciamo alcune notazioni.

Notazione

Un’interfaccia 〈0, (X−, X+)〉 si abbrevia con (X−, X+); un insieme singoletto {x}con x; e 〈m, (∅, ∅)〉 con m. Le interfacce (∅, ∅) e 0 indicano la stessa interfaccia,

l’origine ε. Qundi l’identita idε puo essere espressa con ε, (∅, ∅) oppure 0.

Un bigrafo A : (∅, X+) → (∅, Y +) e definito da una (non necessariamente su-

riettiva) funzione σ : X+ → Y +, chiamata substitution, se non ha nodi e archi e

la mappa dei link e σ; analogamente un bigrafo A : (X−, ∅) → (Y −, ∅) e definito

da una (non necessariamente suriettiva) funzione δ : Y − → X−, chiamata fusion,

12 CAPITOLO 2. BIGRAFI DIRETTI

se non ha ne nodi ne archi e la mappa dei link e δ. Abusando della notazione scri-

veremo σ e δ per indicare i rispettivi bigrafi. Siano ~x, ~y due vettori della stessa

lunghezza; scriveremo (y0/x0, y1/x1, . . . ) o M~y~x dove tutti gli xi sono distinti, per la

mappa suriettiva xi 7→ yi; similmente scriveremo (y0/x0, y1/x1, . . . ) o O~y~x dove tutti

gli yi sono distinti, par la mappa suriettiva yi 7→ xi.

Indichiamo con MX : (∅, ∅) → (∅, X) il bigrafo definito dalla substitution vuota

σ : ∅ → X, allo stesso modo indichiamo con OX : (X, ∅) → (∅, ∅) il bigrafo definito

dalla fusion vuota δ : ∅ → X.

Si noti che ogni substitution σ puo essere espressa unicamente come σ = τ ⊗MX , dove τ e una substitution suriettiva; invece ogni fusion δ puo essere espressa

unicamente come δ = ζ ⊗OX , dove ζ e una fusion suriettiva. Indiceremo le rename

con α, ovvero le substitution biiettive e le fusion biiettive.

Introduciamo quindi i bigrafi closure. La closure HNxy : (∅, y)→ (x, ∅) non ha nodi,

un unico arco e la mappa dei link e link(x) = e = link(y). Altri due tipi di closure

si ottengono combinando la closure HNxy e Mx oppure Oy rispettivamente:

• La up-closure Ny : (∅, y)→ (∅, ∅) non ha nodi, ha un arco e link(y) = e;

• La down-closure Hx : (∅, ∅)→ (x, ∅) non ha nodi, ha un arco e link(x) = e;

Definizione 13 (wiring). Un wiring e un bigrafo le cui interfacce hanno ampiezza

0 (quindi non ha nodi). I wiring ω sono generati dalla composizione e tensore di tre

elementi base: substitutions σ : (∅, X+) → (∅, Y +), fusions δ : (Y −, ∅) → (X−, ∅) e

closures HNxy : (∅, y)→ (x, ∅).

Definizione 14 (Bigrafo primo). Un’interfaccia e prima se ha ampiezza uguale

ad 1. Spesso si abbrevia un’interfaccia prima 〈1, (X−, X+)〉 con 〈(X−, X+)〉, in

particolare 〈(∅, ∅)〉 = 1. Un bigrafo primo P : 〈m, (Y −, ∅)〉 → 〈(∅, X+)〉 non ha

nomi interni verso l’alto e non ha nomi esterni verso il basso, ad ha una interfacia

esterna prima.

Un importante bigrafo primo e mergem : m→ 1, non ha nodi e mappa m siti in un’u-

nica radice. Un bigrafo G : n→ 〈m, (X−, X+)〉 senza nomi nell’interfaccia interna,

puo essere convertito in un bigrafo primo come segue: (mergem ⊗ id(X−,X+)) ◦G.

Definizione 15 (Bigrafo discreto). Un bigrafo D e discreto se non ha archi e la

sua mappa dei link e una biiezione. Questo vuol dire che tutti i punti sono aperti,

nessuna coppia di punti e peer e nessun link e idle.

2.3. BIGRAFI DIRETTI 13

Il tensore e la composizione generano bigrafi discreti se gli argomenti sono di-

screti.

Definizione 16 (ion). Per ogni controllo non atomico K con arieta k e una coppia

di sequenze ~x− e ~x+ di nomi distinti, la cui lunghezza complessiva e k, definiamo il

discrete ion K(v)~x+

~x− : 〈(~x−, ∅)〉 → 〈(∅, ~x+)〉 come il bigrafo con un unico K-nodo v,

le cui porte sono separatamente mappate su ~x− oppure su ~x+. Si omettera v quando

si potra capire.

Uno ion arbitrario (non discreto) e formato dalla composizione di ω⊗id1 con uno

discreto. Spesso si omettera . . .⊗ idI nelle composizioni quando non c’e ambiguita.

Per esempio si scrivera mergem◦G intendendo (mergem⊗id(X−,X+))◦G e K(v)~x+

~x−◦Pintendendo (K(v)~x

+

~x− ⊗ id(Y −,Y +)) ◦ P .

Ora definiamo qualche variante del tensore che permette la condivisione dei nomi.

Nei bigrafi diretti la condivisione puo riguardare i nomi dell’interfaccia interna verso

il basso o i nomi dell’interfaccia esterna verso l’alto, come descritto dalle definizioni

che seguono.

Definizione 17 (Sharing products). L’outer sharing product, inner sharing product,

e lo sharing product di due link graph Ai : Xi → Yii = (0, 1) sono definiti come segue:

(X−, X+) (Y −, Y +) , (X− ] Y −, X+ ∪ Y −)

(X−, X+) � (Y −, Y +) , (X− ∪ Y −, X+ ] Y −)

A0 A1 , (V0 ] V1, E0 ] E1, ctrl0 ] ctrl1, link0 ] link1) : X0 ⊗X1 → Y0 Y1

A0 �A1 , (V0 ] V1, E0 ] E1, ctrl0 ] ctrl1, link0 ] link1) : X0 �X1 → Y0 ⊗ Y1

A0 ‖ A1 , (V0 ] V1, E0 ] E1, ctrl0 ] ctrl1, link0 ] link1) : X0 �X1 → Y0 Y1

definiti quando le loro interfacce sono definite e Ai hanno insiemi di nodi e archi

disgiunti.

L’outer sharing product, inner sharing product, e lo sharing product di due bigrafi

Gi : Ii → Ji sono definiti estendendo le rispettive operazioni sui link graph con il

tensore sull’ampiezza dei place graph.

〈m,X〉 〈n, Y 〉 , 〈n+m,X Y 〉 〈m,X〉 � 〈n, Y 〉 , 〈n+m,X � Y 〉

14 CAPITOLO 2. BIGRAFI DIRETTI

G0 G1 , 〈GP0 ⊗GP1 , GL0 GL1 〉 : I0 ⊗ I1 → J0 J1

G0 �G1 , 〈GP0 ⊗GP1 , GL0 �GL1 〉 : I0 � I1 → J0 ⊗ J1

G0 ‖ G1 , 〈GP0 ⊗GP1 , GL0 ‖ GL1 〉 : I0 � I1 → J0 J1

definiti quando le loro interfacce sono definite e Gi hanno insiemi di nodi ed archi

disgiunti.

E facile verificare che , �, ‖ sono associative con l’unita ε. Un altro modo per

costruire gli sharing product di due bigrafi G0, G1 e di dividere i nomi di G0 e G1,

quindi fare il tensore dei bigrafi e poi riunire i nomi:

Definizione 18. Siano G0 e G1 bigrafi con nodi e archi disgiunti, allora:

G0 G1 = σ(G0 ⊗ τG1ζ) G0 G1 = (G0 ⊗ τG1ζ)δ G0 G1 = σ(G0 ⊗ τG1ζ)δ

dove le substitutions σ e τ sono definite nel seguente modo: se zi(i ∈ n) sono i nomi

dell’interfaccia esterna verso l’alto condivisi da G0 eG1, e wi sono nomi nuovi in

biiezione con i zi , allora τ(zi) = wi e σ(wi) = σ(zi) = zi(i ∈ n). Le fusions δ e ζ

sono definite similmente ma sui nomi verso il basso dell’interfaccia interna.

Definizione 19 (Prime products). Il prime outer sharing product e prime sharing

product sono definiti come segue:

〈m, (X−, X+)〉 & 〈n, (Y −, Y +)〉 , 〈(X− ] Y −, X+ ∪ Y +)〉

G0 & G1 , merge(width(J0)+width(J1)) ◦ (G0 G1) : I0 ⊗ I1 → J0 & J1

G0 | G1 , merge(width(J0)+width(J1)) ◦ (G0 ‖ G1) : I0 � I1 → J0 & J1

definiti quando le loro interfacce sono definite e Gi ha nodi ed archi disgiunti.

E facile dimostrare che & e | sono associativi, con l’unita 1 quando applicati a

bigrafi primi. Si noti che per un wiring ω e un bigrafo primo P , si ha ω & P = ωP e

ω | P = ω ‖ P , in quanto in questo caso queste operazioni hanno lo stesso significato.

Teorema 1 (Forma normale discreta). Ogni bigrafo G puo essere espresso unica-

mente come G = (ω ⊗ idn) ◦ D ◦ (ω′ ⊗ idm), dove D e un bigrafo discreto e ω, ω

sono due wiring che soddisfano le seguenti condizioni:

• in ω, se due nomi dell’interfaccia esterna verso il basso sono peer, allora

puntano ad un arco;

2.3. BIGRAFI DIRETTI 15

• in ω′

non ci sono archi, e nessuna coppia di nomi dell’interfaccia interna

verso l’alto sono peer, (sui nomi dell’interfaccia interna verso l’alto ω′

e una

rinomina, pero i nomi dell’interfaccia esterna verso il basso possono essere

peer).

Ogni bigrafo discreto D : 〈m, (X−, X+)〉 → 〈n, (Y −, Y +)〉 puo essere fattorizzato

in modo unico sul dominio di ogni fattore Di, come:

D = α⊗ ((D0 ⊗ . . .⊗Dn−1) ◦ (π ⊗ iddom( ~D)))

con α una rinomina, ogni Di primo e discreto, e π una permutazione.

Dimostrazione Per la prima parte, si consideri un bigrafo G : 〈n, (X−, X+)〉 →〈m, (Y −, Y +)〉. Si divide G in tre parti: un bigrafo discreto D : 〈n, (Z−, Z+)〉 →〈m, (W−,W+)〉 e due wiring ω : (W−,W+) → (Y −, Y +) e ω

′: (X−, X+) →

(Z−, Z+) che soddisfano le seguenti condizioni. Si procede per casi:

p ∈ P , linkG(p) = e ∈ E : si aggiunge un nuovo nomi we ∈ W+ e si definisce

linkD(p) = we e linkw(we) = e;

p ∈ P , linkG(p) = y ∈ Y + : si aggiunge un nuovo nomi wy ∈ W+ e si definisce

linkD(p) = wy e linkw(wy) = y;

p ∈ P , linkG(p) = x ∈ X− : questo caso e analogo al precedente;

y ∈ Y −, linkG(y) = e ∈ E : si definisce linkw(y) = e;

x ∈ X+, linkG(x) = e ∈ E : aggiungiamo un nome nuovo ze ∈ Z+, un nuovo nome

zx ∈ Z− e si definisce linkω′ (x) = ze, linkD(ze) = we, linkω(we) = e;

y ∈ Y −, linkG(y) = x ∈ X− : aggiungiamo un nome nuovo wx ∈ W−, un nuovo

nome zx ∈ Z− e si definisce linkω(y) = wx, linkD(wx) = zx, linkω′ (zx) = x;

x ∈ X+, linkg(x) = y ∈ Y + : questo caso e analogo al precedente, e sufficiente

invertire la direzione dei link e scambiare la regola di ω con ω′.

Si noti che non ci sono nomi idle in Z−, Z+, W− e W+, quindi questi insiemi sono

formati solo da nomi nuovi definiti durante la dimostrazione. Inoltre le tre condizioni

sopra sono valide in quando creiamo un nuovo nome ogni volta che serve.

La dimostrazione della seconda parte e facile. Siccome l’interfaccia esterna di

D ha ampiezza n, possiamo decomporre D in n parti discrete e prime, ottenendo

16 CAPITOLO 2. BIGRAFI DIRETTI

D0 ⊗ . . . ⊗Dn−1. La rinomina α descrive le connessioni tra l’interfaccia interna ed

esterna. Quindi la permutazione π da la giusta sequenza dei siti, in modo da poter

eseguire il tensore di Di (i = 0, . . . , n − 1) in qualsiasi ordine. Chiameremo questa

fattorizzazione forma normale discreta (DNF).

2.3.2 Bigrafi elementari

Si introducono ora i bigrafi elementari, in grado di definire qualsiasi bigrafo in forma

normale discreta.

y

x

HNxy : (∅, y)→ (x, ∅)

closure

y

x1 x2 . . . xn

. . .

MyX : (∅, X)→ (∅, y)

substitution

x

y1 y2 . . . ym

. . .

OYx : (x, ∅)→ (Y, ∅)

fusion

Figura 2.2: Bigrafi che formano i wiring

I primi tre bigrafi, costruiscono tutti i wiring, ovvero tutti i link graph che non

hanno nodi. Tutte le substitutions (fusions risp.) possono essere ottenute con tensori

di substitutions elementari MyX (fusions OY

x risp.); dal tensore si una substitution sin-

goletto Myx e/o fusion singoletto Ox

y si ottengono tutte le rename. Dalla composizione

e il tensore di substitutions, fusions e closures si ottengono tutti i wiring.

1 : ε→ 1barren root

0 1

merge : 2→ 1fonde 2 siti in 1 radice

1 0

γ1,1 : 2→ 2scambia 2 siti

Figura 2.3: Bigrafi che formano tutti i place graph senza nodi

I tre bigrafi della figura 2.3 definiscono tutti i place graph senza nodi; per esempio

mergem : m→ 1, che fonde m siti in un’unica radice, e definito come:

merge0 , 1 mergem+1 , merge ◦ (id1 ⊗megem)

Si noti che merge1 = id e merge2 = merge, e che tutte le permutazioni π : m→ m

sono costruite con composizioni e tensori di γm,n. L’ultimo tipo di bigrafo che serve

2.3. BIGRAFI DIRETTI 17

x−1 x−2. . . x−j . . . x−k−1x

−k

x+1 x

+2. . . x+

j. . . x+

n−1x+n

. . .

. . .

. . .

. . .

K(l) : 〈(~x−, ~Y +)〉 → 〈(~Y −, ~x+)〉un discrete ion

Figura 2.4: Un discrete ion

per esprimere un qualsiasi bigrafo e il discrete ion K~x+

~x− (fig. 2.4).

Ogni bigrafo puo essere espresso in forma normale discreta quindi ogni bigrafo

puo essere espresso come composizione e tensore di questi bigrafi elementari.

18 CAPITOLO 2. BIGRAFI DIRETTI

3Implementazione dei bigrafi diretti

In questo capitolo sara presentata l’implementazione di signatures e bigrafi descri-

vendo la struttura dati e le operazioni piu importanti, successivamente saranno

descritti i bigrafi elementari, la forma normale e l’uguaglianza tra bigrafi.

D’ora in poi quando si parlera di “interfaccia”, “link graph” e “bigrafo” si inten-

dera “interfaccia polarizzata”, “directed link graph” e “bigrafo diretto” salvo dove

indicato diversamente.

3.1 Linguaggio utilizzato

Il linguaggio scelto per l’implementazione e l’Objective Caml (OCaml)1, un’esten-

sione ad oggetti del linguaggio Caml che e a sua volta un dialetto delle famiglia di

linguaggi di programmazione ML.

OCaml e un progetto open source gestito e sviluppato principalmente dall’INRIA

ovvero l’istituto nazionale per la ricerca nell’informatica e nell’automazione che fa

parte dell’istituto nazionale francese per la ricerca. Esso e stato sviluppato per essere

veloce, efficiente e richiedere poca memoria.

Essendo open source inoltre fa si che sia disponibile sulle piu comuni piattaforme

software e hardware.

Le caratteristiche che interessavano per la scrittura del codice sono:

Funzionale Le funzioni possono essere annidate e passate come parametri.

Inferenza dei tipi I tipi dei valori sono automaticamente inferiti non devono essere

specificati.

Polimorfismo Nei casi dove diversi tipi possono essere validi, ognuno puo essere

usato.1Si veda: http://caml.inria.fr/

20 CAPITOLO 3. IMPLEMENTAZIONE DEI BIGRAFI DIRETTI

Pattern Matching Valori, ed in particolare i contenuti di strutture dati, possono

essere confrontati con pattern per determinare l’azione adeguata.

Oggetti C’e la possibilita di definire oggetti.

Garbage collector I valori che non vengono usati sono automaticamente deallo-

cati.

3.2 Struttura dati

3.2.1 Insieme delle signature

Una struttura ausiliaria quella del bigrafo e l’insieme delle signature. La struttura

dati utilizzata per implementarla e quella del modulo Set che fa parte della libreria

standard di OCaml, questa struttura dati implementa la gestione di un insieme su

un tipo ordinato.

E stato creato un tipo Signature per descrivere gli elementi dell’insieme, il tipo e

formato da elementi (signature, (attivita, arieta)) dove signature e di tipo stringa,

attivita e di tipo stringa ed arieta e un intero. Successivamente e stata definita la

funzione compare su questo tipo per definire un ordine, questa confronta solo il primo

elemento della coppia in modo da non permettere che ci siano due signature uguali

con arieta o attivita diversa.

module S ignature =s t r u c t

type t = s t r i n g ∗ ( s t r i n g ∗ i n t )l et compare ( s ig1 , ( t1 , n1 ) ) ( s ig2 , ( t2 , n2 ) ) =

i f s i g 1 < s i g 2 then − 1else i f s i g 1 > s i g 2 then 1else 0

end ; ;

La definizione del modulo che implementa l’insieme e :

module S ignatureSet = Set . Make( S ignature ) ; ;

Per rendere piu usabile questa struttura dati e stata creata una classe con dei

metodi per l’inserimento, rimozione e i metodi per ottenere l’arieta o l’attivita a

partire dalla signature.

3.2.2 Classe directedbg

La struttura dati che rappresenta una bigrafo e stata implementante come una classe.

La classe ha in seguenti attributi:

3.2. STRUTTURA DATI 21

v Insieme dei nodi del bigrafo.

e Insieme degli archi del bigrafo.

prnt Lista che descrive il place graph.

link Lista dei link del bigrafo.

ctrl Lista dei controlli.

innerint Interfaccia interna.

outerint Interfaccia esterna.

Per rappresentare gli elementi degli insiemi e stato costruito un tipo formato

da una coppia di stringhe (elemento,tipo) dove elemento e la stringa che identifi-

ca un nome, nodo, arco etc. . . mentre tipo e una stringa che identifica la classe

dell’elemento, puo essere uno dei seguenti:

“v” Rappresenta un nodo.

“e” Rappresenta un arco.

“inm” Rappresenta un nome dell’interfaccia interna verso il basso.

“inp” Rappresenta un nome dell’interfaccia interna verso l’alto.

“onm” Rappresenta un nome dell’interfaccia esterna verso il basso.

“onp” Rappresenta un nome dell’interfaccia esterna verso l’alto.

La definizione del tipo e la seguente:

module S t r i ng E l t =s t r u c t

type t = s t r i n g ∗ s t r i n gl et compare ( e l t 1 , t1 ) ( e l t 2 , t2 ) =

i f e l t 1 < e l t 2 then − 1else i f e l t 1 > e l t 2 then 1else 0

end ; ;

Si noti che il tipo non conta ai fini dell’ordinamento. Segue la definizione del modulo:

module S t r ingSe t = Set . Make( S t r i n gE l t ) ; ;

Seguono i dettagli sull’implementazione delle singole componenti.

22 CAPITOLO 3. IMPLEMENTAZIONE DEI BIGRAFI DIRETTI

3.2.2.1 Insieme dei nodi

L’insieme dei nodi e un attributo della classe di tipo StringSet.

La gestione dell’inserimento dei nodi richiede due operazioni sulla struttura dati,

l’inserimento del nodo con il tipo “v” nell’insieme e l’aggiunta alla lista ctrl del

nome del nodo e della sua arieta. Per permettere questo al metodo che effettua

l’inserimento del nodo va passato anche la sua signature e la classe delle signature.

method addnode : s t r i n g −> s t r i n g −> Bigraph . s i g n a t u r e s −>uni t

E presente un’altro metodo per l’inserimento dei nodi che non richiede la classe delle

signature ma viene passata direttamente la sua arieta.

method addnodear : s t r i n g −> i n t −> uni t

3.2.2.2 Insieme degli archi

L’inserimento degli archi richiede solo l’aggiunta dell’elemento all’insieme e. Il tipo

“e” viene aggiunto automaticamente.

method addedge : s t r i n g −> uni t

3.2.2.3 Place graph

Gli elementi del place graph sono radici, nodi e siti. Si e scelto di rappresentare siti

e radici tramite interi mentre i nodi con stringhe.

L’intera struttura del place graph e stata implementata con una lista di elementi

del tipo (figlio,padre). L’inserimento di una coppia si esegue semplicemente aggiun-

gendola alla fine della lista. Per realizzare questo si e sfruttato il polimorfismo sui

dati che permette OCaml come si nota dalla definizione del tipo della lista:

type t p l a c e = SiteNode of i n t ∗ s t r i n g| SiteRoot of i n t ∗ i n t| NodeRoot of s t r i n g ∗ i n t| NodeNode of s t r i n g ∗ s t r i n g ; ;

Il tipo della lista e tplace e le possibili combinazioni sono:

- Sito figlio di un nodo.

- Sito figlio di una radice.

- Nodo figlio di una radice.

- Nodo figlio di un nodo.

3.2. STRUTTURA DATI 23

Visto i tipi diversi dei dati, per ogni diversa combinazione e presente un metodo:

method addprnts i tenode : i n t −> s t r i n g −> uni tmethod a ddprn t s i t e r oo t : i n t −> i n t −> uni tmethod addprntnoderoot : s t r i n g −> i n t −> uni tmethod addprntnodenode : s t r i n g −> s t r i n g −> uni t

Quando si chiamano i metodi viene controllato che i nodi esistano e il numero che

identifica la radice sia minore del numero totale di radici.

3.2.2.4 Link graph

La struttura del link graph e stata resa tramite una lista che contiene delle coppie

del tipo (sorgente,destinazione).

Un link puo partire da due tipi di elementi: una porta oppure un nome. La porta

e rappresentata tramite un intero mente i nomi sono rappresentati con stringhe. Sono

stati creati quindi due diversi tipi per la sorgente :

type tpo in t = Port of ( i n t ∗ s t r i n g )| Name of s t r i n g ∗ s t r i n g ; ;

Il tipo Port per rappresentare la porta usa una coppia (numero porta, nodo) mentre

il tipo Name e formato dalla coppia (nome, tipo) dove il tipo indica l’interfaccia a

cui appartiene.

La destinazione di un link puo essere un arco oppure un nome, entrambi sono

rappresentati da stringhe quindi il tipo e comune:

type t l i n k = NameEdge of s t r i n g ∗ s t r i n g ; ;

Il primo elemento della coppia rappresenta la destinazione mentre la seconda parte

rappresenta il tipo “e”’ se e un arco, il tipo associato all’interfaccia a cui appartiene

se e un nome.

Visto che ci sono due tipi per la sorgente del link vi sono due metodi per inserirli,

uno per i link che partono da una porta e uno per i link che partono da nomi:

method addl inkfromport : i n t −> s t r i n g −> s t r i n g −>s t r i n g −> uni t

method addlinkfromname : s t r i n g −> s t r i n g −> s t r i n g −>s t r i n g −> uni t

Quando si inseriscono i link viene controllato che la sorgente e la destinazione

esistano e che sia un link tra quelli permessi, essi sono:

- Da una porta ad un arco.

- Da una porta ad un nome verso il basso dell’interfaccia interna.

24 CAPITOLO 3. IMPLEMENTAZIONE DEI BIGRAFI DIRETTI

- Da una porta ad un nome verso l’alto dell’interfaccia esterna.

- Da un nome dell’interfaccia interna verso l’alto ad un arco.

- Da un nome dell’interfaccia interna verso l’alto ad un nome dell’interfaccia

esterna verso l’alto.

- Da un nome dell’interfaccia esterna verso il basso ad un arco.

- Da un nome dell’interfaccia esterna verso il basso ad un nome dell’interfaccia

interna verso il basso.

Controllando il tipo passato insieme agli elementi e possibile controllare che il link

sia fra quelli elencati.

3.2.2.5 Lista dei controlli

La lista dei controlli e implementata come una lista di elementi del tipo (nodo,arieta)

dove nodo e la stringa che identifica il nodo e arieta e un intero che rappresenta la

sua arieta. Vi sono due metodi per l’inserimento:

method addc t r l : s t r i n g −> s t r i n g −> Bigraph . s i g n a t u r e s −> uni tmethod a d d c t r l a r : s t r i n g −> i n t −> uni t

tutti e due necessitano del nome del nodo ma il primo prende in ingresso la sua

signature e la classe delle signature, mentre il secondo accetta direttamente l’arieta

del nodo.

Questi sono i metodi usati dalle funzioni che aggiungono i nodi al bigrafo.

3.2.2.6 Interfaccia interna

La struttura scelta per rappresentare l’interfaccia e la coppia (numero siti, (nomi

verso il basso, nomi verso l’alto)) dove il primo elemento e un intero e il secondo e

una coppia di insiemi.

Risulta quindi cosı definita:

va l mutable i n n e r i n t : i n t ∗ ( S t r ingSe t . t ∗ St r ingSe t . t )

Sono presenti i metodi per definire il numero di siti ed aggiungere nomi nei due

insiemi dell’interfaccia:

method s e t i n n e r i n t n : i n t −> uni tmethod addxminus : s t r i n g −> uni tmethod addxplus : s t r i n g −> uni t

3.3. OPERAZIONI DI BASE 25

I metodi addxplus e addxminus aggiungono i nomi all’insieme dei nomi verso il basso

ed alto rispettivamente. Se il nome e verso il basso verra aggiunto il tipo “inm”,

“inp” per quelli verso l’alto.

3.2.2.7 Interfaccia esterna

L’interfaccia esterna e strutturata analogamente a quella interna, con la differenza

che l’intero rappresenta il numero di radici del bigrafo e non il numero di siti. I

metodi per impostare il numero di radici ed aggiungere i nomi sono:

method s e t o u t e r i n t n : i n t −> uni tmethod addyminus : s t r i n g −> uni tmethod addyplus : s t r i n g −> uni t

I tipi aggiunti per i nomi in questo caso sono “onm” per i nomi verso il basso, “onp”

per i nomi verso l’alto.

3.3 Operazioni di base

3.3.1 Tensore

L’operazione tensore (⊗) su due bigrafi puo essere eseguita solo se le loro compo-

nenti sono disgiunte, per controllare che questa condizione sussista e stato creato il

metodo aredisjoint che richiede un bigrafo come parametro. Questo metodo chiama

diversi metodi che controllano se le componenti rappresentate internamente e quelle

del bigrafo passato sono disgiunte, il risultato e di tipo booleano: true se tutte le

componenti sono disgiunte mentre false se non lo sono.

Se le componenti sono disgiunte si puo procedere con l’operazione di tensore, vie-

ne creato un nuovo bigrafo le cui componenti sono l’unione di quelle dei due bigrafi

su cui si esegue il tensore. Per le componenti che sono rappresentate tramite insiemi

(nodi, archi . . . ) il modulo StringSet dispone dell’operazione di unione insiemistica,

mentre per le componenti che sono rappresentate come liste si opera semplicemente

concatenandole. La lista prnt del bigrafo passato come parametro va pero modifi-

cata. Visto che le radici partono da 0 e necessario incrementarle con il numero di

radici del bigrafo rappresentato internamente. Per i siti invece prima si controlla

se i due bigrafi hanno siti in comune; se ci sono siti comuni tutti i siti del secondo

bigrafo sono incrementati del massimo sito del primo bigrafo piu uno, se no allora

non e necessario fare modifiche. In questo modo si evitano sovrapposizioni.

Quando si esegue il tensore il numero di radici del bigrafo che si genera e dato

dalla somma del numero delle radici dei due bigrafi, lo stesso vale per i siti.

26 CAPITOLO 3. IMPLEMENTAZIONE DEI BIGRAFI DIRETTI

Segue il codice del metodo:

method tenso r ( dbg : d i r e c t edbg ) =i f s e l f#a r e d i s j o i n t dbg thennew d i r e c t edbg ( S t r ingSe t . union dbg#getnodes v )

( S t r ingSe t . union dbg#getedges e )( ( s e l f#addn dbg#getprnt ) @ prnt )( dbg#g e t l i n k @link )( dbg#g e t c t r l @ c t r l )( dbg#g e t i n n e r i n t n + s e l f#ge t inne r in tn ,( S t r ingSe t . union dbg#getxminus s e l f#getxminus ,S t r i ngSe t . union dbg#getxp lus s e l f#getxp lus ) )( dbg#g e t o u t e r i n t n + s e l f#getoute r in tn ,( S t r ingSe t . union dbg#getyminus s e l f#getyminus ,S t r i ngSe t . union dbg#getyp lus s e l f#getyp lus ) )

elser a i s e B i g r a p h s a r e n o t d i s j o i n t

I metodi il cui nome comincia con “get” servono ad ottenere le varie componenti

del bigrafo.

Nel caso che i bigrafi non siano disgiunti viene sollevata un’eccezione del tipo

Bigraphs are not disjoint .

3.3.2 Composizione

Per poter eseguire l’operazione di composizione tra due bigrafi devono sussistere due

condizioni. La prima condizione richiede che gli insiemi dei loro nodi ed archi devono

essere disgiunti. La seconda richiede che le due interfacce che formano l’interfaccia

comune siano uguali. Nel caso A1 ◦A0 , per esempio, l’interfaccia interna di A1 deve

essere uguale all’interfaccia esterna di A0.

Vengono usati i metodi aredisjointv ed aredisjointe per controllare che gli in-

siemi dei nodi ed archi rispettivamente siano disgiunti, mentre sameinterface per

controllare che i bigrafi abbiano abbiano le due interfacce su cui opera la com-

posizione uguali. Se queste condizioni non sussistono viene sollevata l’eccezione

Bigraphs have no common interface.

Sia A1 ◦ A0 la composizione da eseguire, essa crea un nuovo bigrafo e le sue

componenti verranno costruite nel seguente modo :

3.3.2.1 Insieme dei nodi

L’insieme dei nodi e semplicemente l’unione dei due insiemi dei nodi di A1 ed A0

3.3. OPERAZIONI DI BASE 27

3.3.2.2 Insieme degli archi

Anche l’insieme degli archi e ottenuto con l’unione dei due insiemi degli archi di

A1 ed A0

3.3.2.3 Place graph

La composizione sul place graph opera mettendo le radici di A0 nei siti di A1. In

pratica nel nuovo bigrafo i figli di una radice di A0 avranno come padre il padre del

rispettivo sito di A1.

Vista l’implementazione tramite liste si puo dividere la composizione sul place

graph in due parti: trovare gli elementi “interni” , ovvero che non verranno modi-

ficati dalla composizione, di A1 e per ogni elemento di A0 che ha come padre una

radice creare un nuovo elemento che ha come padre il padre del rispettivo sito di

A1, lasciando invariati gli altri. Sono stati creati due metodi che svolgono queste

operazioni compositeprntint per trovare gli elementi “interni” di A1 ed compositeprnt

per l’unione di siti con radici. La lista prnt del nuovo bigrafo e la concatenazione

del risultato di questi due metodi.

3.3.2.4 Link graph

La composizione sul link graph cerca link che partono da un bigrafo e finiscono nel-

l’interfaccia comune, per ognuno di questi si cerca nell’altro bigrafo un link che parte

dallo stesso elemento dell’interfaccia comune. Se quest’elemento esiste si crea un link

che ha come sorgente la sorgente del primo e come destinazione la destinazione del

secondo.

Il lavoro della composizione e stato diviso in due fasi: una fase consiste nel cer-

care e mantenere i link “interni” ad ognuno dei bigrafi. I link interni sono quelli

che non hanno come destinazione o sorgente l’interfaccia condivisa e che quindi non

verranno modificati dalla composizione. La seconda fase consiste nel cercare i link

che attraversano l’interfaccia condivisa, ovvero quelli che partendo da un bigrafo ar-

rivano ad un nome dell’interfaccia condivisa. Per ognuno di questi si cerca nell’altro

bigrafo un link che parte da questo nome, se esiste si crea il link composto.

Ognuna delle fasi e stata implementata con un metodo: compositelinkint per

trovare i link interni e compositelink per la composizione dei link. La lista dei link

del nuovo bigrafo sara la concatenazione dei risultati dei due metodi per ognuno dei

due bigrafi.

28 CAPITOLO 3. IMPLEMENTAZIONE DEI BIGRAFI DIRETTI

3.3.2.5 Lista dei controlli

Siccome il bigrafo risultante dalla composizione contiene i nodi di A1 ed A0 la lista

ctrl risultante sara la concatenazione delle liste dei due bigrafi.

3.3.2.6 Interfaccia interna

L’interfaccia interna del nuovo bigrafo sara uguale all’interfaccia interna di A0.

3.3.2.7 interfaccia esterna

L’interfaccia esterna del nuovo bigrafo sara uguale all’interfaccia esterna di A1.

3.3.2.8 Il metodo composition

Il metodo che esegue la composizione e composition , supponendo di disporre di due

istanze a1 ed a0 che rappresentano bigrafi la composizione A1 ◦ A0 viene eseguita

con a1#composition a0. Segue il codice del metodo:

method compos it ion ( dbg : d i r e c t edbg ) =i f ( s e l f#same in t e r f a c e dbg )

&(dbg#a r e d i s j o i n t v v )&(dbg#a r e d i s j o i n t e e )

thennew d i r e c t edbg ( S t r ingSe t . union dbg#getnodes v )

( S t r ingSe t . union dbg#getedges e )( ( s e l f#compositeprnt dbg#getprnt prnt )@( s e l f#compos i t eprnt int prnt ) )( ( s e l f#c o m p o s i t e l i n k i n t dbg#g e t l i n k ”inm” ” inp ” )@( s e l f#compos i t e l ink dbg#g e t l i n k l i n k ”onp” ” inp ” )@( s e l f#c o m p o s i t e l i n k i n t l i n k ”onp” ”onm” )@( s e l f#compos i t e l ink l i n k dbg#g e t l i n k ”inm” ”onm” ) )( dbg#g e t c t r l @ c t r l )( dbg#get inne r in tn , ( dbg#getxminus , dbg#getxp lus ) )( s e l f#getoute r in tn , ( s e l f#getyminus , s e l f#getyp lus ) )

elser a i s e Bigraphs have no common inter face

3.4 Operazioni derivate

Si procede a descrivere ora l’implementazione delle operazioni derivate ovvero sha-

ring products e prime products.

3.4. OPERAZIONI DERIVATE 29

3.4.1 Sharing products

Gli sharing products sono delle varianti del tensore che permettono la condivisione

dei nomi. La loro implementazione e molto simile a quella del tensore con la diffe-

renza che per gli insiemi dei nomi che andranno condivisi si esegue l’unione senza

controllare che essi siano disgiunti.

3.4.1.1 Outer sharing product

L’outer sharing product consente la condivisione dei nomi dell’interfaccia esterna

verso l’alto, non serve controllare che questi ultimi siano disgiunti nei due bigrafi

quindi. Il codice del metodo e il seguente:

method osp ( dbg : d i r e c t edbg ) =i f ( dbg#a r e d i s j o i n t v v )

& ( dbg#a r e d i s j o i n t e e )& ( dbg#ared i s j o i n txminus s e l f#getxminus )& ( dbg#a r e d i s j o i n t x p l u s s e l f#getxp lus )& ( dbg#ared i s j o i n tyminus s e l f#getyminus )

thennew d i r e c t edbg ( S t r ingSe t . union dbg#getnodes v )

( S t r ingSe t . union dbg#getedges e )( ( s e l f#addn dbg#getprnt ) @ prnt )( dbg#g e t l i n k @link )( dbg#g e t c t r l @ c t r l )( dbg#g e t i n n e r i n t n + s e l f#ge t inne r in tn ,( S t r ingSe t . union dbg#getxminus s e l f#getxminus ,

S t r i ngSe t . union dbg#getxp lus s e l f#getxp lus ) )( dbg#g e t o u t e r i n t n + s e l f#getoute r in tn ,( S t r ingSe t . union dbg#getyminus s e l f#getyminus ,

S t r i ngSe t . union dbg#getyp lus s e l f#getyp lus ) )else

r a i s e B i g r a p h s a r e n o t d i s j o i n t

3.4.1.2 Inner sharing product

L’inner sharing product consente la condivisione dei nomi dell’interfaccia interna

verso il basso, si omette il controllo su questi insiemi di nomi quindi. Il codice del

metodo e il seguente:

method i s p ( dbg : d i r e c t edbg ) =i f ( dbg#a r e d i s j o i n t v v )

& ( dbg#a r e d i s j o i n t e e )& ( dbg#a r e d i s j o i n t x p l u s s e l f#getxp lus )& ( dbg#ared i s j o i n tyminus s e l f#getyminus )& ( dbg#a r e d i s j o i n t y p l u s s e l f#getyp lus )

thennew d i r e c t edbg ( S t r ingSe t . union dbg#getnodes v )

30 CAPITOLO 3. IMPLEMENTAZIONE DEI BIGRAFI DIRETTI

( S t r ingSe t . union dbg#getedges e )( ( s e l f#addn dbg#getprnt ) @ prnt )( dbg#g e t l i n k @link )( dbg#g e t c t r l @ c t r l )( dbg#g e t i n n e r i n t n + s e l f#ge t inne r in tn ,( S t r ingSe t . union dbg#getxminus s e l f#getxminus ,

S t r i ngSe t . union dbg#getxp lus s e l f#getxp lus ) )( dbg#g e t o u t e r i n t n + s e l f#getoute r in tn ,( S t r ingSe t . union dbg#getyminus s e l f#getyminus ,S t r i ngSe t . union dbg#getyp lus s e l f#getyp lus ) )

elser a i s e B i g r a p h s a r e n o t d i s j o i n t

3.4.1.3 Sharing product

Lo sharing product consente la condivisione dei nomi dell’interfaccia interna verso il

basso e dei nomi dell’interfaccia esterna verso l’alto. I controlli da omettere quindi

sono gli stessi dell’outer sharing product e dell’inner sharing product. Il codice del

metodo e il seguente:

method sp ( dbg : d i r e c t edbg ) =i f ( dbg#a r e d i s j o i n t v v )

& ( dbg#a r e d i s j o i n t e e )& ( dbg#a r e d i s j o i n t x p l u s s e l f#getxp lus )& ( dbg#ared i s j o i n tyminus s e l f#getyminus )

thennew d i r e c t edbg ( S t r ingSe t . union dbg#getnodes v )

( S t r ingSe t . union dbg#getedges e )( ( s e l f#addn dbg#getprnt ) @ prnt )( dbg#g e t l i n k @link )( dbg#g e t c t r l @ c t r l )( dbg#g e t i n n e r i n t n + s e l f#ge t inne r in tn ,( S t r ingSe t . union dbg#getxminus s e l f#getxminus ,

S t r i ngSe t . union dbg#getxp lus s e l f#getxp lus ) )( dbg#g e t o u t e r i n t n + s e l f#getoute r in tn ,( S t r ingSe t . union dbg#getyminus s e l f#getyminus ,

S t r i ngSe t . union dbg#getyp lus s e l f#getyp lus ) )else

r a i s e B i g r a p h s a r e n o t d i s j o i n t

3.4.2 Prime sharing products

Le due operazioni in questo gruppo si comportano come l’outer sharing product e lo

sharing product con la differenza che il bigrafo risultante avra solo una radice. Tutti

le componenti del place graph sono resi figli di questa unica radice. Per fare questo le

liste prnt dei due bigrafi vanno analizzate e tutti gli elementi figli di una radice vanno

3.4. OPERAZIONI DERIVATE 31

resi figli della radice 0. Il numero dei siti del bigrafo passato come parametro invece

va modificato come nel tensore. il metodo che svolge quest’operazione e oneroot.

3.4.2.1 Prime outer sharing product

Operazione analoga all’outer sharing product ma tutti gli elementi del place graph

vengono resi figli della radice 0.

Segue il codice del metodo:

method posp ( dbg : d i r e c t edbg ) =i f ( dbg#a r e d i s j o i n t v v )

& ( dbg#a r e d i s j o i n t e e )& ( dbg#ared i s j o i n txminus s e l f#getxminus )& ( dbg#a r e d i s j o i n t x p l u s s e l f#getxp lus )& ( dbg#ared i s j o i n tyminus s e l f#getyminus )

thennew d i r e c t edbg ( S t r ingSe t . union dbg#getnodes v )

( S t r ingSe t . union dbg#getedges e )( ( s e l f#oneroot dbg#getprnt ) @ ( s e l f#oneroot1 prnt 0 ) )( dbg#g e t l i n k @link )( dbg#g e t c t r l @ c t r l )( dbg#g e t i n n e r i n t n + s e l f#ge t inne r in tn ,( S t r ingSe t . union dbg#getxminus s e l f#getxminus ,S t r i ngSe t . union dbg#getxp lus s e l f#getxp lus ) )(1 ,( S t r ingSe t . union dbg#getyminus s e l f#getyminus ,

S t r i ngSe t . union dbg#getyp lus s e l f#getyp lus ) )else

r a i s e B i g r a p h s a r e n o t d i s j o i n t

3.4.2.2 Prime sharing product

Operazione analoga allo sharing product ma tutti gli elementi del place graph

vengono resi figli della radice 0.

Segue il codice del metodo:

method psp ( dbg : d i r e c t edbg ) =i f ( dbg#a r e d i s j o i n t v v )

& ( dbg#a r e d i s j o i n t e e )& ( dbg#a r e d i s j o i n t x p l u s s e l f#getxp lus )& ( dbg#ared i s j o i n tyminus s e l f#getyminus )

thennew d i r e c t edbg ( S t r ingSe t . union dbg#getnodes v )

( S t r ingSe t . union dbg#getedges e )( ( s e l f#oneroot dbg#getprnt ) @ ( s e l f#oneroot1 prnt 0 ) )( dbg#g e t l i n k @link )( dbg#g e t c t r l @ c t r l )( dbg#g e t i n n e r i n t n + s e l f#ge t inne r in tn ,( S t r ingSe t . union dbg#getxminus s e l f#getxminus ,

32 CAPITOLO 3. IMPLEMENTAZIONE DEI BIGRAFI DIRETTI

St r ingSe t . union dbg#getxp lus s e l f#getxp lus ) )(1 ,( S t r ingSe t . union dbg#getyminus s e l f#getyminus ,

S t r i ngSe t . union dbg#getyp lus s e l f#getyp lus ) )else

r a i s e B i g r a p h s a r e n o t d i s j o i n t

3.5 Algebra

3.5.1 Bigrafi elementari

I bigrafi elementari possono essere creati con delle funzioni passando i parametri

necessari.

3.5.1.1 Swap

La funzione che crea il bigrafo swap prende in ingresso due parametri: m ed n. Il

bigrafo risultante ha m + n radici ed m + n siti. I primi m siti pero sono mappati

nelle ultime m radici mentre i seguenti n sono mappati nelle prime n radici.

La costruzione della lista prnt del bigrafo e eseguita dalla funzione swapaux:

l et rec swapaux m n i = i f ( i + 1) = (m + n) thenSiteRoot ( i , i − m) : : [ ]

else i f i < m thenSiteRoot ( i , i + n ) : : ( swapaux m n ( i + 1) )

elseSiteRoot ( i , i − m) : : ( swapaux m n ( i + 1 ) ) ; ;

Il codice della funzione che crea il bigrafo swap e il seguente:

l et swap m n = i f (m + n) = 0 thennew d i r e c t edbg St r ingSe t . empty St r ingSe t . empty [ ] [ ] [ ]

( 0 , ( S t r i ngSe t . empty , S t r ingSe t . empty ) )(0 , ( S t r i ngSe t . empty , S t r ingSe t . empty ) )

elsenew d i r e c t edbg St r ingSe t . empty St r ingSe t . empty( swapaux m n 0) [ ] [ ](m + n , ( S t r ingSe t . empty , S t r ingSe t . empty ) )

(m + n , ( S t r ingSe t . empty , S t r ingSe t . empty ) ) ; ;

Si nota che se m+ n = 0 la funzione ritorna un bigrafo vuoto.

3.5.1.2 Identita

La funzione che crea il bigrafo identita e la funzione id. Essa prende in ingresso il

numero di siti/radici da creare e le liste dei nomi dell’interfaccia inferiore verso l’alto

3.5. ALGEBRA 33

e quelli dell’interfaccia superiore verso l’alto. Sia n il numero di siti/radici e siano ~x

e ~y i nomi delle interfacce, interna ed esterna rispettivamente.

Viene usata la funzione swap per creare un bigrafo con n radici ognuna con un

sito come figlio. Usando 0 come valore del parametro m i siti non vengono scambiati

quindi il sito 0 avra come padre la radice 0 e cosı via. A questo bigrafo vengono

aggiunti i nomi alle interfacce e creati i link ~x → ~y tramite la funzione ausiliaria

idaux.

Il codice della funzione e:

l et id n lm lp = l et idbg = swap 0 n inidbg#addxminus l i s t lm ;idbg#addyminus l i s t lm ;idbg#a d d x p l u s l i s t lp ;idbg#a d d y p l u s l i s t lp ;idaux lm ”onm” ”inm” idbg ;idaux lp ” inp ” ”onp” idbg ;idbg ; ;

3.5.1.3 Closure

Il bigrafo closure e formato da due nomi ed un arco. Un nome appartiene all’inter-

faccia esterna verso il basso, mentre l’altro all’interfaccia interna verso l’alto, siano

essi y ed x rispettivamente. Sia e l’arco, vengono quindi creati i link x→ e ed y → e.

La funzione sfrutta la funzione id per creare un bigrafo vuoto, ovvero senza radici

e senza nomi.

Il codice della funzione e:

l et c l o s u r e x y e = l et c l = id 0 [ ] [ ] inc l#addedge e ;c l#addyminus y ;c l#addxplus x ;c l#addlinkfromname y ”onm” e ”e” ;c l#addlinkfromname x ” inp ” e ”e” ;c l ; ;

3.5.1.4 Up-closure

Variante del bigrafo closure con un’unico nome che appartiene all’interfaccia esterna

verso il basso. Sia esso y e sia e l’unico arco del bigrafo, viene creato il link y → e.

Il codice e il seguente:

l et upc lo sure y e = l et upcl = id 0 [ ] [ ] inupcl#addedge e ;upcl#addyminus y ;

34 CAPITOLO 3. IMPLEMENTAZIONE DEI BIGRAFI DIRETTI

upcl#addlinkfromname y ”onm” e ”e” ;upcl ; ;

3.5.1.5 Down-closure

Variante del bigrafo closure con un’unico nome che appartiene all’interfaccia interna

verso l’alto. Sia esso x e sia e l’unico arco del bigrafo, viene creato il link x→ e.

Il codice e il seguente:

l et downclosure x e = l et dwcl = id 0 [ ] [ ] indwcl#addedge e ;dwcl#addxplus x ;dwcl#addlinkfromname x ” inp ” e ”e” ;dwcl ; ;

3.5.1.6 Merge

Il bigrafo merge e formato da una radice con n siti al suo interno. Esso e creato dalla

funzione merge ed usa una funzione ausiliaria mergeaux che si occupa di aggiungere

n siti al bigrafo passato come parametro.

La funzione merge richiede come parametro il numero di siti da creare. Il suo

codice e il seguente:

l et merge n = i f n = 0 thennew d i r e c t edbg St r ingSe t . empty St r ingSe t . empty [ ] [ ] [ ]

( 0 , ( S t r i ngSe t . empty , S t r ingSe t . empty ) )(1 , ( S t r i ngSe t . empty , S t r ingSe t . empty ) )

elsemergeaux n (new d i r e c t edbg St r ingSe t . empty

St r ingSe t . empty [ ] [ ] [ ](n , ( S t r ingSe t . empty , S t r ingSe t . empty ) )(1 , ( S t r i ngSe t . empty , S t r ingSe t . empty ) ) ) ; ;

Si nota che se il parametro e 0 la funzione merge ritorna un bigrafo con una radice

ma nessun sito.

3.5.1.7 Barren root

Il bigrafo barren root e un bigrafo composto da una radice. La funzione che lo crea

e oneDB. Viene creato usando la funzione merge con 0 come parametro. Il codice e

il seguente:

l et oneDB = fun ( ) −> merge 0 ; ;

3.5. ALGEBRA 35

3.5.1.8 Substitution

Il bigrafo substitution contiene dei nomi nell’interfaccia interna verso l’alto, siano

essi ~x, ed un solo nome in quella esterna verso l’alto, sia esso y. I link presenti nel

bigrafo allora sono ~x→ y.

La funzione che crea il bigrafo substitution e substitution. Essa richiede in in-

gresso la lista dei nomi dell’interfaccia interna verso l’alto ed il nome dell’interfaccia

esterna verso l’alto. La funzione crea i link ~x→ y tramite la funzione linklist .

Il codice della funzione substitution e il seguente:

l et s u b s t i t u t i o n x l y = l et subs = id 0 [ ] [ ] insubs#a d d x p l u s l i s t x l ;subs#addyplus y ;l i n k l i s t x l ” inp ” y ”onp” subs ; ;

3.5.1.9 Empty Substitution

Un bigrafo di tipo empty substitution contiene dei nomi nell’interfaccia esterna verso

l’alto ma nessun nome nell’interfaccia interna verso l’alto.

La funzione che lo crea e:

l et emptysubst i tut ion y l = l et esubs = id 0 [ ] [ ] inesubs#a d d y p l u s l i s t y l ;esubs ; ;

3.5.1.10 Fusion

Il bigrafo fusion e analogo al bigrafo substitution ma i link partono dall’interfaccia

esterna verso il basso ed arrivano all’unico nome nell’interfaccia interna verso il

basso. La funzione che lo crea e fusion ed i parametri da passare sono il nome x

dell’interfaccia interna e la lista ~y dei nomi dell’interfaccia esterna.

Il codice della funzione e il seguente:

l et f u s i o n x y l = l et f u s = id 0 [ ] [ ] inf u s#addyminus l i s t y l ;f u s#addxminus x ;l i n k l i s t y l ”onm” x ”inm” fu s ; ;

3.5.1.11 Empty Fusion

Un bigrafo di tipo empty fusion contiene dei nomi nell’interfaccia interna verso il

basso ma nessun nome nell’interfaccia esterna verso il basso.

La funzione che lo crea e:

36 CAPITOLO 3. IMPLEMENTAZIONE DEI BIGRAFI DIRETTI

l et emptyfusion x l = l et e f u s = id 0 [ ] [ ] ine f u s#addxminus l i s t x l ;e f u s ; ;

3.5.1.12 Rename

Un bigrafo di tipo rename contiene una biezione tra i nomi delle interfacce.

Vi sono due tipi di bigrafo rinomina, uno di tipo substitution ed uno di tipo

fusion. Se e di tipo substitution i link vanno dall’interfaccia interna a quella esterna,

nel caso che sia fusion i link sono orientati nel verso opposto.

Sono presenti due funzioni che creano questi due tipi di bigrafo rename, a tutti

e due va passato come parametro una lista di coppie (nome sorgente, nome destina-

zione). Questa lista viene passata alla funzione linkpairlist che si occupa di creare

i link.

Il codice delle funzioni e il seguente:

l et subs t i tut ionrename l = l et subsr = id 0 [ ] [ ] insubsr#a d d x p l u s l i s t ( f s t ( L i s t . s p l i t l ) ) ;subsr#a d d y p l u s l i s t ( snd ( L i s t . s p l i t l ) ) ;l i n k p a i r l i s t l ” inp ” ”onp” subsr ;subsr ; ;

l et fus ionrename l = l et f u s r = id 0 [ ] [ ] inf u s r#addyminus l i s t ( f s t ( L i s t . s p l i t l ) ) ;f u s r#addxminus l i s t ( snd ( L i s t . s p l i t l ) ) ;l i n k p a i r l i s t l ”onm” ”inm” f u s r ;f u s r ; ;

3.5.1.13 Discrete Ion

Il bigrafo discrete ion e formato da una radice che contiene un nodo, l’unico del

bigrafo. Il nodo a sua volta contiene un sito. I link di questo bigrafo partono dalle

porte del nodo ed arrivano alle interfacce. La funzione che costruisce questo bigrafo

e discreteion . Essa richiede come parametri:

- il nome del nodo

- la sua signature

- la lista dei nomi dell’interfaccia interna verso il basso

- la lista dei nomi dell’interfaccia esterna verso l’alto

- una lista di coppie (porta, nome) che definisce i link da creare

3.5. ALGEBRA 37

- la classe delle signature

La funzione discreteion utilizza la funzione discreteionaux per creare i link.

Il codice della funzione discreteion e il seguente:

l et d i s c r e t e i o n v k x l y l l l s i g n s =l et d i s c r i o n = oneDB ( ) ind i s c r i o n#addnode v k s i g n s ;d i s c r i o n#addxminus l i s t x l ;d i s c r i o n#a d d y p l u s l i s t y l ;d i s c r i o n#s e t i n n e r i n t n 1 ;d i s c r i o n#addprntnoderoot v 0 ;d i s c r i o n#addprnts i tenode 0 v ;d i s c r e t e i o n a u x d i s c r i o n v l l ;d i s c r i o n ; ;

Una variante di discreteion e discreteionf che utilizza una funzione per trovare la

destinazione del link che parte da una data porta. Viene usata la funzione ausiliaria

discreteionauxf per costruire, data l’arieta del nodo e la funzione che mappa le porte

nei nomi, la lista (porta, nome). Viene quindi usata discreteionaux per costruire i

link come nella versione precedente.

Il codice di discreteionf e il seguente:

l et d i s c r e t e i o n f v k x l y l f s i g n s =l et d i s c r i o n = oneDB ( ) inlet l l = d i s c r e t e i o n a u x f f ( s i g n s#a r i t y v ) 0 ind i s c r i o n#addnode v k s i g n s ;d i s c r i o n#addxminus l i s t x l ;d i s c r i o n#a d d y p l u s l i s t y l ;d i s c r i o n#addprntnoderoot v 0 ;d i s c r i o n#addprnts i tenode 0 v ;d i s c r e t e i o n a u x d i s c r i o n v l l ;d i s c r i o n ; ;

3.5.2 Forma normale discreta

La forma normale si ottiene attraverso la funzione dnf che prendendo in ingresso un

bigrafo ritorna la lista [w;d;w’] contenente le componenti della scomposizione. Per

creare questi tre bigrafi si procede nel seguente modo:

- si crea un bigrafo vuoto w a cui si aggiungono gli archi e i nomi dell’interfaccia

esterna del bigrafo passato come parametro.

- si crea un bigrafo vuoto w’ a cui si aggiungono i nomi dell’interfaccia interna

del bigrafo passato come parametro.

38 CAPITOLO 3. IMPLEMENTAZIONE DEI BIGRAFI DIRETTI

- si crea un bigrafo d che mantiene i nodi, la lista prnt, la lista ctrl, il numero

di radici e siti del bigrafo passato come parametro.

Il codice della funzione e il seguente:

l et dnf ( dbg : d i r e c t edbg ) = l et w = id 0 [ ] [ ] inlet d = new d i r e c t edbg ( dbg#getnodes ) S t r ingSe t . empty

( dbg#getprnt ) [ ] ( dbg#g e t c t r l )( dbg#get inne r in tn , ( S t r ingSe t . empty , S t r ingSe t . empty ) )( dbg#getoute r in tn , ( S t r ingSe t . empty , S t r ingSe t . empty ) ) inlet w’ = id 0 [ ] [ ] inw#a d d y p l u s l i s t ( dbg#returnyp lus ) ;w#addyminus l i s t ( dbg#returnyminus ) ;w#a d d e d g e l i s t ( dbg#returnedges ) ;w’# a d d x p l u s l i s t ( dbg#returnxp lus ) ;w’# addxminus l i s t ( dbg#returnxminus ) ;d n f l i n k ( dbg#g e t l i n k ) w d w’ 0 0 ;w : : d : : w ’ : : [ ] ; ;

La funzione che scompone i link del bigrafo originale nei link dei tre bigrafi della

forma normale e dnflink. Essa richiede come parametri la lista dei link del bigrafo

originale, i tre bigrafi w, d e w’ e due interi. Questi due interi servono per creare nomi

nuovi distinti per le interfacce tra i bigrafi. Siano X− ed X+ gli insiemi dei nomi

verso il basso e verso l’alto dell’interfaccia interna, Y − ed Y + quelli dell’interfaccia

esterna, sia p una generica porta di un nodo e sia e un generico arco.

Analizzando la lista di link si possono presentare i seguenti casi con le relative

scomposizioni e codice che lo implementa:

y → x con y ∈ Y − ed x ∈ X− : si creano due nuovi nomi wi e zi ed i link da creare

sono y → wi nel bigrafo w, wi → zi nel bigrafo d e zi → x nel bigrafo w’.

l et rec d n f l i n kl i n k (w: d i r e c t edbg ) ( dbg : d i r e c t edbg ) (w ’ : d i r e c t edbg ) i j =match l i n k with| (Name( a , b ) , NameEdge( c , d ) ) : : t a i l when b =”onm” & d =”inm”

−> w#addxminus ( ”w” ˆ( s t r i n g o f i n t i ) ) ;dbg#addxminus ( ”z” ˆ( s t r i n g o f i n t j ) ) ;dbg#addyminus ( ”w” ˆ( s t r i n g o f i n t i ) ) ;w’#addyminus ( ”z” ˆ( s t r i n g o f i n t j ) ) ;w#addlinkfromname a ”onm” ( ”w” ˆ( s t r i n g o f i n t i ) ) ”inm” ;dbg#addlinkfromname ( ”w” ˆ( s t r i n g o f i n t i ) ) ”onm”( ”z” ˆ( s t r i n g o f i n t j ) ) ”inm” ;w’#addlinkfromname ( ”z” ˆ( s t r i n g o f i n t j ) ) ”onm” c ”inm” ;d n f l i n k t a i l w dbg w’ ( i +1) ( j +1)

x→ y con y ∈ Y + ed x ∈ X+ : si creano due nuovi nomi wi e zi ed i link da creare

sono wi → y nel bigrafo w, zi → wi nel bigrafo d e x→ zi nel bigrafo w’.

3.5. ALGEBRA 39

| (Name( a , b ) , NameEdge ( c , d ) ) : : t a i l when b =” inp ” & d =”onp”−> w#addxplus ( ”w” ˆ( s t r i n g o f i n t i ) ) ;dbg#addxplus ( ”z” ˆ( s t r i n g o f i n t j ) ) ;

dbg#addyplus ( ”w” ˆ( s t r i n g o f i n t i ) ) ;w’#addyplus ( ”z” ˆ( s t r i n g o f i n t j ) ) ;

w#addlinkfromname ( ”w” ˆ( s t r i n g o f i n t i ) ) ” inp ” c ”onp” ;dbg#addlinkfromname ( ”z” ˆ( s t r i n g o f i n t j ) ) ” inp ”( ”w” ˆ( s t r i n g o f i n t i ) ) ”onp” ;w’#addlinkfromname a ” inp ” ( ”z” ˆ( s t r i n g o f i n t j ) ) ”onp” ;d n f l i n k t a i l w dbg w’ ( i +1) ( j +1)

y → e con y ∈ Y − : si crea il link y → e in w.

| (Name( a , b ) , NameEdge( c , d ) ) : : t a i l when b =”onm” & d =”e”−> w#addlinkfromname a ”onm” c ”e” ;d n f l i n k t a i l w dbg w’ i j

x→ e con x ∈ X+ : si creano due nuovi nomi wi e zi ed i link da creare sono wi → e

nel bigrafo w, zi → wi nel bigrafo d e x→ zi nel bigrafo w’.

| (Name( a , b ) , NameEdge( c , d ) ) : : t a i l when b =” inp ” & d =”e”−> w#addxplus ( ”w” ˆ( s t r i n g o f i n t i ) ) ;dbg#addxplus ( ”z” ˆ( s t r i n g o f i n t j ) ) ;dbg#addyplus ( ”w” ˆ( s t r i n g o f i n t i ) ) ;w’#addyplus ( ”z” ˆ( s t r i n g o f i n t j ) ) ;w#addlinkfromname ( ”w” ˆ( s t r i n g o f i n t i ) ) ” inp ” c ”e” ;dbg#addlinkfromname ( ”z” ˆ( s t r i n g o f i n t j ) ) ” inp ”( ”w” ˆ( s t r i n g o f i n t i ) ) ”onp” ;w’#addlinkfromname a ” inp ” ( ”z” ˆ( s t r i n g o f i n t j ) ) ”onp” ;d n f l i n k t a i l w dbg w’ ( i +1) ( j +1)

p→ y con y ∈ Y + : si crea un nuovo nome wi ed i link da creare sono wi → y nel

bigrafo w e p→ wi nel bigrafo d.

| ( Port ( a , b ) , NameEdge( c , d ) ) : : t a i l when d =”onp”−> w#addxplus ( ”w” ˆ( s t r i n g o f i n t i ) ) ;dbg#addyplus ( ”w” ˆ( s t r i n g o f i n t i ) ) ;w#addlinkfromname ( ”w” ˆ( s t r i n g o f i n t i ) ) ” inp ” c ”onp” ;dbg#addl inkfromport a b ( ”w” ˆ( s t r i n g o f i n t i ) ) ”onp” ;d n f l i n k t a i l w dbg w’ ( i +1) j

p→ x con x ∈ X− : si crea un nuovo nome zi ed i link da creare sono p → zi nel

bigrafo d e zi → x nel bigrafo w’.

40 CAPITOLO 3. IMPLEMENTAZIONE DEI BIGRAFI DIRETTI

| ( Port ( a , b ) , NameEdge( c , d ) ) : : t a i l when d =”inm”−> dbg#addxminus ( ”z” ˆ( s t r i n g o f i n t j ) ) ;w’#addyminus ( ”z” ˆ( s t r i n g o f i n t j ) ) ;dbg#addl inkfromport a b ( ”z” ˆ( s t r i n g o f i n t j ) ) ”inm” ;w’#addlinkfromname ( ”z” ˆ( s t r i n g o f i n t j ) ) ”onm” c ”inm” ;d n f l i n k t a i l w dbg w’ i ( j +1)

p→ x : si crea un nuovo nome wi ed i link da creare sono wi → e nel bigrafo w e

p→ wi nel bigrafo d.

| ( Port ( a , b ) , NameEdge( c , d ) ) : : t a i l when d =”e”−> w#addxplus ( ”w” ˆ( s t r i n g o f i n t i ) ) ;dbg#addyplus ( ”w” ˆ( s t r i n g o f i n t i ) ) ;w#addlinkfromname ( ”w” ˆ( s t r i n g o f i n t i ) ) ” inp ” c ”e” ;dbg#addl inkfromport a b ( ”w” ˆ( s t r i n g o f i n t i ) ) ”onp” ;d n f l i n k t a i l w dbg w’ ( i +1) j

| head : : t a i l −> d n f l i n k t a i l w dbg w’ i j| [ ] −> ( ) ; ;

3.5.2.1 Scomposizione in bigrafi primi

Una volta creato d con la funzione dnf e possibile scomporlo in bigrafi primi con la

funzione primebg. Questa funzione prendendo in ingresso un bigrafo restituisce una

lista di bigrafi. Il primo elemento di questa lista e un bigrafo di tipo rename che

contiene i link del bigrafo passato che vanno da un’interfaccia all’altra. Seguono a

questo tanti bigrafi quante le radici del bigrafo passato, ognuno con una sola radice.

Questi sono il risultato della scomposizione del bigrafo passato, per ogni sua radice

si crea un bigrafo che contiene i suoi figli ed i link che partono da questi. Il codice

di primebg e il seguente:

l et primebg ( dbg : d i r e c t edbg ) = l et alpha = id 0 [ ] [ ] inprimealpha ( dbg#g e t l i n k ) alpha ;alpha : : ( p r i m e b g l i s t ( dbg#getprnt ) ( dbg#g e t l i n k )

( dbg#g e t c t r l ) ( dbg#g e t o u t e r i n t n − 1) 0 ) ; ;

La funzione primealpha crea il bigrafo rinomina mentre primebglist crea i bigrafi a

partire dalle componenti del bigrafo passato.

3.5.3 Uguaglianza tra bigrafi

La funzione che controlla se due bigrafi sono uguali e samebg, essa non fa altro

che controllare se tutte le componenti del bigrafo sono uguali. In questo caso si

sfrutta il polimorfismo delle funzioni di OCaml in quanto l’operatore = funziona

su qualsiasi tipo e ricorsivamente anche sulle liste. Per poter confrontare le liste

3.5. ALGEBRA 41

pero bisogna ordinarle in quanto gli stessi elementi possono generare liste diverse a

seconda dell’ordine. Il modulo List contiene una funzione sort che necessita pero di

una funzione per confrontare gli elementi della lista da ordinare. Anche in questo

caso si sfrutta il polimorfismo, in particolare della funzione compare che garantisce

un ordine fra gli elementi.

Il codice della funzione e il seguente :

l et samebg ( dbg1 : d i r e c t edbg ) ( dbg2 : d i r e c t edbg ) =( St r ingSe t . equal ( dbg1#getnodes ) ( dbg2#getnodes ) ) &( St r ingSe t . equal ( dbg1#getedges ) ( dbg2#getedges ) ) &( ( L i s t . s o r t compare dbg1#getprnt ) =

( L i s t . s o r t compare ( dbg2#getprnt ) ) ) &( ( L i s t . s o r t compare dbg1#g e t l i n k ) =

( L i s t . s o r t compare ( dbg2#g e t l i n k ) ) ) &( ( L i s t . s o r t compare dbg1#g e t c t r l ) =( L i s t . s o r t compare ( dbg2#g e t c t r l ) ) ) &( ( dbg1#g e t i n n e r i n t n ) = ( dbg2#g e t i n n e r i n t n ) ) &( St r ingSe t . equal ( dbg1#getxminus ) ( dbg2#getxminus ) ) &( St r ingSe t . equal ( dbg1#getxp lus ) ( dbg2#getxp lus ) ) &( ( dbg1#g e t o u t e r i n t n ) = ( dbg2#g e t o u t e r i n t n ) ) &( St r ingSe t . equal ( dbg1#getyminus ) ( dbg2#getyminus ) ) &( St r ingSe t . equal ( dbg1#getyp lus ) ( dbg2#getyp lus ) ) ; ;

42 CAPITOLO 3. IMPLEMENTAZIONE DEI BIGRAFI DIRETTI

4Il linguaggio ed il compilatore

In questo capitolo sara presentato il linguaggio per descrivere i bigrafi diretti e il re-

lativo compilatore. Tale linguaggio, denominato DBPL (Directed Bigraph Program-

ming Language) consente di descrivere sia un bigrafo sia la signature di controllo.

Il compilatore puo generare sia le classi directedbg e signatures, sia un programma

OCaml equivalente.

4.1 Il linguaggio

Il linguaggio DBPL consente di

• Definire la signature di controllo di un bigrafo

• Scrivere in modo semplice i bigrafi elementari

• Applicare le operazione tra bigrafi

• Dare un nome ad un bigrafo per riusarlo in seguito

4.1.1 La grammatica

Il linguaggio e descritto dalla seguente grammatica libera dal contesto:⟨dbpl

⟩::=

⟨signature

⟩⟨letblock

⟩EOF⟨

signature⟩

::= SIGNATURE LSB RSB SEMICOLON

| SIGNATURE LSB⟨sigelem

⟩RSB SEMICOLON⟨

sigelem⟩

::= SIGTYPE NAME COLON NUM

|⟨sigelem

⟩COMMA SIGTYPE NAME COLON NUM⟨

letblock⟩

::=⟨bg⟩

|⟨letelem

⟩IN⟨letblock

44 CAPITOLO 4. IL LINGUAGGIO ED IL COMPILATORE

⟨letelem

⟩::= LET NAME EQ

⟨bg⟩

⟨bg⟩

::= LRB⟨bg⟩

RRB

|⟨merge

⟩|⟨ion⟩

|⟨substitution

⟩|⟨fusion

⟩|⟨closure

⟩|⟨permutation

⟩|⟨tensor

⟩|⟨osp⟩

|⟨isp⟩

|⟨sp⟩

|⟨posp

⟩|⟨psp⟩

|⟨composition

⟩| NAME

⟨merge

⟩::= MERGE NUM

⟨ion⟩

::= NAME⟨ctrllist

⟩⟨substitution

⟩::= NAME SUBSTITUTION NAME

| NAME SUBSTITUTION⟨nset

⟩| NAME SUBSTITUTION

|⟨nset

⟩SUBSTITUTION

⟨fusion

⟩::= NAME FUSION NAME

|⟨nset

⟩FUSION NAME

| FUSION NAME

| FUSION⟨nset

⟩⟨closure

⟩::= NAME CLOSURE NAME

|⟨nset

⟩CLOSURE NAME

| NAME CLOSURE⟨nset

⟩|⟨nset

⟩CLOSURE

⟨nset

⟩| NAME CLOSURE

| CLOSURE NAME

4.2. IL COMPILATORE 45

|⟨nset

⟩CLOSURE

| CLOSURE⟨nset

⟩⟨permutation

⟩::= PERMUTATION

⟨siteset

⟩⟨tensor

⟩::=

⟨bg⟩

TENSOR⟨bg⟩

⟨osp

⟩::=

⟨bg⟩

OSP⟨bg⟩

⟨isp⟩

::=⟨bg⟩

ISP⟨bg⟩

⟨sp⟩

::=⟨bg⟩

SP⟨bg⟩

⟨posp

⟩::=

⟨bg⟩

POSP⟨bg⟩

⟨psp

⟩::=

⟨bg⟩

PSP⟨bg⟩

⟨composition

⟩::=

⟨bg⟩

COMPOSITION⟨bg⟩

⟨ctrllist

⟩::= LSB RSB

| LSB⟨ctrlelem

⟩RSB⟨

ctrlelem⟩

::= SIGN NAME

|⟨ctrlelem

⟩COMMA SIGN NAME⟨

siteset⟩

::= LSB RSB

| LSB⟨siteelem

⟩RSB⟨

siteelem⟩

::= NUM

|⟨siteelem

⟩COMMA NUM⟨

nset⟩

::= LSB⟨nsetelem

⟩RSB⟨

nsetelem⟩

::= NAME COMMA NAME

|⟨nsetelem

⟩COMMA NAME

Per convenzione i simboli terminali sono scritti in maiuscolo, mentre i simboli non

terminali in minuscolo. I simboli non terminali sono anche racchiusi tra parentesi

angolari. Il simbolo iniziale e “dbpl”.

4.2 Il Compilatore

Il compilatore per il linguaggio DBPL e formato da tre componenti: un analizzatore

lessicale, un parser ed un insieme di funzioni che formano l’interfaccia.

46 CAPITOLO 4. IL LINGUAGGIO ED IL COMPILATORE

4.2.1 L’analizzatore lessicale

L’analizzatore lessicale si occupa di analizzare il sorgente DBPL (leggendolo da un

file o una stringa, a seconda di quale funzione di interfaccia e stata usata) e produrre

una lista di token. L’analizzatore solleva una eccezione se incontra una sequenza di

caratteri che non corrisponde a nessun token conosciuto. L’analizzatore e stato

scritto usando il programma ocamllex. Ocamllex1 legge da un file le regole per

riconoscere i token (scritte usando espressioni regolari) e produce il sorgente del

corrispondende analizzatore lessicale scritto in OCaml. Queste sono le associazioni

tra stringhe e tokens:

• SIGNATURE : “Signature”

• LSB: “[”

• RSB: “]”

• SEMICOLON: “;”

• SIGTYPE : “active” oppure “passive” oppure “atomic”

• NAME : qualsiasi stringa che inizia con una lettera minuscola seguita da un

qualsiasi numero di lettere minuscole, maiuscole (esclusa la X) o cifre

• COLON : “:”

• NUM : un qualsiasi numero intero assoluto (non puo iniziare con uno 0)

• COMMA : “,”

• IN : “in”

• LET : “let”

• EQ : “=”

• LRB : “(”

• RRB : “)”

• MERGE : “merge”

• SUBSTITUTION : “/”

1Si veda la sezione 4.3.1 per ulteriori dettagli

4.2. IL COMPILATORE 47

• FUSION : \

• CLOSURE : “X”

• PERMUTATION : “@”

• TENSOR : “*”

• OSP : “/\”

• ISP : “\/”

• SP : “||”

• POSP : “/ˆ\”

• PSP : “|”

• COMPOSITION “°”

Una qualsiasi stringa che non rientra in queste categorie e considerata un errore.

In questo caso l’analizzatore lessicale alza una eccezione di tipo Unknown Symbol

con due parametri: la riga e la colonna dove e stata incontrata la stringa.

4.2.2 Il parser

Il parser si occupa di analizzare una sequenza di token (ottenuti invocando l’analizza-

tore lessicale) per determinare la sua struttra grammaticale in base alla grammatica

definita nella sezione 4.1.1. Il parser e stato scritto usando il programma ocamlyacc.

Ocamlyacc2 legge da un file la descrizione di una grammatica libera dal contesto

LARL(1) e produce un parser per quella grammatica scritto in OCaml.

4.2.2.1 La signature

Il parser controlla che ogni sorgente DBPL inizi con la definizione di una signature.

Questa descrizione e introdotta dalla parola chiave “Signature” seguita da zero o

piu definizioni di tipi di signature. Tali definizioni sono racchiuse da una coppia

di parentesi quadre e separate da virgole. La definizione di un tipo di signature e

formata da tre elementi: un tipo di attivita (active, passive o atomic), un nome per

questo tipo e un numero che rappresenta l’arieta. Esempi di signature valide sono:

2Si veda la sezione 4.3.2 per ulteriori dettagli

48 CAPITOLO 4. IL LINGUAGGIO ED IL COMPILATORE

Signature [];

Signature [active t0:2];

Signature [atomic t1:1,active t2:4];

Il parser e in grado di capire quando la definizione di una signature e scritta male.

In questo caso solleva un’apposita eccezione che indica il punto in cui si e verificato

l’errore. Se la signature e stata definita correttamente i singoli tipi sono inseriti in

un oggetto di tipo signatures.

4.2.2.2 I bigrafi elementari

Una volta definita la signature (che puo essere vuota) e possibile descrivere un qual-

siasi bigrafo utilizzando i bigrafi elementari le operazioni tra bigrafi. Dbpl consente

di descrivere i bigrafi substitution, fusion, closure, merge, permutation e discrete ion.

La definizione di questi bigrafi non e associativa e ha la precedenza sulle operazioni

tra bigrafi. Per descrivere questi bigrafi e necessario introdurre i name set, i site set

e le control list.

Name set I name set sono semplicemente delle liste di nomi di interfacce. Ogni

name set deve contenere almeno due nomi ed essere racchiuso tra parentesi quadre.

I singoli nomi sono separati da virgole e sono token di tipo NAME. Esempi di name

set validi sono:

[a,b]

[a,b,c]

[a1,bB]

Site set I site set sono liste di siti utilizzati per la descrizione dei bigrafi permuta-

tion. Un siteset e una lista di token di tipo NUM racchiusa da parentesi quadre. Gli

elementi della lista sono separati da virgole. Un site set puo essere vuoto. Esempi

di siteset validi sono:

[]

[1]

[2,5,4,1]

Control list Le control list descrivono i link che partono dal nodo contenuto in

un discrete ion. Una control list e una lista, racchiusa tra parentesi quadre, di token

4.2. IL COMPILATORE 49

di tipo NAME preceduti dai simboli “+” o “-”. Gli elementi di questa lista (che puo

essere vuota) sono separati da virgole. Esempi di control list valide sono:

[]

[+a]

[-a,+b,-c,+d]

Per convenzione i nomi e i name set posizionati a sinistra del simbolo che rap-

presenta il bigrafo elementare faranno parte dell’interfaccia esterna del bigrafo. I

nomi e i name set posizionati a destra invece faranno parte dell’interfaccia interna.

Quando si scrivera “uno o piu nomi” si intendera un nome oppure un name set.

Bigrafo substitution Il bigrafo substitution contiene uno o piu nomi nell’inter-

faccia interna verso l’alto che sono collegati ad un unico nome nell’interfaccia esterna

verso l’alto. Se si omettono i nomi dell’interfaccia interna verso l’alto si ottiene il

bigrafo emptysubstitution. La sintassi per descrivere un bigrafo di questo tipo e:

NAME / NAME

NAME / nset

NAME /

nset /

Esempi di bigrafi substitution validi sono:

a/b

a/[b,c]

a/

[b,c]/

In figura 4.1 sono riportati degli esempi di questo tipo di bigrafo. Sotto ogni

bigrafo c’e il codice DBPL per ottenerlo.

Bigrafo fusion Il bigrafo fusion contiene uno o piu nomi nell’interfaccia esterna

verso il basso che sono collegati ad un unico nome nell’interfaccia interna verso il

basso. Se si omettono i nomi dell’interfaccia esterna verso il basso si ottiene il bigrafo

emptyfusion. La sintassi per descrivere un bigrafo di questo tipo e:

NAME \ NAME

nset \ NAME

50 CAPITOLO 4. IL LINGUAGGIO ED IL COMPILATORE

a

ba/b

a

b c da/[b,c,d]

b c d

[b,c,d]/

Figura 4.1: Esempi di bigrafi substitution

a

ba\b

a

b c d

a\[b,c,d]b c d\[b,c,d]

Figura 4.2: Esempi di bigrafi fusion

\ NAME

\ nset

Esempi di bigrafi fusion validi sono:

a\ b

[a,b]\ c

\ a

\ [a,b]

In figura 4.2 sono riportati degli esempi di questo tipo di bigrafo. Sotto ogni bigrafo

c’e il codice DBPL per ottenerlo.

Bigrafo closure Il bigrafo closure contiene uno o piu nomi nell’interfaccia esterna

verso il basso e uno o piu nomi nell’interfaccia interna verso l’alto. Tutti questi nomi

sono collegati ad un unico arco. Si possono omettere i nomi dell’interfaccia esterna

verso il basso per ottenere un bigrafo down-closure oppure i nomi dell’interfaccia

interna verso l’alto per ottenere un bigrafo up-closure. La sintassi per descrivere un

bigrafo di questo tipo e:

4.2. IL COMPILATORE 51

a

b

e

aXb

a b

e

c d[a,b]X[c,d]

a b

e

[a,b]Xc d

e

X[c,d]

Figura 4.3: Esempi di bigrafi closure

NAME X NAME

nset X NAME

NAME X nset

nset X nset

NAME X

X NAME

nset X

X nset

Esempi di bigrafi closure validi sono:

a X b

[a,b] X c

a X [b,c]

[a,b] X [c,d]

a X

X a

[a,b] X

X [a,b]

In figura 4.3 sono riportati degli esempi di questo tipo di bigrafo. Sotto ogni bigrafo

c’e il codice DBPL per ottenerlo.

Bigrafo merge Il bigrafo merge e formato da una radice che contiene n siti al

suo interno. La sintassi per descrivere un bigrafo di questo tipo e:

merge NUM

Esempi di bigrafi merge validi sono:

52 CAPITOLO 4. IL LINGUAGGIO ED IL COMPILATORE

0

0

merge 1

0

0 1

merge 2

Figura 4.4: Esempi di bigrafi merge

0 1 2

2 0 1

@[2,0,1]

Figura 4.5: Esempio di bigrafo permutation

merge 1

merge 2

merge 6

In figura 4.4 sono riportati degli esempi di questo tipo di bigrafo. Sotto ogni bigrafo

c’e il codice DBPL per ottenerlo.

Bigrafo permutation Il bigrafo permutation e formato da n radici e n siti e ogni

radice ha come figlio un solo sito. Il numero del sito figlio e determinato da un site

set. Il site set usa una notazione posizionale: il sito che ha come numero il primo

elemento del site set sara figlio della radice 0, il sito che ha come numero il secondo

elemento del site set sara figlio della radice 1 e cosı via. La sintassi per descrivere

un bigrafo di questo tipo e:

@ siteset

Esempi di bigrafi permutation validi sono:

@ [1,4,2,3]

@ [5,1,3]

In figura 4.5 e riportato un esempo di questo tipo di bigrafo. Sotto ogni bigrafo c’e

il codice DBPL per ottenerlo.

4.2. IL COMPILATORE 53

0

v00

a c

b d

t2 [-a,+b,-c,+d]

Figura 4.6: Esempio di bigrafo discrete ion

Bigrafo discrete ion Il bigrafo discrete ion e formato da una radice che con-

tiene un nodo. Il nodo contiene un sito. Dalle porte del nodo partono dei link ed

arrivano alle interfacce. I link del nodo sono descritti dalla control list la quale usa

una notazione posizionale simile al site set. Il primo elemento della control list e

un link che parte dalla porta 0 del nodo, il secondo e un link che parte dalla porta

1 e cosı via. Ogni elemento della control list inizia con un simbolo “+” o “-”. Gli

elementi che iniziano con un “+” sono collegati al corrispondente nome sull’inter-

faccia esterna, mentre quelli che iniziano con un “-” sono collegati al corrispondente

nome sull’interfaccia interna. Ogni nodo ha una arieta e puo essere active, passi-

ve o atomic. Queste proprieta sono descritte dalla signature definita all’inizio del

programma DBPL. Il nome del tipo di un elemento della signature e usato quando

bisogna descrivere un discrete ion. La sintassi per descrivere un bigrafo di questo

tipo e:

NAME ctrlist

dove NAME e il nome di un tipo di signature precedentemente definito Esempi di

bigrafi discrete ion validi sono:

t0 [+a]

t1 [-a]

t2 [-a,+b,+d,-c]

In figura 4.6 e riportato un esempo di questo tipo di bigrafo. Sotto ogni bigrafo c’e

il codice DBPL per ottenerlo.

54 CAPITOLO 4. IL LINGUAGGIO ED IL COMPILATORE

4.2.2.3 Le operazioni tra bigrafi

Una volta che si ha a disposizione i bigrafi elementari e possibile applicare le ope-

razioni tra bigrafi per ottenere un qualsiasi altro bigrafo. Le operazioni tra bigrafi

supportate dal DBPL sono:

• Composizione

• Outer sharing product

• Inner sharing product

• Sharing product

• Prime outer sharing product

• Prime sharing product

• Tensore

Queste operazioni sono elencate in ordine decrescente di precedenza e sono associa-

tive (per convenzione si associa a sinistra).

Tensore Il tensore e l’operazione che “unisce” due bigrafi disgiunti. La sintassi

per questa operazione e:

bg * bg

dove bg sono due bigrafi disgiunti. Se i due bigrafi non sono disgiunti il parser alza

una eccezzione Bigraphs are not disjoint. Esempi di tensore sono:

marge 1 * a/b

t1 [-a,+b,-c,+d] * [f,g] X z

In figura 4.7 e riportato un esempo di questo tipo di bigrafo. Sotto ogni bigrafo c’e

il codice DBPL per ottenerlo.

Composizione Informalmente questa operazione tra due bigrafi inserisce le radici

del secondo nei siti del primo. Inoltre modifica i links che attraversano l’interfaccia

comune (quella interna del primo e quella esterna del secondo) cambiando le loro

destinazioni (o eliminandoli). Per effettuare questa operazione e necessario che i nodi

e gli archi dei due bigrafi siano disgiunti. Inoltre l’interfaccia interna del primo deve

essere uguale all’interfaccia esterna del secondo. La sintassi per questa operazione

e:

4.2. IL COMPILATORE 55

0

v00

a c

b d

t2 [-a,+b,-c,+d]

f g

e

z[c,d]Xz

0

v0

0

a c

b d f g

e

z

t2 [-a,+b,-c,+d] * [f,g]Xz

Figura 4.7: Esempio di tensore: sopra i bigrafi di partenza, sotto il risultato

56 CAPITOLO 4. IL LINGUAGGIO ED IL COMPILATORE

0

v00

c d

a b

t2 [+a,-c,+b,-d]

0

v1

f

c d

g ht1 [-f] * c\g * d\h

0

v0v1

g h

a b

f

t2 [+a,-c,+b,-d] °(t1 [-f] * c\g * d\h)

Figura 4.8: Esempio di composizione: sopra i bigrafi di partenza, sotto il risultato

4.2. IL COMPILATORE 57

b

a

a/b

c

a

a/c

a

b c

a/b /\a/b

Figura 4.9: Esempio di outer sharing product: sopra i bigrafi di partenza, sotto ilrisultato

bg ° bg

dove bg sono i due bigrafi. Esempi di composizione sono:

[a,b,c]\z ° zXf

t2 [+a,+b,-c,-d] ° (t1 [-f] * c\g * d\h)

In figura 4.8 e riportato un esempo di questo tipo di bigrafo. Sotto ogni bigrafo c’e

il codice DBPL per ottenerlo.

Outer sharing product L’outer sharing product e una variante del tensore che

consente la condivisione dei nomi dell’interfaccia esterna verso l’alto. La sintassi per

questa operazione e:

bg /\ bg

Esempi di outer sharing product sono:

a/b /\ a/c

t1 [+a] /\ t1 [+a]

58 CAPITOLO 4. IL LINGUAGGIO ED IL COMPILATORE

a

b

b/a

a

c

c/a

a

b c

b/a \/ c/a

Figura 4.10: Esempio di inner sharing product: sopra i bigrafi di partenza, sotto ilrisultato

In figura 4.9 e riportato un esempo di questo tipo di bigrafo. Sotto ogni bigrafo c’e

il codice DBPL per ottenerlo.

Inner sharing product L’inner sharing product e una variante del tensore che

consente la condivisione dei nomi dell’interfaccia interna verso il basso. La sintassi

per questa operazione e:

bg \/ bg

Esempi di inner sharing product sono:

b/a \/ c/a

t1 [-a] \/ t1 [-a]

In figura 4.10 e riportato un esempo di questo tipo di bigrafo. Sotto ogni bigrafo c’e

il codice DBPL per ottenerlo.

bigrafo. Sotto ogni bigrafo c’e il codice DBPL per ottenerlo.

4.2. IL COMPILATORE 59

a

d

c

b

a/d * c\b

e

a

b

f

a/e * f\b

c f a

b d e

(a/d * c\b) || (a/e * f\b)

Figura 4.11: Esempio di sharing product: sopra i bigrafi di partenza, sotto il risultato

Sharing product Il sharing product e una variante del tensore che consente la

condivisione dei nomi dell’interfaccia interna verso il basso e dei nomi dell’interfaccia

esterna verso l’alto. La sintassi per questa operazione e:

bg || bg

Esempi di sharing product sono:

b/a || c/a

t1 [-a,+b] || t1 [-a,+b]

In figura 4.11 e riportato un esempo di questo tipo di bigrafo. Sotto ogni bigrafo c’e

il codice DBPL per ottenerlo.

Prime outer sharing product Il prime outer sharing product e una variante

del tensore che consente la condivisione dei nomi dell’interfaccia esterna verso l’alto

e tutti gli elementi del place graph figli di radici diventano figli della stessa radice.

La sintassi per questa operazione e:

bg /^\ bg

60 CAPITOLO 4. IL LINGUAGGIO ED IL COMPILATORE

0

v0

c

t1 [+c]

1

v1

c

t1 [+c]

0

v0 v1

c

t1 [+c] /ˆ\t1 [+c]

Figura 4.12: Esempio di prime outer sharing product: sopra i bigrafi di partenza,sotto il risultato

4.2. IL COMPILATORE 61

0

v0

a

bt1 [+a,-b]

1

v1

a

bt1 [+a,-b]

0

v0 v1

a

bt1 [+a,-b] — t1 [+a,-b]

Figura 4.13: Esempio di prime sharing product: sopra i bigrafi di partenza, sotto ilrisultato

Un esempio di prime outer sharing product e:

t1 [+a] /^\ t1 [+a]

In figura 4.12 e riportato un esempo di questo tipo di bigrafo. Sotto ogni bigrafo c’e

il codice DBPL per ottenerlo.

Prime sharing product Il prime sharing product e una variante del tensore

che consente la condivisione dei nomi dell’interfaccia esterna verso l’alto, dei nomi

dell’interfaccia interna verso il basso e tutti gli elementi del place graph figli di radici

diventano figli della stessa radice. La sintassi per questa operazione e:

bg | bg

Un esempio di prime outer sharing product e:

t1 [+a,-b] | t1 [+a,-b]

62 CAPITOLO 4. IL LINGUAGGIO ED IL COMPILATORE

In figura 4.13 e riportato un esempo di questo tipo di bigrafo. Sotto ogni bigrafo c’e

il codice DBPL per ottenerlo.

4.2.2.4 Forzare le precedenze

Nel caso ci sia la necessita si possono usare le parentesi tonde per cambiare l’ordine

di esecuzione delle operazioni in un ordine diverso da quello dettato dalle normali

precedenze tra gli operatori. Ad esempio:

t2[-a,-b]°(merge 1 *a\c*b\d)

eseguira i tensori prima della composizione.

4.2.2.5 I blocchi let

Il linguaggio DBPL consente di dare dei nomi a bigrafi per poi riutilizzarli senza

dover riscrivere il bigrafo stesso. Come in molti linguaggi di programmazione l’as-

sociazione di un nome ad un bigrafo avviene usando le parole chiave “let” e “in”; in

particolare la sintassi e:

let NAME = bg IN letblock

dove NAME e il nome per il nuovo bigrafo e bg e il bigrafo da nominare (e possibile

creare degli alias per lo stesso bigrafo). Il letblock finale permette di un annidamento

arbitrario dei blocchi let. Esempi:

let bg1=[a,b]\c in

let bg2=[f,g]X[h,j] in

bg1 * bg2

4.2.3 L’interfaccia del compilatore

Il compilatore puo essere invocato attraverso quattro diverse funzioni che determi-

nano che parametri prendere e che risultati ritornare. Tutte queste funzioni sono

contenute nel modulo Dbplcompiler. Le funzioni sono queste:

compilefromfile: string -> Bigraph.signatures * Bigraph.directedbg

Questa funzione prende in ingresso una striga che contiene il nome di un file.

La funzione legge da questo file il sorgente dbpl e restituisce la coppia (signature,

bigrafo).

4.3. ASPETTI IMPLEMENTATIVI 63

compilefromstring : string -> Bigraph.signatures * Bigraph.directedbg

Questa funzione prende in ingresso una striga che contiene il sorgente dbpl e

restituisce la coppia (signature, bigrafo)

compilefromfile2ocaml : string -> string -> unit

Questa funzione prende in ingresso due strighe. La prima contiene il nome del

file col sorgente dbpl da elaborare. La seconda e il nome del file in cui scrivere il

programma ocaml corrispondente.

compilefromstring2ocaml : string -> string -> unit

Questa funzione prende in ingresso due strighe. La prima contiene il sorgente

dbpl e la seconda e il nome del file in cui scrivere il programma ocaml corrispondente.

4.3 Aspetti implementativi

In questa sezione sara descritta l’implementazione delle componenti del compilato-

re. La generazione del programma ocaml corrispondente al bigrafo e molto simile

alla generazione della coppia (signature, bigrafo) e quindi saranno descritte solo le

differenze rispetto a quest’ultima.

4.3.1 L’analizzatore lessicale

L’analizzatore lessicale e stato generato usando il programma ocamllex. Questo

programma prende un file sorgente contenente le regole per individuare i token e

prodice il sorgente ocaml di un programma che implementa l’analizzatore lessicale.

Il sorgente ocamllex e diviso in quattro sezioni: intestazione, definizioni, regole e

il blocco finale. Solo la prima e la terza sezione sono obbligatorie, le altre sono

opzionali. In questa implementazione dell’analizzatore lessicale non e stato usato il

blocco finale

4.3.1.1 Intestazione

L’intestazione contiene codice ocaml racchiuso tra parentesi graffe ed e copiata al-

l’inizio del codice ocaml generato da ocamllex. Questa sezione di solito e usata per

aprire moduli oppure per definire funzioni da usare successivamente. L’intestazione

dell’analizzatore lessicale e:

{

open Dbplparser

64 CAPITOLO 4. IL LINGUAGGIO ED IL COMPILATORE

exception Unknown_Symbol of (int*int);;

let incr_linenum lexbuf = let pos = lexbuf.Lexing.lex_curr_p in

lexbuf.Lexing.lex_curr_p <- { pos with

Lexing.pos_lnum = pos.Lexing.pos_lnum + 1;

Lexing.pos_bol = pos.Lexing.pos_cnum;

}

;;

}

In questo caso per prima cosa si apre il modulo Dbplparser che contiene l’implemen-

tazione del parser. Tale apertura e necessaria per poter accedere alla lista di token

previsti per il linguaggio. Dopo l’apertura del modulo c’e la dichiarazione di una ec-

cezione. Questa e l’eccezione sollevata dall’analizzatore quando incontra una stringa

che non corrisponde ad un token valido. Infine c’e la dichiarazione della funzione

incr linenum. Questa funzione si occupa di aggiornare alcune tabelle necessarie per

localizzare in quale punto del sorgente dbpl si incontrano i vari token. Tali tabelle

sono indispensabili per riconoscere gli errori e sollevare le giuste eccezioni.

4.3.1.2 Definizioni

Questa sezione serve per dare dei nomi a dei pattern per semplificare la scrittura

dell’analizzatore. La sintassi generica di una definizione e

let ident = regexp

dove ident e il nome della definizione e regexp e una espressione regolare. La lista

delle definizioni e:

let num = [’0’-’9’] | [’1’-’9’][’0’-’9’]+

let name = [’a’-’z’][’a’-’z’ ’A’-’W’ ’Y’-’Z’ ’0’-’9’]*

let sign = ’+’ | ’-’

secondo queste definizioni num e una stringa formata dai caratteri compresi tra 0

e 9 oppure dai caratteri compresi tra 1 e 9 seguiti da uno o piu caratteri tra 0 e

9. name e una stringa che inizia con una lettera minuscola ed e seguita da zero o

piu lettere minuscole, maiuscole (esclusa la X) e cifre. Infine sign sono i caratteri +

oppure -.

4.3. ASPETTI IMPLEMENTATIVI 65

4.3.1.3 Regole

Le regole definiscono cosa bisogna fare quando si trova una certa stringa. La sintassi

generica per una regola e:

rule entrypoint [arg1... argn] = parse

| pattern {action}

| pattern {action}

...

entrypoint e il nome della regola (che puo avere parametri). Questo sara anche il

nome della funzione da chiamare nel parser per chiamare l’analizzatore. pattern e

una espressione regolare (si possono usare le definizioni di prima) e action e l’azione

eseguita quando si incontra una stringa che corrisponde al pattern. L’analizzatore

legge un carattere alla volta fino a quando non trova un pattern che corrisponde alla

stringa letta. Se ci sono piu pattern che corrispondono si sceglie il piu lungo, se ci

sono piu pattern dalla stessa lunghezza si sceglie il primo. Le regole dell’analizzatore

sono queste:

rule token = parse

| [’ ’ ’\t’] { token lexbuf }

| ’\n’ { incr_linenum lexbuf; token lexbuf }

| "merge" { MERGE }

| "Signature" { SIGNATURE }

| "active"

| "passive"

| "atomic" as sigtype { SIGTYPE (sigtype) }

| "in" { IN }

| "let" { LET }

| num as n { NUM(int_of_string n) }

| name as nm { NAME(nm) }

| sign as sn { SIGN (String.make 1 sn) }

| "=" { EQ }

| "[" { LSB }

| "]" { RSB }

| "," { COMMA }

| ":" { COLON }

| ";" { SEMICOLON }

66 CAPITOLO 4. IL LINGUAGGIO ED IL COMPILATORE

| "*" { TENSOR }

| "°" { COMPOSITION }

| "/\\" { OSP }

| "\\/" { ISP }

| "||" { SP }

| "/^\\" { POSP }

| "|" { PSP }

| "/" { SUBSTITUTION }

| "\\" { FUSION }

| "(" { LRB }

| ")" { RRB }

| "X" { CLOSURE }

| "@" { PERMUTATION }

| eof { EOF }

| _ { raise (Unknown_Symbol (lexbuf.Lexing.lex_curr_p.

Lexing.pos_lnum, (lexbuf.Lexing.lex_curr_p.

Lexing.pos_cnum-lexbuf.Lexing.lex_curr_p.Lexing.pos_bol))) }

Il primo pattern serve per scartare gli spazi mentre il secondo serve per chiamare la

funzione incr linenum per i motivi descritti in precedenza. I pattern successivi indivi-

duano e generano i token previsti dalla grammatica (Le stringhe num rappresentano

interi quindi e necessario fare un cast esplicito). L’ultimo pattern e il simbolo “-”

che corrisponde a qualsiasi stringa. Se l’analizzatore arriva a questo punto significa

che ha incontrato una stringa non valida e segnala la situazione alzando l’eccezione

Unknown Symbol.

4.3.1.4 Differenze per la generazione del programma OCaml

L’analizzatore per la variante del compilatore che genera il programma OCaml cor-

rispondente al bigrafo e praticamente identico a quello appena descritto. L’unica

differenza e che, dovendo generare stringhe, non e necessario fare il cast delle stringhe

num in interi.

4.3.2 Il Parser

Il parser e stato generato con il programma ocamlyacc. Tale programma prende un

file contenente la lista dei token, le loro proprieta e produzioni della grammatica e

produce il sorgente di un programma OCaml che implementa il parser. Il sorgente

4.3. ASPETTI IMPLEMENTATIVI 67

per ocamlyacc e diviso in quattro sezioni: intestazione, dichiarazioni, regole della

grammatica e blocco finale (quest’ultimo non e stato usato).

4.3.2.1 Intestazione

L’intestazione contiene codice OCaml che sara copiato all’inizio del sorgente del

parser. Questo blocco e racchiuso dai simboli “%{” e “%}”. Nell’intestazione di

solito si aprono i moduli e si dichiarano variabili, funzioni ed eccezioni. Questa e

l’intestazione del parser:

open String

open Algebra

open Bigraph

Per prima cosa si aprono questi tre moduli. Il primo contiene funzioni utili per

manipolare le stringhe, il secondo contiene le funzioni che implementano l’algebra

dei bigrafi diretti e l’ultimo contiene l’implementazione delle strutture dati per le

signatures e i bigrafi diretti

exception Unbound_Bigraph of (int*int)

exception Malformed_Dbpl of (int*int)

exception Malformed_Signature of (int*int)

exception Malformed_Signature_Element of (int*int)

exception Malformed_SiteSet of (int*int)

exception Malformed_SiteSet_Element of (int*int)

exception Malformed_IonLinkList of (int*int)

exception Malformed_IonLinkList_Element of (int*int)

exception Malformed_NameSet of (int*int)

exception Malformed_NameSet_Element of (int*int)

exception Malformed_Bigraph of (int*int)

exception Malformed_Merge of (int*int)

exception Malformed_Ion of (int*int)

exception Malformed_Substitution of (int*int)

exception Malformed_Fusion of (int*int)

exception Malformed_Permutation of (int*int)

exception Malformed_Tensor of (int*int)

exception Malformed_Osp of (int*int)

exception Malformed_Isp of (int*int)

68 CAPITOLO 4. IL LINGUAGGIO ED IL COMPILATORE

exception Malformed_Sp of (int*int)

exception Malformed_Posp of (int*int)

exception Malformed_Psp of (int*int)

exception Malformed_Composition of (int*int)

Queste sono le eccezioni sollevate in caso di errore. Ogni eccezione ha due parametri:

la riga e la colonna dove si e verificato l’errore

let ecount = ref (-1);;

let vcount = ref (-1);;

Questi sono i contatori per gli archi e i nodi; servono per dare i nomi ad essi dato

che il DBPL non prevede la possibilita di denominarli esplicitamente

let sign = new signatures;;

Dichiarazione di un oggetto di tipo signatures. Serve per gestire la signature letta

dal sorgente DBPL.

let bgcount = ref 0;;

let bigraphs = Hashtbl.create 16;;

let invbigraphs = Hashtbl.create 16;;

let ids = Hashtbl.create 16;;

Il primo e un contatore di bigrafi trovati, gli altri tre sono tabelle hash usate per

la gestione dei blocchi let. La prima associa un codice numerico ad un bigrafo; la

seconda associa un bigrafo ad un codice numerico e la terza associa un nome ad un

codice numerico

let rec perm str n = match str with

| [] -> []

| head::tail -> (head, n)::perm tail (n+1)

;;

let rec makeSigSet data = match data with

| [] -> sign

| (t, n, a)::tail -> sign#addsign2 n t a; makeSigSet tail

;;

let rec donames list c = match list with

| [] -> []

4.3. ASPETTI IMPLEMENTATIVI 69

| head::tail -> if (get head 0 = c)

then (sub head 1 (length head -1))::

donames tail c

else donames tail c

;;

let rec makelinklist l n = match l with

| [] -> []

| head::tail -> (n, (sub head 1 (length head -1)))::

makelinklist tail (n+1)

;;

let location pos = (pos.Lexing.pos_lnum,

pos.Lexing.pos_cnum-pos.Lexing.pos_bol);;

La prima funzione costruisce la lista delle coppie (sito, radice) da passare come

parametro alla funzione che crea il bigrafo permutation. La seconda inserisce gli

elementi della signature nella apposita classe. La terza filtra i link passati come

parametro a seconda della loro direzione (“+” per i link verso l’alto e “-” per i link

verso il basso). La quarta crea la lista che associa ad ogni porta di un nodo la

destinazione del link che parte da quella porta. Infine la quinta ritorna la posizione

di un token nella forma (riga, colonna)

4.3.2.2 Dichiarazioni

Questa sezione contiene le dichiarazioni dei simboli del linguaggio e le loro proprieta.

Ogni dichiarazione deve iniziare col simbolo “%”. Le dichiarazioni sono queste:

%token <int> NUM

%token <string> NAME

%token <string> SIGTYPE

%token <string> SIGN

%token EOF LET IN EQ

%token TENSOR COMPOSITION OSP ISP SP POSP PSP

%token SUBSTITUTION FUSION PERMUTATION

%token LRB RRB LSB RSB COLON SEMICOLON COMMA

%token MERGE CTRLLIST CLOSURE SIGNATURE

%left OSP ISP SP POSP PSP TENSOR

%left COMPOSITION

%nonassoc CLOSURE PERMUTATION

70 CAPITOLO 4. IL LINGUAGGIO ED IL COMPILATORE

%nonassoc SUBSTITUTION FUSION

%nonassoc MERGE

%start dbpl

%type <(Bigraph.signatures * Bigraph.directedbg)> dbpl

Le righe che iniziano con “token” introducono la definizione di un nuovo token.

Tra parentesi angolari c’e il tipo dell’eventuale valore associato al token. Le righe

che iniziano con left, right o nonassoc introducono la definizione di token che rap-

presentano una operazione. Permettono di specificare sia le precedenze (in ordine

crescende) sia l’associativita (left associa a sinistra, right associa a destra e nonassoc

non e associativo). La riga che inizia con start dichiara il simbolo iniziale e la riga

che inizia con type dichiara il suo tipo.

4.3.2.3 Regole

La sezione delle regole descrive tutte le produzioni della grammatica e le azioni da

eseguire quando si trova una corrispondenza tra i token incontrati e una produzione.

La sezione delle regole e separata da quella delle dichiarazioni da una coppia di

simboli percentuale (“%%”). La sintassi generica per una produzione e:

result:

symbol1 ... symboln {action}

| symbol1 ... symboln {action}

| ...

;

dove result e un simbolo non terminale, symbol1 . . . symboln sono simboli (terminali

o non) e action e il codice OCaml da eseguire per quella produzione. Si puo usare

l’espressione $n per accedere al valore associato all’n-esimo simbolo della produzione,

se presente. Nelle produzioni e possibile usare il simbolo terminale speciale “error”

per l’individuazione degli errori. Ogni volta che si incontra un nuovo token si cerca

una produzione per i token incontrati. Se la si trova, si applica l’azione prevista;

se non la si trova si legge il token successivo. Se si possono applicare due o piu

produzioni si applica la piu lunga. Se due o piu produzioni hanno la stessa lunghezza

allora la grammatica e ambigua. La prima produzione riguarda il simbolo iniziale:

dbpl: signature letblock EOF { ($1, $2) }

| error EOF {

4.3. ASPETTI IMPLEMENTATIVI 71

raise (Malformed_Dbpl (location (Parsing.rhs_start_pos 1))) }

| signature error EOF {

raise (Malformed_Dbpl (location (Parsing.rhs_start_pos 2))) }

;

un sorgente DBPL valido e formato da una signature e un bigrafo. Quasiasi cosa

diversa genera un errore (e il sollevamento della relativa eccezione).

letblock: bg { $1 }

| letelem IN letblock { $3 }

;

letelem: LET NAME EQ bg {

if (Hashtbl.mem invbigraphs $4)

then Hashtbl.replace ids $2 (Hashtbl.find invbigraphs $4)

else Hashtbl.add bigraphs !bgcount $4;

Hashtbl.replace ids $2 !bgcount;

Hashtbl.add invbigraphs $4 !bgcount;bgcount:=!bgcount+1 }

;

Queste due produzioni gestiscono i blocchi let. I blocchi let possono essere annidati a

piacere ma alla fine c’e sempre la definizione di un bigrafo. Nel caso dell’assegnazione

di un nome ad un bigrafo si controlla se tale bigrafo e gia stato incontrato. In caso

positivo tramite la tabella invbigraphs si ottiene il codice associato e si aggiunge nella

tabella ids l’associazione tra il nuovo nome e il codice cosı ottenuto. In caso negativo

si aggiunge alle tabelle bigraphs e invbigraphs le associazioni (codice, bigrafo) e

(bigrafo, codice) rispettivamente e si aggiunge alla tabella ids l’associazione (nome,

codice); infine si incrementa il contatore dei bigrafi

signature: SIGNATURE LSB RSB SEMICOLON { makeSigSet [] }

| SIGNATURE LSB sigelem RSB SEMICOLON { makeSigSet $3 }

| error {

raise (Malformed_Signature (location (Parsing.rhs_start_pos 1)))

}

;

sigelem: SIGTYPE NAME COLON NUM { [($1, $2, $4)] }

| sigelem COMMA SIGTYPE NAME COLON NUM { $1@[($3, $4, $6)]}

| error {raise(

Malformed_Signature_Element (location (Parsing.rhs_start_pos 1))

72 CAPITOLO 4. IL LINGUAGGIO ED IL COMPILATORE

)}

;

Queste sono le produzioni per gestire la signature in accordo con quanto visto in

4.2.2.1. Gli elementi della signature sono inseriti in una lista che e poi passata alla

funzione makeSigSet. In caso di errore di sintassi il partser solleva una eccezione

siteset: LSB RSB { [] }

| LSB siteelem RSB { $2 }

| error {raise (

Malformed_SiteSet (location (Parsing.rhs_start_pos 1))

)}

;

siteelem: NUM { [$1] }

| siteelem COMMA NUM { $1@[$3] }

| error {raise (

Malformed_SiteSet_Element (location (Parsing.rhs_start_pos 1))

)}

;

ctrllist: LSB RSB { [] }

| LSB ctrlelem RSB { $2 }

| error {raise (

Malformed_IonLinkList (location (Parsing.rhs_start_pos 1))

)}

;

ctrlelem: SIGN NAME { [($1^$2)] }

| ctrlelem COMMA SIGN NAME{ $1@[($3^$4)] }

| error {raise (

Malformed_IonLinkList_Element(location (Parsing.rhs_start_pos 1))

)}

;

nset: LSB nsetelem RSB { $2 }

| error {raise (

Malformed_NameSet (location (Parsing.rhs_start_pos 1))

)}

;

nsetelem: NAME COMMA NAME { $1::[$3] }

4.3. ASPETTI IMPLEMENTATIVI 73

| nsetelem COMMA NAME { $1@[$3] }

| error {raise (

Malformed_NameSet_Element (location (Parsing.rhs_start_pos 1))

)}

;

Queste produzioni riguardano le liste di siti, nomi e link per gli ioni in accordo

con quanto visto in 4.2.2.2. In caso di errore di sintassi il parser solleva l’eccezione

opportuna

bg: LRB bg RRB { $2 }

| merge { $1 }

| ion { $1 }

| substitution { $1 }

| fusion { $1 }

| closure { $1 }

| permutation { $1 }

| tensor { $1 }

| osp { $1 }

| isp { $1 }

| sp { $1 }

| posp { $1 }

| psp { $1 }

| composition { $1 }

| NAME { try (Hashtbl.find bigraphs(Hashtbl.find ids $1))

with Not_found ->

raise (Unbound_Bigraph (location (Parsing.rhs_start_pos 1))) }

;

Questa e la produzione che descrive tutti i possibili bigrafi. Un bigrafo puo essere un

bigrafo elementare, il risultato di una operazione tra bigrafi, un bigrafo tra parentesi

tonde (per forzare le precedenze tra operazioni) o un NAME (per usare bigrafi

denominati in precedenza). Gli errori sono gestiti dai singoli tipi di bigrafo tranne

che nell’ultimo caso. Se si tenta di usare un bigrafo non definito il parser solleva una

eccezione

merge: MERGE NUM { (merge $2) }

74 CAPITOLO 4. IL LINGUAGGIO ED IL COMPILATORE

| error NUM {

raise (Malformed_Merge (location (Parsing.rhs_start_pos 1))) }

| MERGE error {

raise (Malformed_Merge (location (Parsing.rhs_start_pos 2))) }

| MERGE NUM error {

raise (Malformed_Merge (location (Parsing.rhs_start_pos 3))) }

;

substitution: NAME SUBSTITUTION NAME { (substitution [$3] $1) }

| NAME SUBSTITUTION nset { (substitution $3 $1) }

| NAME SUBSTITUTION { (emptysubstitution [$1]) }

| nset SUBSTITUTION { (emptysubstitution $1) }

| nset SUBSTITUTION NAME {raise (

Malformed_Substitution (location (Parsing.rhs_start_pos 1))) }

| nset SUBSTITUTION nset { raise (

Malformed_Substitution (location (Parsing.rhs_start_pos 1))) }

;

fusion: NAME FUSION NAME { (fusion $3 [$1]) }

| nset FUSION NAME { (fusion $3 $1) }

| FUSION NAME { (emptyfusion [$2]) }

| FUSION nset { (emptyfusion $2) }

| NAME FUSION nset { raise (

Malformed_Fusion (location (Parsing.rhs_start_pos 3))) }

| nset FUSION nset { raise (

Malformed_Fusion (location (Parsing.rhs_start_pos 3))) }

;

permutation: PERMUTATION siteset { permutation (perm $2 0) }

Queste produzioni gestiscono la creazione dei bigrafi elementari merge, substitu-

tion, fusion e permutation in accordo con quanto visto in 4.2.2.2 usando le apposite

funzioni dell’algebra. In caso di errori di sintassi il parser alza le opportune eccezioni

closure: NAME CLOSURE NAME {

ecount:=!ecount+1; closure $3 $1 ("e" ^ string_of_int !ecount) }

| nset CLOSURE NAME {

ecount:=!ecount+1; (fusion "1unused" $1)#composition

(closure $3 "1unused" ("e" ^ string_of_int !ecount)) }

| NAME CLOSURE nset {

4.3. ASPETTI IMPLEMENTATIVI 75

ecount:=!ecount+1;

(closure "2unused" $1 ("e" ^ string_of_int !ecount))#composition

(substitution $3 "2unused") }

| nset CLOSURE nset { ecount:=!ecount+1;

((fusion "3unused" $1)#composition

(closure "4unused" "3unused"

("e" ^ string_of_int !ecount)))#composition

(substitution $3 "4unused") }

| NAME CLOSURE { ecount:=!ecount+1;

(upclosure $1 ("e" ^ string_of_int !ecount)) }

| CLOSURE NAME { ecount:=!ecount+1;

(downclosure $2 ("e" ^ string_of_int !ecount)) }

| nset CLOSURE { ecount:=!ecount+1;

(fusion "1unused" $1)#composition

(upclosure "1unused" ("e" ^ string_of_int !ecount)) }

| CLOSURE nset { ecount:=!ecount+1;

(downclosure "2unused" ("e" ^ string_of_int !ecount))#composition

(substitution $2 "2unused") }

;

Questa produzione gestisce la generazione del bigrafo closure (e anche up-closure

e down-closure) in accordo con quanto visto in 4.2.2.2 usando l’apposita funzione

dell’algebra. Le closures con nset si generano componento opportunamente bigrafi

substitution, bigrafi fusion e closures semplici

ion: NAME ctrllist { vcount:=!vcount+1;

try (let dbg = (discreteion ("v" ^ string_of_int !vcount) $1

(donames $2 ’-’ ) (donames $2 ’+’) (makelinklist $2 0) sign) in

if (sign#activity $1="atomic") then

(dbg#composition ((merge 0)#tensor (id 0 (donames $2 ’-’) [])))

else dbg

)with Not_found -> raise

(Malformed_Ion (location (Parsing.rhs_start_pos 1))) }

;

Questa produzione gestisce la generazione del bigrafo discrete ion in accordo con

quanto visto in 4.2.2.2 usando l’apposita funzione dell’algebra. Sono usate le fun-

76 CAPITOLO 4. IL LINGUAGGIO ED IL COMPILATORE

zioni donames e makelinklist per costruire i parametri da passare alla funzione di-

screteion. Se lo ione e atomico allora lo si compone con un bigrafo costruito ad-hoc

per rimuovere il sito

tensor: bg TENSOR bg { try ($1#tensor $3)

with Bigraphs_are_not_disjoint ->

raise (Malformed_Tensor (location (Parsing.rhs_start_pos 2)))}

;

osp: bg OSP bg { try ($1#osp $3)

with Bigraphs_are_not_disjoint ->

raise (Malformed_Osp (location (Parsing.rhs_start_pos 2)))}

;

isp: bg ISP bg { try ($1#isp $3)

with Bigraphs_are_not_disjoint ->

raise (Malformed_Isp (location (Parsing.rhs_start_pos 2)))}

;

sp: bg SP bg { try ($1#sp $3)

with Bigraphs_are_not_disjoint ->

raise (Malformed_Sp (location (Parsing.rhs_start_pos 2)))}

;

posp: bg POSP bg { try ($1#posp $3)

with Bigraphs_are_not_disjoint ->

raise (Malformed_Posp (location (Parsing.rhs_start_pos 2)))}

;

psp: bg PSP bg { try ($1#psp $3)

with Bigraphs_are_not_disjoint ->

raise (Malformed_Psp (location (Parsing.rhs_start_pos 2)))}

;

composition: bg COMPOSITION bg { try ($1#composition $3)

with Bigraphs_have_no_common_interface ->

raise (Malformed_Composition (location (Parsing.rhs_start_pos 2)))}

;

Queste produzioni gestiscono le operazioni tra bigrafi in accordo con quanto visto in

4.2.2.3 usando le operazioni della struttura dati che implementa i bigrafi diretti. In

caso di errori nell’esecuzione delle operazioni il parser solleva le eccezioni adeguate.

4.3. ASPETTI IMPLEMENTATIVI 77

4.3.2.4 Differenze per la generazione del programma ocaml

Anche in questo caso le differenze sono minime. La chiamata effettiva alla funzione

dell’algebra o della struttura dati che implementa i bigrafi diretti e sostituita con

una stringa con il testo della chiamata stessa. Nel programma ocaml generato c’e la

definizione di due funzioni senza parametri: compiledsignature e compiledbigraph.

Queste funzioni restituiscono rispettivamente la signature e il bigrafo descritti nel

sorgente dbpl.

4.3.3 L’interfaccia del compilatore

L’interfaccia del compilatore e formata da quattro funzioni che differiscono per i

parametri che prendono e il valore restituito.

let compilefromfile file =

let inChannel = open_in file in

let lexbuf = Lexing.from_channel inChannel in

Dbplparser.dbpl Dbpllexer.token lexbuf;;

Questa funzione legge il sorgente DBPL dal file specificato dal parametro e restituisce

la coppia (signature, bigrafo) generata dal parser.

let compilefromstring string =

let lexbuf = Lexing.from_string string in

Dbplparser.dbpl Dbpllexer.token lexbuf;;

Questa funzione e simile alla prima ma legge il sorgente dalla stringa passata come

parametro

let compilefromfile2ocaml filein fileout =

let inChannel = open_in filein in

let outChannel = open_out fileout in

let lexbuf = Lexing.from_channel inChannel in

Printf.fprintf outChannel "%s\n"

(Dbplparser2ocaml.dbpl Dbpllexer2ocaml.token lexbuf);;

Questa funzione legge il sorgente DBPL dal file specificato nel parametro e scrive il

risultato nel file specificato dal secondo parametro

78 CAPITOLO 4. IL LINGUAGGIO ED IL COMPILATORE

let compilefromstring2ocaml string fileout =

let outChannel = open_out fileout in

let lexbuf = Lexing.from_string string in

Printf.fprintf outChannel "%s\n"

(Dbplparser2ocaml.dbpl Dbpllexer2ocaml.token lexbuf);;

Infine questa funzione e simile alla precedente ma legge il sorgente dalla stringa

passata come parametro.

5Il decompilatore

In questo capitolo sara presentato il decompilatore. Esso svolge il ruolo inverso

del compilatore. Data una signature e un bigrafo, si occupa produrre una stringa

contenente codice DBPL. La compilazione di tale codice produrra una signature

ed un bigrafo uguali a quelli di partenza a meno dei nomi di nodi ed archi. Il

decompilatore e eseguito chiamando la sua funzione principale:

val printDBPL :

< getsigns : (string * (string * int)) list;

typeof : string -> int -> string; .. > ->

Bigraph.directedbg -> string

tale funzione ha due parametri: la classe delle signature e il bigrafo da decom-

pilare. La funzione chiama le funzioni printsignature e printBG per stampare le

componenti della signature e il bigrafo, rispettivamente.

5.1 Decompilazione della signature

La decompilazione della signature e molto semplice ed e implementata da questa

funzione:

val printsignature : (string * (string * int)) list -> string list

l’unico parametro della funzione e l’insieme degli elementi che compongono la

signature sotto forma di lista (tale lista e ottenuta chiamando il metodo getsigns

della classe signatures). Per ogni elemento la funzione costruisce una stringa secondo

la sintassi vista in 4.2.2.1. La funzione restituisce una lista di stringhe dove ogni

elemento della lista e un elemento della signature. Tale lista e convertita in una

stringa usando la funzione concat del modulo String (tale funzione si occupa anche

di inserire le virgole che separano gli elementi della signature).

80 CAPITOLO 5. IL DECOMPILATORE

5.2 Decompilazione del bigrafo

La decompilazione del bigrafo e implementata in questa funzione che prende come

parametri il bigrafo da decompilare e la classa delle signatures:

val printBG :

Bigraph.directedbg -> < typeof : string -> int -> string; .. >

-> string

per prima cosa si scompone il bigrafo passato come parametro nelle tre compo-

nenti che formano la forma normale. Successivamente la componente w e passata

alla funzione printW, mentre la componente d (composta con la componente w’ op-

portunamente modificata per semplificare il lavoro) e passata alla funzione printD.

Le funzioni printW e printD si occupano di produrre il codice DBPL che descrive il

bigrafo sotto forma di operazioni tra i bigrafi elementari visti nella sezione 4.2.2.2.

Una volta ottenute le stringhe che rappresentano questi bigrafi si controlla quali

componenti sono presenti e quali no per evitare di inserire simboli di composizione

non necessari.

5.2.1 Componente w

La funzione printW si occupa di produrre il codice DBPL che descrive la componente

W. Questa funzione prende come parametri la lista dei link e il numero di radici

presenti nella componente d

val printW : (Bigraph.tpoint * Bigraph.tlink) list -> int -> string

La funzione prima chiama linksdest per ottenere la lista delle coppie (destinazione

del link, tipo destinazione) e una tabella hash che associa ad ogni destinazione la

sorgente del link e il suo tipo. Questa lista e la tabella sono passate alla funzione

printW2 che per ogni destinazione di un link produce il codice che genera l’apposito

bigrafo elementare. La lista di stringhe con il codice DBPL e concatenata (se esiste)

con i simboli di tensore. Se la componente d ha delle radici, alla stringa appena

generata si aggiunge in coda un tensore con un bigrafo merge per permettere poi la

composizione della componente w con la componente d.

val printW2 :

(string * string) list -> (string, string * string) Hashtbl.t

-> string list

Questa e la funzione printW2. Essa prende come parametri la lista delle desti-

nazioni con il loro tipo e la tabella generata nella funzione printW. Questa funzione

5.2. DECOMPILAZIONE DEL BIGRAFO 81

si limita a chiamare per ogni destinazione di link nella lista la funzione printW3

passandole come parametro la destinazione in fase di elaborazione, il suo tipo e la

lista delle sorgenti dei link con quella destinazione (e il loro tipo).

val printW3 : string -> string -> (string * string) list -> string

Questa e la funzione che si occupa di generare il codice DBPL per i vari bigrafi

che formano la componente w. Il tipo della destinazione serve per determinare

quale bigrafo generare: se la destinazione e un arco allora bisogna generare un

bigrafo closure, se e un nome di interfaccia esterna verso l’alto bisogna generare un

bigrafo substitution, altrimenti bisogna generare un bigrafo fusion. Due chiamate a

namesoftype permettono di individuare i nomi che andranno a formare l’interfaccia

esterna e interna. Una volta ottenuti questi dati e possibile produrre il codice DBPL

opportuno.

5.2.2 Componente d

La funzione printD si occupa di produrre il codice DBPL relativo alla componente

D. Tale funzione prende come parametri il parent graph della componente, il link

graph della componente, la mappa di controllo, il numero di radici e la classe del-

le signatures. La funzione restituisce la stringa contenente il codice DBPL della

componente.

val printD :

Bigraph.tplace list ->

(Bigraph.tpoint * Bigraph.tlink) list ->

(string * ’a) list ->

int -> < typeof : string -> ’a -> string; .. > -> string

La funzione inizia creando la lista delle radici e due tabelle hash: la prima associa

ad ogni elemento padre del place graph la lista dei figli; la seconda associa ad ogni

nodo la porta, la destinazione e il tipo della destinazione di ogni link che parte da

quel nodo. Poi si chiama la funzione printroots che restituisce una lista di stringhe

dove ogni elemento e il codice DBPL che rappresenta una radice. Infine si chiama

passthroughlink per ottenere il codice DBPL per rappresentare i link che vanno da

un nome di interfaccia interna verso l’alto ad un nome di interfaccia esterna verso

l’alto e i link vanno da un nome di interfaccia esterna verso il basso ad un nome di

interfaccia interna verso il basso.

val printroots :

int list ->

82 CAPITOLO 5. IL DECOMPILATORE

(Bigraph.tprnt, Bigraph.tprnt) Hashtbl.t ->

(string, ’a * string * string) Hashtbl.t ->

(string * ’b) list -> < typeof : string -> ’b -> string; .. >

-> string list

Questa funzione scorre la lista delle radici e, per ogni radice della lista, produce il

codice DBPL che descrive tutti i figli della radice stessa. Per prima cosa si estrae la

lista dei figli della radice dalla tabella hash. Se la lista contiene almeno un elemento

si chiama la funzione printson che produce il codice relativo ai figli. Se invece la

radice non ha figli si genera semplicemente il codice per un bigrafo vuoto e si passa

alla radice successiva.

val printson :

Bigraph.tprnt list ->

(Bigraph.tprnt, Bigraph.tprnt) Hashtbl.t ->

(string, ’a * string * string) Hashtbl.t ->

(string * ’b) list ->

< typeof : string -> ’b -> string; .. > -> string list

-> string list

Questa funzione produce il codice DBPL relativo agli elementi presenti in una

lista passata come parametro. Se la lista e vuota allora produco il codice per generare

gli eventuali link verso il basso presenti. Se l’elemento attuale e un sito allora

costruisco la stringa che lo descrive aggiungendo una permutazione per aggiustare il

numero del sito. Se l’elemento attuale e un nodo allora procedo come segue:

1. determino l’arieta del nodo

2. cerco tutti i link che partono dal nodo e costruisco la lista ctrllist

3. se il nodo ha dei figli allora determino la lista di tutti i link verso l’alto di tutti

i figli

4. genero il codice per uno discrete ion

5. aggiungo l’eventuale codice per la lista dei links dei figli

6. compongo l’ion con il risultato della chiamata ricorsiva della funzione applicata

ai figli di questo nodo

7. se il nodo non ha figli genero semplicemente il codice per uno discrete ion

5.3. FUNZIONI AUSILIARIE 83

Se non rientro in uno dei casi precedenti scarto l’elemento e proseguo con la chiamata

ricorsiva

5.3 Funzioni ausiliarie

In questa stezione saranno descritte tutte le funzioni ausiliarie utilizzate dal decom-

pilatore

val filterlink : (’a * ’b * ’c) list -> ’c -> ’b list

Questa funzione prende come parametro una lista di triple (porta di partenza,

nome di destinazione, tipo) e un tipo di nome. Produce una lista di nomi destinazioni

di link il cui tipo e uguale al tipo passato come parametro

val sonslink :

Bigraph.tprnt ->

(string, ’a * ’b * string) Hashtbl.t ->

(Bigraph.tprnt, Bigraph.tprnt) Hashtbl.t -> ’b list

val sonslink1 :

Bigraph.tprnt list ->

(string, ’a * ’b * string) Hashtbl.t ->

(Bigraph.tprnt, Bigraph.tprnt) Hashtbl.t -> ’b list

Queste due funzione mutuamente ricorsive creano una lista di link verso nomi

di interfaccia esterna verso l’alto e che partono da tutti i figli di un certo elemento

passato come parametro.

val printionlinks : (’a * string * string) list -> string list

Questa funzione costruisce una ctrllist per un certo ion. Prende come parametro

una lista di triple (porta di partenza, nome di destinazione, tipo) e restituisce la

lista dei nomi di destinazione preceduti dai simboli “+” o “-” a seconda del tipo del

nome.

val printlinks : string list -> string -> string list

Questa funzione genera il codice di bigrafi substitution o fusion. Prende come

parametro una lista di nomi e una stringa che puo essere “+” o “-”. Per ogni

elemento della lista di nomi, genera il codice per un bigrafo substitution (se il secondo

parametro e “+”) o fusion (se il secondo parametro e “-”) usando l’elemento della

lista come nome sia d’interfaccia interna che esterna

val linkcompare : ’a * ’b * ’c -> ’a * ’d * ’e -> int

84 CAPITOLO 5. IL DECOMPILATORE

Questa funzione confronta due link in base al numero della porta di partenza. I

due link sono espressi sotto forma di triple (porta di partenza, nome di destinazione,

tipo). Tale funzione e usata per ordinare questo tipo di liste di link.

val linksdest :

(string, string * string) Hashtbl.t ->

(Bigraph.tpoint * Bigraph.tlink) list -> (string * string) list

Questa funzione crea una tabella hash che associa ad ogni nome di destinazione

il nome sorgente e il suo tipo. Restituisce una lista di coppie (destinazione, tipo

destinazione).

val namesoftype : (’a * ’b) list -> ’b -> ’a list

Questa funzione restituisce una lista di nomi sorgenti di link in base al loro tipo.

val hashprnt :

(Bigraph.tprnt, Bigraph.tprnt) Hashtbl.t ->

Bigraph.tplace list -> (Bigraph.tprnt, Bigraph.tprnt) Hashtbl.t

Questa funzione crea una tabella hash che associa ad ogni padre la lista dei suoi

figli.

val hashlink :

(string, int * string * string) Hashtbl.t ->

(Bigraph.tpoint * Bigraph.tlink) list ->

(string, int * string * string) Hashtbl.t

Questa funzione crea una tabella hash che associa ad ogni nodo la lista dei link

che partono da esso assieme alla porta di partenza e il tipo di link.

val findsites : Bigraph.tplace list -> int list

Questa funzione scorre il parent graph per trovare tutti i siti di un bigrafo.

val makebg : int list -> Bigraph.directedbg

val makebgaux : < addprntsiteroot : ’a -> ’a -> ’b; .. > ->

’a list -> unit

Queste due funzioni creano un bigrafo da usare per poter comporre la compo-

nente d con la componente w’.

val makerootlist : int -> int list -> int list

Questa funzione costruisce una lista di interi 0..n.

5.4. ESEMPO DI OUTPUT 85

y1

e3

e2

e0

e1

v4v5

v0v1

v2v3

Figura 5.1: Bigrafo d’esempio per il decompilatore

5.4 Esempo di output

In questa sezione sara mostrato l’output prodotto dal decompilatore dato un bigrafo.

Il bigrafo in figura 5.1 puo essere scritto in DBPL in questo modo:

Signature [active t4:1,atomic t5:1,atomic t2:2];

let a=merge 1|X[x,z]|(y1X[a,y]*t4 [-w])°(w\w*merge 1|t5 [+a]*y/y) in

let b=(((wX[b,c]*merge 1)°(b/b*t4 [+c])°t2 [+b,-d]|t2 [+x,-e])°([d,e]X)) in

let c = t2 [+z,+y] in

a°(b*c)

Per questo bigrafo il decompilatore produrra questo codice:

Signature [atomic t2:2,active t4:1,atomic t5:1];

(X[w3,w2]*X[w6,w4]*y1X[w7,w5]*X[w8,w1,w0]* merge 1)°

(((t4 [+w8]*w7/w7*w5/w5*w4/w4)°(t5 [+w7]|t2 [+w4,+w5])|

(t4 [+w1]*w3/w3*w0/w0)°(t2 [+w0,+w3])|t2 [+w6,+w2]))

86 CAPITOLO 5. IL DECOMPILATORE

6Il visualizzatore

In questo capitolo sara presentato il visualizzatore. Questo programma permette di

visualizzare un bigrafo qualsiasi sotto forma di immagine SVG. E stato scelto tale

formato principalmente per tre motivi:

• una immagine SVG e un file XML

• le immagini SVG sono immagini vettoriali. Questo significa che possono essere

ingrandite a piacere

• tali immagini possono essere visualizzate con un browser web che supporti tale

formato (nativamente o con un plug-in)

La generazione del codice svg e suddivisa in tre fasi: generazione del codice relativo

al place graph, posizionamento di archi e nomi e generazione del codice per i link. I

dati necessari per stampare il place graph sono inseriti in un albero di tipo datatree

cosı definito:

type datatree =

Elem of (Bigraph.tprnt * float * float *

float * float * datatree list);;

Il primo campo e l’elemento del place graph (puo essere una radice, un sito oppure

un nodo). I quattro successvi sono rispettivamente posizione orrizzontale, posi-

zione verticale, larghezza ed altezza dell’elemento e l’ultimo e una lista dei figli

dell’elemento.

6.1 Funzione principale

Il visualizzatore ha una funzione d’interfaccia principale: dbg2svg. Tale funzione

prende come parametro il bigrafo da disegnare e restituisce una stringa contenente

il codice SVG che rappresenta il bigrafo.

88 CAPITOLO 6. IL VISUALIZZATORE

val printBG :

Bigraph.directedbg -> string

La funzione opera in questo modo:

1. Estrae il place graph e il link graph dal bigrafo. Le informazioni del place

graph sono inserite in una tabella hash che associa ad ogni padre la lista dei

figli

2. Genera la lista delle radici

3. Crea l’albero “printpgraphgrezzo”. Tale albero e una rappresentazione del

place graph con l’aggiunta di dimensioni e posizioni di default degli elementi.

Se il bigrafo non contiene almeno una radice allora si inserisce una radice

fittizia per contenere gli eventuali link

4. Genera una lista di archi e calcola la loro dimensione totale in pixel. Questo

serve per determinare la minima spaziatura tra i nodi quando si dovra inserire

gli archi nell’immagine SVG

5. Calcola la lunghezza minima di una radice in base alle dimensioni richieste per

inserire tutti i nomi di interfaccia esterna ed interna relativi a quella radice.

Un nome sara disegnato sopra o sotto una radice se c’e almeno un link che

arriva a quel nome partendo da uno dei figli di quella radice. I link che non

partono da nodi sono considerati relativi alla prima radice

6. Calcola le dimensioni di tutti gli elementi che compongono il place graph. Tali

informazioni sono inserite nell’albero generato in precedenza

7. Imposta la stessa altezza in pixel per tutte le radici

8. Determina la posizione assoluta degli elementi del place graph in base alle loro

dimensioni

9. Determina la posizione di nomi ed archi

10. Chiama le funzioni che si occupano di generare il codice SVG per tutti gli

elementi del bigrafo usando i dati calcolati in precedenza

6.2 Codice per il place graph

La generazione del codice per il place graph e eseguita da due funzioni mutuamente

ricorsive. La prima si occupa di chiamare la seconda su ogni elemento di una lista

6.3. POSIZIONI DI ARCHI E NOMI 89

alberi di tipo datatree mentre la seconda genera il codice per quell’elemento e chiama

la prima sui figli dell’elemento.

val printpgraph : datatree list -> string

val printpgraph2 : datatree -> string

Le funzioni sono molto semplici. In base all’elemento attuale si decide che figura

SVG generare: rettangoli per radici e siti, ellissi per i nodi. La seconda funzione si

occupa anche di inserire sotto forma di testo i numeri che indentificano radici e siti

e le stringhe che identificano i nodi.

6.3 Posizioni di archi e nomi

Questa fase ha come scopo deteminare le coordinate dove disegnare tutti gli archi

e nomi ed usa principalmente tre funzioni: rootlinkslength, placelinks e placeedges.

La prima funzione decide in quali radici andranno disegnati i nomi, la lunghezza

minima di ogni radice per contenere i nomi necessari e prepara una lista che conterra

le coordinate dove disegnare ogni nome.

val rootlinkslength :

datatree list ->

(Bigraph.tpoint * Bigraph.tlink) list ->

Bigraph.StringSet.t ->

Bigraph.StringSet.t ->

Bigraph.StringSet.t ->

Bigraph.StringSet.t -> int -> (int * float * float) list

Questa funzione prende come parametri l’algebero grezzo, la lista dei link, le

liste dei quattro tipi di nomi. L’ultimo parametro serve per gestire l’inserimento dei

link che non partono da nodi nella prima radice. La funzione restituisce una lista

che associa ad ogni radice la larghezza minima che deve avere per contenere i nomi

dell’interfaccia estera ed interna. Inoltre inizializza una lista globale che associa

ad ogni nome la radice di cui fara parte, le coordinate di default e il suo tipo. La

funzione inizia determinando tutti i suoi nodi figli (con la funzione allnodes) e i nomi

destinazioni di link che partono dai nodi appena trovati (con la funzione rootlinks)

inserendo i dati necessari nella lista globale. Successivamente determina i nomi di

interfaccia esterna verso l’alto e di interfaccia interna verso il basso che non partono

dai nodi. Tali nomi sono inseriti nella lista globale. Infine con i dati raccolti si

calcola la lunghezza totale delle due interfaccie della radice (i nomi di interfaccia

90 CAPITOLO 6. IL VISUALIZZATORE

esterna verso l’alto e di interfaccia interna verso il basso che non partono dai nodi

contribuiscono a questo calcolo solo per la prima radice).

La funzione placelinks si occupa di completare i dati ottenuti dalla lista globale

con le coordinate dei nomi.

val placelinks :

datatree list ->

(string * (int * ’a * ’b * string)) list ->

(string * (float * float * string)) list

val placelinks2 :

(string * (’a * ’b * ’c * string)) list ->

float -> float -> float -> (string * (float * float * string)) list

val allnamescmp :

’a * (’b * ’c * ’d * string) -> ’e * (’f * ’g * ’h * string) -> int

Placelinks prende come parametri l’albero e la lista globale e usa placelinks2 per

calcolare le coordinate dei nomi di ogni radice. I nomi sono ordinati (usando allna-

mescmp per i confronti) in modo che siano considerati prima i nomi di interfaccia

esterna verso il basso e i nomi di interfaccia interna verso l’alto. Placelinks2 imposta

le coordinate di ogni nome in base all’interfaccia di appartenenza, la lunghezza del

nome e una spaziatura minima tra ogni nome

Infine placeedges si occupa di determinare le coordinate per la stampa di ogni

arco. Questa funzione prende come parametri la lista degli archi e l’albero con la

prima radice e restituisce una coppia dove il primo elemento e una lista che associa

ad ogni arco le sue coortinate e la seconda e il codice SVG che disegna l’arco.

La funzione disegna gli archi nella prima radice tra il primo e il secondo nodo, se

presenti. La funzione placeedges2 si occupa di generare concretamente la lista di

associazione e il codice SVG.

val printedges :

string list ->

datatree -> float -> ((string * (float * float)) * string) list

val printedges2 :

string list -> float -> float

-> ((string * (float * float)) * string) list

6.4. CODICE PER I LINK 91

6.4 Codice per i link

La generazione del codice SVG per i link e gestita dalla funzione printlink che prende

come parametri l’albero con i dati del place graph, la lista di tutti i link del bigrafo,

due liste con i dati sulle posizioni di nomi ed archi e l’altezza in pixel delle radici.

val printlink :

datatree list ->

(Bigraph.tpoint * Bigraph.tlink) list ->

(string * (float * float * string)) list ->

(string * (float * float)) list -> float -> string

Molto semplicemente la funzione costruisce una tabella ausiliaria con i dati sulle

coordinate di partenza dei link che partono da nodi (usando le funzioni countocc e ha-

shtree, descritte nella sezione 6.5) e chiama printlink2 che si occupa della generazione

del codice SVG a partire da questi dati.

La funzione printlink2 prende come parametri la lista di tutti i link, una tabella

con le informazioni sulle coordinate di partenza dei link che partono da nodi, i dati

sulle posizioni di nomi e archi e l’altezza delle radici. Il suo codice e questo:

val printlink2 :

(Bigraph.tpoint * Bigraph.tlink) list ->

(string,

float * float * float * float * float * float * float * float *

float * float * float)

Hashtbl.t ->

(string * (float * float * string)) list ->

(string * (float * float)) list -> float -> string

La funzione detemina il codice da generare in base alla sorgente e alla destina-

zione dei link. Per i link che partono da nodi prima si determinano le coordinate di

partenza estraendole dalla tabella hash passata come parametro. Poi si deteminano

le coordinate di destinazione estraendole dalla liste passate come parametro a secon-

da della destinazione del link (nms per i nomi, edg per gli archi). Poi si aggiorna la

tabella hash inserendo il nuovo punto di partenza per il successivo link dello stesso

tipo e infine si genera il codice SVG usando i dati appena estratti e aggiungendo

punti intermedi per evitare le sovrapposizioni. Per i link che partono di nomi basta

estrarre le coordinate di partenza e destinazione dalle liste passate come parametro

e generare il codice SVG come appena visto per i nodi. Alla fine di ogni caso c’e la

92 CAPITOLO 6. IL VISUALIZZATORE

chiamata ricorsiva per generare il codice del link successivo.

6.5 Altre funzioni

In questa sezione saranno descritte tutte le altre funzioni usate dal visualizzatore

val hashprnt :

(Bigraph.tprnt, Bigraph.tprnt) Hashtbl.t ->

Bigraph.tplace list -> (Bigraph.tprnt, Bigraph.tprnt) Hashtbl.t

Questa funzione crea una tabella hash che associa ad ogni elemento padre la lista

dei figli

val filltree :

Bigraph.tprnt list ->

(Bigraph.tprnt, Bigraph.tprnt) Hashtbl.t -> datatree list

val filltree2 :

Bigraph.tprnt -> (Bigraph.tprnt, Bigraph.tprnt) Hashtbl.t

-> datatree

Queste due funzioni creano l’albero grezzo che contiene solo il place graph e le

dimensioni di default degli elementi. filltree si occupa di chiamare filltree2 per ogni

elemento padre del place graph. filltree2 costruisce l’albero grezzo con le dimensioni

di default degli elementi e chiama ricorsivamente filltree per costruire l’albero con i

dati dei figli

val fixsize : datatree list -> (int * float) list -> float

-> datatree list

val fixsize2 : datatree -> (int * float) list -> float -> datatree

val xsize :

datatree list ->

(int * float) list -> float -> float * datatree list

val xsize1 : datatree list -> float

Queste funzioni si occupano di calcolare le dimensioni minime di ogni elemento

dell’albero in funzione delle dimensioni dei figli. fixsize si occupa di chiamare fixsize2

su ogni elemento della lista di datatree passata come parametro. fixsize2 calcola la

dimensione di ogni elemento in base alle dimensioni dei figli. La funzione xsize e

usata per ottenere questi dati. xsize restituisce una coppia formata dalla larghezza

totale dei figli e dal datatree dei figli con le dimensioni gia calcolate. Per ottenere il

6.5. ALTRE FUNZIONI 93

datatree dei figli xsize chiama ricorsivamente fixsize. Per ottenere la larghezza totale

dei figli xsize chiama xsize1 la quale si limita a sommare le larghezze degli elementi

presenti in una lista di datatree.

val heights : datatree list -> float list

Questa funzione crea una lista con le altezze di tutte le radici.

val fixheight : datatree list -> datatree list

Questa funzione imposta l’altezza di una radice in modo tale che ci sia una

spaziatura di 60 pixel sopra e sotto il suo nodo figlio piu alto. Per fare cio scorre la

lista dei datatree passata come parametro e per ogni radice imposta la sua altezza

a 120 pixel piu l’altezza del figlio piu alto.

val setrootsheight : datatree list -> float -> datatree list

Questa funzione imposta l’altezza delle radici ad un valore passato come para-

metro. E usata per uniformare l’altezza di tutte le radici.

val fixpos : datatree list -> float -> float -> float

-> datatree list

val fixpos2 : datatree -> float -> float -> float -> float

-> datatree

val fixpos3 :

datatree list ->

float -> float -> float -> float -> float -> datatree list

Queste tre funzioni si occupano di calcolare la posizione assoluta di ogni elemento

del datatree in base alle sue dimensioni. fixpos chiama fixpos2 su ogni elemento

della lista di datatree passata come parametro e si assicura che tutte le radici siano

distanziate orrizzontalmente di 20 pixel. fixpos2 e fixpos3 si chiamano mutuamente

per calcolare le posizioni dei figli di una radice. I figli di una radice sono distanziati

di 60 pixel. I figli dei figli (e tutto il resto della discendenza) sono distanziati di 30

pixel.

val allnodes : datatree list -> string list

Questa funzione crea una lista di nomi di nodi scandendo l’albero passato come

parametro.

val filterlinksfromport :

(Bigraph.tpoint * Bigraph.tlink) list -> string list -> string

-> string list

94 CAPITOLO 6. IL VISUALIZZATORE

Questa funzione crea una lista di destinazioni di link che partono da nodi che

appartendono ad una certa radice e sono del tipo passato come parametro.

val nonportlinks :

(Bigraph.tpoint * Bigraph.tlink) list -> string

-> (string * string) list

Questa funzione crea una lista di coppie (destinazione, tipo) che contiene solo

destinazioni di link di un certo tipo e che partono da nomi.

val eqtn : float -> float -> float -> float -> float -> float

-> float

Questa funzione calcola la coordinata y di un punto che appartiene ad una ellisse

dati i suoi parametri. E usata per determinare il punto sorgente di un link durante

la stampa del codice SVG dei link.

val thisrootlinks :

’a -> (’b * (’a * ’c * ’d * ’e)) list

-> (’b * (’a * ’c * ’d * ’e)) list

Questa funzione individua tutti i link che partono dai figli di una radice passata

come parametro. I link sono espressi con una lista che associa il nome di destinazione

alla radice a cui appartiene, alle sue coordinate (del nome) e il tipo del link.

val printnames : (string * (float * float * ’a)) list -> string

Questa funzione genera il codice SVG per disegnare un nome. I dati sono forniti

da una lista che associa ad ogni nome le coordinate dove disegnarlo.

val findinlist :

’a -> (’a * (float * float * ’b)) list -> ’b -> float * float

Questa funzione, dato un nome, trova le sue coordinate.

val countocc :

(string, float * float * float) Hashtbl.t ->

(Bigraph.tpoint * Bigraph.tlink) list ->

(string, float * float * float) Hashtbl.t

Questa funzione conta quanti link partono da un nome e vanno in un nome

d’interfaccia esterna verso l’alto, in un nome di interfaccia interna verso il basso e

in un arco.

val hashtree :

datatree list ->

(string,

6.5. ALTRE FUNZIONI 95

float * float * float * float * float * float * float * float *

float * float * float)

Hashtbl.t -> (string, float * float * float) Hashtbl.t -> unit

Questa funzione calcola la spaziatura minima necessaria per disegnare tutti i link

che partono da un nodo.

val edges : (Bigraph.tpoint * Bigraph.tlink) list -> string list

Questa funzione genera una lista con tutti gli archi del bigrafo.

val rootlinks :

string list ->

(Bigraph.tpoint * Bigraph.tlink) list -> string list -> string

-> string list

Questa funzione trova tutti i nomi che sono destinazioni di link che partono dai

nodi figli di una data radice.

val makelist : ’a list -> ’b -> ’c

-> (’a * (’b * float * float * ’c)) list

Questa funzione crea una lista grezza che associa ad ogni nome la radice in cui

si trova, le coordinate di default e il suo tipo.

val in_allnodes_list : ’a -> (’a * (’b * ’c * ’d * ’e)) list -> bool

Questa funzione determina se un nome appariene ad una lista di nomi.

val singleallnodes :

(’a * (’b * ’c * ’d * ’e)) list -> (’a * (’b * ’c * ’d * ’e)) list

Questa funzione elimina i duplicati da una lisa di nomi.

val linksfromname :

(Bigraph.tpoint * Bigraph.tlink) list -> string -> string list

Questa funzione trova i nomi destinazioni di link che partono da un nome e sono

di un dato tipo.

val difference : ’a list -> ’a list -> ’a list

Questa funzione i nomi destinazione di link che non sono gia destinazioni di link

che partono da un nodo.

val maxvalue : (’a * ’b * ’b) list -> (’a * ’b) list

Questa funzione calcola la larghezza minima di una radice in base alla lunghezza

dei nomi che compongono le due interfaccie del bigrafo.

val makerootlist : int -> int -> Bigraph.tprnt list

Questa funzione crea una lista [0..n].

96 CAPITOLO 6. IL VISUALIZZATORE

Figura 6.1: Bigrafo d’esempio in SVG

6.6 Esempio di output

Avendo a disposizione il compilatore DBPL e il visualizzatore e possibile combinarli

per creare un programma che, dato bigrafo in DBPL, produca la corrispondente

immagine SVG. Una funzione che implementa questo programma e:

let drawbg =

let out = open_out (Sys.argv.(2)) in

let bg = (snd(compilefromfile (Sys.argv.(1)))) in

Printf.fprintf out "%s" (dbg2svg bg);;

Dato questo codice DBPL:

Signature [active t4:1,atomic t5:1,atomic t2:2];

let a=merge 1|X[x,z]|(y1X[a,y]*t4 [-w])°(w\w*merge 1|t5 [+a]*y/y) in

let b=(((wX[b,c]*merge 1)°(b/b*t4 [+c])°t2 [+b,-d]|t2 [+x,-e])°([d,e]X)) in

let c = t2 [+z,+y] in

a°(b*c)

il bigrafo corrispondente e mostrato in figura 6.1

7Conclusioni

In questo lavoro e stata presentata una implementazione degli strumenti per utiliz-

zare in modo semplice il meta-modello dei bigrafi diretti; in particolare e stato pro-

gettato un linguaggio per la descrizione dei bigrafi diretti e sono stati implementati

il compilatore, il decompilatore e il visualizzatore.

Il linguaggo per bigrafi diretti, chiamato DBPL, e un linguaggio simile ad un

linguaggio di programmazione funzionale e consente di descrivere la signature di

controllo e bigrafi diretti qualsiasi ottenuti dai bigrafi elementari e dalle operazioni

su di essi. Il linguaggio consente anche la denominazione dei bigrafi per riusarli in

seguito.

Il compilatore implementa il linguaggio per i bigrafi ed e formato da un ana-

lizzatore lessicale, un parser e un insieme di funzioni d’interfaccia. Il compilatore

puo generare gli oggetti OCaml corrispondenti alla signature e al bigrafo oppure un

programma OCaml. In tale programma sono definite due funzioni che restituiscono

la signature e il bigrafo descritti nel sorgente compilato.

Il decompilatore svolge il ruolo inverso del compilatore. Dato un bigrafo e una

signature, il decompilatore genera il relativo sorgente DBPL.

Infine il visualizzatore e in grado di produrre una immagine SVG corrispondente

ad un dato bigrafo. L’immagine e manipolabile con i programmi che supportano

tale formato ed e visualizzabile con un semplice browser web.

I lavori futuri si dividono in due parti: completamento delle funzioni di libreria

e completamento degli strumenti di sviluppo.

La prima parte prevede la realizzazione delle funzioni che costruiscono gli IPO e

che rendono possibile il matching dei bigrafi. Queste funzioni sono complementari

agli RPO per la costruzione degli LTS. Il matching dei bigrafi e usato per le rea-

zioni. Trovando combinazioni note di elementi in un bigrafo, se esiste una regola di

reazione, esse possono essere riscritte come il risultato di queste reazioni. Una vol-

98 CAPITOLO 7. CONCLUSIONI

ta implementato il matching sara possibile scrivere dei simulatori. Questo lavoro e

stato fatto da Birkedal, Damgaard, Glenstrup, Milner in [1] per i bigrafi non diretti.

La seconda parte prevede il completamento degli strumenti per usare il bigrafi

diretti, in particolare l’interfaccia grafica. L’interfaccia permettera agli utenti di

disegnare facilmente un bigrafo e di esportarlo sotto forma di sorgente DBPL. Per

l’implementazione di tale interfaccia si e pensato di usare il linguaggio Java e i

framework JGraph e JGraphpad [aggiungere riferimento], framework che servono

per realizzare editor di grafi generici.

L’obiettivo e realizzare una interfaccia simile all’interfaccia BPLweb per i bigrafi

non diretti disponibile su http://tiger.itu.dk:8080/bplweb/.

ASorgenti del compilatore

A.1 Generazione delle coppie (signature,bigrafo)

A.1.1 Analizzatore lessicale

{

open Dbplparser

exception Unknown_Symbol of (int*int);;

let incr_linenum lexbuf =

let pos = lexbuf.Lexing.lex_curr_p in

lexbuf.Lexing.lex_curr_p <- { pos with

Lexing.pos_lnum = pos.Lexing.pos_lnum + 1;

Lexing.pos_bol = pos.Lexing.pos_cnum;

}

;;

}

let num = [’0’-’9’] | [’1’-’9’][’0’-’9’]+

let name = [’a’-’z’][’a’-’z’ ’A’-’W’ ’Y’-’Z’ ’0’-’9’]*

let sign = ’+’ | ’-’

rule token = parse

| [’ ’ ’\t’] { token lexbuf }

| ’\n’ { incr_linenum lexbuf; token lexbuf }

| "merge" { MERGE }

| "Signature" { SIGNATURE }

| "active"

| "passive"

| "atomic" as sigtype { SIGTYPE (sigtype) }

100 APPENDICE A. SORGENTI DEL COMPILATORE

| "in" { IN }

| "let" { LET }

| num as n { NUM(int_of_string n) }

| name as nm { NAME(nm) }

| sign as sn { SIGN (String.make 1 sn) }

| "=" { EQ }

| "[" { LSB }

| "]" { RSB }

| "," { COMMA }

| ":" { COLON }

| ";" { SEMICOLON }

| "*" { TENSOR }

| "°" { COMPOSITION }

| "/\\" { OSP }

| "\\/" { ISP }

| "||" { SP }

| "/^\\" { POSP }

| "|" { PSP }

| "/" { SUBSTITUTION }

| "\\" { FUSION }

| "(" { LRB }

| ")" { RRB }

| "X" { CLOSURE }

| "@" { PERMUTATION }

| eof { EOF }

| _ { raise (Unknown_Symbol

(lexbuf.Lexing.lex_curr_p.Lexing.pos_lnum,

(lexbuf.Lexing.lex_curr_p.Lexing.pos_cnum-

lexbuf.Lexing.lex_curr_p.Lexing.pos_bol))) }

A.1.2 Parser

%{

open String

open Algebra

open Bigraph

A.1. GENERAZIONE DELLE COPPIE (SIGNATURE,BIGRAFO) 101

exception Unbound_Bigraph of (int*int)

exception Malformed_Dbpl of (int*int)

exception Malformed_Signature of (int*int)

exception Malformed_Signature_Element of (int*int)

exception Malformed_SiteSet of (int*int)

exception Malformed_SiteSet_Element of (int*int)

exception Malformed_IonLinkList of (int*int)

exception Malformed_IonLinkList_Element of (int*int)

exception Malformed_NameSet of (int*int)

exception Malformed_NameSet_Element of (int*int)

exception Malformed_Bigraph of (int*int)

exception Malformed_Merge of (int*int)

exception Malformed_Ion of (int*int)

exception Malformed_Substitution of (int*int)

exception Malformed_Fusion of (int*int)

exception Malformed_Permutation of (int*int)

exception Malformed_Tensor of (int*int)

exception Malformed_Osp of (int*int)

exception Malformed_Isp of (int*int)

exception Malformed_Sp of (int*int)

exception Malformed_Posp of (int*int)

exception Malformed_Psp of (int*int)

exception Malformed_Composition of (int*int)

let ecount = ref (-1);;

let vcount = ref (-1);;

let sign = new signatures;;

let bigraphs = Hashtbl.create 16;;

let invbigraphs = Hashtbl.create 16;;

let bgcount = ref 0;;

let ids = Hashtbl.create 16;;

let rec perm str n = match str with

| [] -> []

| head::tail -> (head, n)::perm tail (n+1)

;;

let rec makeSigSet data = match data with

| [] -> sign

102 APPENDICE A. SORGENTI DEL COMPILATORE

| (t, n, a)::tail -> sign#addsign2 n t a; makeSigSet tail

;;

let rec donames list c = match list with

| [] -> []

| head::tail -> if (get head 0 = c)

then (sub head 1 (length head -1))::donames tail c

else donames tail c

;;

let rec makelinklist l n = match l with

| [] -> []

| head::tail ->

(n, (sub head 1 (length head -1)))::makelinklist tail (n+1)

;;

let location pos = (pos.Lexing.pos_lnum,

pos.Lexing.pos_cnum-pos.Lexing.pos_bol);;

%}

%token <int> NUM

%token <string> NAME

%token <string> SIGTYPE

%token <string> SIGN

%token EOF LET IN EQ

%token TENSOR COMPOSITION OSP ISP SP POSP PSP

%token SUBSTITUTION FUSION PERMUTATION

%token LRB RRB LSB RSB COLON SEMICOLON COMMA

%token MERGE CTRLLIST CLOSURE SIGNATURE

%left OSP ISP SP POSP PSP TENSOR

%left COMPOSITION

%nonassoc CLOSURE PERMUTATION

%nonassoc SUBSTITUTION FUSION

%nonassoc MERGE

%start dbpl

%type <(Bigraph.signatures * Bigraph.directedbg)> dbpl

%%

dbpl: signature letblock EOF { ($1, $2) }

| error EOF {

raise (Malformed_Dbpl (location (Parsing.rhs_start_pos 1))) }

A.1. GENERAZIONE DELLE COPPIE (SIGNATURE,BIGRAFO) 103

| signature error EOF {

raise (Malformed_Dbpl (location (Parsing.rhs_start_pos 2))) }

;

letblock: bg { $1 }

| letelem IN letblock { $3 }

;

letelem: LET NAME EQ bg {

if (Hashtbl.mem invbigraphs $4)

then Hashtbl.replace ids $2 (Hashtbl.find invbigraphs $4)

else Hashtbl.add bigraphs !bgcount $4;

Hashtbl.replace ids $2 !bgcount;

Hashtbl.add invbigraphs $4 !bgcount;

bgcount:=!bgcount+1 }

;

signature: SIGNATURE LSB RSB SEMICOLON { makeSigSet [] }

| SIGNATURE LSB sigelem RSB SEMICOLON { makeSigSet $3 }

| error {

raise (Malformed_Signature (location (Parsing.rhs_start_pos 1))) }

;

sigelem: SIGTYPE NAME COLON NUM { [($1, $2, $4)] }

| sigelem COMMA SIGTYPE NAME COLON NUM { $1@[($3, $4, $6)]}

| error {

raise (Malformed_Signature_Element (location (Parsing.rhs_start_pos 1))) }

;

siteset: LSB RSB { [] }

| LSB siteelem RSB { $2 }

| error {

raise (Malformed_SiteSet (location (Parsing.rhs_start_pos 1))) }

;

siteelem: NUM { [$1] }

| siteelem COMMA NUM { $1@[$3] }

| error {

raise (Malformed_SiteSet_Element (location (Parsing.rhs_start_pos 1))) }

;

ctrllist: LSB RSB { [] }

| LSB ctrlelem RSB { $2 }

104 APPENDICE A. SORGENTI DEL COMPILATORE

| error {

raise (Malformed_IonLinkList (location (Parsing.rhs_start_pos 1))) }

;

ctrlelem: SIGN NAME { [($1^$2)] }

| ctrlelem COMMA SIGN NAME{ $1@[($3^$4)] }

| error {

raise (Malformed_IonLinkList_Element (location (Parsing.rhs_start_pos 1))) }

;

nset: LSB nsetelem RSB { $2 }

| error {

raise (Malformed_NameSet (location (Parsing.rhs_start_pos 1))) }

;

nsetelem: NAME COMMA NAME { $1::[$3] }

| nsetelem COMMA NAME { $1@[$3] }

| error {

raise (Malformed_NameSet_Element (location (Parsing.rhs_start_pos 1))) }

;

bg: LRB bg RRB { $2 }

| merge { $1 }

| ion { $1 }

| substitution { $1 }

| fusion { $1 }

| closure { $1 }

| permutation { $1 }

| tensor { $1 }

| osp { $1 }

| isp { $1 }

| sp { $1 }

| posp { $1 }

| psp { $1 }

| composition { $1 }

| NAME {

try (Hashtbl.find bigraphs(Hashtbl.find ids $1))

with Not_found ->

raise (Unbound_Bigraph (location (Parsing.rhs_start_pos 1))) }

;

A.1. GENERAZIONE DELLE COPPIE (SIGNATURE,BIGRAFO) 105

merge: MERGE NUM { (merge $2) }

| error NUM {

raise (Malformed_Merge (location (Parsing.rhs_start_pos 1))) }

| MERGE error {

raise (Malformed_Merge (location (Parsing.rhs_start_pos 2))) }

| MERGE NUM error {

raise (Malformed_Merge (location (Parsing.rhs_start_pos 3))) }

;

ion: NAME ctrllist {

vcount:=!vcount+1;

try (let dbg = (discreteion ("v" ^ string_of_int !vcount) $1

(donames $2 ’-’ ) (donames $2 ’+’)

(makelinklist $2 0) sign) in

if (sign#activity $1="atomic")

then (dbg#composition ((merge 0)#tensor (id 0 (donames $2 ’-’) [])))

else dbg)

with Not_found -> raise (Malformed_Ion (location (Parsing.rhs_start_pos 1))) }

;

substitution: NAME SUBSTITUTION NAME { (substitution [$3] $1) }

| NAME SUBSTITUTION nset { (substitution $3 $1) }

| NAME SUBSTITUTION { (emptysubstitution [$1]) }

| nset SUBSTITUTION { (emptysubstitution $1) }

| nset SUBSTITUTION NAME {

raise (Malformed_Substitution (location (Parsing.rhs_start_pos 1))) }

| nset SUBSTITUTION nset {

raise (Malformed_Substitution (location (Parsing.rhs_start_pos 1))) }

;

fusion: NAME FUSION NAME { (fusion $3 [$1]) }

| nset FUSION NAME { (fusion $3 $1) }

| FUSION NAME { (emptyfusion [$2]) }

| FUSION nset { (emptyfusion $2) }

| NAME FUSION nset {

raise (Malformed_Fusion (location (Parsing.rhs_start_pos 3))) }

| nset FUSION nset {

raise (Malformed_Fusion (location (Parsing.rhs_start_pos 3))) }

;

106 APPENDICE A. SORGENTI DEL COMPILATORE

closure: NAME CLOSURE NAME {

ecount:=!ecount+1;

closure $3 $1 ("e" ^ string_of_int !ecount) }

| nset CLOSURE NAME {

ecount:=!ecount+1;

(fusion "1unused" $1)#composition

(closure $3 "1unused" ("e" ^ string_of_int !ecount)) }

| NAME CLOSURE nset {

ecount:=!ecount+1;

(closure "2unused" $1 ("e" ^ string_of_int !ecount))#composition

(substitution $3 "2unused") }

| nset CLOSURE nset {

ecount:=!ecount+1;

((fusion "3unused" $1)#composition

(closure "4unused" "3unused" ("e" ^ string_of_int !ecount)))#composition

(substitution $3 "4unused") }

| NAME CLOSURE {

ecount:=!ecount+1;

(upclosure $1 ("e" ^ string_of_int !ecount)) }

| CLOSURE NAME {

ecount:=!ecount+1;

(downclosure $2 ("e" ^ string_of_int !ecount)) }

| nset CLOSURE {

ecount:=!ecount+1;

(fusion "1unused" $1)#composition

(upclosure "1unused" ("e" ^ string_of_int !ecount)) }

| CLOSURE nset {

ecount:=!ecount+1;

(downclosure "2unused" ("e" ^ string_of_int !ecount))#composition

(substitution $2 "2unused") }

;

permutation: PERMUTATION siteset { permutation (perm $2 0) }

;

tensor: bg TENSOR bg {

try ($1#tensor $3)

with Bigraphs_are_not_disjoint ->

A.2. GENERAZIONE DEL PROGRAMMA OCAML 107

raise (Malformed_Tensor (location (Parsing.rhs_start_pos 2)))}

;

osp: bg OSP bg {

try ($1#osp $3)

with Bigraphs_are_not_disjoint ->

raise (Malformed_Osp (location (Parsing.rhs_start_pos 2)))}

;

isp: bg ISP bg {

try ($1#isp $3)

with Bigraphs_are_not_disjoint ->

raise (Malformed_Isp (location (Parsing.rhs_start_pos 2)))}

;

sp: bg SP bg {

try ($1#sp $3)

with Bigraphs_are_not_disjoint ->

raise (Malformed_Sp (location (Parsing.rhs_start_pos 2)))}

;

posp: bg POSP bg {

try ($1#posp $3)

with Bigraphs_are_not_disjoint ->

raise (Malformed_Posp (location (Parsing.rhs_start_pos 2)))}

;

psp: bg PSP bg {

try ($1#psp $3)

with Bigraphs_are_not_disjoint ->

raise (Malformed_Psp (location (Parsing.rhs_start_pos 2)))}

;

composition: bg COMPOSITION bg {

try ($1#composition $3)

with Bigraphs_have_no_common_interface ->

raise (Malformed_Composition (location (Parsing.rhs_start_pos 2)))}

A.2 Generazione del programma OCaml

A.2.1 Analizzatore lessicale

{

108 APPENDICE A. SORGENTI DEL COMPILATORE

open Dbplparser2ocaml

exception Unknown_Symbol of (int*int);;

let incr_linenum lexbuf =

let pos = lexbuf.Lexing.lex_curr_p in

lexbuf.Lexing.lex_curr_p <- { pos with

Lexing.pos_lnum = pos.Lexing.pos_lnum + 1;

Lexing.pos_bol = pos.Lexing.pos_cnum;

}

;;

}

let num = [’0’-’9’] | [’1’-’9’][’0’-’9’]+

let name = [’a’-’z’][’a’-’z’ ’A’-’W’ ’Y’-’Z’ ’0’-’9’]*

let sign = ’+’ | ’-’

rule token = parse

| [’ ’ ’\t’] { token lexbuf }

| ’\n’ { incr_linenum lexbuf; token lexbuf }

| "merge" { MERGE }

| "Signature" { SIGNATURE }

| "active"

| "passive"

| "atomic" as sigtype { SIGTYPE (sigtype) }

| "in" { IN }

| "let" { LET }

| num as n { NUM(n) }

| name as nm { NAME(nm) }

| sign as sn { SIGN (String.make 1 sn) }

| "=" { EQ }

| "[" { LSB }

| "]" { RSB }

| "," { COMMA }

| ":" { COLON }

| ";" { SEMICOLON }

| "*" { TENSOR }

| "°" { COMPOSITION }

| "/\\" { OSP }

A.2. GENERAZIONE DEL PROGRAMMA OCAML 109

| "\\/" { ISP }

| "||" { SP }

| "/^\\" { POSP }

| "|" { PSP }

| "/" { SUBSTITUTION }

| "\\" { FUSION }

| "(" { LRB }

| ")" { RRB }

| "X" { CLOSURE }

| "@" { PERMUTATION }

| eof { EOF }

| _ { raise (Unknown_Symbol (lexbuf.Lexing.lex_curr_p.Lexing.pos_lnum,

(lexbuf.Lexing.lex_curr_p.Lexing.pos_cnum-

lexbuf.Lexing.lex_curr_p.Lexing.pos_bol))) }

A.2.2 Parser

%{

open String

open Algebra

open Bigraph

exception Unbound_Name of (int*int)

exception Unbound_Bigraph of (int*int)

exception Malformed_Dbpl of (int*int)

exception Malformed_Signature of (int*int)

exception Malformed_Signature_Element of (int*int)

exception Malformed_SiteSet of (int*int)

exception Malformed_SiteSet_Element of (int*int)

exception Malformed_IonLinkList of (int*int)

exception Malformed_IonLinkList_Element of (int*int)

exception Malformed_NameSet of (int*int)

exception Malformed_NameSet_Element of (int*int)

exception Malformed_Bigraph of (int*int)

exception Malformed_Merge of (int*int)

exception Malformed_Ion of (int*int)

exception Malformed_Substitution of (int*int)

110 APPENDICE A. SORGENTI DEL COMPILATORE

exception Malformed_Fusion of (int*int)

let ecount = ref (-1);;

let vcount = ref (-1);;

let sign = new signatures;;

let bigraphs = Hashtbl.create 16;;

let invbigraphs = Hashtbl.create 16;;

let bgcount = ref 0;;

let ids = Hashtbl.create 16;;

let rec perm str n = match str with

| [] -> []

| head::tail ->

("(" ^head^ ", "^string_of_int n^")")::perm tail (n+1)

;;

let rec makeSigSet data = match data with

| [] -> "\n"

| (t, n, a)::tail -> sign#addsign2 n t (int_of_string a);

"sign#addsign2 \""^n^"\" \""^t^"\" "^a^";\n"^ makeSigSet tail

;;

let rec donames list c = match list with

| [] -> []

| head::tail ->

if (get head 0 = c)

then ("\"" ^ (sub head 1 (length head -1))^"\"")::donames tail c

else donames tail c

;;

let rec makelinklist l n = match l with

| [] -> []

| head::tail ->

("(" ^ string_of_int n ^ ", \"" ^

(sub head 1 (length head -1)) ^ "\")")::

makelinklist tail (n+1)

;;

let location pos = (pos.Lexing.pos_lnum, pos.Lexing.pos_cnum-pos.Lexing.pos_bol);;

let parse_error msg = Printf.eprintf "%s\n" msg

%}

%token <string> NUM

A.2. GENERAZIONE DEL PROGRAMMA OCAML 111

%token <string> NAME

%token <string> SIGTYPE

%token <string> SIGN

%token EOF LET IN EQ

%token TENSOR COMPOSITION OSP ISP SP POSP PSP

%token SUBSTITUTION FUSION PERMUTATION

%token LRB RRB LSB RSB COLON SEMICOLON COMMA

%token MERGE CTRLLIST CLOSURE SIGNATURE

%left TENSOR OSP ISP SP POSP PSP

%left COMPOSITION

%nonassoc CLOSURE PERMUTATION

%nonassoc SUBSTITUTION FUSION

%nonassoc MERGE

%start dbpl

%type <string> dbpl

%%

dbpl: signature letblock EOF {

"open Algebra\nopen Bigraph\n \

let compiledsignature = fun () ->

let sign = new signatures in\n" ^ $1 ^"sign;;\n \

let compiledbigraph = fun () ->"^ $2 ^ ";;\n" }

| error EOF {

raise (Malformed_Dbpl (location (Parsing.rhs_start_pos 1))) }

;

letblock: bg { $1 }

| letelem IN letblock { $3 }

;

letelem: LET NAME EQ bg {

if (Hashtbl.mem invbigraphs $4)

then Hashtbl.replace ids $2 (Hashtbl.find invbigraphs $4)

else Hashtbl.add bigraphs !bgcount $4;

Hashtbl.replace ids $2 !bgcount;

Hashtbl.add invbigraphs $4 !bgcount;

bgcount:=!bgcount+1 }

;

signature: SIGNATURE LSB RSB SEMICOLON { makeSigSet [] }

112 APPENDICE A. SORGENTI DEL COMPILATORE

| SIGNATURE LSB sigelem RSB SEMICOLON { makeSigSet $3 }

| error {

raise (Malformed_Signature (location (Parsing.rhs_start_pos 1))) }

;

sigelem: SIGTYPE NAME COLON NUM { ($1, $2, $4)::[] }

| SIGTYPE NAME COLON NUM COMMA sigelem { ($1, $2, $4)::$6}

| error {

raise (Malformed_Signature_Element (location (Parsing.rhs_start_pos 1))) }

;

siteset: LSB RSB { [] }

| LSB siteelem RSB { $2 }

| error {

raise (Malformed_SiteSet (location (Parsing.rhs_start_pos 1))) }

;

siteelem: NUM { $1::[] }

| NUM COMMA siteelem { $1::$3 }

| error {

raise (Malformed_SiteSet_Element (location (Parsing.rhs_start_pos 1))) }

;

ctrllist: LSB RSB { [] }

| LSB ctrlelem RSB { $2 }

| error {

raise (Malformed_IonLinkList (location (Parsing.rhs_start_pos 1))) }

;

ctrlelem: SIGN NAME { ($1^$2)::[] }

| SIGN NAME COMMA ctrlelem { ($1^$2)::$4 }

;

nset: LSB nsetelem RSB { $2 }

| error {

raise (Malformed_NameSet (location (Parsing.rhs_start_pos 1))) }

;

nsetelem: NAME COMMA NAME { $1::[$3] }

| nsetelem COMMA NAME { $1@[$3] }

| error {

raise (Malformed_NameSet_Element (location (Parsing.rhs_start_pos 1))) }

;

A.2. GENERAZIONE DEL PROGRAMMA OCAML 113

bg: LRB bg RRB { $2 }

| merge { $1 }

| ion { $1 }

| substitution { $1 }

| fusion { $1 }

| closure { $1 }

| permutation { $1 }

| tensor { $1 }

| osp { $1 }

| isp { $1 }

| sp { $1 }

| posp { $1 }

| psp { $1 }

| composition { $1 }

| NAME {

try (Hashtbl.find bigraphs(Hashtbl.find ids $1))

with Not_found ->

raise (Unbound_Bigraph (location (Parsing.rhs_start_pos 1))) }

;

merge: MERGE NUM { "merge " ^ $2 }

| error NUM {

raise (Malformed_Merge (location (Parsing.rhs_start_pos 1))) }

| MERGE error {

raise (Malformed_Merge (location (Parsing.rhs_start_pos 2))) }

| MERGE NUM error {

raise (Malformed_Merge (location (Parsing.rhs_start_pos 3))) }

;

ion: NAME ctrllist {

vcount:=!vcount+1;

let nm1=donames $2 ’-’ in

let nm=if (nm1=[]) then "[]" else "["^concat ";" nm1^"]" in

let dbg = "(discreteion \"" ^ ("v" ^ string_of_int !vcount) ^

"\" \"" ^ $1 ^ "\" "^nm^" [" ^ concat ";" (donames $2 ’+’) ^

"] [" ^ concat ";" (makelinklist $2 0) ^ "] sign" in

if (sign#activity $1="atomic")

then (dbg^"#composition ((merge 0)#tensor (id 1 "^nm^" []))")

114 APPENDICE A. SORGENTI DEL COMPILATORE

else dbg^")" }

substitution: NAME SUBSTITUTION NAME {

"substitution [\""^$3^"\"] \""^$1^"\"" }

| NAME SUBSTITUTION nset {

"substitution [\""^concat "\";\"" $3^"\"] \""^$1^"\"" }

| NAME SUBSTITUTION {

"emptysubstitution [" ^ $1 ^ "]" }

| nset SUBSTITUTION {

"emptysubstitution [\""^concat "\";\"" $1^"\"]" }

| nset SUBSTITUTION NAME {

raise (Malformed_Substitution (location (Parsing.rhs_start_pos 1))) }

| nset SUBSTITUTION nset {

raise (Malformed_Substitution (location (Parsing.rhs_start_pos 1))) }

;

fusion: NAME FUSION NAME { "fusion \""^$3^"\" [\""^$1^"\"]" }

| nset FUSION NAME { "fusion "^$3^" [\""^concat "\";\"" $1^"\"]" }

| FUSION NAME { "emptyfusion ["^$2^"]" }

| FUSION nset { "emptyfusion [\""^concat "\";\"" $2^"\"]" }

| NAME FUSION nset {

raise (Malformed_Fusion (location (Parsing.rhs_start_pos 3))) }

| nset FUSION nset {

raise (Malformed_Fusion (location (Parsing.rhs_start_pos 3))) }

;

closure: NAME CLOSURE NAME {

ecount:=!ecount+1;

"(closure \""^$3^"\" \""^$1^"\" \""^("e" ^ string_of_int !ecount)^"\")" }

| nset CLOSURE NAME {

ecount:=!ecount+1;

" (fusion \"1unused\" [\""^concat "\";\"" $1^"\"])#composition

(closure \""^$3^"\" \"1unused\" \""^("e" ^ string_of_int !ecount)^"\")" }

| NAME CLOSURE nset {

ecount:=!ecount+1;

" (closure \"2unused\" \""^$1^"\" \""^

("e" ^ string_of_int !ecount)^"\")#composition

(substitution [\""^concat "\";\"" $3^"\"] \"2unused\")"}

A.2. GENERAZIONE DEL PROGRAMMA OCAML 115

| nset CLOSURE nset {

ecount:=!ecount+1;

" ((fusion \"1unused\" [\""^concat "\";\"" $1^"\"])#composition

(closure \"2unused\" \"1unused\" \""^

("e" ^ string_of_int !ecount)^"\"))#composition

(substitution [\""^concat "\";\"" $3^"\"] \"2unused\")" }

| NAME CLOSURE {

ecount:=!ecount+1;

"upclosure "^$1^" "^("e" ^ string_of_int !ecount) }

| CLOSURE NAME {

ecount:=!ecount+1;

"downclosure "^$2^" "^("e" ^ string_of_int !ecount) }

| nset CLOSURE {

ecount:=!ecount+1;

"(fusion \"1unused\" [\""^concat "\";\"" $1^"\"])#composition

(upclosure \"1unused\" \""^("e" ^ string_of_int !ecount)^"\")" }

| CLOSURE nset {

"(downclosure \"2unused\" \""^ ("e" ^ string_of_int !ecount)^

"\")#composition (substitution [\""^concat "\";\"" $2^"\"] \"2unused\")"}

;

permutation: PERMUTATION siteset {

"permutation ["^concat "\";\"" (perm $2 0)^"]" }

;

tensor: bg TENSOR bg { "(("^$1^")#tensor ("^$3^"))" }

;

osp: bg OSP bg { "(("^$1^")#osp ("^$3^"))" }

;

isp: bg ISP bg { "(("^$1^")#isp ("^$3^"))" }

;

sp: bg SP bg { "(("^$1^")#sp ("^$3^"))" }

;

posp: bg POSP bg { "(("^$1^")#posp ("^$3^"))" }

;

psp: bg PSP bg { "(("^$1^")#psp ("^$3^"))" }

;

composition: bg COMPOSITION bg { "(("^$1^")#composition ("^$3^"))" }

116 APPENDICE A. SORGENTI DEL COMPILATORE

;

A.3 Interfaccia del compilatore

let compilefromfile file =

let inChannel = open_in file in

let lexbuf = Lexing.from_channel inChannel in

Dbplparser.dbpl Dbpllexer.token lexbuf;;

let compilefromstring string =

let lexbuf = Lexing.from_string string in

Dbplparser.dbpl Dbpllexer.token lexbuf;;

let compilefromfile2ocaml filein fileout =

let inChannel = open_in filein in

let outChannel = open_out fileout in

let lexbuf = Lexing.from_channel inChannel in

Printf.fprintf outChannel "%s\n" (Dbplparser2ocaml.dbpl Dbpllexer2ocaml.token lexbuf);;

let compilefromstring2ocaml string fileout =

let outChannel = open_out fileout in

let lexbuf = Lexing.from_string string in

Printf.fprintf outChannel "%s\n" (Dbplparser2ocaml.dbpl Dbpllexer2ocaml.token lexbuf);;

BSorgenti del decompilatore

let printDBPL signs bg =

"Signature ["^(concat "," (printsignature signs#getsigns))^"];\n"^

(printBG bg signs)^"\n";;

let rec printsignature signs = match signs with

| [] -> []

| (t, (act, ary))::tail ->

(act^" "^t^":"^string_of_int ary)::printsignature tail

;;

let printBG dbg signs=

let bg=Algebra.dnf dbg in

let w=List.hd bg in

let daux=List.hd (List.tl bg) in

let w1=List.hd (List.tl (List.tl bg)) in

let d = daux#composition

(w1#tensor (makebg (findsites daux#getprnt))) in

let wstr=printW w#returnlink d#getouterintn in

let dstr=printD d#returnprnt d#returnlink d#returnctrl

d#getouterintn signs in

if (wstr="")

then dstr

else (if (dstr="")

then wstr

else wstr^"°\n"^dstr);;

118 APPENDICE B. SORGENTI DEL DECOMPILATORE

let printW links inn =

let ltab = Hashtbl.create 32 in

let destinations = singlelist (linksdest ltab links) in

let w=printW2 destinations ltab in

"("^

if (w=[])

then (if (inn!=0)

then "merge "^string_of_int inn

else "")

else (concat "*" w)^

(if (inn!=0)

then "* merge "^string_of_int inn

else "")^")";;

let rec printW2 links ltab = match links with

| [] -> []

| (d, td)::tail ->

(printW3 d td (Hashtbl.find_all ltab d)) :: printW2 tail ltab

;;

let printW3 d td linkssources =

let n1=namesoftype linkssources "onm" in

let n2=namesoftype linkssources "inp" in

let top=(if (List.length n1 = 0)

then ""

else if (List.length n1 = 1)

then List.hd n1

else "["^concat "," n1 ^"]") in

let bottom=(if (List.length n2 = 0)

then ""

else if (List.length n2 = 1)

then List.hd n2

else "["^concat "," n2 ^"]") in

if (td="e")

then top^"X"^bottom

else if (td="onp")

119

then d^"/"^bottom

else top^"\\"^d

;;

let printD prn lnk ctrl nr signs =

let roots = makerootlist (nr-1) [] in

let ptab = hashprnt (Hashtbl.create 16) prn in

let ltab = hashlink (Hashtbl.create 16) lnk in

let d = printroots roots ptab ltab ctrl signs in

let l = passthroughlink lnk in

if (d=[])

then (if (l=[])

then ""

else "("^concat "*" l ^")")

else (if (l=[])

then ("("^concat "*" d ^")")

else ("(("^concat "*" d ^")*("^concat "*" l ^"))"));;

let rec printroots roots ptab ltab ctrl signs = match roots with

| [] -> []

| head::tail ->

let rsons = Hashtbl.find_all ptab (Root(head)) in

if (rsons=[])

then "merge 0"::printroots tail ptab ltab ctrl signs

else let sns = printson rsons ptab ltab ctrl signs [] in

if (sns=[])

then printroots tail ptab ltab ctrl signs

else ("("^concat "|" sns^")")::

printroots tail ptab ltab ctrl signs;;

let rec printson sons ptab ltab ctrl signs downlinks =

match sons with

| [] -> if (downlinks=[])

then []

else ["("^concat "*" (printlinks downlinks "-")^")"]

| Site(n)::tail ->

120 APPENDICE B. SORGENTI DEL DECOMPILATORE

("(merge 1@["^string_of_int n^"])")::

printson tail ptab ltab ctrl signs downlinks

| Node(n)::tail ->

let ary = List.assoc n ctrl in

let l = printionlinks (List.sort linkcompare

(Hashtbl.find_all ltab n)) in

let ionlinks = if (l=[])

then " []"

else " ["^concat "," l^"]" in

if (Hashtbl.mem ptab (Node(n)))

then let sl=(printlinks

(sonslink (Node(n)) ltab ptab) "+") in

("("^signs#typeof "active" ary^ionlinks^

(if (sl=[])

then ""

else "*"^concat "*" sl)^")°("^

concat "|" (printson

(Hashtbl.find_all ptab (Node(n)))

ptab ltab ctrl signs (filterlink

(Hashtbl.find_all ltab n) "inm"))^")")::

printson tail ptab ltab ctrl signs downlinks

else (signs#typeof "atomic" ary^ionlinks)::

printson tail ptab ltab ctrl signs downlinks

| head::tail -> printson tail ptab ltab ctrl signs downlinks

;;

let rec filterlink l t1= match l with

| [] -> []

| (p, d, t)::tail when t=t1 -> d::filterlink tail t1

| head::tail -> filterlink tail t1

;;

let rec sonslink f ltab ptab =

let sons = Hashtbl.find_all ptab f in

sonslink1 sons ltab ptab

and sonslink1 sons ltab ptab = match sons with

121

| [] -> []

| Node(n)::tail ->

(filterlink (Hashtbl.find_all ltab n) "onp")@

(sonslink (Node(n)) ltab ptab)@

sonslink1 tail ltab ptab

| head::tail -> sonslink1 tail ltab ptab

;;

let rec printionlinks l = match l with

| [] -> []

| (p, d, t)::tail ->

(if (t="onp")

then ("+"^d)

else ("-"^d))::printionlinks tail

;;

let rec printlinks l t = match l with

| [] -> []

| head::tail ->

if (t="-")

then (head^"\\"^head)::printlinks tail t

else (head^"/"^head)::printlinks tail t

;;

let linkcompare (p, d, t) (p1, d1, t1) =

if (p<p1)

then -1

else

if (p=p1)

then 0

else 1;;

let rec linksdest ltab links = match links with

| [] -> []

| (Name (s, ts), NameEdge (d, td))::tail ->

Hashtbl.add ltab d (s, ts);

122 APPENDICE B. SORGENTI DEL DECOMPILATORE

(d, td)::linksdest ltab tail

| head::tail -> linksdest ltab tail

;;

let rec namesoftype linkssources t = match linkssources with

| [] -> []

| (s, ts)::tail when (ts=t) -> s::namesoftype tail t

| head :: tail -> namesoftype tail t

;;

let rec hashprnt sons prn = match prn with

| [] -> sons

| SiteRoot (s, f)::tail ->

Hashtbl.add sons (Root(f)) (Site(s));

hashprnt sons tail

| NodeRoot (s, f)::tail ->

Hashtbl.add sons (Root(f)) (Node(s));

hashprnt sons tail

| NodeNode (s, f)::tail ->

Hashtbl.add sons (Node(f)) (Node(s));

hashprnt sons tail

| SiteNode (s, f)::tail ->

Hashtbl.add sons (Node(f)) (Site(s));

hashprnt sons tail

;;

let rec hashlink lnktab lnk = match lnk with

| [] -> lnktab

| (Port(p, n),NameEdge (d, t))::tail ->

Hashtbl.add lnktab n (p, d, t); hashlink lnktab tail

| head::tail -> hashlink lnktab tail

;;

let rec findsites p = match p with

| [] -> []

| (SiteNode (s,f))::tail -> s::findsites tail

123

| (SiteRoot (s,f))::tail -> s::findsites tail

| head::tail -> findsites tail;;

let rec makebgaux bg l = match l with

| [] -> ()

| head::tail -> bg#addprntsiteroot head head; makebgaux bg tail;;

let makebg l =

let bg = Algebra.id 0 [] [] in

bg#setinnerintn (List.length l);

bg#setouterintn (List.length l);

makebgaux bg l;

bg;;

let rec makerootlist n acc =

if (n>=0)

then makerootlist (n-1) (n::acc)

else acc;;

124 APPENDICE B. SORGENTI DEL DECOMPILATORE

CSorgenti del visualizzatore

let dbg2svg bg =

let prn = bg#returnprnt in

let lnk = bg#returnlink in

let ptab = hashprnt (Hashtbl.create 16) prn in

let roots = makerootlist bg#getouterintn 0 in

let rawtree = if (bg#getouterintn = 0)

then ([Elem(Root(0), 0., 0., 60., 60.,[])])

else filltree roots ptab in

let edgelist = singlelist (edges lnk) in

let edgewidth = (float_of_int (List.fold_left (+) 0

(List.map (String.length) edgelist)))*.10. in

let linkslength = rootlinkslength rawtree lnk

(bg#getyminus) (bg#getyplus)

(bg#getxminus) (bg#getxplus) 0 in

let widthfixedtree = fixheight (fixsize rawtree

(maxvalue linkslength) edgewidth) in

let highest = (List.fold_right max (heights widthfixedtree) 0.0) in

let heigthfixedtree = setrootsheight widthfixedtree

(max highest (highest -.44.+.float_of_int

(List.length edgelist) *.30.)) in

let t = fixpos heigthfixedtree highest 0.0 edgewidth in

let namespos = placelinks t !allnames in

let edgedata = printedges edgelist (List.hd t) (highest -.44.) in

"<?xml version=\"1.0\" standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC "^

"\"-//W3C//DTD SVG 1.1//EN\"\n\"http://www.w3.org/Graphics/SVG/1."^

"1/DTD/svg11.dtd\">\n<svg width=\"100%%\" height=\"100%%\" versio"^

126 APPENDICE C. SORGENTI DEL VISUALIZZATORE

"n=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n<g transform=\""^

"translate(50,50)\">\n"^(printpgraph t)^

(printnames namespos)^String.concat "" (sndlist edgedata)

^(printlink t lnk namespos (firstlist edgedata) highest)^

"</g></svg>\n";;

let rec printpgraph t = match t with

| [] -> ""

| head:: tail -> printpgraph2 head^"\n"^printpgraph tail

and printpgraph2 e = match e with

| Elem(Root(n), x, y, rx, ry, sns) ->

"<rect width=\""^string_of_float rx^"\" "^

"height=\""^string_of_float ry^"\" x=\""^

string_of_float x^"\" y=\""^string_of_float y^

"\" style=\"fill:white;stroke:black;"^

"stroke-width:1;stroke-dasharray:9,5\"/>"^

(if (n!= (- 1))

then "\n<text x=\""^string_of_float (x +.5.)^

"\" y=\""^string_of_float (y +.15.)^"\""^

" font-size=\"15\">"^string_of_int n^

"</text>\n"

else "")^printpgraph sns

| Elem(Node(n), x, y, rx, ry, sns) ->

"<ellipse cx=\""^string_of_float x^

"\" cy=\""^string_of_float y^"\" rx=\""^

string_of_float (rx /.2.0)^"\" ry=\""^

string_of_float (ry /.2.0)^"\" "^

"style=\"fill:white;stroke:black;"^

"stroke-width:1\"/>\n<text x=\""^

string_of_float (x -.4.*.(float_of_int (String.length n)))^

"\" y=\""^string_of_float (y -.ry /.2.-.2.)^

"\" font-size=\"10\">"^n^"</text>\n"^

printpgraph sns

| Elem(Site(n), x, y, rx, ry, _) ->

"<rect width=\""^string_of_float rx^

"\" height=\""^string_of_float ry^"\" x=\""^

127

string_of_float x^"\" y=\""^

string_of_float y^"\" style=\"fill:#C3C3C3"^

";stroke:black;stroke-width:0\"/>\n<text x=\""^

string_of_float (x +.5.)^"\" y=\""^

string_of_float (y +.15.)^"\" font-size=\"1"^

"5\">"^string_of_int n^"</text>\n";;

let rec rootlinkslength t l ym yp xm xp s = match t with

| [] -> allnames:= singleallnodes !allnames; []

| (Elem(Root(n), x, y, rx, ry, sns)):: tail ->

let sons = allnodes sns in

let ypl = rootlinks sons l (getsetelem yp) "onp" in

let xml = rootlinks sons l (getsetelem xm) "inm" in

let yplfromname = difference (linksfromname l "onp") ypl in

let xmlfromname = difference (linksfromname l "inm") xml in

allnames:= (makelist ypl n "onp")@(!allnames);

allnames:= (makelist xml n "inm")@(!allnames);

if (s = 0)

then (allnames:= (makelist (getsetelem ym) n "onm")

@(!allnames);

allnames:= (makelist (getsetelem xp) n "inp")@(!allnames);

allnames:= (makelist yplfromname n "onp")@(!allnames);

allnames:= (makelist xmlfromname n "inm")@(!allnames);

(n, 12.*.float_of_int (List.fold_left (+) 0 (List.map

(String.length) (yplfromname@ypl@(getsetelem ym))))

+.6.*.float_of_int(List.length

(yplfromname@ypl@(getsetelem ym)) + 2),

12.*.float_of_int (List.fold_left (+) 0 (List.map

(String.length) (xmlfromname@xml@(getsetelem xp))))

+.6.*.float_of_int(List.length

(xmlfromname@xml@(getsetelem xp)) + 2))::

rootlinkslength tail l ym yp xm xp 1)

else (n, 12.*.float_of_int (List.fold_left (+) 0 (List.map

(String.length) ypl))

+.6.*.float_of_int(List.length ypl + 2),

128 APPENDICE C. SORGENTI DEL VISUALIZZATORE

12.*.float_of_int (List.fold_left (+) 0 (List.map

(String.length) xml))

+.6.*.float_of_int(List.length xml + 2))::

rootlinkslength tail l ym yp xm xp 1

| head:: tail -> rootlinkslength tail l ym yp xm xp 1;;

let rec placelinks2 l t b h = match l with

| [] -> []

| (n, (r, x, y, ty)):: tail when ty ="onm" or ty ="onp" ->

(n, (t, 0., ty))::

placelinks2 tail (t +.6.+.12.*.float_of_int

(String.length n)) b h

| (n, (r, x, y, ty)):: tail when ty ="inm" or ty ="inp" ->

(n, (b, (h +.16.), ty))::

placelinks2 tail t (b +.6.+.12.*.float_of_int

(String.length n)) h

| head:: tail -> placelinks2 tail t b h;;

let allnamescmp (n, (r, x, y, t)) (n1, (r1, x1, y1, t1)) =

if (t = t1)

then 0

else if ((t ="onm" or t ="inp") & (t1 ="onp" or t1 ="inm"))

then - 1

else 1;;

let rec placelinks t nms = match t with

| [] -> []

| (Elem(Root(n), x, y, rx, ry, sns)):: tail ->

placelinks2 (List.sort (allnamescmp) (thisrootlinks n nms))

(x +.15.) (x +.18.) ry@placelinks tail nms

| _ -> [];;

let rec printedges2 l x y = match l with

| [] -> []

| head:: tail -> ((head, (x, y)),

"<text x=\""^string_of_float x^"\" y=\""^string_of_float y^

129

"\" style=\"font-size:15\">"^head^"</text>\n")::

printedges2 tail (x +.8.*.float_of_int(String.length head))

(y +.30.);;

let printedges e (Elem(a, x, y, rx, ry, sns)) h =

if (sns =[]) then printedges2 e 30. h else

match (List.hd sns) with

(Elem(b, x1, y1, rx1, ry1, sns1)) ->

printedges2 e (x1 +.rx1 /.2.+.5.) h;;

let printlink t l nms edg h =

let ltab = Hashtbl.create 16 in

hashtree t ltab (countocc (Hashtbl.create 16) l);

Random.self_init();

printlink2 l ltab nms edg h;;

let rec printlink2 l tab nms edg h = match l with

| [] -> ""

| (Port(p, n), NameEdge(d, td)):: tail when td = "onp" ->

let (x, y, rx, ry, xs, tsp, b, bsp, el, esp, er) =

Hashtbl.find tab n in

let ys = eqtn x y (rx /.2.) (ry /.2.) xs (- 1.) in

let (x1, yd) = findinlist d nms "onp" in

let xd = x1 +.5.*.float_of_int (String.length d) in

Hashtbl.replace tab n (x, y, rx, ry, xs +.tsp,

tsp, b, bsp, el, esp, er);

"<polyline points=\""^

string_of_float xs^","^string_of_float ys^" "^

string_of_float xs^","^string_of_float (ys -.20.)^" "^

string_of_float xd^","^string_of_float (yd +.10.)^" "^

string_of_float xd^","^string_of_float yd^" "^

string_of_float (xd -.5.)^","^string_of_float (yd +.10.)

^" "^

string_of_float xd^","^string_of_float yd^" "^

string_of_float (xd +.5.)^","^string_of_float (yd +.10.)^

130 APPENDICE C. SORGENTI DEL VISUALIZZATORE

"\" style=\"fill:none;stroke:black;stroke-width:1\"/>\n"

^printlink2 tail tab nms edg h

| (Port(p, n), NameEdge(d, td)):: tail when td = "inm" ->

let (x, y, rx, ry, t, tsp, xs, bsp, el, esp, er) =

Hashtbl.find tab n in

let ys = eqtn x y (rx /.2.) (ry /.2.) xs 1. in

let (x1, yd) = findinlist d nms "inm" in

let xd = x1 +.5.*.float_of_int (String.length d) in

Hashtbl.replace tab n (x, y, rx, ry, t, tsp,

xs +.bsp, bsp, el, esp, er);

"<polyline points=\""^

string_of_float xs^","^string_of_float ys^" "^

string_of_float xs^","^string_of_float (ys +.20.)^" "^

string_of_float xd^","^string_of_float (yd -.26.)^" "^

string_of_float xd^","^string_of_float (yd -.16.)^" "^

string_of_float (xd -.5.)^","^string_of_float (yd -.26.)

^" "^

string_of_float xd^","^string_of_float (yd -.16.)^" "^

string_of_float (xd +.5.)^","^string_of_float (yd -.26.)

^" "^

"\" style=\"fill:none;stroke:black;stroke-width:1\"/>\n"^

printlink2 tail tab nms edg h

| (Port(p, n), NameEdge(d, td)):: tail when td = "e" ->

let (x, y, rx, ry, t, tsp, b, bsp, el, esp, er) =

Hashtbl.find tab n in

let (xd, yd) = List.assoc d edg in

let newel=if (x<xd) then el else el+.esp in

let newer=if (x<xd) then er-.esp else er in

let rnd=(Random.float 40.) -. 10. in

Hashtbl.replace tab n (x, y, rx, ry, t, tsp,

b, bsp, newel, esp, newer);

(if (x < xd)

then ("<polyline points=\""^string_of_float er^","^

string_of_float (eqtn x y (rx /.2.) (ry /.2.) er 1.)

^" "^

131

string_of_float er^","^string_of_float (h -.25. +.rnd)^" "^

string_of_float xd^","^string_of_float yd^

"\" style=\"fill:none;stroke:black;stroke-width:1\"/>\n")

else ("<polyline points=\""^string_of_float el^","^

string_of_float (eqtn x y (rx /.2.) (ry /.2.) el 1.)^" "^

string_of_float el^","^string_of_float (h -.36.+.rnd)^" "^

string_of_float (xd +.10.*.float_of_int(String.length d))

^","^

string_of_float (yd -.8.)^

"\" style=\"fill:none;stroke:black;stroke-width:1\"/>\n"))^

printlink2 tail tab nms edg h

| (Name(s, ts), NameEdge(d, td)):: tail when ts ="onm" & td ="inm" ->

let (xa, y1) = findinlist s nms "onm" in

let (xb, y2) = findinlist d nms "inm" in

let x1 = xa +.5.*.float_of_int (String.length s) in

let x2 = xb +.5.*.float_of_int (String.length d) in

"<polyline points=\""^

string_of_float x1^","^string_of_float y1^" "^

string_of_float x2^","^string_of_float (y2 -.26.)^" "^

string_of_float x2^","^string_of_float (y2 -.16.)^" "^

string_of_float (x2 -.5.)^","^string_of_float (y2 -.26.)^" "^

string_of_float x2^","^string_of_float (y2 -.16.)^" "^

string_of_float (x2 +.5.)^","^string_of_float (y2 -.26.)^

"\" style=\"fill:none;stroke:black;stroke-width:1\"/>\n"^

printlink2 tail tab nms edg h

| (Name(s, ts), NameEdge(d, td)):: tail when ts ="onm" & td ="e" ->

let (xa, y1) = findinlist s nms "onm" in

let (x2, y2) = List.assoc d edg in

let x1 = xa +.5.*.float_of_int (String.length s) in

"<polyline points=\""^

string_of_float x1^","^string_of_float y1^" "^

string_of_float x1^","^string_of_float (h -.40.)^" "^

string_of_float x2^","^string_of_float y2^

"\" style=\"fill:none;stroke:black;stroke-width:1\"/>\n"^

printlink2 tail tab nms edg h

132 APPENDICE C. SORGENTI DEL VISUALIZZATORE

| (Name(s, ts), NameEdge(d, td)):: tail when ts ="inp" & td ="onp" ->

let (xa, y1) = findinlist s nms "inp" in

let (xb, y2) = findinlist d nms "onp" in

let x1 = xa +.5.*.float_of_int (String.length s) in

let x2 = xb +.5.*.float_of_int (String.length d) in

"<polyline points=\""^

string_of_float x1^","^string_of_float (y1 -.16.)^" "^

string_of_float x1^","^string_of_float 20.^" "^

string_of_float x2^","^string_of_float (y2 +.10.)^" "^

string_of_float x2^","^string_of_float y2^" "^

string_of_float (x2 -.5.)^","^string_of_float (y2 +.10.)^" "^

string_of_float x2^","^string_of_float y2^" "^

string_of_float (x2 +.5.)^","^string_of_float (y2 +.10.)^

"\" style=\"fill:none;stroke:black;stroke-width:1\"/>\n"^

printlink2 tail tab nms edg h

| (Name(s, ts), NameEdge(d, td)):: tail when ts ="inp" & td ="e" ->

let (xa, y1) = findinlist s nms "inp" in

let (x2, y2) = List.assoc d edg in

let x1 = xa +.5.*.float_of_int (String.length s) in

"<polyline points=\""^

string_of_float x1^","^string_of_float (y1 -.16.)^" "^

string_of_float x1^","^string_of_float (h -.25.)^" "^

string_of_float x2^","^string_of_float y2^" "^

"\" style=\"fill:none;stroke:black;stroke-width:1\"/>\n"^

printlink2 tail tab nms edg h

| head:: tail -> printlink2 tail tab nms edg h;;

let rec hashprnt sons prn = match prn with

| [] -> sons

| SiteRoot (s, f):: tail -> Hashtbl.add sons (Root(f)) (Site(s));

hashprnt sons tail

| NodeRoot (s, f):: tail -> Hashtbl.add sons (Root(f)) (Node(s));

hashprnt sons tail

| NodeNode (s, f):: tail -> Hashtbl.add sons (Node(f)) (Node(s));

133

hashprnt sons tail

| SiteNode (s, f):: tail -> Hashtbl.add sons (Node(f)) (Site(s));

hashprnt sons tail;;

let rec filltree2 e ptab =

let sons = Hashtbl.find_all ptab e in match e with

| Root(n) -> Elem(Root(n), 0.0, 0.0, 0.0, 0.0, filltree sons ptab)

| Node(n) -> Elem(Node(n), 0.0, 0.0, 0.0, 0.0, filltree sons ptab)

| Site(n) -> Elem(Site(n), 0.0, 0.0, 45.0, 30.0,[])

and filltree roots ptab = match roots with

| [] -> []

| head:: tail -> filltree2 head ptab:: filltree tail ptab;;

let rec fixsize2 e l minspaz= match e with

| Elem(Root(n), x, y, rx, ry,[]) ->

Elem(Root(n), x, y, max (List.assoc n l) minspaz, 40.0,[])

| Elem(Node(n), x, y, rx, ry,[]) ->

Elem(Node(n), x, y, 45.0, 30.0,[])

| Elem(Site(n), x, y, rx, ry, _) ->

Elem(Site(n), x, y, 45.0, 30.0,[])

| Elem(Root(n), x, y, rx, ry, sns) ->

let xs1 = xsize sns l minspaz in

let minsize = List.assoc n l in

let xs = (max (fst(xs1) +.60.0 *.float_of_int (1 + List.length sns))

minsize)+.minspaz in

Elem(Root(n), x, y, xs , xs /.1.5, snd(xs1))

| Elem(Node(n), x, y, rx, ry, sns) ->

let xs1 = xsize sns l minspaz in

let xs = fst(xs1) +.30.0 *.float_of_int (1 + List.length sns) in

Elem(Node(n), x, y, xs, xs /.1.5, snd(xs1))

and fixsize t l minspaz= match t with

| [] -> []

| head:: tail -> fixsize2 head l minspaz:: fixsize tail l minspaz

and xsize t l minspaz = let t1 = fixsize t l minspaz in (xsize1 t1, t1)

and xsize1 t = match t with

| [] -> 0.0

134 APPENDICE C. SORGENTI DEL VISUALIZZATORE

| Elem(_, x, y, rx, ry, _):: tail -> rx +.xsize1 tail;;

let rec heights t = match t with

| [] -> []

| Elem(_, _, _, _, ry, _):: tail -> ry:: heights tail;;

let rec fixheight ts = match ts with

| [] -> []

| Elem(Root(n), x, y, rx, ry, sns):: tail ->

let newry = List.fold_right max (heights sns) 0.0 in

Elem(Root(n), x, y, rx, newry +.120.0, sns):: fixheight tail

| head:: tail -> head:: fixheight tail;;

let rec setrootsheight t h = match t with

| [] -> []

| Elem(e, x, y, rx, ry, sns):: tail ->

Elem(e, x, y, rx, h, sns):: setrootsheight tail h;;

let rec fixpos2 e h l minspaz rootsp = match e with

| Elem(Root(n), x, y, rx, ry, sns) ->

let sons = fixpos3 sns h ((max 60.0 minspaz) +.l) 2.0 minspaz rootsp in

Elem(Root(n), l, y, rx, ry, sons)

| Elem(Node(n), x, y, rx, ry, sns) ->

let sons = fixpos3 sns h (30.0 +.l) 1.0 minspaz rootsp in

Elem(Node(n), l +.rx /.2.0, h /.2.0, rx, ry, sons)

| Elem(Site(n), x, y, rx, ry, _) ->

Elem(Site(n), l, h /.2.0 -.15.0, rx, ry,[])

and fixpos3 sns h l m minspaz rootsp= match sns with

| [] -> []

| Elem(a, x, y, rx, ty, sns):: tail ->

fixpos2 (Elem(a, x, y, rx, ty, sns)) h l minspaz 0.::

fixpos3 tail h (l +.(max (minspaz*.rootsp) (30.0 *.m)) +.rx)

m minspaz rootsp;;

let rec fixpos t h l minspaz = match t with

| [] -> []

135

| Elem(a, x, y, rx, ry, sns):: tail ->

(fixpos2 (Elem(a, x, y, rx, ry, sns)) h l minspaz 1.)::

fixpos tail h (l +.rx +.20.0) minspaz;;

let rec allnodes s = match s with

| [] -> []

| Elem(Root(n), x, y, rx, ry, sns):: tail -> allnodes tail

| Elem(Site(n), x, y, rx, ry, sns):: tail -> allnodes tail

| Elem(Node(n), x, y, rx, ry, sns):: tail ->

[n]@(allnodes sns)@allnodes tail;;

let rec filterlinksfromport l s ty = match l with

| [] -> []

| (Port(p, n), NameEdge(d, td)):: tail when (is_in_list n s & td = ty) ->

d:: filterlinksfromport tail s ty

| head:: tail -> filterlinksfromport tail s ty;;

let rec nonportlinks l ty = match l with

| [] -> []

| (Name(s, ts), NameEdge(d, td)):: tail when td = ty ->

(d, td):: nonportlinks tail ty

| head:: tail -> nonportlinks tail ty;;

let eqtn x y a b p m =

y +.sqrt(b ** 2.-.b ** 2./.a ** 2.*.(p -.x) ** 2.) *.m;;

let rec thisrootlinks root nms = match nms with

| [] -> []

| (n, (r, x, y, t)):: tail when root = r ->

(n, (r, x, y, t)):: thisrootlinks root tail

| head:: tail -> thisrootlinks root tail;;

let rec printnames l = match l with

| [] -> ""

| (n, (x, y, t)):: tail ->

"<text x=\""^string_of_float x^"\" y=\""^string_of_float y^

136 APPENDICE C. SORGENTI DEL VISUALIZZATORE

"\" style=\"font-size:15\">"^n^"</text>\n"^printnames tail;;

let rec findinlist e l ty = match l with

| [] -> (nan, nan)

| (n, (x, y, t)):: tail when n = e & t = ty -> (x, y)

| head:: tail -> findinlist e tail ty;;

let rec countocc tab l = match l with

| [] -> tab

| (Port(p, n), NameEdge(d, td)):: tail when td ="onp" ->

if (Hashtbl.mem tab n)

then (let (t, b, e) = Hashtbl.find tab n in

Hashtbl.replace tab n (t +.1., b, e))

else Hashtbl.add tab n (1., 0., 0.); countocc tab tail

| (Port(p, n), NameEdge(d, td)):: tail when td ="inm" ->

if (Hashtbl.mem tab n)

then (let (t, b, e) = Hashtbl.find tab n in

Hashtbl.replace tab n (t, b +.1., e))

else Hashtbl.add tab n (0., 1., 0.); countocc tab tail

| (Port(p, n), NameEdge(d, td)):: tail when td ="e" ->

if (Hashtbl.mem tab n)

then (let (t, b, e) = Hashtbl.find tab n in

Hashtbl.replace tab n (t, b, e +.1.))

else Hashtbl.replace tab n (0., 0., 1.); countocc tab tail

| head:: tail -> countocc tab tail;;

let rec hashtree t tab occ = match t with

| [] -> ()

| Elem(Node(n), x, y, rx, ry, sns):: tail ->

if (Hashtbl.mem occ n)

then let (t, b, e) = Hashtbl.find occ n in

Hashtbl.add tab n (x, y, rx, ry, x -.rx /.2.+.10., (rx -.20.) /.t,

x -.rx /.2.+.10., (rx -.20.) /.b,x -.rx /.2., 20./.e, x +.rx /.2.);

hashtree sns tab occ;

hashtree tail tab occ

else hashtree sns tab occ;

137

hashtree tail tab occ

| Elem(Root(n), x, y, rx, ry, sns):: tail ->

hashtree sns tab occ;

hashtree tail tab occ

| head:: tail -> hashtree tail tab occ;;

let rec edges l = match l with

| [] -> []

| (Port(p, n), NameEdge(d, t)):: tail when (t ="e") -> d:: edges tail

| (Name(s, ts), NameEdge(d, td)):: tail when (td ="e") -> d:: edges tail

| head:: tail -> edges tail;;

let rec rootlinks s l nms ty = match nms with

| [] -> []

| head:: tail ->

if (is_in_list head (filterlinksfromport l s ty))

then head:: rootlinks s l tail ty

else rootlinks s l tail ty;;

let rec makelist l n t = match l with

| [] -> []

| head:: tail -> (head, (n, 0., 0., t)):: makelist tail n t;;

let rec in_allnodes_list e l = match l with

| [] -> false

| (n, (r, x, y, t)):: tail -> if (n = e) then true else in_allnodes_list e tail;;

let rec singleallnodes l = match l with

| [] -> []

| (n, (r, x, y, t)):: tail when not(in_allnodes_list n tail) ->

(n, (r, x, y, t)):: singleallnodes tail

| head:: tail -> singleallnodes tail;;

let rec linksfromname l t = match l with

| [] -> []

| (Name(s, ts), NameEdge(d, td)):: tail when t = td -> d:: linksfromname tail t

138 APPENDICE C. SORGENTI DEL VISUALIZZATORE

| head:: tail -> linksfromname tail t;;

let rec difference l1 l2 = match l1 with

| [] -> []

| head:: tail when (not (is_in_list head l2)) -> head:: difference tail l2

| head:: tail -> difference tail l2;;

let rec maxvalue l = match l with

| [] -> []

| (n, t, b):: tail -> (n, max t b):: maxvalue tail;;

let rec makerootlist total acc =

if (acc < total)

then Root(acc):: makerootlist total (acc + 1)

else [];;

Bibliografia

[1] Lars Birkedal, Troels Christoffer Damgaard, Arne J. Glenstrup, and Robin Mil-

ner. Matching of bigraphs. Electr. Notes Theor. Comput. Sci., 175(4):3–19, 2007.

7

[2] Lars Birkedal, Thomas Hildebrandt, Arne J. Glenstrup, Mikkel Bund-

gaard, Troels C. Damgaard, Søren Debois, Ebbe Elsborg, and Espen

Højsgaard. Bigraphical programming language, 2004. Available at

http://www.itu.dk/research/pls/wiki/index.php/Bigraphical_

Programming_Languages_(BPL). 1

[3] Davide Grohmann and Marino Miculan. An algebra for directed bigraphs. In

Ian Mackie and Detlef Plump, editors, Pre-proceedings of TERMGRAPH 2007,

ENTCS. Elsevier, 2007. 1, 1, 2.3.1

[4] Davide Grohmann and Marino Miculan. Directed bigraphs. In Proc. XXIII

MFPS, volume 173 of ENTCS, pages 121–137. Elsevier, 2007. 1, 1, 1, 2.2

[5] O. H. Jensen and Robin Milner. Bigraphs and mobile processes (revised). Techni-

cal report UCAM-CL-TR-580, Computer Laboratory, University of Cambridge,

2004. 2.1

[6] Ole Høgh Jensen and Robin Milner. Bigraphs and transitions. In POPL, pages

38–49, 2003. 1

[7] Robin Milner. Bigraphical reactive systems. In CONCUR, pages 16–35, 2001. 1

[8] Robin Milner. Pure bigraphs: Structure and dynamics. Information and

Computation, 204(1):60–122, 2006. 1, 2.1.1

[9] Raul Pellarini. Implementazione dei Bigrafi Diretti: strutture dati, algebra e

relative pushout. ., 2008. 1