void fvnGetKNN(unsigned data_dim, unsigned data_size, const float * data, unsigned k, unsigned * KNNs){ //KNNS should be an array of size data_size * data_size unsigned n = data_size; for ( int i = 0 ; i < data_size * data_size ; i ++){ KNNs[i] = 0; } for( int i = 0 ; i < n ; i++){ float sqdistances[n]; for (int j = 0 ; j < n ; j++){ float sqdist = 0; unsigned pos1 = i* data_dim; unsigned pos2 = j* data_dim; for (int k = 0 ; k < data_dim ; k++){ sqdist += pow(data[pos1 + k] - data[pos2+k],2); } sqdistances[j] = sqdist; }; size_t idxs[k]; //take the k+1 smallest in order to ignore the gsl_sort_float_smallest_index(idxs, k + 1, sqdistances, 1, n); for (int j = 0 ; j < k +1 ; j++){ if(idxs[j] != i) KNNs[i + data_size * idxs[j]] = 1; }; }; uvnSymmetrizeMatrix(data_size, KNNs); };
// A basic implementation of brute force k-NN search. This does not // use a heap. Instead it computes all distances and then sorts. void bruteK(matrix x, matrix q, unint **NNs, float **dToNNs, unint k) { int i, j, l; int nt = omp_get_max_threads(); float ***d; size_t ***t; d = (float***)calloc(nt, sizeof(*d)); t = (size_t***)calloc(nt, sizeof(*t)); for(i=0; i<nt; i++) { d[i] = (float**)calloc(CL, sizeof(**d)); t[i] = (size_t**)calloc(CL, sizeof(**t)); for(j=0; j<CL; j++) { d[i][j] = (float*)calloc(x.pr, sizeof(***d)); t[i][j] = (size_t*)calloc(x.pr, sizeof(***t)); } } #pragma omp parallel for private(j,l) shared(d,t,k) for( i=0; i<q.pr/CL; i++) { int row = i*CL; int tn = omp_get_thread_num(); //thread num for( j=0; j<x.r; j++) { for( l=0; l<CL; l++) { d[tn][l][j] = distVec( q, x, row+l, j); } } for(l=0; l<CL; l++) gsl_sort_float_smallest_index(t[tn][l], k, d[tn][l], 1, x.r); for(l=0; l<CL; l++) { if(row+l<q.r) { for(j=0; j<k; j++) { NNs[row+l][j] = (unint)t[tn][l][j]; dToNNs[row+l][j] = d[tn][l][t[tn][l][j]]; } } } } for(i=0; i<nt; i++) { for(j=0; j<CL; j++) { free(d[i][j]); free(t[i][j]); } free(d[i]); free(t[i]); } free(t); free(d); }