package de.jungblut.ner;

import com.google.common.base.Preconditions;

import de.jungblut.classification.AbstractClassifier;
import de.jungblut.math.DoubleMatrix;
import de.jungblut.math.DoubleVector;
import de.jungblut.math.ViterbiUtils;
import de.jungblut.math.dense.DenseDoubleMatrix;
import de.jungblut.math.dense.DenseDoubleVector;
import de.jungblut.math.minimize.DenseMatrixFolder;
import de.jungblut.math.minimize.Minimizer;
import de.jungblut.math.sparse.SparseDoubleRowMatrix;

/**
 * Maximum entropy markov model for named entity recognition (classifying labels
 * in sequence learning).
 * 
 * @author thomas.jungblut
 * 
 */
public final class MaxEntMarkovModel extends AbstractClassifier {

  private final Minimizer minimizer;
  private final boolean verbose;
  private final int numIterations;
  private DenseDoubleMatrix theta;
  private int classes;

  public MaxEntMarkovModel(Minimizer minimizer, int numIterations,
      boolean verbose) {
    this.minimizer = minimizer;
    this.numIterations = numIterations;
    this.verbose = verbose;
  }

  @Override
  public void train(DoubleVector[] features, DenseDoubleVector[] outcome) {
    Preconditions
        .checkArgument(
            features.length == outcome.length && features.length > 0,
            "There wasn't at least a single featurevector, or the two array didn't match in size.");
    this.classes = outcome[0].getDimension() == 1 ? 2 : outcome[0]
        .getDimension();
    DoubleMatrix mat = null;
    if (features[0].isSparse()) {
      mat = new SparseDoubleRowMatrix(features);
    } else {
      mat = new DenseDoubleMatrix(features);
    }
    ConditionalLikelihoodCostFunction func = new ConditionalLikelihoodCostFunction(
        mat, new DenseDoubleMatrix(outcome));
    DenseDoubleVector vx = new DenseDoubleVector(mat.getColumnCount() * classes);
    DoubleVector input = minimizer.minimize(func, vx, numIterations, verbose);
    theta = DenseMatrixFolder.unfoldMatrix(input, classes,
        (int) (input.getLength() / (double) classes));
  }

  /**
   * Customized prediction method, WARNING the feature vector needs a special
   * data layout to work correctly:<br/>
   * TODO
   * 
   */
  @Override
  public DoubleVector predict(DoubleVector features) {
    return null;
  }

  // matrix prediction
  public DoubleMatrix predict(DoubleMatrix features,
      DoubleMatrix featuresPerState) {
    return ViterbiUtils.decode(theta, features, featuresPerState, classes);
  }

}

@@ -69,62 +69,8 @@
 s;%0A%0A
-import de.jungblut.classification.AbstractClassifier;%0A
 impo
@@ -95,32 +95,32 @@
 h.DoubleMatrix;%0A
+
 import de.jungbl
@@ -619,35 +619,8 @@
 del 
-extends AbstractClassifier 
 %7B%0A%0A 
@@ -979,28 +979,16 @@
 e;%0A  %7D%0A%0A
-  @Override%0A
   public
@@ -1882,24 +1882,24 @@
 t, classes,%0A
+
         (int
@@ -1950,244 +1950,8 @@
  %7D%0A%0A
-  /**%0A   * Customized prediction method, WARNING the feature vector needs a special%0A   * data layout to work correctly:%3Cbr/%3E%0A   * TODO%0A   * %0A   */%0A  @Override%0A  public DoubleVector predict(DoubleVector features) %7B%0A    return null;%0A  %7D%0A%0A
   //

remove the classifier interface because it will get to ugly..