ROOT logo
#include <malloc.h>

#include "TSystem.h"
#include "TFile.h"
#include "TTree.h"
#include "TH2I.h"
#include "TLegend.h"
#include "TRandom.h"
#include "TString.h"
#include "TGraph.h"
#include "TMarker.h"
#include "TStopwatch.h"
#include "../src/TKDPDF.h"
#include "../src/TKDTree.h"

void kNNTest(const int np = 10000, const int ndim = 2);
void kNNDraw(const Float_t *p, const int kNN=20);
void build(const Int_t ndim = 2, const Int_t nstat = 1000000);
Float_t Mem();


//______________________________________________________________
void kNNTest(const int np, const int ndim)
{
// Test speed and quality of nearest neighbors search.
// The results are compared with a simple loop search through the data.
// The macro should run in compiled mode.

	const int ntimes = 1000; // times to repeate kNN search
	const Int_t kNN = 1; // number of neighbors

	Float_t **x = new Float_t*[ndim];
	for(int idim =0 ; idim<ndim; idim++){
		x[idim] = new Float_t[np];
		for(int ip=0; ip<np; ip++) x[idim][ip] = gRandom->Gaus();
	}
	TKDTreeIF nnFinder(np, ndim, 1, x);
	
	// generate test sample
	Float_t **p = new Float_t*[ntimes];
	for(int ip =0 ; ip<ntimes; ip++){
		p[ip] = new Float_t[ndim];
		for(int idim=0; idim<ndim; idim++) p[ip][idim] = gRandom->Gaus();
	}


	Int_t *index;
	Float_t *d;
	TStopwatch timer;
	timer.Start(kTRUE);
	for(int itime=0; itime<ntimes; itime++) nnFinder.FindNearestNeighbors(p[itime], kNN, index, d);
	timer.Stop();
	printf("kDTree NN calculation.\n");
	printf("cpu = %f [ms] real = %f [ms]\n", 1.E3*timer.CpuTime()/ntimes, 1.E3*timer.RealTime()/ntimes);
	printf("Points indexes in increasing order of their distance to the target point.\n");
	for(int i=0; i<kNN; i++){
		printf("%5d [%7.4f] ", index[i], d[i]);
		if(i%5==4) printf("\n");
	}
	printf("\n");
	
	// draw kNN
	TLegend *leg = new TLegend(.7, .7, .9, .9);
	leg->SetBorderSize(1);
	leg->SetHeader("NN finders");
	TH2 *h2 = new TH2I("h2", "", 100, -2., 2., 100, -2., 2.);
	h2->Draw(); h2->SetStats(kFALSE);
	TMarker *mp = new TMarker(p[ntimes-1][0], p[ntimes-1][1], 3);
	mp->SetMarkerColor(4);
	mp->Draw(); leg->AddEntry(mp, "Target", "p");
	TGraph *gKD = new TGraph(kNN);
	gKD->SetMarkerStyle(24);
	gKD->SetMarkerColor(2);
	gKD->SetMarkerSize(.5);
	for(int ip=0; ip<kNN; ip++) gKD->SetPoint(ip, x[0][index[ip]], x[1][index[ip]]);
	gKD->Draw("p"); leg->AddEntry(gKD, "kDTree", "p");
	

		
	// STAND ALONE
	Float_t ftmp, gtmp, dist;
	Int_t itmp, jtmp;
	Int_t   fkNN[kNN];
	Float_t fkNNdist[kNN];
	for(int i=0; i<kNN; i++) fkNNdist[i] = 9999.;

	// calculate
	timer.Start(kTRUE);
	for(int idx=0; idx<np; idx++){
		// calculate distance in the L1 metric
		dist = 0.;
		for(int idim=0; idim<ndim; idim++) dist += TMath::Abs(p[ntimes-1][idim] - x[idim][idx]);
		if(dist >= fkNNdist[kNN-1]) continue;

		//insert neighbor
		int iNN=0;
		while(dist >= fkNNdist[iNN]) iNN++;
		itmp = fkNN[iNN]; ftmp = fkNNdist[iNN];
		fkNN[iNN]     = idx;
		fkNNdist[iNN] = dist;
		for(int ireplace=iNN+1; ireplace<kNN; ireplace++){
			jtmp = fkNN[ireplace]; gtmp = fkNNdist[ireplace];
			fkNN[ireplace] = itmp; fkNNdist[ireplace] = ftmp;
			itmp = jtmp; ftmp = gtmp;
			if(ftmp == 9999.) break;
		}
	}
	timer.Stop();
	printf("\nStand Alone NN calculation.\n");
	printf("cpu = %f [ms] real = %f [ms]\n", 1.E3*timer.CpuTime(), 1.E3*timer.RealTime());
	printf("Points indexes in increasing order of their distance to the target point.\n");
	for(int i=0; i<kNN; i++){
		printf("%5d [%7.4f] ", fkNN[i], fkNNdist[i]);
		if(i%5==4) printf("\n");
	}
	printf("\n");	

	TGraph *gSA = new TGraph(kNN);
	gSA->SetMarkerStyle(24);
	for(int ip=0; ip<kNN; ip++) gSA->SetPoint(ip, x[0][fkNN[ip]], x[1][fkNN[ip]]);

	gSA->Draw("p"); leg->AddEntry(gSA, "Stand Alone", "p");
	leg->Draw();
	
	for(int ip=0; ip<ntimes; ip++) delete [] p[ip];
	delete [] p;
	for(int idim=0; idim<ndim; idim++) delete [] x[idim];
	delete [] x;
}


//______________________________________________________________
Float_t p[]={1.4, -.6}; //}{1.7, -.4};
void kNNDraw(const Float_t *p, const int kNN)
{
// Test memory consumption and draw "kNN" nearest neighbours of point "p".
// The distance (in the L1 metric) is encoded in the color code.

	const Int_t npoints = 10000;
	Float_t *data0 =  new Float_t[npoints*2];
  Float_t *data[2];
  data[0] = &data0[0];
  data[1] = &data0[npoints];
  for (Int_t i=0;i<npoints;i++) {
    data[1][i]= gRandom->Gaus();
    data[0][i]= gRandom->Gaus();
  }

	TKDPDF pdf(npoints, 2, 100, data);
	pdf.DrawNode(pdf.GetNodeIndex(p));
	
	TMarker *mp = new TMarker(p[0], p[1], 3);
	mp->SetMarkerColor(4);
	mp->Draw();
		
	Int_t *index, color;
	Float_t *d, d0, pknn[2];
	Float_t start = Mem();
	pdf.FindNearestNeighbors(p, kNN, index, d);
	Float_t end = Mem();
	printf("FindNearestNeighbors memory usage %fKB\n", end-start);
	d0 = d[kNN-1];
	TMarker *ma = new TMarker[kNN];
	for(int ip=0; ip<kNN; ip++){
		pdf.GetDataPoint(index[ip], pknn);
		color = 101 - Int_t(50. * d[ip]/d0);
		ma[ip].SetMarkerStyle(4);
		ma[ip].SetMarkerColor(color);
		ma[ip].DrawMarker(pknn[0], pknn[1]);
	}
}


//______________________________________________________________
Float_t Mem()
{
  // size in KB
  static struct mallinfo memdebug; 
  memdebug = mallinfo();
  return memdebug.uordblks/1024.;
}

//______________________________________________________________
void build(const Int_t ndim, const Int_t nstat)
{
// Build "nstat" data points in "ndim" dimensions taken from an
// uncorrelated 2D Gauss distribution.
	

	printf("build data ... \n");
	Double_t pntTrain[ndim];
	TFile *f = TFile::Open(Form("%dD_Gauss.root", ndim), "RECREATE");
	TTree *t = new TTree("db", "gauss database");
	for(int idim=0; idim<ndim; idim++) t->Branch(Form("x%d", idim), &pntTrain[idim], Form("x%d/D", idim));
	
	for(int istat=0; istat<nstat; istat++){
		for(int idim=0; idim<ndim; idim++) pntTrain[idim] = gRandom->Gaus();
		t->Fill();
	}
	f->cd();
	t->Write();
	f->Close();
	delete f;
}

 kNNTest.C:1
 kNNTest.C:2
 kNNTest.C:3
 kNNTest.C:4
 kNNTest.C:5
 kNNTest.C:6
 kNNTest.C:7
 kNNTest.C:8
 kNNTest.C:9
 kNNTest.C:10
 kNNTest.C:11
 kNNTest.C:12
 kNNTest.C:13
 kNNTest.C:14
 kNNTest.C:15
 kNNTest.C:16
 kNNTest.C:17
 kNNTest.C:18
 kNNTest.C:19
 kNNTest.C:20
 kNNTest.C:21
 kNNTest.C:22
 kNNTest.C:23
 kNNTest.C:24
 kNNTest.C:25
 kNNTest.C:26
 kNNTest.C:27
 kNNTest.C:28
 kNNTest.C:29
 kNNTest.C:30
 kNNTest.C:31
 kNNTest.C:32
 kNNTest.C:33
 kNNTest.C:34
 kNNTest.C:35
 kNNTest.C:36
 kNNTest.C:37
 kNNTest.C:38
 kNNTest.C:39
 kNNTest.C:40
 kNNTest.C:41
 kNNTest.C:42
 kNNTest.C:43
 kNNTest.C:44
 kNNTest.C:45
 kNNTest.C:46
 kNNTest.C:47
 kNNTest.C:48
 kNNTest.C:49
 kNNTest.C:50
 kNNTest.C:51
 kNNTest.C:52
 kNNTest.C:53
 kNNTest.C:54
 kNNTest.C:55
 kNNTest.C:56
 kNNTest.C:57
 kNNTest.C:58
 kNNTest.C:59
 kNNTest.C:60
 kNNTest.C:61
 kNNTest.C:62
 kNNTest.C:63
 kNNTest.C:64
 kNNTest.C:65
 kNNTest.C:66
 kNNTest.C:67
 kNNTest.C:68
 kNNTest.C:69
 kNNTest.C:70
 kNNTest.C:71
 kNNTest.C:72
 kNNTest.C:73
 kNNTest.C:74
 kNNTest.C:75
 kNNTest.C:76
 kNNTest.C:77
 kNNTest.C:78
 kNNTest.C:79
 kNNTest.C:80
 kNNTest.C:81
 kNNTest.C:82
 kNNTest.C:83
 kNNTest.C:84
 kNNTest.C:85
 kNNTest.C:86
 kNNTest.C:87
 kNNTest.C:88
 kNNTest.C:89
 kNNTest.C:90
 kNNTest.C:91
 kNNTest.C:92
 kNNTest.C:93
 kNNTest.C:94
 kNNTest.C:95
 kNNTest.C:96
 kNNTest.C:97
 kNNTest.C:98
 kNNTest.C:99
 kNNTest.C:100
 kNNTest.C:101
 kNNTest.C:102
 kNNTest.C:103
 kNNTest.C:104
 kNNTest.C:105
 kNNTest.C:106
 kNNTest.C:107
 kNNTest.C:108
 kNNTest.C:109
 kNNTest.C:110
 kNNTest.C:111
 kNNTest.C:112
 kNNTest.C:113
 kNNTest.C:114
 kNNTest.C:115
 kNNTest.C:116
 kNNTest.C:117
 kNNTest.C:118
 kNNTest.C:119
 kNNTest.C:120
 kNNTest.C:121
 kNNTest.C:122
 kNNTest.C:123
 kNNTest.C:124
 kNNTest.C:125
 kNNTest.C:126
 kNNTest.C:127
 kNNTest.C:128
 kNNTest.C:129
 kNNTest.C:130
 kNNTest.C:131
 kNNTest.C:132
 kNNTest.C:133
 kNNTest.C:134
 kNNTest.C:135
 kNNTest.C:136
 kNNTest.C:137
 kNNTest.C:138
 kNNTest.C:139
 kNNTest.C:140
 kNNTest.C:141
 kNNTest.C:142
 kNNTest.C:143
 kNNTest.C:144
 kNNTest.C:145
 kNNTest.C:146
 kNNTest.C:147
 kNNTest.C:148
 kNNTest.C:149
 kNNTest.C:150
 kNNTest.C:151
 kNNTest.C:152
 kNNTest.C:153
 kNNTest.C:154
 kNNTest.C:155
 kNNTest.C:156
 kNNTest.C:157
 kNNTest.C:158
 kNNTest.C:159
 kNNTest.C:160
 kNNTest.C:161
 kNNTest.C:162
 kNNTest.C:163
 kNNTest.C:164
 kNNTest.C:165
 kNNTest.C:166
 kNNTest.C:167
 kNNTest.C:168
 kNNTest.C:169
 kNNTest.C:170
 kNNTest.C:171
 kNNTest.C:172
 kNNTest.C:173
 kNNTest.C:174
 kNNTest.C:175
 kNNTest.C:176
 kNNTest.C:177
 kNNTest.C:178
 kNNTest.C:179
 kNNTest.C:180
 kNNTest.C:181
 kNNTest.C:182
 kNNTest.C:183
 kNNTest.C:184
 kNNTest.C:185
 kNNTest.C:186
 kNNTest.C:187
 kNNTest.C:188
 kNNTest.C:189
 kNNTest.C:190
 kNNTest.C:191
 kNNTest.C:192
 kNNTest.C:193
 kNNTest.C:194
 kNNTest.C:195
 kNNTest.C:196
 kNNTest.C:197
 kNNTest.C:198
 kNNTest.C:199
 kNNTest.C:200
 kNNTest.C:201
 kNNTest.C:202
 kNNTest.C:203
 kNNTest.C:204
 kNNTest.C:205
 kNNTest.C:206