/** Legal as long as there is at least one item on the state's stack. */ public boolean isLegal(State state, List<ParserConstraint> constraints) { if (state.finished) { return false; } if (state.stack.size() == 0) { return false; } Tree top = state.stack.peek(); if (top.label().value().equals(label)) { // Disallow unary transitions where the label doesn't change return false; } if (top.label().value().startsWith("@") && !label.equals(top.label().value().substring(1))) { return false; } if (top.children().length == 1) { Tree child = top.children()[0]; if (child.children().length == 1) { Tree grandChild = child.children()[0]; if (grandChild.children().length == 1) { // Three consecutive unary trees. Not legal to keep adding unaries. // TODO: do preterminals count in that equation? return false; } } } if (isRoot && (state.stack.size() > 1 || !state.endOfQueue())) { return false; } // UnaryTransition actually doesn't care about the constraints. // If the constraint winds up unsatisfied, we'll get stuck and // have to do an "emergency transition" to fix the situation. return true; }
private boolean parseInternal() { final int maxBeamSize = Math.max(parser.op.testOptions().beamSize, 1); success = true; unparsable = false; PriorityQueue<State> beam = new PriorityQueue<>(maxBeamSize + 1, ScoredComparator.ASCENDING_COMPARATOR); beam.add(initialState); // TODO: don't construct as many PriorityQueues while (beam.size() > 0) { // System.err.println("================================================"); // System.err.println("Current beam:"); // System.err.println(beam); PriorityQueue<State> oldBeam = beam; beam = new PriorityQueue<>(maxBeamSize + 1, ScoredComparator.ASCENDING_COMPARATOR); State bestState = null; for (State state : oldBeam) { Collection<ScoredObject<Integer>> predictedTransitions = parser.model.findHighestScoringTransitions(state, true, maxBeamSize, constraints); // System.err.println("Examining state: " + state); for (ScoredObject<Integer> predictedTransition : predictedTransitions) { Transition transition = parser.model.transitionIndex.get(predictedTransition.object()); State newState = transition.apply(state, predictedTransition.score()); // System.err.println(" Transition: " + transition + " (" + predictedTransition.score() + // ")"); if (bestState == null || bestState.score() < newState.score()) { bestState = newState; } beam.add(newState); if (beam.size() > maxBeamSize) { beam.poll(); } } } if (beam.size() == 0) { // Oops, time for some fallback plan // This can happen with the set of constraints given by the original paper // For example, one particular French model had a situation where it would reach // @Ssub @Ssub . // without a left(Ssub) transition, so finishing the parse was impossible. // This will probably result in a bad parse, but at least it // will result in some sort of parse. for (State state : oldBeam) { Transition transition = parser.model.findEmergencyTransition(state, constraints); if (transition != null) { State newState = transition.apply(state); if (bestState == null || bestState.score() < newState.score()) { bestState = newState; } beam.add(newState); } } } // bestState == null only happens when we have failed to make progress, so quit // If the bestState is finished, we are done if (bestState == null || bestState.isFinished()) { break; } } List<State> bestParses; if (beam.size() == 0) { success = false; unparsable = true; debinarized = null; finalState = null; bestParses = Collections.emptyList(); } else { // TODO: filter out beam elements that aren't finished bestParses = Generics.newArrayList(beam); Collections.sort(bestParses, beam.comparator()); Collections.reverse(bestParses); finalState = bestParses.get(0); debinarized = debinarizer.transformTree(finalState.stack.peek()); debinarized = Tsurgeon.processPattern( rearrangeFinalPunctuationTregex, rearrangeFinalPunctuationTsurgeon, debinarized); } return success; }