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.FeatureVector;
012    import org.maltparser.core.feature.system.FeatureEngine;
013    import org.maltparser.core.helper.SystemLogger;
014    import org.maltparser.core.helper.Util;
015    import org.maltparser.core.plugin.PluginLoader;
016    import org.maltparser.core.syntaxgraph.DependencyStructure;
017    import org.maltparser.parser.DependencyParserConfig;
018    import org.maltparser.parser.guide.decision.DecisionModel;
019    import org.maltparser.parser.history.GuideHistory;
020    import org.maltparser.parser.history.action.GuideDecision;
021    import org.maltparser.parser.history.action.MultipleDecision;
022    import org.maltparser.parser.history.action.SingleDecision;
023    import org.maltparser.parser.history.container.TableContainer.RelationToNextDecision;
024    
025    
026    /**
027     * The guide is used by a parsing algorithm to predict the next parser action during parsing and to
028     * add a instance to the training instance set during learning.
029    
030    @author Johan Hall
031    @since 1.0
032    */
033    public class SingleGuide implements ClassifierGuide {
034            private DependencyParserConfig configuration;
035            private GuideHistory history;
036            private DecisionModel decisionModel = null;
037            private GuideMode guideMode;
038            private FeatureModelManager featureModelManager;
039            private FeatureModel featureModel;
040            private String guideName;
041            
042            public SingleGuide(DependencyParserConfig configuration, GuideHistory history, GuideMode guideMode) throws MaltChainedException {
043                    setConfiguration(configuration);
044                    setHistory(history);
045                    setGuideMode(guideMode);
046                    initFeatureModelManager();
047                    initHistory();
048                    initFeatureModel();
049                    featureModel.updateCardinality();
050            }
051                    
052            public void addInstance(GuideDecision decision) throws MaltChainedException {
053                    if (decisionModel == null) {
054                            if (decision instanceof SingleDecision) {
055                                    initDecisionModel((SingleDecision)decision);
056                            } else if (decision instanceof MultipleDecision && decision.numberOfDecisions() > 0) {
057                                    initDecisionModel(((MultipleDecision)decision).getSingleDecision(0));
058                            }
059                    }
060                    decisionModel.addInstance(decision);
061            }
062            
063            public void finalizeSentence(DependencyStructure dependencyGraph) throws MaltChainedException {
064                    if (decisionModel != null) {
065                            decisionModel.finalizeSentence(dependencyGraph);
066                    }
067            }
068            
069            public void noMoreInstances() throws MaltChainedException {
070                    if (decisionModel != null) {
071                            decisionModel.noMoreInstances();
072                    } else {
073                            configuration.getConfigLogger().debug("The guide cannot create any models because there is no decision model. ");
074                    }
075            }
076            
077            public void terminate() throws MaltChainedException {
078                    if (decisionModel != null) {
079                            decisionModel.terminate();
080                            decisionModel = null;
081                    }
082            }
083    
084            public void predict(GuideDecision decision) throws MaltChainedException {
085                    if (decisionModel == null) {
086                            if (decision instanceof SingleDecision) {
087                                    initDecisionModel((SingleDecision)decision);
088                            } else if (decision instanceof MultipleDecision && decision.numberOfDecisions() > 0) {
089                                    initDecisionModel(((MultipleDecision)decision).getSingleDecision(0));
090                            }
091                    }
092                    decisionModel.predict(decision);
093            }
094    
095            public FeatureVector predictExtract(GuideDecision decision) throws MaltChainedException {
096                    if (decisionModel == null) {
097                            if (decision instanceof SingleDecision) {
098                                    initDecisionModel((SingleDecision)decision);
099                            } else if (decision instanceof MultipleDecision && decision.numberOfDecisions() > 0) {
100                                    initDecisionModel(((MultipleDecision)decision).getSingleDecision(0));
101                            }
102                    }
103                    return decisionModel.predictExtract(decision);
104            }
105            
106            public FeatureVector extract() throws MaltChainedException {
107                    return decisionModel.extract();
108            }
109            
110            public boolean predictFromKBestList(GuideDecision decision) throws MaltChainedException {
111                    if (decisionModel != null) {
112                            return decisionModel.predictFromKBestList(decision);
113                    } else {
114                            throw new GuideException("The decision model cannot be found. ");
115                    }
116            }
117            
118            public DecisionModel getDecisionModel() {
119                    return decisionModel;
120            }
121    
122            public DependencyParserConfig getConfiguration() {
123                    return configuration;
124            }
125            
126            public GuideHistory getHistory() {
127                    return history;
128            }
129            
130            public GuideMode getGuideMode() {
131                    return guideMode;
132            }
133            
134            public FeatureModelManager getFeatureModelManager() {
135                    return featureModelManager;
136            }
137            
138            protected void setConfiguration(DependencyParserConfig configuration) {
139                    this.configuration = configuration;
140            }
141    
142            protected void setHistory(GuideHistory actionHistory) {
143                    this.history = actionHistory;
144            }
145            
146            protected void setGuideMode(GuideMode guideMode) {
147                    this.guideMode = guideMode;
148            }
149            
150            protected void initHistory() throws MaltChainedException {
151                    Class<?> kBestListClass = null;
152                    int kBestSize = 1;
153                    if (guideMode == ClassifierGuide.GuideMode.CLASSIFY) {
154                            kBestListClass = (Class<?>)getConfiguration().getOptionValue("guide", "kbest_type");
155                            kBestSize = ((Integer)getConfiguration().getOptionValue("guide", "kbest")).intValue();
156                    }
157                    history.setKBestListClass(kBestListClass);
158                    history.setKBestSize(kBestSize);
159                    history.setSeparator(getConfiguration().getOptionValue("guide", "classitem_separator").toString());
160            }
161            
162            protected void initDecisionModel(SingleDecision decision) throws MaltChainedException {
163                    Class<?> decisionModelClass = null;
164                    if (decision.getRelationToNextDecision() == RelationToNextDecision.SEQUANTIAL) {
165                            decisionModelClass = org.maltparser.parser.guide.decision.SeqDecisionModel.class;
166                    } else if (decision.getRelationToNextDecision() == RelationToNextDecision.BRANCHED) {
167                            decisionModelClass = org.maltparser.parser.guide.decision.BranchedDecisionModel.class;
168                    } else if (decision.getRelationToNextDecision() == RelationToNextDecision.NONE) {
169                            decisionModelClass = org.maltparser.parser.guide.decision.OneDecisionModel.class;
170                    }
171    
172                    if (decisionModelClass == null) {
173                            throw new GuideException("Could not find an appropriate decision model for the relation to the next decision"); 
174                    }
175                    
176                    try {
177                            Class<?>[] argTypes = { org.maltparser.parser.guide.ClassifierGuide.class, org.maltparser.core.feature.FeatureModel.class };
178                            Object[] arguments = new Object[2];
179                            arguments[0] = this;
180                            arguments[1] = featureModel;
181                            Constructor<?> constructor = decisionModelClass.getConstructor(argTypes);
182                            decisionModel = (DecisionModel)constructor.newInstance(arguments);
183                    } catch (NoSuchMethodException e) {
184                            throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e);
185                    } catch (InstantiationException e) {
186                            throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e);
187                    } catch (IllegalAccessException e) {
188                            throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e);
189                    } catch (InvocationTargetException e) {
190                            throw new GuideException("The decision model class '"+decisionModelClass.getName()+"' cannot be initialized. ", e);
191                    }
192            }
193            
194            protected void initFeatureModelManager() throws MaltChainedException {
195                    final FeatureEngine system = new FeatureEngine();
196                    system.load("/appdata/features/ParserFeatureSystem.xml");
197                    system.load(PluginLoader.instance());
198                    featureModelManager = new FeatureModelManager(system, getConfiguration().getConfigurationDir());
199            }
200            
201            protected void initFeatureModel() throws MaltChainedException {
202                    String featureModelFileName = getConfiguration().getOptionValue("guide", "features").toString().trim();
203    
204                    if (featureModelFileName.endsWith(".par")) {
205                            String markingStrategy = getConfiguration().getOptionValue("pproj", "marking_strategy").toString().trim();
206                            String coveredRoot = getConfiguration().getOptionValue("pproj", "covered_root").toString().trim();
207                            featureModelManager.loadParSpecification(featureModelFileName, markingStrategy, coveredRoot);
208                    } else {
209                            featureModelManager.loadSpecification(featureModelFileName);
210                    }
211                    if (getConfiguration().getConfigLogger().isInfoEnabled()) {
212                            getConfiguration().getConfigLogger().info("  Feature model        : " + featureModelFileName+"\n");
213                            if (getGuideMode() == ClassifierGuide.GuideMode.BATCH) {
214                                    getConfiguration().getConfigLogger().info("  Learner              : " + getConfiguration().getOptionValueString("guide", "learner").toString()+"\n");
215                            } else {
216                                    getConfiguration().getConfigLogger().info("  Classifier           : " + getConfiguration().getOptionValueString("guide", "learner")+"\n");      
217                            }
218                    }
219                    featureModel = getFeatureModelManager().getFeatureModel(getConfiguration().getOptionValue("guide", "features").toString(), 0, getConfiguration().getRegistry());
220                    if (getGuideMode() == ClassifierGuide.GuideMode.BATCH && getConfiguration().getConfigurationDir().getInfoFileWriter() != null) {
221                            try {
222                                    getConfiguration().getConfigurationDir().getInfoFileWriter().write("\nFEATURE MODEL\n");
223                                    getConfiguration().getConfigurationDir().getInfoFileWriter().write(featureModel.toString());
224                                    getConfiguration().getConfigurationDir().getInfoFileWriter().flush();
225                            } catch (IOException e) {
226                                    throw new GuideException("Could not write feature model specification to configuration information file. ", e);
227                            }
228                    }
229            }
230            
231            
232            public String getGuideName() {
233                    return guideName;
234            }
235    
236            public void setGuideName(String guideName) {
237                    this.guideName = guideName;
238            }
239    
240            public String toString() {
241                    final StringBuilder sb = new StringBuilder();
242                    return sb.toString();
243            }
244    }