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.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 TwoPlanar extends TransitionSystem {
021 protected static final int SHIFT = 1;
022 protected static final int SWITCH = 2;
023 protected static final int RIGHTARC = 3;
024 protected static final int LEFTARC = 4;
025 protected static final int REDUCE = 5;
026 protected static final int REDUCEBOTH = 6;
027
028
029
030
031 public TwoPlanar() throws MaltChainedException {
032 super();
033 }
034
035 public void apply(GuideUserAction currentAction, ParserConfiguration config) throws MaltChainedException {
036 TwoPlanarConfig planarConfig = (TwoPlanarConfig)config;
037 Stack<DependencyNode> activeStack = planarConfig.getActiveStack();
038 Stack<DependencyNode> inactiveStack = planarConfig.getInactiveStack();
039 Stack<DependencyNode> input = planarConfig.getInput();
040 currentAction.getAction(actionContainers);
041 Edge e = null;
042 int actionCode = transActionContainer.getActionCode();
043 switch ( actionCode ) {
044 case LEFTARC:
045 e = planarConfig.getDependencyStructure().addDependencyEdge(input.peek().getIndex(), activeStack.peek().getIndex());
046 addEdgeLabels(e);
047 break;
048 case RIGHTARC:
049 e = planarConfig.getDependencyStructure().addDependencyEdge(activeStack.peek().getIndex(), input.peek().getIndex());
050 addEdgeLabels(e);
051 break;
052 case SWITCH:
053 planarConfig.switchStacks();
054 if ( planarConfig.reduceAfterSwitch() )
055 {
056 planarConfig.getActiveStack().pop();
057 }
058 break;
059 case REDUCE:
060 activeStack.pop();
061 break;
062 case REDUCEBOTH:
063 activeStack.pop();
064 inactiveStack.pop();
065 break;
066 default: //SHIFT
067 DependencyNode n = input.pop();
068 activeStack.push(n);
069 inactiveStack.push(n);
070 break;
071 }
072 planarConfig.setLastAction(actionCode);
073 }
074
075
076 public GuideUserAction getDeterministicAction(GuideUserHistory history, ParserConfiguration config) throws MaltChainedException {
077 TwoPlanarConfig theConfig = (TwoPlanarConfig)config;
078 if (theConfig.getRootHandling() != TwoPlanarConfig.NORMAL && theConfig.getActiveStack().peek().isRoot()) {
079 return updateActionContainers(history, TwoPlanar.SHIFT, null);
080 }
081 return null;
082 }
083
084 protected void addAvailableTransitionToTable(TransitionTable ttable) throws MaltChainedException {
085 ttable.addTransition(SHIFT, "SH", false, null);
086 ttable.addTransition(SWITCH, "SW", false, null);
087 ttable.addTransition(REDUCE, "RE", false, null);
088 ttable.addTransition(REDUCEBOTH, "RB", false, null);
089 ttable.addTransition(RIGHTARC, "RA", true, null);
090 ttable.addTransition(LEFTARC, "LA", true, null);
091 }
092
093 protected void initWithDefaultTransitions(GuideUserHistory history) throws MaltChainedException {
094 GuideUserAction currentAction = new ComplexDecisionAction((History)history);
095
096 transActionContainer.setAction(SHIFT);
097 transActionContainer.setAction(REDUCE);
098 transActionContainer.setAction(SWITCH); //TODO it seems like a good idea to do this, but I don't know what it actually does
099 transActionContainer.setAction(REDUCEBOTH); //TODO same as above
100 for (int i = 0; i < arcLabelActionContainers.length; i++) {
101 arcLabelActionContainers[i].setAction(-1);
102 }
103 currentAction.addAction(actionContainers);
104 }
105
106 public String getName() {
107 return "two-planar arc-eager";
108 }
109
110 public boolean permissible(GuideUserAction currentAction, ParserConfiguration config) throws MaltChainedException {
111 currentAction.getAction(actionContainers);
112 int trans = transActionContainer.getActionCode();
113 TwoPlanarConfig planarConfig = (TwoPlanarConfig)config;
114 DependencyNode activeStackPeek = planarConfig.getActiveStack().peek();
115 DependencyNode inactiveStackPeek = planarConfig.getInactiveStack().peek();
116 DependencyNode inputPeek = planarConfig.getInput().peek();
117 DependencyStructure dg = planarConfig.getDependencyGraph();
118 //int rootHandling = planarConfig.getRootHandling();
119 boolean singleHeadConstraint = planarConfig.requiresSingleHead();
120 boolean noCoveredRootsConstraint = planarConfig.requiresNoCoveredRoots();
121 boolean acyclicityConstraint = planarConfig.requiresAcyclicity();
122 //boolean connectednessConstraintOnReduce = planarConfig.requiresConnectednessCheckOnReduce();
123 //boolean connectednessConstraintOnShift = planarConfig.requiresConnectednessCheckOnShift();
124 if ((trans == LEFTARC || trans == RIGHTARC) && !isActionContainersLabeled()) {
125 return false;
126 }
127 //if ((trans == LEFTARC || trans == REDUCE) && stackPeek.isRoot()) {
128 // return false;
129 //}
130 if (trans == LEFTARC) {
131 //avoid making root child of something
132 if ( activeStackPeek.isRoot() )
133 return false;
134 //enforce single-head constraint if present
135 if ( activeStackPeek.hasHead() && singleHeadConstraint )
136 return false;
137 //avoid two links being created from and to the same node
138 if ( activeStackPeek.hasHead() && dg.getTokenNode(activeStackPeek.getIndex()).getHead().getIndex() == inputPeek.getIndex() )
139 return false;
140 //enforce acyclicity constraint if present
141 if ( acyclicityConstraint && activeStackPeek.findComponent().getIndex() == inputPeek.findComponent().getIndex() )
142 return false;
143 }
144 if (trans == RIGHTARC) {
145 //enforce single-head constraint if present
146 if ( inputPeek.hasHead() && singleHeadConstraint )
147 return false;
148 //avoid two links being created from and to the same node
149 if ( inputPeek.hasHead() && dg.getTokenNode(inputPeek.getIndex()).getHead().getIndex() == activeStackPeek.getIndex() )
150 return false;
151 //enforce acyclicity constraint if present
152 if ( acyclicityConstraint && activeStackPeek.findComponent().getIndex() == inputPeek.findComponent().getIndex() )
153 return false;
154 }
155 if (trans == REDUCE) {
156 //do not reduce the dummy root
157 if ( activeStackPeek.isRoot() )
158 return false;
159 //enforce no-covered-roots constraint if present
160 if ( !activeStackPeek.hasHead() && noCoveredRootsConstraint )
161 return false;
162 //TODO does this line still make sense? (from Nivre arc-eager)
163 //if ( !stackPeek.hasHead() && rootHandling == PlanarConfig.STRICT )
164 // return false;
165 //enforce connectedness constraint if present
166 /*
167 if ( connectednessConstraintOnReduce )
168 {
169 boolean path1 = ( stackPeek.findComponent().getIndex() == inputPeek.findComponent().getIndex() );
170 boolean path2;
171 if ( planarConfig.getStack().size() < 2 ) path2=false;
172 else
173 {
174 DependencyNode stackPrev = planarConfig.getStack().get(planarConfig.getStack().size()-2);
175 path2 = stackPrev.findComponent().getIndex() == stackPeek.findComponent().getIndex();
176 }
177 return path1 || path2;
178 }
179 */
180 }
181 if ( trans == SHIFT )
182 {
183 /*
184 if ( connectednessConstraintOnShift && planarConfig.getInput().size() == 1 ) //last word
185 {
186 boolean path = ( planarConfig.getDependencyGraph().getTokenNode(1).findComponent().getIndex() == inputPeek.findComponent().getIndex() ); //require connection to 1st
187 return path;
188 }
189 */
190 }
191 if (trans == REDUCEBOTH) {
192 //do not reduce the dummy root
193 if ( activeStackPeek.isRoot() || inactiveStackPeek.isRoot() )
194 return false;
195 //enforce no-covered-roots constraint if present
196 if ( (!activeStackPeek.hasHead() || inactiveStackPeek.hasHead()) && noCoveredRootsConstraint )
197 return false;
198
199 //TODO remove this:
200 //not using this transition at the moment, so
201 return false;
202 }
203 if ( trans == SWITCH )
204 {
205 if ( planarConfig.reduceAfterSwitch() )
206 {
207 if ( inactiveStackPeek.isRoot() )
208 return false;
209 //enforce no-covered-roots constraint if present
210 if ( !inactiveStackPeek.hasHead() && noCoveredRootsConstraint )
211 return false;
212 }
213 else
214 {
215 if ( planarConfig.getLastAction() == SWITCH ) return false;
216 }
217 }
218 return true;
219 }
220
221 public GuideUserAction defaultAction(GuideUserHistory history, ParserConfiguration configuration) throws MaltChainedException {
222 return updateActionContainers(history, TwoPlanar.SHIFT, null);
223 }
224
225
226 }