    001    package org.maltparser.parser.algorithm.twoplanar;
    002
    003    import java.util.Stack;
    004
    005    import org.maltparser.core.exception.MaltChainedException;
    006    import org.maltparser.core.symbol.SymbolTable;
    007    import org.maltparser.core.symbol.SymbolTableHandler;
    008    import org.maltparser.core.syntaxgraph.DependencyGraph;
    009    import org.maltparser.core.syntaxgraph.DependencyStructure;
    010    import org.maltparser.core.syntaxgraph.edge.Edge;
    011    import org.maltparser.core.syntaxgraph.node.DependencyNode;
    012    import org.maltparser.parser.ParserConfiguration;
    013    import org.maltparser.parser.ParsingException;
    014    /**
    015     * @author Carlos Gomez Rodriguez
    016     *
    017     */
    018    public class TwoPlanarConfig extends ParserConfiguration {
    019
    020
    021            //Connectedness enforcing
    022            /*
    023            public static final int NO_CONNECTEDNESS = 1;
    024            public static final int REDUCE_ONLY = 2; //connectedness enforced on reduce only
    025            public static final int FULL_CONNECTEDNESS = 3; //connectedness enforced on shift and reduce
    026            */
    027
    028            // Root Handling
    029            public static final int NORMAL = 1; //root tokens attached to Root with RightArc
    030            public static final int RELAXED = 2; //root tokens unattached
    031
    032            //Constraints
    033            public final boolean SINGLE_HEAD = true; //single-head constraint
    034            public boolean noCoveredRoots = false; //no-covered-roots constraint
    035            public boolean acyclicity = true; //acyclicity constraint
    036
    037            //public int connectedness = NO_CONNECTEDNESS; //connectedness constraint
    038
    039            public boolean reduceAfterSwitch = false;
    040
    041
    042            private Stack<DependencyNode> firstStack;
    043            private Stack<DependencyNode> secondStack;
    044
    045            public static final boolean FIRST_STACK = false;
    046            public static final boolean SECOND_STACK = true;
    047
    048            private boolean activeStack;
    049
    050            private Stack<DependencyNode> input;
    051
    052            private DependencyStructure dependencyGraph;
    053
    054            //root handling: explicitly create links to dummy root or not?
    055            private int rootHandling;
    056
    057            //needed to disallow two consecutive switches:
    058            private int lastAction;
    059
    060
    061            public TwoPlanarConfig(SymbolTableHandler symbolTableHandler, String noCoveredRoots , String acyclicity , String reduceAfterSwitch , String rootHandling) throws MaltChainedException {
    062                    super();
    063                    firstStack = new Stack<DependencyNode>();
    064                    secondStack = new Stack<DependencyNode>();
    065                    activeStack = FIRST_STACK;
    066                    input = new Stack<DependencyNode>();
    067                    dependencyGraph = new DependencyGraph(symbolTableHandler);
    068                    setRootHandling(rootHandling);
    069                    setNoCoveredRoots(Boolean.valueOf(noCoveredRoots));
    070                    setAcyclicity(Boolean.valueOf(acyclicity));
    071                    setReduceAfterSwitch(Boolean.valueOf(reduceAfterSwitch));
    072            }
    073
    074            public void switchStacks()
    075            {
    076                    activeStack = !activeStack;
    077            }
    078
    079            public boolean reduceAfterSwitch ()
    080            {
    081                    return reduceAfterSwitch;
    082            }
    083
    084            public void setReduceAfterSwitch ( boolean ras )
    085            {
    086                    reduceAfterSwitch = ras;
    087            }
    088
    089            public void setLastAction ( int action )
    090            {
    091                    lastAction = action;
    092            }
    093
    094            public int getLastAction ( )
    095            {
    096                    return lastAction;
    097            }
    098
    099            public boolean getStackActivityState()
    100            {
    101                    return activeStack;
    102            }
    103
    104            private Stack<DependencyNode> getFirstStack() {
    105                    return firstStack;
    106            }
    107
    108            private Stack<DependencyNode> getSecondStack() {
    109                    return secondStack;
    110            }
    111
    112            public Stack<DependencyNode> getActiveStack() {
    113                    if ( activeStack == FIRST_STACK ) return getFirstStack();
    114                    else return getSecondStack();
    115            }
    116
    117            public Stack<DependencyNode> getInactiveStack() {
    118                    if ( activeStack == FIRST_STACK ) return getSecondStack();
    119                    else return getFirstStack();
    120            }
    121
    122            public Stack<DependencyNode> getInput() {
    123                    return input;
    124            }
    125
    126            public DependencyStructure getDependencyStructure() {
    127                    return dependencyGraph;
    128            }
    129
    130            public boolean isTerminalState() {
    131                    return input.isEmpty();
    132            }
    133
    134            private DependencyNode getStackNode(Stack<DependencyNode> stack , int index) throws MaltChainedException {
    135                    if (index < 0) {
    136                            throw new ParsingException("Stack index must be non-negative in feature specification. ");
    137                    }
    138                    if (stack.size()-index > 0) {
    139                            return stack.get(stack.size()-1-index);
    140                    }
    141                    return null;
    142            }
    143
    144            public DependencyNode getActiveStackNode ( int index ) throws MaltChainedException {
    145                    return getStackNode ( getActiveStack() , index );
    146            }
    147
    148            public DependencyNode getInactiveStackNode ( int index ) throws MaltChainedException {
    149                    return getStackNode ( getInactiveStack() , index );
    150            }
    151
    152            public DependencyNode getInputNode(int index) throws MaltChainedException {
    153                    if (index < 0) {
    154                            throw new ParsingException("Input index must be non-negative in feature specification. ");
    155                    }
    156                    if (input.size()-index > 0) {
    157                            return input.get(input.size()-1-index);
    158                    }
    159                    return null;
    160            }
    161
    162            public void setDependencyGraph(DependencyStructure source) throws MaltChainedException {
    163                    dependencyGraph.clear();
    164                    for (int index : source.getTokenIndices()) {
    165                            DependencyNode gnode = source.getTokenNode(index);
    166                            DependencyNode pnode = dependencyGraph.addTokenNode(gnode.getIndex());
    167                            for (SymbolTable table : gnode.getLabelTypes()) {
    168                                    pnode.addLabel(table, gnode.getLabelSymbol(table));
    169                            }
    170
    171                            if (gnode.hasHead()) {
    172                                    Edge s = gnode.getHeadEdge();
    173                                    Edge t = dependencyGraph.addDependencyEdge(s.getSource().getIndex(), s.getTarget().getIndex());
    174
    175                                    for (SymbolTable table : s.getLabelTypes()) {
    176                                            t.addLabel(table, s.getLabelSymbol(table));
    177                                    }
    178                            }
    179                    }
    180            }
    181
    182            public DependencyStructure getDependencyGraph() {
    183                    return dependencyGraph;
    184            }
    185
    186            public void initialize(ParserConfiguration parserConfiguration) throws MaltChainedException {
    187                    if (parserConfiguration != null) {
    188                            TwoPlanarConfig planarConfig = (TwoPlanarConfig)parserConfiguration;
    189                            this.activeStack = planarConfig.activeStack;
    190                            Stack<DependencyNode> sourceActiveStack = planarConfig.getActiveStack();
    191                            Stack<DependencyNode> sourceInactiveStack = planarConfig.getInactiveStack();
    192                            Stack<DependencyNode> sourceInput = planarConfig.getInput();
    193                            setDependencyGraph(planarConfig.getDependencyGraph());
    194                            for (int i = 0, n = sourceActiveStack.size(); i < n; i++) {
    195                                    getActiveStack().add(dependencyGraph.getDependencyNode(sourceActiveStack.get(i).getIndex()));
    196                            }
    197                            for ( int i =0, n = sourceInactiveStack.size() ; i < n ; i++ ) {
    198                                    getInactiveStack().add(dependencyGraph.getDependencyNode(sourceInactiveStack.get(i).getIndex()));
    199                            }
    200                            for (int i = 0, n = sourceInput.size(); i < n; i++) {
    201                                    input.add(dependencyGraph.getDependencyNode(sourceInput.get(i).getIndex()));
    202                            }
    203                    } else {
    204                            getActiveStack().push(dependencyGraph.getDependencyRoot());
    205                            getInactiveStack().push(dependencyGraph.getDependencyRoot());
    206                            for (int i = dependencyGraph.getHighestTokenIndex(); i > 0; i--) {
    207                                    final DependencyNode node = dependencyGraph.getDependencyNode(i);
    208                                    if (node != null) {
    209                                            input.push(node);
    210                                    }
    211                            }
    212                    }
    213            }
    214
    215
    216            public int getRootHandling() {
    217                    return rootHandling;
    218            }
    219
    220            protected void setRootHandling(String rh) throws MaltChainedException {
    221                    if (rh.equalsIgnoreCase("relaxed")) {
    222                            rootHandling = RELAXED;
    223                    } else if (rh.equalsIgnoreCase("normal")) {
    224                            rootHandling = NORMAL;
    225                    } else {
    226                            throw new ParsingException("The root handling '"+rh+"' is unknown");
    227                    }
    228            }
    229
    230
    231            public boolean requiresSingleHead()
    232            {
    233                    return SINGLE_HEAD;
    234            }
    235
    236            public boolean requiresNoCoveredRoots()
    237            {
    238                    return noCoveredRoots;
    239            }
    240
    241            public boolean requiresAcyclicity()
    242            {
    243                    return acyclicity;
    244            }
    245
    246            //does not make much sense to enforce the no-covered-roots constraint in 2-planar parsing, it won't capture some 2-planar structures
    247            public void setNoCoveredRoots ( boolean value ) {noCoveredRoots = value;}
    248
    249            public void setAcyclicity ( boolean value ) {acyclicity = value;}
    250
    251            public void clear() throws MaltChainedException {
    252                    dependencyGraph.clear();
    253                    getActiveStack().clear();
    254                    getInactiveStack().clear();
    255                    input.clear();
    256                    historyNode = null;
    257            }
    258
    259            public boolean equals(Object obj) {
    260                    if (this == obj)
    261                            return true;
    262                    if (obj == null)
    263                            return false;
    264                    if (getClass() != obj.getClass())
    265                            return false;
    266                    TwoPlanarConfig that = (TwoPlanarConfig)obj;
    267
    268                    if (getActiveStack().size() != that.getActiveStack().size())
    269                            return false;
    270                    if (getInactiveStack().size() != that.getInactiveStack().size())
    271                            return false;
    272                    if (input.size() != that.getInput().size())
    273                            return false;
    274                    if (dependencyGraph.nEdges() != that.getDependencyGraph().nEdges())
    275                            return false;
    276                    for (int i = 0; i < getActiveStack().size(); i++) {
    277                            if (getActiveStack().get(i).getIndex() != that.getActiveStack().get(i).getIndex()) {
    278                                    return false;
    279                            }
    280                    }
    281                    for (int i = 0; i < getInactiveStack().size(); i++) {
    282                            if (getInactiveStack().get(i).getIndex() != that.getInactiveStack().get(i).getIndex()) {
    283                                    return false;
    284                            }
    285                    }
    286                    for (int i = 0; i < input.size(); i++) {
    287                            if (input.get(i).getIndex() != that.getInput().get(i).getIndex()) {
    288                                    return false;
    289                            }
    290                    }
    291                    return dependencyGraph.getEdges().equals(that.getDependencyGraph().getEdges());
    292            }
    293
    294            public String toString() {
    295                    final StringBuilder sb = new StringBuilder();
    296                    sb.append(getActiveStack().size());
    297                    sb.append(", ");
    298                    sb.append(getInactiveStack().size());
    299                    sb.append(", ");
    300                    sb.append(input.size());
    301                    sb.append(", ");
    302                    sb.append(dependencyGraph.nEdges());
    303                    return sb.toString();
    304            }
    305    }