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