    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    }