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.Guide; 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 Guide 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(Guide 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(Guide 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 update() 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() != Guide.GuideMode.TRAIN) { 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 update(); 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 update(); 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 boolean predictFromKBestList(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 145 boolean success = false; 146 final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex); 147 // TODO develop different strategies for resolving which kBestlist that should be used 148 if (nextDecisionModel != null && singleDecision.continueWithNextDecision()) { 149 success = nextDecisionModel.predictFromKBestList(decision); 150 } 151 if (!success) { 152 success = singleDecision.updateFromKBestList(); 153 if (success && singleDecision.continueWithNextDecision() && decisionIndex+1 < decision.numberOfDecisions()) { 154 if (nextDecisionModel == null) { 155 initNextDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), branchedDecisionSymbols); 156 } 157 nextDecisionModel.predict(decision); 158 } 159 } 160 return success; 161 } 162 163 164 public Guide getGuide() { 165 return guide; 166 } 167 168 public String getModelName() { 169 return modelName; 170 } 171 172 public FeatureModel getFeatureModel() { 173 return featureModel; 174 } 175 176 public int getDecisionIndex() { 177 return decisionIndex; 178 } 179 180 public DecisionModel getPrevDecisionModel() { 181 return prevDecisionModel; 182 } 183 184 public DecisionModel getNextDecisionModel() { 185 return nextDecisionModel; 186 } 187 188 private void setPrevDecisionModel(DecisionModel prevDecisionModel) { 189 this.prevDecisionModel = prevDecisionModel; 190 } 191 192 private void setNextDecisionModel(DecisionModel nextDecisionModel) { 193 this.nextDecisionModel = nextDecisionModel; 194 } 195 196 private void setFeatureModel(FeatureModel featureModel) { 197 this.featureModel = featureModel; 198 } 199 200 private void setDecisionIndex(int decisionIndex) { 201 this.decisionIndex = decisionIndex; 202 } 203 204 private void setModelName(String modelName) { 205 this.modelName = modelName; 206 } 207 208 private void setGuide(Guide guide) { 209 this.guide = guide; 210 } 211 212 private void initInstanceModel(String subModelName) throws MaltChainedException { 213 FeatureVector fv = featureModel.getFeatureVector(branchedDecisionSymbols+"."+subModelName); 214 if (fv == null) { 215 fv = featureModel.getFeatureVector(subModelName); 216 } 217 if (fv == null) { 218 fv = featureModel.getMainFeatureVector(); 219 } 220 if (guide.getConfiguration().getOptionValue("guide", "data_split_column").toString().length() == 0) { 221 instanceModel = new AtomicModel(-1, fv, this); 222 } else { 223 instanceModel = new FeatureDivideModel(fv, this); 224 } 225 } 226 227 private void initNextDecisionModel(SingleDecision decision, String branchedDecisionSymbol) throws MaltChainedException { 228 Class<?> decisionModelClass = null; 229 if (decision.getRelationToNextDecision() == RelationToNextDecision.SEQUANTIAL) { 230 decisionModelClass = org.maltparser.parser.guide.decision.SeqDecisionModel.class; 231 } else if (decision.getRelationToNextDecision() == RelationToNextDecision.BRANCHED) { 232 decisionModelClass = org.maltparser.parser.guide.decision.BranchedDecisionModel.class; 233 } else if (decision.getRelationToNextDecision() == RelationToNextDecision.NONE) { 234 decisionModelClass = org.maltparser.parser.guide.decision.OneDecisionModel.class; 235 } 236 237 if (decisionModelClass == null) { 238 throw new GuideException("Could not find an appropriate decision model for the relation to the next decision"); 239 } 240 241 try { 242 Class<?>[] argTypes = { org.maltparser.parser.guide.Guide.class, org.maltparser.parser.guide.decision.DecisionModel.class, 243 java.lang.String.class }; 244 Object[] arguments = new Object[3]; 245 arguments[0] = getGuide(); 246 arguments[1] = this; 247 arguments[2] = branchedDecisionSymbol; 248 Constructor<?> constructor = decisionModelClass.getConstructor(argTypes); 249 setNextDecisionModel((DecisionModel)constructor.newInstance(arguments)); 250 } catch (NoSuchMethodException e) { 251 throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e); 252 } catch (InstantiationException e) { 253 throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e); 254 } catch (IllegalAccessException e) { 255 throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e); 256 } catch (InvocationTargetException e) { 257 throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e); 258 } 259 } 260 261 public String toString() { 262 final StringBuilder sb = new StringBuilder(); 263 sb.append(modelName + ", "); 264 sb.append(nextDecisionModel.toString()); 265 return sb.toString(); 266 } 267 }