void getCopyOfPointfromArrayOfPoints(SPKDArray kdArray, int index, SPPoint* p){ assert (kdArray != NULL); if (kdArray->array_of_points[index]==NULL){ *p = NULL; return; } *p = spPointCopy(kdArray->array_of_points[index]); }
SPKDTreeNode spKDTreeCreateLeaf(SPPoint point){ SPKDTreeNode leaf = (SPKDTreeNode)malloc(sizeof(*leaf)); if (!leaf){ spLoggerPrintError(ALLOC_FAIL, __FILE__, __FUNCTION__, __LINE__); return NULL; } leaf->dim = INVALID; leaf->val = INVALID; leaf->left = NULL; leaf->right = NULL; leaf->data = spPointCopy(point); return leaf; }
SPPoint SPKDArrayGetPointByDim(SPKDArray kdArr, int index, int dim, SP_KDARRAY_MSG* msg) { SPPoint ret; assert(msg != NULL); if (kdArr == NULL || dim < -1 || index < 0 || index >= kdArr->size) { *msg = SP_KDARRAY_INVALID_ARGUMENT; return NULL; } if (dim >= kdArr->dims) { *msg = SP_KDARRAY_INDEX_OUT_OF_RANGE; return NULL; } if (dim == -1) ret = spPointCopy(kdArr->points[index]); else ret = spPointCopy(kdArr->points[kdArr->pointsByCoors[dim][index]]); if (ret == NULL) *msg = SP_KDARRAY_ALLOC_FAIL; else *msg = SP_KDARRAY_SUCCESS; return ret; }
//Checks if copy Works bool pointBasicCopyTest() { double data[2] = { 1.0, 1.0 }; int dim = 2; int index = 1; SPPoint p = spPointCreate(data, dim, index); SPPoint q = spPointCopy(p); ASSERT_TRUE(spPointGetIndex(p) == spPointGetIndex(q)); ASSERT_TRUE(spPointGetDimension(p) == spPointGetDimension(q)); int i; for (i = 0; i < spPointGetDimension(p); i++) { ASSERT_TRUE(spPointGetAxisCoor(p, i) == spPointGetAxisCoor(q, i)); } spPointDestroy(p); spPointDestroy(q); return true; }
/** * A recursive function to construct the kd-tree */ KDTreeNode constructTree(KDArray mat, int size, int dim, int splitMethod, int lastLevelDim) { KDTreeNode newNode; KDArray left, right; SPPoint* p; int splitDim = -1; double medianVal; assert(size > 0); p = kdArrayGetPoints(mat); newNode = (KDTreeNode) malloc(sizeof(*newNode)); if (newNode == NULL ) { spLoggerPrintError(ALLOC_ERROR_MSG, __FILE__, __func__, __LINE__); return NULL ; } if (size == 1) { // creates a new leaf which represents a point newNode->dim = -1; newNode->val = -1; newNode->left = NULL; newNode->right = NULL; newNode->data = spPointCopy(p[0]); return newNode; } if (splitMethod == 0) { // RANDOM srand(time(NULL )); splitDim = rand() % dim; } else if (splitMethod == 1) { // MAX SPREAD double maxSpread; int i; maxSpread = 0; for (i = 0; i < dim; i++) { int minIndex, maxIndex; double spread; minIndex = kdArrayGet(mat, i, 0); maxIndex = kdArrayGet(mat, i, size - 1); spread = spPointGetAxisCoor(p[maxIndex], i) - spPointGetAxisCoor(p[minIndex], i); if (spread >= maxSpread) { maxSpread = spread; splitDim = i; } } } else if (splitMethod == 2) { // INCREMENTAL splitDim = (lastLevelDim + 1) % dim; } left = kdArrayInitEmpty(); if (left == NULL ) return NULL ; right = kdArrayInitEmpty(); if (right == NULL ) { kdArrayDestroy(left); return NULL ; } // compute the median to split according to it medianVal = spPointGetAxisCoor(p[kdArrayGet(mat, splitDim, (size - 1) / 2)], splitDim); kdArraySplit(mat, splitDim, left, right); newNode->dim = splitDim; newNode->val = medianVal; // recursively create the left sub-tree newNode->left = constructTree(left, kdArrayGetSize(left), dim, splitMethod, splitDim); // recursively create the right sub-tree newNode->right = constructTree(right, kdArrayGetSize(right), dim, splitMethod, splitDim); newNode->data = NULL; // not a leaf // free data not needed anymore kdArrayDestroy(left); kdArrayDestroy(right); return newNode; }
int Split(SPKDArray kdArr, int coor, SPKDArray* left_array, SPKDArray* right_array){ int n; // number of points in kdArr int d; // number of dimensions of each point in kdArr int num_of_left_points; // number of points that will be in the left half int num_of_right_points; // number of points that will be in the right half int* is_index_in_left; // array of 0's and 1's. value is 1 if the point in this index is in left half int* map_indexes; // mapping from the indexes of the points in kdArr to the indexes in left or right half int helper_function_result; // holds the result of a call to a helper function int index; int i, j; int L_cnt; //index counter for left_points int R_cnt; //index counter for right_points //check validation of arguments if (coor<0){ spLoggerPrintError(INVALID_ARG_ERROR, __FILE__, __func__, __LINE__); spLoggerPrintDebug(PARAMETER_COOR_INVALID, __FILE__, __func__, __LINE__); return -1; } if (kdArr==NULL){ spLoggerPrintError(INVALID_ARG_ERROR, __FILE__, __func__, __LINE__); spLoggerPrintDebug(PARAMETER_KDARR_INVALID, __FILE__, __func__, __LINE__); return -1; } //initialize n and d n = kdArr->n; d = kdArr->d; //initialize num_of_left_points and num_of_right_points if (n%2==0){ num_of_left_points = n/2; } else{ num_of_left_points = (n+1)/2; } num_of_right_points = n - num_of_left_points; //allocate memory for *left_array -> this is creating a new SPKDArray if ( (helper_function_result = mallocForNewKdArray(left_array, num_of_left_points, d)) == -1){ //free memory of left_array is in mallocForNewKdArray return -1; } //allocate memory for *right_array -> this is creating a new SPKDArray if ( (helper_function_result = mallocForNewKdArray(right_array, num_of_right_points, d)) == -1){ //free memory of right_array is in mallocForNewKdArray destroyKDArray(*left_array); return -1; } //initialize n and d for left_array and right_array (*left_array)->d = d; (*left_array)->n = num_of_left_points; (*right_array)->d = d; (*right_array)->n = num_of_right_points; //allocate memory for is_index_in_left if ( (is_index_in_left = (int*)malloc(n*sizeof(int))) == NULL){ spLoggerPrintError(ALLOC_ERROR_MSG, __FILE__, __func__, __LINE__); destroyKDArray(*left_array); destroyKDArray(*right_array); return -1; } // fill is_index_in_left for (i=0; i<num_of_left_points; i++){ is_index_in_left[kdArr->matrix_of_sorted_indexes[coor][i]] = 1; } for (i=num_of_left_points; i<n; i++){ is_index_in_left[kdArr->matrix_of_sorted_indexes[coor][i]] = 0; } // fill left->array_of_points and right->array_of_points L_cnt=0; //index counter for left_points R_cnt=0; //index counter for right_points for (i=0; i<n; i++){ // i= index counter for is_index_in_left if (is_index_in_left[i]==1){ if( ((*left_array)->array_of_points[L_cnt]= spPointCopy(kdArr->array_of_points[i])) == NULL){ destroyKDArray(*left_array); destroyKDArray(*right_array); free(is_index_in_left); return -1; } L_cnt++; } else{ //is_index_in_left[i]==0 if( ((*right_array)->array_of_points[R_cnt]= spPointCopy(kdArr->array_of_points[i])) ==NULL){ destroyKDArray(*left_array); destroyKDArray(*right_array); free(is_index_in_left); return -1; } R_cnt++; } } //allocate memory for map_indexes if ( (map_indexes= (int*)malloc(n*sizeof(int)))==NULL ){ spLoggerPrintError(ALLOC_ERROR_MSG, __FILE__, __func__, __LINE__); destroyKDArray(*left_array); destroyKDArray(*right_array); free(is_index_in_left); return -1; } //fill map_indexes L_cnt=0; //counter for left R_cnt=0; //counter for right for (i=0; i<n; i++){ if (is_index_in_left[i]==1){ //i is an index that belongs to left map_indexes[i] = L_cnt; L_cnt++; } else{ //i is an index that belongs to right map_indexes[i] = R_cnt; R_cnt++; } } //fill left_array->matrix_of_sorted_indexes and right_array->matrix_of_sorted_indexes L_cnt=0; //counter for left R_cnt=0; //counter for right for (i=0; i<d; i++){ //for number of dimensions for(j=0; j<n; j++){ //for number of points index = kdArr->matrix_of_sorted_indexes[i][j]; if (is_index_in_left[index]==1){ //the index to map belongs to left (*left_array)->matrix_of_sorted_indexes[i][L_cnt] = map_indexes[index]; L_cnt++; } else{ //the index to map belongs to right (*right_array)->matrix_of_sorted_indexes[i][R_cnt] = map_indexes[index]; R_cnt++; } } //reset counters R_cnt=0; L_cnt=0; } //free memory and return free(map_indexes); free(is_index_in_left); return 1; }
SPKDArray Init(SPPoint* arr, int size){ SPKDArray KDArray; int d; // d = the dimension of the points (assuming dimension is the same for all points) double** index_val_arr; //double array containing n rows. each row contains the index and the value of a specific coordinate in the point of that index int i,j; int malloc_result; // holds the result of the call to mallocForNewKdArray //check validation of the parameters if (size<1){ spLoggerPrintError(INVALID_ARG_ERROR, __FILE__, __func__, __LINE__); spLoggerPrintDebug(PARAMETER_SIZE_INVALID, __FILE__, __func__, __LINE__); return NULL; } if (arr==NULL){ spLoggerPrintError(INVALID_ARG_ERROR, __FILE__, __func__, __LINE__); spLoggerPrintDebug(PARAMETER_ARR_INVALID, __FILE__, __func__, __LINE__); return NULL; } //initialize d d = spPointGetDimension(arr[0]); // allocate memory for KDArray and its fields malloc_result = mallocForNewKdArray(&KDArray, size, d); if (malloc_result==-1){ // the memory freeing would already be done inside mallocForInitKdArray return NULL; } //copy each point from arr to KDArray->array_of_points for (i=0; i<size; i++){ KDArray->array_of_points[i] = spPointCopy(arr[i]); //spPointCopy returns NULL if an allocation error occurred if (KDArray->array_of_points[i] == NULL){ spLoggerPrintError(GENERAL_ERROR_MSG, __FILE__, __func__, __LINE__); spLoggerPrintDebug(SPPOINTCOPY_RETURNED_NULL, __FILE__, __func__, __LINE__); destroyKDArray(KDArray); return NULL; } } //allocate memory for index_val_arr: n rows, 2 columns if ( (index_val_arr = (double**)malloc(size*sizeof(double*))) == NULL){ spLoggerPrintError(ALLOC_ERROR_MSG, __FILE__, __func__, __LINE__); destroyKDArray(KDArray); return NULL; } for (i=0; i<size; i++){ if( (index_val_arr[i]=(double*)malloc(2*sizeof(double))) == NULL){ spLoggerPrintError(ALLOC_ERROR_MSG, __FILE__, __func__, __LINE__); for (j=0; j<i; j++){ free(index_val_arr[j]); } free(index_val_arr); destroyKDArray(KDArray); return NULL; } } // for each coordinate for (i=0; i<d; i++){ // i=coordinate // fill index and value of coordinate to val_index_arr for (j=0; j<size; j++){ //j=index of point index_val_arr[j][0] = (double)j; index_val_arr[j][1] = spPointGetAxisCoor(arr[j],i); } /* sort the rows in index_val_arr by the value in the second column, * meaning by the value of the coordinate of each point. * the first column will be the indexes of the points sorted by the values of the coordinate */ qsort(index_val_arr, size, sizeof(index_val_arr[0]), copmareByValue); // fill the sorted indexes in to KDArray->Array for (j=0; j<size; j++){ //j=index of point KDArray->matrix_of_sorted_indexes[i][j] = (int)index_val_arr[j][0]; } } // initialize n and d KDArray->n = size; KDArray->d = d; for (j=0; j<size; j++){ free(index_val_arr[j]); } free(index_val_arr); return KDArray; }
SPKDArray SPKDArrayInit(SPPoint* arr, int size, int dims, SP_KDARRAY_MSG* msg) { SPKDArray kdArr; int i, j, k; SPSortingHelper* sorter; assert(msg != NULL); if (arr == NULL || size <= 0 || dims <= 0) { *msg = SP_KDARRAY_INVALID_ARGUMENT; return NULL; } kdArr = (SPKDArray)malloc(sizeof(*kdArr)); if (kdArr == NULL) { *msg = SP_KDARRAY_ALLOC_FAIL; return NULL; } // Set kdArr fields, allocate memory kdArr->dims = dims; kdArr->size = size; kdArr->points = (SPPoint*)malloc(size * sizeof(SPPoint)); kdArr->pointsByCoors = (int**)malloc(dims * sizeof(int*)); if (kdArr->points == NULL || kdArr->pointsByCoors == NULL) { *msg = SP_KDARRAY_ALLOC_FAIL; free(kdArr->points); free(kdArr); return NULL; } for (i = 0; i < dims; i++) { kdArr->pointsByCoors[i] = (int*)malloc(size * sizeof(int)); if (kdArr->pointsByCoors[i] == NULL) { *msg = SP_KDARRAY_ALLOC_FAIL; for (j = 0; j < i; j++) free(kdArr->pointsByCoors[j]); free(kdArr->pointsByCoors); free(kdArr->points); free(kdArr); return NULL; } } for (i = 0; i < size; i++) // Copy the points kdArr->points[i] = spPointCopy(arr[i]); for (k = 0; k < dims; k++) // Now we sort the points according to dimension k { // Allocate helper array sorter = (SPSortingHelper*)malloc(size * sizeof(SPSortingHelper)); if (sorter == NULL) { *msg = SP_KDARRAY_ALLOC_FAIL; SPKDArrayDestroy(kdArr); return NULL; } for (i = 0; i < size; i++) { // Allocate and initialize sorter[i] sorter[i] = (SPSortingHelper)malloc(sizeof(*sorter[i])); if (sorter[i] == NULL) { *msg = SP_KDARRAY_ALLOC_FAIL; for (j = 0; j < i; j++) free(sorter[j]); free(sorter); SPKDArrayDestroy(kdArr); return NULL; } sorter[i]->point = spPointCopy(kdArr->points[i]); sorter[i]->dim = k; sorter[i]->originalIndex = i; } qsort(sorter, size, sizeof(SPSortingHelper), SPSortingHelperCompare); // Now sort for (i = 0; i < size; i++) // And update the appropriate line of pointsByCoors { kdArr->pointsByCoors[k][i] = sorter[i]->originalIndex; spPointDestroy(sorter[i]->point); free(sorter[i]); } free(sorter); } // Done *msg = SP_KDARRAY_SUCCESS; return kdArr; }
SPKDArray* SPKDArraySplit(SPKDArray kdArr, int coor, SP_KDARRAY_MSG* msg) { bool* isLeft; SPKDArray* ret; int i, j, leftIndex, rightIndex; int sizeOfLeft, sizeOfRight; int* leftMap; int* rightMap; assert(msg != NULL); if (kdArr == NULL || coor < 0) { *msg = SP_KDARRAY_INVALID_ARGUMENT; return NULL; } if (coor >= kdArr->dims) { *msg = SP_KDARRAY_INDEX_OUT_OF_RANGE; return NULL; } ret = (SPKDArray*)malloc(2 * sizeof(SPKDArray)); if (ret == NULL) { *msg = SP_KDARRAY_ALLOC_FAIL; free(ret); return NULL; } // Allocate everything we need ret[0] = (SPKDArray)malloc(sizeof(*ret[0])); ret[1] = (SPKDArray)malloc(sizeof(*ret[1])); if (ret[0] == NULL || ret[1] == NULL) { *msg = SP_KDARRAY_ALLOC_FAIL; free(ret[0]); free(ret[1]); free(ret); return NULL; } sizeOfLeft = kdArr->size / 2 + kdArr->size % 2; sizeOfRight = kdArr->size - sizeOfLeft; ret[0]->pointsByCoors = (int**)malloc(kdArr->dims * sizeof(int*)); ret[0]->points = (SPPoint*)malloc(sizeOfLeft * sizeof(SPPoint)); ret[1]->pointsByCoors = (int**)malloc(kdArr->dims * sizeof(int*)); ret[1]->points = (SPPoint*)malloc(sizeOfRight * sizeof(SPPoint)); if (ret[0]->pointsByCoors == NULL || ret[0]->points == NULL || ret[1]->pointsByCoors == NULL || ret[1]->points == NULL) { *msg = SP_KDARRAY_ALLOC_FAIL; free(ret[0]->pointsByCoors); free(ret[0]->points); free(ret[0]); free(ret[1]->pointsByCoors); free(ret[1]->points); free(ret[1]); free(ret); return NULL; } for (i = 0; i < kdArr->dims; i++) { ret[0]->pointsByCoors[i] = (int*)malloc(sizeOfLeft * sizeof(int)); ret[1]->pointsByCoors[i] = (int*)malloc(sizeOfRight * sizeof(int)); if (ret[0]->pointsByCoors[i] == NULL || ret[1]->pointsByCoors[i] == NULL) { *msg = SP_KDARRAY_ALLOC_FAIL; for (j = 0; j <= i; j++) { free(ret[0]->pointsByCoors[j]); free(ret[1]->pointsByCoors[j]); } free(ret[0]->pointsByCoors); free(ret[0]->points); free(ret[0]); free(ret[1]->pointsByCoors); free(ret[1]->points); free(ret[1]); free(ret); return NULL; } } isLeft = (bool*)malloc(kdArr->size * sizeof(bool)); leftMap = (int*)malloc(kdArr->size * sizeof(int)); rightMap = (int*)malloc(kdArr->size * sizeof(int)); if (isLeft == NULL || leftMap == NULL || rightMap == NULL) { *msg = SP_KDARRAY_ALLOC_FAIL; SPKDArrayDestroy(ret[0]); SPKDArrayDestroy(ret[1]); free(ret); free(isLeft); free(leftMap); free(rightMap); return NULL; } ret[0]->dims = kdArr->dims; ret[0]->size = sizeOfLeft; ret[1]->dims = kdArr->dims; ret[1]->size = sizeOfRight; for (i = 0; i < kdArr->size; i++) // Check for each point if it belongs in the left half isLeft[kdArr->pointsByCoors[coor][i]] = (i < sizeOfLeft ? true : false); rightIndex = 0; leftIndex = 0; for (i = 0; i < kdArr->size; i++) // Update the maps, like in the suggested solution { if (isLeft[i]) { rightMap[i] = -1; leftMap[i] = leftIndex; ret[0]->points[leftIndex] = spPointCopy(kdArr->points[i]); leftIndex++; } else { leftMap[i] = -1; rightMap[i] = rightIndex; ret[1]->points[rightIndex] = spPointCopy(kdArr->points[i]); rightIndex++; } } for (i = 0; i < kdArr->dims; i++) // Set pointsByCoors for the two KD-Arrays { leftIndex = 0; rightIndex = 0; for (j = 0; j < kdArr->size; j++) { if (isLeft[kdArr->pointsByCoors[i][j]]) { ret[0]->pointsByCoors[i][leftIndex] = leftMap[kdArr->pointsByCoors[i][j]]; leftIndex++; } else { ret[1]->pointsByCoors[i][rightIndex] = rightMap[kdArr->pointsByCoors[i][j]]; rightIndex++; } } } // All done free(isLeft); free(leftMap); free(rightMap); return ret; }