001package org.maltparser.core.syntaxgraph; 002 003import java.util.Iterator; 004import java.util.SortedMap; 005import java.util.SortedSet; 006import java.util.TreeSet; 007 008import org.maltparser.core.exception.MaltChainedException; 009import org.maltparser.core.pool.ObjectPoolList; 010import org.maltparser.core.symbol.SymbolTable; 011import org.maltparser.core.symbol.SymbolTableHandler; 012import org.maltparser.core.syntaxgraph.edge.Edge; 013import org.maltparser.core.syntaxgraph.edge.GraphEdge; 014import org.maltparser.core.syntaxgraph.node.ComparableNode; 015import org.maltparser.core.syntaxgraph.node.DependencyNode; 016import org.maltparser.core.syntaxgraph.node.Node; 017import org.maltparser.core.syntaxgraph.node.Root; 018/** 019 * 020 * 021 * @author Johan Hall 022 */ 023public class DependencyGraph extends Sentence implements DependencyStructure { 024 private final ObjectPoolList<Edge> edgePool; 025 private final SortedSet<Edge> graphEdges; 026 private final Root root; 027 private boolean singleHeadedConstraint; 028 private RootLabels rootLabels; 029 030 public DependencyGraph(SymbolTableHandler symbolTables) throws MaltChainedException { 031 super(symbolTables); 032 setSingleHeadedConstraint(true); 033 root = new Root(); 034 root.setBelongsToGraph(this); 035 graphEdges = new TreeSet<Edge>(); 036 edgePool = new ObjectPoolList<Edge>() { 037 protected Edge create() { return new GraphEdge(); } 038 public void resetObject(Edge o) throws MaltChainedException { o.clear(); } 039 }; 040 clear(); 041 } 042 043 public DependencyNode addDependencyNode() throws MaltChainedException { 044 return addTokenNode(); 045 } 046 047 public DependencyNode addDependencyNode(int index) throws MaltChainedException { 048 if (index == 0) { 049 return root; 050 } 051 return addTokenNode(index); 052 } 053 054 public DependencyNode getDependencyNode(int index) throws MaltChainedException { 055 if (index == 0) { 056 return root; 057 } 058 return getTokenNode(index); 059 } 060 061 public int nDependencyNode() { 062 return nTokenNode() + 1; 063 } 064 065 public int getHighestDependencyNodeIndex() { 066 if (hasTokens()) { 067 return getHighestTokenIndex(); 068 } 069 return 0; 070 } 071 072 public Edge addDependencyEdge(int headIndex, int dependentIndex) throws MaltChainedException { 073 DependencyNode head = null; 074 DependencyNode dependent = null; 075 if (headIndex == 0) { 076 head = root; 077 } else { // if (headIndex > 0) { 078 head = getOrAddTerminalNode(headIndex); 079 } 080 081 if (dependentIndex > 0) { 082 dependent = getOrAddTerminalNode(dependentIndex); 083 } 084 return addDependencyEdge(head, dependent); 085 } 086 087 protected Edge addDependencyEdge(DependencyNode head, DependencyNode dependent) throws MaltChainedException { 088 if (head == null || dependent == null) { 089 throw new SyntaxGraphException("Head or dependent node is missing."); 090 } else if (!dependent.isRoot()) { 091 if (singleHeadedConstraint && dependent.hasHead()) { 092 return moveDependencyEdge(head, dependent); 093 } 094 final DependencyNode hc = ((DependencyNode)head).findComponent(); 095 final DependencyNode dc = ((DependencyNode)dependent).findComponent(); 096 if (hc != dc) { 097 link(hc, dc); 098 numberOfComponents--; 099 } 100 Edge e = edgePool.checkOut(); 101 e.setBelongsToGraph(this); 102 e.setEdge((Node)head, (Node)dependent, Edge.DEPENDENCY_EDGE); 103 graphEdges.add(e); 104 return e; 105 } else { 106 throw new SyntaxGraphException("Head node is not a root node or a terminal node."); 107 } 108 } 109 110 public Edge moveDependencyEdge(int newHeadIndex, int dependentIndex) throws MaltChainedException { 111 DependencyNode newHead = null; 112 DependencyNode dependent = null; 113 if (newHeadIndex == 0) { 114 newHead = root; 115 } else if (newHeadIndex > 0) { 116 newHead = terminalNodes.get(newHeadIndex); 117 } 118 119 if (dependentIndex > 0) { 120 dependent = terminalNodes.get(dependentIndex); 121 } 122 return moveDependencyEdge(newHead, dependent); 123 } 124 125 protected Edge moveDependencyEdge(DependencyNode newHead, DependencyNode dependent) throws MaltChainedException { 126 if (dependent == null || !dependent.hasHead()) { 127 return null; 128 } 129 Edge headEdge = dependent.getHeadEdge(); 130 final LabelSet labels = checkOutNewLabelSet(); 131 for (SymbolTable table : headEdge.getLabelTypes()) { 132 labels.put(table, headEdge.getLabelCode(table)); 133 } 134 headEdge.clear(); 135 headEdge.setBelongsToGraph(this); 136 headEdge.setEdge((Node)newHead, (Node)dependent, Edge.DEPENDENCY_EDGE); 137 headEdge.addLabel(labels); 138 labels.clear(); 139 checkInLabelSet(labels); 140 return headEdge; 141 } 142 143 public void removeDependencyEdge(int headIndex, int dependentIndex) throws MaltChainedException { 144 Node head = null; 145 Node dependent = null; 146 if (headIndex == 0) { 147 head = root; 148 } else if (headIndex > 0) { 149 head = terminalNodes.get(headIndex); 150 } 151 152 if (dependentIndex > 0) { 153 dependent = terminalNodes.get(dependentIndex); 154 } 155 removeDependencyEdge(head, dependent); 156 } 157 158 protected void removeDependencyEdge(Node head, Node dependent) throws MaltChainedException { 159 if (head == null || dependent == null) { 160 throw new SyntaxGraphException("Head or dependent node is missing."); 161 } else if (!dependent.isRoot()) { 162 Iterator<Edge> ie = dependent.getIncomingEdgeIterator(); 163 164 while (ie.hasNext()) { 165 Edge e = ie.next(); 166 if (e.getSource() == head) { 167 graphEdges.remove(e); 168 ie.remove(); 169 edgePool.checkIn(e); 170 } 171 } 172 } else { 173 throw new SyntaxGraphException("Head node is not a root node or a terminal node."); 174 } 175 } 176 177 public Edge addSecondaryEdge(ComparableNode source, ComparableNode target) throws MaltChainedException { 178 if (source == null || target == null) { 179 throw new SyntaxGraphException("Head or dependent node is missing."); 180 } else if (!target.isRoot()) { 181 Edge e = edgePool.checkOut(); 182 e.setBelongsToGraph(this); 183 e.setEdge((Node)source, (Node)target, Edge.SECONDARY_EDGE); 184 graphEdges.add(e); 185 return e; 186 } 187 return null; 188 } 189 190 public void removeSecondaryEdge(ComparableNode source, ComparableNode target) throws MaltChainedException { 191 if (source == null || target == null) { 192 throw new SyntaxGraphException("Head or dependent node is missing."); 193 } else if (!target.isRoot()) { 194 final Iterator<Edge> ie = ((Node)target).getIncomingEdgeIterator(); 195 while (ie.hasNext()) { 196 Edge e = ie.next(); 197 if (e.getSource() == source) { 198 ie.remove(); 199 graphEdges.remove(e); 200 edgePool.checkIn(e); 201 } 202 } 203 } 204 } 205 206// public boolean hasLabeledDependency(int index, SymbolTable table) { 207// return (!getDependencyNode(index).isRoot() && getDependencyNode(index).getLabelCode(table) != null); 208// } 209 210 public boolean hasLabeledDependency(int index) throws MaltChainedException { 211 return (getDependencyNode(index).hasHead() && getDependencyNode(index).getHeadEdge().isLabeled()); 212 } 213 214 public boolean isConnected() { 215 return (numberOfComponents == 1); 216 } 217 218 public boolean isProjective() throws MaltChainedException { 219 for (int i : terminalNodes.keySet()) { 220 if (!terminalNodes.get(i).isProjective()) { 221 return false; 222 } 223 } 224 return true; 225 } 226 227 public boolean isTree() { 228 return isConnected() && isSingleHeaded(); 229 } 230 231 public boolean isSingleHeaded() { 232 for (int i : terminalNodes.keySet()) { 233 if (!terminalNodes.get(i).hasAtMostOneHead()) { 234 return false; 235 } 236 } 237 return true; 238 } 239 240 public boolean isSingleHeadedConstraint() { 241 return singleHeadedConstraint; 242 } 243 244 public void setSingleHeadedConstraint(boolean singleHeadedConstraint) { 245 this.singleHeadedConstraint = singleHeadedConstraint; 246 } 247 248 public int nNonProjectiveEdges() throws MaltChainedException { 249 int c = 0; 250 for (int i : terminalNodes.keySet()) { 251 if (!terminalNodes.get(i).isProjective()) { 252 c++; 253 } 254 } 255 return c; 256 } 257 258 public int nEdges() { 259 return graphEdges.size(); 260 } 261 262 public SortedSet<Edge> getEdges() { 263 return graphEdges; 264 } 265 266 public SortedSet<Integer> getDependencyIndices() { 267 SortedSet<Integer> indices = new TreeSet<Integer>(terminalNodes.keySet()); 268 indices.add(0); 269 return indices; 270 } 271 272 protected DependencyNode link(DependencyNode x, DependencyNode y) throws MaltChainedException { 273 if (x.getRank() > y.getRank()) { 274 y.setComponent(x); 275 } else { 276 x.setComponent(y); 277 if (x.getRank() == y.getRank()) { 278 y.setRank(y.getRank()+1); 279 } 280 return y; 281 } 282 return x; 283 } 284 285 public void linkAllTreesToRoot() throws MaltChainedException { 286 for (int i : terminalNodes.keySet()) { 287 if (!terminalNodes.get(i).hasHead()) { 288 addDependencyEdge(root,terminalNodes.get(i)); 289 } 290 } 291 } 292 293 public LabelSet getDefaultRootEdgeLabels() throws MaltChainedException { 294 if (rootLabels == null) { 295 return null; 296 } 297 return rootLabels.getDefaultRootLabels(); 298 } 299 300 public String getDefaultRootEdgeLabelSymbol(SymbolTable table) throws MaltChainedException { 301 if (rootLabels == null) { 302 return null; 303 } 304 return rootLabels.getDefaultRootLabelSymbol(table); 305 } 306 307 public int getDefaultRootEdgeLabelCode(SymbolTable table) throws MaltChainedException { 308 if (rootLabels == null) { 309 return -1; 310 } 311 return rootLabels.getDefaultRootLabelCode(table); 312 } 313 314 public void setDefaultRootEdgeLabel(SymbolTable table, String defaultRootSymbol) throws MaltChainedException { 315 if (rootLabels == null) { 316 rootLabels = new RootLabels(); 317 } 318 rootLabels.setDefaultRootLabel(table, defaultRootSymbol); 319 } 320 321 public void setDefaultRootEdgeLabels(String rootLabelOption, SortedMap<String, SymbolTable> edgeSymbolTables) throws MaltChainedException { 322 if (rootLabels == null) { 323 rootLabels = new RootLabels(); 324 } 325 rootLabels.setRootLabels(rootLabelOption, edgeSymbolTables); 326 } 327 328 public void clear() throws MaltChainedException { 329 edgePool.checkInAll(); 330 graphEdges.clear(); 331 root.clear(); 332 super.clear(); 333 numberOfComponents++; 334 } 335 336 public DependencyNode getDependencyRoot() { 337 return root; 338 } 339 340 public String toString() { 341 final StringBuilder sb = new StringBuilder(); 342 for (int index : terminalNodes.keySet()) { 343 sb.append(terminalNodes.get(index).toString().trim()); 344 sb.append('\n'); 345 } 346 sb.append('\n'); 347 return sb.toString(); 348 } 349}