package edu.stanford.nlp.trees; import edu.stanford.nlp.ling.CoreLabel; import edu.stanford.nlp.ling.HasWord; import edu.stanford.nlp.ling.Label; import edu.stanford.nlp.util.XMLUtils; /** * An individual dependency between a head and a dependent. * The head and dependent are represented as a Label. * For example, these can be a * Word or a WordTag. If one wishes the dependencies to preserve positions * in a sentence, then each can be a LabeledConstituent. * * @author Christopher Manning * @author Spence Green * */ public class UnnamedDependency implements Dependency<Label, Label, Object> { private static final long serialVersionUID = -3768440215342256085L; // We store the text of the labels separately because it looks like // it is possible for an object to request a hash code using itself // in a partially reconstructed state when unserializing. For // example, a TreeGraphNode might ask for the hash code of an // UnnamedDependency, which then uses an unfilled member of the same // TreeGraphNode to get the hash code. Keeping the text of the // labels breaks that possible cycle. protected final String regentText; protected final String dependentText; private final Label regent; private final Label dependent; public UnnamedDependency(String regent, String dependent) { if (regent == null || dependent == null) { throw new IllegalArgumentException("governor or dependent cannot be null"); } CoreLabel headLabel = new CoreLabel(); headLabel.setValue(regent); headLabel.setWord(regent); this.regent = headLabel; CoreLabel depLabel = new CoreLabel(); depLabel.setValue(dependent); depLabel.setWord(dependent); this.dependent = depLabel; regentText = regent; dependentText = dependent; } public UnnamedDependency(Label regent, Label dependent) { if (regent == null || dependent == null) { throw new IllegalArgumentException("governor or dependent cannot be null"); } this.regent = regent; this.dependent = dependent; regentText = getText(regent); dependentText = getText(dependent); } public Label governor() { return regent; } public Label dependent() { return dependent; } public Object name() { return null; } protected String getText(Label label) { if (label instanceof HasWord) { String word = ((HasWord) label).word(); if (word != null) { return word; } } return label.value(); } @Override public int hashCode() { return regentText.hashCode() ^ dependentText.hashCode(); } @Override public boolean equals(Object o) { return equalsIgnoreName(o); } public boolean equalsIgnoreName(Object o) { if (this == o) { return true; } else if( !(o instanceof UnnamedDependency)) { return false; } UnnamedDependency d = (UnnamedDependency) o; String thisHeadWord = regentText; String thisDepWord = dependentText; String headWord = d.regentText; String depWord = d.dependentText; return thisHeadWord.equals(headWord) && thisDepWord.equals(depWord); } @Override public String toString() { return String.format("%s --> %s", regentText, dependentText); } /** * Provide different printing options via a String keyword. * The recognized options are currently "xml", and "predicate". * Otherwise the default toString() is used. */ public String toString(String format) { switch (format) { case "xml": return " <dep>\n <governor>" + XMLUtils.escapeXML(governor().value()) + "</governor>\n <dependent>" + XMLUtils.escapeXML(dependent().value()) + "</dependent>\n </dep>"; case "predicate": return "dep(" + governor() + "," + dependent() + ")"; default: return toString(); } } public DependencyFactory dependencyFactory() { return DependencyFactoryHolder.df; } public static DependencyFactory factory() { return DependencyFactoryHolder.df; } // extra class guarantees correct lazy loading (Bloch p.194) private static class DependencyFactoryHolder { private static final DependencyFactory df = new UnnamedDependencyFactory(); } /** * A <code>DependencyFactory</code> acts as a factory for creating objects * of class <code>Dependency</code> */ private static class UnnamedDependencyFactory implements DependencyFactory { /** * Create a new <code>Dependency</code>. */ public Dependency<Label, Label, Object> newDependency(Label regent, Label dependent) { return newDependency(regent, dependent, null); } /** * Create a new <code>Dependency</code>. */ public Dependency<Label, Label, Object> newDependency(Label regent, Label dependent, Object name) { return new UnnamedDependency(regent, dependent); } } }