001package org.maltparser.core.lw.parser;
002
003import java.util.Set;
004
005import org.maltparser.core.exception.MaltChainedException;
006import org.maltparser.core.feature.FeatureModel;
007import org.maltparser.core.feature.FeatureVector;
008import org.maltparser.core.feature.value.SingleFeatureValue;
009import org.maltparser.core.helper.HashMap;
010import org.maltparser.parser.history.action.ComplexDecisionAction;
011import org.maltparser.parser.history.action.SingleDecision;
012import org.maltparser.parser.history.container.TableContainer.RelationToNextDecision;
013
014/**
015* A lightweight version of the decision models, the guide model and the instance models located in org.maltparser.parser.guide.{decision,instance} and
016* can only be used in parsing mode. It is also limited to predict at most two decisions.
017* 
018* @author Johan Hall
019*/
020public final class LWDecisionModel {
021        private final String classifierName;
022        private final HashMap<String, LWClassifier> classifiers;
023        
024        public LWDecisionModel(McoModel mcoModel, boolean _excludeNullValues, String _classifierName) {
025                this.classifierName = _classifierName;
026                this.classifiers = new HashMap<String, LWClassifier>();
027                Set<String> mcoEntryObjectKeys = mcoModel.getMcoEntryObjectKeys();
028                for (String key : mcoEntryObjectKeys) {
029                        if (key.endsWith(".moo")) {
030                                String prefixFileName = key.substring(0,key.length()-4);
031                                classifiers.put(prefixFileName, new LWClassifier(mcoModel, prefixFileName, _excludeNullValues));
032                        }
033                }
034        }
035        
036        public boolean predict(FeatureModel featureModel, ComplexDecisionAction decision, boolean one_prediction) throws MaltChainedException {
037                if (decision.numberOfDecisions() > 2) {
038                        throw new MaltChainedException("Number of decisions is greater than two,  which is unsupported in the light-weight parser (lw.parser)");
039                }
040                featureModel.update();
041                boolean success = true;
042                for (int i = 0; i < decision.numberOfDecisions(); i++) {
043                        LWClassifier classifier = null;
044                        final SingleDecision singleDecision = decision.getSingleDecision(i);
045                        final StringBuilder classifierString = new StringBuilder();
046                        
047                        final StringBuilder decisionModelString = new StringBuilder();
048                        if (singleDecision.getRelationToNextDecision() == RelationToNextDecision.BRANCHED) {
049                                decisionModelString.append("bdm");
050                        } else if (singleDecision.getRelationToNextDecision() == RelationToNextDecision.SEQUANTIAL) {
051                                decisionModelString.append("sdm");
052                        } else {
053                                decisionModelString.append("odm");
054                        }
055                        decisionModelString.append(i);
056                        String decisionSymbol = "";
057                        if (i == 1 && singleDecision.getRelationToNextDecision() == RelationToNextDecision.BRANCHED) {
058                                decisionSymbol = singleDecision.getDecisionSymbol();
059                                decisionModelString.append(decisionSymbol);
060                        }
061                        decisionModelString.append('.');
062                        FeatureVector featureVector = featureModel.getFeatureVector(decisionSymbol, singleDecision.getTableContainer().getTableContainerName());
063                        
064                        if (featureModel.hasDivideFeatureFunction()) {
065                                SingleFeatureValue featureValue =(SingleFeatureValue)featureModel.getDivideFeatureFunction().getFeatureValue();
066                                classifierString.append(decisionModelString);
067                                classifierString.append(String.format("%03d", featureValue.getIndexCode()));
068                                classifierString.append('.');
069                                classifierString.append(classifierName);
070                                classifier = classifiers.get(classifierString.toString());
071                                if (classifier != null) {
072                                        FeatureVector dividefeatureVector = featureModel.getFeatureVector("/" + featureVector.getSpecSubModel().getSubModelName());
073                                        success = classifier.predict(dividefeatureVector, singleDecision, one_prediction) && success;
074                                        continue;
075                                } 
076                                classifierString.setLength(0);
077                        }
078
079                        classifierString.append(decisionModelString);
080                        classifierString.append(classifierName);
081                        classifier = classifiers.get(classifierString.toString());
082                        if (classifier != null) {
083                                success = classifier.predict(featureVector, singleDecision, one_prediction) && success;
084                        } else {
085                                singleDecision.addDecision(1);
086                        } 
087                        if (!singleDecision.continueWithNextDecision()) {
088                                break;
089                        }
090                }
091                return success;
092        }
093        
094        public boolean predictFromKBestList(FeatureModel featureModel, ComplexDecisionAction decision) throws MaltChainedException {
095                predict(featureModel, decision, false);
096                if (decision.numberOfDecisions() == 1) {
097                        return decision.getSingleDecision(0).updateFromKBestList();
098                } else if (decision.numberOfDecisions() > 2) {
099                        throw new MaltChainedException("Number of decisions is greater than two,  which is unsupported in the light-weight parser (lw.parser)");
100                }
101                boolean success = false;
102                if (decision.getSingleDecision(0).continueWithNextDecision()) {
103                        success = decision.getSingleDecision(1).updateFromKBestList();
104                }
105                return success;
106        }
107}