001package org.maltparser.parser.algorithm.planar;
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 PlanarConfig extends ParserConfiguration {
015        // Root Handling
016        /*
017        public static final int STRICT = 1; //root tokens unattached, Reduce not permissible
018        public static final int RELAXED = 2; //root tokens unattached, Reduce permissible
019        public static final int NORMAL = 3; //root tokens attached to Root with RightArc
020        */
021        
022        //Connectedness enforcing
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        // Root Handling
028        public static final int NORMAL = 1; //root tokens attached to Root with RightArc
029        public static final int RELAXED = 2; //root tokens unattached
030        
031        //Constraints
032        public final boolean SINGLE_HEAD = true; //single-head constraint
033        public boolean noCoveredRoots = false; //no-covered-roots constraint
034        public boolean acyclicity = true; //acyclicity constraint
035        public int connectedness = NO_CONNECTEDNESS; //connectedness constraint
036        
037        
038        private final Stack<DependencyNode> stack;
039        private final Stack<DependencyNode> input;
040        private DependencyStructure dependencyGraph;
041        
042        
043        //root handling: explicitly create links to dummy root or not?
044        private int rootHandling;
045
046        
047        public PlanarConfig(String noCoveredRoots , String acyclicity , String connectedness , String rootHandling ) throws MaltChainedException {
048                super();
049                stack = new Stack<DependencyNode>();
050                input = new Stack<DependencyNode>();
051                setRootHandling(rootHandling);
052                setNoCoveredRoots(Boolean.valueOf(noCoveredRoots));
053                setAcyclicity(Boolean.valueOf(acyclicity));
054                setConnectedness(connectedness);
055        }
056        
057        public Stack<DependencyNode> getStack() {
058                return stack;
059        }
060        
061        public Stack<DependencyNode> getInput() {
062                return input;
063        }
064        
065        public DependencyStructure getDependencyStructure() {
066                return dependencyGraph;
067        }
068        
069        public boolean isTerminalState() {
070                return input.isEmpty();
071        }
072        
073        public DependencyNode getStackNode(int index) throws MaltChainedException {
074                if (index < 0) {
075                        throw new ParsingException("Stack index must be non-negative in feature specification. ");
076                }
077                if (stack.size()-index > 0) {
078                        return stack.get(stack.size()-1-index);
079                }
080                return null;
081        }
082        
083        public DependencyNode getInputNode(int index) throws MaltChainedException {
084                if (index < 0) {
085                        throw new ParsingException("Input index must be non-negative in feature specification. ");
086                }
087                if (input.size()-index > 0) {
088                        return input.get(input.size()-1-index);
089                }       
090                return null;
091        }
092        
093        public void setDependencyGraph(DependencyStructure source) throws MaltChainedException {
094                this.dependencyGraph = source;
095//              dependencyGraph.clear();
096//              for (int index : source.getTokenIndices()) {
097//                      DependencyNode gnode = source.getDependencyNode(index);
098//                      DependencyNode pnode = dependencyGraph.addDependencyNode(gnode.getIndex());
099//                      for (SymbolTable table : gnode.getLabelTypes()) {
100//                              pnode.addLabel(table, gnode.getLabelSymbol(table));
101//                      }
102//                      
103//                      if (gnode.hasHead()) {
104//                              Edge s = gnode.getHeadEdge();
105//                              Edge t = dependencyGraph.addDependencyEdge(s.getSource().getIndex(), s.getTarget().getIndex());
106//                              
107//                              for (SymbolTable table : s.getLabelTypes()) {
108//                                      t.addLabel(table, s.getLabelSymbol(table));
109//                              }
110//                      }
111//              }
112//              for (SymbolTable table : source.getDefaultRootEdgeLabels().keySet()) {
113//                      dependencyGraph.setDefaultRootEdgeLabel(table, source.getDefaultRootEdgeLabelSymbol(table));
114//              }
115        }
116        
117        public DependencyStructure getDependencyGraph() {
118                return dependencyGraph;
119        }
120        
121        public void initialize(ParserConfiguration parserConfiguration) throws MaltChainedException {
122                if (parserConfiguration != null) {
123                        PlanarConfig planarConfig = (PlanarConfig)parserConfiguration;
124                        Stack<DependencyNode> sourceStack = planarConfig.getStack();
125                        Stack<DependencyNode> sourceInput = planarConfig.getInput();
126                        setDependencyGraph(planarConfig.getDependencyGraph());
127                        for (int i = 0, n = sourceStack.size(); i < n; i++) {
128                                stack.add(dependencyGraph.getDependencyNode(sourceStack.get(i).getIndex()));
129                        }
130                        for (int i = 0, n = sourceInput.size(); i < n; i++) {
131                                input.add(dependencyGraph.getDependencyNode(sourceInput.get(i).getIndex()));
132                        }
133                } else {
134                        stack.push(dependencyGraph.getDependencyRoot());
135                        for (int i = dependencyGraph.getHighestTokenIndex(); i > 0; i--) {
136                                final DependencyNode node = dependencyGraph.getDependencyNode(i);
137                                if (node != null && !node.hasHead()) { 
138                                        input.push(node);
139                                }
140                        }
141                }
142        }
143        
144        public void initialize() throws MaltChainedException {
145                stack.push(dependencyGraph.getDependencyRoot());
146                for (int i = dependencyGraph.getHighestTokenIndex(); i > 0; i--) {
147                        final DependencyNode node = dependencyGraph.getDependencyNode(i);
148                        if (node != null && !node.hasHead()) { 
149                                input.push(node);
150                        }
151                }
152        }
153        /*
154        public int getRootHandling() {
155                return rootHandling;
156        }
157        */
158        
159        public boolean requiresSingleHead()
160        {
161                return SINGLE_HEAD;
162        }
163        
164        public boolean requiresNoCoveredRoots()
165        {
166                return noCoveredRoots;
167        }
168        
169        public boolean requiresAcyclicity()
170        {
171                return acyclicity;
172        }
173        
174        public boolean requiresConnectednessCheckOnReduce()
175        {
176                return connectedness != NO_CONNECTEDNESS;
177        }
178        
179        public boolean requiresConnectednessCheckOnShift()
180        {
181                return connectedness == FULL_CONNECTEDNESS;
182        }
183        
184        public void setNoCoveredRoots ( boolean value ) {noCoveredRoots = value;}
185        
186        public void setAcyclicity ( boolean value ) {acyclicity = value;}
187
188        protected void setConnectedness(String conn) throws MaltChainedException {
189                if (conn.equalsIgnoreCase("none")) {
190                        connectedness = NO_CONNECTEDNESS;
191                } else if (conn.equalsIgnoreCase("reduceonly")) {
192                        connectedness = REDUCE_ONLY;
193                } else if (conn.equalsIgnoreCase("full")) {
194                        connectedness = FULL_CONNECTEDNESS;
195                } else {
196                        throw new ParsingException("The connectedness constraint option '"+conn+"' is unknown");
197                }
198        }
199        
200        /*
201        public void setRootHandling(int rootHandling) {
202                this.rootHandling = rootHandling;
203        }
204        
205        protected void setRootHandling(String rh) throws MaltChainedException {
206                if (rh.equalsIgnoreCase("strict")) {
207                        rootHandling = STRICT;
208                } else if (rh.equalsIgnoreCase("relaxed")) {
209                        rootHandling = RELAXED;
210                } else if (rh.equalsIgnoreCase("normal")) {
211                        rootHandling = NORMAL;
212                } else {
213                        throw new ParsingException("The root handling '"+rh+"' is unknown");
214                }
215        }
216        */
217        
218        public int getRootHandling() {
219                return rootHandling;
220        }
221        
222        protected void setRootHandling(String rh) throws MaltChainedException {
223                if (rh.equalsIgnoreCase("relaxed")) {
224                        rootHandling = RELAXED;
225                } else if (rh.equalsIgnoreCase("normal")) {
226                        rootHandling = NORMAL;
227                } else {
228                        throw new ParsingException("The root handling '"+rh+"' is unknown");
229                }
230        }
231        
232        public void clear() throws MaltChainedException {
233//              dependencyGraph.clear();
234                stack.clear();
235                input.clear();
236                historyNode = null;
237        }
238        
239        public boolean equals(Object obj) {
240                if (this == obj)
241                        return true;
242                if (obj == null)
243                        return false;
244                if (getClass() != obj.getClass())
245                        return false;
246                PlanarConfig that = (PlanarConfig)obj;
247                
248                if (stack.size() != that.getStack().size()) 
249                        return false;
250                if (input.size() != that.getInput().size())
251                        return false;
252                if (dependencyGraph.nEdges() != that.getDependencyGraph().nEdges())
253                        return false;
254                for (int i = 0; i < stack.size(); i++) {
255                        if (stack.get(i).getIndex() != that.getStack().get(i).getIndex()) {
256                                return false;
257                        }
258                }
259                for (int i = 0; i < input.size(); i++) {
260                        if (input.get(i).getIndex() != that.getInput().get(i).getIndex()) {
261                                return false;
262                        }
263                }               
264                return dependencyGraph.getEdges().equals(that.getDependencyGraph().getEdges());
265        }
266        
267        public String toString() {
268                final StringBuilder sb = new StringBuilder();
269                sb.append(stack.size());
270                sb.append(", ");
271                sb.append(input.size());
272                sb.append(", ");
273                sb.append(dependencyGraph.nEdges());
274                return sb.toString();
275        }
276}