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);
}
}
}