/** Returns true if, from this state, the automaton accepts any suffix * starting with a label between start and end, inclusive. We just * look for a transition, matching this range, to the sink state. */ private boolean acceptsSuffixRange(int state, int start, int end) { int count = automaton.initTransition(state, scratchTransition); for(int i=0;i<count;i++) { automaton.getNextTransition(scratchTransition); if (start >= scratchTransition.min && end <= scratchTransition.max && scratchTransition.dest == sinkState) { return true; } } return false; }
/** * Returns the list of terms that start at the provided state */ public Term[] getTerms(String field, int state) { int numT = det.initTransition(state, transition); List<Term> terms = new ArrayList<> (); for (int i = 0; i < numT; i++) { det.getNextTransition(transition); for (int id = transition.min; id <= transition.max; id++) { Term term = new Term(field, idToTerm.get(id)); terms.add(term); } } return terms.toArray(new Term[terms.size()]); }
/** * Checks whether there is a loop containing state. (This is sufficient since * there are never transitions to dead states.) */ // TODO: not great that this is recursive... in theory a // large automata could exceed java's stack so the maximum level of recursion is bounded to 1000 private static boolean isFinite(Transition scratch, Automaton a, int state, BitSet path, BitSet visited, int level) { if (level > MAX_RECURSION_LEVEL) { throw new IllegalArgumentException("input automaton is too large: " + level); } path.set(state); int numTransitions = a.initTransition(state, scratch); for(int t=0;t<numTransitions;t++) { a.getTransition(state, t, scratch); if (path.get(scratch.dest) || (!visited.get(scratch.dest) && !isFinite(scratch, a, scratch.dest, path, visited, level+1))) { return false; } } path.clear(state); visited.set(state); return true; }
public void setState(int state) { this.state = state; transitionIndex = 0; transitionCount = ite.automaton.getNumTransitions(state); if (transitionCount != 0) { ite.automaton.initTransition(state, transition); ite.automaton.getNextTransition(transition); } else { // Must set min to -1 so the "label < min" check never falsely triggers: transition.min = -1; // Must set max to -1 so we immediately realize we need to step to the next transition and then pop this frame: transition.max = -1; } }
/** Returns bitset marking states reachable from the initial state. */ private static BitSet getLiveStatesFromInitial(Automaton a) { int numStates = a.getNumStates(); BitSet live = new BitSet(numStates); if (numStates == 0) { return live; } ArrayDeque<Integer> workList = new ArrayDeque<>(); live.set(0); workList.add(0); Transition t = new Transition(); while (workList.isEmpty() == false) { int s = workList.removeFirst(); int count = a.initTransition(s, t); for(int i=0;i<count;i++) { a.getNextTransition(t); if (live.get(t.dest) == false) { live.set(t.dest); workList.add(t.dest); } } } return live; }
private static int topoSortStatesRecurse(Automaton a, BitSet visited, int[] states, int upto, int state, int level) { if (level > MAX_RECURSION_LEVEL) { throw new IllegalArgumentException("input automaton is too large: " + level); } Transition t = new Transition(); int count = a.initTransition(state, t); for (int i=0;i<count;i++) { a.getNextTransition(t); if (!visited.get(t.dest)) { visited.set(t.dest); upto = topoSortStatesRecurse(a, visited, states, upto, t.dest, level+1); } } states[upto] = state; upto++; return upto; } }
/** * Returns whether the provided state is the start of multiple side paths of different length (eg: new york, ny) */ public boolean hasSidePath(int state) { int numT = det.initTransition(state, transition); if (numT <= 1) { return false; } det.getNextTransition(transition); int dest = transition.dest; for (int i = 1; i < numT; i++) { det.getNextTransition(transition); if (dest != transition.dest) { return true; } } return false; }
private static void articulationPointsRecurse(Automaton a, int state, int d, int[] depth, int[] low, int[] parent, BitSet visited, List<Integer> points) { visited.set(state); depth[state] = d; low[state] = d; int childCount = 0; boolean isArticulation = false; Transition t = new Transition(); int numT = a.initTransition(state, t); for (int i = 0; i < numT; i++) { a.getNextTransition(t); if (visited.get(t.dest) == false) { parent[t.dest] = state; articulationPointsRecurse(a, t.dest, d + 1, depth, low, parent, visited, points); childCount++; if (low[t.dest] >= depth[state]) { isArticulation = true; } low[state] = Math.min(low[state], low[t.dest]); } else if (t.dest != parent[state]) { low[state] = Math.min(low[state], depth[t.dest]); } } if ((parent[state] != -1 && isArticulation) || (parent[state] == -1 && childCount > 1)) { points.add(state); } } }
b.append(" [shape=circle,label=\"" + state + "\"]\n"); int numTransitions = initTransition(state, t);
int count = a.initTransition(s, t); for(int i=0;i<count;i++) { a.getNextTransition(t); int count = a2.initTransition(s, t); for(int i=0;i<count;i++) { a2.getNextTransition(t);
return false; int count = a.initTransition(state, t); for(int i=0;i<count;i++) { a.getNextTransition(t);
/** * Returns the articulation points (or cut vertices) of the graph: * https://en.wikipedia.org/wiki/Biconnected_component */ public int[] articulationPoints() { if (det.getNumStates() == 0) { return new int[0]; } // Automaton.Builder undirect = new Automaton.Builder(); undirect.copy(det); for (int i = 0; i < det.getNumStates(); i++) { int numT = det.initTransition(i, transition); for (int j = 0; j < numT; j++) { det.getNextTransition(transition); undirect.addTransition(transition.dest, i, transition.min); } } int numStates = det.getNumStates(); BitSet visited = new BitSet(numStates); int[] depth = new int[det.getNumStates()]; int[] low = new int[det.getNumStates()]; int[] parent = new int[det.getNumStates()]; Arrays.fill(parent, -1); List<Integer> points = new ArrayList<>(); articulationPointsRecurse(undirect.finish(), 0, 0, depth, low, parent, visited, points); Collections.reverse(points); return points.stream().mapToInt(p -> p).toArray(); }
/** Add a [virtual] epsilon transition between source and dest. * Dest state must already have all transitions added because this * method simply copies those same transitions over to source. */ public void addEpsilon(int source, int dest) { Transition t = new Transition(); int count = initTransition(dest, t); for(int i=0;i<count;i++) { getNextTransition(t); addTransition(source, t.dest, t.min, t.max); } if (isAccept(dest)) { setAccept(source, true); } }
/** Returns sink state, if present, else -1. */ private static int findSinkState(Automaton automaton) { int numStates = automaton.getNumStates(); Transition t = new Transition(); int foundState = -1; for (int s=0;s<numStates;s++) { if (automaton.isAccept(s)) { int count = automaton.initTransition(s, t); boolean isSinkState = false; for(int i=0;i<count;i++) { automaton.getNextTransition(t); if (t.dest == s && t.min == 0 && t.max == 0xff) { isSinkState = true; break; } } if (isSinkState) { foundState = s; break; } } } return foundState; }
/** Copies over all states/transitions from other. */ public void copy(Automaton other) { int offset = getNumStates(); int otherNumStates = other.getNumStates(); // Copy all states copyStates(other); // Copy all transitions Transition t = new Transition(); for(int s=0;s<otherNumStates;s++) { int count = other.initTransition(s, t); for(int i=0;i<count;i++) { other.getNextTransition(t); addTransition(offset + s, offset + t.dest, t.min, t.max); } } }
int numTransitions = a.initTransition(i, t);
automaton.initTransition(state, transition); for (int i = 0; i < numTransitions; i++) { automaton.getNextTransition(transition);
int count = a.initTransition(0, t); for(int i=0;i<count;i++) { a.getNextTransition(t); for(int s=0;s<numStates;s++) { if (a.isAccept(s)) { count = a.initTransition(0, t); for(int i=0;i<count;i++) { a.getNextTransition(t);
for (int s=0;s<numStates;s++) { int numTransitions = a.getNumTransitions(s); a.initTransition(s, t); for(int i=0;i<numTransitions;i++) { a.getNextTransition(t);
for(int i=0;i<numStates;i++) { int maxi = Character.MIN_CODE_POINT; int count = a.initTransition(i, t); for(int j=0;j<count;j++) { a.getNextTransition(t);