I P-invarianti di una rete di Petri sono essenziali per

RELAZIONE DEL PROGETTO PER L’ESAME
DI
AUTOMAZIONE INDUSTRIALE
Prof. Ferrarini
A.A. 1999/2000
OTTIMIZZAZIONE DEGLI
ALGORITMI PER IL CALCOLO DI
P-INVARIANTI
Davide Pozzi
Politecnico di Milano
Facoltà di Ingegneria di Como
Indice
ABSTRACT ...................................................................................................................................................................... 3
1.INTRODUZIONE.......................................................................................................................................................... 3
2.MODALITÀ D’USO ..................................................................................................................................................... 3
3.FUNZIONALITÀ IMPLEMENTATE ........................................................................................................................ 4
4.IMPLEMENTAZIONE DEGLI ALGORITMI .......................................................................................................... 6
4.1.DESCRIZIONE DELL'ALGORITMO ................................................................................................................................. 6
4.1.1.CONFRONTO DEI SUPPORTI ..................................................................................................................................... 6
4.1.2.SELEZIONE DELLA COLONNA DA ANNULLARE............................................................................................................ 6
4.1.3.CLASSIFICAZIONE DELLE RIGHE DELLA MATRICE ...................................................................................................... 7
4.1.4.PRE-ELIMINAZIONE DELLE SEQUENZE...................................................................................................................... 7
4.1.5.FAST TEST OF MINIMALITY - TEST OF MINIMALITY ..................................................................................................... 7
4.2.OTTIMIZZAZIONI UTILIZZATE NEL CALCOLO DEI P-INVARIANTI FINALIZZATO AL CALCOLO DEI SIFONI DI UNA PN….8
4.2.1.ELIMINAZIONE DI P-INVARIANTI DI CSTAR_AUX CONTENENTI P-INVARIANTI DI C……………………………………….8
4.2.2.ELIMINAZIONE DI P-INVARIANTI DI CSTAR_AUX CHE CONTENGONO RIGHE NON MINIME DELLA SOLUZIONE…………..9
5.CONCLUSIONI ........................................................................................................................................................... 10
APPENDICE A: CODICE MATLAB .......................................................................................................................... 11
APPENDICE B: GRAFICI DI PESIM DI ALCUNE RETI UTILIZZATE PER IL TESTING DEL
PROGRAMMA .............................................................................................................................................................. 29
2
Abstract
I P-invarianti di una rete di Petri sono essenziali per studiarne le proprietà. Gli algoritmi per
calcolare i P-invarianti minimi di una rete di Petri sono però molto complessi. Alcuni studiosi
hanno però proposto algoritmi per ridurre questo problema. In particolare qui di seguito viene
descritta la realizzazione software di uno di questi algoritmi: quello proposto da J. M. Colom e M.
Silva. Inoltre viene inoltre presentata l'implementazione di una versione di questo algoritmo
appositamente ottimizzata per il calcolo dei sifoni di una rete di Petri.
1.Introduzione
Lo scopo di questo progetto è di realizzare algoritmi ottimizzati per il calcolo dei P-invarianti in una
rete di Petri, a partire dalla sua matrice di incidenza.
Due sono i principali programmi realizzati: uno generico per il calcolo dei P-invarianti in una rete di
Petri, e uno appositamente studiato per il calcolo dei P-invarianti finalizzato al calcolo dei sifoni di
una rete di Petri. Per ogni programma sono state realizzate due versioni che differiscono
leggermente per l'algoritmo implementato (come sarà spiegato in seguito).
L’implementazione è nel linguaggio degli script di Matlab, e ne rispecchia pertanto lo stile; dei
programmi realizzati il primo sostituisce quello analogo presente nel tool software per le reti di
Petri realizzato dallo studente Stefano Maggi, il secondo invece non è presente in questo tool.
Il primo programma non richiede l'uso di altri script per il suo funzionamento (quello originale
richiedeva l'uso di uno script che calcolava il supporto minimo di un insieme di vettori, suppmin.m,
ma per l'algoritmo realizzato ciò non è necessario), ma può essere utilizzato da altri programmi
(presenti nel tool di Maggi). Nella realizzazione del programma si è puntato a realizzare uno script
robusto e efficiente, che terminasse l'esecuzione dove quello originario non riusciva e che
realizzasse le stesse funzioni dello script originario con minore dispendio di risorse.
Il secondo programma richiede l'uso di due script per il funzionamento: uno è lo script suppmin.m,
che era presente nel tool di maggi ma che è stato sostituito da una nuova versione realizzata dal
professor Ferrarini; l'altro è una versione da me modificata dello script sifoni.m, sempre fornitami
dal professor Ferrarini e sostituente l'analogo script realizzato da Maggi.
L'algoritmo per il calcolo dei P-invarianti di una rete di Petri implementato negli script è descritto
nell'articolo: "Convex Geometry and Semiflows in P/T Nets. A Comparative Study of Algorithms
for Computation of Minimal P-Semiflows." di J. M. Colom e M. Silva.
La versione di Matlab utilizzata è la 5.3. Per studiare casi di test con cui verificare il corretto
funzionamento del programma si è utilizzato Pesim.
2.Modalità d’uso
Gli script forniti sono utilizzabili come qualsiasi altra funzione di Matlab, digitando al prompt dello
stesso il nome della funzione da chiamare con i dovuti parametri di ingresso e uscita.
Si presuppone comunque una conoscenza di base dell’ambiente di lavoro di Matlab, nel quale
bisogna comunque operare ad esempio per inserire le matrici.
3
3.Funzionalità implementate
Calcolo dei P-invarianti non canonici - versione con fast test of minimality
P = PINVARIANTI_FToM(C) calcola i P-invarianti di una rete di Petri avente C come matrice di
incidenza. Versione che utilizza il "Fast Test of Minimality". Ritorna una matrice di dimensioni
<numero di P-invarianti> * <numero di posti della rete> in cui ogni riga rappresenta un Pinvariante.
Calcolo dei P-invarianti non canonici - versione con test of minimality
P = PINVARIANTI_ToM(C) calcola i P-invarianti di una rete di Petri avente C come matrice di
incidenza. Versione che utilizza il "Test of Minimality". Ritorna una matrice di dimensioni
<numero di P-invarianti> * <numero di posti della rete> in cui ogni riga rappresenta un Pinvariante.
Calcolo dei P-invarianti ottimizzato per il calcolo dei sifoni di una PN versione con fast test of minimality
PINVARIANTI_S_FToM(P, Cstar_aux) calcola i P-invarianti di una rete di Petri modificata per il
calcolo dei sifoni avente Cstar_aux come matrice di incidenza; tra i P-invarianti di Cstar_aux vi
sono anche i P-invarianti della rete originaria, contenuti in P, essi vengono esclusi dal calcolo dei Pinvarianti a partire da Cstar_aux e vengono aggiunti al termine dell'algoritmo agli altri P-invarianti
trovati. Versione che utilizza il "Fast Test of Minimality". Ritorna una matrice di dimensioni
<numero di P-invarianti> * <numero di posti della rete> in cui ogni riga rappresenta un Pinvariante.
Calcolo dei P-invarianti ottimizzato per il calcolo dei sifoni di una PN versione con test of minimality
PINVARIANTI_S_ToM(P, Cstar_aux) calcola i P-invarianti di una rete di Petri modificata per il
calcolo dei sifoni avente Cstar_aux come matrice di incidenza; tra i P-invarianti di Cstar_aux vi
sono anche i P-invarianti della rete originaria, contenuti in P, essi vengono esclusi dal calcolo dei Pinvarianti a partire da Cstar_aux e vengono aggiunti al termine dell'algoritmo agli altri P-invarianti
trovati. Versione che utilizza il "Test of Minimality". Ritorna una matrice di dimensioni <numero di
P-invarianti> * <numero di posti della rete> in cui ogni riga rappresenta un P-invariante.
Calcolo dei sifoni di una PN - versione con fast test of minimality
SIFONI_FToM(I,O) ritorna una matrice in cui ogni riga rappresenta un sifone della rete di Petri
avente I come matrice di ingresso e O come matrice di uscita. Usa la versione di Pinvarianti_S con
il "Fast Test of Minimality". Ogni riga contiene gli indici (riferiti alla matrice di incidenza) dei posti
che fanno parte del sifone.
Calcolo dei sifoni di una PN - versione con test of minimality
SIFONI_ToM(I,O) ritorna una matrice in cui ogni riga rappresenta un sifone della rete di Petri
avente I come matrice di ingresso e O come matrice di uscita. Usa la versione di Pinvarianti_S con
il "Test of Minimality". Ogni riga contiene gli indici (riferiti alla matrice di incidenza) dei posti che
fanno parte del sifone.
4
Ho realizzato anche due semplicissime funzioni per ricavare la matrici degli ingressi I e la matrice
delle uscite O di una PN a partire dalla matrice di incidenza C della rete per agevolare l'utilizzo
degli script per il calcolo dei sifoni. Queste funzioni vengono riportate solo in Appendice A.
5
4.Implementazione degli algoritmi
Vengono qui brevemente descritte le caratteristiche principali dell'algoritmo utilizzato per gli script
di calcolo dei P-invarianti (pinvarianti_ftom.m, pinvarianti_tom.m, pinvarianti_s_ftom.m,
pinvarianti_tom.m) così come è stato implementato. Per una descrizione esauriente dell'algoritmo in
generale si rimanda all'articolo già citato in precedenza. Per tutti i richiami di carattere teorico
riguardanti le reti di Petri, si rimanda agli appunti del corso di Automazione Industriale del prof.
Luca Ferrarini.
4.1.Descrizione dell'algoritmo
L'algoritmo descritto da Colom e Silva propone cinque ottimizzazioni da applicare all'algoritmo non
ottimizzato. Le cinque ottimizzazioni realizzabili sono le seguenti:
 confronto dei supporti prima di generare una nuova riga;
 selezione della colonna da annullare secondo un approccio euristico;
 classificazione delle righe della matrice, prima di annullare una colonna, in tre sottomatrici che
raggruppano le righe in cui colonna da annullare è rispettivamente pari a 0, positiva o negativa;
 pre-eliminazione di sequenze;
 "fast test of minimality".
Nelle prossime sezioni viene descritta l'implementazione nello script di ogni ottimizzazione.
4.1.1.Confronto dei supporti
Il confronto dei supporti consiste nel verificare che il supporto di un nuovo possibile P-invariante
non contenga il supporto dei P-invarianti esistenti, infatti, se così non fosse, il nuovo P-invariante
non sarebbe minimo. Per questo il confronto viene fatto prima di generare una nuova riga come
combinazione lineare di altre due. Nello script realizzato il confronto viene fatto tra il supporto del
nuovo P-invariante trovato e tra quelli generati in precedenza e contenuti nelle righe delle tre
matrici in cui viene divisa la matrice di incidenza (vedi 4.1.3.). Sono escluse dal confronto le righe
che generano il nuovo P-invariante.
4.1.2.Selezione della colonna da annullare
L'algoritmo proposto nell'articolo suggerisce di utilizzare approcci euristici per selezionare la
colonna da annullare. In particolare questa ottimizzazione è basata sul calcolo dell' expansion factor
delle colonne della matrice su cui l'algoritmo opera. L' expansion factor rappresenta il numero di
nuove righe aggiunte annullando la colonna k ed è definito come:
F(k): = Pk*Nk - (Pk+Nk), ove Pk e Nk sono rispettivamente il numero di elementi positivi e
negativi della colonna k da annullare.
Il valore di nuove righe da aggiungere, combinando paia di righe, è Pk*Nk.
Chiamando k la colonna da annullare, l'ottimizzazione prevede di selezionare k in modo che sia la
prima colonna non nulla della matrice su cui opera l'algoritmo tale che il suo expansion factor sia
negativo; venendo a mancare una colonna che soddisfi questa condizione l'euristica prevede di
scegliere la colonna k che minimizzi Pk*Nk.
Inizialmente questa ottimizzazione non era stata implementata con successo, poi è stata realizzata
Correttamente portando a una maggiore velocità computazionale (meno righe generate
dall'algoritmo).
6
4.1.3.Classificazione delle righe della matrice
Questa ottimizzazione consiste nel suddividere la matrice su cui l'algoritmo opera in tre sottomatrici
a seconda del valore assunto dalla colonna da annullare nelle righe della matrice. Le righe in cui
questo valore è nullo vengono poste in una sottomatrice, le altre due sottomatrici (Upos e Uneg
nello script) hanno le righe in cui il valore è rispettivamente positivo o negativo. Una nuova riga
viene generata combinando linearmente una riga di Upos con una riga di Uneg. Questa soluzione
permette di ridurre il numero di test necessari per selezionare due righe i cui valori nella colonna k
da annullare sono non nulli e di segno opposto.
4.1.4.Pre-eliminazione di sequenze
L'algoritmo proposto suggeriva di annullare tutte le colonne della matrice di incidenza che avessero
un solo elemento positivo e un solo elemento negativo (ovvero di eliminare le transizioni della PN
con un solo arco in ingresso e un solo arco in uscita: le sequenze), prima di proseguire con il resto
dell'algoritmo. L'implementazione di questa procedura ha causato vari problemi. Innanzitutto per
mezzo di semplici esempi si è potuto verificare che questa operazione può portare a risultati errati
nel caso l'elemento positivo e quello negativo siano sì unici ma diversi in modulo. Inoltre, sempre
dopo vari test del programma, si è constatato che questa ottimizzazione tendeva a portare errori in
alcune reti, anche se i valori in modulo degli elementi delle colonne da annullare erano identici, nel
caso si annullassero tutte le sequenze. In particolare dopo varie prove ho potuto stabilire che non
porta errori eliminare solo una di tutte le sequenze della rete, a meno che non vi sia una sola
sequenza nella rete, nel qual caso questa non deve essere eliminata.
In conclusione nello script questa ottimizzazione è stata implementata nel seguente modo:
 se la matrice di incidenza ha una sola colonna con un elemento negativo e uno positivo uguali
in modulo, essa non viene annullata;
 se la matrice di incidenza ha più di una colonna con un elemento negativo e uno positivo
uguali in modulo, solo la prima di esse viene annullata.
Si è deciso di tenere questa ottimizzazione in tale forma limitata poiché essa offre pur sempre un
discreto vantaggio, che diventa grande nel caso del calcolo di T-invarianti, in cui ciò causa
l'annullamento di una riga della matrice su cui si calcolano i T-invarianti (si veda l'implementazione
di tinvarianti.m nel tool di Maggi).
4.1.5.Fast test of Minimality - Test of Minimality
L'ultima ottimizzazione prevista nell'algoritmo descritto da Colom e Silva prevede l'utilizzo di una
condizione sufficiente per escludere P-invarianti non minimi prima di generare nuove righe e di
effettuare il confronto dei supporti. Questa condizione prevede il calcolo del numero di elementi
diversi da 0 del supporto del nuovo P-invariante ( card(||Y||) ) e il calcolo del rank-upperbound.
Quest'ultimo è il limite superiore del rango di sottomatrici di C generate a partire dal P-invariante
considerato. Esso viene calcolato nello script come il numero di elementi diversi da 0 del vettore
(ristretto alle colonne annullate fino a quel momento) costituito dall'unione delle righe della matrice
di incidenza indicizzate dal P-invariante considerato. La condizione sufficiente risulta essere la
seguente:
-
un P-invariante Y non è minimo se card(||Y||) > rank-upperbound +1
Questa ottimizzazione non era stata inizialmente implementata del tutto correttamente, in seguito è
stata realizzata con successo. L'errore era nel calcolo delle colonne annullate fino al momento di
applicare il test. Il calcolo esatto, implementato negli script realizzati, prevede l'utilizzo di una
7
maschera delle colonne attivamente annullate: esse sono quelle via via fornite dall'euristica di
selezione della colonna da annullare (vedi il paragrafo 4.2.2.), a meno che a seguito della selezione
di questa colonna le matrici Upos e/o Uneg (vedi paragrafo 4.2.3.) non siano nulle (nel qual caso la
parte principale dell'algoritmo non viene eseguita): in questo caso la colonna viene tolta dalla
maschera delle colonne attivamente annullate.
Solo se il test dà esito positivo viene eseguito nello script il confronto dei supporti, altrimenti si
passa a un'altra riga.
Il Fast Test of Minimality è una condizione sufficiente tratta dalla condizione necessaria e
sufficiente data dal Test of Minimality:
-
un P-invariante Y è minimo se e solo se card(||Y||) = rank(subC) +1
ove rank(subC) rappresenta il rango della sottomatrice della matrice di incidenza C composta dalle
righe di C indicizzate da i per le quali Y[i] è un valore diverso da 0.
Nell'articolo di Colom e Silva questa condizione non viene considerata perché il calcolo del rango
di una matrice era considerato troppo oneroso. In realtà, implementando questa ottimizzazione, ho
potuto verificare che non risulta significativamente diversa dall'altra in termini di velocità
computazionale e di efficienza. Inoltre l'algoritmo risulta utilizzando il Test of Minimality assai più
semplice anche perché non è più necessario realizzare il confronto dei supporti (vedi paragrafo
4.2.1).
Ho quindi deciso di implementare due versioni degli script, una con il Fast Test of Minimality, e
l'atra con il Test of Minimality, lasciando la scelta della versione da utilizzare all'utente del software.
4.2.Ottimizzazioni utilizzate nel calcolo dei P-invarianti finalizzato al
calcolo dei sifoni di una PN
Oltre alle ottimizzazioni proposte nell'algoritmo descritto da Colom e Silva, nella realizzazione
degli script pinvarianti_s_ftom.m e pinvarianti_s_tom.m sono state introdotte altre ottimizzazioni
relative al caso del calcolo dei p-invarianti utilizzato per trovare il i sifoni di una PN.
Sono state introdotte due ottimizzazioni per questo caso:
 eliminazione di P-invarianti di Cstar_aux contenenti P-invarianti di C;
 eliminazione di P-invarianti di Cstar_aux che contengono righe non minime della soluzione.
Nelle prossime sezioni viene descritta l'implementazione nello script di ogni ottimizzazione (per
comodità ci si riferirà solo allo script pinvarianti_s_tom.m, ma quanto detto vale allo stesso modo
anche per pinvarianti_s_ftom.m).
4.2.1.Eliminazione di P-invarianti di Cstar_aux contenenti P-invarianti di C
Lo script pinvarianti_s_tom riceve in ingresso la matrice Cstar_aux (la matrice C opportunamente
estesa per il calcolo dei sifoni, corrispondente alla rete originaria modificata con posti fittizi) e deve
fornire i suoi P-invarianti. Di questi poi saranno solo considerate le colonne relative alla rete
originaria (che sono le prime colC colonne, ove colC è il numero di colonne di C), quindi lo stesso
numero di colonne di C. Per come è strutturata Cstar_aux, nei suoi P-invarianti troviamo anche
quelli di C, se consideriamo le prime colC colonne. Dato che la matrice Cstar_aux è di dimensioni
molto maggiori di quelle di C, e l'algoritmo può diventare per essa assai pesante, si vuole evitare di
generare durante l'algoritmo le righe che contengono i P-invarianti di C. A tale scopo in ingresso a
8
pinvarianti_s_tom.m vengono passati anche i P-invarianti di C (calcolati con pinvarianti_ftom.m o
pinvarianti_tom.m): prima di generare una riga come combinazione lineare di altre due viene
confrontato il supporto (limitato alle prime colC colonne) di un candidato P-invariante di Cstar_aux
con i supporti dei P-invarianti di C. Se il supporto del candidato P-invariante risulta uguale a uno di
questi, non si procede oltre nell'algoritmo e si passa un nuovo candidato P-invariante.
In seguito a questa ottimizzazione i tempi di calcolo sono diminuiti molto, ma venivano ancora
generate troppe righe e l'algoritmo risultava di conseguenza ancora pesante.
Si è allora proceduto a un'ulteriore ottimizzazione: non si procede nell'algoritmo passando al
candidato successivo anche se il supporto del candidato P-invariante di Cstar_aux (limitato alle
prime colC colonne) contiene il supporto di uno dei P-invarianti di C (questi P-invarianti di
Cstar_aux darebbero luogo a sifoni non minimi).
Con questo meccanismo il numero di righe generate dall'algoritmo è diminuito nettamente e le
prestazioni dello stesso sono migliorate moltissimo, in particolare come tempi di calcolo.
4.2.2.Eliminazione di P-invarianti di Cstar_aux che contengono righe non
minime della soluzione
Volendo ottimizzare ulteriormente l'algoritmo, ho osservato che in alcune reti su cui lo testavo, in
particolare nella rete provadav2 (vedi appendice B), la soluzione relativa a pinvarianti_s_tom.m
(intesa come la matrice dei P-invarianti di Cstar_aux limitata alle sue prime colC colonne)
presentava righe che si ripetevano o ne contenevano altre e che davano quindi luogo a sifoni non
minimi. Ho deciso allora di fare in modo che queste righe non fossero generate. A questo scopo, a
mano a mano che vengono generate righe come combinazioni lineari di altre due, il supporto di
queste, limitato alle prime colC colonne, viene inserito in una matrice di supporto. Il supporto di
ogni nuovo candidato P-invariante (limitato alle prime colC colonne) viene allora confrontato,
prima di procedere con l'algoritmo, con le righe di questa matrice: se il candidato è uguale a o
contiene una delle righe di questa matrice non si procede con l'algoritmo e si passa a un nuovo
candidato.
Anche se l'impatto di questa ottimizzazione non è stato forte come quello della precedente, esso ha
permesso in alcuni casi (come per la citata rete provadav2) di diminuire di molto le righe generate,
e quindi di portare a una maggiore velocità di esecuzione.
Inoltre le due ottimizzazioni hanno anche migliorato la robustezza generale dell'algoritmo, in
particolare nei casi di reti di grandi dimensioni.
9
5.Conclusioni
In conclusione l'implementazione degli algoritmi descritti ha portato dei vantaggi rispetto
all'utilizzo degli script non ottimizzati. Per quanto riguarda gli algoritmi per il calcolo generico dei
P-invarianti, vi sono alcune matrici di incidenza che causavano errori nello script di Maggi per il
calcolo dei P-invarianti: in particolare esso si bloccava in corrispondenza di una reti non coperte da
P-invarianti, invece di riportare un risultato nullo, e si bloccava con alcune reti di dimensioni
piuttosto elevate. Il nuovo algoritmo negli stessi casi, riporta nel primo un risultato nullo e nel
secondo giunge a buon fine. Inoltre in generale l'algoritmo ottimizzato genera in esecuzione meno
righe del precedente. Quindi i nuovi script hanno portato due notevoli vantaggi:


una maggiore robustezza in genere;
maggiore efficienza computazionale.
Le stesse conclusioni si possono trarre per gli script per il calcolo dei P-invarianti finalizzato al
calcolo dei sifoni. In particolare grazie alle sue due ottimizzazioni presentate i tempi di calcolo sono
diminuiti in maniera veramente notevole.
10
Appendice A: codice Matlab
function P = pinvarianti_FToM(C)
%PINVARIANTI_FToM
Calcolo dei P-invarianti di una rete di Petri
%
PINVARIANTI_FToM(C) calcola i P-invarianti di una rete di Petri
%
avente C come matrice di incidenza.
%
Versione che utilizza il "Fast Test of Minimality".
%
Ritorna una matrice di dimensioni
%
<numero di P-invarianti> * <numero di posti della rete>
%
in cui ogni riga rappresenta un P-invariante.
%disp('Inizio Pinvarianti'),pause
cont_righe=0;
% conta le righe via via generate dall'algoritmo
trovato=0; % flag: indica che si è trovata la colonna da cui parte l'algoritmo principale
strart_col=0; % colonna di partenza ottenuta calcolando l'"expansion factor"
start_col2=0; % colonna di partenza che minimizza il prodotto Pk*Nk (definiti sotto)
i=0; % contatore per i prodotti parziali Pk*Nk
[numposti, numtrans] = size(C);
U° = sparse([C eye(numposti)]); % creo la matrice U°
P=[]; % matrice che conterrà i p-invarianti
ann=0; % contatore colonne annullate
col_ann=0; % indica quale colonna è stata annullata
c=0; % contatore delle colonne da annullare
% conto le colonne da annullare
for k = 1:numtrans %per ogni colonna di C
pos=find(C(:,k)>0); % indici degli elementi positivi della k-esima colonna di C
Pk = length(pos); % numero degli elementi positivi della k-esima colonna di C
neg=find(C(:,k)<0); % indici degli elementi negativi della k-esima colonna di C
Nk = length(neg); % numero degli elementi negativi della k-esima colonna di C
if Pk * Nk == 1 & abs(U°(pos,k)) == abs(U°(neg,k)) % se Pk=Nk=1 e l'elemento positivo
% e negativo sono uguali in modulo
c=c+1;
end
end
% prima ottimizzazione: viene annullata una colonna di U° che abbia un elemento
% positivo e un elemento negativo uguali in modulo, a meno che la colonna con queste
% caratteristiche non sia una sola
for k = 1:numtrans %per ogni colonna di A°
pos=find(U°(:,k)>0); % indici degli elementi positivi della k-esima colonna di A°
Pk = length(pos); % numero degli elementi positivi della k-esima colonna di A°
neg=find(U°(:,k)<0); % indici degli elementi negativi della k-esima colonna di A°
Nk = length(neg); % numero degli elementi negativi della k-esima colonna di A°
% se Pk=Nk=1 e non si è ancora annullata la colonna di C e l'elemento
% positivo e il negativo sono uguali in modulo e la colonna da annullare non è una sola
if Pk * Nk == 1 & abs(U°(pos,k)) == abs(U°(neg,k)) & ann < 1 & ann < 1 & c > 1
U°(pos,k) = 0; % annullo la
U°(neg,k) = 0; % k-esima colonna
Pk=0; % ora Pk è nullo
Nk=0; % e anche Nk
ann=ann+1; % è stata annullata una colonna
col_ann=k; % indica quale colonna è stata annullata
end
end
% viene ora ricercata la colonna di partenza per la parte principale dell'algoritmo
for k = 1:numtrans %per ogni colonna di A°
pos=find(C(:,k)>0); % indici degli elementi positivi della k-esima colonna di C
Pk = length(pos); % numero degli elementi positivi della k-esima colonna di C
neg=find(C(:,k)<0); % indici degli elementi negativi della k-esima colonna di C
Nk = length(neg); % numero degli elementi negativi della k-esima colonna di C
if Pk + Nk ~= 0 & Pk*Nk-(Pk+Nk) < 0 & trovato == 0
% se la colonna è non nulla, l'"expansion factor" è negativo e non ho ancora trovato
% la colonna di partenza
trovato=1; % ho trovato la colonna di partenza
start_col=k;
end
11
if Pk + Nk ~= 0 & trovato == 0 % se la colonna è non nulla e
% non ha un "expansion factor" negativo
prod_Pk_Nk=Pk*Nk; % calcolo Pk*Nk
if i == 0 % se è la prima colonna per cui calcolo Pk*Nk
slack=prod_Pk_Nk; % setto una variabile di confronto a Pk*Nk
i=1; % aggiorno il contatore
start_col2=k; % setto la colonna di partenza secondo questa logica
end
if prod_Pk_Nk < slack % se trovo un prodotto Pk*Nk minore di quello
% calcolato precedentemente
slack=prod_Pk_Nk; % aggiorno la variabile di confronto
start_col2=k; % e la colonna di partenza
end
end
end
if trovato == 0
% se non ho trovato una colonna che soddisfa il criterio
% dell'"expansion factor" negativo
start_col=start_col2; % la colonna di partenza è quella che minimizza Pk*Nk
end
Uk1=U°;
% poni la matrice Uk1 = U°
act_ann=zeros(1,numtrans);
% maschera della colonne attivamente annullate
[numpostiUk1, numcolUk1]=size(Uk1)
k=start_col
% serve solo "numpostiUk1" per l'algoritmo principale;
% mostra a video le due dimensioni
% mostra la colonna di partenza dell'algoritmo principale
act_ann(k)=1;
% metti a 1 il valore della maschera corrispondente alla colonna k
Uk=sparse([]); % inizializza la matrice Uk
Uneg=sparse([]); % inizializza la matrice Uneg
Upos=sparse([]); % inizializza la matrice Upos
while k ~= 0 % inizio dell'algoritmo principale
for j = 1:numpostiUk1 % per ogni riga di Uk1
if Uk1(j, k) == 0 % se l'elemento all'incrocio fra riga j e colonna k è pari a 0
Uk=[Uk; Uk1(j, :)]; % aggiungi la riga con esso ad Uk
elseif Uk1(j, k) < 0 % se l'elemento all'incrocio fra riga j e colonna k è < 0
Uneg=[Uneg; Uk1(j, :)]; % aggiungi la riga con esso ad Uneg
else % se l'elemento all'incrocio fra riga j e colonna k è > 0
Upos=[Upos; Uk1(j, :)]; % aggiungi la riga con esso ad Upos
end
end
% se Uneg e/o Upos sono vuote, metti a 0 il valore della maschera corrispondente
% alla colonna k
if isequal(Uneg,[])
act_ann(k)=0;
end
if isequal(Upos,[])
act_ann(k)=0;
end
[x1, y1]=size(Uneg); % serve solo x1: numero delle righe di Uneg
[x2, y2]=size(Upos); % serve solo x2: numero delle righe di Upos
[xk, yk]=size(Uk); % serve solo xk: numero delle righe di Uk
if x1 ~= 0 & x2 ~= 0 % se le matrici non hanno dimensioni nulle
row1=1; % indice prima riga di Uneg
while row1 <= x1
row2=1; % indice prima riga di Upos
while row2 <= x2
% calcola il supporto del nuovo P-i Y come unione dei supporti dei P-I
% corrispondenti alle righe row1 e row2 rispettivamente di Uneg e di Upos
suppY=spones(Uneg(row1, numtrans+1:numposti+numtrans))|spones(Upos(row2,
numtrans+1:numposti+numtrans));
IsuppY=find(suppY>0); % indici elementi diversi da zero del supporto di Y
card_suppY=length(find(IsuppY>0)); % calcola la cardinalità del supporto di Y
supp_rowC=zeros(1, numtrans); % vettore che conterrà l'unione dei supporti delle
% righe di C indicizzate dal supporto di Y
% calcola l'unione dei supporti delle righe di C indicizzate dal supporto di Y
for f = IsuppY % per ogni valore del supporto di Y
supp_rowC=spones(C(f, :))|supp_rowC; % calcola l'unione dei corrispondenti
% supporti delle righe di C
end
12
% calcola il rank_upperbound
rank_upperbound=length(find(act_ann.*supp_rowC>0));
% ottimizzazione: esegue il "fast test of minimality"
if card_suppY <= rank_upperbound + 1
v=1; % contatore
includes=0; % flag usato nel "support comparison"
% esecuzione del "support comparison": confronto il supporto del P-I trovato
% con il supporto dei P-I presenti in Uk, Uneg o Upos
% confronto con i P-I di Uneg:
while v <= x1 & includes == 0
if v ~= row1
% esegui il "support comparison" fra
% il nuovo P-I e quelli trovati in precedenza
supp_comp=suppY|Uneg(v,numtrans+1:numposti+numtrans);
if supp_comp == suppY % se il nuovo P-I contiene il supporto di altri
% P-I trovati prima
v=x1+1; % termina il "support comparison"
includes=1; % il nuovo P-I ne contiene un altro
else
v=v+1; % altrimenti continua
end
else
v=v+1;
end
end
% confronto con i P-i di Upos:
v=1;
while v <= x2 & includes == 0
if v ~= row2
% esegui il "support comparison" fra
% il nuovo P-I e quelli trovati in precedenza
supp_comp=suppY|Upos(v,numtrans+1:numposti+numtrans);
if supp_comp == suppY % se il nuovo P-I contiene il supporto di altri
% P-I trovati prima
v=x2+1; % termina il "support comparison"
includes=1; % il nuovo P-I ne contiene un altro
else
v=v+1; % altrimenti continua
end
else
v=v+1;
end
end
% confronto con i P-i di Uk:
v=1;
while v <= xk & includes == 0
% esegui il "support comparison" fra
% il nuovo P-I e quelli trovati in precedenza
supp_comp=suppY|Uk(v,numtrans+1:numposti+numtrans);
if supp_comp == suppY % se il nuovo P-I contiene il supporto di altri
% P-I trovati prima
v=xk+1; % termina il "support comparison"
includes=1; % il nuovo P-I ne contiene un altro
else
v=v+1; % altrimenti continua
end
end
if includes ~= 1 % se il P-I non contiene il supporto di altri P-I
alpha=abs(Upos(row2, k)); % calcola il coefficiente alpha
beta=abs(Uneg(row1, k)); % calcola il coefficiente beta
new_row=alpha*Uneg(row1, :)+beta*Upos(row2, :); % calcola la nuova riga
% da aggiungere a Uk
cont_righe=cont_righe+1;
% calcola le righe generate fino ad ora
% calcola il MCD della nuova riga
supp_new_row=find(new_row);
MCD=new_row(supp_new_row(1));
for l = 2:length(supp_new_row)
MCD=gcd(MCD, new_row(supp_new_row(l)));
end
Uk=[Uk; new_row/MCD]; % aggiungi a Uk la nuova riga divisa per il MCD
end
13
end
row2=row2+1; % passa alla successiva riga di Upos
end
row1=row1+1; % passa alla successiva riga di Uneg
end
end
Uneg=sparse([]); % annulla la matrice Uneg
Upos=sparse([]); % annulla la matrice Upos
trovato=0; % % flag: indica che si è trovata la colonna da cui parte l'algoritmo principale
strart_col=0; % colonna di partenza ottenuta calcolando l'"expansion factor"
start_col2=0; % colonna di partenza che minimizza il prodotto Pk*Nk (definiti sotto)
i=0; % contatore per i prodotti parziali Pk*Nk
[numuk,num2uk]=size(Uk);
if numuk == 0
start_col=0;
else
% viene ora ricercata la colonna di partenza per la parte principale dell'algoritmo
for k = 1:numtrans %per ogni colonna di A°
pos=find(Uk(:,k)>0); % indici degli elementi positivi della k-esima colonna di C
Pk = length(pos); % numero degli elementi positivi della k-esima colonna di C
neg=find(Uk(:,k)<0); % indici degli elementi negativi della k-esima colonna di C
Nk = length(neg); % numero degli elementi negativi della k-esima colonna di C
if Pk + Nk ~= 0 & Pk*Nk-(Pk+Nk) < 0 & trovato == 0
% se la colonna è non nulla, l'"expansion factor" è negativo e non ho ancora trovato
% la colonna di partenza
trovato=1; % ho trovato la colonna di partenza
start_col=k;
end
if Pk + Nk ~= 0 & trovato == 0 % se la colonna è non nulla e
% non ha un "expansion factor" negativo
prod_Pk_Nk=Pk*Nk; % calcolo Pk*Nk
if i == 0 % se è la prima colonna per cui calcolo Pk*Nk
slack=prod_Pk_Nk; % setto una variabile di confronto a Pk*Nk
i=1; % aggiorno il contatore
start_col2=k; % setto la colonna di partenza secondo questa logica
end
if prod_Pk_Nk < slack % se trovo un prodotto Pk*Nk minore di quello
% calcolato precedentemente
slack=prod_Pk_Nk; % aggiorno la variabile di confronto
start_col2=k; % e la colonna di partenza
end
end
end
if trovato == 0 % se non ho trovato una colonna che soddisfa il criterio
% dell'"expansion factor" negativo
start_col=start_col2; % la colonna di partenza è quella che minimizza Pk*Nk
end
end
k=start_col % mostra la colonna di partenza dell'algortitmo principale
if k ~= 0 % se k è diverso da 0, poni la posizione della maschera corrispondente a k pari a 1
act_ann(k)=1;
end
Uk1=Uk; % prepara la matrice di partenza Uk1 per l'algoritmo principale
[numpostiUk1, numtransUk1]=size(Uk1); % serve solo "numpostiUk1" per l'algoritmo principale
numpostiUk1 % mostra a video il numero di righe di Uk1
Uk=sparse([]); % setta Uk come matrice nulla
end
% calcola la matrice dei P-I, P
for n=1:numpostiUk1
if Uk1(n,1:numtrans) == zeros(1,numtrans);
P=full([Uk1(n,numtrans+1:numposti+numtrans); P]);
end
end
cont_righe
% metti i P-I trovati in P
% mostra le righe generate dall'algoritmo
14
function P = pinvarianti_ToM(C)
%PINVARIANTI_ToM
Calcolo dei P-invarianti di una rete di Petri
%
PINVARIANTI_ToM(C) calcola i P-invarianti di una rete di Petri
%
avente C come matrice di incidenza.
%
Versione che utilizza il "Test of Minimality".
%
Ritorna una matrice di dimensioni
%
<numero di P-invarianti> * <numero di posti della rete>
%
in cui ogni riga rappresenta un P-invariante.
%disp('Inizio Pinvarianti'),pause
cont_righe=0;
% conta le righe via via generate dall'algoritmo
trovato=0; % flag: indica che si è trovata la colonna da cui parte l'algoritmo principale
strart_col=0; % colonna di partenza ottenuta calcolando l'"expansion factor"
start_col2=0; % colonna di partenza che minimizza il prodotto Pk*Nk (definiti sotto)
i=0; % contatore per i prodotti parziali Pk*Nk
[numposti, numtrans] = size(C);
U° = sparse([C eye(numposti)]); % creo la matrice U°
P=[]; % matrice che conterrà i p-invarianti
ann=0; % contatore colonne annullate
col_ann=0; % indica quale colonna è stata annullata
c=0; % contatore delle colonne da annullare
% conto le colonne da annullare
for k = 1:numtrans %per ogni colonna di C
pos=find(C(:,k)>0); % indici degli elementi positivi della k-esima colonna di C
Pk = length(pos); % numero degli elementi positivi della k-esima colonna di C
neg=find(C(:,k)<0); % indici degli elementi negativi della k-esima colonna di C
Nk = length(neg); % numero degli elementi negativi della k-esima colonna di C
if Pk * Nk == 1 & abs(U°(pos,k)) == abs(U°(neg,k)) % se Pk=Nk=1 e l'elemento positivo
% e negativo sono uguali in modulo
c=c+1;
end
end
% prima ottimizzazione: viene annullata una colonna di U° che abbia un elemento
% positivo e un elemento negativo uguali in modulo, a meno che la colonna con queste
% caratteristiche non sia una sola
for k = 1:numtrans %per ogni colonna di A°
pos=find(U°(:,k)>0); % indici degli elementi positivi della k-esima colonna di A°
Pk = length(pos); % numero degli elementi positivi della k-esima colonna di A°
neg=find(U°(:,k)<0); % indici degli elementi negativi della k-esima colonna di A°
Nk = length(neg); % numero degli elementi negativi della k-esima colonna di A°
% se Pk=Nk=1 e non si è ancora annullata la colonna di C e l'elemento
% positivo e il negativo sono uguali in modulo e la colonna da annullare non è una sola
if Pk * Nk == 1 & abs(U°(pos,k)) == abs(U°(neg,k)) & ann < 1 & ann < 1 & c > 1
U°(pos,k) = 0; % annullo la
U°(neg,k) = 0; % k-esima colonna
Pk=0; % ora Pk è nullo
Nk=0; % e anche Nk
ann=ann+1; % è stata annullata una colonna
col_ann=k; % indica quale colonna è stata annullata
end
end
% viene ora ricercata la colonna di partenza per la parte principale dell'algoritmo
for k = 1:numtrans %per ogni colonna di A°
pos=find(C(:,k)>0); % indici degli elementi positivi della k-esima colonna di C
Pk = length(pos); % numero degli elementi positivi della k-esima colonna di C
neg=find(C(:,k)<0); % indici degli elementi negativi della k-esima colonna di C
Nk = length(neg); % numero degli elementi negativi della k-esima colonna di C
if Pk + Nk ~= 0 & Pk*Nk-(Pk+Nk) < 0 & trovato == 0
% se la colonna è non nulla, l'"expansion factor" è negativo e non ho ancora trovato
% la colonna di partenza
trovato=1; % ho trovato la colonna di partenza
start_col=k;
end
if Pk + Nk ~= 0 & trovato == 0 % se la colonna è non nulla e
% non ha un "expansion factor" negativo
prod_Pk_Nk=Pk*Nk; % calcolo Pk*Nk
if i == 0 % se è la prima colonna per cui calcolo Pk*Nk
slack=prod_Pk_Nk; % setto una variabile di confronto a Pk*Nk
15
i=1; % aggiorno il contatore
start_col2=k; % setto la colonna di partenza secondo questa logica
end
if prod_Pk_Nk < slack % se trovo un prodotto Pk*Nk minore di quello
% calcolato precedentemente
slack=prod_Pk_Nk; % aggiorno la variabile di confronto
start_col2=k; % e la colonna di partenza
end
end
end
if trovato == 0
% se non ho trovato una colonna che soddisfa il criterio
% dell'"expansion factor" negativo
start_col=start_col2; % la colonna di partenza è quella che minimizza Pk*Nk
end
Uk1=U°;
% poni la matrice Uk1 = U°
act_ann=zeros(1,numtrans);
% maschera della colonne attivamente annullate
[numpostiUk1, numcolUk1]=size(Uk1)
k=start_col
% serve solo "numpostiUk1" per l'algoritmo principale;
% mostra a video le due dimensioni
% mostra la colonna di partenza dell'algoritmo principale
act_ann(k)=1;
% metti a 1 il valore della maschera corrispondente alla colonna k
Uk=sparse([]); % inizializza la matrice Uk
Uneg=sparse([]); % inizializza la matrice Uneg
Upos=sparse([]); % inizializza la matrice Upos
while k ~= 0 % inizio dell'algoritmo principale
for j = 1:numpostiUk1 % per ogni riga di Uk1
if Uk1(j, k) == 0 % se l'elemento all'incrocio fra riga j e colonna k è pari a 0
Uk=[Uk; Uk1(j, :)]; % aggiungi la riga con esso ad Uk
elseif Uk1(j, k) < 0 % se l'elemento all'incrocio fra riga j e colonna k è < 0
Uneg=[Uneg; Uk1(j, :)]; % aggiungi la riga con esso ad Uneg
else % se l'elemento all'incrocio fra riga j e colonna k è > 0
Upos=[Upos; Uk1(j, :)]; % aggiungi la riga con esso ad Upos
end
end
% se Uneg e/o Upos sono vuote, metti a 0 il valore della maschera corrispondente
% alla colonna k
if isequal(Uneg,[])
act_ann(k)=0;
end
if isequal(Upos,[])
act_ann(k)=0;
end
[x1, y1]=size(Uneg); % serve solo x1: numero delle righe di Uneg
[x2, y2]=size(Upos); % serve solo x2: numero delle righe di Upos
[xk, yk]=size(Uk); % serve solo xk: numero delle righe di Uk
if x1 ~= 0 & x2 ~= 0 % se le matrici non hanno dimensioni nulle
row1=1; % indice prima riga di Uneg
while row1 <= x1
row2=1; % indice prima riga di Upos
while row2 <= x2
% calcola il supporto del nuovo P-i Y come unione dei supporti dei P-I
% corrispondenti alle righe row1 e row2 rispettivamente di Uneg e di Upos
suppY=spones(Uneg(row1, numtrans+1:numposti+numtrans))|spones(Upos(row2,
numtrans+1:numposti+numtrans));
IsuppY=find(suppY>0); % indici elementi diversi da zero del supporto di Y
card_suppY=length(find(IsuppY>0)); % calcola la cardinalità del supporto di Y
subC=sparse([]); % prepara la sottomatrice di C di cui si calcolerà il rango
for f = IsuppY % per ogni valore del supporto di Y
subC=[subC; C(f, :).*act_ann]; % aggiungi a subC le corrispondenti
% righe di C considerando solo le colonne indicate dalla maschera
end
rank_subC=rank(subC); % calcola il rango di subC
if card_suppY == rank_subC + 1 % esegui il test of minimality
alpha=abs(Upos(row2, k)); % calcola il coefficiente alpha
beta=abs(Uneg(row1, k)); % calcola il coefficiente beta
new_row=alpha*Uneg(row1, :)+beta*Upos(row2, :); % calcola la nuova riga
16
% da aggiungere a Uk
cont_righe=cont_righe+1;
% calcola le righe generate fino ad ora
% calcola il MCD della nuova riga
supp_new_row=find(new_row);
MCD=new_row(supp_new_row(1));
for l = 2:length(supp_new_row)
MCD=gcd(MCD, new_row(supp_new_row(l)));
end
Uk=[Uk; new_row/MCD]; % aggiungi a Uk la nuova riga divisa per il MCD
end
row2=row2+1; % passa alla successiva riga di Upos
end
row1=row1+1; % passa alla successiva riga di Uneg
end
end
Uneg=sparse([]); % annulla la matrice Uneg
Upos=sparse([]); % annulla la matrice Upos
trovato=0; % % flag: indica che si è trovata la colonna da cui parte l'algoritmo principale
strart_col=0; % colonna di partenza ottenuta calcolando l'"expansion factor"
start_col2=0; % colonna di partenza che minimizza il prodotto Pk*Nk (definiti sotto)
i=0; % contatore per i prodotti parziali Pk*Nk
[numuk,num2uk]=size(Uk);
if numuk == 0
start_col=0;
else
% viene ora ricercata la colonna di partenza per la parte principale dell'algoritmo
for k = 1:numtrans %per ogni colonna di A°
pos=find(Uk(:,k)>0); % indici degli elementi positivi della k-esima colonna di C
Pk = length(pos); % numero degli elementi positivi della k-esima colonna di C
neg=find(Uk(:,k)<0); % indici degli elementi negativi della k-esima colonna di C
Nk = length(neg); % numero degli elementi negativi della k-esima colonna di C
if Pk + Nk ~= 0 & Pk*Nk-(Pk+Nk) < 0 & trovato == 0
% se la colonna è non nulla, l'"expansion factor" è negativo e non ho ancora trovato
% la colonna di partenza
trovato=1; % ho trovato la colonna di partenza
start_col=k;
end
if Pk + Nk ~= 0 & trovato == 0 % se la colonna è non nulla e
% non ha un "expansion factor" negativo
prod_Pk_Nk=Pk*Nk; % calcolo Pk*Nk
if i == 0 % se è la prima colonna per cui calcolo Pk*Nk
slack=prod_Pk_Nk; % setto una variabile di confronto a Pk*Nk
i=1; % aggiorno il contatore
start_col2=k; % setto la colonna di partenza secondo questa logica
end
if prod_Pk_Nk < slack % se trovo un prodotto Pk*Nk minore di quello
% calcolato precedentemente
slack=prod_Pk_Nk; % aggiorno la variabile di confronto
start_col2=k; % e la colonna di partenza
end
end
end
if trovato == 0 % se non ho trovato una colonna che soddisfa il criterio
% dell'"expansion factor" negativo
start_col=start_col2; % la colonna di partenza è quella che minimizza Pk*Nk
end
end
k=start_col % mostra la colonna di partenza dell'algortitmo principale
if k ~= 0 % se k è diverso da 0, poni la posizione della maschera corrispondente a k pari a 1
act_ann(k)=1;
end
Uk1=Uk; % prepara la matrice di partenza Uk1 per l'algoritmo principale
[numpostiUk1, numtransUk1]=size(Uk1); % serve solo "numpostiUk1" per l'algoritmo principale
numpostiUk1 % mostra a video il numero di righe di Uk1
Uk=sparse([]); % setta Uk come matrice nulla
end
17
% calcola la matrice dei P-I, P
for n=1:numpostiUk1
if Uk1(n,1:numtrans) == zeros(1,numtrans);
P=full([Uk1(n,numtrans+1:numposti+numtrans); P]);
end
end
cont_righe
% metti i P-I trovati in P
% mostra le righe generate dall'algoritmo
function P_s = pinvarianti_S_FToM(P, Cstar_aux)
%PINVARIANTI_S_FToM
Calcolo dei P-invarianti di una rete di Petri
%
ottimizzato per la rilevazione dei sifoni nella rete
%
PINVARIANTI_S_FToM(P, Cstar_aux) calcola i P-invarianti di una rete di Petri modificata
%
per il calcolo dei sifoni avente Cstar_aux come matrice di incidenza; tra i
%
P-invarianti di Cstar_aux vi sono anche i P-invarianti della rete originaria, contenuti
%
in P, essi vengono esclusi dal calcolo dei P-invarianti a partire da Cstar_aux e
%
vengono aggiunti al termine dell'algoritmo agli altri P-invarianti trovati.
%
Versione che utilizza il "Fast Test of Minimality".
%
Ritorna una matrice di dimensioni
%
<numero di P-invarianti> * <numero di posti della rete>
%
in cui ogni riga rappresenta un P-invariante.
%disp('Inizio Pinvarianti_S'),pause
cont_righe=0;
% conta le righe via via generate dall'algoritmo
trovato=0; % flag: indica che si è trovata la colonna da cui parte l'algoritmo principale
strart_col=0; % colonna di partenza ottenuta calcolando l'"expansion factor"
start_col2=0; % colonna di partenza che minimizza il prodotto Pk*Nk (definiti sotto)
i=0; % contatore per i prodotti parziali Pk*Nk
[numposti, numtrans] = size(Cstar_aux);
U° = sparse([Cstar_aux eye(numposti)]); % creo la matrice U°
P_s=sparse([]); % matrice che conterrà i p-invarianti
suppP=sparse([]); % matrice con i supporti dei P-invarianti di P
[xP, yP]=size(P);
for u = 1:xP
suppP=[suppP; spones(P(u,:))]; % riempio suppP con i supporti delle righe di P
end
suppParz=[];
% matrice usata per contenere i supporti dei P-I trovati con l'algoritmo
% principale ristretti alle dimensioni di P
ann=0; % contatore colonne annullate
col_ann=0; % indica quale colonna è stata annullata
c=0; % contatore delle colonne da annullare
% conto le colonne da annullare
for k = 1:numtrans %per ogni colonna di Cstar_aux
pos=find(Cstar_aux(:,k)>0); % indici degli elementi positivi della k-esima colonna di Cstar_aux
Pk = length(pos); % numero degli elementi positivi della k-esima colonna di Cstar_aux
neg=find(Cstar_aux(:,k)<0); % indici degli elementi negativi della k-esima colonna di Cstar_aux
Nk = length(neg); % numero degli elementi negativi della k-esima colonna di Cstar_aux
if Pk * Nk == 1 & abs(U°(pos,k)) == abs(U°(neg,k)) % se Pk=Nk=1 e l'elemento positivo
% e negativo sono uguali in modulo
c=c+1;
end
end
% prima ottimizzazione: viene annullata una colonna di U° che abbia un elemento
% positivo e un elemento negativo uguali in modulo, a meno che la colonna con queste
% caratteristiche non sia una sola
for k = 1:numtrans %per ogni colonna di A°
pos=find(U°(:,k)>0); % indici degli elementi positivi della k-esima colonna di A°
Pk = length(pos); % numero degli elementi positivi della k-esima colonna di A°
neg=find(U°(:,k)<0); % indici degli elementi negativi della k-esima colonna di A°
Nk = length(neg); % numero degli elementi negativi della k-esima colonna di A°
% se Pk=Nk=1 e non si è ancora annullata la colonna di Cstar_aux e l'elemento
% positivo e il negativo sono uguali in modulo e la colonna da annullare non è una sola
if Pk * Nk == 1 & abs(U°(pos,k)) == abs(U°(neg,k)) & ann < 1 & ann < 1 & c > 1
U°(pos,k) = 0; % annullo la
18
U°(neg,k) = 0; % k-esima colonna
Pk=0; % ora Pk è nullo
Nk=0; % e anche Nk
ann=ann+1; % è stata annullata una colonna
col_ann=k; % indica quale colonna è stata annullata
end
end
% viene ora ricercata la colonna di partenza per la parte principale dell'algoritmo
for k = 1:numtrans %per ogni colonna di A°
pos=find(Cstar_aux(:,k)>0); % indici degli elementi positivi della k-esima colonna di Cstar_aux
Pk = length(pos); % numero degli elementi positivi della k-esima colonna di Cstar_aux
neg=find(Cstar_aux(:,k)<0); % indici degli elementi negativi della k-esima colonna di Cstar_aux
Nk = length(neg); % numero degli elementi negativi della k-esima colonna di Cstar_aux
if Pk + Nk ~= 0 & Pk*Nk-(Pk+Nk) < 0 & trovato == 0
% se la colonna è non nulla, l'"expansion factor" è negativo e non ho ancora trovato
% la colonna di partenza
trovato=1; % ho trovato la colonna di partenza
start_col=k;
end
if Pk + Nk ~= 0 & trovato == 0 % se la colonna è non nulla e
% non ha un "expansion factor" negativo
prod_Pk_Nk=Pk*Nk; % calcolo Pk*Nk
if i == 0 % se è la prima colonna per cui calcolo Pk*Nk
slack=prod_Pk_Nk; % setto una variabile di confronto a Pk*Nk
i=1; % aggiorno il contatore
start_col2=k; % setto la colonna di partenza secondo questa logica
end
if prod_Pk_Nk < slack % se trovo un prodotto Pk*Nk minore di quello
% calcolato precedentemente
slack=prod_Pk_Nk; % aggiorno la variabile di confronto
start_col2=k; % e la colonna di partenza
end
end
end
if trovato == 0 % se non ho trovato una colonna che soddisfa il criterio
% dell'"expansion factor" negativo
start_col=start_col2; % la colonna di partenza è quella che minimizza Pk*Nk
end
Uk1=U°;
% poni la matrice Uk1 = U°
act_ann=zeros(1,numtrans);
% maschera della colonne attivamente annullate
[numpostiUk1, numcolUk1]=size(Uk1)
k=start_col
% serve solo "numpostiUk1" per l'algoritmo principale;
% mostra a video le due dimensioni
% mostra la colonna di partenza dell'algoritmo principale
act_ann(k)=1;
% metti a 1 il valore della maschera corrispondente alla colonna k
Uk=sparse([]); % inizializza la matrice Uk
Uneg=sparse([]); % inizializza la matrice Uneg
Upos=sparse([]); % inizializza la matrice Upos
while k ~= 0 % inizio dell'algoritmo principale
for j = 1:numpostiUk1 % per ogni riga di Uk1
if Uk1(j, k) == 0 % se l'elemento all'incrocio fra riga j e colonna k è pari a 0
Uk=[Uk; Uk1(j, :)]; % aggiungi la riga con esso ad Uk
elseif Uk1(j, k) < 0 % se l'elemento all'incrocio fra riga j e colonna k è < 0
Uneg=[Uneg; Uk1(j, :)]; % aggiungi la riga con esso ad Uneg
else % se l'elemento all'incrocio fra riga j e colonna k è > 0
Upos=[Upos; Uk1(j, :)]; % aggiungi la riga con esso ad Upos
end
end
% se Uneg e/o Upos sono vuote, metti a 0 il valore della maschera corrispondente
% alla colonna k
if isequal(Uneg,[])
act_ann(k)=0;
end
if isequal(Upos,[])
act_ann(k)=0;
end
[x1, y1]=size(Uneg);
% serve solo x1: numero delle righe di Uneg
19
[x2, y2]=size(Upos); % serve solo x2: numero delle righe di Upos
[xk, yk]=size(Uk); % serve solo xk: numero delle righe di Uk
if x1 ~= 0 & x2 ~= 0 % se le matrici non hanno dimensioni nulle
row1=1; % indice prima riga di Uneg
while row1 <= x1
row2=1; % indice prima riga di Upos
while row2 <= x2
% calcola il supporto del nuovo P-i Y come unione dei supporti dei P-I
% corrispondenti alle righe row1 e row2 rispettivamente di Uneg e di Upos
suppY=spones(Uneg(row1, numtrans+1:numposti+numtrans))|spones(Upos(row2,
numtrans+1:numposti+numtrans));
% confronto il supporto del nuovoP-i con i supporti dei P-i in suppP:
% se il supporto del nuovo P-i è uguale o include uno in suppP, non continuo
w=1; % contatore
doppio=0; % flag di supporto uguale
while w <= xP
suppUnion=suppY(:, 1:yP)|suppP(w,:); % calcolo l'unione fra il supporto del
% nuovo P-I e quello di suppP corrispondente all riga w
if isequal(suppY(:, 1:yP), suppP(w,:)) % se i supporti sono uguali
doppio=1; % ho trovato un doppione
w=xP+1; % esco dal while
elseif suppY(:, 1:yP) == suppUnion % se il supporto del nuovo P-I include quello di
suppP
doppio=1; % ho trovato un P-I inutile
w=xP+1; % esco dal while
else
w=w+1;
end
end
% confronto fra il supporto del P-I nuovo (ristretto alle dimensioni di suppParz)
% e i supporti contenuti in suppParz: se il nuovo P-I contiene uno di questi, esso è un
doppione
if ~isequal(suppParz,[]) & doppio == 0 % se suppParz non è vuota
w=1;
[xSPZ, ySPZ]=size(suppParz);
while w <= xSPZ % per ogni riga di supppParz
suppUnion2=suppY(:, 1:ySPZ)|suppParz(w, :); % calcola l'unione del supporto
% del nuovo P-I trovato con quello della w-esima riga di suppParz
if suppY(:, 1:ySPZ) == suppUnion2 % se il nuovo P-I contiene un P-I di suppParz
doppio=1; % ho trovato un P-I inutile
w=xSPZ+1; % esco dal while
else
w=w+1;
end
end
end
if doppio ~= 1
% se non si tratta di un P-I doppio
IsuppY=find(suppY>0); % indici elementi diversi da zero del supporto di Y
card_suppY=length(find(IsuppY>0)); % calcola la cardinalità del supporto di Y
supp_rowC=zeros(1, numtrans); % vettore che conterrà l'unione dei supporti delle
% righe di Cstar_aux indicizzate dal supporto di Y
% calcola l'unione dei supporti delle righe di Cstar_aux indicizzate dal supporto di Y
for f = IsuppY % per ogni valore del supporto di Y
supp_rowC=spones(Cstar_aux(f, :))|supp_rowC; % calcola l'unione dei corrispondenti
% supporti delle righe di Cstar_aux
end
% calcola il rank_upperbound
rank_upperbound=length(find(act_ann.*supp_rowC>0));
% ottimizzazione: esegue il "fast test of minimality"
if card_suppY <= rank_upperbound + 1
v=1; % contatore
includes=0; % flag usato nel "support comparison"
% esecuzione del "support comparison": confronto il supporto del P-I trovato
% con il supporto dei P-I presenti in Uk, Uneg o Upos
% confronto con i P-I di Uneg:
while v <= x1 & includes == 0
if v ~= row1
% esegui il "support comparison" fra
20
% il nuovo P-I e quelli trovati in precedenza
supp_comp=suppY|Uneg(v,numtrans+1:numposti+numtrans);
if supp_comp == suppY % se il nuovo P-I contiene il supporto di altri
% P-I trovati prima
v=x1+1; % termina il "support comparison"
includes=1; % il nuovo P-I ne contiene un altro
else
v=v+1; % altrimenti continua
end
else
v=v+1;
end
end
% confronto con i P-i di Upos:
v=1;
while v <= x2 & includes == 0
if v ~= row2
% esegui il "support comparison" fra
% il nuovo P-I e quelli trovati in precedenza
supp_comp=suppY|Upos(v,numtrans+1:numposti+numtrans);
if supp_comp == suppY % se il nuovo P-I contiene il supporto di altri
% P-I trovati prima
v=x2+1; % termina il "support comparison"
includes=1; % il nuovo P-I ne contiene un altro
else
v=v+1; % altrimenti continua
end
else
v=v+1;
end
end
% confronto con i P-i di Uk:
v=1;
while v <= xk & includes == 0
% esegui il "support comparison" fra
% il nuovo P-I e quelli trovati in precedenza
supp_comp=suppY|Uk(v,numtrans+1:numposti+numtrans);
if supp_comp == suppY % se il nuovo P-I contiene il supporto di altri
% P-I trovati prima
v=xk+1; % termina il "support comparison"
includes=1; % il nuovo P-I ne contiene un altro
else
v=v+1; % altrimenti continua
end
end
if includes ~= 1 % se il P-I non contiene il supporto di altri P-I
alpha=abs(Upos(row2, k)); % calcola il coefficiente alpha
beta=abs(Uneg(row1, k)); % calcola il coefficiente beta
new_row=alpha*Uneg(row1, :)+beta*Upos(row2, :); % calcola la nuova riga
% da aggiungere a Uk
cont_righe=cont_righe+1;
% calcola le righe generate fino ad ora
if new_row(:,1:numtrans) == zeros(1,numtrans) % se la nuova riga trovata
rappresenta un P-I
% metti il suo supporto ristretto alle dimensioni di suppParz in suppParz
suppParz=[spones(new_row(:,numtrans+1:numposti)); suppParz];
end
% calcola il MCD della nuova riga
supp_new_row=find(new_row);
MCD=new_row(supp_new_row(1));
for l = 2:length(supp_new_row)
MCD=gcd(MCD, new_row(supp_new_row(l)));
end
Uk=[Uk; new_row/MCD]; % aggiungi a Uk la nuova riga divisa per il MCD
end
end
end
row2=row2+1; % passa alla successiva riga di Upos
end
row1=row1+1; % passa alla successiva riga di Uneg
21
end
end
Uneg=sparse([]);
Upos=sparse([]);
% annulla la matrice Uneg
% annulla la matrice Upos
trovato=0; % % flag: indica che si è trovata la colonna da cui parte l'algoritmo principale
strart_col=0; % colonna di partenza ottenuta calcolando l'"expansion factor"
start_col2=0; % colonna di partenza che minimizza il prodotto Pk*Nk (definiti sotto)
i=0; % contatore per i prodotti parziali Pk*Nk
[numuk,num2uk]=size(Uk);
if numuk == 0
start_col=0;
else
% viene ora ricercata la colonna di partenza per la parte principale dell'algoritmo
for k = 1:numtrans %per ogni colonna di A°
pos=find(Uk(:,k)>0); % indici degli elementi positivi della k-esima colonna di Uk
Pk = length(pos); % numero degli elementi positivi della k-esima colonna di Uk
neg=find(Uk(:,k)<0); % indici degli elementi negativi della k-esima colonna di Uk
Nk = length(neg); % numero degli elementi negativi della k-esima colonna di Uk
if Pk + Nk ~= 0 & Pk*Nk-(Pk+Nk) < 0 & trovato == 0
% se la colonna è non nulla, l'"expansion factor" è negativo e non ho ancora trovato
% la colonna di partenza
trovato=1; % ho trovato la colonna di partenza
start_col=k;
end
if Pk + Nk ~= 0 & trovato == 0 % se la colonna è non nulla e
% non ha un "expansion factor" negativo
prod_Pk_Nk=Pk*Nk; % calcolo Pk*Nk
if i == 0 % se è la prima colonna per cui calcolo Pk*Nk
slack=prod_Pk_Nk; % setto una variabile di confronto a Pk*Nk
i=1; % aggiorno il contatore
start_col2=k; % setto la colonna di partenza secondo questa logica
end
if prod_Pk_Nk < slack % se trovo un prodotto Pk*Nk minore di quello
% calcolato precedentemente
slack=prod_Pk_Nk; % aggiorno la variabile di confronto
start_col2=k; % e la colonna di partenza
end
end
end
if trovato == 0 % se non ho trovato una colonna che soddisfa il criterio
% dell'"expansion factor" negativo
start_col=start_col2; % la colonna di partenza è quella che minimizza Pk*Nk
end
end
k=start_col % mostra la colonna di partenza dell'algortitmo principale
if k ~= 0 % se k è diverso da 0, poni la posizione della maschera corrispondente a k pari a 1
act_ann(k)=1;
end
Uk1=Uk; % prepara la matrice di partenza Uk1 per l'algoritmo principale
[numpostiUk1, numtransUk1]=size(Uk1); % serve solo "numpostiUk1" per l'algoritmo principale
numpostiUk1 % mostra a video il numero di righe di Uk1
Uk=sparse([]); % setta Uk come matrice nulla
end
% calcola la matrice dei P-I, P_s
for n=1:numpostiUk1
if Uk1(n,1:numtrans) == zeros(1,numtrans);
P_s=full([Uk1(n,numtrans+1:numposti+numtrans); P_s]);
end
end
cont_righe
% metti i P-I trovati in P_s
% mostra le righe generate dall'algoritmo
function P_s = pinvarianti_S_ToM(P, Cstar_aux)
%PINVARIANTI_S_ToM
Calcolo dei P-invarianti di una rete di Petri
%
ottimizzato per la rilevazione dei sifoni nella rete
%
PINVARIANTI_S_ToM(P, Cstar_aux) calcola i P-invarianti di una rete di Petri modificata
22
%
%
%
%
%
%
%
%
per il calcolo dei sifoni avente Cstar_aux come matrice di incidenza; tra i
P-invarianti di Cstar_aux vi sono anche i P-invarianti della rete originaria, contenuti
in P, essi vengono esclusi dal calcolo dei P-invarianti a partire da Cstar_aux e
vengono aggiunti al termine dell'algoritmo agli altri P-invarianti trovati
Versione che utilizza il "Test of Minimality".
Ritorna una matrice di dimensioni
<numero di P-invarianti> * <numero di posti della rete>
in cui ogni riga rappresenta un P-invariante.
%disp('Inizio Pinvarianti_S'),pause
cont_righe=0;
% conta le righe via via generate dall'algoritmo
trovato=0; % flag: indica che si è trovata la colonna da cui parte l'algoritmo principale
strart_col=0; % colonna di partenza ottenuta calcolando l'"expansion factor"
start_col2=0; % colonna di partenza che minimizza il prodotto Pk*Nk (definiti sotto)
i=0; % contatore per i prodotti parziali Pk*Nk
[numposti, numtrans] = size(Cstar_aux);
U° = sparse([Cstar_aux eye(numposti)]); % creo la matrice U°
P_s=sparse([]); % matrice che conterrà i p-invarianti
suppP=sparse([]); % matrice con i supporti dei P-invarianti di P
[xP, yP]=size(P); % serve solo xP
for u = 1:xP
suppP=[suppP; spones(P(u,:))]; % riempio suppP con i supporti delle righe di P
end
suppParz=[];
% matrice usata per contenere i supporti dei P-I trovati con l'algoritmo
% principale ristretti alle dimensioni di P
ann=0; % contatore colonne annullate
col_ann=0; % indica quale colonna è stata annullata
c=0; % contatore delle colonne da annullare
% conto le colonne da annullare
for k = 1:numtrans %per ogni colonna di Cstar_aux
pos=find(Cstar_aux(:,k)>0); % indici degli elementi positivi della k-esima colonna di Cstar_aux
Pk = length(pos); % numero degli elementi positivi della k-esima colonna di Cstar_aux
neg=find(Cstar_aux(:,k)<0); % indici degli elementi negativi della k-esima colonna di Cstar_aux
Nk = length(neg); % numero degli elementi negativi della k-esima colonna di Cstar_aux
if Pk * Nk == 1 & abs(U°(pos,k)) == abs(U°(neg,k)) % se Pk=Nk=1 e l'elemento positivo
% e negativo sono uguali in modulo
c=c+1;
end
end
% prima ottimizzazione: viene annullata una colonna di U° che abbia un elemento
% positivo e un elemento negativo uguali in modulo, a meno che la colonna con queste
% caratteristiche non sia una sola
for k = 1:numtrans %per ogni colonna di A°
pos=find(U°(:,k)>0); % indici degli elementi positivi della k-esima colonna di A°
Pk = length(pos); % numero degli elementi positivi della k-esima colonna di A°
neg=find(U°(:,k)<0); % indici degli elementi negativi della k-esima colonna di A°
Nk = length(neg); % numero degli elementi negativi della k-esima colonna di A°
% se Pk=Nk=1 e non si è ancora annullata la colonna di Cstar_aux e l'elemento
% positivo e il negativo sono uguali in modulo e la colonna da annullare non è una sola
if Pk * Nk == 1 & abs(U°(pos,k)) == abs(U°(neg,k)) & ann < 1 & ann < 1 & c > 1
U°(pos,k) = 0; % annullo la
U°(neg,k) = 0; % k-esima colonna
Pk=0; % ora Pk è nullo
Nk=0; % e anche Nk
ann=ann+1; % è stata annullata una colonna
col_ann=k; % indica quale colonna è stata annullata
end
end
% viene ora ricercata la colonna di partenza per la parte principale dell'algoritmo
for k = 1:numtrans %per ogni colonna di A°
pos=find(Cstar_aux(:,k)>0); % indici degli elementi positivi della k-esima colonna di Cstar_aux
Pk = length(pos); % numero degli elementi positivi della k-esima colonna di Cstar_aux
neg=find(Cstar_aux(:,k)<0); % indici degli elementi negativi della k-esima colonna di Cstar_aux
Nk = length(neg); % numero degli elementi negativi della k-esima colonna di Cstar_aux
if Pk + Nk ~= 0 & Pk*Nk-(Pk+Nk) < 0 & trovato == 0
23
% se la colonna è non nulla, l'"expansion factor" è negativo e non ho ancora trovato
% la colonna di partenza
trovato=1; % ho trovato la colonna di partenza
start_col=k;
end
if Pk + Nk ~= 0 & trovato == 0 % se la colonna è non nulla e
% non ha un "expansion factor" negativo
prod_Pk_Nk=Pk*Nk; % calcolo Pk*Nk
if i == 0 % se è la prima colonna per cui calcolo Pk*Nk
slack=prod_Pk_Nk; % setto una variabile di confronto a Pk*Nk
i=1; % aggiorno il contatore
start_col2=k; % setto la colonna di partenza secondo questa logica
end
if prod_Pk_Nk < slack % se trovo un prodotto Pk*Nk minore di quello
% calcolato precedentemente
slack=prod_Pk_Nk; % aggiorno la variabile di confronto
start_col2=k; % e la colonna di partenza
end
end
end
if trovato == 0
% se non ho trovato una colonna che soddisfa il criterio
% dell'"expansion factor" negativo
start_col=start_col2; % la colonna di partenza è quella che minimizza Pk*Nk
end
Uk1=U°;
% poni la matrice Uk1 = U°
act_ann=zeros(1,numtrans);
% maschera della colonne attivamente annullate
[numpostiUk1, numcolUk1]=size(Uk1)
k=start_col
% serve solo "numpostiUk1" per l'algoritmo principale;
% mostra a video le due dimensioni
% mostra la colonna di partenza dell'algoritmo principale
act_ann(k)=1;
% metti a 1 il valore della maschera corrispondente alla colonna k
Uk=sparse([]); % inizializza la matrice Uk
Uneg=sparse([]); % inizializza la matrice Uneg
Upos=sparse([]); % inizializza la matrice Upos
while k ~= 0 % inizio dell'algoritmo principale
for j = 1:numpostiUk1 % per ogni riga di Uk1
if Uk1(j, k) == 0 % se l'elemento all'incrocio fra riga j e colonna k è pari a 0
Uk=[Uk; Uk1(j, :)]; % aggiungi la riga con esso ad Uk
elseif Uk1(j, k) < 0 % se l'elemento all'incrocio fra riga j e colonna k è < 0
Uneg=[Uneg; Uk1(j, :)]; % aggiungi la riga con esso ad Uneg
else % se l'elemento all'incrocio fra riga j e colonna k è > 0
Upos=[Upos; Uk1(j, :)]; % aggiungi la riga con esso ad Upos
end
end
% se Uneg e/o Upos sono vuote, metti a 0 il valore della maschera corrispondente
% alla colonna k
if isequal(Uneg,[])
act_ann(k)=0;
end
if isequal(Upos,[])
act_ann(k)=0;
end
[x1, y1]=size(Uneg); % serve solo x1: numero delle righe di Uneg
[x2, y2]=size(Upos); % serve solo x2: numero delle righe di Upos
[xk, yk]=size(Uk); % serve solo xk: numero delle righe di Uk
if x1 ~= 0 & x2 ~= 0 % se le matrici non hanno dimensioni nulle
row1=1; % indice prima riga di Uneg
while row1 <= x1
row2=1; % indice prima riga di Upos
while row2 <= x2
% calcola il supporto del nuovo P-i Y come unione dei supporti dei P-I
% corrispondenti alle righe row1 e row2 rispettivamente di Uneg e di Upos
suppY=spones(Uneg(row1, numtrans+1:numposti+numtrans))|spones(Upos(row2,
numtrans+1:numposti+numtrans));
% confronto il supporto del nuovoP-i con i supporti dei P-i in suppP:
% se il supporto del nuovo P-i è uguale a uno in suppP, non continuo
w=1; % contatore
24
doppio=0; % flag di supporto uguale
while w <= xP
suppUnion=suppY(:, 1:yP)|suppP(w,:); % calcolo l'unione fra il supporto del
% nuovo P-I e quello di suppP corrispondente all riga w
if isequal(suppY(:, 1:yP), suppP(w,:)) % se i supporti sono uguali
doppio=1; % ho trovato un doppione
w=xP+1; % esco dal while
elseif suppY(:, 1:yP) == suppUnion % se il supporto del nuovo P-I include quello di
suppP
doppio=1; % ho trovato un P-I inutile
w=xP+1; % esco dal while
else
w=w+1;
end
end
% confronto fra il supporto del P-I nuovo (ristretto alle dimensioni di suppParz)
% e i supporti contenuti in suppParz: se il nuovo P-I contiene uno di questi, esso è un
doppione
if ~isequal(suppParz,[]) & doppio == 0 % se suppParz non è vuota
w=1;
[xSPZ, ySPZ]=size(suppParz);
while w <= xSPZ % per ogni riga di supppParz
suppUnion2=suppY(:, 1:ySPZ)|suppParz(w, :); % calcola l'unione del supporto
% del nuovo P-I trovato con quello della w-esima riga di suppParz
if suppY(:, 1:ySPZ) == suppUnion2 % se il nuovo P-I contiene un P-I di suppParz
doppio=1; % ho trovato un P-I inutile
w=xSPZ+1; % esco dal while
else
w=w+1;
end
end
end
if doppio ~= 1
% se non si tratta di un P-I doppio
IsuppY=find(suppY>0); % indici elementi diversi da zero del supporto di Y
card_suppY=length(find(IsuppY>0)); % calcola la cardinalità del supporto di Y
subC=sparse([]); % prepara la sottomatrice di C di cui si calcolerà il rango
for f = IsuppY % per ogni valore del supporto di Y
subC=[subC; Cstar_aux(f, :).*act_ann]; % aggiungi a subC le corrispondenti
% righe di C considerando solo le colonne indicate dalla maschera
end
rank_subC=rank(subC); % calcola il rango di subC
if card_suppY == rank_subC + 1 % esegui il test of minimality
alpha=abs(Upos(row2, k)); % calcola il coefficiente alpha
beta=abs(Uneg(row1, k)); % calcola il coefficiente beta
new_row=alpha*Uneg(row1, :)+beta*Upos(row2, :); % calcola la nuova riga
% da aggiungere a Uk
cont_righe=cont_righe+1;
% calcola le righe generate fino ad ora
if new_row(:,1:numtrans) == zeros(1,numtrans)
% se la nuova riga trovata rappresenta
un P-I
% metti il suo supporto ristretto alle dimensioni di suppParz in suppParz
suppParz=[spones(new_row(:,numtrans+1:numposti)); suppParz];
end
% calcola il MCD della nuova riga
supp_new_row=find(new_row);
MCD=new_row(supp_new_row(1));
for l = 2:length(supp_new_row)
MCD=gcd(MCD, new_row(supp_new_row(l)));
end
Uk=[Uk; new_row/MCD]; % aggiungi a Uk la nuova riga divisa per il MCD
end
end
row2=row2+1; % passa alla successiva riga di Upos
end
row1=row1+1; % passa alla successiva riga di Uneg
end
end
Uneg=sparse([]); % annulla la matrice Uneg
25
Upos=sparse([]);
% annulla la matrice Upos
trovato=0; % % flag: indica che si è trovata la colonna da cui parte l'algoritmo principale
strart_col=0; % colonna di partenza ottenuta calcolando l'"expansion factor"
start_col2=0; % colonna di partenza che minimizza il prodotto Pk*Nk (definiti sotto)
i=0; % contatore per i prodotti parziali Pk*Nk
[numuk,num2uk]=size(Uk);
if numuk == 0
start_col=0;
else
% viene ora ricercata la colonna di partenza per la parte principale dell'algoritmo
for k = 1:numtrans %per ogni colonna di A°
pos=find(Uk(:,k)>0); % indici degli elementi positivi della k-esima colonna di Uk
Pk = length(pos); % numero degli elementi positivi della k-esima colonna di Uk
neg=find(Uk(:,k)<0); % indici degli elementi negativi della k-esima colonna di Uk
Nk = length(neg); % numero degli elementi negativi della k-esima colonna di Uk
if Pk + Nk ~= 0 & Pk*Nk-(Pk+Nk) < 0 & trovato == 0
% se la colonna è non nulla, l'"expansion factor" è negativo e non ho ancora trovato
% la colonna di partenza
trovato=1; % ho trovato la colonna di partenza
start_col=k;
end
if Pk + Nk ~= 0 & trovato == 0 % se la colonna è non nulla e
% non ha un "expansion factor" negativo
prod_Pk_Nk=Pk*Nk; % calcolo Pk*Nk
if i == 0 % se è la prima colonna per cui calcolo Pk*Nk
slack=prod_Pk_Nk; % setto una variabile di confronto a Pk*Nk
i=1; % aggiorno il contatore
start_col2=k; % setto la colonna di partenza secondo questa logica
end
if prod_Pk_Nk < slack % se trovo un prodotto Pk*Nk minore di quello
% calcolato precedentemente
slack=prod_Pk_Nk; % aggiorno la variabile di confronto
start_col2=k; % e la colonna di partenza
end
end
end
if trovato == 0 % se non ho trovato una colonna che soddisfa il criterio
% dell'"expansion factor" negativo
start_col=start_col2; % la colonna di partenza è quella che minimizza Pk*Nk
end
end
k=start_col % mostra la colonna di partenza dell'algortitmo principale
if k ~= 0 % se k è diverso da 0, poni la posizione della maschera corrispondente a k pari a 1
act_ann(k)=1;
end
Uk1=Uk; % prepara la matrice di partenza Uk1 per l'algoritmo principale
[numpostiUk1, numtransUk1]=size(Uk1); % serve solo "numpostiUk1" per l'algoritmo principale
numpostiUk1 % mostra a video il numero di righe di Uk1
Uk=sparse([]); % setta Uk come matrice nulla
end
% calcola la matrice dei P-I, P_s
for n=1:numpostiUk1
if Uk1(n,1:numtrans) == zeros(1,numtrans);
P_s=full([Uk1(n,numtrans+1:numposti+numtrans); P_s]);
end
end
cont_righe
% metti i P-I trovati in P_s
% mostra le righe generate dall'algoritmo
function S = sifoni_FToM(I,O)
%SIFONI_FToM
Calcolo dei sifoni di una rete di Petri
%
SIFONI_FToM(I,O) ritorna una matrice in cui ogni riga rappresenta un sifone
%
della rete di Petri avente I come matrice di ingresso e O come matrice di uscita.
%
Usa la versione di Pinvarianti_S con il "Fast Test of Minimality".
%
Ogni riga contiene gli indici (riferiti alla matrice di incidenza) dei posti che
%
fanno parte del sifone.
26
%Costruzione della rete di Petri ausiliaria
%La rete ausiliaria ha gli stessi posti, transizioni e archi della rete di partenza,
%ma il peso di ogni arco entrante in una transizione viene moltiplicato per un coefficiante
%pari alla somma dei pesi degli archi uscenti dalla medesima transizione.
aux = repmat(sum(O,1),size(O,1),1); %matrice ausiliaria di righe tutte uguali contenenti la somma
dei pesi degli archi uscenti da ogni transizione
Istar = I .* aux; %.* è il prodotto elemento per elemento
C=O-I; % matrice di incidenza della rete di Petri originaria
P=full(spones(pinvarianti(C))); %calcola i P-invarianti della rete originaria
Cstar = O - Istar; %matrice di incidenza della nuova rete di Petri
%Soluzione del sistema x'Cstar <= 0
%La soluzione di questo problema è equivalente al calcolo dei P_invarianti della rete trasformata
%a cui si aggiungano per ogni transizione un posto e un arco diretto dalla transizione al posto.
Cstar_aux = [Cstar; eye(size(O,2))];
soluzione = pinvarianti_S_FToM(P, Cstar_aux);
if ~isequal(soluzione,[])
% se soluzione non è una matrice vuota (cioè se gli unici sifoni
% della rete sono i P-I di C)
soluzione = sign(soluzione(:,1:size(I,1))); %AL POSTO DI I C'ERA CSTAR% vanno prese solo le
colonne che si riferiscono ai posti della rete; le ultime colonne invece si riferiscono a posti
fittizi
end
soluzione=[soluzione; P];
% aggiungi i supporti dei P-I di C a quelli trovati in più per Cstar_aux
%disp('Inizio suppmin sifoni'),pause
S = suppmin(soluzione);
%disp('Fine suppmin sifoni'),pause
%riscrittura dei sifoni nella forma: 1 = posto appartiene al sifone, 0 altrimenti
function S = sifoni_ToM(I,O)
%SIFONI_ToM
Calcolo dei sifoni di una rete di Petri
%
SIFONI_ToM(I,O) ritorna una matrice in cui ogni riga rappresenta un sifone
%
della rete di Petri avente I come matrice di ingresso e O come matrice di uscita.
%
Usa la versione di Pinvarianti_S con il "Test of Minimality".
%
Ogni riga contiene gli indici (riferiti alla matrice di incidenza) dei posti che
%
fanno parte del sifone.
%Costruzione della rete di Petri ausiliaria
%La rete ausiliaria ha gli stessi posti, transizioni e archi della rete di partenza,
%ma il peso di ogni arco entrante in una transizione viene moltiplicato per un coefficiante
%pari alla somma dei pesi degli archi uscenti dalla medesima transizione.
aux = repmat(sum(O,1),size(O,1),1); %matrice ausiliaria di righe tutte uguali contenenti la somma
dei pesi degli archi uscenti da ogni transizione
Istar = I .* aux; %.* è il prodotto elemento per elemento
C=O-I; % matrice di incidenza della rete di Petri originaria
P=full(spones(pinvarianti(C))); %calcola i P-invarianti della rete originaria
Cstar = O - Istar; %matrice di incidenza della nuova rete di Petri
%Soluzione del sistema x'Cstar <= 0
%La soluzione di questo problema è equivalente al calcolo dei P_invarianti della rete trasformata
%a cui si aggiungano per ogni transizione un posto e un arco diretto dalla transizione al posto.
Cstar_aux = [Cstar; eye(size(O,2))];
soluzione = pinvarianti_S_ToM(P, Cstar_aux);
if ~isequal(soluzione,[])
% se soluzione non è una matrice vuota (cioè se gli unici sifoni
% della rete sono i P-I di C)
soluzione = sign(soluzione(:,1:size(I,1))); %AL POSTO DI I C'ERA CSTAR% vanno prese solo le
colonne che si riferiscono ai posti della rete; le ultime colonne invece si riferiscono a posti
fittizi
end
soluzione=[soluzione; P]; % aggiungi i supporti dei P-I di C a quelli trovati in più per Cstar_aux
%disp('Inizio suppmin sifoni'),pause
S = suppmin(soluzione);
27
%disp('Fine suppmin sifoni'),pause
%riscrittura dei sifoni nella forma: 1 = posto appartiene al sifone, 0 altrimenti
function o = OfromC(C)
%OfromC
Calcolo della matrice delle uscite O di una rete di Petri
%
OfromC(C) calcola la matrice delle uscite O di una rete di Petri
%
avente C come matrice di incidenza.
[x, y]=size(C);
o=C;
for k = 1:x
for j = 1:y
if o(k,j) < 0
o(k,j)=0;
end
end
end
function i = IfromC(C)
%IfromC
Calcolo della matrice degli ingressi I di una rete di Petri
%
IfromC(C) calcola la matrice degli ingressi I di una rete di Petri
%
avente C come matrice di incidenza.
[x, y]=size(C);
i=C;
for k = 1:x
for j = 1:y
if i(k,j) > 0
i(k,j)=0;
end
if i(k,j) < 0
i(k,j)=i(k,j)*(-1);
end
end
end
28
Appendice B: grafici di Pesim di alcune reti utilizzate per il testing del
programma
(per ogni grafico è indicato il nome del file .txt contenente la matrice di incidenza della rete)
P2
P1
T1
2
2
T4
T3
P3
T2
P4
P5
provadav2.txt
T5
P1
P7
P4
P8
T1
T2
T6
T7
P2
5
P5
P9
T3
P3
P13
T4
5
P6
T8
P11
P10
P12
T9
prova.txt
29
P1
T1
P13
T11
T2
P2
T12
T3
P14
P3
T13
T4
P15
P4
T5
T14
P10
P5
P11
P12
P16
T6
T15
P6
T7
P17
P7
T16
T8
P18
P8
T17
T9
P19
P9
T20
T18
T10
P20
RETE.txt
P21
T19
30