    001    package calhoun.analysis.crf.features.generic;
    002    import java.util.ArrayList;
    003    import java.util.List;
    004
    005    import org.apache.commons.logging.Log;
    006    import org.apache.commons.logging.LogFactory;
    007
    008    import calhoun.analysis.crf.AbstractFeatureManager;
    009    import calhoun.analysis.crf.FeatureList;
    010    import calhoun.analysis.crf.FeatureManagerEdge;
    011    import calhoun.analysis.crf.ModelManager;
    012    import calhoun.analysis.crf.io.InputSequence;
    013    import calhoun.util.Assert;
    014    import calhoun.util.DenseBooleanMatrix2D;
    015    import calhoun.util.DenseIntMatrix2D;
    016
    017    /** a set of indicator features for the valid transitions in the model.
    018     * <p>
    019     * <b>Notes:</b>
    020     * <ul>
    021     * <li> Each indicator returns 1 when evaluated on it's transition, otherwise 0.
    022     * <li> Exactly one feature will return a non-zero value for every valid edge transition.
    023     * </ul>
    024     */
    025    public class IndicatorEdges extends AbstractFeatureManager implements FeatureManagerEdge {
    026            private static final long serialVersionUID = -2633500053477439285L;
    027            private static final Log log = LogFactory.getLog(IndicatorEdges.class);
    028            boolean debug = log.isDebugEnabled();
    029
    030            int startIx;
    031            DenseIntMatrix2D transitions;
    032            List<String> names;
    033
    034            public String getFeatureName(int featureIndex) {
    035                    Assert.a(featureIndex - startIx < names.size(), "Invalid feature index");
    036                    return names.get(featureIndex - startIx);
    037            }
    038
    039            public int getNumFeatures() {
    040                    return names.size();
    041            }
    042
    043            public void evaluateEdge(InputSequence seq, int pos, int prevState, int state, FeatureList result) {
    044                    int index = transitions.getQuick(prevState, state);
    045                    if(index != -1) {
    046                            result.addFeature(index, 1);
    047                    }
    048            }
    049
    050            /** Edge features don't train based on the data.  Just set up based on the model. */
    051            public void train(int startingIndex, ModelManager modelInfo, List data) {
    052                    startIx = startingIndex;
    053                    int nStates = modelInfo.getNumStates();
    054                    transitions = new DenseIntMatrix2D(nStates, nStates);
    055                    transitions.assign(-1);
    056                    names = new ArrayList<String>();
    057
    058                    int n = 0;
    059                    DenseBooleanMatrix2D trans = modelInfo.getLegalTransitions();
    060                    for(int i=0; i<nStates; ++i) {
    061                            for(int j=0; j<nStates; ++j) {
    062                                    if(trans.getQuick(i, j)) {
    063                                            transitions.setQuick(i, j, startIx + n);
    064                                            names.add("Edge."+modelInfo.getStateName(i)+"-"+modelInfo.getStateName(j));
    065                                            ++n;
    066                                    }
    067                            }
    068                    }
    069            }
    070    }