001 package org.maltparser.parser.guide.decision; 002 003 import java.lang.reflect.Constructor; 004 import java.lang.reflect.InvocationTargetException; 005 006 import org.maltparser.core.exception.MaltChainedException; 007 import org.maltparser.core.feature.FeatureModel; 008 import org.maltparser.core.feature.FeatureVector; 009 import org.maltparser.core.syntaxgraph.DependencyStructure; 010 import org.maltparser.parser.DependencyParserConfig; 011 import org.maltparser.parser.guide.ClassifierGuide; 012 import org.maltparser.parser.guide.GuideException; 013 import org.maltparser.parser.guide.instance.AtomicModel; 014 import org.maltparser.parser.guide.instance.FeatureDivideModel; 015 import org.maltparser.parser.guide.instance.InstanceModel; 016 import org.maltparser.parser.history.action.GuideDecision; 017 import org.maltparser.parser.history.action.MultipleDecision; 018 import org.maltparser.parser.history.action.SingleDecision; 019 import org.maltparser.parser.history.container.TableContainer.RelationToNextDecision; 020 /** 021 * 022 * @author Johan Hall 023 * @since 1.1 024 **/ 025 public class SeqDecisionModel implements DecisionModel { 026 private ClassifierGuide guide; 027 private String modelName; 028 private FeatureModel featureModel; 029 private InstanceModel instanceModel; 030 private int decisionIndex; 031 private DecisionModel prevDecisionModel; 032 private DecisionModel nextDecisionModel; 033 private String branchedDecisionSymbols; 034 035 public SeqDecisionModel(ClassifierGuide guide, FeatureModel featureModel) throws MaltChainedException { 036 this.branchedDecisionSymbols = ""; 037 setGuide(guide); 038 setFeatureModel(featureModel); 039 setDecisionIndex(0); 040 setModelName("sdm"+decisionIndex); 041 setPrevDecisionModel(null); 042 } 043 044 public SeqDecisionModel(ClassifierGuide guide, DecisionModel prevDecisionModel, String branchedDecisionSymbol) throws MaltChainedException { 045 if (branchedDecisionSymbol != null && branchedDecisionSymbol.length() > 0) { 046 this.branchedDecisionSymbols = branchedDecisionSymbol; 047 } else { 048 this.branchedDecisionSymbols = ""; 049 } 050 setGuide(guide); 051 setFeatureModel(prevDecisionModel.getFeatureModel()); 052 setDecisionIndex(prevDecisionModel.getDecisionIndex() + 1); 053 setPrevDecisionModel(prevDecisionModel); 054 if (branchedDecisionSymbols != null && branchedDecisionSymbols.length() > 0) { 055 setModelName("sdm"+decisionIndex+branchedDecisionSymbols); 056 } else { 057 setModelName("sdm"+decisionIndex); 058 } 059 } 060 061 public void updateFeatureModel() throws MaltChainedException { 062 featureModel.update(); 063 } 064 065 public void finalizeSentence(DependencyStructure dependencyGraph) throws MaltChainedException { 066 if (instanceModel != null) { 067 instanceModel.finalizeSentence(dependencyGraph); 068 } 069 if (nextDecisionModel != null) { 070 nextDecisionModel.finalizeSentence(dependencyGraph); 071 } 072 } 073 074 public void noMoreInstances() throws MaltChainedException { 075 if (guide.getGuideMode() == ClassifierGuide.GuideMode.CLASSIFY) { 076 throw new GuideException("The decision model could not create it's model. "); 077 } 078 if (instanceModel != null) { 079 instanceModel.noMoreInstances(); 080 instanceModel.train(); 081 } 082 if (nextDecisionModel != null) { 083 nextDecisionModel.noMoreInstances(); 084 } 085 } 086 087 public void terminate() throws MaltChainedException { 088 if (instanceModel != null) { 089 instanceModel.terminate(); 090 instanceModel = null; 091 } 092 if (nextDecisionModel != null) { 093 nextDecisionModel.terminate(); 094 nextDecisionModel = null; 095 } 096 } 097 098 public void addInstance(GuideDecision decision) throws MaltChainedException { 099 if (decision instanceof SingleDecision) { 100 throw new GuideException("A sequantial decision model expect a sequence of decisions, not a single decision. "); 101 } 102 featureModel.update(); 103 final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex); 104 if (instanceModel == null) { 105 initInstanceModel(singleDecision.getTableContainer().getTableContainerName()); 106 } 107 instanceModel.addInstance(singleDecision); 108 if (singleDecision.continueWithNextDecision() && decisionIndex+1 < decision.numberOfDecisions()) { 109 if (nextDecisionModel == null) { 110 initNextDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), branchedDecisionSymbols); 111 } 112 nextDecisionModel.addInstance(decision); 113 } 114 } 115 116 public boolean predict(GuideDecision decision) throws MaltChainedException { 117 if (decision instanceof SingleDecision) { 118 throw new GuideException("A sequantial decision model expect a sequence of decisions, not a single decision. "); 119 } 120 featureModel.update(); 121 final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex); 122 if (instanceModel == null) { 123 initInstanceModel(singleDecision.getTableContainer().getTableContainerName()); 124 } 125 126 boolean success = instanceModel.predict(singleDecision); 127 if (singleDecision.continueWithNextDecision() && decisionIndex+1 < decision.numberOfDecisions()) { 128 if (nextDecisionModel == null) { 129 initNextDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), branchedDecisionSymbols); 130 } 131 success = nextDecisionModel.predict(decision) && success; 132 } 133 return success; 134 } 135 136 public FeatureVector predictExtract(GuideDecision decision) throws MaltChainedException { 137 if (decision instanceof SingleDecision) { 138 throw new GuideException("A sequantial decision model expect a sequence of decisions, not a single decision. "); 139 } 140 featureModel.update(); 141 final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex); 142 if (instanceModel == null) { 143 initInstanceModel(singleDecision.getTableContainer().getTableContainerName()); 144 } 145 146 FeatureVector fv = instanceModel.predictExtract(singleDecision); 147 if (singleDecision.continueWithNextDecision() && decisionIndex+1 < decision.numberOfDecisions()) { 148 if (nextDecisionModel == null) { 149 initNextDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), branchedDecisionSymbols); 150 } 151 nextDecisionModel.predictExtract(decision); 152 } 153 return fv; 154 } 155 156 public FeatureVector extract() throws MaltChainedException { 157 featureModel.update(); 158 return instanceModel.extract(); // TODO handle many feature vectors 159 } 160 161 public boolean predictFromKBestList(GuideDecision decision) throws MaltChainedException { 162 if (decision instanceof SingleDecision) { 163 throw new GuideException("A sequantial decision model expect a sequence of decisions, not a single decision. "); 164 } 165 166 boolean success = false; 167 final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex); 168 // TODO develop different strategies for resolving which kBestlist that should be used 169 if (nextDecisionModel != null && singleDecision.continueWithNextDecision()) { 170 success = nextDecisionModel.predictFromKBestList(decision); 171 } 172 if (!success) { 173 success = singleDecision.updateFromKBestList(); 174 if (success && singleDecision.continueWithNextDecision() && decisionIndex+1 < decision.numberOfDecisions()) { 175 if (nextDecisionModel == null) { 176 initNextDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), branchedDecisionSymbols); 177 } 178 nextDecisionModel.predict(decision); 179 } 180 } 181 return success; 182 } 183 184 185 public ClassifierGuide getGuide() { 186 return guide; 187 } 188 189 public String getModelName() { 190 return modelName; 191 } 192 193 public FeatureModel getFeatureModel() { 194 return featureModel; 195 } 196 197 public int getDecisionIndex() { 198 return decisionIndex; 199 } 200 201 public DecisionModel getPrevDecisionModel() { 202 return prevDecisionModel; 203 } 204 205 public DecisionModel getNextDecisionModel() { 206 return nextDecisionModel; 207 } 208 209 private void setPrevDecisionModel(DecisionModel prevDecisionModel) { 210 this.prevDecisionModel = prevDecisionModel; 211 } 212 213 private void setNextDecisionModel(DecisionModel nextDecisionModel) { 214 this.nextDecisionModel = nextDecisionModel; 215 } 216 217 private void setFeatureModel(FeatureModel featureModel) { 218 this.featureModel = featureModel; 219 } 220 221 private void setDecisionIndex(int decisionIndex) { 222 this.decisionIndex = decisionIndex; 223 } 224 225 private void setModelName(String modelName) { 226 this.modelName = modelName; 227 } 228 229 private void setGuide(ClassifierGuide guide) { 230 this.guide = guide; 231 } 232 233 private void initInstanceModel(String subModelName) throws MaltChainedException { 234 FeatureVector fv = featureModel.getFeatureVector(branchedDecisionSymbols+"."+subModelName); 235 if (fv == null) { 236 fv = featureModel.getFeatureVector(subModelName); 237 } 238 if (fv == null) { 239 fv = featureModel.getMainFeatureVector(); 240 } 241 242 DependencyParserConfig c = guide.getConfiguration(); 243 244 if (c.getOptionValue("guide", "data_split_column").toString().length() == 0) { 245 instanceModel = new AtomicModel(-1, fv, this); 246 } else { 247 instanceModel = new FeatureDivideModel(fv, this); 248 } 249 } 250 251 private void initNextDecisionModel(SingleDecision decision, String branchedDecisionSymbol) throws MaltChainedException { 252 Class<?> decisionModelClass = null; 253 if (decision.getRelationToNextDecision() == RelationToNextDecision.SEQUANTIAL) { 254 decisionModelClass = org.maltparser.parser.guide.decision.SeqDecisionModel.class; 255 } else if (decision.getRelationToNextDecision() == RelationToNextDecision.BRANCHED) { 256 decisionModelClass = org.maltparser.parser.guide.decision.BranchedDecisionModel.class; 257 } else if (decision.getRelationToNextDecision() == RelationToNextDecision.NONE) { 258 decisionModelClass = org.maltparser.parser.guide.decision.OneDecisionModel.class; 259 } 260 261 if (decisionModelClass == null) { 262 throw new GuideException("Could not find an appropriate decision model for the relation to the next decision"); 263 } 264 265 try { 266 Class<?>[] argTypes = { org.maltparser.parser.guide.ClassifierGuide.class, org.maltparser.parser.guide.decision.DecisionModel.class, 267 java.lang.String.class }; 268 Object[] arguments = new Object[3]; 269 arguments[0] = getGuide(); 270 arguments[1] = this; 271 arguments[2] = branchedDecisionSymbol; 272 Constructor<?> constructor = decisionModelClass.getConstructor(argTypes); 273 setNextDecisionModel((DecisionModel)constructor.newInstance(arguments)); 274 } catch (NoSuchMethodException e) { 275 throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e); 276 } catch (InstantiationException e) { 277 throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e); 278 } catch (IllegalAccessException e) { 279 throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e); 280 } catch (InvocationTargetException e) { 281 throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e); 282 } 283 } 284 285 public String toString() { 286 final StringBuilder sb = new StringBuilder(); 287 sb.append(modelName + ", "); 288 sb.append(nextDecisionModel.toString()); 289 return sb.toString(); 290 } 291 }