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    }