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 }