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}