/*
* Automaton.java
*
* Copyright (c) 2010-2011, Ontotext (www.ontotext.com).
*
* This file is part of GATE (see http://gate.ac.uk/), and is free
* software, licenced under the GNU Library General Public License,
* Version 2, June 1991 (in the distribution as file licence.html,
* and also available at http://gate.ac.uk/gate/licence.html).
*
* $Id$
*/
package com.ontotext.jape.automaton;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import com.ontotext.jape.pda.StatePDA;
import com.ontotext.jape.pda.TransitionPDA;
/**
* This class provides basic functionalities for standard one-tape automata. The
* class is a reuse from the incaut library. It is originally designed to
* support operations with automata of all sizes: from very small automata (that
* have several states) to very large automata (that have millions of states).
* This explains the excessive use of arrays and closed hash tables.
*
* @author petar.mitankin
*/
public class Automaton {
public static final int EPSILON = 0;
// transitions:
// the i-th transition is represented as a triple (transitionsFrom[i],
// transitionsLabel.elementAt(i), transitionsTo[i])
// the number of all transitions is transitionsStored
public int[] transitionsFrom;
public GenericWholeArrray transitionsLabel;
public int[] transitionsTo;
protected int transitionsStored;
// states:
// the information for the q-th state is encoded as follows:
// stateFinalities.elementAt(q) represents the finality of the state
// stateTransitions[q] is the number of the first transition with start
// state q
// stateNumberOfTransitions.elementAt(q) represents the number of the
// transitions with start state q
// the number of all states is statesStored
protected int[] stateTransitions;
public GenericWholeArrray stateFinalities;
protected GenericWholeArrray stateNumberOfTransitions;
protected int statesStored;
// initial states:
protected IntSequence initialStates;
// this flag is true iff there is an epsilon-transition in the automaton
boolean hasEpsilonTransitions;
// the alphabet of the automaton is 0 = EPSILON, 1, 2, 3, ...,
// alphabetLength-1.
protected int alphabetLength;
public Automaton(AutomatonBuildHelp help, int stateFinalityType,
int stateNumberOfTransitionsType) {
init(help, stateFinalityType, stateNumberOfTransitionsType);
}
public Automaton(AutomatonBuildHelp help, int stateFinalityType) {
init(help, stateFinalityType, GenericWholeArrray.TYPE_INT);
}
protected void init(AutomatonBuildHelp help, int stateFinalityType,
int stateNumberOfTransitionsType) {
alphabetLength = help.alphabetLength;
transitionsFrom = new int[help.transitionsAlloced];
if (alphabetLength <= Byte.MAX_VALUE) {
transitionsLabel = new GenericWholeArrray(
GenericWholeArrray.TYPE_BYTE, help.transitionsAlloced);
} else if (alphabetLength <= Short.MAX_VALUE) {
transitionsLabel = new GenericWholeArrray(
GenericWholeArrray.TYPE_SHORT, help.transitionsAlloced);
} else {
transitionsLabel = new GenericWholeArrray(
GenericWholeArrray.TYPE_INT, help.transitionsAlloced);
}
transitionsTo = new int[help.transitionsAlloced];
stateTransitions = new int[help.statesAlloced];
stateFinalities = new GenericWholeArrray(stateFinalityType,
help.statesAlloced);
stateNumberOfTransitions = new GenericWholeArrray(
stateNumberOfTransitionsType, help.statesAlloced);
initialStates = new IntSequence(1);
}
public void addState(AutomatonBuildHelp help, int state) {
if (statesStored <= state) {
if (help.statesAlloced <= state) {
int mem = (state + 1) + (state + 1) / 4;
stateTransitions = GenericWholeArrray.realloc(stateTransitions,
mem, statesStored);
stateFinalities.realloc(mem, statesStored);
stateNumberOfTransitions.realloc(mem, statesStored);
help.statesAlloced = mem;
}
for (; statesStored <= state; statesStored++) {
stateTransitions[statesStored] = Constants.NO;
stateFinalities.setElement(statesStored, Constants.NO);
stateNumberOfTransitions.setElement(statesStored, 0);
}
}
}
/**
* Adds a transition in the automaton
*
* @param help
* @param stateFrom
* @param label
* @param stateTo
*/
public void addTransition(AutomatonBuildHelp help, int stateFrom,
int label, int stateTo) {
addState(help, stateFrom > stateTo ? stateFrom : stateTo);
if (transitionsStored == help.transitionsAlloced) {
int mem = transitionsStored + transitionsStored / 4;
transitionsFrom = GenericWholeArrray.realloc(transitionsFrom, mem,
transitionsStored);
transitionsLabel.realloc(mem, transitionsStored);
transitionsTo = GenericWholeArrray.realloc(transitionsTo, mem,
transitionsStored);
help.transitionsAlloced = mem;
}
transitionsFrom[transitionsStored] = stateFrom;
transitionsLabel.setElement(transitionsStored, label);
transitionsTo[transitionsStored] = stateTo;
stateNumberOfTransitions.setElement(stateFrom,
stateNumberOfTransitions.elementAt(stateFrom) + 1);
transitionsStored++;
if (label == EPSILON) {
hasEpsilonTransitions = true;
}
}
protected void sortTransitions() {
int i;
for (i = 0; i < statesStored; i++) {
stateNumberOfTransitions.setElement(i, 0);
stateTransitions[i] = Constants.NO;
}
if (transitionsStored == 0) {
return;
}
int q;
if (transitionsStored == 1) {
q = transitionsFrom[0];
stateTransitions[q] = 0;
stateNumberOfTransitions.setElement(q, 1);
return;
}
for (i = 0; i < transitionsStored; i++) {
trPush(i);
}
for (i = 1; i < transitionsStored; i++) {
trSwap(0, transitionsStored - i);
trSink(transitionsStored - i);
}
int j = 1;
q = transitionsFrom[0];
stateTransitions[q] = 0;
stateNumberOfTransitions.setElement(q, 1);
for (i = 1; i < transitionsStored; i++) {
if (trCmp(j - 1, i) != 0) {
if (j != i) {
trCpy(j, i);
}
if (transitionsFrom[j] == q) {
stateNumberOfTransitions.setElement(q,
stateNumberOfTransitions.elementAt(q) + 1);
} else {
q = transitionsFrom[j];
stateTransitions[q] = j;
stateNumberOfTransitions.setElement(q, 1);
}
j++;
}
}
transitionsStored = j;
}
protected Automaton removeEpsilonTransitions(StatePDA[] finalities) {
sortTransitions();
if (!hasEpsilonTransitions) {
return (this);
}
EpsilonClosure ec = new EpsilonClosure(this);
int i;
for (i = 0; i < statesStored; i++) {
ec.setMarker(i);
findEpsilonClosure(ec, i);
ec.finish();
}
AutomatonBuildHelp help = new AutomatonBuildHelp(alphabetLength);
help.statesAlloced = statesStored;
help.transitionsAlloced = transitionsStored;
Automaton result = new Automaton(help, stateFinalities.getType(),
stateNumberOfTransitions.getType());
result.initialStates.cpy(initialStates);
int j, k, n, tr, to, sf, newsf;
for (i = 0; i < statesStored; i++) {
result.addState(help, i);
result.stateFinalities.setElement(i, stateFinalities.elementAt(i));
n = stateNumberOfTransitions.elementAt(i);
tr = stateTransitions[i];
for (j = 0; j < n && transitionsLabel.elementAt(tr + j) == EPSILON; j++)
;
for (; j < n; j++) {
result.addTransition(help, i,
transitionsLabel.elementAt(tr + j), transitionsTo[tr
+ j]);
}
if (ec.closure(i) == 0) {
continue;
}
for (k = ec.closure(i); k != Constants.NO; k = ec.next.seq[k]) {
to = ec.state.seq[k];
sf = result.stateFinalities.elementAt(i);
newsf = stateFinalities.elementAt(to);
if (newsf != Constants.NO
&& (sf == Constants.NO || finalities[newsf]
.precedes(finalities[sf]))) {
result.stateFinalities.setElement(i, newsf);
}
n = stateNumberOfTransitions.elementAt(to);
tr = stateTransitions[to];
for (j = 0; j < n
&& transitionsLabel.elementAt(tr + j) == EPSILON; j++)
;
for (; j < n; j++) {
result.addTransition(help, i,
transitionsLabel.elementAt(tr + j),
transitionsTo[tr + j]);
}
}
}
result.sortTransitions();
return (result);
}
private void findEpsilonClosure(EpsilonClosure ec, int state) {
ec.mark(state);
int n = stateNumberOfTransitions.elementAt(state);
int tr = stateTransitions[state];
int to;
for (int i = 0; i < n && transitionsLabel.elementAt(tr + i) == EPSILON; i++) {
to = transitionsTo[tr + i];
if (ec.isMarked(to)) {
continue;
}
if (ec.closure(to) == Constants.NO) {
findEpsilonClosure(ec, to);
continue;
}
ec.mark(to);
if (ec.closure(to) == 0) {
continue;
}
for (to = ec.closure(to); to != Constants.NO; to = ec.next.seq[to]) {
ec.mark(ec.state.seq[to]);
}
}
}
/**
* Determinizes the automaton.
*
* @param finalities
* finalities[f] is a State that has a finality f.
* @return
*/
public Automaton determinize(StatePDA[] finalities) {
AutomatonBuildHelp bHelp = new AutomatonBuildHelp(alphabetLength);
if (initialStates.seqStored == 0) {
return new Automaton(bHelp, stateFinalities.getType(),
stateNumberOfTransitions.getType());
}
Automaton a;
if (hasEpsilonTransitions) {
a = removeEpsilonTransitions(finalities);
} else {
sortTransitions();
a = this;
}
Automaton result = new Automaton(bHelp, stateFinalities.getType(),
stateNumberOfTransitions.getType());
AutomatonDeterminizationHelp dHelp = new AutomatonDeterminizationHelp();
dHelp.set.cpy(a.initialStates);
result.setTheInitialState(dHelp.push());
int set, letter, tr;
while (!dHelp.queueIsEmpty()) {
set = dHelp.pop();
result.addState(bHelp, set);
result.stateFinalities.setElement(set, a.computeSetFinality(
dHelp.states.seq, dHelp.sets.seq[set], finalities));
result.stateTransitions[set] = result.transitionsStored;
dHelp.addTransitions(set, a);
letter = Constants.NO;
while ((tr = dHelp.getNextTransition(a)) != Constants.NO) {
if (letter != a.transitionsLabel.elementAt(tr)) {
if (letter != Constants.NO) {
result.addTransition(bHelp, set, letter, dHelp.push());
}
letter = a.transitionsLabel.elementAt(tr);
dHelp.set.seqStored = 0;
}
dHelp.set.add(a.transitionsTo[tr]);
}
if (letter != Constants.NO) {
result.addTransition(bHelp, set, letter, dHelp.push());
}
}
return (result);
}
protected AutomatonMinimizationHelp hopcroftMinimize(int labelsStored) {
int i, j;
for (i = 0; i < transitionsStored; i++) {
j = transitionsFrom[i];
transitionsFrom[i] = transitionsTo[i];
transitionsTo[i] = j;
}
sortTransitions();
IntSequence classes = new IntSequence();
j = 0;
for (i = 0; i < statesStored; i++) {
if (stateFinalities.elementAt(i) != Constants.NO) {
j++;
}
classes.addIfDoesNotExsist(stateFinalities.elementAt(i));
}
AutomatonMinimizationHelp mHelp = new AutomatonMinimizationHelp(
statesStored);
if (j == 0) {
return mHelp;
}
for (j = 0; j < classes.seqStored; j++) {
mHelp.classesFirstState[j] = Constants.NO;
mHelp.classesNewClass[j] = Constants.NO;
mHelp.classesNewPower[j] = 0;
mHelp.classesPower[j] = 0;
mHelp.classesFirstLetter[j] = Constants.NO;
mHelp.classesNext[j] = Constants.NO;
}
mHelp.classesStored = classes.seqStored;
for (i = 0; i < statesStored; i++) {
mHelp.addState(i, classes.contains(stateFinalities.elementAt(i)));
}
for (i = 1; i < labelsStored; i++) {
for (j = 0; j < mHelp.classesStored; j++) {
mHelp.addLetter(j, i);
}
}
IntSequence states = new IntSequence();
classes.seqStored = 0;
GenericWholeArrray alph = new GenericWholeArrray(
GenericWholeArrray.TYPE_BIT, labelsStored);
int q1, a, state, tr, q0;
while (mHelp.firstClass != Constants.NO) {
q1 = mHelp.firstClass;
a = mHelp.lettersLetter[mHelp.classesFirstLetter[q1]];
mHelp.classesFirstLetter[q1] = mHelp.lettersNext[mHelp.classesFirstLetter[q1]];
if (mHelp.classesFirstLetter[q1] == Constants.NO) {
mHelp.firstClass = mHelp.classesNext[q1];
}
classes.seqStored = 0;
states.seqStored = 0;
for (state = mHelp.classesFirstState[q1]; state != Constants.NO; state = mHelp.statesNext[state]) {
for (tr = getNextTransition(state, a, Constants.NO); tr != Constants.NO; tr = getNextTransition(
state, a, tr)) {
q0 = mHelp.statesClassNumber[transitionsTo[tr]];
states.add(transitionsTo[tr]);
if (mHelp.classesNewPower[q0] == 0) {
classes.add(q0);
}
mHelp.classesNewPower[q0]++;
}
}
for (j = 0; j < states.seqStored; j++) {
q0 = mHelp.statesClassNumber[states.seq[j]];
if (mHelp.classesNewPower[q0] == mHelp.classesPower[q0]) {
continue;
}
if (mHelp.classesNewClass[q0] == Constants.NO) {
if (mHelp.classesStored == mHelp.classesAlloced) {
mHelp.reallocClasses();
}
mHelp.classesNewClass[q0] = mHelp.classesStored;
mHelp.classesFirstState[mHelp.classesStored] = Constants.NO;
mHelp.classesNewClass[mHelp.classesStored] = Constants.NO;
mHelp.classesNewPower[mHelp.classesStored] = 0;
mHelp.classesPower[mHelp.classesStored] = 0;
mHelp.classesFirstLetter[mHelp.classesStored] = Constants.NO;
mHelp.classesNext[mHelp.classesStored] = Constants.NO;
mHelp.classesStored++;
}
mHelp.moveState(states.seq[j], mHelp.classesNewClass[q0]);
}
for (i = 0; i < classes.seqStored; i++) {
q0 = classes.seq[i];
if (mHelp.classesNewPower[q0] != mHelp.classesPower[q0]) {
mHelp.classesPower[q0] -= mHelp.classesNewPower[q0];
for (j = 1; j < labelsStored; j++) {
alph.setElement(j, 0);
}
for (j = mHelp.classesFirstLetter[q0]; j != Constants.NO; j = mHelp.lettersNext[j]) {
mHelp.addLetter(mHelp.classesNewClass[q0],
mHelp.lettersLetter[j]);
alph.setElement(mHelp.lettersLetter[j], Constants.NO);
}
for (j = 1; j < labelsStored; j++) {
if (alph.elementAt(j) == Constants.NO) {
continue;
}
if (mHelp.classesPower[q0] < mHelp.classesPower[mHelp.classesNewClass[q0]]) {
mHelp.addLetter(q0, j);
} else {
mHelp.addLetter(mHelp.classesNewClass[q0], j);
}
}
}
mHelp.classesNewPower[q0] = 0;
mHelp.classesNewClass[q0] = Constants.NO;
}
}
return mHelp;
}
/**
* Minimizes a deterministic automaton according to Hopcroft's minimization
* algorithm. It run im time O(Sigma N log N), where Sigma is the number of
* letters in the alphabet of the automaton and N is the number of states.
*
* @return the minimized automaton
*/
public Automaton minimize() {
AutomatonMinimizationHelp mHelp = hopcroftMinimize(alphabetLength);
AutomatonBuildHelp bHelp = new AutomatonBuildHelp(alphabetLength);
if (mHelp.classesStored == 0) {
bHelp.statesAlloced = 0;
bHelp.transitionsAlloced = 0;
return new Automaton(bHelp, stateFinalities.getType(),
stateNumberOfTransitions.getType());
}
int i, j;
for (i = 0; i < transitionsStored; i++) {
j = transitionsFrom[i];
transitionsFrom[i] = transitionsTo[i];
transitionsTo[i] = j;
}
sortTransitions();
bHelp.statesAlloced = mHelp.classesStored;
bHelp.transitionsAlloced = 0;
for (i = 0; i < mHelp.classesStored; i++) {
bHelp.transitionsAlloced += stateNumberOfTransitions
.elementAt(mHelp.classesFirstState[i]);
}
Automaton result = new Automaton(bHelp, stateFinalities.getType(),
stateNumberOfTransitions.getType());
result.setTheInitialState(mHelp.statesClassNumber[initialStates.seq[0]]);
int n, state, tr;
for (i = 0; i < mHelp.classesStored; i++) {
state = mHelp.classesFirstState[i];
tr = stateTransitions[state];
n = stateNumberOfTransitions.elementAt(state);
for (j = 0; j < n; j++) {
result.addTransition(bHelp, i,
transitionsLabel.elementAt(tr + j),
mHelp.statesClassNumber[transitionsTo[tr + j]]);
}
}
j = 0;
for (i = 0; i < mHelp.classesStored; i++) {
state = mHelp.classesFirstState[i];
result.stateFinalities.setElement(i,
stateFinalities.elementAt(state));
result.stateTransitions[i] = j;
result.stateNumberOfTransitions.setElement(i,
stateNumberOfTransitions.elementAt(state));
j += result.stateNumberOfTransitions.elementAt(i);
}
return (result);
}
public void generateGraphVizInput(File file, String charSet)
throws IOException {
FileOutputStream fos = null;
OutputStreamWriter osw = null;
try {
fos = new FileOutputStream(file);
osw = new OutputStreamWriter(fos, charSet);
osw.write("Digraph A{ \n");
osw.write("rankdir=LR;\n");
osw.write("node[shape = circle, color = white]; \"\";\n");
osw.write("node [shape = doublecircle, color = black];\n");
int s;
for (s = 0; s < statesStored; s++) {
if (stateFinalities.elementAt(s) != Constants.NO) {
osw.write(Integer.toString(s));
osw.write("\n");
}
}
osw.write("node [shape = circle];\n");
int i;
for (i = 0; i < initialStates.seqStored; i++) {
osw.write("\"\" -> ");
osw.write(Integer.toString(initialStates.seq[i]));
osw.write(";\n");
}
int tr, n;
for (s = 0; s < statesStored; s++) {
tr = stateTransitions[s];
n = stateNumberOfTransitions.elementAt(s);
for (i = 0; i < n; i++) {
osw.write(Integer.toString(s));
osw.write(" -> ");
osw.write(Integer.toString(transitionsTo[tr + i]));
writeTransitionLabel(osw, tr + i);
}
}
osw.write("\n");
for (s = 0; s < statesStored; s++) {
if (stateFinalities.elementAt(s) != Constants.NO) {
writeStateOtput(osw, s);
}
}
osw.write("}\n");
} finally {
if (osw != null) {
try {
osw.close();
} catch (Exception e) {
}
}
if (fos != null) {
try {
fos.close();
} catch (Exception e) {
}
}
}
}
protected void writeTransitionLabel(OutputStreamWriter osw, int tr)
throws IOException {
osw.write(" [ label = \"");
if (transitionsLabel.elementAt(tr) != EPSILON) {
osw.write(Integer.toString(transitionsLabel.elementAt(tr)));
}
osw.write("\" ];\n");
}
protected void writeStateOtput(OutputStreamWriter osw, int s)
throws IOException {
}
protected int getNextTransition(int state, int letter, int transition) {
if (transition != Constants.NO) {
transition++;
if (transition >= transitionsStored) {
return (Constants.NO);
}
if (transitionsFrom[transition] == state
&& transitionsLabel.elementAt(transition) == letter) {
return (transition);
}
return (Constants.NO);
}
if (stateNumberOfTransitions.elementAt(state) == 0) {
return (Constants.NO);
}
int left = stateTransitions[state];
int right = left + stateNumberOfTransitions.elementAt(state) - 1;
int mid;
while (true) {
if (left == right) {
if (transitionsLabel.elementAt(left) == letter) {
transition = left;
break;
}
return (Constants.NO);
}
if (left + 1 == right) {
if (transitionsLabel.elementAt(left) == letter) {
transition = left;
break;
}
if (transitionsLabel.elementAt(right) == letter) {
transition = right;
break;
}
return (Constants.NO);
}
mid = (left + right) / 2;
if (transitionsLabel.elementAt(mid) < letter) {
left = mid;
} else if (letter < transitionsLabel.elementAt(mid)) {
right = mid;
} else {
transition = mid;
break;
}
}
for (; transition > stateTransitions[state]
&& transitionsLabel.elementAt(transition - 1) == letter; transition--)
;
return (transition);
}
protected int computeSetFinality(int[] states, int pos,
StatePDA[] finalities) {
int sf = Constants.NO;
int newsf;
for (; states[pos] != Constants.NO; pos++) {
newsf = stateFinalities.elementAt(states[pos]);
if (newsf != Constants.NO
&& (sf == Constants.NO || finalities[newsf]
.precedes(finalities[sf]))) {
sf = newsf;
}
}
return sf;
}
public void setTheInitialState(int s) {
initialStates.seqStored = 0;
initialStates.add(s);
}
protected void trPush(int tr) {
int p;
while (tr > 0) {
p = (tr - 1) / 2;
if (trCmp(tr, p) > 0) {
trSwap(p, tr);
tr = p;
} else {
break;
}
}
}
protected void trSink(int heapStored) {
int c, l, r;
c = 0;
while (true) {
l = 2 * c + 1;
if (l < heapStored) {
r = l + 1;
if (r < heapStored) {
if (trCmp(l, r) > 0) {
if (trCmp(l, c) > 0) {
trSwap(l, c);
c = l;
} else {
break;
}
} else if (trCmp(c, r) < 0) {
trSwap(r, c);
c = r;
} else {
break;
}
} else if (trCmp(l, c) > 0) {
trSwap(l, c);
c = l;
} else {
break;
}
} else {
break;
}
}
}
protected void trSwap(int tr1, int tr2) {
int tmp;
tmp = transitionsFrom[tr1];
transitionsFrom[tr1] = transitionsFrom[tr2];
transitionsFrom[tr2] = tmp;
tmp = transitionsLabel.elementAt(tr1);
transitionsLabel.setElement(tr1, transitionsLabel.elementAt(tr2));
transitionsLabel.setElement(tr2, tmp);
tmp = transitionsTo[tr1];
transitionsTo[tr1] = transitionsTo[tr2];
transitionsTo[tr2] = tmp;
}
protected int trCmp(int tr1, int tr2) {
if (transitionsFrom[tr1] < transitionsFrom[tr2]) {
return (-1);
}
if (transitionsFrom[tr1] > transitionsFrom[tr2]) {
return (1);
}
int l1 = transitionsLabel.elementAt(tr1);
int l2 = transitionsLabel.elementAt(tr2);
if (l1 < l2) {
return (-1);
}
if (l1 > l2) {
return (1);
}
if (transitionsTo[tr1] < transitionsTo[tr2]) {
return (-1);
}
if (transitionsTo[tr1] > transitionsTo[tr2]) {
return (1);
}
return (0);
}
protected int trLabelCmp(int tr1, int tr2) {
int l1 = transitionsLabel.elementAt(tr1);
int l2 = transitionsLabel.elementAt(tr2);
if (l1 < l2) {
return (-1);
}
if (l1 > l2) {
return (1);
}
return (0);
}
protected void trCpy(int trTo, int trFrom) {
transitionsFrom[trTo] = transitionsFrom[trFrom];
transitionsLabel.setElement(trTo, transitionsLabel.elementAt(trFrom));
transitionsTo[trTo] = transitionsTo[trFrom];
}
/**
* Gets the number of the states of the automaton
*/
public int getStatesStored() {
return statesStored;
}
/**
* Gets the initial state of the automaton
*/
public int getInitialState() {
if (initialStates.seqStored == 0) {
return Constants.NO;
}
return initialStates.seq[0];
}
/**
* Gets the number of transitions in the automaton
*
* @return
*/
public int getTransitionsStored() {
return transitionsStored;
}
/**
* Converts the automaton into State[].
*
* @param tripleTransitions
* @return
*/
public StatePDA[] toFSM(TripleTransitions tripleTransitions) {
StatePDA[] fsmStates = new StatePDA[statesStored];
int i;
for (i = 0; i < statesStored; i++) {
fsmStates[i] = new StatePDA();
}
TransitionPDA[] oldTransitions = tripleTransitions.labels
.getCopyOfTransitions();
StatePDA[] oldStates = tripleTransitions.finalities;
TransitionPDA t;
StatePDA s;
int j, n, tr;
for (i = 0; i < statesStored; i++) {
n = stateNumberOfTransitions.elementAt(i);
for (j = 0; j < n; j++) {
tr = stateTransitions[i] + j;
t = oldTransitions[transitionsLabel.elementAt(tr) - 1];
fsmStates[i].addTransition(
new TransitionPDA(t.getConstraints(),
fsmStates[transitionsTo[tr]], t.getType()),
null);
}
n = stateFinalities.elementAt(i);
if (n == Constants.NO) {
continue;
}
s = oldStates[n];
fsmStates[i].setAction(s.getAction(), null);
fsmStates[i].setFileIndex(s.getFileIndex());
fsmStates[i].setPriority(s.getPriority());
fsmStates[i].setItFinal(null);
}
return fsmStates;
}
}