The Cuik KD-Tree Library


test-cuik-kdtree.c

Go to the documentation of this file.
00001 #include "cuik-kdtree.h"
00002 #include "random.h"
00003 #include "definitions.h"
00004 #include "vector.h"
00005 
00006 #include <stdio.h>
00007 #include <time.h>
00008 #include <stdlib.h>
00009 #include <string.h>
00010 #include <math.h>
00011 #include <sys/resource.h>
00012 #include <DNN/ANN_C.h>
00013 
00033 #define POINTS_ON_SPHERE 0
00034 
00040 #define N_POINTS 50000
00041 
00047 #define DIM 8
00048 
00054 #define TOPOLOGY TOPOLOGY_S
00055 
00061 #define POINTS_IN_LEAF 25
00062 
00070 #define SAMPLING_EXPANSION 1.0
00071 
00077 #define R 2.0
00078 
00085 #define REP 1000
00086 
00087 
00093 #define N_OPTIONS 9
00094 
00107 int CmpUInt(const void *a,const void *b);
00108 
00116 double getTime();
00117 
00118 /**********************************************************************************************/
00119 /**********************************************************************************************/
00120 
00121 int CmpUInt(const void *a,const void *b)
00122 {
00123   return(*((unsigned int*)a)-*((unsigned int*)b));
00124 }
00125 
00126 double getTime()
00127 {
00128   struct rusage usage;
00129   
00130   getrusage(RUSAGE_SELF,&usage);
00131   
00132   /* Accumulate the user and system time and convert to miliseconds */
00133   return((double)(usage.ru_utime.tv_sec +usage.ru_stime.tv_sec )*1000.0+
00134          (double)(usage.ru_utime.tv_usec+usage.ru_stime.tv_usec)/1000.0);
00135 }
00136 
00137 /**********************************************************************************************/
00138 /**********************************************************************************************/
00139 
00159 int main(int argc, char **arg)
00160 {
00161   char *option[N_OPTIONS]={"-h","-n","-d","-t","-l","-r","-m","-s","-e"};
00162 
00163   unsigned int nPoints,dim,tpg,pLeaf,rep;
00164   double searchR,expansion;
00165 
00166   /* The two kd-trees to compare */
00167   TKDtree *Mkdt;
00168   #ifdef _MPNN
00169     TKDTree *Ykdt;
00170   #endif
00171 
00172   /* Several auxiliary variables */
00173   boolean found;
00174   unsigned int i,j;
00175   double **point,*q;
00176   Trectangle ambient;
00177   unsigned int *topology;
00178   unsigned int id;
00179   double l,u,d,r2;
00180   unsigned int *nn,n,m;
00181   double *dst,dMin;
00182   unsigned int idMin;
00183 
00184   /* Random seed */
00185   unsigned int ri;
00186   
00187   /* To measure time */
00188   time_t t;
00189   double tStart,tEnd;
00190 
00191   /* Set the parameters to the default values */
00192   nPoints=N_POINTS;
00193   dim=DIM;
00194   tpg=TOPOLOGY;
00195   pLeaf=POINTS_IN_LEAF;
00196   expansion=SAMPLING_EXPANSION;
00197   searchR=R;
00198   rep=REP;
00199 
00200   /* Process the input parameters, if any */
00201   i=1;
00202   while (i<argc)
00203     {
00204       found=FALSE;
00205       j=0;
00206       while((!found)&&(j<N_OPTIONS))
00207         {
00208           if (strcmp(arg[i],option[j])==0)
00209             {
00210               switch(j)
00211                 {
00212                 case 0: /* -h */
00213                   fprintf(stderr,"cuik-kdtree test program\n");
00214                   fprintf(stderr,"Usage: \n");
00215                   fprintf(stderr,"  test-cuik-kdtree <option> <ooption> <option> ...\n");
00216                   fprintf(stderr,"Options: \n");
00217                   fprintf(stderr,"  -n <value>   Number of random  points to generate.\n");
00218                   fprintf(stderr,"                 Default value: %u\n",N_POINTS);
00219                   fprintf(stderr,"  -d <value>   Dimension of the  points to generate.\n");
00220                   fprintf(stderr,"                 Default value: %u\n",DIM);
00221                   fprintf(stderr,"  -t <R|S>     Topology (R or S) of the  points to generate.\n");
00222                   fprintf(stderr,"               The same topology is used for all the dimensions.\n");
00223                   fprintf(stderr,"                 Default value: %s\n",(TOPOLOGY==TOPOLOGY_R?"R":"S"));
00224                   fprintf(stderr,"  -l <value>   Maximum number of points in each leaf.\n");
00225                   fprintf(stderr,"                 Default value: %u\n",POINTS_IN_LEAF);
00226                   fprintf(stderr,"  -r <value>   Search radius (for the in-ball queries).\n");
00227                   fprintf(stderr,"                 Default value: %f\n",R);
00228                   fprintf(stderr,"  -m <value>   Number of reptetions to gather execution times.\n");
00229                   fprintf(stderr,"                 Default value: %u\n",REP);
00230                   fprintf(stderr,"  -e <value>   Sampling expansion (not used so far in the test).\n");
00231                   fprintf(stderr,"                 Default value: %f\n",SAMPLING_EXPANSION);
00232                   fprintf(stderr,"  -s <value>   Random seed.\n");
00233                   fprintf(stderr,"                 Default value: arbitrarily fixed\n");
00234                   fprintf(stderr,"  -h           This help.\n"); 
00235                   fprintf(stderr,"Examples: \n");
00236                   fprintf(stderr,"  test-cuik-kdtree\n"); 
00237                   fprintf(stderr,"  test-cuik-kdtree -t R -r 0.75\n"); 
00238                   fprintf(stderr,"  test-cuik-kdtree -n 100000\n"); 
00239                   exit(EXIT_SUCCESS);
00240                   break;
00241 
00242                 case 1: /* -n */
00243                   found=TRUE;
00244                   i++;
00245                   nPoints=(unsigned int)atoi(arg[i]);
00246                   if (nPoints<2)
00247                     {
00248                       fprintf(stderr,"Too smalll number of points (-n).\n");
00249                       exit(EXIT_FAILURE);
00250                     }
00251                   break;
00252 
00253                 case 2: /* -d */
00254                   found=TRUE;
00255                   i++;
00256                   dim=(unsigned int)atoi(arg[i]);
00257                   if (dim<1)
00258                     {
00259                       fprintf(stderr,"Too smalll dimension (-d).\n");
00260                       exit(EXIT_FAILURE);
00261                     }
00262                   break;
00263 
00264                 case 3: /* -t */
00265                   found=TRUE;
00266                   i++;
00267                   
00268                   if (arg[i][0]=='R')
00269                     tpg=TOPOLOGY_R;
00270                   else
00271                     {
00272                       if (arg[i][0]=='S')
00273                         tpg=TOPOLOGY_S;
00274                       else
00275                         {
00276                           fprintf(stderr,"Unknown topology (-t).\n");
00277                           exit(EXIT_FAILURE);
00278                         }
00279                     }
00280                   break;
00281 
00282                 case 4: /* -l */
00283                   found=TRUE;
00284                   i++;
00285                   pLeaf=(unsigned int)atoi(arg[i]);
00286                   if (pLeaf<1)
00287                     {
00288                       fprintf(stderr,"Too smalll number of points in each leaf (-l).\n");
00289                       exit(EXIT_FAILURE);
00290                     }
00291                   break;
00292 
00293                 case 5: /* -r */
00294                   found=TRUE;
00295                   i++;
00296                   searchR=(double)atof(arg[i]);
00297                   if (searchR<=0)
00298                     {
00299                       fprintf(stderr,"The search radius must be positive (-r).\n");
00300                       exit(EXIT_FAILURE);
00301                     }
00302                   break;
00303 
00304                 case 6: /* -m */
00305                   found=TRUE;
00306                   i++;
00307                   rep=(unsigned int)atoi(arg[i]);
00308                   if (rep<1)
00309                     {
00310                       fprintf(stderr,"The number of repetitions must be positive (-m).\n");
00311                       exit(EXIT_FAILURE);
00312                     }
00313                   break;
00314 
00315                 case 7: /* -s */
00316                   found=TRUE;
00317                   i++;
00318                   ri=(unsigned int)atof(arg[i]);
00319                   break;
00320 
00321                 case 8: /* -e */
00322                   found=TRUE;
00323                   i++;
00324                   ri=(unsigned int)atof(arg[i]);
00325                   break;
00326                 }
00327             }
00328           j++;
00329         }
00330 
00331       if (!found)
00332         {
00333           fprintf(stderr,"Unknown command line option %s.\nUse -h for help.\n",arg[i]);
00334           exit(EXIT_FAILURE);
00335         }
00336       i++;
00337     }
00338 
00339   /* Init the random number generator  */
00340   t=time(NULL);  /* Get the time at which input files have been read */
00341   ri=(unsigned int)t;
00342   //ri=1386189846;
00343   randomSet(ri);
00344 
00345   /* Print information about */
00346   printf("\n\n************************************************************\n");
00347   printf("Parameters\n");
00348   printf("  Random seed   : %u\n",ri);
00349   printf("  Topology      : %s\n",(tpg==TOPOLOGY_R?"R":"S"));
00350   printf("  No. points    : %u\n",nPoints);
00351   printf("  Dimension     : %u\n",dim);
00352   printf("  Points in leaf: %u\n",pLeaf);
00353   printf("  Search radius : %f\n",searchR);
00354   if (rep>1)
00355     printf("  Repetitions   : %u\n",rep);
00356   printf("\n");
00357 
00358   /* define the ambient space */
00359   InitRectangle(dim,NULL,NULL,&ambient);
00360   
00361   if (tpg==TOPOLOGY_R)
00362     {
00363       l=-1;
00364       u=1;
00365       topology=NULL;
00366     }
00367   else
00368     {
00369       l=-M_PI;
00370       u=+M_PI;
00371       NEW(topology,dim,unsigned int);
00372       for(i=0;i<dim;i++)
00373         topology[i]=tpg; /* == TOPOLOGY_S */
00374     }
00375    for(i=0;i<dim;i++)
00376      {
00377        SetRectangleLowerLimit(i,l,&ambient);
00378        SetRectangleUpperLimit(i,u,&ambient);
00379      }
00380 
00381   /* Define the points: uniform distribution on a dim-sphere */
00382   printf("Generating %u random points\n\n",nPoints);
00383   NEW(point,nPoints,double*);
00384   for(i=0;i<nPoints;i++)
00385     {
00386       NEW(point[i],dim,double);
00387       #if (POINTS_ON_SPHERE)
00388         for(j=0;j<dim;j++)
00389           point[i][j]=randomNormal();
00390         VectorNormalize(dim,point[i]);
00391       #else
00392         RandomPointInRectangle(point[i],&ambient);
00393       #endif
00394     }
00395 
00396   /* Build the two kd-trees */
00397   printf("Building kd-tree\n");
00398   #ifdef _MPNN
00399     tStart=getTime();
00400     if (topology==NULL)
00401       Ykdt=CreateKDTree(dim);
00402     else
00403       Ykdt=CreateKDTreeT(dim,(int *)topology);
00404     for(i=0;i<nPoints;i++)
00405       AddPoint2KDTree(point[i],Ykdt);
00406     tEnd=getTime();
00407     printf("  MPNN        : %7.3f ms\n",tEnd-tStart);
00408     printf("  MPNN x point: %7.3f ms\n",(tEnd-tStart)/(double)nPoints);
00409   #endif
00410 
00411   tStart=getTime();
00412   for(i=0;i<nPoints;i++)
00413     {
00414       if (i==0)
00415         Mkdt=InitKDTree(&ambient,pLeaf,expansion,1,&(point[i]),&i);
00416       else
00417         AddPoint2KDtree(topology,point[i],i,&Mkdt);
00418     }
00419   tEnd=getTime();
00420   printf("  Cuik        : %7.3f ms\n",tEnd-tStart);
00421   printf("  Cuik x point: %7.3f ms\n\n",(tEnd-tStart)/(double)nPoints);
00422   //printf("    Height    : %u (%u)\n\n",Mkdt->height,(unsigned int)ceil(1+log2((double)nPoints/(double)pLeaf))); 
00423 
00424   /* Define the query point */
00425   printf("Defining the query point\n\n");
00426   NEW(q,dim,double);
00427   RandomPointInRectangle(q,&ambient);
00428 
00429   /* Query the trees */
00430   #ifdef _MPNN
00431     printf("Searching NN\n");
00432     printf("  MPNN kd-tree      : ");
00433     QueryKDTree(q,(int *)&id,&d,Ykdt);
00434     printf("%u\n",id);
00435   #endif
00436 
00437   printf("  Cuik kd-tree      : ");
00438   NearestNeighbour(topology,q,Mkdt);  
00439   printf("%u\n",id);
00440 
00441   printf("  Brute-force search: ");  
00442   dMin=INF;
00443   for(i=0;i<nPoints;i++)
00444     {
00445       d=VectorSquaredDistanceTopologyMin(dMin,dim,topology,point[i],q);
00446       if (d<dMin)
00447         {
00448           idMin=i;
00449           dMin=d;
00450         }
00451     }
00452   printf("%u\n\n",idMin);
00453 
00454   printf("Searching in-ball\n");
00455   #ifdef _MPNN
00456     printf("  MPNN kd-tree      : ");
00457     QueryKDTreeR(q,searchR,(int *)(&n),(int **)(&nn),&dst,Ykdt);
00458     if (n>0)
00459       {
00460         qsort(nn,n,sizeof(unsigned int),CmpUInt);
00461         printf("[%u] ",n);
00462         if (n>10)
00463           {
00464             for(i=0;i<5;i++)
00465               printf("%u ",nn[i]);
00466             printf("... ");
00467             for(i=n-5;i<n;i++)
00468               printf("%u ",nn[i]);
00469           }
00470         else
00471           {
00472             for(i=0;i<n;i++)
00473               printf("%u ",nn[i]);
00474           }
00475         if (n>0)
00476           {
00477             free(nn);
00478             free(dst);
00479           }
00480       }
00481     else
00482       printf("no point");
00483     printf("\n");
00484   #endif
00485 
00486   printf("  Cuik kd-tree      : ");
00487   NeighboursInBall(topology,q,searchR,&n,&nn,Mkdt);
00488   if (n>0)
00489     {
00490       qsort(nn,n,sizeof(unsigned int),CmpUInt);
00491       printf("[%u] ",n);
00492       if (n>10)
00493         {
00494           for(i=0;i<5;i++)
00495             printf("%u ",nn[i]);
00496           printf("... ");
00497           for(i=n-5;i<n;i++)
00498             printf("%u ",nn[i]);
00499         }
00500       else
00501         {
00502           for(i=0;i<n;i++)
00503             printf("%u ",nn[i]);
00504         }
00505       if (n>0)
00506         free(nn);
00507     }
00508   else
00509     printf("no point");
00510   printf("\n");
00511       
00512   printf("  Brute-force search: ");  
00513   r2=searchR*searchR;
00514   n=0;
00515   m=100;
00516   NEW(nn,m,unsigned int);
00517   for(i=0;i<nPoints;i++)
00518     {
00519       if (VectorSquaredDistanceTopologyMin(r2,dim,topology,point[i],q)<r2)
00520         {
00521           if (n==m)
00522             MEM_DUP(nn,m,unsigned int);
00523           nn[n]=i;
00524           n++;
00525         }
00526     }
00527   if (n>0)
00528     {
00529       printf("[%u] ",n);
00530       if (n>10)
00531         {
00532           for(i=0;i<5;i++)
00533             printf("%u ",nn[i]);
00534           printf("... ");
00535           for(i=n-5;i<n;i++)
00536             printf("%u ",nn[i]);
00537         }
00538       else
00539         {
00540           for(i=0;i<n;i++)
00541             printf("%u ",nn[i]);
00542         }
00543     }
00544   else
00545     printf("no point");
00546   free(nn);
00547   printf("\n\n");
00548 
00549   /* If we have to collect statistics about the execution time.... */
00550   if (rep>1)
00551     {
00552       printf("Average time per NN query\n");
00553  
00554       #ifdef _MPNN
00555         tStart=getTime();
00556         for(j=0;j<rep;j++)
00557           {
00558             RandomPointInRectangle(q,&ambient);
00559             QueryKDTree(q,(int *)&id,&d,Ykdt);
00560           }
00561         tEnd=getTime();
00562         printf("  MPNN       : %f ms\n",(tEnd-tStart)/(double)rep);
00563       #endif
00564 
00565       tStart=getTime();
00566       for(j=0;j<rep;j++)
00567         {
00568           RandomPointInRectangle(q,&ambient);
00569           id=NearestNeighbour(topology,q,Mkdt);
00570         }
00571       tEnd=getTime();
00572       printf("  Cuik       : %f ms\n",(tEnd-tStart)/(double)rep);
00573 
00574       tStart=getTime();
00575       for(j=0;j<rep;j++)
00576         {
00577           dMin=INF;
00578           for(i=0;i<nPoints;i++)
00579             {
00580               d=VectorSquaredDistanceTopologyMin(dMin,dim,topology,point[i],q);
00581               if (d<dMin)
00582                 {
00583                   idMin=i;
00584                   dMin=d;
00585                 }
00586             }
00587         }
00588       tEnd=getTime();
00589       printf("  Brute-force: %f ms\n\n",(tEnd-tStart)/(double)rep);
00590 
00591       printf("Average time per in-ball query\n");
00592 
00593       #ifdef _MPNN
00594         tStart=getTime();
00595         for(j=0;j<rep;j++)
00596           {
00597             RandomPointInRectangle(q,&ambient);
00598             QueryKDTreeR(q,searchR,(int *)(&n),(int **)(&nn),&dst,Ykdt);
00599             if (n>0)
00600               {
00601                 free(nn);
00602                 free(dst);
00603               }
00604           }
00605         tEnd=getTime();
00606         printf("  MPNN       : %f ms\n",(tEnd-tStart)/(double)rep);
00607       #endif
00608 
00609       tStart=getTime();
00610       for(j=0;j<rep;j++)
00611         {
00612           RandomPointInRectangle(q,&ambient);
00613           NeighboursInBall(topology,q,searchR,&n,&nn,Mkdt);
00614           if (n>0)
00615             free(nn);
00616         }
00617       tEnd=getTime();
00618       printf("  Cuik       : %f ms\n",(tEnd-tStart)/(double)rep);
00619 
00620       tStart=getTime();
00621       for(j=0;j<rep;j++)
00622         {
00623           RandomPointInRectangle(q,&ambient);
00624           n=0;
00625           m=100;
00626           NEW(nn,m,unsigned int);
00627           for(i=0;i<nPoints;i++)
00628             {
00629               if (VectorSquaredDistanceTopologyMin(r2,dim,topology,point[i],q)<r2)
00630                 {
00631                   if (n==m)
00632                     MEM_DUP(nn,m,unsigned int);
00633                   nn[n]=i;
00634                   n++;
00635                 }
00636             }
00637           free(nn);
00638         }
00639       tEnd=getTime();
00640       printf("  Brute force: %f ms\n\n",(tEnd-tStart)/(double)rep);
00641     }
00642 
00643   /* Release the information */
00644   free(q);
00645 
00646   for(i=0;i<nPoints;i++)
00647     free(point[i]);
00648   free(point);
00649 
00650   if (topology!=NULL)
00651     free(topology);
00652   DeleteRectangle(&ambient);
00653 
00654   DeleteKDtree(Mkdt);
00655   #ifdef _MPNN
00656     DeleteKDTree(Ykdt);
00657   #endif
00658 
00659   return(EXIT_SUCCESS);
00660 }