package edu.stanford.nlp.semgraph;
import java.io.IOException;
import java.io.StringReader;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import junit.framework.TestCase;
import edu.stanford.nlp.ling.IndexedWord;
import edu.stanford.nlp.trees.EnglishGrammaticalRelations;
import edu.stanford.nlp.trees.LabeledScoredTreeFactory;
import edu.stanford.nlp.trees.PennTreeReader;
import edu.stanford.nlp.trees.Tree;
import edu.stanford.nlp.util.Generics;
/**
*
* @author David McClosky
*/
public class SemanticGraphTest extends TestCase {
private SemanticGraph graph;
@Override
public void setUp() {
synchronized(SemanticGraphTest.class) {
if (graph == null) {
graph = makeGraph();
}
}
}
private static SemanticGraph makeGraph() {
Tree tree;
try {
tree = new PennTreeReader(new StringReader("(S1 (S (S (S (NP (DT The) (NN CD14) (NN LPS) (NN receptor)) (VP (VBZ is) (, ,) (ADVP (RB however)) (, ,) (ADVP (RB up)) (VP (VBN regulated) (PRN (-LRB- -LRB-) (FRAG (RB not) (ADJP (RB down) (VBN regulated))) (-RRB- -RRB-)) (PP (IN in) (NP (JJ tolerant) (NNS cells)))))) (, ,) (CC and) (S (NP (NN LPS)) (VP (MD can) (, ,) (PP (IN in) (NP (NN fact))) (, ,) (ADVP (RB still)) (VP (VB lead) (PP (TO to) (NP (NP (NN activation)) (PP (IN of) (NP (JJ tolerant) (NNS cells))))) (SBAR (IN as) (S (VP (VBN evidenced) (PP (IN by) (NP (NP (NN mobilization)) (PP (IN of) (NP (DT the) (NN transcription) (NN factor) (NP (NP (JJ nuclear) (NN factor) (NN kappa) (NN B)) (PRN (-LRB- -LRB-) (NP (NN NF-kappa) (NN B)) (-RRB- -RRB-)))))))))))))) (. .)))"),
new LabeledScoredTreeFactory()).readTree();
} catch (IOException e) {
// the tree should parse correctly
throw new RuntimeException(e);
}
return SemanticGraphFactory.makeFromTree(tree, SemanticGraphFactory.Mode.BASIC, true, true);
}
public void testShortestPath() {
//graph.prettyPrint();
IndexedWord word1 = graph.getNodeByIndex(10);
IndexedWord word2 = graph.getNodeByIndex(14);
// System.out.println("word1: " + word1);
// System.out.println("word1: " + word1.hashCode());
// System.out.println("word2: " + word2);
// System.out.println("word2: " + word2.hashCode());
// System.out.println("word eq: " + word1.equals(word2));
// System.out.println("word eq: " + (word1.hashCode() == word2.hashCode()));
// System.out.println("word eq: " + (word1.toString().equals(word2.toString())));
List<SemanticGraphEdge> edges =
graph.getShortestUndirectedPathEdges(word1, word2);
// System.out.println("path: " + edges);
assertNotNull(edges);
List<IndexedWord> nodes =
graph.getShortestUndirectedPathNodes(word1, word2);
// System.out.println("path: " + nodes);
assertNotNull(nodes);
assertEquals(word1, nodes.get(0));
assertEquals(word2, nodes.get(nodes.size() - 1));
edges = graph.getShortestUndirectedPathEdges(word1, word1);
// System.out.println("path: " + edges);
assertNotNull(edges);
assertEquals(0, edges.size());
nodes = graph.getShortestUndirectedPathNodes(word1, word1);
// System.out.println("path: " + nodes);
assertNotNull(nodes);
assertEquals(1, nodes.size());
assertEquals(word1, nodes.get(0));
}
public void testGetCommonAncestor(){
IndexedWord common = graph.getCommonAncestor(graph.getNodeByIndex(43), graph.getNodeByIndex(44));
assertEquals(45, common.index());
common = graph.getCommonAncestor(graph.getNodeByIndex(41), graph.getNodeByIndex(39));
assertEquals(41, common.index());
common = graph.getCommonAncestor(graph.getNodeByIndex(39), graph.getNodeByIndex(41));
assertEquals(41, common.index());
common = graph.getCommonAncestor(graph.getNodeByIndex(40), graph.getNodeByIndex(42));
assertEquals(41, common.index());
// too far for this method
common = graph.getCommonAncestor(graph.getNodeByIndex(10), graph.getNodeByIndex(42));
assertEquals(null, common);
common = graph.getCommonAncestor(graph.getNodeByIndex(10), graph.getNodeByIndex(10));
assertEquals(10, common.index());
common = graph.getCommonAncestor(graph.getNodeByIndex(40), graph.getNodeByIndex(40));
assertEquals(40, common.index());
// a couple tests at the top of the graph
common = graph.getCommonAncestor(graph.getNodeByIndex(10), graph.getNodeByIndex(1));
assertEquals(10, common.index());
common = graph.getCommonAncestor(graph.getNodeByIndex(1), graph.getNodeByIndex(10));
assertEquals(10, common.index());
}
public void testCommonAncestor(){
assertEquals(1, graph.commonAncestor(graph.getNodeByIndex(43), graph.getNodeByIndex(44)));
assertEquals(1, graph.commonAncestor(graph.getNodeByIndex(41), graph.getNodeByIndex(39)));
assertEquals(1, graph.commonAncestor(graph.getNodeByIndex(39), graph.getNodeByIndex(41)));
assertEquals(2, graph.commonAncestor(graph.getNodeByIndex(40), graph.getNodeByIndex(42)));
assertEquals(2, graph.commonAncestor(graph.getNodeByIndex(42), graph.getNodeByIndex(40)));
// too far for this method
assertEquals(-1, graph.commonAncestor(graph.getNodeByIndex(10), graph.getNodeByIndex(42)));
// assertEquals(null, common);
assertEquals(0, graph.commonAncestor(graph.getNodeByIndex(10), graph.getNodeByIndex(10)));
assertEquals(0, graph.commonAncestor(graph.getNodeByIndex(40), graph.getNodeByIndex(40)));
// assertEquals(40, common.index());
// a couple tests at the top of the graph
assertEquals(2, graph.commonAncestor(graph.getNodeByIndex(10), graph.getNodeByIndex(1)));
assertEquals(2, graph.commonAncestor(graph.getNodeByIndex(1), graph.getNodeByIndex(10)));
}
public void testTopologicalSort() {
SemanticGraph gr = SemanticGraph.valueOf("[ate subj:Bill dobj:[muffins nn:blueberry]]");
verifyTopologicalSort(gr);
List<IndexedWord> vertices = gr.vertexListSorted();
gr.addEdge(vertices.get(1), vertices.get(2), EnglishGrammaticalRelations.DIRECT_OBJECT, 1.0, false);
verifyTopologicalSort(gr);
gr = SemanticGraph.valueOf("[ate subj:Bill dobj:[muffins nn:blueberry]]");
vertices = gr.vertexListSorted();
gr.addEdge(vertices.get(2), vertices.get(1), EnglishGrammaticalRelations.DIRECT_OBJECT, 1.0, false);
verifyTopologicalSort(gr);
gr = SemanticGraph.valueOf("[ate subj:Bill dobj:[muffins nn:blueberry]]");
vertices = gr.vertexListSorted();
gr.addEdge(vertices.get(1), vertices.get(3), EnglishGrammaticalRelations.DIRECT_OBJECT, 1.0, false);
verifyTopologicalSort(gr);
// now create a graph with a directed loop, which we should not
// be able to topologically sort
gr = SemanticGraph.valueOf("[ate subj:Bill dobj:[muffins nn:blueberry]]");
vertices = gr.vertexListSorted();
gr.addEdge(vertices.get(3), vertices.get(0), EnglishGrammaticalRelations.DIRECT_OBJECT, 1.0, false);
try {
verifyTopologicalSort(gr);
throw new RuntimeException("Expected to fail");
} catch (IllegalStateException e) {
// yay, correctly caught error
}
}
/**
* Tests that a particular topological sort is correct by verifying
* for each node that it appears in the sort and all of its children
* occur later in the sort
*/
private static void verifyTopologicalSort(SemanticGraph graph) {
List<IndexedWord> sorted = graph.topologicalSort();
Map<IndexedWord, Integer> indices = Generics.newHashMap();
for (int index = 0; index < sorted.size(); ++index) {
indices.put(sorted.get(index), index);
}
for (IndexedWord parent : graph.vertexSet()) {
assertTrue(indices.containsKey(parent));
int parentIndex = indices.get(parent);
for (IndexedWord child : graph.getChildren(parent)) {
assertTrue(indices.containsKey(child));
int childIndex = indices.get(child);
assertTrue(parentIndex < childIndex);
}
}
}
public void testGetPathToRoot() {
verifyPath(graph.getPathToRoot(graph.getNodeByIndex(1)), 4, 10);
verifyPath(graph.getPathToRoot(graph.getNodeByIndex(10))); // empty path
verifyPath(graph.getPathToRoot(graph.getNodeByIndex(34)), 35, 28, 10);
}
private static void verifyPath(List<IndexedWord> path, int ... expected) {
assertEquals(expected.length, path.size());
for (int i = 0; i < expected.length; ++i) {
assertEquals(expected[i], path.get(i).index());
}
}
public void testGetSiblings() {
verifySet(graph.getSiblings(graph.getNodeByIndex(43)), 42, 44, 48);
verifySet(graph.getSiblings(graph.getNodeByIndex(10))); // empty set
verifySet(graph.getSiblings(graph.getNodeByIndex(42)), 43, 44, 48);
}
private static void verifySet(Collection<IndexedWord> nodes, int ... expected) {
Set<Integer> results = Generics.newTreeSet();
for (IndexedWord node : nodes) {
results.add(node.index());
}
Set<Integer> expectedIndices = Generics.newTreeSet();
for (Integer index : expected) {
expectedIndices.add(index);
}
assertEquals(expectedIndices, results);
}
public void testIsAncestor() {
//System.err.println(graph.toString(CoreLabel.VALUE_TAG_INDEX_FORMAT));
assertEquals(1, graph.isAncestor(graph.getNodeByIndex(42), graph.getNodeByIndex(45)));
assertEquals(2, graph.isAncestor(graph.getNodeByIndex(40), graph.getNodeByIndex(38)));
assertEquals(-1, graph.isAncestor(graph.getNodeByIndex(40), graph.getNodeByIndex(37)));
assertEquals(-1, graph.isAncestor(graph.getNodeByIndex(40), graph.getNodeByIndex(10)));
assertEquals(-1, graph.isAncestor(graph.getNodeByIndex(45), graph.getNodeByIndex(42)));
}
public void testHasChildren() {
SemanticGraph gr = SemanticGraph.valueOf("[ate subj:Bill dobj:[muffins nn:blueberry]]");
List<IndexedWord> vertices = gr.vertexListSorted();
for (IndexedWord word : vertices) {
if (word.word().equals("ate") || word.word().equals("muffins")) {
assertTrue(gr.hasChildren(word));
} else {
assertFalse(gr.hasChildren(word));
}
}
}
}