001package org.maltparser.core.lw.parser;
002import java.util.ArrayList;
003
004import org.maltparser.core.exception.MaltChainedException;
005import org.maltparser.core.feature.FeatureModel;
006import org.maltparser.core.feature.FeatureModelManager;
007import org.maltparser.core.helper.HashMap;
008import org.maltparser.core.symbol.SymbolTableHandler;
009import org.maltparser.core.symbol.TableHandler;
010import org.maltparser.core.syntaxgraph.DependencyStructure;
011import org.maltparser.parser.AlgoritmInterface;
012import org.maltparser.parser.DependencyParserConfig;
013import org.maltparser.parser.ParserConfiguration;
014import org.maltparser.parser.ParserRegistry;
015import org.maltparser.parser.TransitionSystem;
016import org.maltparser.parser.history.GuideUserHistory;
017import org.maltparser.parser.history.action.ComplexDecisionAction;
018import org.maltparser.parser.history.action.GuideUserAction;
019import org.maltparser.parser.history.container.ActionContainer;
020import org.maltparser.parser.history.container.CombinedTableContainer;
021import org.maltparser.parser.history.container.TableContainer;
022
023/**
024* A lightweight version of org.maltparser.parser.DeterministicParser. This class also implements a lightweight version of 
025* org.maltparser.parser.history.History and reduces the need of org.maltparser.parser.ParserState. 
026* 
027* The class must be used in the same thread.
028* 
029* @author Johan Hall
030*/
031public final class LWDeterministicParser implements AlgoritmInterface,  GuideUserHistory {
032        private final LWSingleMalt manager;
033        private final ParserRegistry registry;
034
035        private final TransitionSystem transitionSystem;
036        private final ParserConfiguration config;
037        private final FeatureModel featureModel;
038        private final ComplexDecisionAction currentAction;
039        
040        private final int kBestSize;
041        private final ArrayList<TableContainer> decisionTables;
042        private final ArrayList<TableContainer> actionTables; 
043        private final HashMap<String, TableHandler> tableHandlers;
044        
045        public LWDeterministicParser(LWSingleMalt lwSingleMalt, SymbolTableHandler symbolTableHandler, FeatureModel _featureModel) throws MaltChainedException {
046                this.manager = lwSingleMalt;
047                this.registry = new ParserRegistry();
048                this.registry.setSymbolTableHandler(symbolTableHandler);
049                this.registry.setDataFormatInstance(manager.getDataFormatInstance());
050                this.registry.setAbstractParserFeatureFactory(manager.getParserFactory());
051                this.registry.setAlgorithm(this);
052                this.transitionSystem = manager.getParserFactory().makeTransitionSystem();
053                this.transitionSystem.initTableHandlers(lwSingleMalt.getDecisionSettings(), symbolTableHandler);
054                
055                this.tableHandlers = transitionSystem.getTableHandlers();
056                this.kBestSize = lwSingleMalt.getkBestSize();
057                this.decisionTables = new ArrayList<TableContainer>();
058                this.actionTables = new ArrayList<TableContainer>();
059                initDecisionSettings(lwSingleMalt.getDecisionSettings(), lwSingleMalt.getClassitem_separator());
060                this.transitionSystem.initTransitionSystem(this);
061                this.config = manager.getParserFactory().makeParserConfiguration();
062                this.featureModel = _featureModel;
063                this.currentAction = new ComplexDecisionAction(this);
064        }
065        
066        public LWDeterministicParser(LWSingleMalt lwSingleMalt, SymbolTableHandler symbolTableHandler) throws MaltChainedException {
067                this.manager = lwSingleMalt;
068                this.registry = new ParserRegistry();
069                this.registry.setSymbolTableHandler(symbolTableHandler);
070                this.registry.setDataFormatInstance(manager.getDataFormatInstance());
071                this.registry.setAbstractParserFeatureFactory(manager.getParserFactory());
072                this.registry.setAlgorithm(this);
073                this.transitionSystem = manager.getParserFactory().makeTransitionSystem();
074                this.transitionSystem.initTableHandlers(lwSingleMalt.getDecisionSettings(), symbolTableHandler);
075                
076                this.tableHandlers = transitionSystem.getTableHandlers();
077                this.kBestSize = lwSingleMalt.getkBestSize();
078                this.decisionTables = new ArrayList<TableContainer>();
079                this.actionTables = new ArrayList<TableContainer>();
080                initDecisionSettings(lwSingleMalt.getDecisionSettings(), lwSingleMalt.getClassitem_separator());
081                this.transitionSystem.initTransitionSystem(this);
082                this.config = manager.getParserFactory().makeParserConfiguration();
083                this.featureModel = manager.getFeatureModelManager().getFeatureModel(lwSingleMalt.getFeatureModelURL(), 0, registry, manager.getDataSplitColumn(), manager.getDataSplitStructure());
084                this.currentAction = new ComplexDecisionAction(this);
085        }
086        
087        public DependencyStructure parse(DependencyStructure parseDependencyGraph) throws MaltChainedException {
088                config.clear();
089                config.setDependencyGraph(parseDependencyGraph);
090                config.initialize();
091
092                while (!config.isTerminalState()) {
093                        GuideUserAction action = transitionSystem.getDeterministicAction(this, config);
094                        if (action == null) {
095                                action = predict();
096                        }
097                        transitionSystem.apply(action, config);
098                } 
099                parseDependencyGraph.linkAllTreesToRoot();
100                return parseDependencyGraph;
101        }
102        
103        private GuideUserAction predict() throws MaltChainedException {
104                currentAction.clear();
105                try {
106                        manager.getDecisionModel().predict(featureModel, currentAction, true);
107                        
108                        while (!transitionSystem.permissible(currentAction, config)) {
109                                if (manager.getDecisionModel().predictFromKBestList(featureModel, currentAction) == false) {
110                                        GuideUserAction defaultAction = transitionSystem.defaultAction(this, config);
111                                        ActionContainer[] actionContainers = this.getActionContainerArray();
112                                        defaultAction.getAction(actionContainers);
113                                        currentAction.addAction(actionContainers);
114                                        break;
115                                }
116                        }
117                } catch (NullPointerException e) {
118                        throw new MaltChainedException("The guide cannot be found. ", e);
119                }
120                return currentAction;
121        }
122        
123        public ParserRegistry getParserRegistry() {
124                return registry;
125        }
126        
127        public ParserConfiguration getCurrentParserConfiguration() {
128                return config;
129        }
130        
131        public DependencyParserConfig getManager() {
132                return manager;
133        }
134        
135        public String getGuideName() {
136                return null;
137        }
138
139        public void setGuideName(String guideName) { }
140        
141        // GuideUserHistory interface
142        public GuideUserAction getEmptyGuideUserAction() throws MaltChainedException {
143                return new ComplexDecisionAction(this);
144        }
145        
146        public ArrayList<ActionContainer> getActionContainers() {
147                ArrayList<ActionContainer> actionContainers = new ArrayList<ActionContainer>();
148                for (int i=0; i<actionTables.size(); i++) {
149                        actionContainers.add(new ActionContainer(actionTables.get(i)));
150                }
151                return actionContainers;
152        }
153        
154        public ActionContainer[] getActionContainerArray() {
155                ActionContainer[] actionContainers = new ActionContainer[actionTables.size()];
156                for (int i=0; i<actionTables.size(); i++) {
157                        actionContainers[i] = new ActionContainer(actionTables.get(i));
158                }
159                return actionContainers;
160        }
161        
162        public void clear() throws MaltChainedException { }
163        
164        public int getNumberOfDecisions() {
165                return decisionTables.size();
166        }
167        
168        public int getKBestSize() {
169                return kBestSize;
170        }
171
172        public int getNumberOfActions() {
173                return actionTables.size();
174        }
175        
176        public ArrayList<TableContainer> getDecisionTables() {
177                return decisionTables;
178        }
179
180        public ArrayList<TableContainer> getActionTables() {
181                return actionTables;
182        }
183
184        private void initDecisionSettings(String decisionSettings, String separator) throws MaltChainedException {
185                if (decisionSettings.equals("T.TRANS+A.DEPREL")) {
186                        actionTables.add(new TableContainer(tableHandlers.get("T").getSymbolTable("TRANS"), "T.TRANS", '+'));
187                        actionTables.add(new TableContainer(tableHandlers.get("A").getSymbolTable("DEPREL"), "A.DEPREL", ' '));
188                        decisionTables.add(new CombinedTableContainer(tableHandlers.get("A"), separator, actionTables, ' '));
189                } else if (decisionSettings.equals("T.TRANS,A.DEPREL")) {
190                        TableContainer transTableContainer = new TableContainer(tableHandlers.get("T").getSymbolTable("TRANS"), "T.TRANS", ',');
191                        TableContainer deprelTableContainer = new TableContainer(tableHandlers.get("A").getSymbolTable("DEPREL"), "A.DEPREL", ',');
192                        actionTables.add(transTableContainer);
193                        actionTables.add(deprelTableContainer);
194                        decisionTables.add(transTableContainer);
195                        decisionTables.add(deprelTableContainer);
196                } else if (decisionSettings.equals("T.TRANS#A.DEPREL")  || decisionSettings.equals("T.TRANS;A.DEPREL")) {
197                        TableContainer transTableContainer = new TableContainer(tableHandlers.get("T").getSymbolTable("TRANS"), "T.TRANS", '#');
198                        TableContainer deprelTableContainer = new TableContainer(tableHandlers.get("A").getSymbolTable("DEPREL"), "A.DEPREL", '#');
199                        actionTables.add(transTableContainer);
200                        actionTables.add(deprelTableContainer);
201                        decisionTables.add(transTableContainer);
202                        decisionTables.add(deprelTableContainer);
203                } else {
204                        int start = 0;
205                        int k = 0;
206                        char prevDecisionSeparator = ' ';
207                        TableContainer tmp = null;
208                        final StringBuilder sbTableHandler = new StringBuilder();
209                        final StringBuilder sbTable = new StringBuilder();
210                        int state = 0;
211                        for (int i = 0; i < decisionSettings.length(); i++) {
212                                switch (decisionSettings.charAt(i)) {
213                                case '.':
214                                        state = 1;
215                                        break;
216                                case '+':
217                                        tmp = new TableContainer(tableHandlers.get(sbTableHandler.toString()).getSymbolTable(sbTable.toString()), 
218                                                        sbTableHandler.toString()+"."+sbTable.toString(), '+');
219                                        actionTables.add(tmp);
220                                        k++;
221                                        sbTableHandler.setLength(0);
222                                        sbTable.setLength(0);
223                                        state = 0;
224                                        break;
225                                case '#':
226                                        state = 2;
227                                        break;
228                                case ';':
229                                        state = 2;
230                                        break;
231                                case ',':
232                                        state = 2;
233                                        break;
234                                default:
235                                        if (state == 0) {
236                                                sbTableHandler.append(decisionSettings.charAt(i));
237                                        } else if (state == 1) {
238                                                sbTable.append(decisionSettings.charAt(i));
239                                        }
240                                }
241                                if (state == 2 || i == decisionSettings.length()-1) {
242                                        char decisionSeparator = decisionSettings.charAt(i);
243                                        if (i == decisionSettings.length()-1) {
244                                                decisionSeparator = prevDecisionSeparator;
245                                        }
246                                        tmp = new TableContainer(tableHandlers.get(sbTableHandler.toString()).getSymbolTable(sbTable.toString()), 
247                                                        sbTableHandler.toString()+"."+sbTable.toString(), decisionSeparator);
248                                        actionTables.add(tmp);
249                                        k++;
250                                        if (k-start > 1) {
251                                                decisionTables.add(new CombinedTableContainer(tableHandlers.get("A"), separator, actionTables.subList(start, k), decisionSeparator));
252                                        } else {
253                                                decisionTables.add(tmp);
254                                        }
255                                        sbTableHandler.setLength(0);
256                                        sbTable.setLength(0);
257                                        state = 0;
258                                        start = k;
259                                        prevDecisionSeparator = decisionSeparator;
260                                }
261                        }
262                }
263        }
264}