001package org.maltparser.parser.guide.decision; 002 003import org.maltparser.core.exception.MaltChainedException; 004import org.maltparser.core.feature.FeatureModel; 005import org.maltparser.core.feature.FeatureVector; 006import org.maltparser.core.helper.HashMap; 007import org.maltparser.core.syntaxgraph.DependencyStructure; 008import org.maltparser.parser.guide.ClassifierGuide; 009import org.maltparser.parser.guide.GuideException; 010import org.maltparser.parser.guide.instance.AtomicModel; 011import org.maltparser.parser.guide.instance.FeatureDivideModel; 012import org.maltparser.parser.guide.instance.InstanceModel; 013import org.maltparser.parser.history.action.GuideDecision; 014import org.maltparser.parser.history.action.MultipleDecision; 015import org.maltparser.parser.history.action.SingleDecision; 016import org.maltparser.parser.history.container.TableContainer.RelationToNextDecision; 017/** 018* 019* @author Johan Hall 020**/ 021public class BranchedDecisionModel implements DecisionModel { 022 private final ClassifierGuide guide; 023 private final String modelName; 024// private final FeatureModel featureModel; 025 private InstanceModel instanceModel; 026 private final int decisionIndex; 027 private final DecisionModel parentDecisionModel; 028 private final HashMap<Integer,DecisionModel> children; 029 private final String branchedDecisionSymbols; 030 031 public BranchedDecisionModel(ClassifierGuide _guide) throws MaltChainedException { 032 this.guide = _guide; 033 this.branchedDecisionSymbols = ""; 034// this.featureModel = _featureModel; 035 this.decisionIndex = 0; 036 this.modelName = "bdm0"; 037 this.parentDecisionModel = null; 038 this.children = new HashMap<Integer,DecisionModel>(); 039 } 040 041 public BranchedDecisionModel(ClassifierGuide _guide, DecisionModel _parentDecisionModel, String _branchedDecisionSymbol) throws MaltChainedException { 042 this.guide = _guide; 043 this.parentDecisionModel =_parentDecisionModel; 044 this.decisionIndex = parentDecisionModel.getDecisionIndex() + 1; 045 if (_branchedDecisionSymbol != null && _branchedDecisionSymbol.length() > 0) { 046 this.branchedDecisionSymbols = _branchedDecisionSymbol; 047 this.modelName = "bdm"+decisionIndex+branchedDecisionSymbols; 048 } else { 049 this.branchedDecisionSymbols = ""; 050 this.modelName = "bdm"+decisionIndex; 051 } 052// this.featureModel = parentDecisionModel.getFeatureModel(); 053 this.children = new HashMap<Integer,DecisionModel>(); 054 } 055 056 private void initInstanceModel(FeatureModel featureModel, String subModelName) throws MaltChainedException { 057 if (featureModel.hasDivideFeatureFunction()) { 058 instanceModel = new FeatureDivideModel(this); 059 } else { 060 instanceModel = new AtomicModel(-1, this); 061 } 062 } 063 064// public void updateFeatureModel() throws MaltChainedException { 065// featureModel.update(); 066// } 067 068 public void finalizeSentence(DependencyStructure dependencyGraph) throws MaltChainedException { 069 if (instanceModel != null) { 070 instanceModel.finalizeSentence(dependencyGraph); 071 } 072 if (children != null) { 073 for (DecisionModel child : children.values()) { 074 child.finalizeSentence(dependencyGraph); 075 } 076 } 077 } 078 079 public void noMoreInstances(FeatureModel featureModel) throws MaltChainedException { 080 if (guide.getGuideMode() == ClassifierGuide.GuideMode.CLASSIFY) { 081 throw new GuideException("The decision model could not create it's model. "); 082 } 083 if (instanceModel != null) { 084 instanceModel.noMoreInstances(featureModel); 085 instanceModel.train(); 086 } 087 if (children != null) { 088 for (DecisionModel child : children.values()) { 089 child.noMoreInstances(featureModel); 090 } 091 } 092 } 093 094 public void terminate() throws MaltChainedException { 095 if (instanceModel != null) { 096 instanceModel.terminate(); 097 instanceModel = null; 098 } 099 if (children != null) { 100 for (DecisionModel child : children.values()) { 101 child.terminate(); 102 } 103 } 104 } 105 106 public void addInstance(FeatureModel featureModel, GuideDecision decision) throws MaltChainedException { 107 if (decision instanceof SingleDecision) { 108 throw new GuideException("A branched decision model expect more than one decisions. "); 109 } 110 featureModel.update(); 111 final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex); 112 if (instanceModel == null) { 113 initInstanceModel(featureModel,singleDecision.getTableContainer().getTableContainerName()); 114 } 115 116 instanceModel.addInstance(featureModel.getFeatureVector(branchedDecisionSymbols, singleDecision.getTableContainer().getTableContainerName()), singleDecision); 117 if (decisionIndex+1 < decision.numberOfDecisions()) { 118 if (singleDecision.continueWithNextDecision()) { 119 DecisionModel child = children.get(singleDecision.getDecisionCode()); 120 if (child == null) { 121 child = initChildDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), 122 branchedDecisionSymbols+(branchedDecisionSymbols.length() == 0?"":"_")+singleDecision.getDecisionSymbol()); 123 children.put(singleDecision.getDecisionCode(), child); 124 } 125 child.addInstance(featureModel,decision); 126 } 127 } 128 } 129 130 public boolean predict(FeatureModel featureModel, GuideDecision decision) throws MaltChainedException { 131 featureModel.update(); 132 final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex); 133 if (instanceModel == null) { 134 initInstanceModel(featureModel, singleDecision.getTableContainer().getTableContainerName()); 135 } 136 instanceModel.predict(featureModel.getFeatureVector(branchedDecisionSymbols, singleDecision.getTableContainer().getTableContainerName()), singleDecision); 137 if (decisionIndex+1 < decision.numberOfDecisions()) { 138 if (singleDecision.continueWithNextDecision()) { 139 DecisionModel child = children.get(singleDecision.getDecisionCode()); 140 if (child == null) { 141 child = initChildDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), 142 branchedDecisionSymbols+(branchedDecisionSymbols.length() == 0?"":"_")+singleDecision.getDecisionSymbol()); 143 children.put(singleDecision.getDecisionCode(), child); 144 } 145 child.predict(featureModel, decision); 146 } 147 } 148 149 return true; 150 } 151 152 public FeatureVector predictExtract(FeatureModel featureModel, GuideDecision decision) throws MaltChainedException { 153 if (decision instanceof SingleDecision) { 154 throw new GuideException("A branched decision model expect more than one decisions. "); 155 } 156 featureModel.update(); 157 final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex); 158 if (instanceModel == null) { 159 initInstanceModel(featureModel, singleDecision.getTableContainer().getTableContainerName()); 160 } 161 FeatureVector fv = instanceModel.predictExtract(featureModel.getFeatureVector(branchedDecisionSymbols, singleDecision.getTableContainer().getTableContainerName()), singleDecision); 162 if (decisionIndex+1 < decision.numberOfDecisions()) { 163 if (singleDecision.continueWithNextDecision()) { 164 DecisionModel child = children.get(singleDecision.getDecisionCode()); 165 if (child == null) { 166 child = initChildDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), 167 branchedDecisionSymbols+(branchedDecisionSymbols.length() == 0?"":"_")+singleDecision.getDecisionSymbol()); 168 children.put(singleDecision.getDecisionCode(), child); 169 } 170 child.predictExtract(featureModel, decision); 171 } 172 } 173 174 return fv; 175 } 176 177 public FeatureVector extract(FeatureModel featureModel) throws MaltChainedException { 178 featureModel.update(); 179 return null; //instanceModel.extract(); // TODO handle many feature vectors 180 } 181 182 public boolean predictFromKBestList(FeatureModel featureModel, GuideDecision decision) throws MaltChainedException { 183 if (decision instanceof SingleDecision) { 184 throw new GuideException("A branched decision model expect more than one decisions. "); 185 } 186 187 boolean success = false; 188 final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex); 189 if (decisionIndex+1 < decision.numberOfDecisions()) { 190 if (singleDecision.continueWithNextDecision()) { 191 DecisionModel child = children.get(singleDecision.getDecisionCode()); 192 if (child != null) { 193 success = child.predictFromKBestList(featureModel, decision); 194 } 195 196 } 197 } 198 if (!success) { 199 success = singleDecision.updateFromKBestList(); 200 if (decisionIndex+1 < decision.numberOfDecisions()) { 201 if (singleDecision.continueWithNextDecision()) { 202 DecisionModel child = children.get(singleDecision.getDecisionCode()); 203 if (child == null) { 204 child = initChildDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), 205 branchedDecisionSymbols+(branchedDecisionSymbols.length() == 0?"":"_")+singleDecision.getDecisionSymbol()); 206 children.put(singleDecision.getDecisionCode(), child); 207 } 208 child.predict(featureModel, decision); 209 } 210 } 211 } 212 return success; 213 } 214 215 216 public ClassifierGuide getGuide() { 217 return guide; 218 } 219 220 public String getModelName() { 221 return modelName; 222 } 223 224// public FeatureModel getFeatureModel() { 225// return featureModel; 226// } 227 228 public int getDecisionIndex() { 229 return decisionIndex; 230 } 231 232 public DecisionModel getParentDecisionModel() { 233 return parentDecisionModel; 234 } 235 236 private DecisionModel initChildDecisionModel(SingleDecision decision, String branchedDecisionSymbol) throws MaltChainedException { 237 if (decision.getRelationToNextDecision() == RelationToNextDecision.SEQUANTIAL) { 238 return new SeqDecisionModel(guide, this, branchedDecisionSymbol); 239 } else if (decision.getRelationToNextDecision() == RelationToNextDecision.BRANCHED) { 240 return new BranchedDecisionModel(guide, this, branchedDecisionSymbol); 241 } else if (decision.getRelationToNextDecision() == RelationToNextDecision.NONE) { 242 return new OneDecisionModel(guide, this, branchedDecisionSymbol); 243 } 244 throw new GuideException("Could not find an appropriate decision model for the relation to the next decision"); 245 } 246 247 public String toString() { 248 final StringBuilder sb = new StringBuilder(); 249 sb.append(modelName + ", "); 250 for (DecisionModel model : children.values()) { 251 sb.append(model.toString() + ", "); 252 } 253 return sb.toString(); 254 } 255}