Files
ta-splitting/anproc.c
2019-02-22 17:33:33 +00:00

893 lines
18 KiB
C

/** anproc.c **/
/*
* Przetwarzanie struktur stworzonych podczas wczytywania sieci automatow,
* tworzenie produktu na podstawie sieci automatow.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include "anproc.h"
#include "antypes.h"
#include "anmacro.h"
#include "macro.h"
#include "dbm.h"
static Aut *aut = NULL;
static Aut_idx naut = 0;
static Clock_idx pclocks_cnt = 0; /* zegary w automacie produktowym */
static ProdClock *pclocks_map;
static Clock_idx **rpclocks_map;
static Act *act = NULL;
Act_idx nact = 0;
DBM_idx dbm_size = 0;
DBM_elem *zeroDBM = NULL;
ProdLoc_set *init_loc_set = NULL;
Property_set *ppts = NULL;
/*
* Inicjalizacja przetwarzania sieci
*
* F-cja ustawia wartosci zmiennych globalnych, zeby uniknac przekazywania niektorych argumentow
*/
void
net_init(AutNet *an)
{
idx_t i;
/* automaty */
aut = an->aut;
naut = an->naut;
/* akcje */
act = an->act;
nact = an->nact;
ppts = an->ppts;
/* zliczamy zegary ze wszystkich automatow skladowych */
for (i = 0; i < naut; i++)
{
pclocks_cnt += aut[i].nclks;
}
dbm_size = pclocks_cnt+1;
zeroDBM = dbm_init_zero(dbm_size);
prod_clocks_mkmap();
#ifdef VERBOSE
printf("Liczba zegarow w automacie produktowym = %d\n", pclocks_cnt);
#endif
}
void
prod_clocks_mkmap(void)
{
Clock_idx i, j, k;
pclocks_map = smalloc(sizeof(ProdClock)*pclocks_cnt); /* produktowy -> skladowy */
rpclocks_map = smalloc(sizeof(Clock_idx *)*naut); /* skladowy -> produktowy */
k = 0;
for (i = 0; i < naut; i++)
{
rpclocks_map[i] = smalloc(sizeof(Clock_idx)*aut[i].nclks);
for (j = 0; j < aut[i].nclks; j++)
{
pclocks_map[k].par_aut = i;
pclocks_map[k].par_idx = j+1; /* ze wzgledu na x_0 */
rpclocks_map[i][j] = k+1;
k++;
}
}
}
void
prod_clock_maps_free(void)
{
idx_t i;
free(pclocks_map);
for (i = 0; i < naut; i++)
{
free(rpclocks_map[i]);
}
free(rpclocks_map);
}
/*
* Konwersja indeksu zegara z automatu skladowego
* do indeksu zegara z automatu produktoweg
*/
Clock_idx
prod_clock_idx2pidx(Aut_idx ai, Clock_idx ci)
{
assert(ai < naut);
assert(ci-1 < aut[ai].nclks);
if (ci == 0)
return 0;
else
{
assert(rpclocks_map[ai][ci-1] < dbm_size);
return rpclocks_map[ai][ci-1];
}
}
/*
* Indeks produktowego zegara -> indeks skladowego
*/
ProdClock
prod_clock_pidx2idx(Clock_idx ci)
{
if (ci == 0)
{
ProdClock r;
r.par_aut = 0;
r.par_idx = 0;
return r;
}
else
{
return pclocks_map[ci-1];
}
}
/*
* Okreslanie poczatkowej lokacji produktowej
*/
Loc_idx *
prod_loc_initial(void)
{
idx_t i;
Loc_idx *initial;
initial = smalloc(sizeof(Loc_idx)*naut);
for (i = 0; i < naut; i++)
initial[i] = aut[i].init_loc;
return initial;
}
/*
* Kopiowanie okreslonej lokacji produktowej
*/
Loc_idx *
prod_loc_copy(Loc_idx *prod_loc)
{
Loc_idx *copy;
copy = smalloc(sizeof(Loc_idx)*naut);
(void)memcpy(copy, prod_loc, sizeof(Loc_idx)*naut);
return copy;
}
/*
* Pobieranie listy akcji POTENCJALNIE wykonalnych z lokacji produktowej
*/
bool *
prod_loc_acts(Loc_idx *prod_loc)
{
idx_t i, j;
Trans_set *t;
bool *used_acts;
used_acts = smalloc_zero(sizeof(bool)*nact);
for (i = 0; i < naut; i++)
{
for (j = 0; j < aut[i].nloc; j++)
{
for (t = TRANS(aut[i].trans, aut[i].nloc, prod_loc[i], j);
t != NULL;
t = t->next)
{
used_acts[t->act] = true;
}
}
}
return used_acts;
}
/*
* Wyswietlanie lokacji produktowej
*/
void
prod_loc_show(Loc_idx *prod_loc)
{
idx_t i;
printf("( ");
for (i = 0; i < naut; i++)
printf("%s ", get_loc_name(aut[i].loc, prod_loc[i]));
printf(")");
}
/*
* Dodawanie lokacji produktowej do zbioru
*/
ProdLoc_set *
prod_loc_set_add(Loc_idx *prod_loc, DBM_elem *inv, ProdLoc_set **root, ProdLoc_set **cur)
{
ProdLoc_set *new;
new = smalloc(sizeof(ProdLoc_set));
new->loc = prod_loc;
new->inv = inv;
new->src_locs = NULL;
new->dst_locs = NULL;
new->classes = NULL;
new->trans_complete = false;
prod_loc_set_raw_add(new, root, cur);
return new;
}
/*
* Dodawanie lokacji produktowej do zbioru w postaci surowej
*/
void
prod_loc_set_raw_add(ProdLoc_set *new, ProdLoc_set **root, ProdLoc_set **cur)
{
new->next = NULL; /* nie wiadomo co tam bylo, a dodajemy na koncu */
if (!*root)
*root = new;
else
(*cur)->next = new;
*cur = new;
}
/*
* Sprawdzanie zawierania lokacji produktowej przez zbior
*/
bool
prod_loc_set_is_in(Loc_idx *prod_loc, ProdLoc_set *root)
{
ProdLoc_set *cur;
for (cur = root; cur; cur = cur->next)
{
if (memcmp(cur->loc, prod_loc, sizeof(Loc_idx)*naut) == 0) return true; /* znaleziono */
}
return false; /* nie znaleziono */
}
/*
* Sprawdzanie zawierania lokacji produktowej przez zbior
*/
ProdLoc_set *
prod_loc_set_getp(Loc_idx *prod_loc, ProdLoc_set *root)
{
ProdLoc_set *cur;
for (cur = root; cur; cur = cur->next)
{
if (memcmp(cur->loc, prod_loc, sizeof(Loc_idx)*naut) == 0) return cur;
}
return NULL;
}
/*
* Wyciaganie (wybieranie i usuwanie) elementu ze zbioru
*/
ProdLoc_set *
prod_loc_set_raw_pick(ProdLoc_set **root)
{
ProdLoc_set *picked;
picked = *root; /* bierzemy korzen */
/* jesli byl korzen, to mial ustawione pole next, ktore wskazuje na nowy korzen */
if (*root)
*root = picked->next;
return picked;
}
/*
* Wyswietlanie zbioru lokacji produktowych
*/
void
prod_loc_set_show(ProdLoc_set *root)
{
ProdLoc_set *cur;
for (cur = root; cur; cur = cur->next)
{
prod_loc_show(cur->loc);
printf("\ninv:\n");
dbm_print(cur->inv, dbm_size);
}
printf("\n");
}
/*
* Pelne zwalnianie pamieci przydzielonej na zbior lokacji produktowych
* (pelne - wraz z lokacjami produktowymi).
*/
void
prod_loc_set_free(ProdLoc_set *root)
{
ProdLoc_set *cur;
for (cur = root; cur; )
{
ProdLoc_set *tmp = cur;
cur = cur->next;
free(tmp->loc);
dbm_destroy(tmp->inv);
free(tmp);
}
}
/*
* Dodawanie przejscia do lokacji
*/
void
trans_add(ProdLoc_set *src_loc, ProdLoc_set *dst_loc, ProdTrLoc_set *prtl)
{
ProdTrans_set *new_trans;
DstLoc_set *cur_dst_loc;
DstLoc_set *dst_group = NULL;
new_trans = smalloc(sizeof(ProdTrans_set));
new_trans->act = prtl->act;
new_trans->guard = prtl->guard;
new_trans->clocks = prtl->clocks;
new_trans->next = NULL;
/*
- zgrupowane wszystkie przejscia do jednej lokacji docelowej
- dodajac nowe przejscie szukamy grupy do ktorej nalezy okreslone
przejscie dodac
- jesli nie ma jeszcze takiej grupy, to ja tworzymy
- z grupa zwiazany jest wskaznik na lokacje docelowa
(dokladnie, element zbioru lokacji ja przetrzymujacy)
*/
/* szukamy grupy przejsc prowadzacych do dst_loc */
cur_dst_loc = src_loc->dst_locs;
while (cur_dst_loc)
{
/* sprawdzamy czy znalezlismy cur_dst_loc == dst_loc */
if (cur_dst_loc->loc_set == dst_loc)
{
dst_group = cur_dst_loc;
break;
}
if (!cur_dst_loc->next)
break;
else
cur_dst_loc = cur_dst_loc->next;
}
/*
* jesli dst_group jest nieustawione, to nie ma jeszcze takiej
* lokacji docelowej i trzeba ja dodac
*/
if (!dst_group)
{
SrcLoc_set *new_src_loc;
dst_group = smalloc(sizeof(DstLoc_set));
dst_group->loc_set = dst_loc;
dst_group->trans = NULL;
dst_group->last_trans = NULL;
dst_group->next = NULL;
/*
* naszym dst_locs_LAST jest cur_dst_loc (gdy dst_group == NULL)
*/
if (!src_loc->dst_locs)
src_loc->dst_locs = dst_group;
else
{
assert(cur_dst_loc != NULL);
cur_dst_loc->next = dst_group; /* Segfault! */
}
new_src_loc = smalloc(sizeof(SrcLoc_set));
new_src_loc->loc_set = src_loc;
new_src_loc->trans = new_trans; /* zapisujemy tylko raz (i tylko pierwszy element) */
new_src_loc->next = NULL;
/*
* zakladamy ze jesli nie udalo sie znalezc istniejacej grupy to
* w lokacji docelowej tez nie ma informacji o tej lokacji zrodlowej
*/
if(!dst_loc->src_locs)
dst_loc->src_locs = new_src_loc;
else
dst_loc->last_src_loc->next = new_src_loc;
dst_loc->last_src_loc = new_src_loc;
}
if (!dst_group->trans)
dst_group->trans = new_trans;
else
dst_group->last_trans->next = new_trans;
dst_group->last_trans = new_trans;
}
/*
* Pobieranie wskaznika na przejscia z lokacji src do lokacji dst
*/
ProdTrans_set *
trans_get(ProdLoc_set *src, ProdLoc_set *dst)
{
DstLoc_set *cur_dstloc;
for (cur_dstloc = src->dst_locs; cur_dstloc; cur_dstloc = cur_dstloc->next)
{
if (cur_dstloc->loc_set == dst)
{
return cur_dstloc->trans;
}
}
return NULL;
}
/*
* Sprawdzanie zawierania elementu zbioru lokacji produktowych
* przez zbior lokacji zrodlowych
*/
bool
ploc_in_src_locs(ProdLoc_set *prod_loc, SrcLoc_set *root)
{
SrcLoc_set *cur;
for (cur = root; cur; cur = cur->next)
{
if (cur->loc_set == prod_loc) return true; /* znaleziono */
}
return false; /* nie znaleziono */
}
void
trloc_set_free(TrLoc_set **trloc)
{
idx_t i;
TrLoc_set *tmp;
for (i = 0; i < naut; i++)
for (tmp = trloc[i]; tmp != NULL; tmp = tmp->next)
free(tmp);
free(trloc);
}
/*
* Sprawdzanie czy lista ograniczen zawiera jakies rzeczywiste ograniczenia
*/
bool
constr_nonempty(Constr *c)
{
if (c)
/* lista jest niepusta */
if (CONSTR_IS_TERM(c))
/* pierwsze ogr. jest terminujace, czyli nic nie ma */
return false;
else
/* jest przynajmniej jedno ogr. */
return true;
else
return false;
}
/*
* Wprowadzanie ograniczen z listy c do DBM-a p
*/
void
constr2dbm(Aut_idx ai, DBM_elem *p, Constr *c)
{
if (!c) return;
for (; !CONSTR_IS_TERM(c); c++)
{
DBM_idx i, j;
i = prod_clock_idx2pidx(ai, c->l_clk);
j = prod_clock_idx2pidx(ai, c->r_clk);
switch (c->rel)
{
case CONSTR_LE:
dbm_constr_le(p, dbm_size, i, j, c->val);
break;
case CONSTR_LT:
dbm_constr_lt(p, dbm_size, i, j, c->val);
break;
default:
FERROR("Unknown relation");
break;
}
dbm_canon1(p, dbm_size, i, j);
}
}
/*
* Zbieranie z automatow skladowych zegarow z indeksami automatu produktowego
*/
void
clocks_collect(ClockIdx_set **root, ClockIdx_set **cur, Aut_idx ai, Clock_idx *clks, Clock_idx nclks)
{
idx_t i;
for (i = 0; i < nclks; i++, clks++)
{
ClockIdx_set *n = smalloc(sizeof(ClockIdx_set));
n->idx = prod_clock_idx2pidx(ai, *clks);
assert(n->idx > 0);
n->next = NULL;
if (!*root)
*root = n;
else
(*cur)->next = n;
*cur = n;
}
}
/*
* Zwalnianie pamieci zaalokowanej przez clocks_collect
*/
void
colclocks_free(ClockIdx_set *elem)
{
ClockIdx_set *next;
while (elem)
{
next = elem->next;
free(elem);
elem = next;
}
}
/*
* Pobieranie niezmiennika dla okreslonej lokacji produktowej w post. DBM.
*/
DBM_elem *
prod_loc_inv(Loc_idx *ploc)
{
DBM_elem *p = NULL;
idx_t i;
p = dbm_init(dbm_size);
for (i = 0; i < naut; i++)
{
constr2dbm(i, p, aut[i].loc[ploc[i]].inv);
}
return p;
}
/*
* Pobieranie niezmiennika dla okreslonej lokacji produktowej w post. DBM.
* Jesli nie ma ograniczen, to DBM == NULL.
*/
DBM_elem *
prod_loc_inv0(Loc_idx *ploc)
{
DBM_elem *p = NULL;
idx_t i;
for (i = 0; i < naut; i++)
{
Constr *cinv;
cinv = aut[i].loc[ploc[i]].inv;
/* DBM alokowany tylko jak jest co do niego wrzucic */
if (!p && constr_nonempty(cinv)) p = dbm_init(dbm_size);
constr2dbm(i, p, cinv);
}
return p; /* p == NULL jesli nie ma ograniczen */
}
/*
* Znajdowanie przejsc z okreslona akcja mozliwych z danej lokacji
* produktowej wraz z lokacjami produktowymi do ktorych prowadza.
*/
ProdTrLoc_set *
prod_loc_succ(Loc_idx *src_ploc, Act_idx a)
{
idx_t i, j;
Trans_set *t;
TrLoc_set **trloc; /* posrednia struktura do ktorej bedziemy zbierac przejscia i lokacje docelowe */
idx_t *ntrloc; /* liczniki odnalezionych przejsc w poszczegolnych automatach */
trloc = smalloc_zero(sizeof(TrLoc_set *)*naut);
ntrloc = smalloc_zero(sizeof(idx_t)*naut);
for (i = 0; i < naut; i++)
{
if (aut[i].uact[a]) /* jesli akcja jest w zbiorze akcji automatu, to idziemy dalej */
{
for (j = 0; j < aut[i].nloc; j++)
{
for (t = TRANS(aut[i].trans, aut[i].nloc, src_ploc[i], j);
t != NULL; t = t->next)
{
if (t->act == a) /* znalezlismy przejscie z poszukiwana akcja */
{
TrLoc_set *n;
ntrloc[i]++; /* znaleziono przejscie */
n = smalloc(sizeof(TrLoc_set));
n->loc = j;
n->trans = t;
n->next = NULL;
if (!trloc[i])
trloc[i] = n;
else
{
TrLoc_set *last;
for (last = trloc[i]; last->next != NULL; last = last->next);
last->next = n;
}
}
}
}
if (!ntrloc[i])
{
/* akcja jest niewykonalna, poniewaz i-ty automat ma ta akcje
* w zbiorze swoich akcji, ale nie jest ona w nim umozliwiona.
*/
trloc_set_free(trloc);
free(ntrloc);
return NULL;
}
}
}
{
ProdTrLoc_set *r = NULL, *r_cur = NULL;
idx_t *idcs = smalloc(sizeof(idx_t)*naut);
int k = 0;
for (i = 0; i < naut; i++)
{
if (ntrloc[i] > 0) idcs[i] = 1;
else idcs[i] = 0;
}
while (k >= 0)
{
Loc_idx *dst_ploc = prod_loc_copy(src_ploc);
ProdTrLoc_set *n = smalloc(sizeof(ProdTrLoc_set));
ClockIdx_set *clocks_cur = NULL;
n->act = a;
n->guard = dbm_init(dbm_size);
n->clocks = NULL; /* musi byc, bo inaczej clocks_cur bedzie brany pod uwage w clocks_collect */
for (i = 0; i < naut; i++)
{
int depth = 0;
TrLoc_set *trloc_tmp;
for (trloc_tmp = trloc[i]; trloc_tmp; trloc_tmp = trloc_tmp->next)
{
/* ten for wykonuje sie tylko jak cos sie zmienilo w i-tym automacie */
depth++;
if (depth == idcs[i])
{
dst_ploc[i] = trloc_tmp->loc;
constr2dbm(i, n->guard, trloc_tmp->trans->guard); /* wystarczy tylko dla trloc[i]? */
/* optymalniej byloby dokonac kanonizacji po wniesieniu zmian do DBM z uwzglednieniem
* ile zostalo zmodyfikowanych elementow (czasami dbm_canon1 nie oplaca sie), poniewaz
* obecnie constr2dbm oblicza za kazdym razem PK co na pewno nie jest oplacalne jesli
* modyfikacji jest tyle co dbm_size.
*/
clocks_collect(&(n->clocks), &clocks_cur, i, trloc_tmp->trans->clocks, trloc_tmp->trans->nclocks);
}
}
}
n->loc = dst_ploc;
n->next = NULL;
if (!r)
r = n;
else
r_cur->next = n;
r_cur = n;
for (k = naut - 1; k >= 0 && idcs[k] == ntrloc[k]; k--)
{
if (ntrloc[k] > 0) idcs[k] = 1;
}
if (k >= 0) idcs[k]++;
}
free(idcs);
trloc_set_free(trloc);
free(ntrloc);
return r;
}
}
/*
* Zwalniamy pamiec prtl i zwracamy kolejny element
* (do wykorzystywania w petlach)
*
*/
ProdTrLoc_set *
prtl_free_getNext(ProdTrLoc_set *prtl)
{
ProdTrLoc_set *next;
next = prtl->next;
free(prtl);
return next;
}
/*
* Generowanie automatu pseudoproduktowego (do testow). Troche nasmiecone. Jesli ma zostac w kodzie, to
* trzeba dokonac doglebnego przegladu.
*/
void
prod_show(AutNet *an)
{
ProdLoc_set *waiting_root = NULL, *waiting_cur = NULL; /* _cur nie musi byc NULL (ale kompilator...) */
ProdLoc_set *visited_root = NULL, *visited_cur = NULL;
Loc_idx *ploc_init;
DBM_elem *ploc_init_inv;
net_init(an);
ploc_init = prod_loc_initial();
ploc_init_inv = prod_loc_inv(ploc_init);
prod_loc_set_add(ploc_init, ploc_init_inv, &waiting_root, &waiting_cur);
while (waiting_root)
{
ProdLoc_set *processed;
bool *actions;
idx_t i;
processed = prod_loc_set_raw_pick(&waiting_root);
prod_loc_set_raw_add(processed, &visited_root, &visited_cur);
actions = prod_loc_acts(processed->loc);
printf("-------------------------------------------------------------\n");
printf("Przejscia mozliwe z lokacji produktowej ");
prod_loc_show(processed->loc); printf("\n");
for (i = 0; i < nact; i++)
{
if (actions[i])
{
ProdTrLoc_set *prtl, *prtl_tmp;
prtl = prod_loc_succ(processed->loc, i);
for (prtl_tmp = prtl; prtl_tmp;)
{
printf("\n");
printf("Akcja %s\n", get_act_name(act, i));
printf("Guard:\n");
dbm_print(prtl_tmp->guard, dbm_size);
printf("Zegary do zresetowania: ");
{
ClockIdx_set *cur;
for (cur = prtl_tmp->clocks; cur; cur = cur->next)
{
ProdClock pc;
pc = prod_clock_pidx2idx(cur->idx);
printf("%s(%s,%d) ", aut[pc.par_aut].name, get_clock_name(aut[pc.par_aut].clks, pc.par_idx), cur->idx);
}
printf("\n");
}
printf("Do lokacji: ");
prod_loc_show(prtl_tmp->loc); printf("\n");
if (!prod_loc_set_is_in(prtl_tmp->loc, waiting_root) && !prod_loc_set_is_in(prtl_tmp->loc, visited_root))
{
/* lokacji nie ma jeszcze ani w WAITING ani w VISITED, wiec moze ja dodamy... */
DBM_elem *inv_guard;
inv_guard = dbm_intersection_cf(processed->inv, prtl_tmp->guard, dbm_size);
if (!dbm_empty(inv_guard, dbm_size))
{
ClockIdx_set *cur;
DBM_elem *prtl_tmp_locInv;
for (cur = prtl_tmp->clocks; cur; cur = cur->next)
{
dbm_reset(inv_guard, dbm_size, cur->idx);
}
/* przeciecie inv_guard (po resetach) z niezmiennikiem lokacji docelowej */
prtl_tmp_locInv = prod_loc_inv(prtl_tmp->loc);
dbm_intersection_cf_ip(inv_guard, prtl_tmp_locInv, dbm_size);
if (!dbm_empty(inv_guard, dbm_size))
{
prod_loc_set_add(prtl_tmp->loc, prtl_tmp_locInv, &waiting_root, &waiting_cur);
}
else
{
dbm_destroy(prtl_tmp_locInv);
}
}
}
else
{
/* mamy juz ta lokacje, wiec zwalniamy pamiec */
free(prtl_tmp->loc);
}
/* informacje z prod_loc_succ zostaly wykorzystane - zwalniamy pamiec */
dbm_destroy(prtl_tmp->guard);
colclocks_free(prtl_tmp->clocks);
{
ProdTrLoc_set *next;
next = prtl_tmp->next;
free(prtl_tmp);
prtl_tmp = next;
}
}
}
}
free(actions); /* moze lepiej byloby pomyslec nad czyms wielokrotnego uzytku...?
albo zastapic jakas lepsza struktura danych? */
}
printf("------\n");
prod_loc_set_show(visited_root);
prod_loc_set_free(visited_root);
}