001    package org.maltparser.parser.guide;
002    
003    
004    import java.io.IOException;
005    import java.lang.reflect.Constructor;
006    import java.lang.reflect.InvocationTargetException;
007    
008    import org.maltparser.core.exception.MaltChainedException;
009    import org.maltparser.core.feature.FeatureModel;
010    import org.maltparser.core.feature.FeatureModelManager;
011    import org.maltparser.core.feature.system.FeatureEngine;
012    import org.maltparser.core.plugin.PluginLoader;
013    import org.maltparser.core.syntaxgraph.DependencyStructure;
014    import org.maltparser.parser.DependencyParserConfig;
015    import org.maltparser.parser.guide.decision.DecisionModel;
016    import org.maltparser.parser.history.GuideHistory;
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    /**
024     * The guide is used by a parsing algorithm to predict the next parser action during parsing and to
025     * add a instance to the training instance set during learning.
026    
027    @author Johan Hall
028    @since 1.0
029    */
030    public class SingleGuide implements Guide {
031            private DependencyParserConfig configuration;
032            private GuideHistory history;
033            private DecisionModel decisionModel = null;
034            private GuideMode guideMode;
035            private FeatureModelManager featureModelManager;
036            private FeatureModel featureModel;
037            
038            public SingleGuide(DependencyParserConfig configuration, GuideHistory history, GuideMode guideMode) throws MaltChainedException {
039                    setConfiguration(configuration);
040                    setHistory(history);
041                    setGuideMode(guideMode);
042                    initFeatureModelManager();
043                    initHistory();
044                    initFeatureModel();
045                    featureModel.updateCardinality();
046            }
047                    
048            public void addInstance(GuideDecision decision) throws MaltChainedException {
049                    if (decisionModel == null) {
050                            if (decision instanceof SingleDecision) {
051                                    initDecisionModel((SingleDecision)decision);
052                            } else if (decision instanceof MultipleDecision && decision.numberOfDecisions() > 0) {
053                                    initDecisionModel(((MultipleDecision)decision).getSingleDecision(0));
054                            }
055                    }
056                    decisionModel.addInstance(decision);
057            }
058            
059            public void finalizeSentence(DependencyStructure dependencyGraph) throws MaltChainedException {
060                    if (decisionModel != null) {
061                            decisionModel.finalizeSentence(dependencyGraph);
062                    }
063            }
064            
065            public void noMoreInstances() throws MaltChainedException {
066                    if (decisionModel != null) {
067                            decisionModel.noMoreInstances();
068                    } else {
069                            configuration.getConfigLogger().debug("The guide cannot create any models because there is no decision model. ");
070                    }
071            }
072            
073            public void terminate() throws MaltChainedException {
074                    if (decisionModel != null) {
075                            decisionModel.terminate();
076                            decisionModel = null;
077                    }
078            }
079    
080            public void predict(GuideDecision decision) throws MaltChainedException {
081                    if (decisionModel == null) {
082                            if (decision instanceof SingleDecision) {
083                                    initDecisionModel((SingleDecision)decision);
084                            } else if (decision instanceof MultipleDecision && decision.numberOfDecisions() > 0) {
085                                    initDecisionModel(((MultipleDecision)decision).getSingleDecision(0));
086                            }
087                    }
088                    decisionModel.predict(decision);
089            }
090    
091            public boolean predictFromKBestList(GuideDecision decision) throws MaltChainedException {
092                    if (decisionModel != null) {
093                            return decisionModel.predictFromKBestList(decision);
094                    } else {
095                            throw new GuideException("The decision model cannot be found. ");
096                    }
097            }
098            
099            public DecisionModel getDecisionModel() {
100                    return decisionModel;
101            }
102    
103            public DependencyParserConfig getConfiguration() {
104                    return configuration;
105            }
106            
107            public GuideHistory getHistory() {
108                    return history;
109            }
110            
111            public GuideMode getGuideMode() {
112                    return guideMode;
113            }
114            
115            public FeatureModelManager getFeatureModelManager() {
116                    return featureModelManager;
117            }
118            
119            protected void setConfiguration(DependencyParserConfig configuration) {
120                    this.configuration = configuration;
121            }
122    
123            protected void setHistory(GuideHistory actionHistory) {
124                    this.history = actionHistory;
125            }
126            
127            protected void setGuideMode(GuideMode guideMode) {
128                    this.guideMode = guideMode;
129            }
130            
131            protected void initHistory() throws MaltChainedException {
132                    Class<?> kBestListClass = null;
133                    int kBestSize = 1;
134                    if (guideMode == Guide.GuideMode.CLASSIFY) {
135                            kBestListClass = (Class<?>)getConfiguration().getOptionValue("guide", "kbest_type");
136                            kBestSize = ((Integer)getConfiguration().getOptionValue("guide", "kbest")).intValue();
137                    }
138                    history.setKBestListClass(kBestListClass);
139                    history.setKBestSize(kBestSize);
140                    history.setSeparator(getConfiguration().getOptionValue("guide", "classitem_separator").toString());
141            }
142            
143            protected void initDecisionModel(SingleDecision decision) throws MaltChainedException {
144                    Class<?> decisionModelClass = null;
145                    if (decision.getRelationToNextDecision() == RelationToNextDecision.SEQUANTIAL) {
146                            decisionModelClass = org.maltparser.parser.guide.decision.SeqDecisionModel.class;
147                    } else if (decision.getRelationToNextDecision() == RelationToNextDecision.BRANCHED) {
148                            decisionModelClass = org.maltparser.parser.guide.decision.BranchedDecisionModel.class;
149                    } else if (decision.getRelationToNextDecision() == RelationToNextDecision.NONE) {
150                            decisionModelClass = org.maltparser.parser.guide.decision.OneDecisionModel.class;
151                    }
152    
153                    if (decisionModelClass == null) {
154                            throw new GuideException("Could not find an appropriate decision model for the relation to the next decision"); 
155                    }
156                    
157                    try {
158                            Class<?>[] argTypes = { org.maltparser.parser.guide.Guide.class, org.maltparser.core.feature.FeatureModel.class };
159                            Object[] arguments = new Object[2];
160                            arguments[0] = this;
161                            arguments[1] = featureModel;
162                            Constructor<?> constructor = decisionModelClass.getConstructor(argTypes);
163                            decisionModel = (DecisionModel)constructor.newInstance(arguments);
164                    } catch (NoSuchMethodException e) {
165                            throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e);
166                    } catch (InstantiationException e) {
167                            throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e);
168                    } catch (IllegalAccessException e) {
169                            throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e);
170                    } catch (InvocationTargetException e) {
171                            throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e);
172                    }
173            }
174            
175            protected void initFeatureModelManager() throws MaltChainedException {
176                    final FeatureEngine system = new FeatureEngine(configuration);
177                    system.load("/appdata/features/ParserFeatureSystem.xml");
178                    system.load(PluginLoader.instance());
179                    featureModelManager = new FeatureModelManager(system, configuration.getRegistry());
180            }
181            
182            protected void initFeatureModel() throws MaltChainedException {
183                    getFeatureModelManager().loadSpecification(getConfiguration().getOptionValue("guide", "features").toString());
184                    featureModel = getFeatureModelManager().getFeatureModel(getConfiguration().getOptionValue("guide", "features").toString(), 0);
185                    if (getGuideMode() == Guide.GuideMode.TRAIN) {
186                            try {
187                                    getConfiguration().getConfigurationDir().getInfoFileWriter().write("\nFEATURE MODEL\n");
188                                    getConfiguration().getConfigurationDir().getInfoFileWriter().write(featureModel.toString());
189                                    getConfiguration().getConfigurationDir().getInfoFileWriter().flush();
190                            } catch (IOException e) {
191                                    throw new GuideException("Could not write feature model specification to configuration information file. ", e);
192                            }
193                    }
194            }
195            
196            public String toString() {
197                    final StringBuilder sb = new StringBuilder();
198                    return sb.toString();
199            }
200    }