825 lines
23 KiB
C
825 lines
23 KiB
C
/** anpsmod.c **/
|
|
|
|
/*
|
|
* Tutaj jest splitting. Zaczyna sie od psmodel_builder.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <assert.h>
|
|
#include "anpsmod.h"
|
|
#include "antclass.h"
|
|
#include "anproc.h"
|
|
#include "antypes.h"
|
|
#include "anmacro.h"
|
|
#include "macro.h"
|
|
#include "dbm.h"
|
|
|
|
#ifdef PSM_VERBOSE
|
|
static unsigned int stTests;
|
|
static unsigned int skip_stTests;
|
|
#endif
|
|
|
|
/*
|
|
* Obliczanie pre_e.
|
|
*
|
|
* (nie ma sprawdzania zgodnosci przejscia miedzy lokacjami, bo to powinno byc wiadomo
|
|
* zanim zostanie wywolana funkcja)
|
|
*
|
|
* Z n time_pre( [Y:=0]( time_pre(Z') n I(s') ) n guard(e) n I(s) )
|
|
*/
|
|
DBM_elem *
|
|
psmodel_pre(ProdTrans_set *trans, ProdLoc_set *loc_src, ProdLoc_set *loc_dst, DBM_elem *z_src, DBM_elem *z_dst)
|
|
{
|
|
DBM_elem *guard_inv, *tmp_dbm;
|
|
|
|
guard_inv = dbm_intersection_cf(trans->guard, loc_src->inv, dbm_size);
|
|
if (dbm_empty(guard_inv, dbm_size))
|
|
{
|
|
tmp_dbm = guard_inv;
|
|
}
|
|
else
|
|
{
|
|
tmp_dbm = dbm_copy(z_dst, dbm_size);
|
|
dbm_time_predecessor(tmp_dbm, dbm_size);
|
|
dbm_intersection_cf_ip(tmp_dbm, loc_dst->inv, dbm_size); /* modyfikacja w miejscu tmp_dbm */
|
|
if (!dbm_empty(tmp_dbm, dbm_size))
|
|
{
|
|
/* tmp_dbm := [reset(trans) := 0]tmp_dbm */
|
|
ClockIdx_set *cur_clock;
|
|
|
|
for (cur_clock = trans->clocks; cur_clock; cur_clock = cur_clock->next)
|
|
dbm_invreset(tmp_dbm, dbm_size, cur_clock->idx);
|
|
|
|
dbm_intersection_cf_ip(tmp_dbm, guard_inv, dbm_size);
|
|
if (!dbm_empty(tmp_dbm, dbm_size))
|
|
{
|
|
dbm_time_predecessor(tmp_dbm, dbm_size);
|
|
dbm_intersection_cf_ip(tmp_dbm, z_src, dbm_size);
|
|
}
|
|
}
|
|
dbm_destroy(guard_inv);
|
|
}
|
|
|
|
return tmp_dbm;
|
|
}
|
|
|
|
/*
|
|
* Porownywanie wyniku pre_e z konkretna strefa
|
|
*/
|
|
bool
|
|
psmodel_pre_eq(DBM_elem *z_cmp, ProdTrans_set *trans, ProdLoc_set *loc_src, ProdLoc_set *loc_dst,
|
|
DBM_elem *z_src, DBM_elem *z_dst)
|
|
{
|
|
bool are_equal;
|
|
DBM_elem *rlt;
|
|
|
|
rlt = psmodel_pre(trans, loc_src, loc_dst, z_src, z_dst);
|
|
|
|
are_equal = dbm_equal(rlt, z_cmp, dbm_size);
|
|
dbm_destroy(rlt);
|
|
|
|
return are_equal;
|
|
}
|
|
|
|
/*
|
|
* Sprawdzanie pustosci wyniku operacji pre_e
|
|
*/
|
|
bool
|
|
psmodel_pre_empty(ProdTrans_set *trans, ProdLoc_set *loc_src, ProdLoc_set *loc_dst,
|
|
DBM_elem *z_src, DBM_elem *z_dst)
|
|
{
|
|
bool is_empty;
|
|
DBM_elem *rlt;
|
|
|
|
rlt = psmodel_pre(trans, loc_src, loc_dst, z_src, z_dst);
|
|
|
|
is_empty = dbm_empty(rlt, dbm_size);
|
|
dbm_destroy(rlt);
|
|
|
|
return is_empty;
|
|
}
|
|
|
|
/*
|
|
* Funkcja wykorzystywana przy Post
|
|
*/
|
|
DBM_elem *
|
|
psmodel_post(ProdTrans_set *trans, ProdLoc_set *loc_src, DBM_elem *z_src, DBM_elem *z_dst)
|
|
{
|
|
DBM_elem *tmp_dbm;
|
|
|
|
tmp_dbm = dbm_copy(z_src, dbm_size);
|
|
dbm_time_successor(tmp_dbm, dbm_size);
|
|
dbm_intersection_cf_ip(tmp_dbm, loc_src->inv, dbm_size);
|
|
if (!dbm_empty(tmp_dbm, dbm_size))
|
|
{
|
|
dbm_intersection_cf_ip(tmp_dbm, trans->guard, dbm_size);
|
|
if (!dbm_empty(tmp_dbm, dbm_size))
|
|
{
|
|
ClockIdx_set *cur_clock;
|
|
|
|
for (cur_clock = trans->clocks; cur_clock; cur_clock = cur_clock->next)
|
|
dbm_reset(tmp_dbm, dbm_size, cur_clock->idx);
|
|
|
|
dbm_time_successor(tmp_dbm, dbm_size);
|
|
dbm_intersection_cf_ip(tmp_dbm, z_dst, dbm_size);
|
|
}
|
|
}
|
|
|
|
return tmp_dbm;
|
|
}
|
|
|
|
bool
|
|
psmodel_post_empty(ProdTrans_set *trans, ProdLoc_set *loc_src, DBM_elem *z_src, DBM_elem *z_dst)
|
|
{
|
|
bool is_empty;
|
|
DBM_elem *rlt;
|
|
|
|
rlt = psmodel_post(trans, loc_src, z_src, z_dst);
|
|
|
|
is_empty = dbm_empty(rlt, dbm_size);
|
|
dbm_destroy(rlt);
|
|
|
|
return is_empty;
|
|
}
|
|
|
|
/*
|
|
* Sprawdzanie stabilnosci danej klasy ze wzgledu na mozliwe nastepniki,
|
|
* a nastepnie ewentualna stabilizacja.
|
|
*/
|
|
void
|
|
psmodel_split(TimedClass_set *tcX, TimedClassRS_set **reach_stable, TimedClassRS_set **reach_stable_cur)
|
|
{
|
|
TimedClass_set *tcY;
|
|
DstLoc_set *tcY_dstloc;
|
|
ProdLoc_set *tcX_prodloc;
|
|
DBM_elem *tcX_dbm, *tcY_dbm;
|
|
ProdTrans_set *trans_e;
|
|
|
|
tcX_prodloc = tcX->loc_set;
|
|
tcX_dbm = tclass_readZoneDBM(tcX);
|
|
|
|
assert(tcX->depth != DEPTH_INF);
|
|
|
|
/*
|
|
* Biore wszystkie klasy Y t.z. da sie do nich przejsc z X (potencjalnie), a nastepnie
|
|
* szukam przejsc e \in E t.z. pre_e(X,Y) != 0.
|
|
*
|
|
* Dla przyspieszenia bierzemy pod uwage potencjalna mozliwosc przejscia. Wystepuje ona dla
|
|
* klas zwiazanych z lokacja do ktorych prowadzi przejscie z lokacji zwiazanej z aktualnie
|
|
* przetwarzana klasa.
|
|
*/
|
|
|
|
/** SZUKAMY WSZYSTKICH MOZLIWYCH NASTEPNIKOW KLASY X **/
|
|
/* Przechodzimy przez wszystkie lokacje (docelowe - dst_locs) z location(X) */
|
|
for (tcY_dstloc = tcX_prodloc->dst_locs; tcY_dstloc; tcY_dstloc = tcY_dstloc->next)
|
|
{
|
|
/*
|
|
* Bierzemy po kolei wszystkie klasy zwiazane z location(Y),
|
|
* ktore sa potencjalnymi klasami docelowymi
|
|
*/
|
|
for (tcY = tcY_dstloc->loc_set->classes; tcY; tcY = tcY->next)
|
|
{
|
|
tcY_dbm = tclass_readZoneDBM(tcY);
|
|
|
|
/* Bierzemy wszystkie przejscia mozliwe DO location(Y)... */
|
|
for (trans_e = tcY_dstloc->trans; trans_e; trans_e = trans_e->next)
|
|
{
|
|
/* ...i dla kazdego e (= trans_e) sprawdzamy czy pre_e(X,Y) != 0 */
|
|
if (!psmodel_pre_empty(trans_e, tcX_prodloc, tcY_dstloc->loc_set, tcX_dbm, tcY_dbm))
|
|
{
|
|
#ifdef PSM_VERBOSE
|
|
printf("\nSprawdzam stabilnosc klasy (%p) ", tcX); tclass_print(tcX);
|
|
printf("\n\tze wzgledu na klase "); tclass_print(tcY); printf("\n\n");
|
|
#endif
|
|
assert(tcX->depth != DEPTH_INF);
|
|
|
|
if (!psmodel_stabilityCheck(tcY, *reach_stable))
|
|
{
|
|
assert(tcY->depth >= tcX->depth+1);
|
|
|
|
/* stabilizujemy klase tcX ze wzgl. na tcY oraz przejscie trans_e */
|
|
psmodel_realSplit(tcX, tcY, trans_e, reach_stable, reach_stable_cur);
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/* jak jestesmy tutaj, to stabilne (Split (X,Pi) = {X}): */
|
|
psmodel_stableHandler(tcX, reach_stable, reach_stable_cur);
|
|
}
|
|
|
|
/*
|
|
* Sprawdzanie stabilnosci wzgledem klasy Y
|
|
*
|
|
* szukamy klasy X1 o minimalnej glebokosci z ktorej istnieje przejscie do klasy Y
|
|
*
|
|
* z klasy X1 do Y istnieje przejscie jak istnieje przejscie e miedzy location(X1) i location(Y)
|
|
* oraz pre_e(X1,Y) != 0
|
|
*
|
|
* location(X1) moze byc ktoras z lokacji nalezacych do zbioru lokacji z ktorych
|
|
* osiagalna jest location(Y)
|
|
*
|
|
* jak znajdziemy takie przejscie to sprawdzamy stabilnosc
|
|
*/
|
|
bool
|
|
psmodel_stabilityCheck(TimedClass_set *tcY, TimedClassRS_set *reach_stable)
|
|
{
|
|
TimedClassRS_set *curRS;
|
|
dpt_t min_depth = DEPTH_INF;
|
|
DBM_elem *tcY_dbm = NULL;
|
|
|
|
assert(tclass_ReachStable_is_sorted(reach_stable)); /* polegamy na tym ze reach_stable jest posortowane */
|
|
|
|
#ifdef PSM_VERBOSE
|
|
stTests++;
|
|
#endif
|
|
|
|
/* zakladamy ze klasa ([q0], {q0}, 0) ma petle wlasna, wiec bedzie stabilna */
|
|
if (tcY->depth == 0 && tclass_hasInit(tcY))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/* Bierzemy kolejne klasy X1 do sprawdzenia */
|
|
for (curRS = reach_stable; curRS; curRS = curRS->next)
|
|
{
|
|
TimedClass_set *tcX1 = curRS->tclass;
|
|
/* do sprawdzenia para lokacji i wszystkie przejscia miedzy nimi: */
|
|
|
|
if (tcX1->depth > min_depth)
|
|
{
|
|
return false; /* nie ma co dalej szukac, bo juz nie ma "minimalnych" */
|
|
}
|
|
|
|
/* Jesli znalazlo sie stabilne przejscie z wybranej klasy, to:
|
|
* - istnieje przejscie (z jakim h \in E)
|
|
* - zachodzi AE na rdzeniach
|
|
* - klasa ma minimalna glebokosc bo wybralismy ja z RS (sortowanie)
|
|
*/
|
|
#ifndef NO_STCACHE
|
|
if (tclass_isStableSucc(tcX1, tcY))
|
|
{
|
|
#ifdef PSM_VERBOSE
|
|
printf("Pominiety test stabilnosci\n");
|
|
skip_stTests++;
|
|
#endif
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
if (ploc_in_src_locs(tcX1->loc_set, tcY->loc_set->src_locs))
|
|
{
|
|
ProdTrans_set *trans_h;
|
|
|
|
if (!tcY_dbm) tcY_dbm = tclass_readZoneDBM(tcY);
|
|
|
|
/* Bierzemy kazde mozliwe przejscie z location(X1) do location(Y) */
|
|
for (trans_h = trans_get(tcX1->loc_set, tcY->loc_set); trans_h; trans_h = trans_h->next)
|
|
{
|
|
if (!psmodel_pre_empty(trans_h, tcX1->loc_set, tcY->loc_set,
|
|
tclass_readZoneDBM(tcX1), tcY_dbm))
|
|
{
|
|
/* znaleziono mozliwe przejscie z X1 do Y */
|
|
DBM_elem *tcX1_corDBM;
|
|
|
|
tcX1_corDBM = tclass_readCorDBM(tcX1);
|
|
|
|
/* aktualizujemy min_depth, bo to bedzie nasze minimum */
|
|
if (min_depth != tcX1->depth)
|
|
min_depth = tcX1->depth;
|
|
|
|
/* Znalazlo sie przejscie! */
|
|
#ifdef PSM_VERBOSE
|
|
printf("Mamy przejscie z klasy (%p) ", tcX1); tclass_print(tcX1);
|
|
printf("\n\tdo klasy "); tclass_print(tcY);
|
|
#endif
|
|
if (psmodel_pre_eq(tcX1_corDBM, trans_h, tcX1->loc_set, tcY->loc_set,
|
|
tcX1_corDBM, tclass_readCorDBM(tcY)))
|
|
{
|
|
#ifdef PSM_VERBOSE
|
|
printf("stabilna\n");
|
|
#endif
|
|
|
|
#ifndef NO_STCACHE
|
|
/* zapamietujemy stabilnosc */
|
|
tclass_saveStable(tcX1, tcY);
|
|
#endif
|
|
return true;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* Obsluga przypadku, gdy split nie mial co robic
|
|
*/
|
|
void
|
|
psmodel_stableHandler(TimedClass_set *tcX, TimedClassRS_set **reach_stable, TimedClassRS_set **reach_stable_cur)
|
|
{
|
|
DstLoc_set *dst_loc;
|
|
TimedClass_set *tcY;
|
|
ProdTrans_set *trans_e;
|
|
|
|
/* oznaczanie klasy tcX jako stabilna */
|
|
tclass_mark_stable(tcX);
|
|
|
|
/* znajdowanie wszystkich nastepnikow klasy tcX */
|
|
for (dst_loc = tcX->loc_set->dst_locs; dst_loc; dst_loc = dst_loc->next)
|
|
{
|
|
for (tcY = dst_loc->loc_set->classes; tcY; tcY = tcY->next)
|
|
{
|
|
for (trans_e = dst_loc->trans; trans_e; trans_e = trans_e->next)
|
|
{
|
|
if (!psmodel_post_empty(trans_e, tcX->loc_set, tclass_readZoneDBM(tcX), tclass_readZoneDBM(tcY)))
|
|
{
|
|
/* ustawianie dpt dla kazdego odnalezionego nastepnika */
|
|
tclass_depthUpdateIncr(tcY, tcX);
|
|
|
|
/* dodawanie do reachable */
|
|
tclass_ReachStable_add(tcY, reach_stable, reach_stable_cur);
|
|
#ifdef PSM_VERBOSE
|
|
printf("dodaje klase do reachable %p [%d]: ", trans_e, trans_e->act); tclass_print(tcY); printf("\n");
|
|
#endif
|
|
/* TODO: tutaj testowanie spelniania wlasnosci - to sie zrobi ;) */
|
|
if (ppty_check(tcY->loc_set->loc))
|
|
{
|
|
tclass_ReachStable_print(*reach_stable);
|
|
exit(0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Sprawdzenie warunku funkcji Sp na potrzeby asercji
|
|
*
|
|
* Powinno zachodzic pre_e(X,Y) != 0 oraz pre_e(Xcor, Ycor) != Xcor
|
|
*/
|
|
bool
|
|
psmodel_realSplit_isDefined(TimedClass_set *tcX, TimedClass_set *tcY, ProdTrans_set *trans_e)
|
|
{
|
|
if (psmodel_pre_empty(trans_e, tcX->loc_set, tcY->loc_set, tclass_readZoneDBM(tcX), tclass_readZoneDBM(tcY)))
|
|
{
|
|
printf("pre_e(X,Y) = 0\n");
|
|
return false;
|
|
}
|
|
if (psmodel_pre_eq(tclass_readCorDBM(tcX), trans_e, tcX->loc_set, tcY->loc_set, tclass_readCorDBM(tcX), tclass_readCorDBM(tcY)))
|
|
{
|
|
printf("pre_e(Xcor, Ycor) = Xcor\n");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Split z rozpatrywaniem 4 przypadkow niestabilnosci
|
|
*/
|
|
void
|
|
psmodel_realSplit(TimedClass_set *tcX, TimedClass_set *tcY, ProdTrans_set *trans_e,
|
|
TimedClassRS_set **reach_stable, TimedClassRS_set **reach_stable_cur)
|
|
{
|
|
DBM_elem *pre_e_Xcor_Ycor;
|
|
DBM_elem *tcX_corDBM, *tcY_corDBM;
|
|
|
|
assert(psmodel_realSplit_isDefined(tcX, tcY, trans_e)); /* bardzo wdzieczna assercja */
|
|
|
|
tcX_corDBM = tclass_readCorDBM(tcX);
|
|
tcY_corDBM = tclass_readCorDBM(tcY);
|
|
|
|
pre_e_Xcor_Ycor = psmodel_pre(trans_e, tcX->loc_set, tcY->loc_set, tcX_corDBM, tcY_corDBM);
|
|
|
|
if (!dbm_empty(pre_e_Xcor_Ycor, dbm_size))
|
|
{
|
|
/* jesli pre_e(Xcor,Ycor) != 0 to pseudo e-stabilny */
|
|
#ifdef PSM_VERBOSE
|
|
printf("pseudo stable\n");
|
|
#endif
|
|
/*
|
|
* Przed aktualizacja stable aktualizujemy reachable, bo dzieki temu
|
|
* przeszukiwac bedziemy mniejszy zbior (stabilnosc oznaczamy na elementach
|
|
* reachable). Pi nie aktualizujemy, bo podmieniamy tylko cor klasy.
|
|
*/
|
|
tclass_ReachStable_delete(tcX, reach_stable, reach_stable_cur); /* usuwanie tcX z reachable i ze stable */
|
|
tclass_mark_preds_unstable(tcX);
|
|
/* tutaj tclass_mark_unstable(tcX, *reach_stable) nie mialoby sensu bo tcX juz jest wyrzucone */
|
|
|
|
#ifndef NO_STCACHE
|
|
tclass_forgetPreStability(tcX);
|
|
#endif
|
|
tclass_replaceCorDBM(tcX, pre_e_Xcor_Ycor); /* nowa klasa */
|
|
tclass_depthUpdateInf(tcX); /* jesli nie zawiera q0 ustawiamy dpt(tcX) := inf */
|
|
if (tclass_hasInit(tcX)) /* jesli zawiera q0, to dodajemy do reachable */
|
|
{
|
|
tclass_ReachStable_addInit(tcX, reach_stable, reach_stable_cur);
|
|
}
|
|
/* Nie zwalniamy pre_e_Xcor_Ycor - wykorzystane jako cor! */
|
|
}
|
|
else
|
|
{
|
|
/* pre_e(Xcor,Ycor) = 0 */
|
|
DBM_elem *pre_e_X_Ycor, *tcX_zoneDBM;
|
|
TimedClass_set *tcN;
|
|
|
|
tcX_zoneDBM = tclass_readZoneDBM(tcX);
|
|
pre_e_X_Ycor = psmodel_pre(trans_e, tcX->loc_set, tcY->loc_set, tcX_zoneDBM, tcY_corDBM);
|
|
if (!dbm_empty(pre_e_X_Ycor, dbm_size))
|
|
{
|
|
DBMset_elem *dbms, *dbms_elem;
|
|
|
|
/* jesli pre_e(X,Ycor) != 0 to pseudo e-niestabilny */
|
|
#ifdef PSM_VERBOSE
|
|
printf("pseudo unstable\n");
|
|
#endif
|
|
/* na podstawie zbioru tworzymy klasy Zone = X\Xcor, Cor = pre_e_X_Ycor */
|
|
dbms = dbm_diff(tcX_zoneDBM, tcX_corDBM, dbm_size);
|
|
for (dbms_elem = dbms; dbms_elem; dbms_elem = dbms_elem->next)
|
|
{
|
|
DBM_elem *new_cor;
|
|
|
|
new_cor = dbm_intersection_cf(pre_e_X_Ycor, dbms_elem->dbm, dbm_size);
|
|
if (dbm_empty(new_cor, dbm_size))
|
|
{
|
|
/*
|
|
* Jesli cor (pre_e_X_Ycor) nie zawiera sie w zone to ustawiamy,
|
|
* ze cor = zone (jak cor = NULL, to cor = zone).
|
|
*/
|
|
dbm_destroy(new_cor);
|
|
new_cor = NULL;
|
|
}
|
|
|
|
tcN = tclass_create_nd(tcX->loc_set, dbms_elem->dbm, new_cor);
|
|
tclass_depthUpdateInf(tcN);
|
|
if (tclass_hasInit(tcN))
|
|
{
|
|
tclass_ReachStable_addInit(tcN, reach_stable, reach_stable_cur);
|
|
}
|
|
tclass_add(tcN);
|
|
}
|
|
dbmset_scaffoldDestroy(dbms);
|
|
|
|
tclass_ReachStable_delete(tcX, reach_stable, reach_stable_cur);
|
|
tclass_mark_preds_unstable(tcX);
|
|
#ifndef NO_STCACHE
|
|
tclass_forgetPreStability(tcX);
|
|
#endif
|
|
tclass_replaceZoneDBM(tcX, tcX_corDBM); /* nowa klasa; cor rowny calej nowej klasie, tzn. cor == NULL */
|
|
tclass_depthUpdateInf(tcX);
|
|
if (tclass_hasInit(tcX))
|
|
{
|
|
tclass_ReachStable_addInit(tcX, reach_stable, reach_stable_cur);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* pre_e(X,Ycor) = 0 */
|
|
DBM_elem *pre_e_Xcor_Y, *tcY_zoneDBM;
|
|
|
|
tcY_zoneDBM = tclass_readZoneDBM(tcY);
|
|
pre_e_Xcor_Y = psmodel_pre(trans_e, tcX->loc_set, tcY->loc_set, tcX_corDBM, tcY_zoneDBM);
|
|
if (!dbm_empty(pre_e_Xcor_Y, dbm_size))
|
|
{
|
|
DBMset_elem *dbms, *dbms_elem;
|
|
|
|
/* jesli pre_e(Xcor,Y) != 0 to semi e-niestabilny */
|
|
#ifdef PSM_VERBOSE
|
|
printf("semi unstable\n");
|
|
#endif
|
|
/* (X, pre_e_Xcor_Y, dpt), robimy podmiane i aktualizujemy */
|
|
tclass_ReachStable_delete(tcX, reach_stable, reach_stable_cur);
|
|
tclass_mark_preds_unstable(tcX);
|
|
#ifndef NO_STCACHE
|
|
tclass_forgetPreStability(tcX);
|
|
#endif
|
|
tclass_replaceCorDBM(tcX, pre_e_Xcor_Y); /* dalej zwolnic pre_e_Xcor_Y */
|
|
tclass_depthUpdateInf(tcX);
|
|
if (tclass_hasInit(tcX))
|
|
{
|
|
tclass_ReachStable_addInit(tcX, reach_stable, reach_stable_cur);
|
|
}
|
|
|
|
/* (Y\Ycor, Y\Ycor, dpt) */
|
|
dbms = dbm_diff(tcY_zoneDBM, tcY_corDBM, dbm_size);
|
|
for (dbms_elem = dbms; dbms_elem; dbms_elem = dbms_elem->next)
|
|
{
|
|
tcN = tclass_create_nd(tcY->loc_set, dbms_elem->dbm, NULL); /* NULL, bo cor = zone */
|
|
tclass_depthUpdateInf(tcN);
|
|
if (tclass_hasInit(tcN))
|
|
{
|
|
tclass_ReachStable_addInit(tcN, reach_stable, reach_stable_cur);
|
|
}
|
|
tclass_add(tcN);
|
|
}
|
|
dbmset_scaffoldDestroy(dbms);
|
|
|
|
/* (Ycor, Ycor, dpt) */
|
|
tclass_ReachStable_delete(tcY, reach_stable, reach_stable_cur);
|
|
tclass_mark_preds_unstable(tcY);
|
|
#ifndef NO_STCACHE
|
|
tclass_forgetPreStability(tcY);
|
|
#endif
|
|
tclass_replaceZoneDBM(tcY, tcY_corDBM); /* cor domyslnie rowny calej klasie */
|
|
tclass_depthUpdateInf(tcY);
|
|
if (tclass_hasInit(tcY))
|
|
{
|
|
tclass_ReachStable_addInit(tcY, reach_stable, reach_stable_cur);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBM_elem *pre_e_X_Y;
|
|
DBMset_elem *dbms, *dbms_elem;
|
|
/* pre_e(Xcor,Y) = 0 */
|
|
|
|
#ifdef PSM_VERBOSE
|
|
printf("unstable\n");
|
|
#endif
|
|
/* TODO: czasem niestety to obliczane jest dwa razy (wczesniej przy spr. mozliwosci przejscia) */
|
|
pre_e_X_Y = psmodel_pre(trans_e, tcX->loc_set, tcY->loc_set, tcX_zoneDBM, tcY_zoneDBM);
|
|
|
|
/* (X\pre_e_X_Y, Xcor, dpt) - uwaga podwojne wykorzystanie pre_e_X_Y - napisac komentarz! */
|
|
dbms = dbm_diff(tcX_zoneDBM, pre_e_X_Y, dbm_size);
|
|
for (dbms_elem = dbms; dbms_elem; dbms_elem = dbms_elem->next)
|
|
{
|
|
DBM_elem *new_cor;
|
|
|
|
new_cor = dbm_intersection_cf(tcX_corDBM, dbms->dbm, dbm_size);
|
|
if (dbm_empty(new_cor, dbm_size))
|
|
{
|
|
dbm_destroy(new_cor);
|
|
new_cor = NULL;
|
|
}
|
|
tcN = tclass_create_nd(tcX->loc_set, dbms_elem->dbm, new_cor);
|
|
tclass_depthUpdateInf(tcN);
|
|
if (tclass_hasInit(tcN))
|
|
{
|
|
tclass_ReachStable_addInit(tcN, reach_stable, reach_stable_cur);
|
|
}
|
|
tclass_add(tcN);
|
|
}
|
|
dbmset_scaffoldDestroy(dbms);
|
|
|
|
/* (pre_e_X_Y, pre_e_X_Y, dpt) */
|
|
tclass_ReachStable_delete(tcX, reach_stable, reach_stable_cur);
|
|
tclass_mark_preds_unstable(tcX);
|
|
#ifndef NO_STCACHE
|
|
tclass_forgetSuccStability(tcX);
|
|
tclass_forgetPreStability(tcX);
|
|
#endif
|
|
tclass_replaceZoneDBM(tcX, pre_e_X_Y); /* nowa klasa; cor zostaje rowny zone, tzn. cor == NULL */
|
|
dbm_destroy(pre_e_X_Y);
|
|
tclass_depthUpdateInf(tcX);
|
|
if (tclass_hasInit(tcX))
|
|
{
|
|
tclass_ReachStable_addInit(tcX, reach_stable, reach_stable_cur);
|
|
}
|
|
|
|
/* (Y\Ycor, Y\Ycor, dpt) */
|
|
dbms = dbm_diff(tcY_zoneDBM, tcY_corDBM, dbm_size);
|
|
for (dbms_elem = dbms; dbms_elem; dbms_elem = dbms_elem->next)
|
|
{
|
|
tcN = tclass_create_nd(tcY->loc_set, dbms_elem->dbm, NULL); /* NULL, bo cor = zone */
|
|
tclass_depthUpdateInf(tcN);
|
|
if (tclass_hasInit(tcN))
|
|
{
|
|
tclass_ReachStable_addInit(tcN, reach_stable, reach_stable_cur);
|
|
}
|
|
tclass_add(tcN);
|
|
}
|
|
dbmset_scaffoldDestroy(dbms);
|
|
|
|
/* (Ycor, Ycor, dpt) */
|
|
tclass_ReachStable_delete(tcY, reach_stable, reach_stable_cur);
|
|
tclass_mark_preds_unstable(tcY);
|
|
#ifndef NO_STCACHE
|
|
tclass_forgetPreStability(tcY);
|
|
#endif
|
|
tclass_replaceZoneDBM(tcY, tcY_corDBM); /* nowy cor domyslnie rowny calej klasie */
|
|
tclass_depthUpdateInf(tcY);
|
|
if (tclass_hasInit(tcY))
|
|
{
|
|
tclass_ReachStable_addInit(tcY, reach_stable, reach_stable_cur);
|
|
}
|
|
}
|
|
dbm_destroy(pre_e_Xcor_Y);
|
|
}
|
|
dbm_destroy(pre_e_X_Ycor);
|
|
}
|
|
dbm_destroy(pre_e_Xcor_Ycor);
|
|
|
|
}
|
|
|
|
/*
|
|
* Inicjalizacja potrzebnych struktur danych do zbudowania ps-modelu:
|
|
*
|
|
* - poczatkowy podzial
|
|
* - zbior lokacji odwiedzonych
|
|
* - zbior klas osiagalnych (reachable), zbior klas stabilnych (stable)
|
|
*/
|
|
void
|
|
psmodel_init(ProdLoc_set **visited_root, ProdLoc_set **visited_cur,
|
|
TimedClassRS_set **reach_stable_root, TimedClassRS_set **reach_stable_cur)
|
|
{
|
|
Loc_idx *ploc_init; /* lokacja poczatkowa */
|
|
DBM_elem *ploc_init_inv; /* jej niezmiennik */
|
|
TimedClass_set *init_tclass;
|
|
|
|
/* zbieramy informacje o lokacji poczatkowej */
|
|
ploc_init = prod_loc_initial(); /* lokacje skladowe */
|
|
ploc_init_inv = prod_loc_inv(ploc_init); /* niezmiennik (koniunkcja niezm. skladowych) */
|
|
|
|
init_loc_set = prod_loc_set_add(ploc_init, ploc_init_inv, visited_root, visited_cur);
|
|
|
|
init_tclass = tclass_create(init_loc_set, NULL, dbm_copy(zeroDBM, dbm_size), 0);
|
|
tclass_add(init_tclass);
|
|
tclass_mark_reach_unst(init_tclass, reach_stable_root, reach_stable_cur);
|
|
}
|
|
|
|
/*
|
|
* Konstruowanie pseudosymulacyjnego modelu abstrakcyjnego
|
|
*/
|
|
void
|
|
psmodel_builder(AutNet *an)
|
|
{
|
|
ProdLoc_set *visited_locs_root = NULL, *visited_locs_cur;
|
|
|
|
TimedClassRS_set *reach_stable_root = NULL, *reach_stable_cur, *picked_tclass_rs;
|
|
|
|
net_init(an); /* inicjalizujemy siec */
|
|
|
|
psmodel_init(&visited_locs_root, &visited_locs_cur, &reach_stable_root, &reach_stable_cur);
|
|
|
|
#ifdef PSM_VERBOSE
|
|
stTests = 0;
|
|
skip_stTests = 0;
|
|
#endif
|
|
|
|
/*
|
|
* Na razie stosujemy zbior zawierajacy klasy osiagalne i oznaczamy te ktore sa w stable,
|
|
* opierajac sie na obserwacji, ze stable zawsze zawiera sie w reachable.
|
|
* W przyszlosci mozna sprobowac rozbic reachable na reachable_stable (stable) i reachable_unstable.
|
|
* Dzieki temu uniknie sie przegladania zbioru w poszukiwaniu pierwszej niestabilnej klasy.
|
|
*/
|
|
|
|
while ((picked_tclass_rs = tclass_pickReachUnst(reach_stable_root)) != NULL)
|
|
{
|
|
TimedClass_set *tc; /* rozwazana klasa Y */
|
|
bool *actions;
|
|
idx_t i;
|
|
ProdLoc_set *cur_loc;
|
|
|
|
tc = picked_tclass_rs->tclass;
|
|
cur_loc = tc->loc_set;
|
|
|
|
#ifdef PSM_VERBOSE
|
|
printf("Przetwarzana klasa "); tclass_print(tc); printf("\n");
|
|
#endif
|
|
|
|
if (!cur_loc->trans_complete)
|
|
{
|
|
/**** okreslamy new_locs, visited_locs i rozszerzamy zbior Pi ****/
|
|
actions = prod_loc_acts(tc->loc_set->loc); /* akcje wykonalne z lokacji zwiazanej z biezaca klasa */
|
|
for (i = 0; i < nact; i++)
|
|
{
|
|
if (actions[i])
|
|
{
|
|
ProdTrLoc_set *prtl, *prtl_tmp;
|
|
prtl = prod_loc_succ(cur_loc->loc, i); /* pobieramy mozliwe przejscia dla akcji i */
|
|
|
|
for (prtl_tmp = prtl; prtl_tmp; prtl_tmp = prtl_free_getNext(prtl_tmp))
|
|
{
|
|
DBM_elem *inv_guard;
|
|
bool transition_added = false;
|
|
|
|
/*
|
|
* UWAGA:
|
|
* Zanim dodamy lokacje lub przejscie do niej prowadzace, sprawdzamy warunek
|
|
* na guardy i niezmienniki. Przejscia rowniez nie sa zapisywane jesli nie jest
|
|
* spelniony ten warunek (linia 6 i 7).
|
|
*/
|
|
|
|
inv_guard = dbm_intersection_cf(cur_loc->inv, prtl_tmp->guard, dbm_size);
|
|
if (!dbm_empty(inv_guard, dbm_size))
|
|
{
|
|
/* niepuste przeciecie niezmiennika lokacji zrodlowej z guardem */
|
|
ClockIdx_set *cur_clock;
|
|
DBM_elem *dst_locInv;
|
|
ProdLoc_set *dst_loc;
|
|
|
|
/* inv_guard := inv_guard[reset(prtl_tmp) := 0] */
|
|
for (cur_clock = prtl_tmp->clocks; cur_clock; cur_clock = cur_clock->next)
|
|
dbm_reset(inv_guard, dbm_size, cur_clock->idx);
|
|
|
|
/* pobieramy adres struktury z lokacja docelowa dla przetwarzanego przejscia
|
|
* jesli nie ma, to dst_loc == NULL
|
|
*
|
|
* dst_loc jest wykorzystywane jako warunek czy lokacja jest w visited_locs
|
|
*/
|
|
dst_loc = prod_loc_set_getp(prtl_tmp->loc, visited_locs_root);
|
|
|
|
/* niezmiennik produktowy obliczamy tylko gdy jeszcze nie zrobilismy tego wczesniej */
|
|
if (!dst_loc)
|
|
dst_locInv = prod_loc_inv(prtl_tmp->loc);
|
|
else
|
|
dst_locInv = dst_loc->inv;
|
|
|
|
dbm_intersection_cf_ip(inv_guard, dst_locInv, dbm_size);
|
|
if (!dbm_empty(inv_guard, dbm_size))
|
|
{
|
|
/* dodajemy lokacje do visited_locs? */
|
|
if (!dst_loc)
|
|
{
|
|
/* dst_loc == NULL */
|
|
dst_loc = prod_loc_set_add(prtl_tmp->loc, dst_locInv, &visited_locs_root, &visited_locs_cur);
|
|
tclass_add(tclass_create_base(dst_loc)); /* dodajemy nowa klase do Pi */
|
|
}
|
|
else
|
|
{
|
|
/* juz mamy ta lokacje, wiec zwalniamy pamiec (juz znamy ta konfiguracje lokacji skladowych) */
|
|
free(prtl_tmp->loc);
|
|
/* dst_locInv: niezmiennika nigdy nie zwalniamy, bo albo jest pobrany
|
|
* istniejacy albo dodajemy nowa lokacje
|
|
*/
|
|
}
|
|
|
|
/* dopisujemy odkryte przejscie do zbioru przejsc lokacji zrodlowej (aktualnie przetwarzana) */
|
|
trans_add(cur_loc, dst_loc, prtl_tmp);
|
|
transition_added = true;
|
|
}
|
|
}
|
|
|
|
dbm_destroy(inv_guard);
|
|
|
|
/* DBM z guardem i liste zegarow (reset) zwalniamy tylko jesli nie dodalismy tranzycji */
|
|
if (!transition_added)
|
|
{
|
|
dbm_destroy(prtl_tmp->guard);
|
|
colclocks_free(prtl_tmp->clocks);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
free(actions);
|
|
cur_loc->trans_complete = true; /* przejscia z tej lokacji zostaly skompletowane */
|
|
}
|
|
psmodel_split(tc, &reach_stable_root, &reach_stable_cur);
|
|
|
|
}
|
|
|
|
tclass_ReachStable_print(reach_stable_root);
|
|
#ifdef PSM_VERBOSE
|
|
printf("\nPominietych testow stabilnosci (cache): %u/%u\n", skip_stTests, stTests);
|
|
printf("Utworzonych rzeczywistych klas: %u\n", tclass_count(visited_locs_root));
|
|
#endif
|
|
|
|
}
|
|
|
|
bool
|
|
ppty_check(Loc_idx *prodloc)
|
|
{
|
|
Property_set *ppty;
|
|
|
|
for (ppty = ppts; ppty; ppty = ppty->next)
|
|
{
|
|
ProdConf_set *w;
|
|
bool sat = false;
|
|
|
|
for (w = ppty->prop; w; w = w->next)
|
|
{
|
|
if (prodloc[w->aut] == w->loc)
|
|
{
|
|
sat = true;
|
|
}
|
|
else
|
|
{
|
|
sat = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (sat)
|
|
{
|
|
printf("Property \"%s\" satisfied!\n", ppty->name);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|