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

edu.stanford.nlp.semgraph.semgrex.CoordinationPattern 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.semgraph.semgrex; 
import edu.stanford.nlp.util.logging.Redwood;

import java.util.*;

import edu.stanford.nlp.ling.IndexedWord;
import edu.stanford.nlp.semgraph.SemanticGraph;

/** @author Chloe Kiddon */
public class CoordinationPattern extends SemgrexPattern  {

  /** A logger for this class */
  private static Redwood.RedwoodChannels log = Redwood.channels(CoordinationPattern.class);

  /**
   * 
   */
  private static final long serialVersionUID = -3122330899634961002L;
  private boolean isConj;
  private boolean isNodeCoord;
  private List children;

  /* if isConj is true, then it is an "AND" ; if it is false, it is an "OR".*/
  /* if isNodeCoord is true, then it is a node coordination conj; if it is false, then
           * 	it is a relation coordination conj. */
  public CoordinationPattern(boolean isNodeCoord, List children, boolean isConj) {
    if (children.size() < 2) {
      throw new RuntimeException("Coordination node must have at least 2 children.");
    }
    this.children = children;
    this.isConj = isConj;
    this.isNodeCoord = isNodeCoord;
  }

  public boolean isNodeCoord() { return isNodeCoord; }

  @Override
  public void setChild(SemgrexPattern child) {
    if (isNodeCoord) {
      for (Object c : children) {
        if (c instanceof NodePattern)
          ((NodePattern)c).setChild(child);
      }
    } else {

    }
  }

  public void addRelnToNodeCoord(SemgrexPattern child) {
    if (isNodeCoord) {
      for (SemgrexPattern c : children) {
        List newChildren = new ArrayList<>();
        newChildren.addAll(c.getChildren());
        newChildren.add(child);
        c.setChild(new CoordinationPattern(false, newChildren, true));
      }
    }
  }

  @Override
  public List getChildren() {
    return children;
  }

  @Override
  public String localString() {
    StringBuilder sb = new StringBuilder();
    if (isNegated()) {
      sb.append('!');
    }
    if (isOptional()) {
      sb.append('?');
    }
    sb.append((isConj ? "and" : "or"));
    sb.append(" ");
    sb.append((isNodeCoord ? "node coordination" : "reln coordination"));
    return sb.toString();
  }

  @Override
  public String toString() {
    return toString(true);
  }

  @Override
  public String toString(boolean hasPrecedence) {
    StringBuilder sb = new StringBuilder();
    if (isConj) {
      for (SemgrexPattern node : children) {
        sb.append(node.toString());
      }
    } else {
      sb.append('[');
      for (Iterator iter = children.iterator(); iter.hasNext();) {
        SemgrexPattern node = iter.next();
        sb.append(node.toString());
        if (iter.hasNext()) {
          sb.append(" |");
        }
      }
      sb.append(']');
    }
    return sb.toString();
  }

  @Override
  public SemgrexMatcher matcher(SemanticGraph sg, IndexedWord node,
                                Map namesToNodes, 
                                Map namesToRelations,
                                VariableStrings variableStrings, 
                                boolean ignoreCase) {
    return new CoordinationMatcher(this, sg, null, null, true, node, 
                                   namesToNodes, namesToRelations,
                                   variableStrings, ignoreCase);
  }

  @Override
  public SemgrexMatcher matcher(SemanticGraph sg, 
                                Alignment alignment, SemanticGraph sg_align,
                                boolean hypToText, IndexedWord node, 
                                Map namesToNodes,
                                Map namesToRelations, 
                                VariableStrings variableStrings, 
                                boolean ignoreCase) {
    return new CoordinationMatcher(this, sg, alignment, sg_align, 
                                   hypToText, node,
                                   namesToNodes, namesToRelations, 
                                   variableStrings, ignoreCase);
  }


  private static class CoordinationMatcher extends SemgrexMatcher {
    private SemgrexMatcher[] children;
    private final CoordinationPattern myNode;
    private int currChild;
    private final boolean considerAll;
    private IndexedWord nextNodeMatch = null;
    // do all con/dis-juncts have to be considered to determine a match?
    // i.e. true if conj and not negated or disj and negated

    public CoordinationMatcher(CoordinationPattern c, SemanticGraph sg, Alignment alignment,
                               SemanticGraph sg_align, boolean hypToText, IndexedWord n,
                               Map namesToNodes,
                               Map namesToRelations, VariableStrings variableStrings,
                               boolean ignoreCase) {
      super(sg, alignment, sg_align, hypToText, n, namesToNodes, namesToRelations, variableStrings);
      myNode = c;
      children = new SemgrexMatcher[myNode.children.size()];
      for (int i = 0; i < children.length; i++) {
        SemgrexPattern node = myNode.children.get(i);
        children[i] = node.matcher(sg, alignment, sg_align, hypToText,
                                   n, namesToNodes,
                                   namesToRelations, variableStrings, ignoreCase);
      }
      currChild = 0;
      considerAll = myNode.isConj ^ myNode.isNegated();
    }

    @Override
    void resetChildIter() {
      currChild = 0;
      for (SemgrexMatcher aChildren : children) {
        aChildren.resetChildIter();
      }
      nextNodeMatch = null;
    }

    @Override
    void resetChildIter(IndexedWord node) {
      // this.tree = node;
      currChild = 0;
      for (SemgrexMatcher aChildren : children) {
        aChildren.resetChildIter(node);
      }
    }

    // find the next local match
    @Override
    public boolean matches() {  // also known as "FUN WITH LOGIC"

      //log.info(myNode.toString());
      //log.info("consider all: " + considerAll);
      if (considerAll) {
        // these are the cases where all children must be considered to match
        if (currChild < 0) {
          // a past call to this node either got that it failed
          // matching or that it was a negative match that succeeded,
          // which we only want to accept once
          return myNode.isOptional();
        }

        // we must have happily reached the end of a match the last
        // time we were here
        if (currChild == children.length) {
          --currChild;
        }

        while (true) {
          if (myNode.isNegated() != children[currChild].matches()) {
            // This node is set correctly.  Move on to the next node
            ++currChild;

            if (currChild == children.length) {
              // yay, all nodes matched.
              if (myNode.isNegated()) {
                // a negated node should only match once (before being reset)
                currChild = -1;
              } else if (myNode.isNodeCoord) {
                nextNodeMatch = children[0].getMatch();
              }
              return true;
            }
          } else {
            // oops, this didn't work.
            children[currChild].resetChildIter();
            // go backwards to see if we can continue matching from an
            // earlier location.
            // TODO: perhaps there should be a version where we only
            // care about new assignments to the root, or new
            // assigments to the root and variables, in which case we
            // could make use of getChangesVariables() to optimize how
            // many nodes we can skip past
            --currChild;
            if (currChild < 0) {
              return myNode.isOptional();
            }
          }
        }
      } else { // these are the cases where a single child node can make you match
        for (; currChild < children.length; currChild++) {
          //   	namesToNodes.putAll(namesToNodesOld);
          //    namesToRelations.putAll(namesToRelationsOld);
          if (myNode.isNegated() != children[currChild].matches()) {
            // a negated node should only match once (before being reset)
            if (myNode.isNegated()) {
              currChild = children.length;
            }
            if (myNode.isNodeCoord)
              nextNodeMatch = children[currChild].getMatch();
            //    this.namesToNodes.putAll(children[currChild].namesToNodes);
            //   this.namesToRelations.putAll(children[currChild].namesToRelations);
            return true;
          }
          children[currChild].resetChildIter();
        }
        if (myNode.isNegated()) {
          currChild = children.length;
        }
        return myNode.isOptional();
      }
    }

    @Override
    public IndexedWord getMatch() {
      if (myNode.isNodeCoord && !myNode.isNegated()) {
        return nextNodeMatch;
      } else {
        throw new UnsupportedOperationException();
      }
    }

    @Override
    public String toString() {
      String ret = "coordinate matcher for: ";
      for (SemgrexMatcher child : children)
        ret += child.toString() + " ";
      return ret;
    }

  }



}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy