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 }