703 lines
21 KiB
C
703 lines
21 KiB
C
/***** ltl2ba : buchi.c *****/
|
|
|
|
/* Written by Denis Oddoux, LIAFA, France */
|
|
/* Copyright (c) 2001 Denis Oddoux */
|
|
/* Modified by Paul Gastin, LSV, France */
|
|
/* Copyright (c) 2007 Paul Gastin */
|
|
/* */
|
|
/* This program is free software; you can redistribute it and/or modify */
|
|
/* it under the terms of the GNU General Public License as published by */
|
|
/* the Free Software Foundation; either version 2 of the License, or */
|
|
/* (at your option) any later version. */
|
|
/* */
|
|
/* This program is distributed in the hope that it will be useful, */
|
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
|
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
|
|
/* GNU General Public License for more details. */
|
|
/* */
|
|
/* You should have received a copy of the GNU General Public License */
|
|
/* along with this program; if not, write to the Free Software */
|
|
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/
|
|
/* */
|
|
/* Based on the translation algorithm by Gastin and Oddoux, */
|
|
/* presented at the 13th International Conference on Computer Aided */
|
|
/* Verification, CAV 2001, Paris, France. */
|
|
/* Proceedings - LNCS 2102, pp. 53-65 */
|
|
/* */
|
|
/* Send bug-reports and/or questions to Paul Gastin */
|
|
/* http://www.lsv.ens-cachan.fr/~gastin */
|
|
|
|
#include "ltl2ba.h"
|
|
|
|
/********************************************************************\
|
|
|* Structures and shared variables *|
|
|
\********************************************************************/
|
|
|
|
extern GState **init, *gstates;
|
|
extern struct rusage tr_debut, tr_fin;
|
|
extern struct timeval t_diff;
|
|
extern int tl_verbose, tl_stats, tl_simp_diff, tl_simp_fly, tl_simp_scc,
|
|
init_size, *final;
|
|
extern void put_uform(void);
|
|
|
|
extern FILE *tl_out;
|
|
BState *bstack, *bstates, *bremoved;
|
|
BScc *scc_stack;
|
|
int bstate_count = 0, btrans_count = 0, rank;
|
|
|
|
static int _accept;
|
|
|
|
/********************************************************************\
|
|
|* Simplification of the generalized Buchi automaton *|
|
|
\********************************************************************/
|
|
|
|
void free_bstate(BState *s) /* frees a state and its transitions */
|
|
{
|
|
free_btrans(s->trans->nxt, s->trans, 1);
|
|
tfree(s);
|
|
}
|
|
|
|
BState *remove_bstate(BState *s, BState *s1) /* removes a state */
|
|
{
|
|
BState *prv = s->prv;
|
|
s->prv->nxt = s->nxt;
|
|
s->nxt->prv = s->prv;
|
|
free_btrans(s->trans->nxt, s->trans, 0);
|
|
s->trans = (BTrans *)0;
|
|
s->nxt = bremoved->nxt;
|
|
bremoved->nxt = s;
|
|
s->prv = s1;
|
|
for(s1 = bremoved->nxt; s1 != bremoved; s1 = s1->nxt)
|
|
if(s1->prv == s)
|
|
s1->prv = s->prv;
|
|
return prv;
|
|
}
|
|
|
|
void copy_btrans(BTrans *from, BTrans *to) {
|
|
to->to = from->to;
|
|
copy_set(from->pos, to->pos, 1);
|
|
copy_set(from->neg, to->neg, 1);
|
|
}
|
|
|
|
int simplify_btrans() /* simplifies the transitions */
|
|
{
|
|
BState *s;
|
|
BTrans *t, *t1;
|
|
int changed = 0;
|
|
|
|
if(tl_stats) getrusage(RUSAGE_SELF, &tr_debut);
|
|
|
|
for (s = bstates->nxt; s != bstates; s = s->nxt)
|
|
for (t = s->trans->nxt; t != s->trans;) {
|
|
t1 = s->trans->nxt;
|
|
copy_btrans(t, s->trans);
|
|
while((t == t1) || (t->to != t1->to) ||
|
|
!included_set(t1->pos, t->pos, 1) ||
|
|
!included_set(t1->neg, t->neg, 1))
|
|
t1 = t1->nxt;
|
|
if(t1 != s->trans) {
|
|
BTrans *free = t->nxt;
|
|
t->to = free->to;
|
|
copy_set(free->pos, t->pos, 1);
|
|
copy_set(free->neg, t->neg, 1);
|
|
t->nxt = free->nxt;
|
|
if(free == s->trans) s->trans = t;
|
|
free_btrans(free, 0, 0);
|
|
changed++;
|
|
}
|
|
else
|
|
t = t->nxt;
|
|
}
|
|
|
|
if(tl_stats) {
|
|
getrusage(RUSAGE_SELF, &tr_fin);
|
|
timeval_subtract (&t_diff, &tr_fin.ru_utime, &tr_debut.ru_utime);
|
|
fprintf(tl_out, "\nSimplification of the Buchi automaton - transitions: %lli.%06ld",
|
|
(long long int)t_diff.tv_sec, t_diff.tv_usec);
|
|
fprintf(tl_out, "\n%i transitions removed\n", changed);
|
|
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
int same_btrans(BTrans *s, BTrans *t) /* returns 1 if the transitions are identical */
|
|
{
|
|
return((s->to == t->to) &&
|
|
same_sets(s->pos, t->pos, 1) &&
|
|
same_sets(s->neg, t->neg, 1));
|
|
}
|
|
|
|
void remove_btrans(BState *to)
|
|
{ /* redirects transitions before removing a state from the automaton */
|
|
BState *s;
|
|
BTrans *t;
|
|
for (s = bstates->nxt; s != bstates; s = s->nxt)
|
|
for (t = s->trans->nxt; t != s->trans; t = t->nxt)
|
|
if (t->to == to) { /* transition to a state with no transitions */
|
|
BTrans *free = t->nxt;
|
|
t->to = free->to;
|
|
copy_set(free->pos, t->pos, 1);
|
|
copy_set(free->neg, t->neg, 1);
|
|
t->nxt = free->nxt;
|
|
if(free == s->trans) s->trans = t;
|
|
free_btrans(free, 0, 0);
|
|
}
|
|
}
|
|
|
|
void retarget_all_btrans()
|
|
{ /* redirects transitions before removing a state from the automaton */
|
|
BState *s;
|
|
BTrans *t;
|
|
for (s = bstates->nxt; s != bstates; s = s->nxt)
|
|
for (t = s->trans->nxt; t != s->trans; t = t->nxt)
|
|
if (!t->to->trans) { /* t->to has been removed */
|
|
t->to = t->to->prv;
|
|
if(!t->to) { /* t->to has no transitions */
|
|
BTrans *free = t->nxt;
|
|
t->to = free->to;
|
|
copy_set(free->pos, t->pos, 1);
|
|
copy_set(free->neg, t->neg, 1);
|
|
t->nxt = free->nxt;
|
|
if(free == s->trans) s->trans = t;
|
|
free_btrans(free, 0, 0);
|
|
}
|
|
}
|
|
while(bremoved->nxt != bremoved) { /* clean the 'removed' list */
|
|
s = bremoved->nxt;
|
|
bremoved->nxt = bremoved->nxt->nxt;
|
|
tfree(s);
|
|
}
|
|
}
|
|
|
|
int all_btrans_match(BState *a, BState *b) /* decides if the states are equivalent */
|
|
{
|
|
BTrans *s, *t;
|
|
if (((a->final == _accept) || (b->final == _accept)) &&
|
|
(a->final + b->final != 2 * _accept) &&
|
|
a->incoming >=0 && b->incoming >=0)
|
|
return 0; /* the states have to be both final or both non final */
|
|
|
|
for (s = a->trans->nxt; s != a->trans; s = s->nxt) {
|
|
/* all transitions from a appear in b */
|
|
copy_btrans(s, b->trans);
|
|
t = b->trans->nxt;
|
|
while(!same_btrans(s, t))
|
|
t = t->nxt;
|
|
if(t == b->trans) return 0;
|
|
}
|
|
for (s = b->trans->nxt; s != b->trans; s = s->nxt) {
|
|
/* all transitions from b appear in a */
|
|
copy_btrans(s, a->trans);
|
|
t = a->trans->nxt;
|
|
while(!same_btrans(s, t))
|
|
t = t->nxt;
|
|
if(t == a->trans) return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int simplify_bstates() /* eliminates redundant states */
|
|
{
|
|
BState *s, *s1;
|
|
int changed = 0;
|
|
|
|
if(tl_stats) getrusage(RUSAGE_SELF, &tr_debut);
|
|
|
|
for (s = bstates->nxt; s != bstates; s = s->nxt) {
|
|
if(s->trans == s->trans->nxt) { /* s has no transitions */
|
|
s = remove_bstate(s, (BState *)0);
|
|
changed++;
|
|
continue;
|
|
}
|
|
bstates->trans = s->trans;
|
|
bstates->final = s->final;
|
|
s1 = s->nxt;
|
|
while(!all_btrans_match(s, s1))
|
|
s1 = s1->nxt;
|
|
if(s1 != bstates) { /* s and s1 are equivalent */
|
|
if(s1->incoming == -1)
|
|
s1->final = s->final; /* get the good final condition */
|
|
s = remove_bstate(s, s1);
|
|
changed++;
|
|
}
|
|
}
|
|
retarget_all_btrans();
|
|
|
|
if(tl_stats) {
|
|
getrusage(RUSAGE_SELF, &tr_fin);
|
|
timeval_subtract (&t_diff, &tr_fin.ru_utime, &tr_debut.ru_utime);
|
|
fprintf(tl_out, "\nSimplification of the Buchi automaton - states: %lli.%06ld",
|
|
(long long int)t_diff.tv_sec, t_diff.tv_usec);
|
|
fprintf(tl_out, "\n%i states removed\n", changed);
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
int bdfs(BState *s) {
|
|
BTrans *t;
|
|
BScc *c;
|
|
BScc *scc = (BScc *)tl_emalloc(sizeof(BScc));
|
|
scc->bstate = s;
|
|
scc->rank = rank;
|
|
scc->theta = rank++;
|
|
scc->nxt = scc_stack;
|
|
scc_stack = scc;
|
|
|
|
s->incoming = 1;
|
|
|
|
for (t = s->trans->nxt; t != s->trans; t = t->nxt) {
|
|
if (t->to->incoming == 0) {
|
|
int result = bdfs(t->to);
|
|
scc->theta = min(scc->theta, result);
|
|
}
|
|
else {
|
|
for(c = scc_stack->nxt; c != 0; c = c->nxt)
|
|
if(c->bstate == t->to) {
|
|
scc->theta = min(scc->theta, c->rank);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if(scc->rank == scc->theta) {
|
|
if(scc_stack == scc) { /* s is alone in a scc */
|
|
s->incoming = -1;
|
|
for (t = s->trans->nxt; t != s->trans; t = t->nxt)
|
|
if (t->to == s)
|
|
s->incoming = 1;
|
|
}
|
|
scc_stack = scc->nxt;
|
|
}
|
|
return scc->theta;
|
|
}
|
|
|
|
void simplify_bscc() {
|
|
BState *s;
|
|
rank = 1;
|
|
scc_stack = 0;
|
|
|
|
if(bstates == bstates->nxt) return;
|
|
|
|
for(s = bstates->nxt; s != bstates; s = s->nxt)
|
|
s->incoming = 0; /* state color = white */
|
|
|
|
bdfs(bstates->prv);
|
|
|
|
for(s = bstates->nxt; s != bstates; s = s->nxt)
|
|
if(s->incoming == 0)
|
|
remove_bstate(s, 0);
|
|
}
|
|
|
|
|
|
|
|
|
|
/********************************************************************\
|
|
|* Generation of the Buchi automaton *|
|
|
\********************************************************************/
|
|
|
|
BState *find_bstate(GState **state, int final, BState *s)
|
|
{ /* finds the corresponding state, or creates it */
|
|
if((s->gstate == *state) && (s->final == final)) return s; /* same state */
|
|
|
|
s = bstack->nxt; /* in the stack */
|
|
bstack->gstate = *state;
|
|
bstack->final = final;
|
|
while(!(s->gstate == *state) || !(s->final == final))
|
|
s = s->nxt;
|
|
if(s != bstack) return s;
|
|
|
|
s = bstates->nxt; /* in the solved states */
|
|
bstates->gstate = *state;
|
|
bstates->final = final;
|
|
while(!(s->gstate == *state) || !(s->final == final))
|
|
s = s->nxt;
|
|
if(s != bstates) return s;
|
|
|
|
s = bremoved->nxt; /* in the removed states */
|
|
bremoved->gstate = *state;
|
|
bremoved->final = final;
|
|
while(!(s->gstate == *state) || !(s->final == final))
|
|
s = s->nxt;
|
|
if(s != bremoved) return s;
|
|
|
|
s = (BState *)tl_emalloc(sizeof(BState)); /* creates a new state */
|
|
s->gstate = *state;
|
|
s->id = (*state)->id;
|
|
s->incoming = 0;
|
|
s->final = final;
|
|
s->trans = emalloc_btrans(); /* sentinel */
|
|
s->trans->nxt = s->trans;
|
|
s->nxt = bstack->nxt;
|
|
bstack->nxt = s;
|
|
return s;
|
|
}
|
|
|
|
int next_final(int *set, int fin) /* computes the 'final' value */
|
|
{
|
|
if((fin != _accept) && in_set(set, final[fin + 1]))
|
|
return next_final(set, fin + 1);
|
|
return fin;
|
|
}
|
|
|
|
void make_btrans(BState *s) /* creates all the transitions from a state */
|
|
{
|
|
int state_trans = 0;
|
|
GTrans *t;
|
|
BTrans *t1;
|
|
BState *s1;
|
|
if(s->gstate->trans)
|
|
for(t = s->gstate->trans->nxt; t != s->gstate->trans; t = t->nxt) {
|
|
int fin = next_final(t->final, (s->final == _accept) ? 0 : s->final);
|
|
BState *to = find_bstate(&t->to, fin, s);
|
|
|
|
for(t1 = s->trans->nxt; t1 != s->trans;) {
|
|
if(tl_simp_fly &&
|
|
(to == t1->to) &&
|
|
included_set(t->pos, t1->pos, 1) &&
|
|
included_set(t->neg, t1->neg, 1)) { /* t1 is redondant */
|
|
BTrans *free = t1->nxt;
|
|
t1->to->incoming--;
|
|
t1->to = free->to;
|
|
copy_set(free->pos, t1->pos, 1);
|
|
copy_set(free->neg, t1->neg, 1);
|
|
t1->nxt = free->nxt;
|
|
if(free == s->trans) s->trans = t1;
|
|
free_btrans(free, 0, 0);
|
|
state_trans--;
|
|
}
|
|
else if(tl_simp_fly &&
|
|
(t1->to == to ) &&
|
|
included_set(t1->pos, t->pos, 1) &&
|
|
included_set(t1->neg, t->neg, 1)) /* t is redondant */
|
|
break;
|
|
else
|
|
t1 = t1->nxt;
|
|
}
|
|
if(t1 == s->trans) {
|
|
BTrans *trans = emalloc_btrans();
|
|
trans->to = to;
|
|
trans->to->incoming++;
|
|
copy_set(t->pos, trans->pos, 1);
|
|
copy_set(t->neg, trans->neg, 1);
|
|
trans->nxt = s->trans->nxt;
|
|
s->trans->nxt = trans;
|
|
state_trans++;
|
|
}
|
|
}
|
|
|
|
if(tl_simp_fly) {
|
|
if(s->trans == s->trans->nxt) { /* s has no transitions */
|
|
free_btrans(s->trans->nxt, s->trans, 1);
|
|
s->trans = (BTrans *)0;
|
|
s->prv = (BState *)0;
|
|
s->nxt = bremoved->nxt;
|
|
bremoved->nxt = s;
|
|
for(s1 = bremoved->nxt; s1 != bremoved; s1 = s1->nxt)
|
|
if(s1->prv == s)
|
|
s1->prv = (BState *)0;
|
|
return;
|
|
}
|
|
bstates->trans = s->trans;
|
|
bstates->final = s->final;
|
|
s1 = bstates->nxt;
|
|
while(!all_btrans_match(s, s1))
|
|
s1 = s1->nxt;
|
|
if(s1 != bstates) { /* s and s1 are equivalent */
|
|
free_btrans(s->trans->nxt, s->trans, 1);
|
|
s->trans = (BTrans *)0;
|
|
s->prv = s1;
|
|
s->nxt = bremoved->nxt;
|
|
bremoved->nxt = s;
|
|
for(s1 = bremoved->nxt; s1 != bremoved; s1 = s1->nxt)
|
|
if(s1->prv == s)
|
|
s1->prv = s->prv;
|
|
return;
|
|
}
|
|
}
|
|
s->nxt = bstates->nxt; /* adds the current state to 'bstates' */
|
|
s->prv = bstates;
|
|
s->nxt->prv = s;
|
|
bstates->nxt = s;
|
|
btrans_count += state_trans;
|
|
bstate_count++;
|
|
}
|
|
|
|
/********************************************************************\
|
|
|* Export of the Buchi automaton *|
|
|
\********************************************************************/
|
|
BState* buchi_bstates() { return bstates; }
|
|
int buchi_accept() { return _accept; }
|
|
|
|
/********************************************************************\
|
|
|* Display of the Buchi automaton *|
|
|
\********************************************************************/
|
|
|
|
void print_buchi(BState *s) /* dumps the Buchi automaton */
|
|
{
|
|
BTrans *t;
|
|
if(s == bstates) return;
|
|
|
|
print_buchi(s->nxt); /* begins with the last state */
|
|
|
|
fprintf(tl_out, "state ");
|
|
if(s->id == -1)
|
|
fprintf(tl_out, "init");
|
|
else {
|
|
if(s->final == _accept)
|
|
fprintf(tl_out, "accept");
|
|
else
|
|
fprintf(tl_out, "T%i", s->final);
|
|
fprintf(tl_out, "_%i", s->id);
|
|
}
|
|
fprintf(tl_out, "\n");
|
|
for(t = s->trans->nxt; t != s->trans; t = t->nxt) {
|
|
if (empty_set(t->pos, 1) && empty_set(t->neg, 1))
|
|
fprintf(tl_out, "1");
|
|
print_set(t->pos, 1);
|
|
if (!empty_set(t->pos, 1) && !empty_set(t->neg, 1)) fprintf(tl_out, " & ");
|
|
print_set(t->neg, 2);
|
|
fprintf(tl_out, " -> ");
|
|
if(t->to->id == -1)
|
|
fprintf(tl_out, "init\n");
|
|
else {
|
|
if(t->to->final == _accept)
|
|
fprintf(tl_out, "accept");
|
|
else
|
|
fprintf(tl_out, "T%i", t->to->final);
|
|
fprintf(tl_out, "_%i\n", t->to->id);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
print_dot_buchi_1(BState *s)
|
|
{
|
|
BTrans *t;
|
|
if(s == bstates) return;
|
|
|
|
print_dot_buchi_1(s->nxt); /* begins with the last state */
|
|
|
|
fprintf(tl_out, "%i[label=\"%i\"%s];\n", s->id, s->id,
|
|
s->final == _accept ? ",shape=doublecircle" : "");
|
|
|
|
for(t = s->trans->nxt; t != s->trans; t = t->nxt) {
|
|
fprintf(tl_out, "%d -> %d [label=\"", s->id, t->to->id);
|
|
|
|
/* print label */
|
|
BTrans *t1;
|
|
spin_print_set(t->pos, t->neg);
|
|
for(t1 = t; t1->nxt != s->trans; ) {
|
|
if (t1->nxt->to->id == t->to->id &&
|
|
t1->nxt->to->final == t->to->final) {
|
|
fprintf(tl_out, ") || (");
|
|
spin_print_set(t1->nxt->pos, t1->nxt->neg);
|
|
t1->nxt = t1->nxt->nxt;
|
|
} else {
|
|
t1 = t1->nxt;
|
|
}
|
|
}
|
|
fprintf(tl_out, "\"];\n");
|
|
}
|
|
}
|
|
|
|
void
|
|
print_dot_buchi()
|
|
{
|
|
fprintf(tl_out,
|
|
"digraph g {\n"
|
|
"rankdir=\"LR\";\n"
|
|
"node [shape=circle];\n"
|
|
"Init[shape=plaintext,label=\"\"];\n"
|
|
"Init -> %i;\n", -1);
|
|
print_dot_buchi_1(bstates->nxt);
|
|
fprintf(tl_out, "}\n");
|
|
}
|
|
|
|
void print_spin_buchi() {
|
|
BTrans *t;
|
|
BState *s;
|
|
int accept_all = 0;
|
|
if(bstates->nxt == bstates) { /* empty automaton */
|
|
fprintf(tl_out, "never { /* ");
|
|
put_uform();
|
|
fprintf(tl_out, " */\n");
|
|
fprintf(tl_out, "T0_init:\n");
|
|
fprintf(tl_out, "\tfalse;\n");
|
|
fprintf(tl_out, "}\n");
|
|
return;
|
|
}
|
|
if(bstates->nxt->nxt == bstates && bstates->nxt->id == 0) { /* true */
|
|
fprintf(tl_out, "never { /* ");
|
|
put_uform();
|
|
fprintf(tl_out, " */\n");
|
|
fprintf(tl_out, "accept_init:\n");
|
|
fprintf(tl_out, "\tif\n");
|
|
fprintf(tl_out, "\t:: (1) -> goto accept_init\n");
|
|
fprintf(tl_out, "\tfi;\n");
|
|
fprintf(tl_out, "}\n");
|
|
return;
|
|
}
|
|
|
|
fprintf(tl_out, "never { /* ");
|
|
put_uform();
|
|
fprintf(tl_out, " */\n");
|
|
for(s = bstates->prv; s != bstates; s = s->prv) {
|
|
if(s->id == 0) { /* accept_all at the end */
|
|
accept_all = 1;
|
|
continue;
|
|
}
|
|
if(s->final == _accept)
|
|
fprintf(tl_out, "accept_");
|
|
else fprintf(tl_out, "T%i_", s->final);
|
|
if(s->id == -1)
|
|
fprintf(tl_out, "init:\n");
|
|
else fprintf(tl_out, "S%i:\n", s->id);
|
|
if(s->trans->nxt == s->trans) {
|
|
fprintf(tl_out, "\tfalse;\n");
|
|
continue;
|
|
}
|
|
fprintf(tl_out, "\tif\n");
|
|
for(t = s->trans->nxt; t != s->trans; t = t->nxt) {
|
|
BTrans *t1;
|
|
fprintf(tl_out, "\t:: (");
|
|
spin_print_set(t->pos, t->neg);
|
|
for(t1 = t; t1->nxt != s->trans; )
|
|
if (t1->nxt->to->id == t->to->id &&
|
|
t1->nxt->to->final == t->to->final) {
|
|
fprintf(tl_out, ") || (");
|
|
spin_print_set(t1->nxt->pos, t1->nxt->neg);
|
|
t1->nxt = t1->nxt->nxt;
|
|
}
|
|
else t1 = t1->nxt;
|
|
fprintf(tl_out, ") -> goto ");
|
|
if(t->to->final == _accept)
|
|
fprintf(tl_out, "accept_");
|
|
else fprintf(tl_out, "T%i_", t->to->final);
|
|
if(t->to->id == 0)
|
|
fprintf(tl_out, "all\n");
|
|
else if(t->to->id == -1)
|
|
fprintf(tl_out, "init\n");
|
|
else fprintf(tl_out, "S%i\n", t->to->id);
|
|
}
|
|
fprintf(tl_out, "\tfi;\n");
|
|
}
|
|
if(accept_all) {
|
|
fprintf(tl_out, "accept_all:\n");
|
|
fprintf(tl_out, "\tskip\n");
|
|
}
|
|
fprintf(tl_out, "}\n");
|
|
}
|
|
|
|
/********************************************************************\
|
|
|* Main method *|
|
|
\********************************************************************/
|
|
|
|
void mk_buchi()
|
|
{/* generates a Buchi automaton from the generalized Buchi automaton */
|
|
int i;
|
|
BState *s = (BState *)tl_emalloc(sizeof(BState));
|
|
GTrans *t;
|
|
BTrans *t1;
|
|
_accept = final[0] - 1;
|
|
|
|
if(tl_stats) getrusage(RUSAGE_SELF, &tr_debut);
|
|
|
|
bstack = (BState *)tl_emalloc(sizeof(BState)); /* sentinel */
|
|
bstack->nxt = bstack;
|
|
bremoved = (BState *)tl_emalloc(sizeof(BState)); /* sentinel */
|
|
bremoved->nxt = bremoved;
|
|
bstates = (BState *)tl_emalloc(sizeof(BState)); /* sentinel */
|
|
bstates->nxt = s;
|
|
bstates->prv = s;
|
|
|
|
s->nxt = bstates; /* creates (unique) inital state */
|
|
s->prv = bstates;
|
|
s->id = -1;
|
|
s->incoming = 1;
|
|
s->final = 0;
|
|
s->gstate = 0;
|
|
s->trans = emalloc_btrans(); /* sentinel */
|
|
s->trans->nxt = s->trans;
|
|
for(i = 0; i < init_size; i++)
|
|
if(init[i])
|
|
for(t = init[i]->trans->nxt; t != init[i]->trans; t = t->nxt) {
|
|
int fin = next_final(t->final, 0);
|
|
BState *to = find_bstate(&t->to, fin, s);
|
|
for(t1 = s->trans->nxt; t1 != s->trans;) {
|
|
if(tl_simp_fly &&
|
|
(to == t1->to) &&
|
|
included_set(t->pos, t1->pos, 1) &&
|
|
included_set(t->neg, t1->neg, 1)) { /* t1 is redondant */
|
|
BTrans *free = t1->nxt;
|
|
t1->to->incoming--;
|
|
t1->to = free->to;
|
|
copy_set(free->pos, t1->pos, 1);
|
|
copy_set(free->neg, t1->neg, 1);
|
|
t1->nxt = free->nxt;
|
|
if(free == s->trans) s->trans = t1;
|
|
free_btrans(free, 0, 0);
|
|
}
|
|
else if(tl_simp_fly &&
|
|
(t1->to == to ) &&
|
|
included_set(t1->pos, t->pos, 1) &&
|
|
included_set(t1->neg, t->neg, 1)) /* t is redondant */
|
|
break;
|
|
else
|
|
t1 = t1->nxt;
|
|
}
|
|
if(t1 == s->trans) {
|
|
BTrans *trans = emalloc_btrans();
|
|
trans->to = to;
|
|
trans->to->incoming++;
|
|
copy_set(t->pos, trans->pos, 1);
|
|
copy_set(t->neg, trans->neg, 1);
|
|
trans->nxt = s->trans->nxt;
|
|
s->trans->nxt = trans;
|
|
}
|
|
}
|
|
|
|
while(bstack->nxt != bstack) { /* solves all states in the stack until it is empty */
|
|
s = bstack->nxt;
|
|
bstack->nxt = bstack->nxt->nxt;
|
|
if(!s->incoming) {
|
|
free_bstate(s);
|
|
continue;
|
|
}
|
|
make_btrans(s);
|
|
}
|
|
|
|
retarget_all_btrans();
|
|
|
|
if(tl_stats) {
|
|
getrusage(RUSAGE_SELF, &tr_fin);
|
|
timeval_subtract (&t_diff, &tr_fin.ru_utime, &tr_debut.ru_utime);
|
|
fprintf(tl_out, "\nBuilding the Buchi automaton : %lli.%06ld",
|
|
(long long int)t_diff.tv_sec, t_diff.tv_usec);
|
|
fprintf(tl_out, "\n%i states, %i transitions\n", bstate_count, btrans_count);
|
|
}
|
|
|
|
if(tl_verbose) {
|
|
fprintf(tl_out, "\nBuchi automaton before simplification\n");
|
|
print_buchi(bstates->nxt);
|
|
if(bstates == bstates->nxt)
|
|
fprintf(tl_out, "empty automaton, refuses all words\n");
|
|
}
|
|
|
|
if(tl_simp_diff) {
|
|
simplify_btrans();
|
|
if(tl_simp_scc) simplify_bscc();
|
|
while(simplify_bstates()) { /* simplifies as much as possible */
|
|
simplify_btrans();
|
|
if(tl_simp_scc) simplify_bscc();
|
|
}
|
|
|
|
if(tl_verbose) {
|
|
fprintf(tl_out, "\nBuchi automaton after simplification\n");
|
|
print_buchi(bstates->nxt);
|
|
if(bstates == bstates->nxt)
|
|
fprintf(tl_out, "empty automaton, refuses all words\n");
|
|
fprintf(tl_out, "\n");
|
|
}
|
|
}
|
|
}
|