//Source file: D:\\Projects\\src\\yi\\stat\\em\\ControlledInitMultiGMM.java

package yi.stat.em;

import java.util.*;
import yi.util.data.*;


/**
 * Given a set of image, their labels and their data.  Learn the Gaussian Mixture
 * Model for one particular object, o.  The initial clusters will be generated
 * using images having one object and images having the object to learn and
 * another one object.  For example, if to learn "tree", and the available labels
 * are "grass", "sky" and "tree", then we will contruct these clusters from:
 * images having "grasss", images having "sky", images having "tree", images
 * having "grass" and "tree", images having "sky" and "tree".
 */
public class ControlledInitMultiGMM extends GaussianMixtureModel
{

  /**
   * Given the features and labels of each image, and the object to learn,
   * construct the initial clusters
   * @param feature_map image name as key and a linked list of double[] as value
   * @param cluster_map image name as key and a linked list of object name as value
   * @param objects all the object available
   * @param obj the object to learn
   */
  public ControlledInitMultiGMM(HashMap feature_map, HashMap cluster_map, LinkedList objects, Object obj)
  {

    Collection image_list = feature_map.keySet();

    // for each object
    for (Iterator i = objects.iterator(); i.hasNext(); ) {
      // the current object
      Object obj1 = i.next();
      System.out.println(obj1);
      // save the images having obj1 and the images having both obj1 and obj
      HashSet img_obj1 = new HashSet();
      HashSet img_obj1_obj = new HashSet();
      for (Iterator j = image_list.iterator(); j.hasNext(); ) {
        String img = (String) j.next();
        // get the objects in the image
        HashSet img_objs = new HashSet( (LinkedList) cluster_map.get(img));
        if (img_objs.contains(obj1)) {
          img_obj1.add(img);
          if (img_objs.contains(obj)) {
            img_obj1_obj.add(img);
          }
        }
      }

      // see whether the these two image set are equal
      boolean img_set_equal = (img_obj1.size() == img_obj1_obj.size());
      System.out.println("images having " + obj1 + ": " + img_obj1.size());
      System.out.println("images having both : " + img_obj1_obj.size());

      // construct a clusters using the images having obj1
      GaussianComponent g = (GaussianComponent)createEMComponent();
      for (Iterator j = img_obj1.iterator(); j.hasNext(); ) {
        String img = (String) j.next();
        // add the features
        LinkedList features = (LinkedList) feature_map.get(img);
        // weight of each feature
        double weight = 1.0 / features.size();
        // if this image contains both objects, then each feature vector will
        // contribute to tow clusters
        if (!img_set_equal && img_obj1_obj.contains(img)) {
          weight /= 2;
        }
        System.out.println(img + " f#=" + features.size() + " w=" + weight);
        for (Iterator f = features.iterator(); f.hasNext(); ) {
          double[] fv = (double[]) f.next();
          g.add(fv, weight);
        }
      }
      m_initComponents.put(obj1, g);
      // the weight of this cluster will be doubled if they are equal
      // the weight of images having obj1 uses the weight of images having obj1
      // and obj since the first cluster is fake anyway.
      if (!img_set_equal) {
        m_weights.put(obj1, new Double(img_obj1_obj.size()));
      } else {
        m_weights.put(obj1, new Double(img_obj1_obj.size() * 2));
      }
      System.out.println("cluster weight of " + obj1 + " =" + m_weights.get(obj1));

      // construct a clusters using the images having obj1 and obj
      if (!img_set_equal) {
        GaussianComponent g2 = (GaussianComponent)createEMComponent();
        for (Iterator j = img_obj1_obj.iterator(); j.hasNext(); ) {
          String img = (String) j.next();
          // add the features
          LinkedList features = (LinkedList) feature_map.get(img);
          // weight of each feature.  each feature vector must have
          // contributed to tow clusters
          double weight = 1.0 / features.size() / 2;
          System.out.println(img + " f#=" + features.size() + " w=" + weight);
          for (Iterator f = features.iterator(); f.hasNext(); ) {
            double[] fv = (double[]) f.next();
            g2.add(fv, weight);
          }
        }
        m_initComponents.put(obj1, g2);
        String name = obj1.toString() + "," + obj.toString();
        m_weights.put(name, new Double(img_obj1_obj.size()));
      }
    }


    // save all the feature vectors (from all the images)
    LinkedList all_data = new LinkedList();

    // for each image
    for (Iterator i = feature_map.keySet().iterator(); i.hasNext(); ) {
      String img = (String) i.next();
      HashSet img_objs = new HashSet( (LinkedList) cluster_map.get(img));
      if (img_objs.contains(obj)) {
        Collection feature_list = (Collection) feature_map.get(img);
        all_data.addAll(feature_list);
      }
    }

    m_data = Conversion.to2DDoubleArray(all_data);
    m_numComponents = m_initComponents.size();

  }

}
