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

1349 lines
24 KiB
C

/** dbm.c **/
/*
* Operacje na macierzach ograniczen roznic
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dbm.h"
#include "dbm_macro.h"
#include "macro.h"
DBM_elem *
dbm_init(DBM_idx dim)
{
DBM_elem *p;
DBM_idx i, j;
p = dbm_rawinit(dim);
/* Poczatkowe wypelnianie macierzy */
for (i = 0; i < dim; i++)
{
for (j = 0; j < dim; j++)
{
if (i == j || i == 0) /* pierwszy wiersz macierzy i przekatna: (0, <=) */
{
DBM(p, dim, i, j) = DBM_E_0LE;
}
else /* pozostale: nieograniczone */
{
DBM(p, dim, i, j) = INF;
}
}
}
assert(dbm_is_sane(p, dim));
return p;
}
DBM_elem *
dbm_init_zero(DBM_idx dim)
{
DBM_elem *p;
DBM_idx i, j;
p = dbm_rawinit(dim);
for (i = 0; i < dim; i++)
{
for (j = 0; j < dim; j++)
{
DBM(p, dim, i, j) = DBM_E_0LE;
}
}
assert(dbm_is_sane(p, dim));
return p;
}
DBM_elem *
dbm_init_empty(DBM_idx dim)
{
DBM_elem *p;
p = dbm_init(dim);
DBM_MARK_EMPTY(p);
return p;
}
DBM_elem *
dbm_rawinit(DBM_idx dim)
{
return (DBM_elem *)smalloc((dim*dim)*sizeof(DBM_elem));
}
DBM_elem *
dbm_copy(DBM_elem *p, DBM_idx dim)
{
DBM_elem *r;
assert(p && dim);
r = dbm_rawinit(dim);
memcpy(r, p, sizeof(DBM_elem)*dim*dim);
return r;
}
void
dbm_print_elem(DBM_elem e)
{
if (e == INF)
printf("inf ");
else
{
printf("(%d,", e >> 1);
switch (e & 1)
{
case REL_LE: /* najmniej znaczacy bit - 1 */
printf("<=) ");
break;
case REL_LT: /* najmniej znaczacy bit - 0 */
printf(" <) ");
break;
}
}
return;
}
void
dbm_print(DBM_elem *p, DBM_idx dim)
{
DBM_idx i, j;
if (!p)
{
FERROR("dbm_print: p == NULL");
}
for (i = 0; i < dim; i++)
{
printf("[ ");
for (j = 0; j < dim; j++)
{
dbm_print_elem(DBM(p, dim, i, j));
}
printf("]\n");
}
return;
}
/*
* Wyswietlanie elementow w zhumanizowanej postaci ;)
*
* Pisane na kolanie, wiec mozna byloby to przemyslec...
*/
void
dbm_xprint_elem(DBM_elem *p, DBM_idx dim, DBM_idx i, DBM_idx j)
{
DBM_elem e;
e = DBM(p, dim, i, j);
if (j == 0) {
printf("[x%d%s%d]", i, (e==INF?"inf":((e&1)==REL_LE?"<=":"<")), e >> 1);
}
else
{
if (i == 0)
{
printf("[x%d%s%d]", j, (e==INF?"inf":((e&1)==REL_LE?">=":">")), -(e >> 1));
}
else
{
printf("[x%d-x%d%s%d]", i, j, (e==INF?"inf":((e&1)==REL_LE?"<=":"<")), e >> 1);
}
}
return;
}
/*
* Wyswietlanie kanonicznych DBM-ow
*/
void
dbm_xprint(DBM_elem *p, DBM_idx dim)
{
DBM_idx i, j;
bool f = false;
if (dbm_empty(p, dim))
printf("Empty");
for (i = 0; i < dim; i++)
{
for (j = 0; j < dim; j++)
{
if (i == j || i == 0)
{
if (DBM(p, dim, i, j) != DBM_E_0LE)
{
f = true;
dbm_xprint_elem(p, dim, i, j);
}
}
else
{
if (DBM(p, dim, i, j) != INF)
{
f = true;
dbm_xprint_elem(p, dim, i, j);
}
}
}
}
if (!f) printf("Default");
}
/* Ustawianie ograniczen */
void
dbm_constr_le(DBM_elem *p, DBM_idx dim, DBM_idx i, DBM_idx j, int val)
{
assert(i < dim && j < dim);
assert(i != j); /* nie wolno modyfikowac przekatnej */
DBM(p, dim, i, j) = DBM_VSC(DBM_ELEM(val, REL_LE));
return;
}
void
dbm_constr_lt(DBM_elem *p, DBM_idx dim, DBM_idx i, DBM_idx j, int val)
{
assert(i < dim && j < dim);
assert(i != j); /* nie wolno modyfikowac przekatnej */
DBM(p, dim, i, j) = DBM_VSC(DBM_ELEM(val, REL_LT));
return;
}
/* Uwalnianie ograniczenia */
void
dbm_rls_constr(DBM_elem *p, DBM_idx dim, DBM_idx i, DBM_idx j)
{
assert(i < dim && j < dim);
assert(i != j); /* nie wolno modyfikowac przekatnej */
DBM(p, dim, i, j) = INF;
assert(dbm_is_sane(p, dim));
return;
}
/*
* Sprowadzamy DBM do postaci kanonicznej (Floyd-Warshall)
*
* p = {0, 1, 2, ..., dim-1}
*
* for (k in p)
* for (i in p)
* for (j in p)
* if (a[i,j] > a[i,k] + a[k,j]) then
* a[i,j] = a[i,k] + a[k,j]
*
*/
void
dbm_canonicalize(DBM_elem *p, DBM_idx dim)
{
DBM_idx k, i, j;
DBM_elem *e, sum;
assert(p != NULL);
assert(dbm_valid_val(p, dim));
for (k = 0; k < dim; k++)
{
for (i = 0; i < dim; i++)
{
for (j = 0; j < dim; j++)
{
e = DBM_P(p, dim, i, j);
sum = DBM_SUM(DBM(p, dim, i, k), DBM(p, dim, k, j));
if (*e > sum)
{
*e = DBM_LVSC(sum);
}
if (i == j && *e < DBM_E_0LE)
{
/*
* Nie obliczamy do konca post. kanonicznej jesli pojawia element ujemny na przekatnej,
* bo i tak mozna to robic w nieskonczonosc. Wtedy natychmiast oznaczamy strefe jako
* pusta. Dzieki temu strefy ktorych DBM-y sprowadzalismy do post. kanonicznej szybko
* sprawdza sie pod katem pustosci.
*/
DBM_MARK_EMPTY(p);
return;
}
}
}
}
assert(dbm_valid_val(p, dim));
return;
}
/*
* Specjalizowany Floyd-Warshal Rokickiego do obliczania
* postaci kanonicznej DBM po wniesieniu jednej zmiany
* do kanonicznego DBM, ktora zaciesnia ograniczenie.
*
* a[x,y] - zmodyfikowany element
* p = {0, 1, 2, ..., dim-1}
*
* for (j in p)
* if (a[x,j] > a[x,y] + a[y,j]) then
* a[x,j] = a[x,y] + a[y,j]
* for (i in p)
* if (a[i,y] > a[i,x] + a[x,y]) then
* a[i,y] = a[i,x] + a[x,y]
* for (j in p)
* if (a[i,j] > a[i,y] + a[y,j]) then
* a[i,j] = a[i,y] + a[y,j]
*
* Odwolanie do pracy Rokickiego odnalezione w kodzie biblioteki DBM Uppaala.
* Stad tez pomysl dobierania sposobu kanonizacji. Metoda przekazywania
* zbioru indeksow elementow zmodyfikowanych jest silnie zainspirowana Uppaalem.
*
* Funkcja zwraca prawde jesli strefa nie jest pusta, w przeciwnym wypadku falsz.
*/
bool
dbm_canon1(DBM_elem *p, DBM_idx dim, DBM_idx x, DBM_idx y)
{
DBM_idx i, j;
DBM_elem *e, sum;
assert(p != NULL);
assert(dbm_valid_val(p, dim));
for (j = 0; j < dim; j++)
{
e = DBM_P(p, dim, x, j);
sum = DBM_SUM(DBM(p, dim, x, y), DBM(p, dim, y, j));
if (*e > sum)
{
*e = DBM_LVSC(sum);
}
}
if (DBM(p, dim, x, x) < DBM_E_0LE) /* strefa pusta? */
{
DBM_MARK_EMPTY(p);
return false;
}
for (i = 0; i < dim; i++)
{
e = DBM_P(p, dim, i, y);
sum = DBM_SUM(DBM(p,dim, i, x), DBM(p, dim, x, y));
if (*e > sum)
{
*e = DBM_LVSC(sum);
for (j = 0; j < dim; j++)
{
e = DBM_P(p, dim, i, j);
sum = DBM_SUM(DBM(p,dim, i, y), DBM(p, dim, y, j));
if (*e > sum) {
*e = DBM_LVSC(sum);
}
}
}
if (DBM(p, dim, i, i) < DBM_E_0LE) /* strefa pusta? */
{
DBM_MARK_EMPTY(p);
return false;
}
}
assert(dbm_valid_val(p, dim));
assert(dbm_is_canonical(p, dim));
return true;
}
/*
* Specjalizowany Floyd-Warshall do obliczania postaci
* kanonicznej po wniesieniu kliku zmian do kanonicznego DBM,
* ktore zaciesniaja ograniczenia.
*
* p = {0, 1, 2, ..., dim-1}
* f - zbior indeksow elementow zmodyfikowanych
*
* for (k in f)
* for (i in p)
* for (j in p)
* if (a[i,j] > a[i,k] + a[k,j]) then
* a[i,j] = a[i,k] + a[k,j]
*
*/
void
dbm_scanon(DBM_elem *p, DBM_idx dim, DBM_idx_flags *f)
{
DBM_idx i, j, k;
DBM_elem *e, sum;
assert(p != NULL);
assert(dbm_valid_val(p, dim));
for (k = 0; k < dim; k++)
{
if (IS_FLAGGED(f, k))
{
for (i = 0; i < dim; i++)
{
for (j = 0; j < dim; j++)
{
e = DBM_P(p, dim, i, j);
sum = DBM_SUM(DBM(p, dim, i, k), DBM(p, dim, k, j));
if (*e > sum)
{
*e = DBM_LVSC(sum);
}
if (i == j && *e < DBM_E_0LE) /* strefa pusta? */
{
DBM_MARK_EMPTY(p);
return;
}
}
}
}
}
assert(dbm_valid_val(p, dim));
assert(dbm_is_canonical(p, dim));
return;
}
bool
dbm_is_canonical(DBM_elem *p, DBM_idx dim)
{
DBM_idx k, i, j;
DBM_elem *e;
assert(p != NULL);
/*
* Jesli strefa ma element ujemny na przekatnej, to uznajemy, ze mamy postac kanoniczna.
* W przeciwnym wypadku nie bylibysmy w stanie tego stwierdzic badajac czy algorytm
* obliczajacy postac kanoniczna nanosi jakies zmiany, poniewaz nanosilby je do
* nieskonczonosci (teoretycznie).
*/
for (i = 0; i < dim; i++)
{
if (DBM(p, dim, i, i) < DBM_E_0LE)
return true;
}
for (k = 0; k < dim; k++)
{
for (i = 0; i < dim; i++)
{
for (j = 0; j < dim; j++)
{
e = DBM_P(p, dim, i, j);
/* sprawdzamy czy algorytm wprowadzilby jakas zmiane w DBM */
if (*e > DBM_SUM(DBM(p, dim, i, k), DBM(p, dim, k, j)))
return false;
}
}
}
return true;
}
/*
* Porownywanie stref w postaciach kanonicznych
*/
bool
dbm_equal(DBM_elem *p, DBM_elem *q, DBM_idx dim)
{
assert(dbm_is_canonical(p, dim));
assert(dbm_is_canonical(q, dim));
if (dbm_empty(p, dim) && dbm_empty(q, dim))
return true; /* obie strefy puste */
/* Jesli chcemy pominac sprawdzenia dbm_empty, to trzeba byloby
* zmienic zalozenie o PK (komentarz w dbm_empty).
*/
if (memcmp(p, q, sizeof(DBM_elem)*dim*dim) == 0)
return true;
else
return false;
}
/*
* Sprawdzanie pustosci DBM w postaci kanonicznej
*/
bool
dbm_empty(DBM_elem *p, DBM_idx dim)
{
int i;
assert(p != NULL);
assert(dbm_is_canonical(p, dim));
if (*p < DBM_E_0LE) return true;
/*
* Jesli dalej nie chcemy sprawdzac calej przekatnej, musielibysmy
* zmienic zalozenie dot. postaci kanonicznej. DBM bylby w postaci
* kanonicznej wtw gdy jesli strefa jest pusta, to DBM(0,0) < DBM_E_0LE
* (czyli jesli gdzies na przekatnej jest element < DBM_E_0LE, to
* wtedy rowniez DBM(0,0) < DBM_E_0LE).
*/
for (i = 1; i < dim; i++)
{
if (DBM(p, dim, i, i) < DBM_E_0LE)
{
DBM_MARK_EMPTY(p); /* oznaczamy strefe aby kolejne sprawdzenia byly szybsze */
return true;
}
}
return false;
}
/*
* Obliczanie przeciecia dwoch stref
*/
DBM_elem *
dbm_intersection(DBM_elem *p, DBM_elem *q, DBM_idx dim)
{
DBM_elem *r, *e;
DBM_idx i, j;
assert(p != NULL && q != NULL);
r = dbm_rawinit(dim);
for (i = 0; i < dim; i++)
{
for (j = 0; j < dim; j++)
{
e = DBM_P(r, dim, i, j);
*e = DBM_MIN(DBM(p, dim, i, j), DBM(q, dim, i, j));
if (i == j && *e < DBM_E_0LE)
{
/*
* Jesli gdzies na przekatnej pojawi sie liczba ujemna,
* wtedy strefe oznaczamy jako pusta i nic wiecej z nia
* nie robimy, bo i tak pozostanie pusta.
*/
DBM_MARK_EMPTY(r);
return r;
}
}
}
dbm_canonicalize(r, dim);
return r;
}
/*
* Obliczanie liczby elementow tablicy mieszczacej bity odpowiadajace zegarom
*/
DBM_idx_flags *
get_flags_array(DBM_idx dim)
{
return (DBM_idx_flags *)smalloc_zero(sizeof(DBM_idx_flags) * GET_ASIZE(dim));
}
/*
* Obliczanie przeciecia dwoch stref (w miejscu, modyfikuje p)
*
* p - DBM w postaci kanonicznej (z tym zalozeniem jest szybciej,
* a w praktyce nie jest ono trudne do spelnienia)
*/
void
dbm_intersection_cf_ip(DBM_elem *p, DBM_elem *q, DBM_idx dim)
{
DBM_elem *e_p, *e_q;
DBM_idx i, j;
DBM_idx_flags *flags;
DBM_idx chg_i = 0, chg_j = 0;
unsigned int chg_cnt = 0;
assert(p != NULL && q != NULL);
assert(dbm_valid_val(p, dim));
assert(dbm_valid_val(q, dim));
assert(dbm_is_canonical(p, dim));
e_p = p;
e_q = q;
/* tablica do flagowania zmodyfikowanych indeksow */
flags = get_flags_array(dim);
for (i = 0; i < dim; i++)
{
for (j = 0; j < dim; j++)
{
assert(e_p == DBM_P(p, dim, i, j)); /* czy na pewno biezacy element odpowiada temu, czego sie spodziewamy */
assert(e_q == DBM_P(q, dim, i, j));
if (*e_p > *e_q)
{
*e_p = *e_q;
SET_FLAG(flags, i); /* flagujemy indeksy modyfikacji */
SET_FLAG(flags, j);
/* jesli jest szansa, ze bedzie to jedyna modyfikacja, to zapisujemy co zmodyfikowano */
if (chg_cnt < 1)
{
chg_i = i;
chg_j = j;
}
chg_cnt++; /* zwiekszamy licznik modyfikacji */
}
if (i == j && *e_p < DBM_E_0LE)
{
free(flags);
DBM_MARK_EMPTY(p);
return;
}
e_p++; /* przechodzimy do kolejnych elementow */
e_q++;
}
}
if (chg_cnt == 1)
{
dbm_canon1(p, dim, chg_i, chg_j);
}
else if (chg_cnt > 1)
{
dbm_scanon(p, dim, flags);
}
free(flags); /* tablica flag juz jest zbedna */
assert(dbm_is_canonical(p, dim));
return;
}
/*
* Obliczanie przeciecia dwoch stref, wejsciowy DBM p w postaci kanonicznej.
*
* W niektorych zastosowaniach jest to szybka metoda. Wystarczyloby udowodnic,
* ze zachowywanie postaci kanonicznej po kazdej najmniejszej zmianie w niczym
* nie przeszkadza.
*
* W praktyce weryfikacji niekoniecznie ma sens ;)
*
* (prototypowo)
*/
void
dbm_intersection_cfX_ip(DBM_elem *p, DBM_elem *q, DBM_idx dim)
{
DBM_elem *e_p, *e_q;
DBM_idx i, j;
assert(dbm_valid_val(p, dim));
assert(dbm_valid_val(q, dim));
assert(dbm_is_canonical(p, dim));
e_p = p;
e_q = q;
for (i = 0; i < dim; i++) {
for (j = 0; j < dim; j++) {
assert(e_p == DBM_P(p, dim, i, j)); /* czy na pewno biezacy element odpowiada temu, czego sie spodziewamy */
assert(e_q == DBM_P(q, dim, i, j));
if (*e_p > *e_q) {
*e_p = *e_q;
if(!dbm_canon1(p, dim, i, j)) {
return; /* dbm_canon1 oznaczyl strefe jako pusta */
}
}
/* Moze nie jest to oplacalne jednak?
* Jesli mamy p w PK i jesli nie jest oznaczona jako pusta to daje nam to tyle, ze
* zostanie oznaczona, ale wczesniej moze to zrobic tez dbm_canon1.
*/
if (i == j && *e_p < 0) {
*p = DBM_E_NEG;
return;
}
e_p++; /* przechodzimy do kolejnych elementow */
e_q++;
}
}
assert(dbm_is_canonical(p, dim));
return;
}
/*
* Obliczanie przeciecia dwoch stref
*
* p - DBM w postaci kanonicznej (pozostaje nienaruszony)
*/
DBM_elem *
dbm_intersection_cf(DBM_elem *p, DBM_elem *q, DBM_idx dim)
{
DBM_elem *x;
assert(p != NULL && q != NULL);
x = dbm_copy(p, dim);
dbm_intersection_cf_ip(x, q, dim);
return x;
}
/*
* Z[x:=0]
* Resetowanie zegara z zachowaniem postaci kanonicznej
*
* c - resetowany zegar
*/
void
dbm_reset(DBM_elem *p, DBM_idx dim, DBM_idx c)
{
DBM_idx i;
assert(p != NULL);
assert(dbm_is_canonical(p, dim));
for (i = 0; i < dim; i++)
{
if (i != c) /* pomijamy DBM(i,i) */
{
DBM(p, dim, c, i) = DBM(p, dim, 0, i);
DBM(p, dim, i, c) = DBM(p, dim, i, 0);
}
}
assert(dbm_is_canonical(p, dim));
return;
}
/*
* [x:=0]Z
*
* c - resetowany zegar
*/
void
dbm_invreset(DBM_elem *p, DBM_idx dim, DBM_idx c)
{
DBM_idx i;
#ifndef NDEBUG
DBM_elem *p_orig;
#endif
assert(p != NULL);
assert(dbm_is_canonical(p, dim));
#ifndef NDEBUG
p_orig = dbm_copy(p, dim);
#endif
if (DBM(p, dim, 0, c) == DBM_E_0LE)
{
/*
* Pomijamy: DBM(p, dim, c, 0) = DBM_E_0LE;
* bo zawiera sie to w nastepnym kroku.
*
* Zamiast obliczania postaci kanonicznej,
* poprawiamy tylko to co trzeba:
*/
for (i = 1; i < dim; i++)
DBM(p, dim, i, 0) = DBM(p, dim, i, c);
for (i = 0; i < dim; i++)
if (i != c) DBM(p, dim, c, i) = INF;
dbm_canonicalize(p, dim);
}
else /* wynikiem operacji jest pusta strefa */
{
DBM_MARK_EMPTY(p);
}
assert(dbm_is_canonical(p, dim));
#ifndef NDEBUG
assert(dbm_check_invreset(p_orig, p, dim, c));
dbm_destroy(p_orig);
#endif
return;
}
/*
* Sprawdzanie poprawnosci obliczania [x:=0]Z wzgledem pierwotnego algorytmu z AinV
*
* p - nienaruszony DBM (do obliczenia)
* q - wynikowy DBM do porownania
*/
bool
dbm_check_invreset(DBM_elem *p, DBM_elem *q, DBM_idx dim, DBM_idx c)
{
DBM_idx i;
assert(p != NULL && q != NULL);
if (DBM(p, dim, 0, c) == DBM_E_0LE)
{
DBM(p, dim, c, 0) = DBM_E_0LE;
dbm_canonicalize(p, dim);
for (i = 0; i < dim; i++)
{
if (i != c) DBM(p, dim, c, i) = INF;
}
dbm_canonicalize(p, dim);
}
else
{
DBM_MARK_EMPTY(p);
}
if (dbm_equal(p, q, dim))
{
return true;
}
printf("Inconsistency detected!\nExpected result:\n");
dbm_print(p, dim);
printf("\nIncorrect result:\n");
dbm_print(q, dim);
return false;
}
/*
* Obliczanie nastepnika czasowego (zachowuje postac kanoniczna)
*/
void
dbm_time_successor(DBM_elem *p, DBM_idx dim)
{
int i;
assert(p != NULL);
assert(dbm_is_canonical(p, dim));
for (i = 1; i < dim; i++)
{
DBM(p, dim, i, 0) = INF;
}
assert(dbm_is_canonical(p, dim));
return;
}
/*
* Obliczanie poprzednika czasowego (zachowuje postac kanoniczna)
*/
void
dbm_time_predecessor(DBM_elem *p, DBM_idx dim)
{
int i, j;
DBM_elem *e1, *e2;
assert(p != NULL);
assert(dbm_is_canonical(p, dim));
for (j = 1; j < dim; j++)
{
e1 = DBM_P(p, dim, 0, j);
*e1 = DBM_E_0LE; /* DBM(0,j) := (0, <=) */
for (i = 1; i < dim; i++)
{
e2 = DBM_P(p, dim, i, j);
if (*e2 < *e1) /* DBM(i,j) < DBM(0,j) */
{
*e1 = *e2;
}
}
}
assert(dbm_is_canonical(p, dim));
return;
}
/*
* Obliczanie poprzednika czasowego (nie zachowuje postaci kanonicznej)
*/
void
dbm_time_predecessor_nc(DBM_elem *p, DBM_idx dim)
{
int j;
assert(p != NULL);
assert(dbm_is_canonical(p, dim)); /* wejsciowy DBM musi byc w PK */
for (j = 1; j < dim; j++)
{
DBM(p, dim, 0, j) = DBM_E_0LE; /* DBM(0,j) := (0, <=) */
}
return;
}
/*
* Makro do rozluzniania ograniczen (zamiana < na <=)
*
* Dzialamy tylko jezeli DBM(i,j) != inf oraz DBM(i,j) z ograniczeniem <.
* Mimo ze obecnosc tego warunku nie jest konieczna, jest on oplacalny.
*/
#define DBM_RELAX_REL(i, j) \
{ \
DBM_elem *e; \
e = DBM_P(p, dim, i, j); \
if (*e != INF && (*e & 1) == REL_LT) *e |= 1; \
}
/*
* Domkniecie strefy (nie mylic z postacia kanoniczna)
*/
void
dbm_closure(DBM_elem *p, DBM_idx dim)
{
DBM_idx i, j;
assert(p != NULL);
assert(dbm_is_canonical(p, dim));
for (i = 0; i < dim; i++)
{
for (j = 0; j < dim; j++)
{
DBM_RELAX_REL(i, j);
}
}
assert(dbm_is_canonical(p, dim));
return;
}
void
dbm_fill(DBM_elem *p, DBM_idx dim)
{
DBM_idx i;
assert(p != NULL);
assert(dbm_is_canonical(p, dim));
/* zaczynamy od 1, bo DBM(0,0) nie potrzeba poprawiac */
for (i = 1; i < dim; i++)
{
DBM_RELAX_REL(i, 0);
DBM_RELAX_REL(0, i);
}
assert(dbm_is_canonical(p, dim));
return;
}
/* wynik w PK */
DBM_elem *
dbm_border(DBM_elem *p, DBM_elem *q, DBM_idx dim)
{
DBM_elem *r;
assert(p != NULL && q != NULL);
assert(dbm_is_canonical(p, dim));
assert(dbm_is_canonical(q, dim));
r = dbm_intersection(p, q, dim);
if (!dbm_empty(r, dim))
{
/* strefy nie sa rozlaczne; wynik: domkniecie przeciecia */
/* dbm_closure(r, dim); */ /* DO SPRAWDZENIA: hm, w rzeczywistosci to wcale nie closure? */
return r;
}
else
{
DBM_idx i, j;
DBM_elem pe, qe;
dbm_destroy(r); /* nie potrzebujemy juz przeciecia stref */
for (i = 1; i < dim; i++)
{
/* (1) szukamy: DBMp(i,0) = (c, <) i DBMq(0,i) = (-c, <=) */
pe = DBM(p, dim, i, 0);
qe = DBM(q, dim, 0, i);
if (DBM_V(pe) == -DBM_V(qe) && DBM_R(pe) == REL_LT && DBM_R(qe) == REL_LE)
{
for (j = 1; j < dim; j++)
{
/* (2) szukamy: DBMp(j,0) = (c, <=) i DBMq(0,j) = (-c, <), j != i*/
pe = DBM(p, dim, j, 0);
qe = DBM(q, dim, 0, j);
if (j != i && DBM_V(pe) == -DBM_V(qe) && DBM_R(pe) == REL_LE && DBM_R(qe) == REL_LT)
{
/* wynik: pusta strefa */
r = dbm_init(dim);
DBM_MARK_EMPTY(r);
return r;
}
} /* nie znalezlismy (2) */
/* wynik: Fill(Z) n Z' */
dbm_fill(p, dim);
r = dbm_intersection(p, q, dim);
return r;
}
} /* nie znalezlismy (1) */
for (i = 1; i < dim; i++)
{
/* (3) szukamy: DBMp(i,0) = (c, <=) i DBMq(0,i) = (-c, <) */
pe = DBM(p, dim, i, 0);
qe = DBM(q, dim, 0, i);
if (DBM_V(pe) == -DBM_V(qe) && DBM_R(pe) == REL_LE && DBM_R(qe) == REL_LT)
{
/* wynik: Z n Fill(Z') */
dbm_fill(q, dim);
r = dbm_intersection(p, q, dim);
return r;
}
} /* nie znalezlismy (3) */
/* wynik: pusta strefa */
r = dbm_init(dim);
DBM_MARK_EMPTY(r);
return r;
}
}
/* Natychmiastowy poprzednik czasowy (w PK) */
DBM_elem *
dbm_imm_time_predecessor(DBM_elem *p, DBM_elem *q, DBM_idx dim)
{
DBM_elem *r, *t;
assert(p != NULL && q != NULL);
assert(dbm_is_canonical(p, dim));
assert(dbm_is_canonical(q, dim));
t = dbm_border(p, q, dim);
dbm_time_predecessor_nc(t, dim);
r = dbm_intersection(p, t, dim);
return r;
}
/*
* Dodawanie kolejnych DBM-ow do zbioru
*/
void
dbmset_add(DBMset_elem **root, DBMset_elem **last, DBM_elem *dbm)
{
DBMset_elem *new;
new = (DBMset_elem *)smalloc(sizeof(DBMset_elem));
new->dbm = dbm;
new->next = NULL;
if (*root == NULL)
*root = new;
else
(*last)->next = new;
*last = new;
return;
}
/*
* Odalokowywanie zbioru DBM-ow (lacznie z elementami zbioru)
*/
void
dbmset_destroy(DBMset_elem *root)
{
DBMset_elem *cur, *tmp;
cur = root;
while (cur != NULL)
{
assert(cur->dbm != NULL);
free(cur->dbm);
tmp = cur;
cur = cur->next;
free(tmp);
}
return;
}
/*
* Odalokowywanie samej struktury zbioru DBM-ow
*/
void
dbmset_scaffoldDestroy(DBMset_elem *root)
{
DBMset_elem *cur, *tmp;
cur = root;
while (cur != NULL)
{
tmp = cur;
cur = cur->next;
free(tmp);
}
return;
}
/*
* Wyswietlanie DBM-ow nalezacych do zbioru
*/
void
dbmset_print(DBMset_elem *root, DBM_idx dim)
{
DBMset_elem *cur;
unsigned int i = 1;
cur = root;
while (cur != NULL)
{
printf("DBM %d:\n", i++);
dbm_print(cur->dbm, dim);
cur = cur->next;
}
return;
}
/*
* Obliczanie roznicy stref
*/
DBMset_elem *
dbm_diff(DBM_elem *p_orig, DBM_elem *q, DBM_idx dim)
{
DBM_idx i, j;
DBMset_elem *r = NULL, *last = NULL; /* zbior stref */
bool done = false, p_used = false;
DBM_elem *p, *q_c, *t, *z, w;
assert(p_orig != NULL && q != NULL);
assert(dbm_is_canonical(p_orig, dim));
assert(dbm_is_canonical(q, dim));
p = dbm_copy(p_orig, dim); /* p bedziemy modyfikowac */
q_c = dbm_copy(q, dim);
dbm_closure(q_c, dim);
for (i = 0; i < dim && !done; i++)
{
for (j = 0; j < dim && !done; j++)
{
/* dodatkowe sprawdzanie != INF (dodane na szybko dla pewnosci, TODO: upewnic sie czy potrzebne) */
if (i != j && DBM(q, dim, i, j) != INF)
{
/* sprawdzamy przeciecie obu stref */
t = dbm_intersection_cf(p, q, dim); /* t jest w PK */
if (dbm_empty(t, dim))
{ /* aktualne Z i Z' sa rozlaczne */
dbm_destroy(t);
assert(dbm_is_canonical(p, dim));
if (!dbm_empty(p, dim)) /* nie dodajemy pustych DBM-ow */
{
dbmset_add(&r, &last, p);
p_used = true; /* p zostalo wykorzystane */
assert(r != NULL);
}
/* nie trzeba zwalniac, bo !p_used (zwolni sie dalej) */
done = true;
}
else if (dbm_equal(t, p, dim)) /* Z n Z' jest rowne aktualnemu Z */
{
dbm_destroy(t);
done = true;
}
else
{
dbm_destroy(t);
t = dbm_copy(q_c, dim);
w = DBM_V(DBM(q, dim, i, j));
DBM(t, dim, i, j) = DBM_ELEM(w, REL_LE);
DBM(t, dim, j, i) = DBM_ELEM(-w, REL_LE);
z = dbm_intersection_cf(p, t, dim); /* z jest w PK */
dbm_destroy(t);
if (!dbm_empty(z, dim))
{
t = dbm_copy(p, dim);
w = DBM(q, dim, i, j);
DBM(t, dim, j, i) = DBM_ELEM(-DBM_V(w), DBM_INV_R(w));
dbm_canonicalize(t, dim); /* przed dodaniem obliczamy PK, TODO: zastanowic sie czy
* nie mozna zoptymalizowac (to jest poprawka na szybko)
*/
if (!dbm_empty(t, dim)) /* nie dodajemy pustych DBM-ow */
{
dbmset_add(&r, &last, t); /* potem nie zwalniamy t, bo juz zostalo "oddane" (inaczej bysmy je utracili) */
assert(r != NULL);
}
else
{
dbm_destroy(t);
}
assert(w <= DBM(p, dim, i, j)); /* zawezanie ograniczenia */
DBM(p, dim, i, j) = w;
dbm_canon1(p, dim, i, j); /* postac kanoniczna p potrzebna jest na wejsciu dbm_equal() */
}
dbm_destroy(z);
}
}
}
}
dbm_destroy(q_c);
if (!p_used) dbm_destroy(p); /* zwalniamy p tylko jesli nie jest uzywane: TODO moze lepiej operowac na 'if (p != NULL)'? */
return r;
}
/*
* Sprawdzanie czy wartosci elementow zawieraja sie w dopuszczalnym przedziale.
*/
bool
dbm_valid_val(DBM_elem *p, DBM_idx dim)
{
assert(p != NULL);
while (dim-- != 0)
{
if ((*p < DBM_RAW_MIN || *p > DBM_RAW_MAX) && *p != INF)
{
return false;
}
p++;
}
return true;
}
/*
* Sprawdzanie czy DBM jest "zdrowy".
*/
bool
dbm_is_sane(DBM_elem *p, DBM_idx dim)
{
DBM_idx i;
assert(p != NULL);
for (i = 0; i < dim; i++)
{
/* Element > (0, <=) w pierwszym wierszu macierzy */
if (DBM(p, dim, 0, i) > DBM_E_0LE)
{
printf("Negative clock valuation allowed!\n");
return false;
}
/* czy (0, <=) na calej przekatnej */
if (DBM(p, dim, i, i) != DBM_E_0LE)
{
printf("Invalid element on a diagonal!\n");
return false;
}
}
if (dbm_valid_val(p, dim))
{
return true;
}
else
{
printf("Not allowed value found (dbm_valid_val check failed)!\n");
return false;
}
return true;
}