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