ROOT logo
/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

// Implemenatation of the K-Means Clustering Algorithm
// See http://en.wikipedia.org/wiki/K-means_clustering and references therein.
//
// This particular implementation is the so called Soft K-means algorithm.
// It has been modified to work on the cylindrical topology in eta-phi space.
//
// Author: Andreas Morsch (CERN)
// andreas.morsch@cern.ch
 
#include "AliKMeansClustering.h"
#include <TMath.h>
#include <TRandom.h>
#include <TH1F.h>

ClassImp(AliKMeansClustering)

Double_t AliKMeansClustering::fBeta = 10.;

 
Int_t AliKMeansClustering::SoftKMeans(Int_t k, Int_t n, const Double_t* x, const Double_t* y, Double_t* mx, Double_t* my , Double_t* rk )
{
    //
    // The soft K-means algorithm
    //
    Int_t i,j;
    //
    // (1) Initialisation of the k means

    for (i = 0; i < k; i++) {
	mx[i] = 2. * TMath::Pi() * gRandom->Rndm();
	my[i] = -1. + 2. * gRandom->Rndm();
    }

    //
    // (2a) The responsibilities
    Double_t** r = new Double_t*[n]; // responsibilities
    for (j = 0; j < n; j++) {r[j] = new Double_t[k];}
    //
    // (2b) Normalisation
    Double_t* nr   = new Double_t[n];
    // (3) Iterations
    Int_t nit = 0;
    
    while(1) {
	nit++;
      //
      // Assignment step
      //
      for (j = 0; j < n; j++) {
	nr[j] = 0.;
	for (i = 0; i < k; i++) {
	  r[j][i] = TMath::Exp(- fBeta * d(mx[i], my[i], x[j], y[j]));
	  nr[j] += r[j][i];
	} // mean i
      } // data point j
	
      for (j = 0; j < n; j++) {
	for (i = 0; i < k; i++) {
	  r[j][i] /=  nr[j];
	} // mean i
      } // data point j
      
	//
	// Update step
      Double_t di = 0;
      
      for (i = 0; i < k; i++) {
	  Double_t oldx = mx[i];
	  Double_t oldy = my[i];
	  
	  mx[i] = x[0];
	  my[i] = y[0];
	  rk[i] = r[0][i];
	
	for (j = 1; j < n; j++) {
	    Double_t xx =  x[j];
//
// Here we have to take into acount the cylinder topology where phi is defined mod 2xpi
// If two coordinates are separated by more than pi in phi one has to be shifted by +/- 2 pi

	    Double_t dx = mx[i] - x[j];
	    if (dx >  TMath::Pi()) xx += 2. * TMath::Pi();
	    if (dx < -TMath::Pi()) xx -= 2. * TMath::Pi();
	    mx[i] = mx[i] * rk[i] + r[j][i] * xx;
	    my[i] = my[i] * rk[i] + r[j][i] * y[j];
	    rk[i] += r[j][i];
	    mx[i] /= rk[i];
	    my[i] /= rk[i];	    
	    if (mx[i] > 2. * TMath::Pi()) mx[i] -= 2. * TMath::Pi();
	    if (mx[i] < 0.              ) mx[i] += 2. * TMath::Pi();
	} // Data
	di += d(mx[i], my[i], oldx, oldy);
      } // means 
	//
	// ending condition
      if (di < 1.e-8 || nit > 1000) break;
    } // while

// Clean-up    
    delete[] nr;
    for (j = 0; j < n; j++) delete[] r[j];
    delete[] r;
// 
    return (nit < 1000);
    
}

Int_t AliKMeansClustering::SoftKMeans2(Int_t k, Int_t n, Double_t* x, Double_t* y, Double_t* mx, Double_t* my , Double_t* sigma2, Double_t* rk )
{
    //
    // The soft K-means algorithm
    //
    Int_t i,j;
    //
    // (1) Initialisation of the k means using k-means++ recipe
    // 
     OptimalInit(k, n, x, y, mx, my);
    //
    // (2a) The responsibilities
    Double_t** r = new Double_t*[n]; // responsibilities
    for (j = 0; j < n; j++) {r[j] = new Double_t[k];}
    //
    // (2b) Normalisation
    Double_t* nr = new Double_t[n];
    //
    // (2c) Weights 
    Double_t* pi = new Double_t[k];
    //
    //
    // (2d) Initialise the responsibilties and weights
    for (j = 0; j < n; j++) {
      nr[j] = 0.;
      for (i = 0; i < k; i++) {
	r[j][i] = TMath::Exp(- fBeta * d(mx[i], my[i], x[j], y[j]));
	nr[j] += r[j][i];
      } // mean i
    } // data point j
    
    for (i = 0; i < k; i++) {
      rk[i]    = 0.;
      sigma2[i] = 1./fBeta;
 
      for (j = 0; j < n; j++) {
	r[j][i] /=  nr[j];
	rk[i] += r[j][i];
      } // mean i
      pi[i] = rk[i] / Double_t(n);
    } // data point j
    // (3) Iterations
    Int_t nit = 0;

    while(1) {
	nit++;
      //
      // Assignment step
      //
      for (j = 0; j < n; j++) {
	nr[j] = 0.;
	for (i = 0; i < k; i++) {
	  r[j][i] = pi[i] * TMath::Exp(- d(mx[i], my[i], x[j], y[j]) / sigma2[i] ) 
	    / (2. * sigma2[i] * TMath::Pi() * TMath::Pi());
	  nr[j] += r[j][i];
	} // mean i
      } // data point j
	
      for (i = 0; i < k; i++) {
	for (j = 0; j < n; j++) {
	  r[j][i] /=  nr[j];
	} // mean i
      } // data point j
      
	//
	// Update step
      Double_t di = 0;
      
      for (i = 0; i < k; i++) {
	  Double_t oldx = mx[i];
	  Double_t oldy = my[i];
	  
	  mx[i] = x[0];
	  my[i] = y[0];
	  rk[i] = r[0][i];
	for (j = 1; j < n; j++) {
	    Double_t xx =  x[j];
//
// Here we have to take into acount the cylinder topology where phi is defined mod 2xpi
// If two coordinates are separated by more than pi in phi one has to be shifted by +/- 2 pi

	    Double_t dx = mx[i] - x[j];
	    if (dx >  TMath::Pi()) xx += 2. * TMath::Pi();
	    if (dx < -TMath::Pi()) xx -= 2. * TMath::Pi();
	    if (r[j][i] > 1.e-15) {
	      mx[i] = mx[i] * rk[i] + r[j][i] * xx;
	      my[i] = my[i] * rk[i] + r[j][i] * y[j];
	      rk[i] += r[j][i];
	      mx[i] /= rk[i];
	      my[i] /= rk[i];	
	    }    
	    if (mx[i] > 2. * TMath::Pi()) mx[i] -= 2. * TMath::Pi();
	    if (mx[i] < 0.              ) mx[i] += 2. * TMath::Pi();
	} // Data
	di += d(mx[i], my[i], oldx, oldy);

      } // means 
      //
      // Sigma
      for (i = 0; i < k; i++) {
	sigma2[i] = 0.;
	for (j = 0; j < n; j++) {
	  sigma2[i] += r[j][i] * d(mx[i], my[i], x[j], y[j]);
	} // Data
	sigma2[i] /= rk[i];
	if (sigma2[i] < 0.0025) sigma2[i] = 0.0025;
      } // Clusters    
      //
      // Fractions
      for (i = 0; i < k; i++) pi[i] = rk[i] / Double_t(n);
      //
// ending condition
      if (di < 1.e-8 || nit > 1000) break;
    } // while

// Clean-up    
    delete[] nr;
    delete[] pi;
    for (j = 0; j < n; j++) delete[] r[j];
    delete[] r;
// 
    return (nit < 1000);
}

Int_t AliKMeansClustering::SoftKMeans3(Int_t k, Int_t n, Double_t* x, Double_t* y, Double_t* mx, Double_t* my , 
				       Double_t* sigmax2, Double_t* sigmay2, Double_t* rk )
{
    //
    // The soft K-means algorithm
    //
    Int_t i,j;
    //
    // (1) Initialisation of the k means using k-means++ recipe
    // 
     OptimalInit(k, n, x, y, mx, my);
    //
    // (2a) The responsibilities
    Double_t** r = new Double_t*[n]; // responsibilities
    for (j = 0; j < n; j++) {r[j] = new Double_t[k];}
    //
    // (2b) Normalisation
    Double_t* nr = new Double_t[n];
    //
    // (2c) Weights 
    Double_t* pi = new Double_t[k];
    //
    //
    // (2d) Initialise the responsibilties and weights
    for (j = 0; j < n; j++) {
      nr[j] = 0.;
      for (i = 0; i < k; i++) {

	r[j][i] = TMath::Exp(- fBeta * d(mx[i], my[i], x[j], y[j]));
	nr[j] += r[j][i];
      } // mean i
    } // data point j
    
    for (i = 0; i < k; i++) {
      rk[i]    = 0.;
      sigmax2[i] = 1./fBeta;
      sigmay2[i] = 1./fBeta;
 
      for (j = 0; j < n; j++) {
	r[j][i] /=  nr[j];
	rk[i] += r[j][i];
      } // mean i
      pi[i] = rk[i] / Double_t(n);
    } // data point j
    // (3) Iterations
    Int_t nit = 0;

    while(1) {
	nit++;
      //
      // Assignment step
      //
      for (j = 0; j < n; j++) {
	nr[j] = 0.;
	for (i = 0; i < k; i++) {

	  Double_t dx = TMath::Abs(mx[i]-x[j]);
	  if (dx > TMath::Pi()) dx = 2. * TMath::Pi() - dx;
	  Double_t dy = TMath::Abs(my[i]-y[j]);
	  r[j][i] = pi[i] * TMath::Exp(-0.5 *  (dx * dx / sigmax2[i] + dy * dy / sigmay2[i])) 
	    / (2. * TMath::Sqrt(sigmax2[i] * sigmay2[i]) * TMath::Pi() * TMath::Pi());
	  nr[j] += r[j][i];
	} // mean i
      } // data point j
	
      for (i = 0; i < k; i++) {
	for (j = 0; j < n; j++) {
	  r[j][i] /=  nr[j];
	} // mean i
      } // data point j
      
	//
	// Update step
      Double_t di = 0;
      
      for (i = 0; i < k; i++) {
	  Double_t oldx = mx[i];
	  Double_t oldy = my[i];
	  
	  mx[i] = x[0];
	  my[i] = y[0];
	  rk[i] = r[0][i];
	for (j = 1; j < n; j++) {
	    Double_t xx =  x[j];
//
// Here we have to take into acount the cylinder topology where phi is defined mod 2xpi
// If two coordinates are separated by more than pi in phi one has to be shifted by +/- 2 pi

	    Double_t dx = mx[i] - x[j];
	    if (dx >  TMath::Pi()) xx += 2. * TMath::Pi();
	    if (dx < -TMath::Pi()) xx -= 2. * TMath::Pi();
	    if (r[j][i] > 1.e-15) {
	      mx[i] = mx[i] * rk[i] + r[j][i] * xx;
	      my[i] = my[i] * rk[i] + r[j][i] * y[j];
	      rk[i] += r[j][i];
	      mx[i] /= rk[i];
	      my[i] /= rk[i];	
	    }    
	    if (mx[i] > 2. * TMath::Pi()) mx[i] -= 2. * TMath::Pi();
	    if (mx[i] < 0.              ) mx[i] += 2. * TMath::Pi();
	} // Data
	di += d(mx[i], my[i], oldx, oldy);

      } // means 
      //
      // Sigma
      for (i = 0; i < k; i++) {
	sigmax2[i] = 0.;
	sigmay2[i] = 0.;

	for (j = 0; j < n; j++) {
	  Double_t dx = TMath::Abs(mx[i]-x[j]);
	  if (dx > TMath::Pi()) dx = 2. * TMath::Pi() - dx;
	  Double_t dy = TMath::Abs(my[i]-y[j]);
	  sigmax2[i] += r[j][i] * dx * dx;
	  sigmay2[i] += r[j][i] * dy * dy;
	} // Data
	sigmax2[i] /= rk[i];
	sigmay2[i] /= rk[i];
	if (sigmax2[i] < 0.0025) sigmax2[i] = 0.0025;
	if (sigmay2[i] < 0.0025) sigmay2[i] = 0.0025;
      } // Clusters    
      //
      // Fractions
      for (i = 0; i < k; i++) pi[i] = rk[i] / Double_t(n);
      //
// ending condition
      if (di < 1.e-8 || nit > 1000) break;
    } // while

// Clean-up    
    delete[] nr;
    delete[] pi;
    for (j = 0; j < n; j++) delete[] r[j];
    delete[] r;
// 
    return (nit < 1000);
}

Double_t AliKMeansClustering::d(Double_t mx, Double_t my, Double_t x, Double_t y)
{
    //
    // Distance definition 
    // Quasi - Euclidian on the eta-phi cylinder
    
    Double_t dx = TMath::Abs(mx-x);
    if (dx > TMath::Pi()) dx = 2. * TMath::Pi() - dx;
    
    return (0.5*(dx * dx + (my - y) * (my - y)));
}



void AliKMeansClustering::OptimalInit(Int_t k, Int_t n, const Double_t* x, const Double_t* y, Double_t* mx, Double_t* my)
{
  //  
  // Optimal initialisation using the k-means++ algorithm
  // http://en.wikipedia.org/wiki/K-means%2B%2B
  //
  // k-means++ is an algorithm for choosing the initial values for k-means clustering in statistics and machine learning. 
  // It was proposed in 2007 by David Arthur and Sergei Vassilvitskii as an approximation algorithm for the NP-hard k-means problem---
  // a way of avoiding the sometimes poor clusterings found by the standard k-means algorithm.
  //
  //
  TH1F d2("d2", "", n, -0.5, Float_t(n)-0.5);
  d2.Reset();

  // (1) Chose first center as a random point among the input data.
  Int_t ir = Int_t(Float_t(n) * gRandom->Rndm());
  mx[0] = x[ir];
  my[0] = y[ir];

  // (2) Iterate
  Int_t icl = 1;
  while(icl < k)
    {
      // find min distance to existing clusters
      for (Int_t j = 0; j < n; j++) {
	Double_t dmin = 1.e10;
	for (Int_t i = 0; i < icl; i++) {
	  Double_t dij = d(mx[i], my[i], x[j], y[j]);
	  if (dij < dmin) dmin = dij;
	} // clusters
	d2.Fill(Float_t(j), dmin);
      } // data points
      // select a new cluster from data points with probability ~d2
      ir = Int_t(d2.GetRandom() + 0.5);
      mx[icl] = x[ir];
      my[icl] = y[ir];
      icl++;
    } // icl
}


ClassImp(AliKMeansResult)


    
AliKMeansResult::AliKMeansResult(Int_t k):
    TObject(),
    fK(k),
    fMx    (new Double_t[k]),
    fMy    (new Double_t[k]),
    fSigma2(new Double_t[k]),
    fRk    (new Double_t[k]),
    fTarget(new Double_t[k]),
    fInd   (new Int_t[k])
{
// Constructor
}

AliKMeansResult::AliKMeansResult(const AliKMeansResult &res):
  TObject(res),
  fK(res.GetK()),
  fMx(new Double_t[res.GetK()]),
  fMy(new Double_t[res.GetK()]),
  fSigma2(new Double_t[res.GetK()]),
  fRk(new Double_t[res.GetK()]),
  fTarget(new Double_t[res.GetK()]),
  fInd(new Int_t[res.GetK()])
{
  // Copy constructor
  for (Int_t i = 0; i <fK; i++) {
    fMx[i]     = (res.GetMx())    [i];
    fMy[i]     = (res.GetMy())    [i];
    fSigma2[i] = (res.GetSigma2())[i];
    fRk[i]     = (res.GetRk())    [i];
    fTarget[i] = (res.GetTarget())[i];
    fInd[i]    = (res.GetInd())   [i];
  }
}

AliKMeansResult& AliKMeansResult::operator=(const AliKMeansResult& res)
{
  //
  // Assignment operator
  if (this != &res) {
    TObject::operator=(res);
    if (fK != res.fK) {
	delete [] fMx;
	delete [] fMy;
	delete [] fSigma2;
	delete [] fRk;
	delete [] fTarget;
	delete [] fInd;
	fK = res.fK;
	fMx     = new Double_t[fK];
	fMy     = new Double_t[fK];
	fSigma2 = new Double_t[fK];
	fRk     = new Double_t[fK];
	fTarget = new Double_t[fK];
	fInd    = new    Int_t[fK];
    }
    
    fK = res.fK;
    memcpy(fMx,     res.fMx,     fK*sizeof(Double_t));
    memcpy(fMy,     res.fMy,     fK*sizeof(Double_t));
    memcpy(fSigma2, res.fSigma2, fK*sizeof(Double_t));
    memcpy(fRk,     res.fRk,     fK*sizeof(Double_t));
    memcpy(fTarget, res.fTarget, fK*sizeof(Double_t));
    memcpy(fInd,    res.fInd,    fK*sizeof(Int_t));
  }
  return *this;
}


AliKMeansResult::~AliKMeansResult()
{
// Destructor
    delete[] fMx;
    delete[] fMy;
    delete[] fSigma2;
    delete[] fRk;
    delete[] fInd;
    delete[] fTarget;
}

void AliKMeansResult::Sort()
{
  // Build target array and sort
  // Sort clusters
  for (Int_t i = 0; i < fK; i++) {
    if (fRk[i] > 2.9) {
      fTarget[i] = fRk[i] / fSigma2[i];
    }
    else fTarget[i] = 0.;
  }
    
  TMath::Sort(fK, fTarget, fInd);
}

void AliKMeansResult::Sort(Int_t n, const Double_t* x, const Double_t* y)
{
  // Build target array and sort
  for (Int_t i = 0; i < fK; i++)
    {
      Int_t nc = 0;
      for (Int_t j = 0; j < n; j++)
	{
	  if (2. * AliKMeansClustering::d(fMx[i], fMy[i], x[j], y[j])  <  2.28 * fSigma2[i]) nc++;
	}

      if (nc > 2) {
	fTarget[i] = Double_t(nc) / (2.28 * fSigma2[i]);
      } else {
	fTarget[i] = 0.;
      }
    }

  TMath::Sort(fK, fTarget, fInd);
}

void AliKMeansResult::CopyResults(const AliKMeansResult* res)
{
  fK = res->GetK();
  for (Int_t i = 0; i <fK; i++) {
    fMx[i]     = (res->GetMx())    [i];
    fMy[i]     = (res->GetMy())    [i];
    fSigma2[i] = (res->GetSigma2())[i];
    fRk[i]     = (res->GetRk())    [i];
    fTarget[i] = (res->GetTarget())[i];
    fInd[i]    = (res->GetInd())   [i];
  }
}
 AliKMeansClustering.cxx:1
 AliKMeansClustering.cxx:2
 AliKMeansClustering.cxx:3
 AliKMeansClustering.cxx:4
 AliKMeansClustering.cxx:5
 AliKMeansClustering.cxx:6
 AliKMeansClustering.cxx:7
 AliKMeansClustering.cxx:8
 AliKMeansClustering.cxx:9
 AliKMeansClustering.cxx:10
 AliKMeansClustering.cxx:11
 AliKMeansClustering.cxx:12
 AliKMeansClustering.cxx:13
 AliKMeansClustering.cxx:14
 AliKMeansClustering.cxx:15
 AliKMeansClustering.cxx:16
 AliKMeansClustering.cxx:17
 AliKMeansClustering.cxx:18
 AliKMeansClustering.cxx:19
 AliKMeansClustering.cxx:20
 AliKMeansClustering.cxx:21
 AliKMeansClustering.cxx:22
 AliKMeansClustering.cxx:23
 AliKMeansClustering.cxx:24
 AliKMeansClustering.cxx:25
 AliKMeansClustering.cxx:26
 AliKMeansClustering.cxx:27
 AliKMeansClustering.cxx:28
 AliKMeansClustering.cxx:29
 AliKMeansClustering.cxx:30
 AliKMeansClustering.cxx:31
 AliKMeansClustering.cxx:32
 AliKMeansClustering.cxx:33
 AliKMeansClustering.cxx:34
 AliKMeansClustering.cxx:35
 AliKMeansClustering.cxx:36
 AliKMeansClustering.cxx:37
 AliKMeansClustering.cxx:38
 AliKMeansClustering.cxx:39
 AliKMeansClustering.cxx:40
 AliKMeansClustering.cxx:41
 AliKMeansClustering.cxx:42
 AliKMeansClustering.cxx:43
 AliKMeansClustering.cxx:44
 AliKMeansClustering.cxx:45
 AliKMeansClustering.cxx:46
 AliKMeansClustering.cxx:47
 AliKMeansClustering.cxx:48
 AliKMeansClustering.cxx:49
 AliKMeansClustering.cxx:50
 AliKMeansClustering.cxx:51
 AliKMeansClustering.cxx:52
 AliKMeansClustering.cxx:53
 AliKMeansClustering.cxx:54
 AliKMeansClustering.cxx:55
 AliKMeansClustering.cxx:56
 AliKMeansClustering.cxx:57
 AliKMeansClustering.cxx:58
 AliKMeansClustering.cxx:59
 AliKMeansClustering.cxx:60
 AliKMeansClustering.cxx:61
 AliKMeansClustering.cxx:62
 AliKMeansClustering.cxx:63
 AliKMeansClustering.cxx:64
 AliKMeansClustering.cxx:65
 AliKMeansClustering.cxx:66
 AliKMeansClustering.cxx:67
 AliKMeansClustering.cxx:68
 AliKMeansClustering.cxx:69
 AliKMeansClustering.cxx:70
 AliKMeansClustering.cxx:71
 AliKMeansClustering.cxx:72
 AliKMeansClustering.cxx:73
 AliKMeansClustering.cxx:74
 AliKMeansClustering.cxx:75
 AliKMeansClustering.cxx:76
 AliKMeansClustering.cxx:77
 AliKMeansClustering.cxx:78
 AliKMeansClustering.cxx:79
 AliKMeansClustering.cxx:80
 AliKMeansClustering.cxx:81
 AliKMeansClustering.cxx:82
 AliKMeansClustering.cxx:83
 AliKMeansClustering.cxx:84
 AliKMeansClustering.cxx:85
 AliKMeansClustering.cxx:86
 AliKMeansClustering.cxx:87
 AliKMeansClustering.cxx:88
 AliKMeansClustering.cxx:89
 AliKMeansClustering.cxx:90
 AliKMeansClustering.cxx:91
 AliKMeansClustering.cxx:92
 AliKMeansClustering.cxx:93
 AliKMeansClustering.cxx:94
 AliKMeansClustering.cxx:95
 AliKMeansClustering.cxx:96
 AliKMeansClustering.cxx:97
 AliKMeansClustering.cxx:98
 AliKMeansClustering.cxx:99
 AliKMeansClustering.cxx:100
 AliKMeansClustering.cxx:101
 AliKMeansClustering.cxx:102
 AliKMeansClustering.cxx:103
 AliKMeansClustering.cxx:104
 AliKMeansClustering.cxx:105
 AliKMeansClustering.cxx:106
 AliKMeansClustering.cxx:107
 AliKMeansClustering.cxx:108
 AliKMeansClustering.cxx:109
 AliKMeansClustering.cxx:110
 AliKMeansClustering.cxx:111
 AliKMeansClustering.cxx:112
 AliKMeansClustering.cxx:113
 AliKMeansClustering.cxx:114
 AliKMeansClustering.cxx:115
 AliKMeansClustering.cxx:116
 AliKMeansClustering.cxx:117
 AliKMeansClustering.cxx:118
 AliKMeansClustering.cxx:119
 AliKMeansClustering.cxx:120
 AliKMeansClustering.cxx:121
 AliKMeansClustering.cxx:122
 AliKMeansClustering.cxx:123
 AliKMeansClustering.cxx:124
 AliKMeansClustering.cxx:125
 AliKMeansClustering.cxx:126
 AliKMeansClustering.cxx:127
 AliKMeansClustering.cxx:128
 AliKMeansClustering.cxx:129
 AliKMeansClustering.cxx:130
 AliKMeansClustering.cxx:131
 AliKMeansClustering.cxx:132
 AliKMeansClustering.cxx:133
 AliKMeansClustering.cxx:134
 AliKMeansClustering.cxx:135
 AliKMeansClustering.cxx:136
 AliKMeansClustering.cxx:137
 AliKMeansClustering.cxx:138
 AliKMeansClustering.cxx:139
 AliKMeansClustering.cxx:140
 AliKMeansClustering.cxx:141
 AliKMeansClustering.cxx:142
 AliKMeansClustering.cxx:143
 AliKMeansClustering.cxx:144
 AliKMeansClustering.cxx:145
 AliKMeansClustering.cxx:146
 AliKMeansClustering.cxx:147
 AliKMeansClustering.cxx:148
 AliKMeansClustering.cxx:149
 AliKMeansClustering.cxx:150
 AliKMeansClustering.cxx:151
 AliKMeansClustering.cxx:152
 AliKMeansClustering.cxx:153
 AliKMeansClustering.cxx:154
 AliKMeansClustering.cxx:155
 AliKMeansClustering.cxx:156
 AliKMeansClustering.cxx:157
 AliKMeansClustering.cxx:158
 AliKMeansClustering.cxx:159
 AliKMeansClustering.cxx:160
 AliKMeansClustering.cxx:161
 AliKMeansClustering.cxx:162
 AliKMeansClustering.cxx:163
 AliKMeansClustering.cxx:164
 AliKMeansClustering.cxx:165
 AliKMeansClustering.cxx:166
 AliKMeansClustering.cxx:167
 AliKMeansClustering.cxx:168
 AliKMeansClustering.cxx:169
 AliKMeansClustering.cxx:170
 AliKMeansClustering.cxx:171
 AliKMeansClustering.cxx:172
 AliKMeansClustering.cxx:173
 AliKMeansClustering.cxx:174
 AliKMeansClustering.cxx:175
 AliKMeansClustering.cxx:176
 AliKMeansClustering.cxx:177
 AliKMeansClustering.cxx:178
 AliKMeansClustering.cxx:179
 AliKMeansClustering.cxx:180
 AliKMeansClustering.cxx:181
 AliKMeansClustering.cxx:182
 AliKMeansClustering.cxx:183
 AliKMeansClustering.cxx:184
 AliKMeansClustering.cxx:185
 AliKMeansClustering.cxx:186
 AliKMeansClustering.cxx:187
 AliKMeansClustering.cxx:188
 AliKMeansClustering.cxx:189
 AliKMeansClustering.cxx:190
 AliKMeansClustering.cxx:191
 AliKMeansClustering.cxx:192
 AliKMeansClustering.cxx:193
 AliKMeansClustering.cxx:194
 AliKMeansClustering.cxx:195
 AliKMeansClustering.cxx:196
 AliKMeansClustering.cxx:197
 AliKMeansClustering.cxx:198
 AliKMeansClustering.cxx:199
 AliKMeansClustering.cxx:200
 AliKMeansClustering.cxx:201
 AliKMeansClustering.cxx:202
 AliKMeansClustering.cxx:203
 AliKMeansClustering.cxx:204
 AliKMeansClustering.cxx:205
 AliKMeansClustering.cxx:206
 AliKMeansClustering.cxx:207
 AliKMeansClustering.cxx:208
 AliKMeansClustering.cxx:209
 AliKMeansClustering.cxx:210
 AliKMeansClustering.cxx:211
 AliKMeansClustering.cxx:212
 AliKMeansClustering.cxx:213
 AliKMeansClustering.cxx:214
 AliKMeansClustering.cxx:215
 AliKMeansClustering.cxx:216
 AliKMeansClustering.cxx:217
 AliKMeansClustering.cxx:218
 AliKMeansClustering.cxx:219
 AliKMeansClustering.cxx:220
 AliKMeansClustering.cxx:221
 AliKMeansClustering.cxx:222
 AliKMeansClustering.cxx:223
 AliKMeansClustering.cxx:224
 AliKMeansClustering.cxx:225
 AliKMeansClustering.cxx:226
 AliKMeansClustering.cxx:227
 AliKMeansClustering.cxx:228
 AliKMeansClustering.cxx:229
 AliKMeansClustering.cxx:230
 AliKMeansClustering.cxx:231
 AliKMeansClustering.cxx:232
 AliKMeansClustering.cxx:233
 AliKMeansClustering.cxx:234
 AliKMeansClustering.cxx:235
 AliKMeansClustering.cxx:236
 AliKMeansClustering.cxx:237
 AliKMeansClustering.cxx:238
 AliKMeansClustering.cxx:239
 AliKMeansClustering.cxx:240
 AliKMeansClustering.cxx:241
 AliKMeansClustering.cxx:242
 AliKMeansClustering.cxx:243
 AliKMeansClustering.cxx:244
 AliKMeansClustering.cxx:245
 AliKMeansClustering.cxx:246
 AliKMeansClustering.cxx:247
 AliKMeansClustering.cxx:248
 AliKMeansClustering.cxx:249
 AliKMeansClustering.cxx:250
 AliKMeansClustering.cxx:251
 AliKMeansClustering.cxx:252
 AliKMeansClustering.cxx:253
 AliKMeansClustering.cxx:254
 AliKMeansClustering.cxx:255
 AliKMeansClustering.cxx:256
 AliKMeansClustering.cxx:257
 AliKMeansClustering.cxx:258
 AliKMeansClustering.cxx:259
 AliKMeansClustering.cxx:260
 AliKMeansClustering.cxx:261
 AliKMeansClustering.cxx:262
 AliKMeansClustering.cxx:263
 AliKMeansClustering.cxx:264
 AliKMeansClustering.cxx:265
 AliKMeansClustering.cxx:266
 AliKMeansClustering.cxx:267
 AliKMeansClustering.cxx:268
 AliKMeansClustering.cxx:269
 AliKMeansClustering.cxx:270
 AliKMeansClustering.cxx:271
 AliKMeansClustering.cxx:272
 AliKMeansClustering.cxx:273
 AliKMeansClustering.cxx:274
 AliKMeansClustering.cxx:275
 AliKMeansClustering.cxx:276
 AliKMeansClustering.cxx:277
 AliKMeansClustering.cxx:278
 AliKMeansClustering.cxx:279
 AliKMeansClustering.cxx:280
 AliKMeansClustering.cxx:281
 AliKMeansClustering.cxx:282
 AliKMeansClustering.cxx:283
 AliKMeansClustering.cxx:284
 AliKMeansClustering.cxx:285
 AliKMeansClustering.cxx:286
 AliKMeansClustering.cxx:287
 AliKMeansClustering.cxx:288
 AliKMeansClustering.cxx:289
 AliKMeansClustering.cxx:290
 AliKMeansClustering.cxx:291
 AliKMeansClustering.cxx:292
 AliKMeansClustering.cxx:293
 AliKMeansClustering.cxx:294
 AliKMeansClustering.cxx:295
 AliKMeansClustering.cxx:296
 AliKMeansClustering.cxx:297
 AliKMeansClustering.cxx:298
 AliKMeansClustering.cxx:299
 AliKMeansClustering.cxx:300
 AliKMeansClustering.cxx:301
 AliKMeansClustering.cxx:302
 AliKMeansClustering.cxx:303
 AliKMeansClustering.cxx:304
 AliKMeansClustering.cxx:305
 AliKMeansClustering.cxx:306
 AliKMeansClustering.cxx:307
 AliKMeansClustering.cxx:308
 AliKMeansClustering.cxx:309
 AliKMeansClustering.cxx:310
 AliKMeansClustering.cxx:311
 AliKMeansClustering.cxx:312
 AliKMeansClustering.cxx:313
 AliKMeansClustering.cxx:314
 AliKMeansClustering.cxx:315
 AliKMeansClustering.cxx:316
 AliKMeansClustering.cxx:317
 AliKMeansClustering.cxx:318
 AliKMeansClustering.cxx:319
 AliKMeansClustering.cxx:320
 AliKMeansClustering.cxx:321
 AliKMeansClustering.cxx:322
 AliKMeansClustering.cxx:323
 AliKMeansClustering.cxx:324
 AliKMeansClustering.cxx:325
 AliKMeansClustering.cxx:326
 AliKMeansClustering.cxx:327
 AliKMeansClustering.cxx:328
 AliKMeansClustering.cxx:329
 AliKMeansClustering.cxx:330
 AliKMeansClustering.cxx:331
 AliKMeansClustering.cxx:332
 AliKMeansClustering.cxx:333
 AliKMeansClustering.cxx:334
 AliKMeansClustering.cxx:335
 AliKMeansClustering.cxx:336
 AliKMeansClustering.cxx:337
 AliKMeansClustering.cxx:338
 AliKMeansClustering.cxx:339
 AliKMeansClustering.cxx:340
 AliKMeansClustering.cxx:341
 AliKMeansClustering.cxx:342
 AliKMeansClustering.cxx:343
 AliKMeansClustering.cxx:344
 AliKMeansClustering.cxx:345
 AliKMeansClustering.cxx:346
 AliKMeansClustering.cxx:347
 AliKMeansClustering.cxx:348
 AliKMeansClustering.cxx:349
 AliKMeansClustering.cxx:350
 AliKMeansClustering.cxx:351
 AliKMeansClustering.cxx:352
 AliKMeansClustering.cxx:353
 AliKMeansClustering.cxx:354
 AliKMeansClustering.cxx:355
 AliKMeansClustering.cxx:356
 AliKMeansClustering.cxx:357
 AliKMeansClustering.cxx:358
 AliKMeansClustering.cxx:359
 AliKMeansClustering.cxx:360
 AliKMeansClustering.cxx:361
 AliKMeansClustering.cxx:362
 AliKMeansClustering.cxx:363
 AliKMeansClustering.cxx:364
 AliKMeansClustering.cxx:365
 AliKMeansClustering.cxx:366
 AliKMeansClustering.cxx:367
 AliKMeansClustering.cxx:368
 AliKMeansClustering.cxx:369
 AliKMeansClustering.cxx:370
 AliKMeansClustering.cxx:371
 AliKMeansClustering.cxx:372
 AliKMeansClustering.cxx:373
 AliKMeansClustering.cxx:374
 AliKMeansClustering.cxx:375
 AliKMeansClustering.cxx:376
 AliKMeansClustering.cxx:377
 AliKMeansClustering.cxx:378
 AliKMeansClustering.cxx:379
 AliKMeansClustering.cxx:380
 AliKMeansClustering.cxx:381
 AliKMeansClustering.cxx:382
 AliKMeansClustering.cxx:383
 AliKMeansClustering.cxx:384
 AliKMeansClustering.cxx:385
 AliKMeansClustering.cxx:386
 AliKMeansClustering.cxx:387
 AliKMeansClustering.cxx:388
 AliKMeansClustering.cxx:389
 AliKMeansClustering.cxx:390
 AliKMeansClustering.cxx:391
 AliKMeansClustering.cxx:392
 AliKMeansClustering.cxx:393
 AliKMeansClustering.cxx:394
 AliKMeansClustering.cxx:395
 AliKMeansClustering.cxx:396
 AliKMeansClustering.cxx:397
 AliKMeansClustering.cxx:398
 AliKMeansClustering.cxx:399
 AliKMeansClustering.cxx:400
 AliKMeansClustering.cxx:401
 AliKMeansClustering.cxx:402
 AliKMeansClustering.cxx:403
 AliKMeansClustering.cxx:404
 AliKMeansClustering.cxx:405
 AliKMeansClustering.cxx:406
 AliKMeansClustering.cxx:407
 AliKMeansClustering.cxx:408
 AliKMeansClustering.cxx:409
 AliKMeansClustering.cxx:410
 AliKMeansClustering.cxx:411
 AliKMeansClustering.cxx:412
 AliKMeansClustering.cxx:413
 AliKMeansClustering.cxx:414
 AliKMeansClustering.cxx:415
 AliKMeansClustering.cxx:416
 AliKMeansClustering.cxx:417
 AliKMeansClustering.cxx:418
 AliKMeansClustering.cxx:419
 AliKMeansClustering.cxx:420
 AliKMeansClustering.cxx:421
 AliKMeansClustering.cxx:422
 AliKMeansClustering.cxx:423
 AliKMeansClustering.cxx:424
 AliKMeansClustering.cxx:425
 AliKMeansClustering.cxx:426
 AliKMeansClustering.cxx:427
 AliKMeansClustering.cxx:428
 AliKMeansClustering.cxx:429
 AliKMeansClustering.cxx:430
 AliKMeansClustering.cxx:431
 AliKMeansClustering.cxx:432
 AliKMeansClustering.cxx:433
 AliKMeansClustering.cxx:434
 AliKMeansClustering.cxx:435
 AliKMeansClustering.cxx:436
 AliKMeansClustering.cxx:437
 AliKMeansClustering.cxx:438
 AliKMeansClustering.cxx:439
 AliKMeansClustering.cxx:440
 AliKMeansClustering.cxx:441
 AliKMeansClustering.cxx:442
 AliKMeansClustering.cxx:443
 AliKMeansClustering.cxx:444
 AliKMeansClustering.cxx:445
 AliKMeansClustering.cxx:446
 AliKMeansClustering.cxx:447
 AliKMeansClustering.cxx:448
 AliKMeansClustering.cxx:449
 AliKMeansClustering.cxx:450
 AliKMeansClustering.cxx:451
 AliKMeansClustering.cxx:452
 AliKMeansClustering.cxx:453
 AliKMeansClustering.cxx:454
 AliKMeansClustering.cxx:455
 AliKMeansClustering.cxx:456
 AliKMeansClustering.cxx:457
 AliKMeansClustering.cxx:458
 AliKMeansClustering.cxx:459
 AliKMeansClustering.cxx:460
 AliKMeansClustering.cxx:461
 AliKMeansClustering.cxx:462
 AliKMeansClustering.cxx:463
 AliKMeansClustering.cxx:464
 AliKMeansClustering.cxx:465
 AliKMeansClustering.cxx:466
 AliKMeansClustering.cxx:467
 AliKMeansClustering.cxx:468
 AliKMeansClustering.cxx:469
 AliKMeansClustering.cxx:470
 AliKMeansClustering.cxx:471
 AliKMeansClustering.cxx:472
 AliKMeansClustering.cxx:473
 AliKMeansClustering.cxx:474
 AliKMeansClustering.cxx:475
 AliKMeansClustering.cxx:476
 AliKMeansClustering.cxx:477
 AliKMeansClustering.cxx:478
 AliKMeansClustering.cxx:479
 AliKMeansClustering.cxx:480
 AliKMeansClustering.cxx:481
 AliKMeansClustering.cxx:482
 AliKMeansClustering.cxx:483
 AliKMeansClustering.cxx:484
 AliKMeansClustering.cxx:485
 AliKMeansClustering.cxx:486
 AliKMeansClustering.cxx:487
 AliKMeansClustering.cxx:488
 AliKMeansClustering.cxx:489
 AliKMeansClustering.cxx:490
 AliKMeansClustering.cxx:491
 AliKMeansClustering.cxx:492
 AliKMeansClustering.cxx:493
 AliKMeansClustering.cxx:494
 AliKMeansClustering.cxx:495
 AliKMeansClustering.cxx:496
 AliKMeansClustering.cxx:497
 AliKMeansClustering.cxx:498
 AliKMeansClustering.cxx:499
 AliKMeansClustering.cxx:500
 AliKMeansClustering.cxx:501
 AliKMeansClustering.cxx:502
 AliKMeansClustering.cxx:503
 AliKMeansClustering.cxx:504
 AliKMeansClustering.cxx:505
 AliKMeansClustering.cxx:506
 AliKMeansClustering.cxx:507
 AliKMeansClustering.cxx:508
 AliKMeansClustering.cxx:509
 AliKMeansClustering.cxx:510
 AliKMeansClustering.cxx:511
 AliKMeansClustering.cxx:512
 AliKMeansClustering.cxx:513
 AliKMeansClustering.cxx:514
 AliKMeansClustering.cxx:515
 AliKMeansClustering.cxx:516
 AliKMeansClustering.cxx:517
 AliKMeansClustering.cxx:518
 AliKMeansClustering.cxx:519
 AliKMeansClustering.cxx:520
 AliKMeansClustering.cxx:521
 AliKMeansClustering.cxx:522
 AliKMeansClustering.cxx:523
 AliKMeansClustering.cxx:524
 AliKMeansClustering.cxx:525
 AliKMeansClustering.cxx:526
 AliKMeansClustering.cxx:527
 AliKMeansClustering.cxx:528
 AliKMeansClustering.cxx:529
 AliKMeansClustering.cxx:530
 AliKMeansClustering.cxx:531
 AliKMeansClustering.cxx:532
 AliKMeansClustering.cxx:533
 AliKMeansClustering.cxx:534
 AliKMeansClustering.cxx:535
 AliKMeansClustering.cxx:536
 AliKMeansClustering.cxx:537
 AliKMeansClustering.cxx:538
 AliKMeansClustering.cxx:539
 AliKMeansClustering.cxx:540
 AliKMeansClustering.cxx:541
 AliKMeansClustering.cxx:542
 AliKMeansClustering.cxx:543
 AliKMeansClustering.cxx:544
 AliKMeansClustering.cxx:545
 AliKMeansClustering.cxx:546
 AliKMeansClustering.cxx:547
 AliKMeansClustering.cxx:548
 AliKMeansClustering.cxx:549
 AliKMeansClustering.cxx:550
 AliKMeansClustering.cxx:551
 AliKMeansClustering.cxx:552
 AliKMeansClustering.cxx:553
 AliKMeansClustering.cxx:554
 AliKMeansClustering.cxx:555
 AliKMeansClustering.cxx:556
 AliKMeansClustering.cxx:557
 AliKMeansClustering.cxx:558
 AliKMeansClustering.cxx:559
 AliKMeansClustering.cxx:560
 AliKMeansClustering.cxx:561
 AliKMeansClustering.cxx:562
 AliKMeansClustering.cxx:563
 AliKMeansClustering.cxx:564
 AliKMeansClustering.cxx:565
 AliKMeansClustering.cxx:566
 AliKMeansClustering.cxx:567
 AliKMeansClustering.cxx:568
 AliKMeansClustering.cxx:569
 AliKMeansClustering.cxx:570