package yi.iu.imgdb.learn;

import java.util.*;
import yi.util.io.*;
import yi.stat.em.*;
import yi.stat.nn.*;
import java.io.*;
import yi.util.config.*;
import yi.iu.imgdb.learn.em.*;

/**
 * pipeline EM variant and NN
 */

public class EMVNNAdapter extends GMMNNAdapter {

  public int NUM_COMP_IN_GMM_COMP= 8;
  public double BREAK_T_IN_GMM_COMP = 1e-6;
  public double BREAK_T_IN_OUTER = 1e-5;

  public EMVNNAdapter(ImgDataCenter data_center, LinkedList img_list,
                      LinkedList ft_list, LinkedList obj_list) {
    super(data_center, img_list, ft_list, obj_list);
  }

  public String[] getParameterNames() {
     String[] parameters = new String[] {
         "NUM_COMP_IN_GMM_COMP",
         "BREAK_T_IN_GMM_COMP",
         "BREAK_T_IN_OUTER"
     };
     String[] parent_param = super.getParameterNames();
     return Configuration.combineParameterNames(parameters, parent_param);
  }

  /**
   * Learn the EM Varient-NN models
   * @param data_center
   * @param img_list
   * @param ft_list
   * @param obj_list
   */
  public void learn(ImgDataCenter data_center, LinkedList img_list,
                      LinkedList ft_list, LinkedList obj_list) {

    System.out.println("objects to learn: ");
    OutputResult.print(System.out, m_objectList);

    for (Iterator f = ft_list.iterator(); f.hasNext(); ) {
      Object feature = f.next();
      LinkedList feature_list = new LinkedList();
      feature_list.add(feature);
      GMMMMAdapter gmmmm_adapter = new GMMMMAdapter(data_center, img_list, feature_list, obj_list);
      GMMMixtureModel gmmmm = (GMMMixtureModel)gmmmm_adapter.getMixtureModel();
      HashMap emv_comps = gmmmm.getRstComponentHashMap();

      // group the feature vectors in the positive ones to construct positive model
      double[][] data = data_center.groupFeatureVectors(img_list,
          (String)feature);
      double uniform_dist = yi.stat.StatUtil.getUniformDistributionDensity(data);

      for (Iterator o = emv_comps.keySet().iterator(); o.hasNext(); ) {
        Object object = o.next();
        GaussianMixtureModel gmm = (GaussianMixtureModel)emv_comps.get(object);
        m_gmmModels.put(object, feature, gmm);
        m_gmmUniformDensity.put(object, feature, new Double(uniform_dist));
      }
    }

    // learn the objects models using EM variant
    for (Iterator o = m_objectList.iterator(); o.hasNext(); ) {
      String object = (String) o.next();
      if (object.compareToIgnoreCase("bg") == 0) continue;

      System.out.println();
      System.out.println("learning on \"" + object + "\"" + "\n");

      // seperate training set and verifying set
      LinkedList posTrainImgs = new LinkedList();
      LinkedList negTrainImgs = new LinkedList();
      seperatePosImgsFromNegImgs(img_list, object, posTrainImgs, negTrainImgs);

      constructAbstractRegionModel(object, img_list);
      double[][] pos_scores_concat = getFeatureVectors(posTrainImgs, object, null);
      double[][] neg_scores_concat = getFeatureVectors(negTrainImgs, object, null);

      if (OUTPUT_NN_DATA) {
        System.out.println("score on pos writen to " + object + ".pos.dat");
        yi.util.io.OutputResult.print(object.toString() + ".pos.dat",
                                      pos_scores_concat,
                                      pos_scores_concat[0].length,
                                      pos_scores_concat.length);
        System.out.println("score on neg writen to " + object + ".neg.dat");
        yi.util.io.OutputResult.print(object.toString() + ".neg.dat",
                                      neg_scores_concat,
                                      pos_scores_concat[0].length,
                                      neg_scores_concat.length);
      }
      if (OUTPUT_NN_FOR_SVM) {
        PrintStream out = OutputResult.getPrintStream(object + ".train");
        if (out != null) {
          for (int i = 0; i < pos_scores_concat.length; i++) {
            out.print("+1");
            for (int j = 0; j < pos_scores_concat[i].length; j++) {
              out.print(" " + (j + 1) + ":" + pos_scores_concat[i][j]);
            }
            out.println();
          }
          for (int i = 0; i < neg_scores_concat.length; i++) {
            out.print("-1");
            for (int j = 0; j < neg_scores_concat[i].length; j++) {
              out.print(" " + (j + 1) + ":" + neg_scores_concat[i][j]);
            }
            out.println();
          }
          out.close();
        }
      }

      // for experiemnt
      LinkedList test_img = StatModelFoldExperiment.testing;
      double[][] pos_test_scores = null;
      double[][] neg_test_scores = null;
      if (test_img != null) {
        constructAbstractRegionFeatures(object, test_img);
        LinkedList posTestImgs = new LinkedList();
        LinkedList negTestImgs = new LinkedList();
        seperatePosImgsFromNegImgs(test_img, object, posTestImgs, negTestImgs);
        pos_test_scores = getFeatureVectors(posTestImgs, object, null);
        neg_test_scores = getFeatureVectors(negTestImgs, object, null);
      }

      NeuralNet nn = trainNN(pos_scores_concat, neg_scores_concat, pos_test_scores, neg_test_scores);
      m_nnModels.put(object, nn);
      m_nnVerifyErrors.putScore(object, nn.getVerifyError());

      if (FIND_THRESHOLD) {
        m_thresholds.put(object, new Double(m_foundThreshold));
      }

    } // end loop of objects
  }

}