private bool initializeCiusters(int nbClusters)
 {
     bool oRet = false;
     var inds = this.Indivs;
     if ((inds == null) || (nbClusters < 2))
     {
         return oRet;
     }
     if (inds.Count < nbClusters)
     {
         return oRet;
     }
     double[] dd = inds.First().DoubleData;
     int nv = dd.Length;
     if (nv < 1)
     {
         return oRet;
     }
     double[,] dLimits = new double[3, nv];
     for (int i = 0; i < nv; ++i)
     {
         double x = dd[i];
         dLimits[0, i] = x;
         dLimits[1, i] = x;
         dLimits[2, i] = 0.0;
     }// i
     int nc = 0;
     foreach (var ind in inds)
     {
         double[] ddx = ind.DoubleData;
         if (ddx.Length < nv)
         {
             continue;
         }
         ++nc;
         for (int i = 0; i < nv; ++i)
         {
             double x = ddx[i];
             if (x < dLimits[0, i])
             {
                 dLimits[0, i] = x;
             }
             else if (x > dLimits[1, i])
             {
                 dLimits[1, i] = x;
             }
         }// i
     }// ind
     if (nc < 1)
     {
         return oRet;
     }
     for (int i = 0; i < nv; ++i)
     {
         double x1 = dLimits[0, i];
         double x2 = dLimits[1, i];
         double step = (x2 - x1) / (nbClusters + 2);
         if (step <= 0.0)
         {
             return oRet;
         }
         dLimits[2, i] = step;
     }// i
     Cluster[] cc = new Cluster[nbClusters];
     for (int i = 0; i < nbClusters; ++i)
     {
         double[] xc = new double[nv];
         for (int j = 0; j < nv; ++j)
         {
             xc[j] = dLimits[0, j] + (i + 1) * dLimits[2, j];
         }// j
         Cluster c = new Cluster();
         c.Index = i;
         c.Name = String.Format("KM{0}", i + 1);
         c.Center = xc;
         cc[i] = c;
     }// i
     this.m_clusters = cc.ToList();
     return true;
 }
 public static CategClusterSet ProcessAsync(OrdModelView model, int nClusters, CancellationToken cancellationToken)
 {
     if ((model == null) || (nClusters < 2))
     {
         return null;
     }
     if (cancellationToken.IsCancellationRequested)
     {
         return null;
     }
     var rd = new Random();
     CategClusterSet oRet = new CategClusterSet(model);
     Cluster[] cc = new Cluster[nClusters];
     IndivData[] inds = oRet.Indivs.ToArray();
     int nMax = inds.Length;
     if (nMax < nClusters)
     {
         return null;
     }
     HashSet<int> oCur = new HashSet<int>();
     for (int i = 0; i < nClusters; ++i)
     {
         int nx = rd.Next(0, nMax);
         while (nx >= nMax)
         {
             nx = rd.Next(nMax);
         }
         IndivData indiv = inds[nx];
         int index = indiv.IndivIndex;
         while (oCur.Contains(index))
         {
             nx = rd.Next(0, nMax);
             while (nx >= nMax)
             {
                 nx = rd.Next(0, nMax);
             }
             indiv = inds[nx];
             index = indiv.IndivIndex;
         }
         oCur.Add(index);
         var xc = new Cluster(indiv, ClassificationType.Utility);
         xc.Name = String.Format("CU{0}", i + 1);
         xc.Index = i;
         cc[i] = xc;
     }// i
     oRet.Clusters = cc.ToList();
     double xx = oRet.compute_global_crit(cancellationToken);
     oRet.GlobalCrit = xx;
     if (cancellationToken.IsCancellationRequested)
     {
         return null;
     }
     foreach (var ind in inds)
     {
         if (cancellationToken.IsCancellationRequested)
         {
             return null;
         }
         if (!oCur.Contains(ind.IndivIndex))
         {
             if (!oRet.processOne(ind, cancellationToken))
             {
                 return null;
             }
         }
     }// inds
     return oRet;
 }