int ahc_quantize(DyArray *ahct, float *v, int d){ __assertinfo(ahct == NULL || v == NULL || d <= 0, "IPP"); int iclu; Cluster *pclu; int nchild = 0; int *_vassign = ivec_new(1); float *_vdis = fvec_new(1); iclu = 0; /* traverse all clusters */ while(true){ // locate at the i-th cluster pclu = (Cluster*)DyArray_get(ahct, iclu, 1); if(pclu->type != ClusterType_Leaf){ // if a cluster is not leaf, extract all centroid of its children nchild = pclu->children.count; // linear_knn(pclu->cents, nchild, v, d, 1, _vassign, _vdis); knn_full(2, 1, nchild, d, 1, pclu->cents, v, NULL, _vassign, _vdis); iclu = *(int*)DyArray_get(&pclu->children, _vassign[0], 1); }else{ break; } } FREE(_vassign); FREE(_vdis); return iclu; }
void mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray*prhs[]) { if (nrhs < 2 || nrhs > 4) mexErrMsgTxt ("Invalid number of input arguments"); if (nlhs != 2) mexErrMsgTxt ("2 output arguments required"); int d = mxGetM (prhs[0]); int n = mxGetN (prhs[0]); int nq = mxGetN (prhs[1]); if (mxGetM (prhs[1]) != d) mexErrMsgTxt("Dimension of base and query vectors are not consistent"); if (mxGetClassID(prhs[0]) != mxSINGLE_CLASS || mxGetClassID(prhs[1]) != mxSINGLE_CLASS ) mexErrMsgTxt ("need single precision array"); float *b = (float*) mxGetPr (prhs[0]); /* database vectors */ float *v = (float*) mxGetPr (prhs[1]); /* query vectors */ int k = 1; int distype = 2; if (nrhs >= 3) k = (int) mxGetScalar(prhs[2]); if (nrhs >= 4) distype = (int) mxGetScalar(prhs[3]); if (n < k) mexErrMsgTxt("fewer vectors than number to be returned"); /* ouptut: centroids, assignment, distances */ plhs[0] = mxCreateNumericMatrix (k, nq, mxINT32_CLASS, mxREAL); int *assign = (int*) mxGetPr (plhs[0]); plhs[1] = mxCreateNumericMatrix (k, nq, mxSINGLE_CLASS, mxREAL); float *dis = (float*) mxGetPr (plhs[1]); /* With Matlab, we have to avoid using threads for the L2 distance, because this one makes a call to MKL, which is no thread-safe */ knn_full (distype, nq, n, d, k, b, v, NULL, assign, dis); /* post-processing: convert to matlab indices, and enforce full sort */ int i; for (i = 0 ; i < nq * k ; i++) assign[i]++; }
float *knn (int npt, int nclust, int d, int k, const float *codebook, const float *coords, int *vw) { /* The distances to centroids that will be returned */ float *vwdis = fvec_new(npt * k); knn_full (2, npt, nclust, d, k, codebook, coords, NULL, vw, vwdis); return vwdis; }
static void nn_task (void *arg, int tid, int i) { nn_input_t *t = arg; long n0 = t->npt * (long)i / t->n_thread; long n1 = t->npt * (long)(i + 1) / t->n_thread; knn_full (t->distance_type, n1 - n0, t->nclust, t->d, t->k, t->codebook, t->points + n0 * t->d, t->vw_weights, t->vw + n0 * t->k, t->vwdis + n0 * t->k); }
double nn (int npt, int nclust, int d, const float *codebook, const float *coords, int *vw) { /* The distances to centroids that will be returned */ float *vwdis = fvec_new(npt); knn_full (2, npt, nclust, d, 1, codebook, coords, NULL, vw, vwdis); double toterr = fvec_sum(vwdis, npt); free(vwdis); return toterr; }
void knn_full_thread (int distance_type, int npt, int nclust, int d, int k, const float *codebook, const float *coords, const float *vw_weights, int *vw, float *vwdis2, int n_thread) { if (npt < n_thread || n_thread == 1) { /* too few pts */ return knn_full (distance_type, npt, nclust, d, k, codebook, coords, vw_weights, vw, vwdis2); } nn_input_t task = { distance_type, nclust, d, k, codebook, npt, coords, vw_weights, vw, vwdis2, n_thread }; compute_tasks (n_thread, n_thread, &nn_task, &task); }