All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.stanford.nlp.parser.shiftreduce.BinaryTransition Maven / Gradle / Ivy

Go to download

Stanford CoreNLP provides a set of natural language analysis tools which can take raw English language text input and give the base forms of words, their parts of speech, whether they are names of companies, people, etc., normalize dates, times, and numeric quantities, mark up the structure of sentences in terms of phrases and word dependencies, and indicate which noun phrases refer to the same entities. It provides the foundational building blocks for higher level text understanding applications.

There is a newer version: 4.5.7
Show newest version
package edu.stanford.nlp.parser.shiftreduce;

import java.util.List;

import edu.stanford.nlp.ling.CoreLabel;
import edu.stanford.nlp.parser.common.ParserConstraint;
import edu.stanford.nlp.trees.LabeledScoredTreeNode;
import edu.stanford.nlp.trees.Tree;
import edu.stanford.nlp.trees.TreeCoreAnnotations;
import edu.stanford.nlp.util.TreeShapedStack;

/**
 * Transition that makes a binary parse node in a partially finished tree.
 */
public class BinaryTransition implements Transition {
  public final String label;

  /** Which side the head is on */
  public final Side side;

  public enum Side {
    LEFT, RIGHT
  }

  public BinaryTransition(String label, Side side) {
    this.label = label;
    this.side = side;
  }

  /**
   * Legal as long as there are at least two items on the state's stack.
   */
  public boolean isLegal(State state, List constraints) {
    // some of these quotes come directly from Zhang Clark 09
    if (state.finished) {
      return false;
    }
    if (state.stack.size() <= 1) {
      return false;
    }
    // at least one of the two nodes on top of stack must be non-temporary
    if (ShiftReduceUtils.isTemporary(state.stack.peek()) && ShiftReduceUtils.isTemporary(state.stack.pop().peek())) {
      return false;
    }
    if (ShiftReduceUtils.isTemporary(state.stack.peek())) {
      if (side == Side.LEFT) {
        return false;
      }
      if (!ShiftReduceUtils.isEquivalentCategory(label, state.stack.peek().value())) {
        return false;
      }
    }
    if (ShiftReduceUtils.isTemporary(state.stack.pop().peek())) {
      if (side == Side.RIGHT) {
        return false;
      }
      if (!ShiftReduceUtils.isEquivalentCategory(label, state.stack.pop().peek().value())) {
        return false;
      }
    }
    // don't allow binarized labels if it makes the state have a stack
    // of size 1 and a queue of size 0
    if (state.stack.size() == 2 && isBinarized() && state.endOfQueue()) {
      return false;
    }
    // when the stack contains only two nodes, temporary resulting
    // nodes from binary reduce must be left-headed
    if (state.stack.size() == 2 && isBinarized() && side == Side.RIGHT) {
      return false;
    }
    // when the queue is empty and the stack contains more than two
    // nodes, with the third node from the top being temporary, binary
    // reduce can be applied only if the resulting node is non-temporary
    if (state.endOfQueue() && state.stack.size() > 2 && ShiftReduceUtils.isTemporary(state.stack.pop().pop().peek()) && isBinarized()) {
      return false;
    }
    // when the stack contains more than two nodes, with the third
    // node from the top being temporary, temporary resulting nodes
    // from binary reduce must be left-headed
    if (state.stack.size() > 2 && ShiftReduceUtils.isTemporary(state.stack.pop().pop().peek()) && isBinarized() && side == Side.RIGHT) {
      return false;
    }

    if (constraints == null) {
      return true;
    }

    final Tree top = state.stack.peek();
    final int leftTop = ShiftReduceUtils.leftIndex(top);
    final int rightTop = ShiftReduceUtils.rightIndex(top);
    final Tree next = state.stack.pop().peek();
    final int leftNext = ShiftReduceUtils.leftIndex(next);
    // The binary transitions are affected by constraints in the
    // following two circumstances.  If a transition would cross the
    // left boundary of a constraint, that is illegal.  If the
    // transition is exactly the right size for the constraint and
    // would make a temporary node, that is also illegal.
    for (ParserConstraint constraint : constraints) {
      if (leftTop == constraint.start) {
        // can't binary reduce away from a tree which doesn't match a constraint
        if (rightTop == constraint.end - 1) {
          if (!ShiftReduceUtils.constraintMatchesTreeTop(top, constraint)) {
            return false;
          } else {
            continue;
          }
        } else if (rightTop >= constraint.end) {
          continue;
        } else {
          // can't binary reduce if it would make the tree cross the left boundary
          return false;
        }
      }
      // top element is further left than the constraint, so
      // there's no harm to be done by binary reduce
      if (leftTop < constraint.start) {
        continue;
      }
      // top element is past the end of the constraint, so it must already be satisfied
      if (leftTop >= constraint.end) {
        continue;
      }
      // now leftTop > constraint.start and < constraint.end, eg inside the constraint
      // the next case is no good because it crosses the boundary
      if (leftNext < constraint.start) {
        return false;
      }
      if (leftNext > constraint.start) {
        continue;
      }
      // can't transition to a binarized node when there's a constraint that matches.
      if (rightTop == constraint.end - 1 && isBinarized()) {
        return false;
      }
    }

    return true;
  }

  public boolean isBinarized() {
    return (label.charAt(0) == '@');
  }

  /**
   * Add a binary node to the existing node on top of the stack
   */
  public State apply(State state) {
    return apply(state, 0.0);
  }

  /**
   * Add a binary node to the existing node on top of the stack
   */
  public State apply(State state, double scoreDelta) {
    TreeShapedStack stack = state.stack;
    Tree right = stack.peek();
    stack = stack.pop();
    Tree left = stack.peek();
    stack = stack.pop();

    Tree head;
    switch(side) {
    case LEFT:
      head = left;
      break;
    case RIGHT:
      head = right;
      break;
    default:
      throw new IllegalArgumentException("Unknown side " + side);
    }

    if (!(head.label() instanceof CoreLabel)) {
      throw new IllegalArgumentException("Stack should have CoreLabel nodes");
    }
    CoreLabel headLabel = (CoreLabel) head.label();

    CoreLabel production = new CoreLabel();
    production.setValue(label);
    production.set(TreeCoreAnnotations.HeadWordLabelAnnotation.class, headLabel.get(TreeCoreAnnotations.HeadWordLabelAnnotation.class));
    production.set(TreeCoreAnnotations.HeadTagLabelAnnotation.class, headLabel.get(TreeCoreAnnotations.HeadTagLabelAnnotation.class));
    Tree newTop = new LabeledScoredTreeNode(production);
    newTop.addChild(left);
    newTop.addChild(right);

    stack = stack.push(newTop);

    return new State(stack, state.transitions.push(this), state.separators, state.sentence, state.tokenPosition, state.score + scoreDelta, false);    
  }

  @Override
  public boolean equals(Object o) {
    if (o == this) {
      return true;
    }
    if (!(o instanceof BinaryTransition)) {
      return false;
    }
    String otherLabel = ((BinaryTransition) o).label;
    Side otherSide = ((BinaryTransition) o).side;
    return otherSide.equals(side) && label.equals(otherLabel);
  }

  @Override
  public int hashCode() {
    // TODO: fix the hashcode for the side?  would require rebuilding all models
    switch(side) {
    case LEFT:
      return 97197711 ^ label.hashCode();
    case RIGHT:
      return 97197711 ^ label.hashCode();
    default:
      throw new IllegalArgumentException("Unknown side " + side);
    }
  }

  @Override
  public String toString() {
    switch(side) {
    case LEFT:
      return "LeftBinary(" + label + ")";
    case RIGHT:
      return "RightBinary(" + label + ")";
    default:
      throw new IllegalArgumentException("Unknown side " + side);
    }
  }

  private static final long serialVersionUID = 1;  
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy