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 }