clueless-kmean now takes as parameter in which mode to work, and test.sh generate...
[clueless-kmeans.git] / clusterer.cc
index 60cead1..d4a70a6 100644 (file)
@@ -35,8 +35,6 @@ Clusterer::~Clusterer() {
 }
 
 scalar_t Clusterer::distance_to_centroid(scalar_t *x, int k) {
-  // We take the variance into account + the normalization term. This
-  // is between k-mean and EM with a diagonal covariance
   scalar_t dist = 0;
   for(int d = 0; d < _dim; d++) {
     dist += sq(_cluster_means[k][d] - x[d]) / (2 * _cluster_var[k][d]);
@@ -180,6 +178,8 @@ scalar_t Clusterer::uninformative_lp_cluster_association(int nb_points, scalar_t
   // The coefficients for the constraints are passed to the glpk
   // functions with a sparse representation.
 
+  // ** GLPK USES INDEXES STARTING AT 1, NOT 0. **
+
   int nb_coeffs = nb_points * _nb_clusters + nb_points * _nb_clusters;
 
   int *coeff_row = new int[nb_coeffs + 1];
@@ -206,22 +206,25 @@ scalar_t Clusterer::uninformative_lp_cluster_association(int nb_points, scalar_t
 
   glp_add_cols(lp, nb_points * _nb_clusters);
 
+  // The column for gamma[n][k] point 1<=n<=nb_points and cluster
+  // 1<=k<=_nb_clusters is nb_points * (k - 1) + n;
+
   // The constraints (A) will be expressed by putting directly bounds
-  // on the column variables. So we need one row per (B) constraint,
-  // and one per (C) constraint.
+  // on the variables (i.e. one per column). So we need one row per
+  // (B) constraint, and one per (C) constraint.
 
   glp_add_rows(lp, nb_points + _nb_clusters * nb_classes);
 
-  // First, we set the weights for the objective function, and the
-  // constraint on the individual gammas
+  // First, we set the weights for the objective function, and the (A)
+  // constraints on the individual gammas
 
   for(int k = 1; k <= _nb_clusters; k++) {
     for(int n = 1; n <= nb_points; n++) {
       int col = n + nb_points * (k - 1);
 
-      // The LP weight on this association coefficient for the global
-      // loss is the normalized distance of that sample to the
-      // centroid of that cluster
+      // The LP weight on the gammas for the global loss is the
+      // normalized distance of that sample to the centroid of that
+      // cluster
 
       glp_set_obj_coef(lp, col, distance_to_centroid(points[n-1], k-1));
 
@@ -232,17 +235,13 @@ scalar_t Clusterer::uninformative_lp_cluster_association(int nb_points, scalar_t
     }
   }
 
-  // The (B) constraints: for each point, the sum of its association
-  // coefficients is equal to 1.0
+  // The (B) constraints: for each point, the sum of its gamma is
+  // equal to 1.0
 
   for(int n = 1; n <= nb_points; n++) {
     int row = n;
     glp_set_row_bnds(lp, row, GLP_FX, 1.0, 1.0);
-  }
-
-  for(int n = 1; n <= nb_points; n++) {
     for(int k = 1; k <= _nb_clusters; k++) {
-      int row = n;
       coeff_row[n_coeff] = row;
       coeff_col[n_coeff] = nb_points * (k - 1) + n;
       coeff_wgt[n_coeff] = 1.0;
@@ -251,21 +250,14 @@ scalar_t Clusterer::uninformative_lp_cluster_association(int nb_points, scalar_t
   }
 
   // The (C) constraints: For each pair cluster/class, the sum of the
-  // association coefficient to this cluster for this class is equal
-  // to the number of sample of that class, divided by the number of
-  // clusters
+  // gammas for this cluster and this class is equal to the number of
+  // sample of that class, divided by the number of clusters
 
   for(int k = 1; k <= _nb_clusters; k++) {
     for(int c = 1; c <= nb_classes; c++) {
       int row = nb_points + (k - 1) * nb_classes + c;
       scalar_t tau = nb_samples_per_class[c-1] / scalar_t(_nb_clusters);
       glp_set_row_bnds(lp, row, GLP_FX, tau, tau);
-    }
-  }
-
-  for(int k = 1; k <= _nb_clusters; k++) {
-    for(int c = 1; c <= nb_classes; c++) {
-      int row = nb_points + (k - 1) * nb_classes + c;
       for(int n = 1; n <= nb_points; n++) {
         if(labels[n-1] == c - 1) {
           coeff_row[n_coeff] = row;