void test_simple(int verbose) { VlKDForest *forest; int i, j; float *data, *query; vl_size dim = 128; vl_size num = 10000; vl_size numTrees = 1; /* * create a test data */ if((data = create_data(dim ,num)) == NULL){ printf("not enough memoey\n"); exit(1); } if(verbose) printf("has created a test data\n"); if((query = (float *)malloc(dim * sizeof(float))) == NULL){ printf("not enough memoey\n"); exit(1); } for(i = 0;i < dim; i++) query[i] = 0.5; if(verbose) printf("has created a query\n"); /* * build a kd-tree forest */ forest = kdtreebuild(1, dim, numTrees, VL_KDTREE_MEDIAN, num, data); if(verbose) printf("has created a forest\n"); if(verbose && 0){ for(j = 0;j < numTrees; j++){ printf("dataIndex[%d] = [", j); for(i = 0;i < forest->numData; i++){ printf("%d ", forest->trees[j]->dataIndex[i].index + 1); } printf("]\n"); } } /* * save */ save_data("data.bin", data, dim, num); save_VlKDForest("forest.bin", forest); /* * search neighbors */ vl_size numNeighbors = 10; unsigned int numComparisons = 0 ; unsigned int maxNumComparisons = 0 ; VlKDForestNeighbor * neighbors ; vl_kdforest_set_max_num_comparisons (forest, maxNumComparisons) ; neighbors = vl_malloc (sizeof(VlKDForestNeighbor) * numNeighbors) ; numComparisons = vl_kdforest_query (forest, neighbors, numNeighbors, query); for(i = 0;i < numNeighbors; i++){ printf("%d %f\n", neighbors[i].index + 1, neighbors[i].distance); /* check distance */ if(fabs( dist_l2(dim, query, &data[neighbors[i].index * dim]) - neighbors[i].distance) > 1e-6){ printf("%d distance is different. %f\n", dist_l2(dim, query, &data[neighbors[i].index * dim]) ); } /* check order */ if(i != 0 && neighbors[i-1].distance > neighbors[i].distance){ printf("order is wrong.\n"); } } vl_free(neighbors); vl_kdforest_delete(forest); free(data); free(query); }
/************************************************************************* Testing Nearest Neighbor Search on uniformly distributed hypercube NormType: 0, 1, 2 D: space dimension N: points count *************************************************************************/ static void testkdtuniform(const ap::real_2d_array& xy, const int& n, const int& nx, const int& ny, const int& normtype, bool& kdterrors) { double errtol; ap::integer_1d_array tags; ap::real_1d_array ptx; ap::real_1d_array tmpx; ap::boolean_1d_array tmpb; kdtree treex; kdtree treexy; kdtree treext; ap::real_2d_array qx; ap::real_2d_array qxy; ap::integer_1d_array qtags; ap::real_1d_array qr; int kx; int kxy; int kt; int kr; double eps; int i; int j; int k; int task; bool isequal; double r; int q; int qcount; qcount = 10; // // Tol - roundoff error tolerance (for '>=' comparisons) // errtol = 100000*ap::machineepsilon; // // fill tags // tags.setlength(n); for(i = 0; i <= n-1; i++) { tags(i) = i; } // // build trees // kdtreebuild(xy, n, nx, 0, normtype, treex); kdtreebuild(xy, n, nx, ny, normtype, treexy); kdtreebuildtagged(xy, tags, n, nx, 0, normtype, treext); // // allocate arrays // tmpx.setlength(nx); tmpb.setlength(n); qx.setlength(n, nx); qxy.setlength(n, nx+ny); qtags.setlength(n); qr.setlength(n); ptx.setlength(nx); // // test general K-NN queries (with self-matches): // * compare results from different trees (must be equal) and // check that correct (value,tag) pairs are returned // * test results from XT tree - let R be radius of query result. // then all points not in result must be not closer than R. // for(q = 1; q <= qcount; q++) { // // Select K: 1..N // if( ap::fp_greater(ap::randomreal(),0.5) ) { k = 1+ap::randominteger(n); } else { k = 1; } // // Select point (either one of the points, or random) // if( ap::fp_greater(ap::randomreal(),0.5) ) { i = ap::randominteger(n); ap::vmove(&ptx(0), 1, &xy(i, 0), 1, ap::vlen(0,nx-1)); } else { for(i = 0; i <= nx-1; i++) { ptx(i) = 2*ap::randomreal()-1; } } // // Test: // * consistency of results from different queries // * points in query are IN the R-sphere (or at the boundary), // and points not in query are outside of the R-sphere (or at the boundary) // * distances are correct and are ordered // kx = kdtreequeryknn(treex, ptx, k, true); kxy = kdtreequeryknn(treexy, ptx, k, true); kt = kdtreequeryknn(treext, ptx, k, true); if( kx!=k||kxy!=k||kt!=k ) { kdterrors = true; return; } kx = 0; kxy = 0; kt = 0; kdtreequeryresultsx(treex, qx, kx); kdtreequeryresultsxy(treexy, qxy, kxy); kdtreequeryresultstags(treext, qtags, kt); kdtreequeryresultsdistances(treext, qr, kr); if( kx!=k||kxy!=k||kt!=k||kr!=k ) { kdterrors = true; return; } kdterrors = kdterrors||kdtresultsdifferent(xy, n, qx, qxy, qtags, k, nx, ny); for(i = 0; i <= n-1; i++) { tmpb(i) = true; } r = 0; for(i = 0; i <= k-1; i++) { tmpb(qtags(i)) = false; ap::vmove(&tmpx(0), 1, &ptx(0), 1, ap::vlen(0,nx-1)); ap::vsub(&tmpx(0), 1, &qx(i, 0), 1, ap::vlen(0,nx-1)); r = ap::maxreal(r, vnorm(tmpx, nx, normtype)); } for(i = 0; i <= n-1; i++) { if( tmpb(i) ) { ap::vmove(&tmpx(0), 1, &ptx(0), 1, ap::vlen(0,nx-1)); ap::vsub(&tmpx(0), 1, &xy(i, 0), 1, ap::vlen(0,nx-1)); kdterrors = kdterrors||ap::fp_less(vnorm(tmpx, nx, normtype),r*(1-errtol)); } } for(i = 0; i <= k-2; i++) { kdterrors = kdterrors||ap::fp_greater(qr(i),qr(i+1)); } for(i = 0; i <= k-1; i++) { ap::vmove(&tmpx(0), 1, &ptx(0), 1, ap::vlen(0,nx-1)); ap::vsub(&tmpx(0), 1, &xy(qtags(i), 0), 1, ap::vlen(0,nx-1)); kdterrors = kdterrors||ap::fp_greater(fabs(vnorm(tmpx, nx, normtype)-qr(i)),errtol); } } // // test general approximate K-NN queries (with self-matches): // * compare results from different trees (must be equal) and // check that correct (value,tag) pairs are returned // * test results from XT tree - let R be radius of query result. // then all points not in result must be not closer than R/(1+Eps). // for(q = 1; q <= qcount; q++) { // // Select K: 1..N // if( ap::fp_greater(ap::randomreal(),0.5) ) { k = 1+ap::randominteger(n); } else { k = 1; } // // Select Eps // eps = 0.5+ap::randomreal(); // // Select point (either one of the points, or random) // if( ap::fp_greater(ap::randomreal(),0.5) ) { i = ap::randominteger(n); ap::vmove(&ptx(0), 1, &xy(i, 0), 1, ap::vlen(0,nx-1)); } else { for(i = 0; i <= nx-1; i++) { ptx(i) = 2*ap::randomreal()-1; } } // // Test: // * consistency of results from different queries // * points in query are IN the R-sphere (or at the boundary), // and points not in query are outside of the R-sphere (or at the boundary) // * distances are correct and are ordered // kx = kdtreequeryaknn(treex, ptx, k, true, eps); kxy = kdtreequeryaknn(treexy, ptx, k, true, eps); kt = kdtreequeryaknn(treext, ptx, k, true, eps); if( kx!=k||kxy!=k||kt!=k ) { kdterrors = true; return; } kx = 0; kxy = 0; kt = 0; kdtreequeryresultsx(treex, qx, kx); kdtreequeryresultsxy(treexy, qxy, kxy); kdtreequeryresultstags(treext, qtags, kt); kdtreequeryresultsdistances(treext, qr, kr); if( kx!=k||kxy!=k||kt!=k||kr!=k ) { kdterrors = true; return; } kdterrors = kdterrors||kdtresultsdifferent(xy, n, qx, qxy, qtags, k, nx, ny); for(i = 0; i <= n-1; i++) { tmpb(i) = true; } r = 0; for(i = 0; i <= k-1; i++) { tmpb(qtags(i)) = false; ap::vmove(&tmpx(0), 1, &ptx(0), 1, ap::vlen(0,nx-1)); ap::vsub(&tmpx(0), 1, &qx(i, 0), 1, ap::vlen(0,nx-1)); r = ap::maxreal(r, vnorm(tmpx, nx, normtype)); } for(i = 0; i <= n-1; i++) { if( tmpb(i) ) { ap::vmove(&tmpx(0), 1, &ptx(0), 1, ap::vlen(0,nx-1)); ap::vsub(&tmpx(0), 1, &xy(i, 0), 1, ap::vlen(0,nx-1)); kdterrors = kdterrors||ap::fp_less(vnorm(tmpx, nx, normtype),r*(1-errtol)/(1+eps)); } } for(i = 0; i <= k-2; i++) { kdterrors = kdterrors||ap::fp_greater(qr(i),qr(i+1)); } for(i = 0; i <= k-1; i++) { ap::vmove(&tmpx(0), 1, &ptx(0), 1, ap::vlen(0,nx-1)); ap::vsub(&tmpx(0), 1, &xy(qtags(i), 0), 1, ap::vlen(0,nx-1)); kdterrors = kdterrors||ap::fp_greater(fabs(vnorm(tmpx, nx, normtype)-qr(i)),errtol); } } // // test general R-NN queries (with self-matches): // * compare results from different trees (must be equal) and // check that correct (value,tag) pairs are returned // * test results from XT tree - let R be radius of query result. // then all points not in result must be not closer than R. // for(q = 1; q <= qcount; q++) { // // Select R // if( ap::fp_greater(ap::randomreal(),0.3) ) { r = ap::maxreal(ap::randomreal(), ap::machineepsilon); } else { r = ap::machineepsilon; } // // Select point (either one of the points, or random) // if( ap::fp_greater(ap::randomreal(),0.5) ) { i = ap::randominteger(n); ap::vmove(&ptx(0), 1, &xy(i, 0), 1, ap::vlen(0,nx-1)); } else { for(i = 0; i <= nx-1; i++) { ptx(i) = 2*ap::randomreal()-1; } } // // Test: // * consistency of results from different queries // * points in query are IN the R-sphere (or at the boundary), // and points not in query are outside of the R-sphere (or at the boundary) // * distances are correct and are ordered // kx = kdtreequeryrnn(treex, ptx, r, true); kxy = kdtreequeryrnn(treexy, ptx, r, true); kt = kdtreequeryrnn(treext, ptx, r, true); if( kxy!=kx||kt!=kx ) { kdterrors = true; return; } kx = 0; kxy = 0; kt = 0; kdtreequeryresultsx(treex, qx, kx); kdtreequeryresultsxy(treexy, qxy, kxy); kdtreequeryresultstags(treext, qtags, kt); kdtreequeryresultsdistances(treext, qr, kr); if( kxy!=kx||kt!=kx||kr!=kx ) { kdterrors = true; return; } kdterrors = kdterrors||kdtresultsdifferent(xy, n, qx, qxy, qtags, kx, nx, ny); for(i = 0; i <= n-1; i++) { tmpb(i) = true; } for(i = 0; i <= kx-1; i++) { tmpb(qtags(i)) = false; } for(i = 0; i <= n-1; i++) { ap::vmove(&tmpx(0), 1, &ptx(0), 1, ap::vlen(0,nx-1)); ap::vsub(&tmpx(0), 1, &xy(i, 0), 1, ap::vlen(0,nx-1)); if( tmpb(i) ) { kdterrors = kdterrors||ap::fp_less(vnorm(tmpx, nx, normtype),r*(1-errtol)); } else { kdterrors = kdterrors||ap::fp_greater(vnorm(tmpx, nx, normtype),r*(1+errtol)); } } for(i = 0; i <= kx-2; i++) { kdterrors = kdterrors||ap::fp_greater(qr(i),qr(i+1)); } } // // Test self-matching: // * self-match - nearest neighbor of each point in XY is the point itself // * no self-match - nearest neighbor is NOT the point itself // if( n>1 ) { // // test for N=1 have non-general form, but it is not really needed // for(task = 0; task <= 1; task++) { for(i = 0; i <= n-1; i++) { ap::vmove(&ptx(0), 1, &xy(i, 0), 1, ap::vlen(0,nx-1)); kx = kdtreequeryknn(treex, ptx, 1, task==0); kdtreequeryresultsx(treex, qx, kx); if( kx!=1 ) { kdterrors = true; return; } isequal = true; for(j = 0; j <= nx-1; j++) { isequal = isequal&&ap::fp_eq(qx(0,j),ptx(j)); } if( task==0 ) { kdterrors = kdterrors||!isequal; } else { kdterrors = kdterrors||isequal; } } } } }