public Classifier<L, F> trainClassifier(
      GeneralDataset<L, F> dataset, float[] dataWeights, LogPrior prior) {
    Minimizer<DiffFunction> minimizer = getMinimizer();
    if (dataset instanceof RVFDataset) ((RVFDataset<L, F>) dataset).ensureRealValues();
    LogConditionalObjectiveFunction<L, F> objective =
        new LogConditionalObjectiveFunction<L, F>(dataset, dataWeights, logPrior);

    double[] initial = objective.initial();
    double[] weights = minimizer.minimize(objective, TOL, initial);

    LinearClassifier<L, F> classifier =
        new LinearClassifier<L, F>(
            objective.to2D(weights), dataset.featureIndex(), dataset.labelIndex());
    return classifier;
  }
  public double[][] trainWeights(
      GeneralDataset<L, F> dataset,
      double[] initial,
      boolean bypassTuneSigma,
      Minimizer<DiffFunction> minimizer) {
    if (minimizer == null) minimizer = minimizerCreator.create();
    if (dataset instanceof RVFDataset) ((RVFDataset<L, F>) dataset).ensureRealValues();
    double[] interimWeights = null;
    if (!bypassTuneSigma) {
      if (tuneSigmaHeldOut) {
        interimWeights =
            heldOutSetSigma(
                dataset); // the optimum interim weights from held-out training data have already
                          // been found.
      } else if (tuneSigmaCV) {
        crossValidateSetSigma(
            dataset, folds); // TODO: assign optimum interim weights as part of this process.
      }
    }
    LogConditionalObjectiveFunction<L, F> objective =
        new LogConditionalObjectiveFunction<L, F>(dataset, logPrior);
    if (initial == null && interimWeights != null && !retrainFromScratchAfterSigmaTuning) {
      // System.err.println("## taking advantage of interim weights as starting point.");
      initial = interimWeights;
    }
    if (initial == null) {
      initial = objective.initial();
    }

    double[] weights = minimizer.minimize(objective, TOL, initial);
    return objective.to2D(weights);
  }
  /**
   * Adapt classifier (adjust the mean of Gaussian prior) under construction -pichuan
   *
   * @param origWeights the original weights trained from the training data
   * @param adaptDataset the Dataset used to adapt the trained weights
   * @return adapted weights
   */
  public double[][] adaptWeights(double[][] origWeights, GeneralDataset<L, F> adaptDataset) {
    Minimizer<DiffFunction> minimizer = getMinimizer();
    System.err.println("adaptWeights in LinearClassifierFactory. increase weight dim only");
    double[][] newWeights =
        new double[adaptDataset.featureIndex.size()][adaptDataset.labelIndex.size()];

    System.arraycopy(origWeights, 0, newWeights, 0, origWeights.length);

    AdaptedGaussianPriorObjectiveFunction<L, F> objective =
        new AdaptedGaussianPriorObjectiveFunction<L, F>(adaptDataset, logPrior, newWeights);

    double[] initial = objective.initial();

    double[] weights = minimizer.minimize(objective, TOL, initial);
    return objective.to2D(weights);

    // Question: maybe the adaptWeights can be done just in LinearClassifier ?? (pichuan)
  }
 public double[][] trainWeightsSemiSup(
     GeneralDataset<L, F> data,
     GeneralDataset<L, F> biasedData,
     double[][] confusionMatrix,
     double[] initial) {
   Minimizer<DiffFunction> minimizer = minimizerCreator.create();
   LogConditionalObjectiveFunction<L, F> objective =
       new LogConditionalObjectiveFunction<L, F>(data, new LogPrior(LogPrior.LogPriorType.NULL));
   BiasedLogConditionalObjectiveFunction biasedObjective =
       new BiasedLogConditionalObjectiveFunction(
           biasedData, confusionMatrix, new LogPrior(LogPrior.LogPriorType.NULL));
   SemiSupervisedLogConditionalObjectiveFunction semiSupObjective =
       new SemiSupervisedLogConditionalObjectiveFunction(objective, biasedObjective, logPrior);
   if (initial == null) {
     initial = objective.initial();
   }
   double[] weights = minimizer.minimize(semiSupObjective, TOL, initial);
   return objective.to2D(weights);
 }
 /**
  * Trains the linear classifier using Generalized Expectation criteria as described in
  * <tt>Generalized Expectation Criteria for Semi Supervised Learning of Conditional Random
  * Fields</tt>, Mann and McCallum, ACL 2008. The original algorithm is proposed for CRFs but has
  * been adopted to LinearClassifier (which is a simpler special case of a CRF). IMPORTANT: the
  * labeled features that are passed as an argument are assumed to be binary valued, although other
  * features are allowed to be real valued.
  */
 public LinearClassifier<L, F> trainSemiSupGE(
     GeneralDataset<L, F> labeledDataset,
     List<? extends Datum<L, F>> unlabeledDataList,
     List<F> GEFeatures,
     double convexComboCoeff) {
   Minimizer<DiffFunction> minimizer = minimizerCreator.create();
   LogConditionalObjectiveFunction<L, F> objective =
       new LogConditionalObjectiveFunction<L, F>(
           labeledDataset, new LogPrior(LogPrior.LogPriorType.NULL));
   GeneralizedExpectationObjectiveFunction<L, F> geObjective =
       new GeneralizedExpectationObjectiveFunction<L, F>(
           labeledDataset, unlabeledDataList, GEFeatures);
   SemiSupervisedLogConditionalObjectiveFunction semiSupObjective =
       new SemiSupervisedLogConditionalObjectiveFunction(
           objective, geObjective, null, convexComboCoeff);
   double[] initial = objective.initial();
   double[] weights = minimizer.minimize(semiSupObjective, TOL, initial);
   return new LinearClassifier<L, F>(
       objective.to2D(weights), labeledDataset.featureIndex(), labeledDataset.labelIndex());
 }
  public Classifier<L, F> trainClassifier(Iterable<Datum<L, F>> dataIterable) {
    Minimizer<DiffFunction> minimizer = getMinimizer();
    Index<F> featureIndex = Generics.newIndex();
    Index<L> labelIndex = Generics.newIndex();
    for (Datum<L, F> d : dataIterable) {
      labelIndex.add(d.label());
      featureIndex.addAll(d.asFeatures()); // If there are duplicates, it doesn't add them again.
    }
    System.err.println(
        String.format(
            "Training linear classifier with %d features and %d labels",
            featureIndex.size(), labelIndex.size()));

    LogConditionalObjectiveFunction<L, F> objective =
        new LogConditionalObjectiveFunction<L, F>(dataIterable, logPrior, featureIndex, labelIndex);
    objective.setPrior(new LogPrior(LogPrior.LogPriorType.QUADRATIC));

    double[] initial = objective.initial();
    double[] weights = minimizer.minimize(objective, TOL, initial);

    LinearClassifier<L, F> classifier =
        new LinearClassifier<L, F>(objective.to2D(weights), featureIndex, labelIndex);
    return classifier;
  }