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