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