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.helper.HashMap;
007import org.maltparser.core.symbol.SymbolTableHandler;
008import org.maltparser.core.symbol.TableHandler;
009import org.maltparser.core.syntaxgraph.DependencyStructure;
010import org.maltparser.parser.AlgoritmInterface;
011import org.maltparser.parser.DependencyParserConfig;
012import org.maltparser.parser.ParserConfiguration;
013import org.maltparser.parser.ParserRegistry;
014import org.maltparser.parser.TransitionSystem;
015import org.maltparser.parser.history.GuideUserHistory;
016import org.maltparser.parser.history.action.ComplexDecisionAction;
017import org.maltparser.parser.history.action.GuideUserAction;
018
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) 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 = manager.getFeatureModelManager().getFeatureModel(lwSingleMalt.getFeatureModelURL(), 0, registry, manager.getDataSplitColumn(), manager.getDataSplitStructure());
063                this.currentAction = new ComplexDecisionAction(this);
064        }
065        
066        public DependencyStructure parse(DependencyStructure parseDependencyGraph) throws MaltChainedException {
067                config.clear();
068                config.setDependencyGraph(parseDependencyGraph);
069                config.initialize();
070
071                while (!config.isTerminalState()) {
072                        GuideUserAction action = transitionSystem.getDeterministicAction(this, config);
073                        if (action == null) {
074                                action = predict();
075                        }
076                        transitionSystem.apply(action, config);
077                } 
078                parseDependencyGraph.linkAllTreesToRoot();
079                return parseDependencyGraph;
080        }
081        
082        private GuideUserAction predict() throws MaltChainedException {
083                currentAction.clear();
084                try {
085                        manager.getDecisionModel().predict(featureModel, currentAction, true);
086                        
087                        while (!transitionSystem.permissible(currentAction, config)) {
088                                if (manager.getDecisionModel().predictFromKBestList(featureModel, currentAction) == false) {
089                                        GuideUserAction defaultAction = transitionSystem.defaultAction(this, config);
090                                        ActionContainer[] actionContainers = this.getActionContainerArray();
091                                        defaultAction.getAction(actionContainers);
092                                        currentAction.addAction(actionContainers);
093                                        break;
094                                }
095                        }
096                } catch (NullPointerException e) {
097                        throw new MaltChainedException("The guide cannot be found. ", e);
098                }
099                return currentAction;
100        }
101        
102        public ParserRegistry getParserRegistry() {
103                return registry;
104        }
105        
106        public ParserConfiguration getCurrentParserConfiguration() {
107                return config;
108        }
109        
110        public DependencyParserConfig getManager() {
111                return manager;
112        }
113        
114        public String getGuideName() {
115                return null;
116        }
117
118        public void setGuideName(String guideName) { }
119        
120        // GuideUserHistory interface
121        public GuideUserAction getEmptyGuideUserAction() throws MaltChainedException {
122                return new ComplexDecisionAction(this);
123        }
124        
125        public ArrayList<ActionContainer> getActionContainers() {
126                ArrayList<ActionContainer> actionContainers = new ArrayList<ActionContainer>();
127                for (int i=0; i<actionTables.size(); i++) {
128                        actionContainers.add(new ActionContainer(actionTables.get(i)));
129                }
130                return actionContainers;
131        }
132        
133        public ActionContainer[] getActionContainerArray() {
134                ActionContainer[] actionContainers = new ActionContainer[actionTables.size()];
135                for (int i=0; i<actionTables.size(); i++) {
136                        actionContainers[i] = new ActionContainer(actionTables.get(i));
137                }
138                return actionContainers;
139        }
140        
141        public void clear() throws MaltChainedException { }
142        
143        public int getNumberOfDecisions() {
144                return decisionTables.size();
145        }
146        
147        public int getKBestSize() {
148                return kBestSize;
149        }
150
151        public int getNumberOfActions() {
152                return actionTables.size();
153        }
154        
155        public ArrayList<TableContainer> getDecisionTables() {
156                return decisionTables;
157        }
158
159        public ArrayList<TableContainer> getActionTables() {
160                return actionTables;
161        }
162
163        private void initDecisionSettings(String decisionSettings, String separator) throws MaltChainedException {
164                if (decisionSettings.equals("T.TRANS+A.DEPREL")) {
165                        actionTables.add(new TableContainer(tableHandlers.get("T").getSymbolTable("TRANS"), "T.TRANS", '+'));
166                        actionTables.add(new TableContainer(tableHandlers.get("A").getSymbolTable("DEPREL"), "A.DEPREL", ' '));
167                        decisionTables.add(new CombinedTableContainer(tableHandlers.get("A"), separator, actionTables, ' '));
168                } else if (decisionSettings.equals("T.TRANS,A.DEPREL")) {
169                        TableContainer transTableContainer = new TableContainer(tableHandlers.get("T").getSymbolTable("TRANS"), "T.TRANS", ',');
170                        TableContainer deprelTableContainer = new TableContainer(tableHandlers.get("A").getSymbolTable("DEPREL"), "A.DEPREL", ',');
171                        actionTables.add(transTableContainer);
172                        actionTables.add(deprelTableContainer);
173                        decisionTables.add(transTableContainer);
174                        decisionTables.add(deprelTableContainer);
175                } else if (decisionSettings.equals("T.TRANS#A.DEPREL")  || decisionSettings.equals("T.TRANS;A.DEPREL")) {
176                        TableContainer transTableContainer = new TableContainer(tableHandlers.get("T").getSymbolTable("TRANS"), "T.TRANS", '#');
177                        TableContainer deprelTableContainer = new TableContainer(tableHandlers.get("A").getSymbolTable("DEPREL"), "A.DEPREL", '#');
178                        actionTables.add(transTableContainer);
179                        actionTables.add(deprelTableContainer);
180                        decisionTables.add(transTableContainer);
181                        decisionTables.add(deprelTableContainer);
182                } else {
183                        int start = 0;
184                        int k = 0;
185                        char prevDecisionSeparator = ' ';
186                        TableContainer tmp = null;
187                        final StringBuilder sbTableHandler = new StringBuilder();
188                        final StringBuilder sbTable = new StringBuilder();
189                        int state = 0;
190                        for (int i = 0; i < decisionSettings.length(); i++) {
191                                switch (decisionSettings.charAt(i)) {
192                                case '.':
193                                        state = 1;
194                                        break;
195                                case '+':
196                                        tmp = new TableContainer(tableHandlers.get(sbTableHandler.toString()).getSymbolTable(sbTable.toString()), 
197                                                        sbTableHandler.toString()+"."+sbTable.toString(), '+');
198                                        actionTables.add(tmp);
199                                        k++;
200                                        sbTableHandler.setLength(0);
201                                        sbTable.setLength(0);
202                                        state = 0;
203                                        break;
204                                case '#':
205                                        state = 2;
206                                        break;
207                                case ';':
208                                        state = 2;
209                                        break;
210                                case ',':
211                                        state = 2;
212                                        break;
213                                default:
214                                        if (state == 0) {
215                                                sbTableHandler.append(decisionSettings.charAt(i));
216                                        } else if (state == 1) {
217                                                sbTable.append(decisionSettings.charAt(i));
218                                        }
219                                }
220                                if (state == 2 || i == decisionSettings.length()-1) {
221                                        char decisionSeparator = decisionSettings.charAt(i);
222                                        if (i == decisionSettings.length()-1) {
223                                                decisionSeparator = prevDecisionSeparator;
224                                        }
225                                        tmp = new TableContainer(tableHandlers.get(sbTableHandler.toString()).getSymbolTable(sbTable.toString()), 
226                                                        sbTableHandler.toString()+"."+sbTable.toString(), decisionSeparator);
227                                        actionTables.add(tmp);
228                                        k++;
229                                        if (k-start > 1) {
230                                                decisionTables.add(new CombinedTableContainer(tableHandlers.get("A"), separator, actionTables.subList(start, k), decisionSeparator));
231                                        } else {
232                                                decisionTables.add(tmp);
233                                        }
234                                        sbTableHandler.setLength(0);
235                                        sbTable.setLength(0);
236                                        state = 0;
237                                        start = k;
238                                        prevDecisionSeparator = decisionSeparator;
239                                }
240                        }
241                }
242        }
243}