morfologik.fsa.builders.FSAInfo Maven / Gradle / Ivy
package morfologik.fsa.builders;
import java.util.BitSet;
import morfologik.fsa.FSA;
import morfologik.fsa.FSA5;
import com.carrotsearch.hppc.IntIntHashMap;
/**
* Compute additional information about an FSA: number of arcs, nodes, etc.
*/
public final class FSAInfo {
/**
* Computes the exact number of states and nodes by recursively traversing the FSA.
*/
private static class NodeVisitor {
final BitSet visitedArcs = new BitSet();
final BitSet visitedNodes = new BitSet();
int nodes;
int arcs;
int totalArcs;
private final FSA fsa;
NodeVisitor(FSA fsa) {
this.fsa = fsa;
}
public void visitNode(final int node) {
if (visitedNodes.get(node)) {
return;
}
visitedNodes.set(node);
nodes++;
for (int arc = fsa.getFirstArc(node); arc != 0; arc = fsa.getNextArc(arc)) {
if (!visitedArcs.get(arc)) {
arcs++;
}
totalArcs++;
visitedArcs.set(arc);
if (!fsa.isArcTerminal(arc)) {
visitNode(fsa.getEndNode(arc));
}
}
}
}
/**
* Computes the exact number of final states.
*/
private static class FinalStateVisitor {
final IntIntHashMap visitedNodes = new IntIntHashMap();
private final FSA fsa;
FinalStateVisitor(FSA fsa) {
this.fsa = fsa;
}
public int visitNode(int node) {
int index = visitedNodes.indexOf(node);
if (index >= 0) {
return visitedNodes.indexGet(index);
}
int fromHere = 0;
for (int arc = fsa.getFirstArc(node); arc != 0; arc = fsa.getNextArc(arc)) {
if (fsa.isArcFinal(arc))
fromHere++;
if (!fsa.isArcTerminal(arc)) {
fromHere += visitNode(fsa.getEndNode(arc));
}
}
visitedNodes.put(node, fromHere);
return fromHere;
}
}
/**
* Number of nodes in the automaton.
*/
public final int nodeCount;
/**
* Number of arcs in the automaton, excluding an arcs from the zero node (initial) and an arc from the start node to
* the root node.
*/
public final int arcsCount;
/**
* Total number of arcs, counting arcs that physically overlap due to merging.
*/
public final int arcsCountTotal;
/**
* Number of final states (number of input sequences stored in the automaton).
*/
public final int finalStatesCount;
/**
* Arcs size (in serialized form).
*/
public final int size;
/*
*
*/
public FSAInfo(FSA fsa) {
final NodeVisitor w = new NodeVisitor(fsa);
int root = fsa.getRootNode();
if (root > 0) {
w.visitNode(root);
}
this.nodeCount = 1 + w.nodes;
this.arcsCount = 1 + w.arcs;
this.arcsCountTotal = 1 + w.totalArcs;
final FinalStateVisitor fsv = new FinalStateVisitor(fsa);
this.finalStatesCount = fsv.visitNode(fsa.getRootNode());
if (fsa instanceof FSA5) {
this.size = ((FSA5) fsa).arcs.length;
} else {
this.size = 0;
}
}
/*
*
*/
public FSAInfo(int nodeCount, int arcsCount, int arcsCountTotal, int finalStatesCount) {
this.nodeCount = nodeCount;
this.arcsCount = arcsCount;
this.arcsCountTotal = arcsCountTotal;
this.finalStatesCount = finalStatesCount;
this.size = 0;
}
/*
*
*/
@Override
public String toString() {
return "Nodes: " + nodeCount + ", arcs visited: " + arcsCount + ", arcs total: " + arcsCountTotal
+ ", final states: " + finalStatesCount + ", size: " + size;
}
}