001 package org.maltparser.core.syntaxgraph.node; 002 003 import java.util.NoSuchElementException; 004 import java.util.SortedSet; 005 import java.util.TreeSet; 006 007 import org.maltparser.core.exception.MaltChainedException; 008 import org.maltparser.core.helper.SystemLogger; 009 import org.maltparser.core.symbol.SymbolTable; 010 import org.maltparser.core.syntaxgraph.SyntaxGraphException; 011 import org.maltparser.core.syntaxgraph.TokenStructure; 012 import org.maltparser.core.syntaxgraph.edge.Edge; 013 import org.maltparser.core.syntaxgraph.headrules.Direction; 014 import org.maltparser.core.syntaxgraph.headrules.HeadRules; 015 016 public class NonTerminal extends GraphNode implements PhraseStructureNode, NonTerminalNode { 017 public final static int INDEX_OFFSET = 10000000; 018 protected final SortedSet<PhraseStructureNode> children; 019 protected PhraseStructureNode parent; 020 protected int index; 021 022 public NonTerminal() throws MaltChainedException { 023 super(); 024 index = -1; 025 children = new TreeSet<PhraseStructureNode>(); 026 } 027 028 public void addIncomingEdge(Edge in) throws MaltChainedException { 029 super.addIncomingEdge(in); 030 if (in.getType() == Edge.PHRASE_STRUCTURE_EDGE && in.getSource() instanceof PhraseStructureNode) { 031 parent = (PhraseStructureNode)in.getSource(); 032 } 033 } 034 035 public void removeIncomingEdge(Edge in) throws MaltChainedException { 036 super.removeIncomingEdge(in); 037 if (in.getType() == Edge.PHRASE_STRUCTURE_EDGE && in.getSource() instanceof PhraseStructureNode) { 038 if (in.getSource() == parent) { 039 this.parent = null; 040 } 041 } 042 } 043 044 public void addOutgoingEdge(Edge out) throws MaltChainedException { 045 super.addOutgoingEdge(out); 046 if (out.getType() == Edge.PHRASE_STRUCTURE_EDGE && out.getTarget() instanceof PhraseStructureNode) { 047 children.add((PhraseStructureNode)out.getTarget()); 048 // boolean notSorted = true; 049 // PhraseStructureNode prev = children.first(); 050 // for (PhraseStructureNode node : children) { 051 // if (prev != node) { 052 // if (node.compareTo(prev) == -1) { 053 // notSorted = false; 054 // System.out.println("NS"); 055 // break; 056 // } 057 // } 058 // prev = node; 059 // } 060 // if (notSorted == false) { 061 // SortedSet<PhraseStructureNode> tmp = new TreeSet<PhraseStructureNode>(children); 062 // children.clear(); 063 // for (PhraseStructureNode node : tmp) { 064 // children.add(node); 065 // } 066 // } 067 } 068 } 069 070 public void removeOutgoingEdge(Edge out) throws MaltChainedException { 071 super.removeOutgoingEdge(out); 072 if (out.getType() == Edge.PHRASE_STRUCTURE_EDGE && out.getTarget() instanceof PhraseStructureNode) { 073 children.remove(out.getTarget()); 074 } 075 } 076 077 public PhraseStructureNode getParent() { 078 return parent; 079 } 080 081 public Edge getParentEdge() throws MaltChainedException { 082 for (Edge e : incomingEdges) { 083 if (e.getSource() == parent && e.getType() == Edge.PHRASE_STRUCTURE_EDGE) { 084 return e; 085 } 086 } 087 return null; 088 } 089 090 public String getParentEdgeLabelSymbol(SymbolTable table) throws MaltChainedException { 091 for (Edge e : incomingEdges) { 092 if (e.getSource() == parent && e.getType() == Edge.PHRASE_STRUCTURE_EDGE) { 093 return e.getLabelSymbol(table); 094 } 095 } 096 return null; 097 } 098 099 public int getParentEdgeLabelCode(SymbolTable table) throws MaltChainedException { 100 for (Edge e : incomingEdges) { 101 if (e.getSource() == parent && e.getType() == Edge.PHRASE_STRUCTURE_EDGE) { 102 return e.getLabelCode(table); 103 } 104 } 105 return -1; 106 } 107 108 public boolean hasParentEdgeLabel(SymbolTable table) throws MaltChainedException { 109 for (Edge e : incomingEdges) { 110 if (e.getSource() == parent && e.getType() == Edge.PHRASE_STRUCTURE_EDGE) { 111 return e.hasLabel(table); 112 } 113 } 114 return false; 115 } 116 117 public int getHeight() { 118 int max = -1; 119 for (PhraseStructureNode node : children) { 120 if (node instanceof Token) { 121 if (max < 0) { 122 max = 0; 123 } 124 } else { 125 int nodeheight = ((NonTerminalNode)node).getHeight(); 126 if (max < nodeheight) { 127 max = nodeheight; 128 } 129 } 130 } 131 return max + 1; 132 } 133 134 public SortedSet<PhraseStructureNode> getChildren() { 135 return new TreeSet<PhraseStructureNode>(children); 136 } 137 138 public PhraseStructureNode getChild(int index) { 139 if (index >= 0 && index < children.size()) { 140 int i = 0; 141 for (PhraseStructureNode node : children) { 142 if (i == index) { 143 return node; 144 } 145 i++; 146 } 147 // return children.toArray(new PhraseStructureNode[children.size()])[index]; 148 } 149 return null; 150 } 151 152 public PhraseStructureNode getLeftChild() { 153 for (PhraseStructureNode node : children) { 154 return node; 155 } 156 return null; 157 } 158 159 public PhraseStructureNode getRightChild() { 160 int n = children.size(); 161 int i = 1; 162 for (PhraseStructureNode node : children) { 163 if (i == n) { 164 return node; 165 } 166 i++; 167 } 168 return null; 169 } 170 171 public int nChildren() { 172 return children.size(); 173 } 174 175 public boolean hasNonTerminalChildren() { 176 for (PhraseStructureNode node : children) { 177 if (node instanceof NonTerminal) { 178 return true; 179 } 180 } 181 return false; 182 } 183 184 public boolean hasTerminalChildren() { 185 for (PhraseStructureNode node : children) { 186 if (node instanceof Token) { 187 return true; 188 } 189 } 190 return false; 191 } 192 193 public TokenNode getLexicalHead(HeadRules headRules) throws MaltChainedException { 194 return identifyHead(headRules); 195 } 196 197 public PhraseStructureNode getHeadChild(HeadRules headRules) throws MaltChainedException { 198 return identifyHeadChild(headRules); 199 } 200 201 public TokenNode getLexicalHead() throws MaltChainedException { 202 return identifyHead(null); 203 } 204 205 public PhraseStructureNode getHeadChild() throws MaltChainedException { 206 return identifyHeadChild(null); 207 } 208 209 private PhraseStructureNode identifyHeadChild(HeadRules headRules) throws MaltChainedException { 210 PhraseStructureNode headChild = (headRules == null)?null:headRules.getHeadChild(this); 211 if (headChild == null) { 212 Direction direction = (headRules == null)?Direction.LEFT:headRules.getDefaultDirection(this); 213 if (direction == Direction.LEFT) { 214 if ((headChild = leftmostTerminalChild()) == null) { 215 headChild = leftmostNonTerminalChild(); 216 } 217 } else { 218 if ((headChild = rightmostTerminalChild()) == null) { 219 headChild = rightmostNonTerminalChild(); 220 } 221 } 222 } 223 return headChild; 224 } 225 226 public TokenNode identifyHead(HeadRules headRules) throws MaltChainedException { 227 PhraseStructureNode headChild = identifyHeadChild(headRules); 228 TokenNode lexicalHead = null; 229 if (headChild instanceof NonTerminalNode) { 230 lexicalHead = ((NonTerminalNode)headChild).identifyHead(headRules); 231 } else if (headChild instanceof TokenNode) { 232 lexicalHead = (TokenNode)headChild; 233 } 234 for (PhraseStructureNode node : children) { 235 if (node != headChild && node instanceof NonTerminalNode) { 236 ((NonTerminalNode)node).identifyHead(headRules); 237 } 238 } 239 return lexicalHead; 240 } 241 242 public int getIndex() { 243 return index; 244 } 245 246 public int getCompareToIndex() { 247 return index + INDEX_OFFSET; 248 } 249 250 private PhraseStructureNode leftmostTerminalChild() { 251 for (PhraseStructureNode node : children) { 252 if (node instanceof TokenNode) { 253 return node; 254 } 255 } 256 return null; 257 } 258 259 private PhraseStructureNode leftmostNonTerminalChild() { 260 for (PhraseStructureNode node : children) { 261 if (node instanceof NonTerminalNode) { 262 return node; 263 } 264 } 265 return null; 266 } 267 268 private PhraseStructureNode rightmostTerminalChild() { 269 try { 270 if (children.last() instanceof TokenNode) { 271 return children.last(); 272 } 273 } catch (NoSuchElementException e) { } 274 275 PhraseStructureNode candidate = null; 276 for (PhraseStructureNode node : children) { 277 if (node instanceof TokenNode) { 278 candidate = node; 279 } 280 } 281 return candidate; 282 } 283 284 private PhraseStructureNode rightmostNonTerminalChild() { 285 try { 286 if (children.last() instanceof NonTerminalNode) { 287 return children.last(); 288 } 289 } catch (NoSuchElementException e) { } 290 291 PhraseStructureNode candidate = null; 292 for (PhraseStructureNode node : children) { 293 if (node instanceof NonTerminalNode) { 294 candidate = node; 295 } 296 } 297 return candidate; 298 } 299 300 // protected void getPhraseDominationSet(SortedSet<PhraseStructureNode> dominationSet) { 301 // for (PhraseStructureNode node : children) { 302 // if (node instanceof TerminalNode) { 303 // dominationSet.add(node); 304 // } else { 305 // ((NonTerminal)node).getPhraseDominationSet(dominationSet); 306 // } 307 // } 308 // } 309 // 310 // private SortedSet<PhraseStructureNode> getPhraseDominationSet() { 311 // SortedSet<PhraseStructureNode> dominationSet = new TreeSet<PhraseStructureNode>(); 312 // getPhraseDominationSet(dominationSet); 313 // return dominationSet; 314 // } 315 316 317 318 public boolean isContinuous() { 319 int lcorner = getLeftmostProperDescendant().getIndex(); 320 int rcorner = getRightmostProperDescendant().getIndex(); 321 322 if (lcorner == rcorner) { 323 return true; 324 } 325 326 TokenNode terminal = ((TokenStructure)getBelongsToGraph()).getTokenNode(lcorner); 327 while (terminal.getIndex() != rcorner) { 328 PhraseStructureNode tmp = terminal.getParent(); 329 while (true) { 330 if (tmp == this) { 331 break; 332 } 333 if (tmp == null) { 334 return false; 335 } 336 tmp = tmp.getParent(); 337 } 338 terminal = terminal.getSuccessor(); 339 } 340 341 return true; 342 } 343 344 public boolean isContinuousExcludeTerminalsAttachToRoot() { 345 int lcorner = getLeftmostProperDescendant().getIndex(); 346 int rcorner = getRightmostProperDescendant().getIndex(); 347 348 if (lcorner == rcorner) { 349 return true; 350 } 351 352 TokenNode terminal = ((TokenStructure)getBelongsToGraph()).getTokenNode(lcorner); 353 while (terminal.getIndex() != rcorner) { 354 if (terminal.getParent() != null && terminal.getParent().isRoot()) { 355 terminal = terminal.getSuccessor(); 356 continue; 357 } 358 PhraseStructureNode tmp = terminal.getParent(); 359 while (true) { 360 if (tmp == this) { 361 break; 362 } 363 if (tmp == null) { 364 return false; 365 } 366 tmp = tmp.getParent(); 367 } 368 terminal = terminal.getSuccessor(); 369 } 370 return true; 371 } 372 373 @Override 374 public boolean isRoot() { 375 return false; 376 } 377 378 379 public ComparableNode getLeftmostProperDescendant() { 380 NonTerminalNode node = this; 381 PhraseStructureNode candidate = null; 382 while (node != null) { 383 candidate = node.getLeftChild(); 384 if (candidate == null || candidate instanceof TokenNode) { 385 return candidate; 386 } 387 node = (NonTerminalNode)candidate; 388 } 389 return null; 390 } 391 392 public ComparableNode getRightmostProperDescendant() { 393 NonTerminalNode node = this; 394 PhraseStructureNode candidate = null; 395 while (node != null) { 396 candidate = node.getRightChild(); 397 if (candidate == null || candidate instanceof TokenNode) { 398 return candidate; 399 } 400 node = (NonTerminalNode)candidate; 401 } 402 return null; 403 } 404 405 public ComparableNode getLeftmostDescendant() throws MaltChainedException { 406 return getLeftmostProperDescendant(); 407 } 408 409 public ComparableNode getRightmostDescendant() throws MaltChainedException { 410 return getRightmostProperDescendant(); 411 } 412 413 // public void reArrangeChildrenAccordingToLeftAndRightProperDesendant() throws MaltChainedException { 414 // int i = 0; 415 // int leftMostCorner = -1; 416 // int leftMostCornerChildIndex = -1; 417 // while (i < children.size()) { 418 // if (leftMostCorner == -1) { 419 // leftMostCorner = getChild(i).getLeftmostProperDescendantIndex(); 420 // leftMostCornerChildIndex = i; 421 // } else if (getChild(i) instanceof NonTerminal && getChild(i).getLeftmostProperDescendantIndex() < leftMostCorner) { 422 // NonTerminalNode child = (NonTerminal)getChild(i); 423 // PhraseStructureNode leftMostCornerChild = getChild(leftMostCornerChildIndex); 424 // if (leftMostCornerChild.getParent() != null) { 425 // LabelSet labelSet = leftMostCornerChild.getParentEdge().getLabelSet(); 426 // ((PhraseStructure)getBelongsToGraph()).removePhraseStructureEdge(this, leftMostCornerChild); 427 // Edge e = ((PhraseStructure)getBelongsToGraph()).addPhraseStructureEdge(child, leftMostCornerChild); 428 // e.addLabel(labelSet); 429 // } 430 // child.reArrangeChildrenAccordingToLeftAndRightProperDesendant(); 431 // i = -1; 432 // leftMostCorner = -1; 433 // leftMostCornerChildIndex = -1; 434 // } else { 435 // leftMostCorner = getChild(i).getLeftmostProperDescendantIndex(); 436 // leftMostCornerChildIndex = i; 437 // } 438 // i++; 439 // } 440 // 441 // for (int j = 0, n=children.size(); j < n; j++) { 442 // if (getChild(j) instanceof NonTerminalNode) { 443 // ((NonTerminalNode)getChild(j)).reArrangeChildrenAccordingToLeftAndRightProperDesendant(); 444 // } 445 // } 446 // } 447 448 @Override 449 public void setIndex(int index) throws MaltChainedException { 450 if (index > 0) { 451 this.index = index; //INDEX_OFFSET+index; 452 } else { 453 throw new SyntaxGraphException("The index must be a positive index"); 454 } 455 456 } 457 458 public void clear() throws MaltChainedException { 459 super.clear(); 460 children.clear(); 461 parent = null; 462 index = -1; 463 } 464 465 @Override 466 public int compareTo(ComparableNode o) { 467 final int BEFORE = -1; 468 final int EQUAL = 0; 469 final int AFTER = 1; 470 if ( this == o ) return EQUAL; 471 try { 472 final int thisLCorner = this.getLeftmostProperDescendantIndex(); 473 final int thatLCorner = (o instanceof TokenNode)?o.getCompareToIndex():o.getLeftmostProperDescendantIndex(); 474 final int thisRCorner = this.getRightmostProperDescendantIndex(); 475 final int thatRCorner = (o instanceof TokenNode)?o.getCompareToIndex():o.getRightmostProperDescendantIndex(); 476 477 // if (thisLCorner == -1 || thatLCorner == -1) { 478 // if (thisRCorner < thatRCorner) return BEFORE; 479 // if (thisRCorner > thatRCorner) return AFTER; 480 // } 481 // if (thisRCorner == -1 || thatRCorner == -1) { 482 // if (thisLCorner < thatLCorner) return BEFORE; 483 // if (thisLCorner > thatLCorner) return AFTER; 484 // } 485 486 if (thisLCorner != -1 && thatLCorner != -1 && thisRCorner != -1 && thatRCorner != -1) { 487 if (thisLCorner < thatLCorner && thisRCorner < thatRCorner) return BEFORE; 488 if (thisLCorner > thatLCorner && thisRCorner > thatRCorner) return AFTER; 489 if (thisLCorner > thatLCorner && thisRCorner < thatRCorner) return BEFORE; 490 if (thisLCorner < thatLCorner && thisRCorner > thatRCorner) return AFTER; 491 } else { 492 if (thisLCorner != -1 && thatLCorner != -1) { 493 if (thisLCorner < thatLCorner) return BEFORE; 494 if (thisLCorner > thatLCorner) return AFTER; 495 } 496 if (thisRCorner != -1 && thatRCorner != -1) { 497 if (thisRCorner < thatRCorner) return BEFORE; 498 if (thisRCorner > thatRCorner) return AFTER; 499 } 500 } 501 502 503 504 // final int thisLCorner = this.getLeftmostDescendantIndex(); 505 // final int thatLCorner = (o instanceof TerminalNode)?o.getCompareToIndex():o.getLeftmostDescendantIndex(); 506 // final int thisRCorner = this.getRightmostDescendantIndex(); 507 // final int thatRCorner = (o instanceof TerminalNode)?o.getCompareToIndex():o.getRightmostDescendantIndex(); 508 // 509 // if (thisLCorner == -1 || thatLCorner == -1) { 510 // if (thisRCorner < thatRCorner) return BEFORE; 511 // if (thisRCorner > thatRCorner) return AFTER; 512 // } 513 // if (thisRCorner == -1 || thatRCorner == -1) { 514 // if (thisLCorner < thatLCorner) return BEFORE; 515 // if (thisLCorner > thatLCorner) return AFTER; 516 // } 517 // if (thisLCorner < thatLCorner && thisRCorner < thatRCorner) return BEFORE; 518 // if (thisLCorner > thatLCorner && thisRCorner > thatRCorner) return AFTER; 519 // if (thisLCorner > thatLCorner && thisRCorner < thatRCorner) return BEFORE; 520 // if (thisLCorner < thatLCorner && thisRCorner > thatRCorner) return AFTER; 521 522 // System.out.println(thisLCorner + " " + thatLCorner + " " +thisRCorner + " " + thatRCorner); 523 524 // int thisCorner = this.getLeftmostDescendantIndex(); 525 // int thatCorner = (o instanceof TerminalNode)?o.getCompareToIndex():o.getLeftmostDescendantIndex(); 526 // if (thisCorner != -1 && thatCorner != -1) { 527 // if (thisCorner < thatCorner) return BEFORE; 528 // if (thisCorner > thatCorner) return AFTER; 529 // } 530 // thisCorner = this.getRightmostDescendantIndex(); 531 // thatCorner = (o instanceof TerminalNode)?o.getCompareToIndex():o.getRightmostDescendantIndex(); 532 // if (thisCorner != -1 && thatCorner != -1) { 533 // if (thisCorner < thatCorner) return BEFORE; 534 // if (thisCorner > thatCorner) return AFTER; 535 // } 536 } catch (MaltChainedException e) { 537 if (SystemLogger.logger().isDebugEnabled()) { 538 SystemLogger.logger().debug("",e); 539 } else { 540 SystemLogger.logger().error(e.getMessageChain()); 541 } 542 System.exit(1); 543 } 544 if (this.getCompareToIndex() < o.getCompareToIndex()) return BEFORE; 545 if (this.getCompareToIndex() > o.getCompareToIndex()) return AFTER; 546 return super.compareTo(o); 547 } 548 549 public boolean equals(Object obj) { 550 if (this == obj) return true; 551 if (!(obj instanceof NonTerminal)) return false; 552 return super.equals(obj); 553 } 554 555 public int hashCode() { 556 return 31 * 7 + super.hashCode(); 557 } 558 559 public String toString() { 560 final StringBuilder sb = new StringBuilder(); 561 sb.append(getIndex()); 562 sb.append('\t'); 563 if (getLabelTypes() != null) { 564 for (SymbolTable table : getLabelTypes()) { 565 try { 566 sb.append(getLabelSymbol(table)); 567 } catch (MaltChainedException e) { 568 System.err.println("Print error : "+e.getMessageChain()); 569 } 570 sb.append('\t'); 571 } 572 } 573 return sb.toString(); 574 } 575 576 }