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