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