001    package org.maltparser.parser.guide.decision;
002    
003    import java.lang.reflect.Constructor;
004    import java.lang.reflect.InvocationTargetException;
005    import java.util.HashMap;
006    
007    import org.maltparser.core.exception.MaltChainedException;
008    import org.maltparser.core.feature.FeatureModel;
009    import org.maltparser.core.feature.FeatureVector;
010    import org.maltparser.core.syntaxgraph.DependencyStructure;
011    import org.maltparser.parser.guide.Guide;
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 BranchedDecisionModel implements DecisionModel {
026            private Guide guide;
027            private String modelName;
028            private FeatureModel featureModel;
029            private InstanceModel instanceModel;
030            private int decisionIndex;
031            private DecisionModel parentDecisionModel;
032            private HashMap<Integer,DecisionModel> children;
033            private String branchedDecisionSymbols;
034            
035            public BranchedDecisionModel(Guide guide, FeatureModel featureModel) throws MaltChainedException {
036                    this.branchedDecisionSymbols = "";
037                    setGuide(guide);
038                    setFeatureModel(featureModel);
039                    setDecisionIndex(0);
040                    setModelName("bdm"+decisionIndex);
041                    setParentDecisionModel(null);
042            }
043            
044            public BranchedDecisionModel(Guide guide, DecisionModel parentDecisionModel, 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                    setParentDecisionModel(parentDecisionModel);
052                    setDecisionIndex(parentDecisionModel.getDecisionIndex() + 1);
053                    setFeatureModel(parentDecisionModel.getFeatureModel());
054                    if (branchedDecisionSymbols != null && branchedDecisionSymbols.length() > 0) {
055                            setModelName("bdm"+decisionIndex+branchedDecisionSymbols);
056                    } else {
057                            setModelName("bdm"+decisionIndex);
058                    }
059                    this.parentDecisionModel = parentDecisionModel;
060            }
061            
062            public void update() throws MaltChainedException {
063                    featureModel.update();
064            }
065            
066            public void updateCardinality() throws MaltChainedException {
067                    featureModel.updateCardinality();
068            }
069            
070    
071            public void finalizeSentence(DependencyStructure dependencyGraph) throws MaltChainedException {
072                    if (instanceModel != null) {
073                            instanceModel.finalizeSentence(dependencyGraph);
074                    }
075                    if (children != null) {
076                            for (DecisionModel child : children.values()) {
077                                    child.finalizeSentence(dependencyGraph);
078                            }
079                    }
080            }
081            
082            public void noMoreInstances() throws MaltChainedException {
083                    if (guide.getGuideMode() != Guide.GuideMode.TRAIN) {
084                            throw new GuideException("The decision model could not create it's model. ");
085                    }
086                    featureModel.updateCardinality();
087                    if (instanceModel != null) {
088                            instanceModel.noMoreInstances();
089                            instanceModel.train();
090                    }
091                    if (children != null) {
092                            for (DecisionModel child : children.values()) {
093                                    child.noMoreInstances();
094                            }
095                    }
096            }
097    
098            public void terminate() throws MaltChainedException {
099                    if (instanceModel != null) {
100                            instanceModel.terminate();
101                            instanceModel = null;
102                    }
103                    if (children != null) {
104                            for (DecisionModel child : children.values()) {
105                                    child.terminate();
106                            }
107                    }
108            }
109            
110            public void addInstance(GuideDecision decision) throws MaltChainedException {
111                    if (decision instanceof SingleDecision) {
112                            throw new GuideException("A branched decision model expect more than one decisions. ");
113                    }
114                    update();
115                    final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex);
116                    if (instanceModel == null) {
117                            initInstanceModel(singleDecision.getTableContainer().getTableContainerName());
118                    }
119                    
120                    instanceModel.addInstance(singleDecision);
121                    if (decisionIndex+1 < decision.numberOfDecisions()) {
122                            if (singleDecision.continueWithNextDecision()) {
123                                    if (children == null) {
124                                            children = new HashMap<Integer,DecisionModel>();
125                                    }
126                                    DecisionModel child = children.get(singleDecision.getDecisionCode());
127                                    if (child == null) {
128                                            child = initChildDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), 
129                                                            branchedDecisionSymbols+(branchedDecisionSymbols.length() == 0?"":"_")+singleDecision.getDecisionSymbol());
130                                            children.put(singleDecision.getDecisionCode(), child);
131                                    }
132                                    child.addInstance(decision);
133                            }
134                    }
135            }
136            
137            public boolean predict(GuideDecision decision) throws MaltChainedException {
138                    if (decision instanceof SingleDecision) {
139                            throw new GuideException("A branched decision model expect more than one decisions. ");
140                    }
141                    update();
142                    final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex);
143                    if (instanceModel == null) {
144                            initInstanceModel(singleDecision.getTableContainer().getTableContainerName());
145                    }
146                    instanceModel.predict(singleDecision);
147                    if (decisionIndex+1 < decision.numberOfDecisions()) {
148                            if (singleDecision.continueWithNextDecision()) {
149                                    if (children == null) {
150                                            children = new HashMap<Integer,DecisionModel>();
151                                    }
152                                    DecisionModel child = children.get(singleDecision.getDecisionCode());
153                                    if (child == null) {
154                                            child = initChildDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), 
155                                                            branchedDecisionSymbols+(branchedDecisionSymbols.length() == 0?"":"_")+singleDecision.getDecisionSymbol());
156                                            children.put(singleDecision.getDecisionCode(), child);
157                                    }
158                                    child.predict(decision);
159                            }
160                    }
161    
162                    return true;
163            }
164            
165            public boolean predictFromKBestList(GuideDecision decision) throws MaltChainedException {
166                    if (decision instanceof SingleDecision) {
167                            throw new GuideException("A branched decision model expect more than one decisions. ");
168                    }
169                    
170                    boolean success = false;
171                    final SingleDecision singleDecision = ((MultipleDecision)decision).getSingleDecision(decisionIndex);
172                    if (decisionIndex+1 < decision.numberOfDecisions()) {
173                            if (singleDecision.continueWithNextDecision()) {
174                                    if (children == null) {
175                                            children = new HashMap<Integer,DecisionModel>();
176                                    }
177                                    DecisionModel child = children.get(singleDecision.getDecisionCode());
178                                    if (child != null) {
179                                            success = child.predictFromKBestList(decision);
180                                    }
181                                    
182                            }
183                    }
184                    if (!success) {
185                            success = singleDecision.updateFromKBestList();
186                            if (decisionIndex+1 < decision.numberOfDecisions()) {
187                                    if (singleDecision.continueWithNextDecision()) {
188                                            if (children == null) {
189                                                    children = new HashMap<Integer,DecisionModel>();
190                                            }
191                                            DecisionModel child = children.get(singleDecision.getDecisionCode());
192                                            if (child == null) {
193                                                    child = initChildDecisionModel(((MultipleDecision)decision).getSingleDecision(decisionIndex+1), 
194                                                                    branchedDecisionSymbols+(branchedDecisionSymbols.length() == 0?"":"_")+singleDecision.getDecisionSymbol());
195                                                    children.put(singleDecision.getDecisionCode(), child);
196                                            }
197                                            child.predict(decision);
198                                    }
199                            }
200                    }
201                    return success;
202            }
203            
204    
205            public Guide getGuide() {
206                    return guide;
207            }
208    
209            public String getModelName() {
210                    return modelName;
211            }
212            
213            public FeatureModel getFeatureModel() {
214                    return featureModel;
215            }
216    
217            public int getDecisionIndex() {
218                    return decisionIndex;
219            }
220    
221            public DecisionModel getParentDecisionModel() {
222                    return parentDecisionModel;
223            }
224    
225            private void setFeatureModel(FeatureModel featureModel) {
226                    this.featureModel = featureModel;
227            }
228            
229            private void setDecisionIndex(int decisionIndex) {
230                    this.decisionIndex = decisionIndex;
231            }
232            
233            private void setParentDecisionModel(DecisionModel parentDecisionModel) {
234                    this.parentDecisionModel = parentDecisionModel;
235            }
236    
237            private void setModelName(String modelName) {
238                    this.modelName = modelName;
239            }
240            
241            private void setGuide(Guide guide) {
242                    this.guide = guide;
243            }
244            
245            
246            private DecisionModel initChildDecisionModel(SingleDecision decision, String branchedDecisionSymbol) throws MaltChainedException {
247                    Class<?> decisionModelClass = null;
248                    if (decision.getRelationToNextDecision() == RelationToNextDecision.SEQUANTIAL) {
249                            decisionModelClass = org.maltparser.parser.guide.decision.SeqDecisionModel.class;
250                    } else if (decision.getRelationToNextDecision() == RelationToNextDecision.BRANCHED) {
251                            decisionModelClass = org.maltparser.parser.guide.decision.BranchedDecisionModel.class;
252                    } else if (decision.getRelationToNextDecision() == RelationToNextDecision.NONE) {
253                            decisionModelClass = org.maltparser.parser.guide.decision.OneDecisionModel.class;
254                    }
255    
256                    if (decisionModelClass == null) {
257                            throw new GuideException("Could not find an appropriate decision model for the relation to the next decision"); 
258                    }
259                    
260                    try {
261                            Class<?>[] argTypes = { org.maltparser.parser.guide.Guide.class, org.maltparser.parser.guide.decision.DecisionModel.class, 
262                                                    java.lang.String.class };
263                            Object[] arguments = new Object[3];
264                            arguments[0] = getGuide();
265                            arguments[1] = this;
266                            arguments[2] = branchedDecisionSymbol;
267                            Constructor<?> constructor = decisionModelClass.getConstructor(argTypes);
268                            return (DecisionModel)constructor.newInstance(arguments);
269                    } catch (NoSuchMethodException e) {
270                            throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e);
271                    } catch (InstantiationException e) {
272                            throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e);
273                    } catch (IllegalAccessException e) {
274                            throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e);
275                    } catch (InvocationTargetException e) {
276                            throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e);
277                    }
278            }
279            
280            private void initInstanceModel(String subModelName) throws MaltChainedException {
281                    FeatureVector fv = featureModel.getFeatureVector(branchedDecisionSymbols+"."+subModelName);
282                    if (fv == null) {
283                            fv = featureModel.getFeatureVector(subModelName);
284                    }
285                    if (fv == null) {
286                            fv = featureModel.getMainFeatureVector();
287                    }
288                    if (guide.getConfiguration().getOptionValue("guide", "data_split_column").toString().length() == 0) {
289                            instanceModel = new AtomicModel(-1, fv, this);
290                    } else {
291                            instanceModel = new FeatureDivideModel(fv, this);
292                    }
293            }
294            
295            public String toString() {
296                    final StringBuilder sb = new StringBuilder();
297                    sb.append(modelName + ", ");
298                    for (DecisionModel model : children.values()) {
299                            sb.append(model.toString() + ", ");
300                    }
301                    return sb.toString();
302            }
303    }