001package org.maltparser.parser.algorithm.twoplanar; 002 003import java.util.Stack; 004 005import org.maltparser.core.exception.MaltChainedException; 006import org.maltparser.core.syntaxgraph.DependencyStructure; 007import org.maltparser.core.syntaxgraph.node.DependencyNode; 008import org.maltparser.parser.ParserConfiguration; 009import org.maltparser.parser.ParsingException; 010/** 011 * @author Carlos Gomez Rodriguez 012 * 013 */ 014public class TwoPlanarConfig extends ParserConfiguration { 015 016 017 //Connectedness enforcing 018 /* 019 public static final int NO_CONNECTEDNESS = 1; 020 public static final int REDUCE_ONLY = 2; //connectedness enforced on reduce only 021 public static final int FULL_CONNECTEDNESS = 3; //connectedness enforced on shift and reduce 022 */ 023 024 // Root Handling 025 public static final int NORMAL = 1; //root tokens attached to Root with RightArc 026 public static final int RELAXED = 2; //root tokens unattached 027 028 //Constraints 029 public final boolean SINGLE_HEAD = true; //single-head constraint 030 public boolean noCoveredRoots = false; //no-covered-roots constraint 031 public boolean acyclicity = true; //acyclicity constraint 032 033 //public int connectedness = NO_CONNECTEDNESS; //connectedness constraint 034 035 public boolean reduceAfterSwitch = false; 036 037 038 private final Stack<DependencyNode> firstStack; 039 private final Stack<DependencyNode> secondStack; 040 041 public static final boolean FIRST_STACK = false; 042 public static final boolean SECOND_STACK = true; 043 044 private boolean activeStack; 045 046 private Stack<DependencyNode> input; 047 048 private DependencyStructure dependencyGraph; 049 050 //root handling: explicitly create links to dummy root or not? 051 private int rootHandling; 052 053 //needed to disallow two consecutive switches: 054 private int lastAction; 055 056 057 public TwoPlanarConfig(String noCoveredRoots , String acyclicity , String reduceAfterSwitch , String rootHandling) throws MaltChainedException { 058 super(); 059 firstStack = new Stack<DependencyNode>(); 060 secondStack = new Stack<DependencyNode>(); 061 activeStack = FIRST_STACK; 062 input = new Stack<DependencyNode>(); 063// dependencyGraph = new DependencyGraph(symbolTableHandler); 064 setRootHandling(rootHandling); 065 setNoCoveredRoots(Boolean.valueOf(noCoveredRoots)); 066 setAcyclicity(Boolean.valueOf(acyclicity)); 067 setReduceAfterSwitch(Boolean.valueOf(reduceAfterSwitch)); 068 } 069 070 public void switchStacks() 071 { 072 activeStack = !activeStack; 073 } 074 075 public boolean reduceAfterSwitch () 076 { 077 return reduceAfterSwitch; 078 } 079 080 public void setReduceAfterSwitch ( boolean ras ) 081 { 082 reduceAfterSwitch = ras; 083 } 084 085 public void setLastAction ( int action ) 086 { 087 lastAction = action; 088 } 089 090 public int getLastAction ( ) 091 { 092 return lastAction; 093 } 094 095 public boolean getStackActivityState() 096 { 097 return activeStack; 098 } 099 100 private Stack<DependencyNode> getFirstStack() { 101 return firstStack; 102 } 103 104 private Stack<DependencyNode> getSecondStack() { 105 return secondStack; 106 } 107 108 public Stack<DependencyNode> getActiveStack() { 109 if ( activeStack == FIRST_STACK ) return getFirstStack(); 110 else return getSecondStack(); 111 } 112 113 public Stack<DependencyNode> getInactiveStack() { 114 if ( activeStack == FIRST_STACK ) return getSecondStack(); 115 else return getFirstStack(); 116 } 117 118 public Stack<DependencyNode> getInput() { 119 return input; 120 } 121 122 public DependencyStructure getDependencyStructure() { 123 return dependencyGraph; 124 } 125 126 public boolean isTerminalState() { 127 return input.isEmpty(); 128 } 129 130 private DependencyNode getStackNode(Stack<DependencyNode> stack , int index) throws MaltChainedException { 131 if (index < 0) { 132 throw new ParsingException("Stack index must be non-negative in feature specification. "); 133 } 134 if (stack.size()-index > 0) { 135 return stack.get(stack.size()-1-index); 136 } 137 return null; 138 } 139 140 public DependencyNode getActiveStackNode ( int index ) throws MaltChainedException { 141 return getStackNode ( getActiveStack() , index ); 142 } 143 144 public DependencyNode getInactiveStackNode ( int index ) throws MaltChainedException { 145 return getStackNode ( getInactiveStack() , index ); 146 } 147 148 public DependencyNode getInputNode(int index) throws MaltChainedException { 149 if (index < 0) { 150 throw new ParsingException("Input index must be non-negative in feature specification. "); 151 } 152 if (input.size()-index > 0) { 153 return input.get(input.size()-1-index); 154 } 155 return null; 156 } 157 158 public void setDependencyGraph(DependencyStructure source) throws MaltChainedException { 159 this.dependencyGraph = source; 160// dependencyGraph.clear(); 161// for (int index : source.getTokenIndices()) { 162// DependencyNode gnode = source.getDependencyNode(index); 163// DependencyNode pnode = dependencyGraph.addDependencyNode(gnode.getIndex()); 164// for (SymbolTable table : gnode.getLabelTypes()) { 165// pnode.addLabel(table, gnode.getLabelSymbol(table)); 166// } 167// 168// if (gnode.hasHead()) { 169// Edge s = gnode.getHeadEdge(); 170// Edge t = dependencyGraph.addDependencyEdge(s.getSource().getIndex(), s.getTarget().getIndex()); 171// 172// for (SymbolTable table : s.getLabelTypes()) { 173// t.addLabel(table, s.getLabelSymbol(table)); 174// } 175// } 176// } 177 } 178 179 public DependencyStructure getDependencyGraph() { 180 return dependencyGraph; 181 } 182 183 public void initialize(ParserConfiguration parserConfiguration) throws MaltChainedException { 184 if (parserConfiguration != null) { 185 TwoPlanarConfig planarConfig = (TwoPlanarConfig)parserConfiguration; 186 this.activeStack = planarConfig.activeStack; 187 Stack<DependencyNode> sourceActiveStack = planarConfig.getActiveStack(); 188 Stack<DependencyNode> sourceInactiveStack = planarConfig.getInactiveStack(); 189 Stack<DependencyNode> sourceInput = planarConfig.getInput(); 190 setDependencyGraph(planarConfig.getDependencyGraph()); 191 for (int i = 0, n = sourceActiveStack.size(); i < n; i++) { 192 getActiveStack().add(dependencyGraph.getDependencyNode(sourceActiveStack.get(i).getIndex())); 193 } 194 for ( int i =0, n = sourceInactiveStack.size() ; i < n ; i++ ) { 195 getInactiveStack().add(dependencyGraph.getDependencyNode(sourceInactiveStack.get(i).getIndex())); 196 } 197 for (int i = 0, n = sourceInput.size(); i < n; i++) { 198 input.add(dependencyGraph.getDependencyNode(sourceInput.get(i).getIndex())); 199 } 200 } else { 201 getActiveStack().push(dependencyGraph.getDependencyRoot()); 202 getInactiveStack().push(dependencyGraph.getDependencyRoot()); 203 for (int i = dependencyGraph.getHighestTokenIndex(); i > 0; i--) { 204 final DependencyNode node = dependencyGraph.getDependencyNode(i); 205 if (node != null) { 206 input.push(node); 207 } 208 } 209 } 210 } 211 212 public void initialize() throws MaltChainedException { 213 getActiveStack().push(dependencyGraph.getDependencyRoot()); 214 getInactiveStack().push(dependencyGraph.getDependencyRoot()); 215 for (int i = dependencyGraph.getHighestTokenIndex(); i > 0; i--) { 216 final DependencyNode node = dependencyGraph.getDependencyNode(i); 217 if (node != null) { 218 input.push(node); 219 } 220 } 221 } 222 223 public int getRootHandling() { 224 return rootHandling; 225 } 226 227 protected void setRootHandling(String rh) throws MaltChainedException { 228 if (rh.equalsIgnoreCase("relaxed")) { 229 rootHandling = RELAXED; 230 } else if (rh.equalsIgnoreCase("normal")) { 231 rootHandling = NORMAL; 232 } else { 233 throw new ParsingException("The root handling '"+rh+"' is unknown"); 234 } 235 } 236 237 238 public boolean requiresSingleHead() 239 { 240 return SINGLE_HEAD; 241 } 242 243 public boolean requiresNoCoveredRoots() 244 { 245 return noCoveredRoots; 246 } 247 248 public boolean requiresAcyclicity() 249 { 250 return acyclicity; 251 } 252 253 //does not make much sense to enforce the no-covered-roots constraint in 2-planar parsing, it won't capture some 2-planar structures 254 public void setNoCoveredRoots ( boolean value ) {noCoveredRoots = value;} 255 256 public void setAcyclicity ( boolean value ) {acyclicity = value;} 257 258 public void clear() throws MaltChainedException { 259// dependencyGraph.clear(); 260 getActiveStack().clear(); 261 getInactiveStack().clear(); 262 input.clear(); 263 historyNode = null; 264 } 265 266 public boolean equals(Object obj) { 267 if (this == obj) 268 return true; 269 if (obj == null) 270 return false; 271 if (getClass() != obj.getClass()) 272 return false; 273 TwoPlanarConfig that = (TwoPlanarConfig)obj; 274 275 if (getActiveStack().size() != that.getActiveStack().size()) 276 return false; 277 if (getInactiveStack().size() != that.getInactiveStack().size()) 278 return false; 279 if (input.size() != that.getInput().size()) 280 return false; 281 if (dependencyGraph.nEdges() != that.getDependencyGraph().nEdges()) 282 return false; 283 for (int i = 0; i < getActiveStack().size(); i++) { 284 if (getActiveStack().get(i).getIndex() != that.getActiveStack().get(i).getIndex()) { 285 return false; 286 } 287 } 288 for (int i = 0; i < getInactiveStack().size(); i++) { 289 if (getInactiveStack().get(i).getIndex() != that.getInactiveStack().get(i).getIndex()) { 290 return false; 291 } 292 } 293 for (int i = 0; i < input.size(); i++) { 294 if (input.get(i).getIndex() != that.getInput().get(i).getIndex()) { 295 return false; 296 } 297 } 298 return dependencyGraph.getEdges().equals(that.getDependencyGraph().getEdges()); 299 } 300 301 public String toString() { 302 final StringBuilder sb = new StringBuilder(); 303 sb.append(getActiveStack().size()); 304 sb.append(", "); 305 sb.append(getInactiveStack().size()); 306 sb.append(", "); 307 sb.append(input.size()); 308 sb.append(", "); 309 sb.append(dependencyGraph.nEdges()); 310 return sb.toString(); 311 } 312}