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}