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