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}