    001    package org.maltparser.parser.algorithm.planar;
    002
    003    import java.util.Stack;
    004
    005    import org.maltparser.core.exception.MaltChainedException;
    006    import org.maltparser.core.syntaxgraph.DependencyStructure;
    007    import org.maltparser.core.syntaxgraph.edge.Edge;
    008    import org.maltparser.core.syntaxgraph.node.DependencyNode;
    009    import org.maltparser.parser.ParserConfiguration;
    010    import org.maltparser.parser.TransitionSystem;
    011    import org.maltparser.parser.history.GuideUserHistory;
    012    import org.maltparser.parser.history.History;
    013    import org.maltparser.parser.history.action.ComplexDecisionAction;
    014    import org.maltparser.parser.history.action.GuideUserAction;
    015    import org.maltparser.parser.transition.TransitionTable;
    016    /**
    017     * @author Carlos Gomez Rodriguez
    018     *
    019     */
    020    public class Planar extends TransitionSystem {
    021            protected static final int SHIFT = 1;
    022            protected static final int REDUCE = 2;
    023            protected static final int RIGHTARC = 3;
    024            protected static final int LEFTARC = 4;
    025
    026            public Planar() throws MaltChainedException {
    027                    super();
    028            }
    029
    030            public void apply(GuideUserAction currentAction, ParserConfiguration config) throws MaltChainedException {
    031                    PlanarConfig planarConfig = (PlanarConfig)config;
    032                    Stack<DependencyNode> stack = planarConfig.getStack();
    033                    Stack<DependencyNode> input = planarConfig.getInput();
    034                    currentAction.getAction(actionContainers);
    035                    Edge e = null;
    036                    switch (transActionContainer.getActionCode()) {
    037                    case LEFTARC:
    038                            e = planarConfig.getDependencyStructure().addDependencyEdge(input.peek().getIndex(), stack.peek().getIndex());
    039                            addEdgeLabels(e);
    040                            break;
    041                    case RIGHTARC:
    042                            e = planarConfig.getDependencyStructure().addDependencyEdge(stack.peek().getIndex(), input.peek().getIndex());
    043                            addEdgeLabels(e);
    044                            break;
    045                    case REDUCE:
    046                            stack.pop();
    047                            break;
    048                    default: //SHIFT
    049                            stack.push(input.pop());
    050                            break;
    051                    }
    052            }
    053
    054            public GuideUserAction getDeterministicAction(GuideUserHistory history, ParserConfiguration config) throws MaltChainedException {
    055                    //PlanarConfig planarConfig = (PlanarConfig)config;
    056                    //if (planarConfig.getRootHandling() != PlanarConfig.NORMAL && planarConfig.getStack().peek().isRoot()) {
    057                    //      return updateActionContainers(history, Planar.SHIFT, null);
    058                    //}
    059                    //TODO: yeah, shift root
    060                    return null;
    061            }
    062
    063            protected void addAvailableTransitionToTable(TransitionTable ttable) throws MaltChainedException {
    064                    ttable.addTransition(SHIFT, "SH", false, null);
    065                    ttable.addTransition(REDUCE, "RE", false, null);
    066                    ttable.addTransition(RIGHTARC, "RA", true, null);
    067                    ttable.addTransition(LEFTARC, "LA", true, null);
    068            }
    069
    070            protected void initWithDefaultTransitions(GuideUserHistory history) throws MaltChainedException {
    071                    GuideUserAction currentAction = new ComplexDecisionAction((History)history);
    072
    073                    transActionContainer.setAction(SHIFT);
    074                    transActionContainer.setAction(REDUCE);
    075                    for (int i = 0; i < arcLabelActionContainers.length; i++) {
    076                            arcLabelActionContainers[i].setAction(-1);
    077                    }
    078                    currentAction.addAction(actionContainers);
    079            }
    080
    081            public String getName() {
    082                    return "planar arc-eager";
    083            }
    084
    085            public boolean permissible(GuideUserAction currentAction, ParserConfiguration config) throws MaltChainedException {
    086                    currentAction.getAction(actionContainers);
    087                    int trans = transActionContainer.getActionCode();
    088                    PlanarConfig planarConfig = (PlanarConfig)config;
    089                    DependencyNode stackPeek = planarConfig.getStack().peek();
    090                    DependencyNode inputPeek = planarConfig.getInput().peek();
    091                    DependencyStructure dg = planarConfig.getDependencyGraph();
    092                    //int rootHandling = planarConfig.getRootHandling();
    093                    boolean singleHeadConstraint = planarConfig.requiresSingleHead();
    094                    boolean noCoveredRootsConstraint = planarConfig.requiresNoCoveredRoots();
    095                    boolean acyclicityConstraint = planarConfig.requiresAcyclicity();
    096                    boolean connectednessConstraintOnReduce = planarConfig.requiresConnectednessCheckOnReduce();
    097                    boolean connectednessConstraintOnShift = planarConfig.requiresConnectednessCheckOnShift();
    098                    if ((trans == LEFTARC || trans == RIGHTARC) && !isActionContainersLabeled()) {
    099                            return false;
    100                    }
    101                    //if ((trans == LEFTARC || trans == REDUCE) && stackPeek.isRoot()) {
    102                    //      return false;
    103                    //}
    104                    if (trans == LEFTARC) {
    105                            //avoid making root child of something
    106                            if ( stackPeek.isRoot() )
    107                                    return false;
    108                            //enforce single-head constraint if present
    109                            if ( stackPeek.hasHead() && singleHeadConstraint )
    110                                    return false;
    111                            //avoid two links being created from and to the same node
    112                            if ( stackPeek.hasHead() && dg.getTokenNode(stackPeek.getIndex()).getHead().getIndex() == inputPeek.getIndex() )
    113                                    return false;
    114                            //enforce acyclicity constraint if present
    115                            if ( acyclicityConstraint && stackPeek.findComponent().getIndex() == inputPeek.findComponent().getIndex() )
    116                                    return false;
    117                    }
    118                    if (trans == RIGHTARC) {
    119                            //enforce single-head constraint if present
    120                            if ( inputPeek.hasHead() && singleHeadConstraint )
    121                                    return false;
    122                            //avoid two links being created from and to the same node
    123                            if ( inputPeek.hasHead() && dg.getTokenNode(inputPeek.getIndex()).getHead().getIndex() == stackPeek.getIndex() )
    124                                    return false;
    125                            //enforce acyclicity constraint if present
    126                            if ( acyclicityConstraint && stackPeek.findComponent().getIndex() == inputPeek.findComponent().getIndex() )
    127                                    return false;
    128                    }
    129                    if (trans == REDUCE) {
    130                            //do not reduce the dummy root
    131                            if ( stackPeek.isRoot() )
    132                                    return false;
    133                            //enforce no-covered-roots constraint if present
    134                            if ( !stackPeek.hasHead() && noCoveredRootsConstraint )
    135                                    return false;
    136                            //TODO does this line still make sense? (from Nivre arc-eager)
    137                            //if ( !stackPeek.hasHead() && rootHandling == PlanarConfig.STRICT )
    138                            //      return false;
    139                            //enforce connectedness constraint if present
    140                            if ( connectednessConstraintOnReduce )
    141                            {
    142                                    boolean path1 = ( stackPeek.findComponent().getIndex() == inputPeek.findComponent().getIndex() );
    143                                    boolean path2;
    144                                    if ( planarConfig.getStack().size() < 2 ) path2=false;
    145                                    else
    146                                    {
    147                                            DependencyNode stackPrev = planarConfig.getStack().get(planarConfig.getStack().size()-2);
    148                                            path2 = stackPrev.findComponent().getIndex() == stackPeek.findComponent().getIndex();
    149                                    }
    150                                    return path1 || path2;
    151                            }
    152                    }
    153                    if ( trans == SHIFT )
    154                    {
    155                            if ( connectednessConstraintOnShift && planarConfig.getInput().size() == 1 ) //last word
    156                            {
    157                                    boolean path = ( planarConfig.getDependencyGraph().getTokenNode(1).findComponent().getIndex() == inputPeek.findComponent().getIndex() ); //require connection to 1st
    158                                    return path;
    159                            }
    160                    }
    161                    return true;
    162            }
    163
    164            public GuideUserAction defaultAction(GuideUserHistory history, ParserConfiguration configuration) throws MaltChainedException {
    165                    return updateActionContainers(history, Planar.SHIFT, null);
    166            }
    167    }