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.syntaxgraph.DependencyStructure; 007import org.maltparser.parser.guide.ClassifierGuide; 008import org.maltparser.parser.guide.GuideException; 009import org.maltparser.parser.guide.instance.AtomicModel; 010import org.maltparser.parser.guide.instance.FeatureDivideModel; 011import org.maltparser.parser.guide.instance.InstanceModel; 012import org.maltparser.parser.history.action.GuideDecision; 013import org.maltparser.parser.history.action.MultipleDecision; 014import org.maltparser.parser.history.action.SingleDecision; 015import org.maltparser.parser.history.container.TableContainer.RelationToNextDecision; 016/** 017* 018* @author Johan Hall 019* @since 1.1 020**/ 021public class SeqDecisionModel 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 prevDecisionModel; 028 private DecisionModel nextDecisionModel; 029 private final String branchedDecisionSymbols; 030 031 public SeqDecisionModel(ClassifierGuide _guide) throws MaltChainedException { 032 this.guide = _guide; 033 this.branchedDecisionSymbols = ""; 034// this.featureModel = _featureModel; 035 this.decisionIndex = 0; 036 this.modelName = "sdm"+decisionIndex; 037 this.prevDecisionModel = null; 038 } 039 040 public SeqDecisionModel(ClassifierGuide _guide, DecisionModel _prevDecisionModel, String _branchedDecisionSymbol) throws MaltChainedException { 041 this.guide = _guide; 042 this.decisionIndex = _prevDecisionModel.getDecisionIndex() + 1; 043 if (_branchedDecisionSymbol != null && _branchedDecisionSymbol.length() > 0) { 044 this.branchedDecisionSymbols = _branchedDecisionSymbol; 045 this.modelName = "sdm"+decisionIndex+branchedDecisionSymbols; 046 } else { 047 this.branchedDecisionSymbols = ""; 048 this.modelName = "sdm"+decisionIndex; 049 } 050// this.featureModel = _prevDecisionModel.getFeatureModel(); 051 this.prevDecisionModel = _prevDecisionModel; 052 } 053 054// public void updateFeatureModel() throws MaltChainedException { 055// featureModel.update(); 056// } 057 058 private void initInstanceModel(FeatureModel featureModel, String subModelName) throws MaltChainedException { 059 if (featureModel.hasDivideFeatureFunction()) { 060 instanceModel = new FeatureDivideModel(this); 061 } else { 062 instanceModel = new AtomicModel(-1, this); 063 } 064 } 065 066 public void finalizeSentence(DependencyStructure dependencyGraph) throws MaltChainedException { 067 if (instanceModel != null) { 068 instanceModel.finalizeSentence(dependencyGraph); 069 } 070 if (nextDecisionModel != null) { 071 nextDecisionModel.finalizeSentence(dependencyGraph); 072 } 073 } 074 075 public void noMoreInstances(FeatureModel featureModel) throws MaltChainedException { 076 if (guide.getGuideMode() == ClassifierGuide.GuideMode.CLASSIFY) { 077 throw new GuideException("The decision model could not create it's model. "); 078 } 079 if (instanceModel != null) { 080 instanceModel.noMoreInstances(featureModel); 081 instanceModel.train(); 082 } 083 if (nextDecisionModel != null) { 084 nextDecisionModel.noMoreInstances(featureModel); 085 } 086 } 087 088 public void terminate() throws MaltChainedException { 089 if (instanceModel != null) { 090 instanceModel.terminate(); 091 instanceModel = null; 092 } 093 if (nextDecisionModel != null) { 094 nextDecisionModel.terminate(); 095 nextDecisionModel = null; 096 } 097 } 098 099 public void addInstance(FeatureModel featureModel, GuideDecision decision) throws MaltChainedException { 100 if (decision instanceof SingleDecision) { 101 throw new GuideException("A sequantial decision model expect a sequence of decisions, not a single decision. "); 102 } 103 featureModel.update(); 104 final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex); 105 if (instanceModel == null) { 106 initInstanceModel(featureModel, singleDecision.getTableContainer().getTableContainerName()); 107 } 108 instanceModel.addInstance(featureModel.getFeatureVector(branchedDecisionSymbols, singleDecision.getTableContainer().getTableContainerName()), singleDecision); 109 if (singleDecision.continueWithNextDecision() && decisionIndex+1 < decision.numberOfDecisions()) { 110 if (nextDecisionModel == null) { 111 initNextDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), branchedDecisionSymbols); 112 } 113 nextDecisionModel.addInstance(featureModel, decision); 114 } 115 } 116 117 public boolean predict(FeatureModel featureModel, GuideDecision decision) throws MaltChainedException { 118 if (decision instanceof SingleDecision) { 119 throw new GuideException("A sequantial decision model expect a sequence of decisions, not a single decision. "); 120 } 121 featureModel.update(); 122 final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex); 123 if (instanceModel == null) { 124 initInstanceModel(featureModel, singleDecision.getTableContainer().getTableContainerName()); 125 } 126 127 boolean success = instanceModel.predict(featureModel.getFeatureVector(branchedDecisionSymbols, singleDecision.getTableContainer().getTableContainerName()), singleDecision); 128 if (singleDecision.continueWithNextDecision() && decisionIndex+1 < decision.numberOfDecisions()) { 129 if (nextDecisionModel == null) { 130 initNextDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), branchedDecisionSymbols); 131 } 132 success = nextDecisionModel.predict(featureModel, decision) && success; 133 } 134 return success; 135 } 136 137 public FeatureVector predictExtract(FeatureModel featureModel, GuideDecision decision) throws MaltChainedException { 138 if (decision instanceof SingleDecision) { 139 throw new GuideException("A sequantial decision model expect a sequence of decisions, not a single decision. "); 140 } 141 featureModel.update(); 142 final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex); 143 if (instanceModel == null) { 144 initInstanceModel(featureModel, singleDecision.getTableContainer().getTableContainerName()); 145 } 146 147 FeatureVector fv = instanceModel.predictExtract(featureModel.getFeatureVector(branchedDecisionSymbols, singleDecision.getTableContainer().getTableContainerName()), singleDecision); 148 if (singleDecision.continueWithNextDecision() && decisionIndex+1 < decision.numberOfDecisions()) { 149 if (nextDecisionModel == null) { 150 initNextDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), branchedDecisionSymbols); 151 } 152 nextDecisionModel.predictExtract(featureModel, decision); 153 } 154 return fv; 155 } 156 157 public FeatureVector extract(FeatureModel featureModel) throws MaltChainedException { 158 featureModel.update(); 159 return null ; //instanceModel.extract(); // TODO handle many feature vectors 160 } 161 162 public boolean predictFromKBestList(FeatureModel featureModel, GuideDecision decision) throws MaltChainedException { 163 if (decision instanceof SingleDecision) { 164 throw new GuideException("A sequantial decision model expect a sequence of decisions, not a single decision. "); 165 } 166 167 boolean success = false; 168 final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex); 169 // TODO develop different strategies for resolving which kBestlist that should be used 170 if (nextDecisionModel != null && singleDecision.continueWithNextDecision()) { 171 success = nextDecisionModel.predictFromKBestList(featureModel, decision); 172 } 173 if (!success) { 174 success = singleDecision.updateFromKBestList(); 175 if (success && singleDecision.continueWithNextDecision() && decisionIndex+1 < decision.numberOfDecisions()) { 176 if (nextDecisionModel == null) { 177 initNextDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), branchedDecisionSymbols); 178 } 179 nextDecisionModel.predict(featureModel, decision); 180 } 181 } 182 return success; 183 } 184 185 186 public ClassifierGuide getGuide() { 187 return guide; 188 } 189 190 public String getModelName() { 191 return modelName; 192 } 193 194// public FeatureModel getFeatureModel() { 195// return featureModel; 196// } 197 198 public int getDecisionIndex() { 199 return decisionIndex; 200 } 201 202 public DecisionModel getPrevDecisionModel() { 203 return prevDecisionModel; 204 } 205 206 public DecisionModel getNextDecisionModel() { 207 return nextDecisionModel; 208 } 209 210 private void initNextDecisionModel(SingleDecision decision, String branchedDecisionSymbol) throws MaltChainedException { 211 if (decision.getRelationToNextDecision() == RelationToNextDecision.SEQUANTIAL) { 212 this.nextDecisionModel = new SeqDecisionModel(guide, this, branchedDecisionSymbol); 213 } else if (decision.getRelationToNextDecision() == RelationToNextDecision.BRANCHED) { 214 this.nextDecisionModel = new BranchedDecisionModel(guide, this, branchedDecisionSymbol); 215 } else if (decision.getRelationToNextDecision() == RelationToNextDecision.NONE) { 216 this.nextDecisionModel = new OneDecisionModel(guide, this, branchedDecisionSymbol); 217 } 218 } 219 220 public String toString() { 221 final StringBuilder sb = new StringBuilder(); 222 sb.append(modelName + ", "); 223 sb.append(nextDecisionModel.toString()); 224 return sb.toString(); 225 } 226}