001 package org.maltparser.parser.guide.decision; 002 003 import java.lang.reflect.Constructor; 004 import java.lang.reflect.InvocationTargetException; 005 import java.util.HashMap; 006 007 import org.maltparser.core.exception.MaltChainedException; 008 import org.maltparser.core.feature.FeatureModel; 009 import org.maltparser.core.feature.FeatureVector; 010 import org.maltparser.core.syntaxgraph.DependencyStructure; 011 import org.maltparser.parser.guide.Guide; 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 BranchedDecisionModel implements DecisionModel { 026 private Guide guide; 027 private String modelName; 028 private FeatureModel featureModel; 029 private InstanceModel instanceModel; 030 private int decisionIndex; 031 private DecisionModel parentDecisionModel; 032 private HashMap<Integer,DecisionModel> children; 033 private String branchedDecisionSymbols; 034 035 public BranchedDecisionModel(Guide guide, FeatureModel featureModel) throws MaltChainedException { 036 this.branchedDecisionSymbols = ""; 037 setGuide(guide); 038 setFeatureModel(featureModel); 039 setDecisionIndex(0); 040 setModelName("bdm"+decisionIndex); 041 setParentDecisionModel(null); 042 } 043 044 public BranchedDecisionModel(Guide guide, DecisionModel parentDecisionModel, 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 setParentDecisionModel(parentDecisionModel); 052 setDecisionIndex(parentDecisionModel.getDecisionIndex() + 1); 053 setFeatureModel(parentDecisionModel.getFeatureModel()); 054 if (branchedDecisionSymbols != null && branchedDecisionSymbols.length() > 0) { 055 setModelName("bdm"+decisionIndex+branchedDecisionSymbols); 056 } else { 057 setModelName("bdm"+decisionIndex); 058 } 059 this.parentDecisionModel = parentDecisionModel; 060 } 061 062 public void update() throws MaltChainedException { 063 featureModel.update(); 064 } 065 066 public void updateCardinality() throws MaltChainedException { 067 featureModel.updateCardinality(); 068 } 069 070 071 public void finalizeSentence(DependencyStructure dependencyGraph) throws MaltChainedException { 072 if (instanceModel != null) { 073 instanceModel.finalizeSentence(dependencyGraph); 074 } 075 if (children != null) { 076 for (DecisionModel child : children.values()) { 077 child.finalizeSentence(dependencyGraph); 078 } 079 } 080 } 081 082 public void noMoreInstances() throws MaltChainedException { 083 if (guide.getGuideMode() != Guide.GuideMode.TRAIN) { 084 throw new GuideException("The decision model could not create it's model. "); 085 } 086 featureModel.updateCardinality(); 087 if (instanceModel != null) { 088 instanceModel.noMoreInstances(); 089 instanceModel.train(); 090 } 091 if (children != null) { 092 for (DecisionModel child : children.values()) { 093 child.noMoreInstances(); 094 } 095 } 096 } 097 098 public void terminate() throws MaltChainedException { 099 if (instanceModel != null) { 100 instanceModel.terminate(); 101 instanceModel = null; 102 } 103 if (children != null) { 104 for (DecisionModel child : children.values()) { 105 child.terminate(); 106 } 107 } 108 } 109 110 public void addInstance(GuideDecision decision) throws MaltChainedException { 111 if (decision instanceof SingleDecision) { 112 throw new GuideException("A branched decision model expect more than one decisions. "); 113 } 114 update(); 115 final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex); 116 if (instanceModel == null) { 117 initInstanceModel(singleDecision.getTableContainer().getTableContainerName()); 118 } 119 120 instanceModel.addInstance(singleDecision); 121 if (decisionIndex+1 < decision.numberOfDecisions()) { 122 if (singleDecision.continueWithNextDecision()) { 123 if (children == null) { 124 children = new HashMap<Integer,DecisionModel>(); 125 } 126 DecisionModel child = children.get(singleDecision.getDecisionCode()); 127 if (child == null) { 128 child = initChildDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), 129 branchedDecisionSymbols+(branchedDecisionSymbols.length() == 0?"":"_")+singleDecision.getDecisionSymbol()); 130 children.put(singleDecision.getDecisionCode(), child); 131 } 132 child.addInstance(decision); 133 } 134 } 135 } 136 137 public boolean predict(GuideDecision decision) throws MaltChainedException { 138 if (decision instanceof SingleDecision) { 139 throw new GuideException("A branched decision model expect more than one decisions. "); 140 } 141 update(); 142 final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex); 143 if (instanceModel == null) { 144 initInstanceModel(singleDecision.getTableContainer().getTableContainerName()); 145 } 146 instanceModel.predict(singleDecision); 147 if (decisionIndex+1 < decision.numberOfDecisions()) { 148 if (singleDecision.continueWithNextDecision()) { 149 if (children == null) { 150 children = new HashMap<Integer,DecisionModel>(); 151 } 152 DecisionModel child = children.get(singleDecision.getDecisionCode()); 153 if (child == null) { 154 child = initChildDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), 155 branchedDecisionSymbols+(branchedDecisionSymbols.length() == 0?"":"_")+singleDecision.getDecisionSymbol()); 156 children.put(singleDecision.getDecisionCode(), child); 157 } 158 child.predict(decision); 159 } 160 } 161 162 return true; 163 } 164 165 public boolean predictFromKBestList(GuideDecision decision) throws MaltChainedException { 166 if (decision instanceof SingleDecision) { 167 throw new GuideException("A branched decision model expect more than one decisions. "); 168 } 169 170 boolean success = false; 171 final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex); 172 if (decisionIndex+1 < decision.numberOfDecisions()) { 173 if (singleDecision.continueWithNextDecision()) { 174 if (children == null) { 175 children = new HashMap<Integer,DecisionModel>(); 176 } 177 DecisionModel child = children.get(singleDecision.getDecisionCode()); 178 if (child != null) { 179 success = child.predictFromKBestList(decision); 180 } 181 182 } 183 } 184 if (!success) { 185 success = singleDecision.updateFromKBestList(); 186 if (decisionIndex+1 < decision.numberOfDecisions()) { 187 if (singleDecision.continueWithNextDecision()) { 188 if (children == null) { 189 children = new HashMap<Integer,DecisionModel>(); 190 } 191 DecisionModel child = children.get(singleDecision.getDecisionCode()); 192 if (child == null) { 193 child = initChildDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), 194 branchedDecisionSymbols+(branchedDecisionSymbols.length() == 0?"":"_")+singleDecision.getDecisionSymbol()); 195 children.put(singleDecision.getDecisionCode(), child); 196 } 197 child.predict(decision); 198 } 199 } 200 } 201 return success; 202 } 203 204 205 public Guide getGuide() { 206 return guide; 207 } 208 209 public String getModelName() { 210 return modelName; 211 } 212 213 public FeatureModel getFeatureModel() { 214 return featureModel; 215 } 216 217 public int getDecisionIndex() { 218 return decisionIndex; 219 } 220 221 public DecisionModel getParentDecisionModel() { 222 return parentDecisionModel; 223 } 224 225 private void setFeatureModel(FeatureModel featureModel) { 226 this.featureModel = featureModel; 227 } 228 229 private void setDecisionIndex(int decisionIndex) { 230 this.decisionIndex = decisionIndex; 231 } 232 233 private void setParentDecisionModel(DecisionModel parentDecisionModel) { 234 this.parentDecisionModel = parentDecisionModel; 235 } 236 237 private void setModelName(String modelName) { 238 this.modelName = modelName; 239 } 240 241 private void setGuide(Guide guide) { 242 this.guide = guide; 243 } 244 245 246 private DecisionModel initChildDecisionModel(SingleDecision decision, String branchedDecisionSymbol) throws MaltChainedException { 247 Class<?> decisionModelClass = null; 248 if (decision.getRelationToNextDecision() == RelationToNextDecision.SEQUANTIAL) { 249 decisionModelClass = org.maltparser.parser.guide.decision.SeqDecisionModel.class; 250 } else if (decision.getRelationToNextDecision() == RelationToNextDecision.BRANCHED) { 251 decisionModelClass = org.maltparser.parser.guide.decision.BranchedDecisionModel.class; 252 } else if (decision.getRelationToNextDecision() == RelationToNextDecision.NONE) { 253 decisionModelClass = org.maltparser.parser.guide.decision.OneDecisionModel.class; 254 } 255 256 if (decisionModelClass == null) { 257 throw new GuideException("Could not find an appropriate decision model for the relation to the next decision"); 258 } 259 260 try { 261 Class<?>[] argTypes = { org.maltparser.parser.guide.Guide.class, org.maltparser.parser.guide.decision.DecisionModel.class, 262 java.lang.String.class }; 263 Object[] arguments = new Object[3]; 264 arguments[0] = getGuide(); 265 arguments[1] = this; 266 arguments[2] = branchedDecisionSymbol; 267 Constructor<?> constructor = decisionModelClass.getConstructor(argTypes); 268 return (DecisionModel)constructor.newInstance(arguments); 269 } catch (NoSuchMethodException e) { 270 throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e); 271 } catch (InstantiationException e) { 272 throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e); 273 } catch (IllegalAccessException e) { 274 throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e); 275 } catch (InvocationTargetException e) { 276 throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e); 277 } 278 } 279 280 private void initInstanceModel(String subModelName) throws MaltChainedException { 281 FeatureVector fv = featureModel.getFeatureVector(branchedDecisionSymbols+"."+subModelName); 282 if (fv == null) { 283 fv = featureModel.getFeatureVector(subModelName); 284 } 285 if (fv == null) { 286 fv = featureModel.getMainFeatureVector(); 287 } 288 if (guide.getConfiguration().getOptionValue("guide", "data_split_column").toString().length() == 0) { 289 instanceModel = new AtomicModel(-1, fv, this); 290 } else { 291 instanceModel = new FeatureDivideModel(fv, this); 292 } 293 } 294 295 public String toString() { 296 final StringBuilder sb = new StringBuilder(); 297 sb.append(modelName + ", "); 298 for (DecisionModel model : children.values()) { 299 sb.append(model.toString() + ", "); 300 } 301 return sb.toString(); 302 } 303 }