}//getOrdDisplayDataAsync 
 private List<DisplayItems> getClusterSetData(CategClusterSet oSet)
 {
     List<DisplayItems> oRet = new List<DisplayItems>();
     if (oSet != null)
     {
         double somme = oSet.Variance;
         foreach (var c in oSet.Clusters)
         {
             DisplayItems line = new DisplayItems();
             line.Add(new DisplayItem(c.Index));
             line.Add(new DisplayItem(c.Name));
             line.Add(new DisplayItem(c.Count));
             double v = c.Variance;
             line.Add(new DisplayItem(v));
             if (somme > 0.0)
             {
                 line.Add(new DisplayItem(v / somme));
             }
             else
             {
                 line.Add(new DisplayItem());
             }
             double[] cx = c.Center;
             int nc = cx.Length;
             for (int i = 0; i < nc; ++i)
             {
                 line.Add(new DisplayItem(cx[i]));
             }// i
             oRet.Add(line);
         }// v
     }// oSet
     return oRet;
 }// getClusterSetData
 }// updatePlots
 public Task<Tuple<CategClusterSet[], int[], PlotModel, DisplayItemsArray>> UpdateClustersAsync(int nbClasses, int nbIterations,
     CancellationToken cancellationToken, IProgress<Tuple<int, CategClusterSet>> progress)
 {
     OrdModelView model = this;
     int nClusters = this.ClustersCount;
     var ltype = this.LinkType;
     CategClusterSet[] oSets = new CategClusterSet[3];
     int[] pRows = null;
     DisplayItemsArray oDisp = null;
     PlotModel pPlot = null;
     return Task.Run<Tuple<CategClusterSet[], int[], PlotModel, DisplayItemsArray>>(() =>
     {
         Parallel.Invoke(() =>
         {
             oSets[0] = CategClusterSet.Clusterize(model, nClusters, nbIterations, cancellationToken, progress);
         }, () =>
         {
             var p = CategClusterSet.KMeans(model, nClusters, nbClasses, cancellationToken, progress);
             oSets[1] = p;
         }, () =>
         {
             oSets[2] = TreeItem.Hierar(model, nClusters, ltype, cancellationToken);
         }, () =>
         {
             var tt = CreateArrangeData(nbIterations, cancellationToken);
             pRows = tt.Item1;
             oDisp = tt.Item2;
             pPlot = tt.Item3;
         });
         return new Tuple<CategClusterSet[], int[], PlotModel, DisplayItemsArray>(oSets, pRows, pPlot, oDisp);
     }, cancellationToken);
 }// UpdateClustersAsync
        }//CreateCombinedShowPlotAsync 
        private PlotModel createShowPlot(String title, String prefix, CategClusterSet oSet)
        {
            PlotModel model = null;
            try
            {
                VariableDesc oVarY = this.CurrentYVariable;
                VariableDesc oVarX = this.CurrentXVariable;
                if ((oVarX == null) || (oVarY == null))
                {
                    return model;
                }
                if ((!oVarX.IsNumVar) || (!oVarY.IsNumVar) && (oVarX.Id == oVarY.Id))
                {
                    return model;
                }
                var allIndivs = this.Individus;
                Dictionary<int, String> categDict = new Dictionary<int, string>();
                List<Tuple<double, double, Cluster>> oList = StatModelViewBase.GetClustersCenters(oVarX, oVarY, oSet);
                if ((oSet != null) && oSet.IsValid)
                {
                    var clusters = oSet.Clusters;
                    foreach (var cluster in clusters)
                    {
                        var col = cluster.Elements;
                        String key = cluster.Name;
                        if (String.IsNullOrEmpty(key))
                        {
                            key = String.Format(prefix, cluster.Index + 1);
                        }
                        foreach (var ind in col)
                        {
                            int index = ind.IndivIndex;
                            if (index >= 0)
                            {
                                categDict[index] = key;
                            }
                        }// col
                    }// cluster
                }
                else
                {
                    String sval = DEFAULT_SERIE_NAME;
                    foreach (var ind in allIndivs)
                    {
                        int index = ind.IndivIndex;
                        categDict[index] = sval;
                    }// ind
                }
                bool bPoints = this.HasPoints;
                bool bLabels = this.HasLabels;
                bool bImages = this.HasImages;
                bool bZeroCrossing = false;
                bool bLeastSquares = false;
                var imagesDict = this.ImagesDictionary;
                model = CreateCartesianPlot(title, allIndivs, oVarX, oVarY, imagesDict, categDict, bPoints, bLabels, bImages, bZeroCrossing,
                    bLeastSquares, oList);
                if (model == null)
                {
                    return model;
                }

            }// try
            catch (Exception /* ex */)
            {
                model = null;
            }
            return model;
        }// createShowPlot
 public static List<Tuple<double[], Cluster>> GetClustersCenters(IEnumerable<VariableDesc> oVars, CategClusterSet oSet)
 {
     List<Tuple<double[], Cluster>> oList = new List<Tuple<double[], Cluster>>();
     if ((oVars == null) || (oSet == null))
     {
         return oList;
     }
     if (!oSet.IsValid)
     {
         return oList;
     }
     var oAr = oVars.ToArray();
     int n = oAr.Length;
     if (n < 1)
     {
         return oList;
     }
     var clusters = oSet.Clusters;
     foreach (var cluster in clusters)
     {
         double[] dd = new double[n];
         int[] count = new int[n];
         for (int i = 0; i < n; ++i)
         {
             dd[i] = 0.0;
             count[i] = 0;
         }// i
         var elements = cluster.Elements;
         foreach (var ind in elements)
         {
             var vals = ind.Values;
             for (int i = 0; i < n; ++i)
             {
                 int nx = (oAr[i]).Id;
                 var q = from x in vals where x.VariableId == nx select x;
                 if (q.Count() > 0)
                 {
                     double xx = q.First().DoubleValue;
                     count[i] = count[i] + 1;
                     dd[i] = dd[i] + xx;
                 }
             }// i
         }// ind
         for (int i = 0; i < n; ++i)
         {
             int nc = count[i];
             if (nc > 0)
             {
                 dd[i] = dd[i] / nc;
             }
         }// i
        oList.Add(new Tuple<double[],Cluster>(dd,cluster));
     }// cluster
     return oList;
 }
 public static List<Tuple<double, double, Cluster>> GetClustersCenters(VariableDesc oVarX, VariableDesc oVarY, CategClusterSet oSet)
 {
     List<Tuple<double,double, Cluster>> oList = new List<Tuple<double, double,Cluster>>();
     if ((oVarX == null) || (oVarY == null) || (oSet == null))
     {
         return oList;
     }
     var col = new VariableDesc[] { oVarX, oVarY};
     var tt = GetClustersCenters(col, oSet);
     if (tt != null)
     {
         foreach (var t in tt)
         {
             double[] dd = t.Item1;
             if ((dd != null) && (dd.Length > 1))
             {
                 double x = dd[0];
                 double y = dd[1];
                 Cluster c = t.Item2;
                 oList.Add(new Tuple<double, double, Cluster>(x, y, c));
             }
         }// t
     }// tt
     return oList;
 }
 public object Clone()
 {
     CategClusterSet pRet = new CategClusterSet();
     pRet.m_model = this.m_model;
     pRet.m_nvars = this.m_nvars;
     pRet.m_currentcrit = this.m_currentcrit;
     pRet.m_globalcrit = this.m_globalcrit;
     pRet.m_indivs = this.m_indivs;
     if (this.m_clusters != null)
     {
         pRet.m_clusters = new List<Cluster>();
         foreach (var x in this.m_clusters)
         {
             pRet.m_clusters.Add((Cluster)x.Clone());
         }
     }
     return pRet;
 }
 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;
 }
 public static Task<CategClusterSet> KMeansAsync(OrdModelView model, int nClusters, int nbIterations, CancellationToken cancellationToken,
     IProgress<Tuple<int, CategClusterSet>> progress)
 {
     return Task.Run<CategClusterSet>(() =>
     {
         CategClusterSet oBest = new CategClusterSet(model);
         oBest.initializeCiusters(nClusters);
         for (int i = 0; i < nbIterations; ++i)
         {
             CategClusterSet pp = new CategClusterSet();
             pp.m_model = oBest.m_model;
             pp.m_nvars = oBest.m_nvars;
             pp.m_indivs = oBest.m_indivs;
             List<Cluster> oList = new List<Cluster>();
             foreach (var c in oBest.Clusters)
             {
                 Cluster cc = new Cluster();
                 cc.Index = c.Index;
                 cc.Name = c.Name;
                 cc.Center = (double[])c.Center.Clone();
                 oList.Add(cc);
             }// c
             pp.Clusters = oList;
             int f = (int)(((double)i / (double)nbIterations) * 100.0 + 0.5);
             if (cancellationToken.IsCancellationRequested)
             {
                 break;
             }
             pp.kmeansstep(cancellationToken);
             if (cancellationToken.IsCancellationRequested)
             {
                 break;
             }
             if (oBest.Equals(pp))
             {
                 break;
             }
             oBest = pp;
             if (progress != null)
             {
                 progress.Report(new Tuple<int, CategClusterSet>(f, pp));
             }
         }// i
         return oBest;
     }, cancellationToken);
 }