package org.maltparser.core.syntaxgraph.node; import java.util.NoSuchElementException; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import org.maltparser.core.exception.MaltChainedException; import org.maltparser.core.helper.SystemLogger; import org.maltparser.core.symbol.SymbolTable; import org.maltparser.core.syntaxgraph.LabelSet; import org.maltparser.core.syntaxgraph.SyntaxGraphException; import org.maltparser.core.syntaxgraph.TokenStructure; import org.maltparser.core.syntaxgraph.edge.Edge; import org.maltparser.core.syntaxgraph.headrules.Direction; import org.maltparser.core.syntaxgraph.headrules.HeadRules; public class Root extends GraphNode implements DependencyNode, PhraseStructureNode, NonTerminalNode { protected final SortedSet<DependencyNode> leftDependents; protected final SortedSet<DependencyNode> rightDependents; protected final SortedSet<PhraseStructureNode> children; /** * a reference to a node where the node is part of a component. If the node * is unconnected it will reference to it self. */ protected DependencyNode component; protected int rank; public Root() throws MaltChainedException { super(); leftDependents = new TreeSet<DependencyNode>(); rightDependents = new TreeSet<DependencyNode>(); children = new TreeSet<PhraseStructureNode>(); clear(); } @Override public void addIncomingEdge(Edge in) throws MaltChainedException { throw new SyntaxGraphException("It is not allowed for a root node to have an incoming edge"); } @Override public void removeIncomingEdge(Edge in) { } @Override public void addOutgoingEdge(Edge out) throws MaltChainedException { super.addOutgoingEdge(out); if (out.getTarget() != null) { if (out.getType() == Edge.DEPENDENCY_EDGE && out.getTarget() instanceof DependencyNode) { Node dependent = out.getTarget(); if (compareTo(dependent) > 0) { leftDependents.add((DependencyNode) dependent); } else if (compareTo(dependent) < 0) { rightDependents.add((DependencyNode) dependent); } } else if (out.getType() == Edge.PHRASE_STRUCTURE_EDGE && out.getTarget() instanceof PhraseStructureNode) { children.add((PhraseStructureNode) out.getTarget()); } } } @Override public void removeOutgoingEdge(Edge out) throws MaltChainedException { super.removeOutgoingEdge(out); if (out.getTarget() != null) { if (out.getType() == Edge.DEPENDENCY_EDGE && out.getTarget() instanceof DependencyNode) { Node dependent = out.getTarget(); if (compareTo(dependent) > 0) { leftDependents.remove((DependencyNode) dependent); } else if (compareTo(dependent) < 0) { rightDependents.remove((DependencyNode) dependent); } } else if (out.getType() == Edge.PHRASE_STRUCTURE_EDGE && out.getTarget() instanceof PhraseStructureNode) { children.remove((PhraseStructureNode) out.getTarget()); } } } public DependencyNode getAncestor() throws MaltChainedException { return this; } public DependencyNode getProperAncestor() throws MaltChainedException { return null; } public int getRank() { return rank; } public void setRank(int r) { this.rank = r; } public DependencyNode findComponent() { return findComponent(this); } private DependencyNode findComponent(DependencyNode x) { if (x != x.getComponent()) { x.setComponent(findComponent(x.getComponent())); } return x.getComponent(); } public DependencyNode getComponent() { return component; } public void setComponent(DependencyNode x) { this.component = x; } public boolean isContinuous() { return true; } public boolean isContinuousExcludeTerminalsAttachToRoot() { return true; } public PhraseStructureNode getParent() { return null; } public Edge getParentEdge() throws MaltChainedException { return null; } public String getParentEdgeLabelSymbol(SymbolTable table) throws MaltChainedException { return null; } public int getParentEdgeLabelCode(SymbolTable table) throws MaltChainedException { return -1; } public boolean hasParentEdgeLabel(SymbolTable table) throws MaltChainedException { return false; } public SortedSet<PhraseStructureNode> getChildren() { return new TreeSet<PhraseStructureNode>(children); } public PhraseStructureNode getChild(int index) { if (index >= 0 && index < children.size()) { return children.toArray(new PhraseStructureNode[children.size()])[index]; } return null; } public PhraseStructureNode getLeftChild() { for (PhraseStructureNode node : children) { return node; } return null; } public PhraseStructureNode getRightChild() { int n = children.size(); int i = 1; for (PhraseStructureNode node : children) { if (i == n) { return node; } } return null; } public int nChildren() { return children.size(); } public boolean hasNonTerminalChildren() { for (PhraseStructureNode node : children) { if (node instanceof NonTerminal) { return true; } } return false; } public boolean hasTerminalChildren() { for (PhraseStructureNode node : children) { if (node instanceof Token) { return true; } } return false; } public int getHeight() { int max = -1; for (PhraseStructureNode node : children) { if (node instanceof Token) { if (max < 0) { max = 0; } } else { int nodeheight = ((NonTerminalNode) node).getHeight(); if (max < nodeheight) { max = nodeheight; } } } return max + 1; } public TokenNode getLexicalHead(HeadRules headRules) throws MaltChainedException { return identifyHead(headRules); } public PhraseStructureNode getHeadChild(HeadRules headRules) throws MaltChainedException { return identifyHeadChild(headRules); } public TokenNode getLexicalHead() throws MaltChainedException { return identifyHead(null); } public PhraseStructureNode getHeadChild() throws MaltChainedException { return identifyHeadChild(null); } private PhraseStructureNode identifyHeadChild(HeadRules headRules) throws MaltChainedException { PhraseStructureNode headChild = (headRules == null) ? null : headRules.getHeadChild(this); if (headChild == null) { Direction direction = (headRules == null) ? Direction.LEFT : headRules.getDefaultDirection(this); if (direction == Direction.LEFT) { if ((headChild = leftmostTerminalChild()) == null) { headChild = leftmostNonTerminalChild(); } } else { if ((headChild = rightmostTerminalChild()) == null) { headChild = rightmostNonTerminalChild(); } } } return headChild; } public TokenNode identifyHead(HeadRules headRules) throws MaltChainedException { PhraseStructureNode headChild = identifyHeadChild(headRules); TokenNode lexicalHead = null; if (headChild instanceof NonTerminalNode) { lexicalHead = ((NonTerminalNode) headChild).identifyHead(headRules); } else if (headChild instanceof TokenNode) { lexicalHead = (TokenNode) headChild; } for (PhraseStructureNode node : children) { if (node != headChild && node instanceof NonTerminalNode) { ((NonTerminalNode) node).identifyHead(headRules); } } return lexicalHead; } private PhraseStructureNode leftmostTerminalChild() { for (PhraseStructureNode node : children) { if (node instanceof TokenNode) { return node; } } return null; } private PhraseStructureNode leftmostNonTerminalChild() { for (PhraseStructureNode node : children) { if (node instanceof NonTerminalNode) { return node; } } return null; } private PhraseStructureNode rightmostTerminalChild() { try { if (children.last() instanceof TokenNode) { return children.last(); } } catch (NoSuchElementException e) { } PhraseStructureNode candidate = null; for (PhraseStructureNode node : children) { if (node instanceof TokenNode) { candidate = node; } } return candidate; } private PhraseStructureNode rightmostNonTerminalChild() { try { if (children.last() instanceof NonTerminalNode) { return children.last(); } } catch (NoSuchElementException e) { } PhraseStructureNode candidate = null; for (PhraseStructureNode node : children) { if (node instanceof NonTerminalNode) { candidate = node; } } return candidate; } public boolean hasAtMostOneHead() { return true; } public boolean hasAncestorInside(int left, int right) throws MaltChainedException { return false; } public boolean hasHead() { return false; } public DependencyNode getHead() throws MaltChainedException { return null; } public Edge getHeadEdge() throws MaltChainedException { return null; } public void addHeadEdgeLabel(SymbolTable table, String symbol) throws MaltChainedException { } public void addHeadEdgeLabel(SymbolTable table, int code) throws MaltChainedException { } public void addHeadEdgeLabel(LabelSet labelSet) throws MaltChainedException { } public int getHeadEdgeLabelCode(SymbolTable table) throws MaltChainedException { return 0; } public LabelSet getHeadEdgeLabelSet() throws MaltChainedException { return null; } public String getHeadEdgeLabelSymbol(SymbolTable table) throws MaltChainedException { return null; } public Set<SymbolTable> getHeadEdgeLabelTypes() throws MaltChainedException { return null; } public boolean hasHeadEdgeLabel(SymbolTable table) throws MaltChainedException { return false; } public boolean isHeadEdgeLabeled() throws MaltChainedException { return false; } public int nHeadEdgeLabels() throws MaltChainedException { return 0; } public Set<Edge> getHeadEdges() throws MaltChainedException { return null; } public Set<DependencyNode> getHeads() throws MaltChainedException { return null; } public boolean hasDependent() { return hasLeftDependent() || hasRightDependent(); } /** * Returns * <code>true</code> if the node has one or more left dependents, otherwise * <code>false</code>. * * @return * <code>true</code> if the node has one or more left dependents, otherwise * <code>false</code>. */ public boolean hasLeftDependent() { return !leftDependents.isEmpty(); } /** * Returns the left dependent at the position * <code>index</code>, where * <code>index==0</code> equals the left most dependent. * * @param index the index * @return the left dependent at the position * <code>index</code>, where * <code>index==0</code> equals the left most dependent */ public DependencyNode getLeftDependent(int index) { if (0 <= index && index < leftDependents.size()) { int i = 0; // DependencyNode candidate = null; for (DependencyNode node : leftDependents) { // candidate = node; if (i == index) { return node; } i++; } } return null; } /** * Return the number of left dependents * * @return the number of left dependents */ public int getLeftDependentCount() { return leftDependents.size(); } public SortedSet<DependencyNode> getLeftDependents() { return leftDependents; } /** * Returns the left sibling if it exists, otherwise * <code>null</code> * * @return the left sibling if it exists, otherwise * <code>null</code> */ public DependencyNode getLeftSibling() throws MaltChainedException { return null; } /** * Returns the left sibling at the same side of head as the node it self. If * not found * <code>null</code is returned * * * @return the left sibling at the same side of head as the node it self. If * not found * <code>null</code is returned */ public DependencyNode getSameSideLeftSibling() throws MaltChainedException { return null; } /** * Returns the closest left dependent to the node it self, if not found * <code>null</code> is returned. * * @return the closest left dependent to the node it self, if not found * <code>null</code> is returned. */ public DependencyNode getClosestLeftDependent() { try { return leftDependents.last(); } catch (NoSuchElementException e) { return null; } } public DependencyNode getLeftmostDependent() { for (DependencyNode dep : leftDependents) { return dep; } return null; // try { // return leftDependents.first(); // } catch (NoSuchElementException e) { // return null; // } } public DependencyNode getRightDependent(int index) { int size = rightDependents.size(); if (index < size) { return rightDependents.toArray(new DependencyNode[size])[size - 1 - index]; } return null; // if (0 <= index && index < rightDependents.size()) { // int i = 0; // DependencyNode candidate = null; // // for (DependencyNode node : rightDependents) { // candidate = node; // if (i == index) { // return candidate; // } // i++; // } // } // return null; } /** * Return the number of right dependents * * @return the number of right dependents */ public int getRightDependentCount() { return rightDependents.size(); } public SortedSet<DependencyNode> getRightDependents() { return rightDependents; } /** * Returns the right sibling if it exists, otherwise * <code>null</code> * * @return the right sibling if it exists, otherwise * <code>null</code> */ public DependencyNode getRightSibling() throws MaltChainedException { return null; } /** * Returns the right sibling at the same side of head as the node it self. * If not found * <code>null</code is returned * * * @return the right sibling at the same side of head as the node it self. * If not found * <code>null</code is returned */ public DependencyNode getSameSideRightSibling() throws MaltChainedException { return null; } /** * Returns the closest right dependent to the node it self, if not found * <code>null</code> is returned. * * @return the closest right dependent to the node it self, if not found * <code>null</code> is returned. */ public DependencyNode getClosestRightDependent() { for (DependencyNode dep : rightDependents) { return dep; } return null; // try { // return rightDependents.first(); // } catch (NoSuchElementException e) { // return null; // } } public DependencyNode getRightmostDependent() { int n = rightDependents.size(); int i = 1; for (DependencyNode node : rightDependents) { if (i == n) { return node; } i++; } return null; // try { // return rightDependents.last(); // } catch (NoSuchElementException e) { // return null; // } } /** * Returns * <code>true</code> if the node has one or more right dependents, otherwise * <code>false</code>. * * @return * <code>true</code> if the node has one or more right dependents, otherwise * <code>false</code>. */ public boolean hasRightDependent() { return !rightDependents.isEmpty(); } protected void getDependencyDominationSet(SortedSet<DependencyNode> dominationSet) { if (leftDependents.size() > 0 || rightDependents.size() > 0) { dominationSet.addAll(leftDependents); dominationSet.addAll(rightDependents); for (DependencyNode node : leftDependents) { ((Token) node).getDependencyDominationSet(dominationSet); } for (DependencyNode node : rightDependents) { ((Token) node).getDependencyDominationSet(dominationSet); } } } // private SortedSet<DependencyNode> getDependencyDominationSet() { // SortedSet<DependencyNode> dominationSet = new TreeSet<DependencyNode>(); // getDependencyDominationSet(dominationSet); // return dominationSet; // } public boolean isProjective() throws MaltChainedException { return true; } public int getDependencyNodeDepth() throws MaltChainedException { return 0; } @Override public int getIndex() { return 0; } public int getCompareToIndex() { return 0; } @Override public boolean isRoot() { return true; } public ComparableNode getLeftmostProperDescendant() throws MaltChainedException { NonTerminalNode node = this; ComparableNode candidate = null; while (node != null) { candidate = node.getLeftChild(); if (candidate == null || candidate instanceof TokenNode) { break; } node = (NonTerminalNode) candidate; } if (candidate == null && candidate instanceof NonTerminalNode) { candidate = null; DependencyNode dep; for (int index : ((TokenStructure) getBelongsToGraph()).getTokenIndices()) { dep = ((TokenStructure) getBelongsToGraph()).getTokenNode(index); while (dep != null) { if (dep == this) { return dep; } dep = dep.getHead(); } } } return candidate; } public ComparableNode getRightmostProperDescendant() throws MaltChainedException { NonTerminalNode node = this; ComparableNode candidate = null; while (node != null) { candidate = node.getRightChild(); if (candidate == null || candidate instanceof TokenNode) { break; } node = (NonTerminalNode) candidate; } if (candidate == null && candidate instanceof NonTerminalNode) { candidate = null; DependencyNode dep; for (int i = ((TokenStructure) getBelongsToGraph()).getHighestTokenIndex(); i > 0; i--) { dep = ((TokenStructure) getBelongsToGraph()).getTokenNode(i); while (dep != null) { if (dep == this) { return dep; } dep = dep.getHead(); } } } return candidate; } public ComparableNode getLeftmostDescendant() throws MaltChainedException { return getLeftmostProperDescendant(); } public ComparableNode getRightmostDescendant() throws MaltChainedException { return getRightmostProperDescendant(); } // public void reArrangeChildrenAccordingToLeftAndRightProperDesendant() throws MaltChainedException { // int i = 0; // int leftMostCorner = -1; // int leftMostCornerChildIndex = -1; // while (i < children.size()) { // if (leftMostCorner == -1) { // leftMostCorner = getChild(i).getLeftmostProperDescendantIndex(); // leftMostCornerChildIndex = i; // } else if (getChild(i) instanceof NonTerminal && getChild(i).getLeftmostProperDescendantIndex() < leftMostCorner) { // NonTerminalNode child = (NonTerminal)getChild(i); // PhraseStructureNode leftMostCornerChild = getChild(leftMostCornerChildIndex); // if (leftMostCornerChild.getParent() != null) { // LabelSet labelSet = leftMostCornerChild.getParentEdge().getLabelSet(); // ((PhraseStructure)getBelongsToGraph()).removePhraseStructureEdge(this, leftMostCornerChild); // Edge e = ((PhraseStructure)getBelongsToGraph()).addPhraseStructureEdge(child, leftMostCornerChild); // e.addLabel(labelSet); // } // child.reArrangeChildrenAccordingToLeftAndRightProperDesendant(); // i = -1; // leftMostCorner = -1; // leftMostCornerChildIndex = -1; // } else { // leftMostCorner = getChild(i).getLeftmostProperDescendantIndex(); // leftMostCornerChildIndex = i; // } // i++; // } // // for (int j = 0, n=children.size(); j < n; j++) { // if (getChild(j) instanceof NonTerminalNode) { // ((NonTerminalNode)getChild(j)).reArrangeChildrenAccordingToLeftAndRightProperDesendant(); // } // } // } @Override public void setIndex(int index) throws MaltChainedException { } @Override public void clear() throws MaltChainedException { super.clear(); component = this; rank = 0; leftDependents.clear(); rightDependents.clear(); children.clear(); } @Override public int compareTo(ComparableNode o) { final int BEFORE = -1; final int EQUAL = 0; final int AFTER = 1; if (this == o) { return EQUAL; } try { final int thisLCorner = this.getLeftmostProperDescendantIndex(); final int thatLCorner = (o instanceof TokenNode) ? o.getCompareToIndex() : o.getLeftmostProperDescendantIndex(); final int thisRCorner = this.getRightmostProperDescendantIndex(); final int thatRCorner = (o instanceof TokenNode) ? o.getCompareToIndex() : o.getRightmostProperDescendantIndex(); // if (thisLCorner == -1 || thatLCorner == -1) { // if (thisRCorner < thatRCorner) return BEFORE; // if (thisRCorner > thatRCorner) return AFTER; // } // if (thisRCorner == -1 || thatRCorner == -1) { // if (thisLCorner < thatLCorner) return BEFORE; // if (thisLCorner > thatLCorner) return AFTER; // } if (thisLCorner != -1 && thatLCorner != -1 && thisRCorner != -1 && thatRCorner != -1) { if (thisLCorner < thatLCorner && thisRCorner < thatRCorner) { return BEFORE; } if (thisLCorner > thatLCorner && thisRCorner > thatRCorner) { return AFTER; } if (thisLCorner > thatLCorner && thisRCorner < thatRCorner) { return BEFORE; } if (thisLCorner < thatLCorner && thisRCorner > thatRCorner) { return AFTER; } } else { if (thisLCorner != -1 && thatLCorner != -1) { if (thisLCorner < thatLCorner) { return BEFORE; } if (thisLCorner > thatLCorner) { return AFTER; } } if (thisRCorner != -1 && thatRCorner != -1) { if (thisRCorner < thatRCorner) { return BEFORE; } if (thisRCorner > thatRCorner) { return AFTER; } } } // final int thisLCorner = this.getLeftmostDescendantIndex(); // final int thatLCorner = (o instanceof TerminalNode)?o.getCompareToIndex():o.getLeftmostDescendantIndex(); // final int thisRCorner = this.getRightmostDescendantIndex(); // final int thatRCorner = (o instanceof TerminalNode)?o.getCompareToIndex():o.getRightmostDescendantIndex(); // // if (thisLCorner == -1 || thatLCorner == -1) { // if (thisRCorner < thatRCorner) return BEFORE; // if (thisRCorner > thatRCorner) return AFTER; // } // if (thisRCorner == -1 || thatRCorner == -1) { // if (thisLCorner < thatLCorner) return BEFORE; // if (thisLCorner > thatLCorner) return AFTER; // } // if (thisLCorner < thatLCorner && thisRCorner < thatRCorner) return BEFORE; // if (thisLCorner > thatLCorner && thisRCorner > thatRCorner) return AFTER; // if (thisLCorner > thatLCorner && thisRCorner < thatRCorner) return BEFORE; // if (thisLCorner < thatLCorner && thisRCorner > thatRCorner) return AFTER; // int thisCorner = this.getLeftmostDescendantIndex(); // int thatCorner = (o instanceof TerminalNode)?o.getCompareToIndex():o.getLeftmostDescendantIndex(); // if (thisCorner != -1 && thatCorner != -1) { // if (thisCorner < thatCorner) return BEFORE; // if (thisCorner > thatCorner) return AFTER; // } // thisCorner = this.getRightmostDescendantIndex(); // thatCorner = (o instanceof TerminalNode)?o.getCompareToIndex():o.getRightmostDescendantIndex(); // if (thisCorner != -1 && thatCorner != -1) { // if (thisCorner < thatCorner) return BEFORE; // if (thisCorner > thatCorner) return AFTER; // } } catch (MaltChainedException e) { if (SystemLogger.logger().isDebugEnabled()) { SystemLogger.logger().debug("", e); } else { SystemLogger.logger().error(e.getMessageChain()); } System.exit(1); } if (0 < o.getCompareToIndex()) { return BEFORE; } if (0 > o.getCompareToIndex()) { return AFTER; } return super.compareTo(o); // // if (o instanceof TerminalNode) { // if (0 == o.getIndex()) { // // } else if (0 < o.getIndex()) { // return -1; // } else { // return 1; // } // } else if (o instanceof Root) { // return super.compareTo(o); // } else if (o instanceof NonTerminalNode) { // int lcorner = ((NonTerminalNode)o).getLeftCornerIndex(); // if (0 == lcorner) { // int rcorner = ((NonTerminalNode)o).getRightCornerIndex(); // if (0 == rcorner) { // if (0 == o.getIndex()) { // return super.compareTo(o); // } else if (0 < o.getIndex()) { // return 1; // } else { // return -1; // } // } else if (0 < rcorner) { // return -1; // } else { // return 1; // } // } else if (0 < lcorner) { // return -1; // } else { // return 1; // } // } // return super.compareTo(o); } @Override public boolean equals(Object obj) { return super.equals(obj); } @Override public int hashCode() { return 31 * 7 + super.hashCode(); } @Override public String toString() { final StringBuilder sb = new StringBuilder(); sb.append(super.toString()); return sb.toString(); } }