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