#include #include #include #include "GPMkdtree.h" #include "../timer.h" // 'mapping' must be of size 2*N. (array[N], ... array[2*N-1] is used as a temporary buffer). // After the call array[mapping[0]] <= array[mapping[1]] <= ... <= array[mapping[N-1]]. // array is not modified. template inline void sort(Type* array, int array_skip, int* mapping, int N) { // mergesort int i; int* mappingSrc = mapping; int* mappingDst = mapping + N; int* pSrc1; int* pSrc2; int* pSrc1End; int* pSrc2End; int* pDst; for (i=0; i<(N&(~1)); i+=2) { if (array[array_skip*i] < array[array_skip*(i+1)]) { mappingSrc[i] = i; mappingSrc[i+1] = i+1; } else { mappingSrc[i] = i+1; mappingSrc[i+1] = i; } } if (i != N) mappingSrc[i] = i; int step; for (step=2; step= mappingSrc + N) { memcpy(pDst, pSrc1, (int)((char*)(mappingSrc + N) - (char*)pSrc1)); break; } pSrc2 = pSrc1End; pSrc2End = pSrc2 + step; if (pSrc2End > mappingSrc + N) pSrc2End = mappingSrc + N; while ( 1 ) { if (array[(array_skip)*(*pSrc1)] < array[array_skip*(*pSrc2)]) { *pDst ++ = *pSrc1 ++; if (pSrc1 == pSrc1End) { memcpy(pDst, pSrc2, (int)((char*)pSrc2End - (char*)pSrc2)); pDst = (int*) ((char*)pDst + (int)((char*)pSrc2End - (char*)pSrc2)); break; } } else { *pDst ++ = *pSrc2 ++; if (pSrc2 == pSrc2End) { memcpy(pDst, pSrc1, (int)((char*)pSrc1End - (char*)pSrc1)); pDst = (int*) ((char*)pDst + (int)((char*)pSrc1End - (char*)pSrc1)); break; } } } } pDst = mappingDst; mappingDst = mappingSrc; mappingSrc = pDst; } if (mappingSrc != mapping) memcpy(mapping, mappingSrc, N*sizeof(int)); } ////////////////////////////////////////////////////////////////////////////////////////// #define NEIGHBOR_PARENT(k) (((k)-1)>>1) #define NEIGHBOR_FIRST_CHILD(k) (((k)<<1)+1) Neighbors::Neighbors() { K_max = 0; dist_array = NULL; } Neighbors::~Neighbors() { if (dist_array) delete [] dist_array; } void Neighbors::Init(int _K, PointId* _array) { K = _K; array = _array; num = 0; if (K > K_max) { if (dist_array) delete [] dist_array; K_max = K; dist_array = new double[K_max]; } } inline void Neighbors::Swap(int k1, int k2) { PointId p = array[k1]; array[k1] = array[k2]; array[k2] = p; double d = dist_array[k1]; dist_array[k1] = dist_array[k2]; dist_array[k2] = d; } inline void Neighbors::Add(PointId p, double dist) { int k; if (num < K) { k = num ++; array[k] = p; dist_array[k] = dist; while ( k > 0 ) { int k_parent = NEIGHBOR_PARENT(k); if (dist_array[k] <= dist_array[k_parent]) break; Swap(k, k_parent); k = k_parent; } } else { if (dist_array[0] <= dist) return; array[0] = p; dist_array[0] = dist; k = 0; while ( 1 ) { int k_child = NEIGHBOR_FIRST_CHILD(k); if (k_child >= K) break; if (k_child+1 < K && dist_array[k_child+1] > dist_array[k_child]) k_child ++; if (dist_array[k] >= dist_array[k_child]) break; Swap(k, k_child); k = k_child; } } //for (k=1; k 0); return dist_array[0]; } ////////////////////////////////////////////////////////////////////////////////////////// GPMKDTree::GPMKDTree(int _D, int _point_num, REAL* coords, GeomPerfectMatching* _GPM) : D(_D), DIM(_GPM->DIM), point_num(_point_num), GPM(_GPM) { Node* i; Node* j; int d, d0, k; int* mapping = new int[(D+2)*point_num]; int* buf = mapping + D*point_num; int* marking = buf + point_num; memset(marking, 0, point_num*sizeof(int)); int* ptr = mapping; int node_num_max = 4*point_num/3+2; nodes = (Node*)malloc(node_num_max*sizeof(Node)); rev_mapping = (Node**)malloc(point_num*sizeof(Node*)); memset(rev_mapping, 0, point_num*sizeof(Node*)); REAL** coords_array = new REAL*[D]; int* skip_array = new int[D]; for (d=0; dsums; skip_array[d] = 1; } for (d=0; d(coords_array[d], skip_array[d], ptr, point_num); if (d == DIM) sum_max = GPM->sums[ptr[point_num-1]]; ptr += point_num; } nodes[0].parent = NULL; nodes[0].order = 0; nodes[0].d = point_num; nodes[0].first_child = NULL; node_num = 1; Node* first_unprocessed = &nodes[0]; while ( (i=first_unprocessed) ) { first_unprocessed = i->first_child; int start = i->order; int num0 = i->d, num; if ((DIM==D && num0<=2) || (DIMd = -num0; for (k=0; kpoints[k] = mapping[start+k]; rev_mapping[mapping[start+k]] = i; } continue; } // not a leaf. if (node_num + 2 > node_num_max) { node_num_max = 3*node_num_max/2 + 16; Node* nodes_old = nodes; nodes = (Node*)realloc(nodes, node_num_max*sizeof(Node)); #define UPDATE_NODE_PTR(ptr) ptr = (Node*)((char*)ptr + ((char*)nodes-(char*)nodes_old)) UPDATE_NODE_PTR(i); if (first_unprocessed) UPDATE_NODE_PTR(first_unprocessed); for (k=0; k=0 && nodes[k].first_child) UPDATE_NODE_PTR(nodes[k].first_child); } for (k=0; kparent) ? ((i->parent->d + 1) % D) : 0; //num = num0/2; const int FRACTION = 20; int num_min = 1; if (num_min < num0/FRACTION) num_min = num0/FRACTION; int num_max = num0-1; if (num_max > (FRACTION-1)*num0/FRACTION) num_max = (FRACTION-1)*num0/FRACTION; int num_max_DIM = num0-1; if (D>DIM && (!i->parent || !i->parent->parent || !i->parent->parent->parent)) d0 = D-1; else { d0 = -1; REAL diff_max = 0; for (d=0; d split) break; } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// ptr = mapping + d0*point_num; for (k=start; kd = d0; PointId p = ptr[start + num - ((num >= num0-num) ? 1 : 0)]; i->coord = coords_array[d0][p*skip_array[d0]]; i->first_child = j = &nodes[node_num]; node_num += 2; j->parent = (j+1)->parent = i; j->order = start; j->d = num; (j+1)->order = start+num; (j+1)->d = num0-num; (j+1)->first_child = first_unprocessed; j->first_child = j+1; first_unprocessed = j; } delete [] coords_array; delete [] skip_array; delete [] mapping; //////////////////////////////////////////////////////////////////////////////////// // set ordering and depth_max int depth = 0, depth_max = 0; // set ordering i = &nodes[0]; k = 0; if (D > DIM) { // ordering for AddNegativeEdges() - tree preorder while ( 1 ) { if (!IS_LEAF(i)) { i = i->first_child; depth ++; if (depth_max < depth) depth_max = depth; } else { while ( 1 ) { i->order = k ++; if (!i->parent) break; if (i->parent->first_child == i) { i ++; break; } i = i->parent; depth --; } if (!i->parent) break; } } } else { // compute tree inorder - useful for nearest neighbor search so that that branches close to the input node are explored first while ( 1 ) { if (!IS_LEAF(i)) { i = i->first_child; depth ++; if (depth_max < depth) depth_max = depth; } else { i->order = k ++; while ( 1 ) { if (!i->parent) break; if (i->parent->first_child == i) { i->parent->order = k ++; i ++; break; } i = i->parent; depth --; } if (!i->parent) break; } } } traversing_buf = (REAL*) malloc((D + depth_max + 2)*sizeof(REAL)); } GPMKDTree::~GPMKDTree() { free(nodes); free(rev_mapping); free(traversing_buf); } void GPMKDTree::AddPerfectMatching(PointId* rev_mapping) { Node* i; int k; PointId p, q = -1; i = &nodes[0]; do { if (IS_LEAF(i)) { for (k=0; k<-i->d; k++) { p = i->points[k]; if (q < 0) q = p; else { GPM->AddInitialEdge(rev_mapping[p], rev_mapping[q]); q = -1; } } } else { i = i->first_child; continue; } while ( i->parent ) { if (i->parent->first_child == i) { i ++; break; } i = i->parent; } } while (i->parent); } ////////////////////////////////////////////////////////////////////////////////////////// #define MOVE_DOWN_LEFT(i)\ {\ *stack ++ = current_diff[i->d];\ if (current_diff[i->d] <= 0 && (diff = i->coord - coord0[i->d]) < 0) current_diff[i->d] = diff;\ i = i->first_child;\ } #define MOVE_DOWN_RIGHT(i)\ {\ *stack ++ = current_diff[i->d];\ if (current_diff[i->d] >= 0 && (diff = i->coord - coord0[i->d]) > 0) current_diff[i->d] = diff;\ i = i->first_child+1;\ } #define MOVE_LEFT(i)\ {\ int d_prev = i->parent->d;\ current_diff[d_prev] = stack[-1];\ if (current_diff[d_prev] <= 0 && (diff = i->parent->coord - coord0[d_prev]) < 0) current_diff[d_prev] = diff;\ i --;\ } #define MOVE_RIGHT(i)\ {\ int d_prev = i->parent->d;\ current_diff[d_prev] = stack[-1];\ if (current_diff[d_prev] >= 0 && (diff = i->parent->coord - coord0[d_prev]) > 0) current_diff[d_prev] = diff;\ i ++;\ } #define MOVE_UP(i)\ {\ i = i->parent;\ current_diff[i->d] = *(-- stack);\ } ////////////////////////////////////////////////////////////////////////////////////////// #define MOVE_DOWN_LEFT_X(i)\ {\ *stack ++ = current_diff[i->d];\ if (i->d < D-1) { if (current_diff[i->d] <= 0 && (diff = i->coord - coord0[i->d]) < 0) current_diff[i->d] = diff; }\ else current_diff[i->d] = i->coord;\ i = i->first_child;\ } #define MOVE_DOWN_RIGHT_X(i)\ {\ *stack ++ = current_diff[i->d];\ if (i->d < D-1) { if (current_diff[i->d] >= 0 && (diff = i->coord - coord0[i->d]) > 0) current_diff[i->d] = diff; }\ i = i->first_child+1;\ } #define MOVE_LEFT_X(i)\ {\ int d_prev = i->parent->d;\ current_diff[d_prev] = stack[-1];\ if (d_prev < D-1) { if (current_diff[d_prev] <= 0 && (diff = i->parent->coord - coord0[d_prev]) < 0) current_diff[d_prev] = diff; }\ else current_diff[d_prev] = i->parent->coord;\ i --;\ } #define MOVE_RIGHT_X(i)\ {\ int d_prev = i->parent->d;\ current_diff[d_prev] = stack[-1];\ if (d_prev < D-1) { if (current_diff[d_prev] >= 0 && (diff = i->parent->coord - coord0[d_prev]) > 0) current_diff[d_prev] = diff; }\ i ++;\ } #define MOVE_UP_X(i)\ {\ i = i->parent;\ current_diff[i->d] = *(-- stack);\ } ////////////////////////////////////////////////////////////////////////////////////////// /* void GPMKDTree::ComputeKNN(PointId p0, int K, PointId* neighbors_array) { int p; REAL* coord0 = GPM->coords + p0*DIM; neighbors.Init(K, neighbors_array); for (p=0; pDist(coord0, GPM->coords+p*DIM)); } } */ void GPMKDTree::ComputeKNN(PointId p0, int K, PointId* neighbors_array) { int neighbor_num = 0; Node* i = rev_mapping[p0]; int k, order0 = i->order; REAL diff; REAL* coords = GPM->coords; REAL* coord0 = GPM->coords + p0*DIM; REAL* current_diff = traversing_buf; REAL* stack = traversing_buf + D; neighbors.Init(K, neighbors_array); for (k=0; kd; k++) { PointId p = i->points[k]; if (p == p0) continue; double dist2; REAL* coord2 = coords+p*DIM; GPM_GET_DIST2(dist2, coord0, coord2); neighbors.Add(p, dist2); } } else { if (neighbors.GetNum() < K || GPM->Norm2(current_diff) < neighbors.GetMax()) { if (i->order > order0) { MOVE_DOWN_LEFT(i); } else { MOVE_DOWN_RIGHT(i); } continue; } } while ( i->parent ) { if (i->parent->order > order0) { if (i->parent->first_child == i) { MOVE_RIGHT(i); break; } } else { if (i->parent->first_child != i) { MOVE_LEFT(i); break; } } MOVE_UP(i); } } while ( i->parent ); } ////////////////////////////////////////////////////////////////////////////////////////// /* void GPMKDTree::AddNegativeEdges(PointId p, PerfectMatching* pm) { PointId q; for (q=p+1; qnodes[q].is_marked) continue; REAL len = GPM->Dist(p, q); if (2*len - GPM->sums[p] - GPM->sums[q] < 0) { if (pm->AddNewEdge(p, q, len, true)>=0) { GPM->AddInitialEdge(p, q); } } } } */ void GPMKDTree::AddNegativeEdges(PointId p0, PerfectMatching* pm) { Node* i = rev_mapping[p0]; int k, order0 = i->order; bool check; REAL diff; REAL* coords = GPM->coords; REAL* coord0 = coords + p0*DIM; REAL* sums = GPM->sums; REAL sum0 = sums[p0]; REAL* current_diff = traversing_buf; REAL* stack = traversing_buf + D; for (k=0; i->points[k]!=p0; k++) {} for (k++; k<-i->d; k++) { PointId p = i->points[k]; REAL len = GPM->Dist(coord0, GPM->coords+p*DIM); if (2*len - GPM->sums[p] < GPM->sums[p0]) { double start_time = get_time(); if (pm->AddNewEdge(p0, p, len, true)>=0) GPM->AddInitialEdge(p0, p); GPM->graph_update_time += get_time() - start_time; } } for (k=0; korder > order0) { if (IS_LEAF(i)) { for (k=0; k<-i->d; k++) { PointId p = i->points[k]; if (!GPM->nodes[p].is_marked) { //REAL* coord2 = coords+p*DIM; //REAL threshold = sums[p0]+sums[p]; //GPM_CHECK_DIST(check, coord0, coord2, threshold); //if (check) { REAL len = GPM->Dist(coord0, GPM->coords+p*DIM); if (2*len - GPM->sums[p] < GPM->sums[p0]) { double start_time = get_time(); if (pm->AddNewEdge(p0, p, len, true)>=0) GPM->AddInitialEdge(p0, p); GPM->graph_update_time += get_time() - start_time; } } } } } else { REAL threshold = current_diff[D-1] + sum0; GPM_CHECK_NORM(check, current_diff, threshold); if (check) { MOVE_DOWN_LEFT_X(i); continue; } } } while ( i->parent ) { if (i->parent->first_child == i) { MOVE_RIGHT_X(i); break; } MOVE_UP_X(i); } } while (i->parent); }