gt:       Counter<L> scores = classifier.scoresOf((Datum<L,F>)d);
context: package edu.stanford.nlp.classify;
  
  import edu.stanford.nlp.optimization.GoldenSectionLineSearch;
  import edu.stanford.nlp.stats.*;
  import edu.stanford.nlp.util.*;
  import edu.stanford.nlp.ling.Datum;
  import edu.stanford.nlp.ling.RVFDatum;
  import edu.stanford.nlp.optimization.LineSearcher;
  
  import java.io.*;
  import java.text.NumberFormat;
  import java.util.*;
  import java.util.function.Function;
  import java.util.regex.Pattern;
  
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  /**
   * This class is meant for training SVMs ({@link SVMLightClassifier}s).  It actually calls SVM Light, or
   * SVM Struct for multiclass SVMs, or SVM perf is the option is enabled, on the command line, reads in the produced
   * model file and creates a Linear Classifier.  A Platt model is also trained
   * (unless otherwise specified) on top of the SVM so that probabilities can
   * be produced. For multiclass classifier, you have to set C using setC otherwise the code will not run (by sonalg).
   *
   * @author Jenny Finkel
   * @author Aria Haghighi
   * @author Sarah Spikes (sdspikes@cs.stanford.edu) (templatization)
   */
  
  public class SVMLightClassifierFactory<L, F> implements ClassifierFactory<L, F, SVMLightClassifier<L,F>>{ //extends AbstractLinearClassifierFactory {
  
    /**
     *
     */
    private static final long serialVersionUID = 1L;
  
    /**
     * C can be tuned using held-out set or cross-validation
     * For binary SVM, if C=0, svmlight uses default of 1/(avg x*x) 
     */
    protected double C = -1.0;
    private boolean useSigmoid = false;
    protected boolean verbose = true;
    private String svmLightLearn = "/u/nlp/packages/svm_light/svm_learn";
    private String svmStructLearn = "/u/nlp/packages/svm_multiclass/svm_multiclass_learn";
    private String svmPerfLearn = "/u/nlp/packages/svm_perf/svm_perf_learn";
    private String svmLightClassify = "/u/nlp/packages/svm_light/svm_classify";
    private String svmStructClassify = "/u/nlp/packages/svm_multiclass/svm_multiclass_classify";
    private String svmPerfClassify = "/u/nlp/packages/svm_perf/svm_perf_classify";
  
    private boolean useAlphaFile = false;
    protected File alphaFile;
    private boolean deleteTempFilesOnExit = true;
    private int svmLightVerbosity = 0;  // not verbose
    private boolean doEval = false;
    private boolean useSVMPerf = false;
  
    final static Logger logger = LoggerFactory.getLogger(SVMLightClassifierFactory.class);
  
    /** @param svmLightLearn is the fullPathname of the training program of svmLight with default value "/u/nlp/packages/svm_light/svm_learn"
     * @param svmStructLearn is the fullPathname of the training program of svmMultiClass with default value "/u/nlp/packages/svm_multiclass/svm_multiclass_learn"
     * @param svmPerfLearn is the fullPathname of the training program of svmMultiClass with default value "/u/nlp/packages/svm_perf/svm_perf_learn"
     */
    public SVMLightClassifierFactory(String svmLightLearn, String svmStructLearn, String svmPerfLearn){
      this.svmLightLearn = svmLightLearn;
      this.svmStructLearn = svmStructLearn;
      this.svmPerfLearn = svmPerfLearn;
    }
  
    public SVMLightClassifierFactory(){
    }
  
    public SVMLightClassifierFactory(boolean useSVMPerf){
      this.useSVMPerf = useSVMPerf;
    }
  
    /**
     * Set the C parameter (for the slack variables) for training the SVM.
     */
    public void setC(double C) {
      this.C = C;
    }
  
    /**
     * Get the C parameter (for the slack variables) for training the SVM.
     */
  
    public double getC() {
      return C;
    }
  
    /**
     * Specify whether or not to train an overlying platt (sigmoid)
     * model for producing meaningful probabilities.
     */
    public void setUseSigmoid(boolean useSigmoid) {
      this.useSigmoid = useSigmoid;
    }
  
    /**
     * Get whether or not to train an overlying platt (sigmoid)
     * model for producing meaningful probabilities.
     */
    public boolean getUseSigma() {
      return useSigmoid;
    }
  
  
    public boolean getDeleteTempFilesOnExitFlag() {
      return deleteTempFilesOnExit;
    }
  
    public void setDeleteTempFilesOnExitFlag(boolean deleteTempFilesOnExit) {
      this.deleteTempFilesOnExit = deleteTempFilesOnExit;
    }
  
    /**
     * Reads in a model file in svm light format.  It needs to know if its multiclass or not
     * because it affects the number of header lines.  Maybe there is another way to tell and we
     * can remove this flag?
     */
    private static Pair<Double, ClassicCounter<Integer>> readModel(File modelFile, boolean multiclass) {
      int modelLineCount = 0;
      try {
  
        int numLinesToSkip = multiclass ? 13 : 10;
        String stopToken   = "#";
  
        BufferedReader in = new BufferedReader(new FileReader(modelFile));
  
        for (int i=0; i < numLinesToSkip; i++) { 
          in.readLine();
          modelLineCount ++;
        }
  
        List<Pair<Double, ClassicCounter<Integer>>> supportVectors = new ArrayList<Pair<Double, ClassicCounter<Integer>>>();
        // Read Threshold
        String thresholdLine = in.readLine();
        modelLineCount ++;
        String[] pieces = thresholdLine.split("\\s+");
        double threshold = Double.parseDouble(pieces[0]);
        // Read Support Vectors
        while (in.ready()) {
          String svLine = in.readLine();
          modelLineCount ++;
          pieces = svLine.split("\\s+");
          // First Element is the alpha_i * y_i
          double  alpha = Double.parseDouble(pieces[0]);
          ClassicCounter<Integer> supportVector  = new ClassicCounter<Integer>();
          for (int i=1; i < pieces.length; ++i) {
            String piece = pieces[i];
            if (piece.equals(stopToken)) break;
            // Each in featureIndex:num class
            String[] indexNum = piece.split(":");
            String featureIndex = indexNum[0];
            // mihai: we may see "qid" as indexNum[0]. just skip this piece. this is the block id useful only for reranking, which we don't do here.
            if(! featureIndex.equals("qid")){
              double count = Double.parseDouble(indexNum[1]);
              supportVector.incrementCount(Integer.valueOf(featureIndex), count);
            }
          }
          supportVectors.add(new Pair<Double, ClassicCounter<Integer>>(alpha, supportVector));
        }
  
        in.close();
  
        return new Pair<Double, ClassicCounter<Integer>>(threshold, getWeights(supportVectors));
      }
      catch (Exception e) {
        e.printStackTrace();
        throw new RuntimeException("Error reading SVM model (line " + modelLineCount + " in file " + modelFile.getAbsolutePath() + ")");
      }
    }
  
    /**
     * Takes all the support vectors, and their corresponding alphas, and computes a weight
     * vector that can be used in a vanilla LinearClassifier.  This only works because
     * we are using a linear kernel.  The Counter is over the feature indices (+1 cos for
     * some reason svm_light is 1-indexed), not features.
     */
    private static ClassicCounter<Integer> getWeights(List<Pair<Double, ClassicCounter<Integer>>> supportVectors) {
      ClassicCounter<Integer> weights = new ClassicCounter<Integer>();
      for (Pair<Double, ClassicCounter<Integer>> sv : supportVectors) {
        ClassicCounter<Integer> c = new ClassicCounter<Integer>(sv.second());
        Counters.multiplyInPlace(c, sv.first());
        Counters.addInPlace(weights, c);
      }
      return weights;
    }
  
    /**
     * Converts the weight Counter to be from indexed, svm_light format, to a format
     * we can use in our LinearClassifier.
     */
    private ClassicCounter<Pair<F, L>> convertWeights(ClassicCounter<Integer> weights, Index<F> featureIndex, Index<L> labelIndex, boolean multiclass) {
      return multiclass ? convertSVMStructWeights(weights, featureIndex, labelIndex) : convertSVMLightWeights(weights, featureIndex, labelIndex);
    }
  
    /**
     * Converts the svm_light weight Counter (which uses feature indices) into a weight Counter
     * using the actual features and labels.  Because this is svm_light, and not svm_struct, the
     * weights for the +1 class (which correspond to labelIndex.get(0)) and the -1 class
     * (which correspond to labelIndex.get(1)) are just the negation of one another.
     */
    private ClassicCounter<Pair<F, L>> convertSVMLightWeights(ClassicCounter<Integer> weights, Index<F> featureIndex, Index<L> labelIndex) {
      ClassicCounter<Pair<F, L>> newWeights = new ClassicCounter<Pair<F, L>>();
      for (int i : weights.keySet()) {
        F f = featureIndex.get(i-1);
        double w = weights.getCount(i);
        // the first guy in the labelIndex was the +1 class and the second guy
        // was the -1 class
        newWeights.incrementCount(new Pair<F, L>(f, labelIndex.get(0)),w);
        newWeights.incrementCount(new Pair<F, L>(f, labelIndex.get(1)),-w);
      }
      return newWeights;
    }
  
    /**
     * Converts the svm_struct weight Counter (in which the weight for a feature/label pair
     * correspondes to ((labelIndex * numFeatures)+(featureIndex+1))) into a weight Counter
     * using the actual features and labels.
     */
    private ClassicCounter<Pair<F, L>> convertSVMStructWeights(ClassicCounter<Integer> weights, Index<F> featureIndex, Index<L> labelIndex) {
      // int numLabels = labelIndex.size();
      int numFeatures = featureIndex.size();
      ClassicCounter<Pair<F, L>> newWeights = new ClassicCounter<Pair<F, L>>();
      for (int i : weights.keySet()) {
        L l = labelIndex.get((i-1) / numFeatures); // integer division on purpose
        F f = featureIndex.get((i-1) % numFeatures);
        double w = weights.getCount(i);
        newWeights.incrementCount(new Pair<F, L>(f, l),w);
      }
  
      return newWeights;
    }
  
    /**
     * Builds a sigmoid model to turn the classifier outputs into probabilities.
     */
    private LinearClassifier<L, L> fitSigmoid(SVMLightClassifier<L, F> classifier, GeneralDataset<L, F> dataset) {
      RVFDataset<L, L> plattDataset = new RVFDataset<L, L>();
      for (int i = 0; i < dataset.size(); i++) {
        RVFDatum<L, F> d = dataset.getRVFDatum(i);
  