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