You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
696 lines
18 KiB
696 lines
18 KiB
/* Written by Denis Oddoux, LIAFA, France *
|
|
* Copyright (c) 2001 Denis Oddoux *
|
|
* Modified by Paul Gastin, LSV, France *
|
|
* Copyright (c) 2007 Paul Gastin *
|
|
* Ported by Carlos Bederian, FaMAF, Argentina *
|
|
* Copyright (c) 2007 Carlos Bederian *
|
|
* *
|
|
* 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 *
|
|
* */
|
|
|
|
package jltl2ba;
|
|
|
|
import java.util.Vector;
|
|
import java.io.PrintStream;
|
|
|
|
|
|
public class Generalized {
|
|
|
|
public int init_size;
|
|
public Vector<GState> g_init;
|
|
public Vector<Integer> _final;
|
|
public GState gstates;
|
|
|
|
private GState gstack;
|
|
private GState gremoved;
|
|
private GScc scc_stack;
|
|
private int gstate_id;
|
|
private int gstate_count;
|
|
private int gtrans_count;
|
|
private int rank;
|
|
private int scc_id;
|
|
private MyBitSet fin;
|
|
private MyBitSet bad_scc;
|
|
|
|
public static class GScc {
|
|
public GState gstate;
|
|
public int rank;
|
|
public int theta;
|
|
public GScc nxt;
|
|
|
|
public GScc() {}
|
|
}
|
|
|
|
public static class GState {
|
|
public int id;
|
|
public int incoming;
|
|
public MyBitSet nodes_set;
|
|
public GTrans trans;
|
|
public GState nxt;
|
|
public GState prv;
|
|
|
|
public GState()
|
|
{
|
|
nodes_set = new MyBitSet();
|
|
}
|
|
|
|
public void free()
|
|
{
|
|
if (trans.nxt != null)
|
|
trans.nxt.free(trans, true);
|
|
nodes_set = null;
|
|
}
|
|
}
|
|
|
|
public static class GTrans {
|
|
public MyBitSet pos;
|
|
public MyBitSet neg;
|
|
public MyBitSet _final;
|
|
public GState to;
|
|
public GTrans nxt;
|
|
|
|
public GTrans()
|
|
{
|
|
pos = new MyBitSet();
|
|
neg = new MyBitSet();
|
|
_final = new MyBitSet();
|
|
nxt = null;
|
|
to = null;
|
|
}
|
|
|
|
public GTrans(MyBitSet _pos, MyBitSet _neg, MyBitSet _fin)
|
|
{
|
|
pos = (MyBitSet) _pos.clone();
|
|
neg = (MyBitSet) _neg.clone();
|
|
_final = (MyBitSet) _fin.clone();
|
|
nxt = null;
|
|
to = null;
|
|
}
|
|
|
|
public GTrans clone()
|
|
{
|
|
GTrans rv = new GTrans(pos, neg, _final);
|
|
rv.to = to;
|
|
rv.nxt = nxt;
|
|
return rv;
|
|
}
|
|
|
|
public void copyTo(GTrans g)
|
|
{
|
|
g.pos = (MyBitSet) pos.clone();
|
|
g.neg = (MyBitSet) neg.clone();
|
|
g._final = (MyBitSet) _final.clone();
|
|
g.to = to;
|
|
}
|
|
|
|
public void free(GTrans sentinel, boolean fly)
|
|
{
|
|
if (this != sentinel) {
|
|
nxt.free(sentinel, fly);
|
|
if (fly)
|
|
to.incoming--;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* generates a generalized Buchi automaton from the alternating automaton */
|
|
public Generalized(Alternating a)
|
|
{
|
|
Alternating.ATrans t;
|
|
GState s;
|
|
|
|
init_size = 0;
|
|
gstate_id = 1;
|
|
gstate_count = 0;
|
|
gtrans_count = 0;
|
|
|
|
fin = new MyBitSet();
|
|
bad_scc = new MyBitSet();
|
|
_final = a.final_set.IntegerList();
|
|
|
|
gstack = new GState();
|
|
gstack.nxt = gstack;
|
|
gremoved = new GState();
|
|
gremoved.nxt = gremoved;
|
|
gstates = new GState();
|
|
gstates.nxt = gstates;
|
|
gstates.prv = gstates;
|
|
|
|
for (t = a.transition.get(0); t != null; t = t.nxt) { /* puts initial states in the stack */
|
|
s = new GState();
|
|
s.id = t.to.isEmpty() ? 0 : gstate_id++;
|
|
s.incoming = 1;
|
|
s.nodes_set.or(t.to);
|
|
s.trans = new GTrans();
|
|
s.trans.nxt = s.trans;
|
|
s.nxt = gstack.nxt;
|
|
gstack.nxt = s;
|
|
init_size++;
|
|
}
|
|
|
|
if (init_size != 0)
|
|
g_init = new Vector<GState>();
|
|
init_size = 0;
|
|
for (s = gstack.nxt; s != gstack; s = s.nxt) {
|
|
g_init.add(s);
|
|
init_size++;
|
|
}
|
|
while (gstack.nxt != gstack) { /* solves all states in the stack until it is empty */
|
|
s = gstack.nxt;
|
|
gstack.nxt = gstack.nxt.nxt;
|
|
if (s.incoming == 0) {
|
|
s.free();
|
|
continue;
|
|
}
|
|
make_gtrans(a, s);
|
|
}
|
|
|
|
retarget_all_gtrans();
|
|
gstack = null;
|
|
|
|
// System.out.println("Generalized Buchi automaton before simplification:");
|
|
// print(System.out, a.sym_table);
|
|
|
|
simplify_gscc(a);
|
|
simplifyGTrans();
|
|
simplify_gscc(a);
|
|
while (simplifyGStates() != 0) { /* simplifies as much as possible */
|
|
simplify_gscc(a);
|
|
simplifyGTrans();
|
|
simplify_gscc(a);
|
|
}
|
|
// System.out.println("Generalized Buchi automaton after simplification:");
|
|
// print(System.out, a.sym_table);
|
|
}
|
|
|
|
/*is the transition final for i ? */
|
|
private boolean isFinal(Alternating a, MyBitSet from, Alternating.ATrans at, int i)
|
|
{
|
|
Alternating.ATrans t;
|
|
boolean in_to;
|
|
if (!at.to.get(i))
|
|
return true;
|
|
in_to = at.to.get(i);
|
|
at.to.clear(i);
|
|
for (t = a.transition.get(i); t != null; t = t.nxt)
|
|
if (at.to.containsAll(t.to) &&
|
|
at.pos.containsAll(t.pos) &&
|
|
at.neg.containsAll(t.neg)) {
|
|
if (in_to)
|
|
at.to.set(i);
|
|
return true;
|
|
}
|
|
if (in_to)
|
|
at.to.set(i);
|
|
return false;
|
|
}
|
|
|
|
/* finds the corresponding state, or creates it */
|
|
private GState findGState(MyBitSet set, GState s)
|
|
{
|
|
if (set.equals(s.nodes_set))
|
|
return s; /* same state */
|
|
|
|
s = gstack.nxt; /* in the stack */
|
|
gstack.nodes_set = set;
|
|
while (!set.equals(s.nodes_set))
|
|
s = s.nxt;
|
|
if (s != gstack)
|
|
return s;
|
|
|
|
s = gstates.nxt; /* in the solved states */
|
|
gstates.nodes_set = set;
|
|
while (!set.equals(s.nodes_set))
|
|
s = s.nxt;
|
|
if (s != gstates)
|
|
return s;
|
|
|
|
s = gremoved.nxt; /* in the removed states */
|
|
gremoved.nodes_set = set;
|
|
while (!set.equals(s.nodes_set))
|
|
s = s.nxt;
|
|
if (s != gremoved)
|
|
return s;
|
|
|
|
s = new GState();
|
|
s.id = set.isEmpty() ? 0 : gstate_id++;
|
|
s.incoming = 0;
|
|
s.nodes_set = (MyBitSet) set.clone();
|
|
s.trans = new GTrans();
|
|
s.trans.nxt = s.trans;
|
|
s.nxt = gstack.nxt;
|
|
gstack.nxt = s;
|
|
return s;
|
|
}
|
|
|
|
/* returns 1 if the transitions are identical */
|
|
private boolean same_gtrans(GState a, GTrans s, GState b, GTrans t, boolean use_scc)
|
|
{
|
|
if ((s.to != t.to) ||
|
|
!s.pos.equals(t.pos) ||
|
|
!s.neg.equals(t.neg))
|
|
return false; /* transitions differ */
|
|
if (s._final.equals(t._final))
|
|
return true; /* same transitions exactly */
|
|
/* next we check whether acceptance conditions may be ignored */
|
|
if (use_scc && ( bad_scc.get(a.incoming)
|
|
|| bad_scc.get(b.incoming)
|
|
|| (a.incoming != s.to.incoming)
|
|
|| (b.incoming != t.to.incoming)))
|
|
return true;
|
|
|
|
return false;
|
|
|
|
/* below is the old test to check whether acceptance conditions may be ignored */
|
|
//if (!use_scc)
|
|
// return 0; /* transitions differ */
|
|
// if ((a.incoming == b.incoming) && (a.incoming == s.to.incoming))
|
|
// return 0; /* same scc: acceptance conditions must be taken into account */
|
|
/* if scc(a)=scc(b)>scc(s->to) then acceptance conditions need not be taken into account */
|
|
/* if scc(a)>scc(b) and scc(a) is non-trivial then all_gtrans_match(a,b,use_scc) will fail */
|
|
/* if scc(a) is trivial then acceptance conditions of transitions from a need not be taken into account */
|
|
// return 1; /* same transitions up to acceptance conditions */
|
|
|
|
}
|
|
|
|
/* decides if the states are equivalent */
|
|
private int allGTransMatch(GState a, GState b, boolean use_scc)
|
|
{
|
|
GTrans s, t;
|
|
for (s = a.trans.nxt; s != a.trans; s = s.nxt) {
|
|
/* all transitions from a appear in b */
|
|
s.copyTo(b.trans);
|
|
t = b.trans.nxt;
|
|
while (!same_gtrans(a, s, b, t, use_scc))
|
|
t = t.nxt;
|
|
if (t == b.trans)
|
|
return 0;
|
|
}
|
|
for (t = b.trans.nxt; t != b.trans; t = t.nxt) {
|
|
/* all transitions from b appear in a */
|
|
t.copyTo(a.trans);
|
|
s = a.trans.nxt;
|
|
while (!same_gtrans(a, s, b, t, use_scc))
|
|
s = s.nxt;
|
|
if (s == a.trans)
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* creates all the transitions from a state */
|
|
private void make_gtrans(Alternating a, GState s)
|
|
{
|
|
int i, state_trans = 0, trans_exist = 1;
|
|
Vector<Integer> list;
|
|
GState s1;
|
|
Alternating.ATrans t1;
|
|
Alternating.AProd prod = new Alternating.AProd(); /* initialization */
|
|
prod.nxt = prod;
|
|
prod.prv = prod;
|
|
prod.prod = new Alternating.ATrans();
|
|
prod.trans = prod.prod;
|
|
prod.trans.nxt = prod.prod;
|
|
list = s.nodes_set.IntegerList();
|
|
|
|
for (i = 0; i < list.size(); i++) {
|
|
Alternating.AProd p = new Alternating.AProd();
|
|
p.astate = list.get(i);
|
|
p.trans = a.transition.get(list.get(i));
|
|
if (p.trans == null)
|
|
trans_exist = 0;
|
|
p.prod = prod.nxt.prod.merge(p.trans);
|
|
p.nxt = prod.nxt;
|
|
p.prv = prod;
|
|
p.nxt.prv = p;
|
|
p.prv.nxt = p;
|
|
}
|
|
|
|
while (trans_exist != 0) { /* calculates all the transitions */
|
|
Alternating.AProd p = prod.nxt;
|
|
t1 = p.prod;
|
|
if (t1 != null) { /* solves the current transition */
|
|
GTrans trans, t2;
|
|
fin.clear();
|
|
for (i = 0; i < _final.size(); i++)
|
|
if (isFinal(a, s.nodes_set, t1, _final.get(i)))
|
|
fin.set(_final.get(i));
|
|
for (t2 = s.trans.nxt; t2 != s.trans;) {
|
|
if (t2.to.nodes_set.containsAll(t1.to) &&
|
|
t2.pos.containsAll(t1.pos) &&
|
|
t2.neg.containsAll(t1.neg) &&
|
|
fin.equals(t2._final)) { /* t2 is redundant */
|
|
GTrans free = t2.nxt;
|
|
t2.to.incoming--;
|
|
t2.to = free.to;
|
|
t2.pos = (MyBitSet) free.pos.clone();
|
|
t2.neg = (MyBitSet) free.neg.clone();
|
|
t2._final = (MyBitSet) free._final.clone();
|
|
t2.nxt = free.nxt;
|
|
if (free == s.trans)
|
|
s.trans = t2;
|
|
free = null;
|
|
state_trans--;
|
|
} else if (t1.to.containsAll(t2.to.nodes_set) && t1.pos.containsAll(t2.pos) && t1.neg.containsAll(t2.neg) && t2._final.equals(fin)) { /* t1 is redundant */
|
|
break;
|
|
} else {
|
|
t2 = t2.nxt;
|
|
}
|
|
}
|
|
if (t2 == s.trans) { /* adds the transition */
|
|
trans = new GTrans();
|
|
trans.to = findGState(t1.to, s);
|
|
trans.to.incoming++;
|
|
trans.pos = (MyBitSet) t1.pos.clone();
|
|
trans.neg = (MyBitSet) t1.neg.clone();
|
|
trans._final = (MyBitSet) fin.clone();
|
|
trans.nxt = s.trans.nxt;
|
|
s.trans.nxt = trans;
|
|
state_trans++;
|
|
}
|
|
}
|
|
if (p.trans == null)
|
|
break;
|
|
while (p.trans.nxt == null) /* calculates the next transition */
|
|
p = p.nxt;
|
|
if (p == prod)
|
|
break;
|
|
p.trans = p.trans.nxt;
|
|
p.prod = p.nxt.prod.merge(p.trans);
|
|
p = p.prv;
|
|
while (p != prod) {
|
|
p.trans = a.transition.get(p.astate);
|
|
p.prod = p.nxt.prod.merge(p.trans);
|
|
p = p.prv;
|
|
}
|
|
}
|
|
|
|
list.clear();
|
|
while (prod.nxt != prod) {
|
|
Alternating.AProd p = prod.nxt;
|
|
prod.nxt = p.nxt;
|
|
p.prod = null;
|
|
p = null;
|
|
}
|
|
prod.prod = null;
|
|
prod = null;
|
|
|
|
if (s.trans == s.trans.nxt) { /* s has no transitions */
|
|
s.trans.nxt.free(s.trans, true);
|
|
s.trans = null;
|
|
s.prv = null;
|
|
s.nxt = gremoved.nxt;
|
|
gremoved.nxt = s;
|
|
for (s1 = gremoved.nxt; s1 != gremoved; s1 = s1.nxt)
|
|
if (s1.prv == s)
|
|
s1.prv = null;
|
|
return;
|
|
}
|
|
|
|
gstates.trans = s.trans;
|
|
s1 = gstates.nxt;
|
|
while (allGTransMatch(s, s1, false) == 0)
|
|
s1 = s1.nxt;
|
|
if (s1 != gstates) { /* s and s1 are equivalent */
|
|
s.trans.nxt.free(s.trans, true);
|
|
s.trans = null;
|
|
s.prv = s1;
|
|
s.nxt = gremoved.nxt;
|
|
gremoved.nxt = s;
|
|
for (s1 = gremoved.nxt; s1 != gremoved; s1 = s1.nxt)
|
|
if (s1.prv == s)
|
|
s1.prv = s.prv;
|
|
return;
|
|
}
|
|
|
|
s.nxt = gstates.nxt; /* adds the current state to 'gstates' */
|
|
s.prv = gstates;
|
|
s.nxt.prv = s;
|
|
gstates.nxt = s;
|
|
gtrans_count += state_trans;
|
|
gstate_count++;
|
|
}
|
|
|
|
/* redirects transitions before removing a state from the automaton */
|
|
private void retarget_all_gtrans()
|
|
{
|
|
GState s;
|
|
GTrans t;
|
|
int i;
|
|
for (i = 0; i < init_size; i++)
|
|
if (g_init.get(i) != null && (g_init.get(i).trans == null)) /* g_init[i] has been removed */
|
|
g_init.set(i, g_init.get(i).prv);
|
|
for (s = gstates.nxt; s != gstates; s = s.nxt)
|
|
for (t = s.trans.nxt; t != s.trans;)
|
|
if (t.to.trans == null) { /* t->to has been removed */
|
|
t.to = t.to.prv;
|
|
if (t.to == null) { /* t->to has no transitions */
|
|
GTrans free = t.nxt;
|
|
t.to = free.to;
|
|
t.pos = (MyBitSet) free.pos.clone();
|
|
t.neg = (MyBitSet) free.neg.clone();
|
|
t._final = (MyBitSet) free._final.clone();
|
|
t.nxt = free.nxt;
|
|
if (free == s.trans)
|
|
s.trans = t;
|
|
free = null;
|
|
} else
|
|
t = t.nxt;
|
|
} else
|
|
t = t.nxt;
|
|
while (gremoved.nxt != gremoved) { /* clean the 'removed' list */
|
|
s = gremoved.nxt;
|
|
gremoved.nxt = gremoved.nxt.nxt;
|
|
if (s.nodes_set != null)
|
|
s.nodes_set = null;
|
|
s = null;
|
|
}
|
|
}
|
|
|
|
/* removes a state */
|
|
private GState removeGState(GState s, GState s1)
|
|
{
|
|
GState prv = s.prv;
|
|
s.prv.nxt = s.nxt;
|
|
s.nxt.prv = s.prv;
|
|
s.trans.nxt.free(s.trans, false);
|
|
s.trans = null;
|
|
s.nodes_set = null;
|
|
s.nxt = gremoved.nxt;
|
|
gremoved.nxt = s;
|
|
s.prv = s1;
|
|
for (s1 = gremoved.nxt; s1 != gremoved; s1 = s1.nxt)
|
|
if (s1.prv == s)
|
|
s1.prv = s.prv;
|
|
return prv;
|
|
}
|
|
|
|
/* simplifies the transitions */
|
|
private int simplifyGTrans()
|
|
{
|
|
int changed = 0;
|
|
GState s;
|
|
GTrans t;
|
|
GTrans t1;
|
|
|
|
for (s = gstates.nxt; s != gstates; s = s.nxt) {
|
|
t = s.trans.nxt;
|
|
while (t != s.trans) { // tries to remove t
|
|
t.copyTo(s.trans);
|
|
t1 = s.trans.nxt;
|
|
while (!((t != t1)
|
|
&& (t1.to == t.to)
|
|
&& t.pos.containsAll(t1.pos)
|
|
&& t.neg.containsAll(t1.neg)
|
|
&& (t1._final.containsAll(t._final) ||
|
|
(s.incoming != t.to.incoming) || bad_scc.get(s.incoming)))
|
|
)
|
|
t1 = t1.nxt;
|
|
|
|
if (t1 != s.trans) {
|
|
GTrans free = t.nxt;
|
|
t.to = free.to;
|
|
t.pos = (MyBitSet) free.pos.clone();
|
|
t.neg = (MyBitSet) free.neg.clone();
|
|
t._final = (MyBitSet) free._final.clone();
|
|
t.nxt = free.nxt;
|
|
if (free == s.trans)
|
|
s.trans = t;
|
|
free = null;
|
|
changed++;
|
|
} else
|
|
t = t.nxt;
|
|
}
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
/* eliminates redundant states */
|
|
private int simplifyGStates()
|
|
{
|
|
int changed = 0;
|
|
GState a, b;
|
|
|
|
for (a = gstates.nxt; a != gstates; a = a.nxt) {
|
|
if (a.trans == a.trans.nxt) { /* a has no transitions */
|
|
a = removeGState(a, null);
|
|
changed++;
|
|
continue;
|
|
}
|
|
gstates.trans = a.trans;
|
|
b = a.nxt;
|
|
while (allGTransMatch(a, b, true) == 0) /* = and not == */
|
|
b = b.nxt;
|
|
if (b != gstates) { /* a and b are equivalent */
|
|
/* if scc(a)>scc(b) and scc(a) is non-trivial then all_gtrans_match(a,b,use_scc) must fail */
|
|
if (a.incoming > b.incoming) // scc(a) is trivial
|
|
a = removeGState(a, b);
|
|
else // either scc(a)=scc(b) or scc(b) is trivial
|
|
removeGState(b, a);
|
|
changed++;
|
|
}
|
|
}
|
|
retarget_all_gtrans();
|
|
|
|
return changed;
|
|
}
|
|
|
|
private int gdfs(GState s)
|
|
{
|
|
GTrans t;
|
|
GScc c;
|
|
GScc scc = new GScc();
|
|
scc.gstate = 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 = gdfs(t.to);
|
|
scc.theta = scc.theta < result ? scc.theta : result;
|
|
} else {
|
|
for (c = scc_stack.nxt; c != null; c = c.nxt) {
|
|
if (c.gstate == t.to) {
|
|
scc.theta = scc.theta < c.rank ? scc.theta : c.rank;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (scc.rank == scc.theta) {
|
|
while (scc_stack != scc) {
|
|
scc_stack.gstate.incoming = scc_id;
|
|
scc_stack = scc_stack.nxt;
|
|
}
|
|
scc.gstate.incoming = scc_id++;
|
|
scc_stack = scc.nxt;
|
|
}
|
|
return scc.theta;
|
|
}
|
|
|
|
private void simplify_gscc(Alternating a)
|
|
{
|
|
GState s;
|
|
GTrans t;
|
|
int i;
|
|
Vector<MyBitSet> scc_final;
|
|
|
|
rank = 1;
|
|
scc_stack = null;
|
|
scc_id = 1;
|
|
|
|
if (gstates == gstates.nxt) return;
|
|
|
|
for (s = gstates.nxt; s != gstates; s = s.nxt) {
|
|
s.incoming = 0; /* state color = white */
|
|
}
|
|
|
|
for (i = 0; i < init_size; i++) {
|
|
if ((g_init.get(i) != null) && g_init.get(i).incoming == 0) {
|
|
gdfs(g_init.get(i));
|
|
}
|
|
}
|
|
|
|
scc_final = new Vector<MyBitSet>();
|
|
for (i = 0; i < scc_id; i++) {
|
|
scc_final.add(new MyBitSet());
|
|
}
|
|
for (s = gstates.nxt; s != gstates; s = s.nxt) {
|
|
if (s.incoming == 0) {
|
|
s = removeGState(s, null);
|
|
}
|
|
else {
|
|
for (t = s.trans.nxt; t != s.trans; t = t.nxt) {
|
|
if (t.to.incoming == s.incoming) {
|
|
scc_final.get(s.incoming).or(t._final);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
bad_scc.clear();
|
|
|
|
for (i = 0; i < scc_id; i++) {
|
|
if (!scc_final.get(i).containsAll(a.final_set)) {
|
|
bad_scc.set(i);
|
|
}
|
|
}
|
|
scc_final.clear();
|
|
}
|
|
|
|
private void reverse_print_generalized(PrintStream out, GState s, APSet symtab)
|
|
{ /* dumps the generalized Buchi automaton */
|
|
GTrans t;
|
|
if (s == gstates)
|
|
return;
|
|
|
|
reverse_print_generalized(out, s.nxt, symtab); /* begins with the last state */
|
|
|
|
out.format("state %d (", s.id);
|
|
s.nodes_set.print(out);
|
|
out.format(") : %d", s.incoming);
|
|
out.println();
|
|
for (t = s.trans.nxt; t != s.trans; t = t.nxt) {
|
|
if (t.pos.isEmpty() && t.neg.isEmpty())
|
|
out.print("1");
|
|
t.pos.print(out, symtab, true);
|
|
if (!t.pos.isEmpty() && !t.neg.isEmpty())
|
|
out.print(" & ");
|
|
t.neg.print(out, symtab, false);
|
|
out.format(" -> %d : ", t.to.id);
|
|
t._final.print(out);
|
|
out.println();
|
|
}
|
|
}
|
|
|
|
/* prints intial states and calls 'reverse_print' */
|
|
public void print(PrintStream out, APSet symtab)
|
|
{
|
|
int i;
|
|
out.println("init :");
|
|
for (i = 0; i < init_size; i++)
|
|
if (g_init.get(i) != null)
|
|
out.println(g_init.get(i).id);
|
|
reverse_print_generalized(out, gstates.nxt, symtab);
|
|
}
|
|
}
|