[
  {
    "path": ".gitignore",
    "content": "# Object files\n*.o\n*.ko\n*.obj\n*.elf\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Libraries\n*.lib\n*.a\n*.la\n*.lo\n\n# Shared objects (inc. Windows DLLs)\n*.dll\n*.so\n*.so.*\n*.dylib\n\n# Executables\n*.exe\n*.out\n*.app\n*.i*86\n*.x86_64\n*.hex\n\n# Debug files\n*.dSYM/\n*.su\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 2.8)\n\nfind_package(OpenCV REQUIRED)\ninclude_directories(${OpenCV_INCLUDE_DIRS})\n\nif (CMAKE_COMPILER_IS_GNUCXX)\n\tset(CMAKE_CXX_FLAGS \"-std=c++11 -Wall -O3\")\nendif (CMAKE_COMPILER_IS_GNUCXX)\n\nfile(GLOB srcs *.c *.cpp *.h*)\n\nadd_executable(kdtree ${srcs})\ntarget_link_libraries(kdtree ${OpenCV_LIBS})"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 Leo Ma\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "# CMAKE generated file: DO NOT EDIT!\n# Generated by \"Unix Makefiles\" Generator, CMake Version 3.26\n\n# Default target executed when no arguments are given to make.\ndefault_target: all\n.PHONY : default_target\n\n# Allow only one \"make -f Makefile2\" at a time, but pass parallelism.\n.NOTPARALLEL:\n\n#=============================================================================\n# Special targets provided by cmake.\n\n# Disable implicit rules so canonical targets will work.\n.SUFFIXES:\n\n# Disable VCS-based implicit rules.\n% : %,v\n\n# Disable VCS-based implicit rules.\n% : RCS/%\n\n# Disable VCS-based implicit rules.\n% : RCS/%,v\n\n# Disable VCS-based implicit rules.\n% : SCCS/s.%\n\n# Disable VCS-based implicit rules.\n% : s.%\n\n.SUFFIXES: .hpux_make_needs_suffix_list\n\n# Command-line flag to silence nested $(MAKE).\n$(VERBOSE)MAKESILENT = -s\n\n#Suppress display of executed commands.\n$(VERBOSE).SILENT:\n\n# A target that is always out of date.\ncmake_force:\n.PHONY : cmake_force\n\n#=============================================================================\n# Set environment variables for the build.\n\n# The shell in which to execute make rules.\nSHELL = /bin/sh\n\n# The CMake executable.\nCMAKE_COMMAND = /home/zhen/.local/lib/python3.10/site-packages/cmake/data/bin/cmake\n\n# The command to remove a file.\nRM = /home/zhen/.local/lib/python3.10/site-packages/cmake/data/bin/cmake -E rm -f\n\n# Escaping for special characters.\nEQUALS = =\n\n# The top-level source directory on which CMake was run.\nCMAKE_SOURCE_DIR = /home/zhen/work_wls/kdtree\n\n# The top-level build directory on which CMake was run.\nCMAKE_BINARY_DIR = /home/zhen/work_wls/kdtree\n\n#=============================================================================\n# Targets provided globally by CMake.\n\n# Special rule for the target edit_cache\nedit_cache:\n\t@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan \"No interactive CMake dialog available...\"\n\t/home/zhen/.local/lib/python3.10/site-packages/cmake/data/bin/cmake -E echo No\\ interactive\\ CMake\\ dialog\\ available.\n.PHONY : edit_cache\n\n# Special rule for the target edit_cache\nedit_cache/fast: edit_cache\n.PHONY : edit_cache/fast\n\n# Special rule for the target rebuild_cache\nrebuild_cache:\n\t@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan \"Running CMake to regenerate build system...\"\n\t/home/zhen/.local/lib/python3.10/site-packages/cmake/data/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)\n.PHONY : rebuild_cache\n\n# Special rule for the target rebuild_cache\nrebuild_cache/fast: rebuild_cache\n.PHONY : rebuild_cache/fast\n\n# The main all target\nall: cmake_check_build_system\n\t$(CMAKE_COMMAND) -E cmake_progress_start /home/zhen/work_wls/kdtree/CMakeFiles /home/zhen/work_wls/kdtree//CMakeFiles/progress.marks\n\t$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 all\n\t$(CMAKE_COMMAND) -E cmake_progress_start /home/zhen/work_wls/kdtree/CMakeFiles 0\n.PHONY : all\n\n# The main clean target\nclean:\n\t$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 clean\n.PHONY : clean\n\n# The main clean target\nclean/fast: clean\n.PHONY : clean/fast\n\n# Prepare targets for installation.\npreinstall: all\n\t$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 preinstall\n.PHONY : preinstall\n\n# Prepare targets for installation.\npreinstall/fast:\n\t$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 preinstall\n.PHONY : preinstall/fast\n\n# clear depends\ndepend:\n\t$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1\n.PHONY : depend\n\n#=============================================================================\n# Target rules for targets named kdtree\n\n# Build rule for target.\nkdtree: cmake_check_build_system\n\t$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 kdtree\n.PHONY : kdtree\n\n# fast build rule for target.\nkdtree/fast:\n\t$(MAKE) $(MAKESILENT) -f CMakeFiles/kdtree.dir/build.make CMakeFiles/kdtree.dir/build\n.PHONY : kdtree/fast\n\nkdtree.o: kdtree.c.o\n.PHONY : kdtree.o\n\n# target to build an object file\nkdtree.c.o:\n\t$(MAKE) $(MAKESILENT) -f CMakeFiles/kdtree.dir/build.make CMakeFiles/kdtree.dir/kdtree.c.o\n.PHONY : kdtree.c.o\n\nkdtree.i: kdtree.c.i\n.PHONY : kdtree.i\n\n# target to preprocess a source file\nkdtree.c.i:\n\t$(MAKE) $(MAKESILENT) -f CMakeFiles/kdtree.dir/build.make CMakeFiles/kdtree.dir/kdtree.c.i\n.PHONY : kdtree.c.i\n\nkdtree.s: kdtree.c.s\n.PHONY : kdtree.s\n\n# target to generate assembly for a file\nkdtree.c.s:\n\t$(MAKE) $(MAKESILENT) -f CMakeFiles/kdtree.dir/build.make CMakeFiles/kdtree.dir/kdtree.c.s\n.PHONY : kdtree.c.s\n\nsample.o: sample.cpp.o\n.PHONY : sample.o\n\n# target to build an object file\nsample.cpp.o:\n\t$(MAKE) $(MAKESILENT) -f CMakeFiles/kdtree.dir/build.make CMakeFiles/kdtree.dir/sample.cpp.o\n.PHONY : sample.cpp.o\n\nsample.i: sample.cpp.i\n.PHONY : sample.i\n\n# target to preprocess a source file\nsample.cpp.i:\n\t$(MAKE) $(MAKESILENT) -f CMakeFiles/kdtree.dir/build.make CMakeFiles/kdtree.dir/sample.cpp.i\n.PHONY : sample.cpp.i\n\nsample.s: sample.cpp.s\n.PHONY : sample.s\n\n# target to generate assembly for a file\nsample.cpp.s:\n\t$(MAKE) $(MAKESILENT) -f CMakeFiles/kdtree.dir/build.make CMakeFiles/kdtree.dir/sample.cpp.s\n.PHONY : sample.cpp.s\n\n# Help Target\nhelp:\n\t@echo \"The following are some of the valid targets for this Makefile:\"\n\t@echo \"... all (the default if no target is provided)\"\n\t@echo \"... clean\"\n\t@echo \"... depend\"\n\t@echo \"... edit_cache\"\n\t@echo \"... rebuild_cache\"\n\t@echo \"... kdtree\"\n\t@echo \"... kdtree.o\"\n\t@echo \"... kdtree.i\"\n\t@echo \"... kdtree.s\"\n\t@echo \"... sample.o\"\n\t@echo \"... sample.i\"\n\t@echo \"... sample.s\"\n.PHONY : help\n\n\n\n#=============================================================================\n# Special targets to cleanup operation of make.\n\n# Special rule to run CMake to check the build system integrity.\n# No rule that depends on this can have commands that come from listfiles\n# because they might be regenerated.\ncmake_check_build_system:\n\t$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0\n.PHONY : cmake_check_build_system\n\n"
  },
  {
    "path": "README.md",
    "content": "# kdtree\nThis is a (nearly absolute) balanced kdtree for fast kNN search. It does not\nsupport dynamic insertion and removal. Actually we adopt quick sort to rebuild\nthe whole tree after changes of nodes. We cache the added or the deleted nodes\nwhich will not be actually mapped into the tree until the rebuild method to be\ninvoked. The good thing is we can always keep the tree balanced, and the bad\nthing is we have to wait some time for the finish of tree rebuild. Moreover,\nduplicated samples are allowed to be added.\n\nThe thought of the implementation is posted [here](https://www.joinquant.com/post/2843).\n\n## how to debug\n\n$ mkdir build\n\n$ cd build\n\n$ cmake ..\n\n$ make\n\n$ ./kdtree 1234  # you can try different seed number for random sample generations\n\n<img width=\"552\" height=\"589\" alt=\"Image\" src=\"https://github.com/user-attachments/assets/2e003772-e441-4923-9e3e-80c769557abd\" />\n"
  },
  {
    "path": "kd_search.m",
    "content": "function [nearest,nearestIndex] = kd_search(rootIndex,Tree,target, k)\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n% \n% 2018/8/6\n% kdڽ\n% rootIndexݵ㼯kdĸڵ±(cellеλã\n% targetĿ\n% Treekdcell\n% nearst㼯оĿĵ±\n% nearst㼯оĿĵ\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\ncurrentNode = rootIndex; %ǰڵ±꣬Ӹڵ㿪ʼ\ncurrentNode = search_down(Tree,currentNode,target);% currentNodeײ\nTree{currentNode}.visited = 1;\n    \ncurrentNearest = Tree{currentNode}.val;                    % ǰ\ncurrentNearestDist = norm(currentNearest-target);    % ǰ\ncurrentNearestIndex = currentNode;\n\nkNearestCandidate = [currentNearestDist, currentNearest', currentNearestIndex];\n\nwhile Tree{currentNode}.isRoot == 0\n    isLeft = Tree{currentNode}.isLeft;     %ǰڵӱ־\n    currentNode = Tree{Tree{currentNode}.parent}.index;\n    if Tree{currentNode}.visited == 0\n        Tree{currentNode}.visited = 1;%Ϊѷ\n        temp = norm(Tree{currentNode}.val-target);\n        if temp<kNearestCandidate(end,1) || size(kNearestCandidate, 1)<k\n            currentNearest = Tree{currentNode}.val;\n            currentNearestDist = temp;\n            currentNearestIndex = currentNode;\n            % 룬ĩλ&β̭\n            kNearestCandidate = [kNearestCandidate; currentNearestDist, currentNearest', currentNearestIndex];\n            kNearestCandidate = sortrows(kNearestCandidate);\n            if size(kNearestCandidate)>=k\n                kNearestCandidate(k+1:end,:) = [];\n            end\n        end\n        temp = abs(Tree{currentNode}.val(Tree{currentNode}.r)-target(Tree{currentNode}.r));   %뵱ǰָߵľ\n        if temp<kNearestCandidate(end,1) || size(kNearestCandidate, 1)<k\n            %ǰָ߾СڵǰС룬ڷָһ߿и㣬һ߼\n            if isLeft == 1\n                if Tree{currentNode}.hasRight == 1 %ǰڵӣҵǰڵҺӣҺ\n                    currentNode = Tree{Tree{currentNode}.right}.index;\n                    currentNode = search_down(Tree,currentNode,target); \n                    Tree{currentNode}.visited = 1;%Ϊѷ\n                    temp = norm(target - Tree{currentNode}.val);\n                    if temp<kNearestCandidate(end,1) || size(kNearestCandidate, 1)<k\n                        currentNearest = Tree{currentNode}.val;\n                        currentNearestDist = temp;\n                        currentNearestIndex = currentNode;\n                        kNearestCandidate = [kNearestCandidate; currentNearestDist, currentNearest', currentNearestIndex];\n                        kNearestCandidate = sortrows(kNearestCandidate);\n                        if size(kNearestCandidate)>=k\n                            kNearestCandidate(k+1:end,:) = [];\n                        end\n                    end\n                end\n            else\n                if Tree{currentNode}.hasLeft == 1  %ǰڵҺӣҸ׽ڵӣ׽ڵ\n                    currentNode = Tree{Tree{currentNode}.left}.index;\n                    currentNode = search_down(Tree,currentNode,target);\n                    Tree{currentNode}.visited = 1;%Ϊѷ\n                    temp = norm(target - Tree{currentNode}.val);\n                    if temp<kNearestCandidate(end,1) || size(kNearestCandidate, 1)<k\n                        currentNearest = Tree{currentNode}.val;\n                        currentNearestDist = temp;\n                        currentNearestIndex = currentNode;\n                        kNearestCandidate = [kNearestCandidate; currentNearestDist, currentNearest', currentNearestIndex];\n                        kNearestCandidate = sortrows(kNearestCandidate);\n                        if size(kNearestCandidate)>=k\n                            kNearestCandidate(k+1:end,:) = [];\n                        end\n                    end\n                end\n            end\n        end\n    end\nend\nnearest = kNearestCandidate(:,2:end-1);\nnearestIndex = kNearestCandidate(:,end);\n            \n        \n            \n        \n"
  },
  {
    "path": "kdtree.c",
    "content": "/*\n * Copyright (C) 2017, Leo Ma <begeekmyfriend@gmail.com>\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <float.h>\n#include <math.h>\n\n#include \"kdtree.h\"\n\nstatic inline int is_leaf(struct kdnode *node)\n{\n        return node->left == node->right;\n}\n\nstatic inline void swap(long *a, long *b)\n{\n        long tmp = *a;\n        *a = *b;\n        *b = tmp;\n}\n\nstatic inline double square(double d)\n{\n        return d * d;\n}\n\nstatic inline double distance(double *c1, double *c2, int dim)\n{\n        double distance = 0;\n        while (dim-- > 0) {\n                distance += square(*c1++ - *c2++);\n        }\n        return distance;\n}\n\nstatic inline double knn_max(struct kdtree *tree)\n{\n        return tree->knn_list_head.prev->distance;\n}\n\nstatic inline double D(struct kdtree *tree, long index, int r)\n{\n        return tree->coord_table[index][r];\n}\n\nstatic inline int kdnode_passed(struct kdtree *tree, struct kdnode *node)\n{\n        return node != NULL ? tree->coord_passed[node->coord_index] : 1;\n}\n\nstatic inline int knn_search_on(struct kdtree *tree, int k, double value, double target)\n{\n        return tree->knn_num < k || square(target - value) < knn_max(tree);\n}\n\nstatic inline void coord_index_reset(struct kdtree *tree)\n{\n        long i;\n        for (i = 0; i < tree->capacity; i++) {\n                tree->coord_indexes[i] = i;\n        }\n}\n\nstatic inline void coord_table_reset(struct kdtree *tree)\n{\n        long i;\n        for (i = 0; i < tree->capacity; i++) {\n                tree->coord_table[i] = tree->coords + i * tree->dim;\n        }\n}\n\nstatic inline void coord_deleted_reset(struct kdtree *tree)\n{\n        memset(tree->coord_deleted, 0, tree->capacity);\n}\n\nstatic inline void coord_passed_reset(struct kdtree *tree)\n{\n        memset(tree->coord_passed, 0, tree->capacity);\n}\n\nstatic void coord_dump_all(struct kdtree *tree)\n{\n        long i, j;\n        for (i = 0; i < tree->count; i++) {\n                long index = tree->coord_indexes[i];\n                double *coord = tree->coord_table[index];\n                printf(\"(\");\n                for (j = 0; j < tree->dim; j++) {\n                        if (j != tree->dim - 1) {\n                                printf(\"%.2f,\", coord[j]);\n                        } else {\n                                printf(\"%.2f)\\n\", coord[j]);\n                        }\n                }\n        }\n}\n\nstatic void coord_dump_by_indexes(struct kdtree *tree, long low, long high, int r)\n{\n        long i;\n        printf(\"r=%d:\", r);\n        for (i = 0; i <= high; i++) {\n                if (i < low) {\n                        printf(\"%8s\", \" \");\n                } else {\n                        long index = tree->coord_indexes[i];\n                        printf(\"%8.2f\", tree->coord_table[index][r]);\n                }\n        }\n        printf(\"\\n\");\n}\n\nstatic void quicksort(struct kdtree *tree, long lo, long hi, int r)\n{\n        long i, j, pivot, *indexes;\n        double *p;\n\n        if (lo >= hi) {\n                return;\n        }\n\n        i = lo;\n        j = hi;\n        indexes = tree->coord_indexes;\n        pivot = indexes[lo];\n\n        while (i < j) {\n                while (i < j && D(tree, indexes[j], r) >= D(tree, pivot, r)) j--;\n                /* Loop invariant: nums[j] > pivot or i == j */\n                indexes[i] = indexes[j];\n                while (i < j && D(tree, indexes[i], r) <= D(tree, pivot, r)) i++;\n                /* Loop invariant: nums[i] < pivot or i == j */\n                indexes[j] = indexes[i];\n        }\n        /* Loop invariant: i == j */\n        indexes[i] = pivot;\n\n        quicksort(tree, lo, i - 1, r);\n        quicksort(tree, i + 1, hi, r);\n}\n\nstatic struct kdnode *kdnode_alloc(double *coord, long index, int r)\n{\n        struct kdnode *node = malloc(sizeof(*node));\n        if (node != NULL) {\n                memset(node, 0, sizeof(*node));\n                node->coord = coord;\n                node->coord_index = index;\n                node->r = r;\n        }\n        return node;\n}\n\nstatic void kdnode_free(struct kdnode *node)\n{\n        free(node);\n}\n\nstatic int coord_cmp(double *c1, double *c2, int dim)\n{\n        int i;\n        double ret;\n        for (i = 0; i < dim; i++) {\n                ret = *c1++ - *c2++;\n                if (fabs(ret) >= DBL_EPSILON) {\n                        return ret > 0 ? 1 : -1;\n                }\n        }\n\n        if (fabs(ret) < DBL_EPSILON) {\n                return 0;\n        } else {\n                return ret > 0 ? 1 : -1;\n        }\n}\n\nstatic void knn_list_add(struct kdtree *tree, struct kdnode *node, double distance)\n{\n        if (node == NULL) return;\n\n        struct knn_list *head = &tree->knn_list_head;\n        struct knn_list *p = head->prev;\n        if (tree->knn_num == 1) {\n                if (p->distance > distance) {\n                        p = p->prev;\n                }\n        } else {\n                while (p != head && p->distance > distance) {\n                        p = p->prev;\n                }\n        }\n\n        if (p == head || coord_cmp(p->node->coord, node->coord, tree->dim)) {\n                struct knn_list *log = malloc(sizeof(*log));\n                if (log != NULL) {\n                        log->node = node;\n                        log->distance = distance;\n                        log->prev = p;\n                        log->next = p->next;\n                        p->next->prev = log;\n                        p->next = log;\n                        tree->knn_num++;\n                }\n        }\n}\n\nstatic void knn_list_adjust(struct kdtree *tree, struct kdnode *node, double distance)\n{\n        if (node == NULL) return;\n\n        struct knn_list *head = &tree->knn_list_head;\n        struct knn_list *p = head->prev;\n        if (tree->knn_num == 1) {\n                if (p->distance > distance) {\n                        p = p->prev;\n                }\n        } else {\n                while (p != head && p->distance > distance) {\n                        p = p->prev;\n                }\n        }\n\n        if (p == head || coord_cmp(p->node->coord, node->coord, tree->dim)) {\n                struct knn_list *log = head->prev;\n                /* Replace the original max one */\n                log->node = node;\n                log->distance = distance;\n                /* Remove from the max position */\n                head->prev = log->prev;\n                log->prev->next = head;\n                /* insert as a new one */\n                log->prev = p;\n                log->next = p->next;\n                p->next->prev = log;\n                p->next = log;\n        }\n}\n\nstatic void knn_list_clear(struct kdtree *tree)\n{\n        if (tree->knn_num > 0) {\n                struct knn_list *head = &tree->knn_list_head;\n                struct knn_list *p = head->next;\n                while (p != head) {\n                        struct knn_list *prev = p;\n                        p = p->next;\n                        free(prev);\n                }\n                tree->knn_num = 0;\n        }\n\n        tree->knn_list_head.next = &tree->knn_list_head;\n        tree->knn_list_head.prev = &tree->knn_list_head;\n        tree->knn_list_head.node = NULL;\n        tree->knn_list_head.distance = 0;\n}\n\nstatic void resize(struct kdtree *tree)\n{\n        tree->capacity *= 2;\n        tree->coords = realloc(tree->coords, tree->dim * sizeof(double) * tree->capacity);\n        tree->coord_table = realloc(tree->coord_table, sizeof(double *) * tree->capacity);\n        tree->coord_indexes = realloc(tree->coord_indexes, sizeof(long) * tree->capacity);\n        tree->coord_deleted = realloc(tree->coord_deleted, sizeof(char) * tree->capacity);\n        tree->coord_passed = realloc(tree->coord_passed, sizeof(char) * tree->capacity);\n        coord_table_reset(tree);\n        coord_index_reset(tree);\n        coord_deleted_reset(tree);\n        coord_passed_reset(tree);\n}\n\nstatic void kdnode_dump(struct kdnode *node, int dim)\n{\n        int i;\n        if (node->coord != NULL) {\n                printf(\"(\");\n                for (i = 0; i < dim; i++) {\n                        if (i != dim - 1) {\n                                printf(\"%.2f,\", node->coord[i]);\n                        } else {\n                                printf(\"%.2f)\\n\", node->coord[i]);\n                        }\n                }\n        } else {\n                printf(\"(none)\\n\");\n        }\n}\n\nvoid kdtree_insert(struct kdtree *tree, double *coord)\n{\n        if (tree->count + 1 > tree->capacity) {\n                resize(tree);\n        }\n        memcpy(tree->coord_table[tree->count++], coord, tree->dim * sizeof(double));\n}\n\nstatic void knn_pickup(struct kdtree *tree, struct kdnode *node, double *target, int k)\n{\n        double dist = distance(node->coord, target, tree->dim);\n        if (tree->knn_num < k) {\n                knn_list_add(tree, node, dist);\n        } else {\n                if (dist < knn_max(tree)) {\n                        knn_list_adjust(tree, node, dist);\n                } else if (fabs(dist - knn_max(tree)) < DBL_EPSILON) {\n                        knn_list_add(tree, node, dist);\n                }\n        }\n}\n\nstatic void kdtree_search_recursive(struct kdtree *tree, struct kdnode *node, double *target, int k, int *pickup)\n{\n        if (node == NULL || kdnode_passed(tree, node)) {\n                return;\n        }\n\n        int r = node->r;\n\n        if (is_leaf(node)) {\n                *pickup = 1;\n        } else {\n                if (target[r] <= node->coord[r]) {\n                        kdtree_search_recursive(tree, node->left, target, k, pickup);\n                        if ((*pickup && knn_search_on(tree, k, node->coord[r], target[r])) || node->left == NULL) {\n                                kdtree_search_recursive(tree, node->right, target, k, pickup);\n                        }\n                } else {\n                        kdtree_search_recursive(tree, node->right, target, k, pickup);\n                        if ((*pickup && knn_search_on(tree, k, node->coord[r], target[r])) || node->right == NULL) {\n                                kdtree_search_recursive(tree, node->left, target, k, pickup);\n                        }\n                }\n        }\n\n        /* back track and pick up  */\n        if (*pickup) {\n                tree->coord_passed[node->coord_index] = 1;\n                knn_pickup(tree, node, target, k);\n        }\n}\n\nvoid kdtree_knn_search(struct kdtree *tree, double *target, int k)\n{\n        if (k > 0) {\n                int pickup = 0;\n                knn_list_clear(tree);\n                coord_passed_reset(tree);\n                kdtree_search_recursive(tree, tree->root, target, k, &pickup);\n        }\n}\n\nvoid kdtree_delete(struct kdtree *tree, double *coord)\n{\n        int r = 0;\n        struct kdnode *node = tree->root;\n        struct kdnode *parent = node;\n\n        while (node != NULL) {\n                if (node->coord == NULL) {\n                        if (parent->right->coord == NULL) {\n                                break;\n                        } else {\n                                node = parent->right;\n                                continue;\n                        }\n                }\n\n                if (coord[r] < node->coord[r]) {\n                        parent = node;\n                        node = node->left;\n                } else if (coord[r] > node->coord[r]) {\n                        parent = node;\n                        node = node->right;\n                } else {\n                        int ret = coord_cmp(coord, node->coord, tree->dim);\n                        if (ret < 0) {\n                                parent = node;\n                                node = node->left;\n                        } else if (ret > 0) {\n                                parent = node;\n                                node = node->right;\n                        } else {\n                                node->coord = NULL;\n                                break;\n                        }\n                }\n                r = (r + 1) % tree->dim;\n        }\n}\n\nstatic void kdnode_build(struct kdtree *tree, struct kdnode **nptr, int r, long low, long high)\n{\n        /* BST preorder constructure */\n        if (low == high) {\n                long index = tree->coord_indexes[low];\n                *nptr = kdnode_alloc(tree->coord_table[index], index, r);\n        } else if (low < high) {\n                /* Sort and fetch the median to build a balanced BST */\n                quicksort(tree, low, high, r);\n                long median = low + (high - low) / 2;\n                long median_index = tree->coord_indexes[median];\n                struct kdnode *node = *nptr = kdnode_alloc(tree->coord_table[median_index], median_index, r);\n                r = (r + 1) % tree->dim;\n                kdnode_build(tree, &node->left, r, low, median - 1);\n                kdnode_build(tree, &node->right, r, median + 1, high);\n        }\n}\n\nstatic void kdtree_build(struct kdtree *tree)\n{\n        kdnode_build(tree, &tree->root, 0, 0, tree->count - 1);\n}\n\nvoid kdtree_rebuild(struct kdtree *tree)\n{\n        long i, j;\n        size_t size_of_coord = tree->dim * sizeof(double);\n        for (i = 0, j = 0; j < tree->count; i++, j++) {\n                while (j < tree->count && tree->coord_deleted[j]) {\n                        j++;\n                }\n                if (i != j && j < tree->count) {\n                        memcpy(tree->coord_table[i], tree->coord_table[j], size_of_coord);\n                        tree->coord_deleted[i] = 0;\n                }\n        }\n        tree->count = i;\n        coord_index_reset(tree);\n        kdtree_build(tree);\n}\n\nstruct kdtree *kdtree_init(int dim)\n{\n        struct kdtree *tree = malloc(sizeof(*tree));\n        if (tree != NULL) {\n                tree->root = NULL;\n                tree->dim = dim;\n                tree->count = 0;\n                tree->capacity = 65536;\n                tree->knn_num = 0;\n                tree->coords = malloc(dim * sizeof(double) * tree->capacity);\n                tree->coord_table = malloc(sizeof(double *) * tree->capacity);\n                tree->coord_indexes = malloc(sizeof(long) * tree->capacity);\n                tree->coord_deleted = malloc(sizeof(char) * tree->capacity);\n                tree->coord_passed = malloc(sizeof(char) * tree->capacity);\n                coord_index_reset(tree);\n                coord_table_reset(tree);\n                coord_deleted_reset(tree);\n                coord_passed_reset(tree);\n        }\n        return tree;\n}\n\nstatic void kdnode_destroy(struct kdnode *node)\n{\n        if (node == NULL) return;\n        kdnode_destroy(node->left);\n        kdnode_destroy(node->right);\n        kdnode_free(node);\n}\n\nvoid kdtree_destroy(struct kdtree *tree)\n{\n        kdnode_destroy(tree->root);\n        knn_list_clear(tree);\n        free(tree->coords);\n        free(tree->coord_table);\n        free(tree->coord_indexes);\n        free(tree->coord_deleted);\n        free(tree->coord_passed);\n        free(tree);\n}\n\n#define _KDTREE_DEBUG\n\n#ifdef _KDTREE_DEBUG\nstruct kdnode_backlog {\n        struct kdnode *node;\n        int next_sub_idx;\n};\n\nvoid kdtree_dump(struct kdtree *tree)\n{\n        int level = 0;\n        struct kdnode *node = tree->root;\n        struct kdnode_backlog nbl, *p_nbl = NULL;\n        struct kdnode_backlog nbl_stack[KDTREE_MAX_LEVEL];\n        struct kdnode_backlog *top = nbl_stack;\n\n        for (; ;) {\n                if (node != NULL) {\n                        /* Fetch the pop-up backlogged node's sub-id.\n                         * If not backlogged, fetch the first sub-id. */\n                        int sub_idx = p_nbl != NULL ? p_nbl->next_sub_idx : KDTREE_RIGHT_INDEX;\n\n                        /* Backlog should be left in next loop */\n                        p_nbl = NULL;\n\n                        /* Backlog the node */\n                        if (is_leaf(node) || sub_idx == KDTREE_LEFT_INDEX) {\n                                top->node = NULL;\n                                top->next_sub_idx = KDTREE_RIGHT_INDEX;\n                        } else {\n                                top->node = node;\n                                top->next_sub_idx = KDTREE_LEFT_INDEX;\n                        }\n                        top++;\n                        level++;\n\n                        /* Draw lines as long as sub_idx is the first one */\n                        if (sub_idx == KDTREE_RIGHT_INDEX) {\n                                int i;\n                                for (i = 1; i < level; i++) {\n                                        if (i == level - 1) {\n                                                printf(\"%-8s\", \"+-------\");\n                                        } else {\n                                                if (nbl_stack[i - 1].node != NULL) {\n                                                        printf(\"%-8s\", \"|\");\n                                                } else {\n                                                        printf(\"%-8s\", \" \");\n                                                }\n                                        }\n                                }\n                                kdnode_dump(node, tree->dim);\n                        }\n\n                        /* Move down according to sub_idx */\n                        node = sub_idx == KDTREE_LEFT_INDEX ? node->left : node->right;\n                } else {\n                        p_nbl = top == nbl_stack ? NULL : --top;\n                        if (p_nbl == NULL) {\n                                /* End of traversal */\n                                break;\n                        }\n                        node = p_nbl->node;\n                        level--;\n                }\n        }\n}\n#endif\n\n\n// (Includes and struct definitions from kdtree.h)\n// (kdnode_dump helper function from original kdtree.c)\n\n/* * Helper struct for our new Root-Left-Right stack.\n * We need to know the node and its level.\n */\nstruct kdnode_dump_item {\n        struct kdnode *node;\n        int level;\n};\n\n/*\n * This is the modified kdtree_dump function.\n * It uses a standard iterative Pre-order (Root-Left-Right) traversal.\n *\n * It manages the line-art state explicitly using a \n * 'level_states' array.\n */\nvoid kdtree_dump_simple(struct kdtree *tree)\n{\n        if (tree->root == NULL) {\n                printf(\"Tree is empty.\\n\");\n                return;\n        }\n\n        /* * 1. Create our stack\n         */\n        struct kdnode_dump_item stack[KDTREE_MAX_LEVEL];\n        int top = -1;\n\n        /*\n         * 2. Create state for line-drawing\n         * This array tracks whether to draw a '|' at a given level.\n         * 1 = draw '|', 0 = draw ' '\n         */\n        int level_states[KDTREE_MAX_LEVEL];\n        memset(level_states, 0, sizeof(level_states));\n        \n        /*\n         * 3. Push the root node to start\n         */\n        top++;\n        stack[top].node = tree->root;\n        stack[top].level = 0;\n\n        while (top != -1) {\n                /*\n                 * Pop a node from the stack\n                 */\n                struct kdnode_dump_item current_item = stack[top--];\n                struct kdnode *node = current_item.node;\n                int level = current_item.level;\n\n                /* --- This is the \"Visit\" step --- */\n                /* Print the prefix lines ('|' or ' ') */\n                int i;\n                for (i = 0; i < level; i++) {\n                        if (level_states[i]  == 2) {\n                                printf(\"%-8s\", \"|\");\n                        } else {\n                                printf(\"%-8s\", \" \");\n                        }\n                }\n                \n                /* Print the node itself */\n                printf(\"%-8s\", \"+-------\");\n                kdnode_dump(node, tree->dim);\n                /* --- End Visit --- */\n                level_states[level]++;\n\n                /*\n                 * 4. Update line-drawing state for the *next* level\n                 * If we have a left child, the right child (if it exists)\n                 * will need a '|' at this level.\n                 */\n                if (node->left != NULL && node->right != NULL) {\n                        level_states[level+1] = 1;\n                } else {\n                        level_states[level+1] = 0;\n                }\n\n                /*\n                 * 5. Push children onto the stack (Root-Left-Right)\n                 * We push RIGHT first, then LEFT.\n                 */\n                if (node->left != NULL) {\n                        top++;\n                        stack[top].node = node->left;\n                        stack[top].level = level + 1;\n                }\n\n                if (node->right != NULL) {\n                        top++;\n                        stack[top].node = node->right;\n                        stack[top].level = level + 1;\n                }\n                \n                \n        }\n}\n"
  },
  {
    "path": "kdtree.h",
    "content": "/*\n * Copyright (C) 2017, Leo Ma <begeekmyfriend@gmail.com>\n */\n\n#ifndef _KD_TREE_H\n#define _KD_TREE_H\n\n/* ADD THIS LINE */\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define KDTREE_MAX_LEVEL 64\n#define KDTREE_LEFT_INDEX 0\n#define KDTREE_RIGHT_INDEX 1\n\ntypedef struct knn_list {\n        struct kdnode *node;\n        double distance;\n        struct knn_list *prev;\n        struct knn_list *next;\n} knn_list_t;\n\ntypedef struct kdnode {\n        long coord_index;\n        double *coord;\n        struct kdnode *left;\n        struct kdnode *right;\n        int r;\n} kdnode_t;\n\ntypedef struct kdtree {\n        struct kdnode *root;\n        size_t count;\n        size_t capacity;\n        double *coords;\n        double **coord_table;\n        long *coord_indexes;\n        unsigned char *coord_deleted;\n        unsigned char *coord_passed;\n        struct knn_list knn_list_head;\n        int dim;\n        int knn_num;\n} kdtree_t;\n\nstruct kdtree *kdtree_init(int dim);\nvoid kdtree_insert(struct kdtree *tree, double *coord);\nvoid kdtree_rebuild(struct kdtree *tree);\nvoid kdtree_knn_search(struct kdtree *tree, double *coord, int k);\nvoid kdtree_destroy(struct kdtree *tree);\nvoid kdtree_dump(struct kdtree *tree);\nvoid kdtree_dump_simple(struct kdtree *tree);\n\n/* ADD THESE LINES */\n#ifdef __cplusplus\n}\n#endif\n\n\n#endif /* _KD_TREE_H */\n"
  },
  {
    "path": "kdtree_bench.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <math.h>\n#include <time.h>\n\n#include \"kdtree.h\"\n\n#define N 1024 * 1024\n\nstatic inline double rd(void)\n{\n        return (double) rand() / RAND_MAX * 20 - 10;\n}\n\nstatic void kdtree_knn_dump(struct kdtree *tree)\n{\n        int i;\n        struct knn_list *p = tree->knn_list_head.next;\n        while (p != &tree->knn_list_head) {\n                putchar('(');\n                for (i = 0; i < tree->dim; i++) {\n                        if (i == tree->dim - 1) {\n                                printf(\"%.2lf) Distance:%lf\\n\", p->node->coord[i], sqrt(p->distance));\n                        } else {\n                                printf(\"%.2lf, \", p->node->coord[i]);\n                        }\n                }\n                p = p->next;\n        }\n}\n\nint main(void)\n{\n        int i, j, dim = 2;\n        struct timespec start, end;\n        struct kdtree *tree = kdtree_init(dim);\n        if (tree == NULL) {\n                exit(-1);\n        }\n\n        double sample1[] = { 6.27, 5.50 };\n        double sample2[] = { 1.24, -2.86 };\n        double sample3[] = { 17.05, -12.79 };\n        double sample4[] = { -6.88, -5.40 };\n        double sample5[] = { -2.96, -0.50 };\n        double sample6[] = { 7.75, -22.68 };\n        double sample7[] = { 10.80, -5.03 };\n        double sample8[] = { -4.60, -10.55 };\n        double sample9[] = { -4.96, 12.61 };\n        double sample10[] = { 1.75, 12.26 };\n        double sample11[] = { 15.31, -13.16 };\n        double sample12[] = { 7.83, 15.70 };\n        double sample13[] = { 14.63, -0.35 };\n\n        kdtree_insert(tree, sample1);\n        kdtree_insert(tree, sample2);\n        kdtree_insert(tree, sample3);\n        kdtree_insert(tree, sample4);\n        kdtree_insert(tree, sample5);\n        kdtree_insert(tree, sample6);\n        kdtree_insert(tree, sample7);\n        kdtree_insert(tree, sample8);\n        kdtree_insert(tree, sample9);\n        kdtree_insert(tree, sample10);\n        kdtree_insert(tree, sample11);\n        kdtree_insert(tree, sample12);\n        kdtree_insert(tree, sample13);\n\n        kdtree_rebuild(tree);\n\n        kdtree_dump(tree);\n\n        int k = 3;\n        double target[] = { -1, -5 };\n        kdtree_knn_search(tree, target, k);\n        printf(\"%d nearest neighbors of sample(\", k);\n        for (i = 0; i < dim; i++) {\n                if (i == dim - 1) {\n                        printf(\"%.2lf):\\n\", target[i]);\n                } else {\n                        printf(\"%.2lf, \", target[i]);\n                }\n        }\n        kdtree_knn_dump(tree);\n\n        double target1[] = { -8, -7 };\n        kdtree_knn_search(tree, target1, k);\n        printf(\"%d nearest neighbors of sample(\", k);\n        for (i = 0; i < dim; i++) {\n                if (i == dim - 1) {\n                        printf(\"%.2lf):\\n\", target1[i]);\n                } else {\n                        printf(\"%.2lf, \", target1[i]);\n                }\n        }\n        kdtree_knn_dump(tree);\n\n        kdtree_destroy(tree);\n\n        /* Performance test */\n        printf(\"\\n>>> Performance test: kNN search for %d samples\\n\\n\", N);\n        dim = 12;\n        tree = kdtree_init(dim);\n        if (tree == NULL) {\n                exit(-1);\n        }\n\n        /* Insert test */\n        printf(\"Add %d nodes...\\n\", N);\n        srandom(time(NULL));\n        clock_gettime(CLOCK_MONOTONIC, &start);\n        for (i = 0; i < N; i++) {\n                double *sample = malloc(dim * sizeof(double));\n                for (j = 0; j < dim; j++) {\n                        sample[j] = rd();\n                }\n                kdtree_insert(tree, sample);\n        }\n        clock_gettime(CLOCK_MONOTONIC, &end);\n        printf(\"time span: %ldms\\n\", (end.tv_sec - start.tv_sec)*1000 + (end.tv_nsec - start.tv_nsec)/1000000);\n\n        /* Build test */\n        printf(\"Build KD tree...\\n\");\n        clock_gettime(CLOCK_MONOTONIC, &start);\n        kdtree_rebuild(tree);\n        clock_gettime(CLOCK_MONOTONIC, &end);\n        printf(\"time span: %ldms\\n\", (end.tv_sec - start.tv_sec)*1000 + (end.tv_nsec - start.tv_nsec)/1000000);\n\n        /* Search test */\n        k = 20;\n        srandom(time(NULL));\n        double *t = malloc(dim * sizeof(double));\n        for (i = 0; i < dim; i++) {\n                t[i] = rd();\n        }\n        printf(\"Search KD tree...\\n\");\n        srandom(time(NULL));\n        clock_gettime(CLOCK_MONOTONIC, &start);\n        kdtree_knn_search(tree, t, k);\n        clock_gettime(CLOCK_MONOTONIC, &end);\n        printf(\"time span: %ldms\\n\", (end.tv_sec - start.tv_sec)*1000 + (end.tv_nsec - start.tv_nsec)/1000000);\n        printf(\"%d nearest neighbors of sample(\", k);\n        for (i = 0; i < dim; i++) {\n                if (i == dim - 1) {\n                        printf(\"%.2lf):\\n\", t[i]);\n                } else {\n                        printf(\"%.2lf, \", t[i]);\n                }\n        }\n        kdtree_knn_dump(tree);\n\n        /* Destroy test */\n        printf(\"Destroy KD tree...\\n\");\n        srandom(time(NULL));\n        clock_gettime(CLOCK_MONOTONIC, &start);\n        kdtree_destroy(tree);\n        clock_gettime(CLOCK_MONOTONIC, &end);\n        printf(\"time span: %ldms\\n\", (end.tv_sec - start.tv_sec)*1000 + (end.tv_nsec - start.tv_nsec)/1000000);\n\n        return 0;\n}\n"
  },
  {
    "path": "sample.cpp",
    "content": "﻿#include <opencv2/opencv.hpp>\n#include <iostream>\n#include <array>\n#include <vector>\n\n#include \"kdtree.h\"\n\n// user-defined point type\n// inherits std::array in order to use operator[]\nclass MyPoint : public std::array<double, 2>\n{\npublic:\n\n\t// dimension of space (or \"k\" of k-d tree)\n\t// KDTree class accesses this member\n\tstatic const int DIM = 2;\n\n\t// the constructors\n\tMyPoint() {}\n\tMyPoint(double x, double y)\n\t{ \n\t\t(*this)[0] = x;\n\t\t(*this)[1] = y;\n\t}\n\n\t// conversion to OpenCV Point2d\n\toperator cv::Point2d() const { return cv::Point2d((*this)[0], (*this)[1]); }\n};\n\nvoid kdtree_knn_dump(struct kdtree *tree, double *candidates, int k) \n{\n        int i, j = 0;\n        struct knn_list *p = tree->knn_list_head.next;\n        const int dim = tree->dim;\n        printf(\"The nearest %d samples are as follows:\\n\", k);\n        while (p != &tree->knn_list_head) {\n                putchar('(');\n                for (i = 0; i < tree->dim; i++) {\n                        if (i == tree->dim - 1) {\n                                printf(\"%.2lf) Distance:%lf\\n\", p->node->coord[i], sqrt(p->distance));\n                        } else {\n                                printf(\"%.2lf, \", p->node->coord[i]);\n                        }\n                        candidates[j*dim+i] = p->node->coord[i];\n                }\n                p = p->next;\n                j++;\n        }\n}\n\nint main(int argc, char **argv)\n{\n\tconst int seed = argc > 1 ? std::stoi(argv[1]) : 0;\n\tsrand(seed);\n\n\t// generate space\n\tconst int width = 500;\n\tconst int height = 500;\n\tcv::Mat img = cv::Mat::zeros(cv::Size(width, height), CV_8UC3);\n\n\t// generate points\n\tconst int npoints = 1000;\n\tstd::vector<MyPoint> points(npoints);\n\tfor (int i = 0; i < npoints; i++)\n\t{\n\t\tconst int x = rand() % width;\n\t\tconst int y = rand() % height;\n\t\tpoints[i] = MyPoint(x, y);\n\t}\n\n\tfor (const auto& pt : points)\n\t\tcv::circle(img, cv::Point2d(pt), 1, cv::Scalar(0, 255, 255), -1);\n\n\t// build k-d tree\n\tint dim = 2;\n\tstruct kdtree *tree = kdtree_init(dim);\n\tfor (int i = 0; i < npoints; i++)\n\t{\n\t\t// 1. Declare an array to hold the coordinates\n\t\tdouble my_coord[] = {points[i][0], points[i][1]};\n\n\t\t// 2. Pass the array (which acts as a pointer) to the function\n\t\tkdtree_insert(tree, my_coord);\t\n\t}\n\tkdtree_rebuild(tree);\n\n\t// generate query (center of the space)\n\tconst int k = 100;\n\tconst MyPoint query(0.5 * width, 0.5 * height);\n\tcv::circle(img, cv::Point2d(query), 1, cv::Scalar(0, 0, 255), -1);\n\n\t// nearest neigbor search\n\tconst cv::Mat I0 = img.clone();\n\tdouble target1[] = {query[0], query[1]};\n\tkdtree_knn_search(tree, target1, 1);\n\t// kdtree_knn_dump(tree, nullptr, k);\n\t// const int idx = kdtree.nnSearch(query);\n\t// cv::circle(I0, cv::Point2d(points[idx]), 1, cv::Scalar(255, 255, 0), -1);\n\t// cv::line(I0, cv::Point2d(query), cv::Point2d(points[idx]), cv::Scalar(0, 0, 255));\n\n\t// k-nearest neigbors search\n\tconst cv::Mat I1 = img.clone();\n\tdouble candidates[k*dim];\n\tkdtree_knn_search(tree, target1, k);\n\tkdtree_knn_dump(tree, candidates, k);\n\tfor (int i = 0; i < k; i++){\n\t\tcv::circle(I1, cv::Point2d(candidates[i*dim], candidates[i*dim + 1]), 1, cv::Scalar(255, 255, 0), -1);\t\n\t\tcv::line(I1, cv::Point2d(query), cv::Point2d(candidates[i*dim], candidates[i*dim + 1]), cv::Scalar(0, 0, 255));\n\t}\n\t\t\n\t// const std::vector<int> knnIndices = kdtree.knnSearch(query, k);\n\t// for (int i : knnIndices)\n\t// {\n\t// \tcv::circle(I1, cv::Point2d(points[i]), 1, cv::Scalar(255, 255, 0), -1);\n\t// \tcv::line(I1, cv::Point2d(query), cv::Point2d(points[i]), cv::Scalar(0, 0, 255));\n\t// }\n\t\n\t// radius search\n\tconst cv::Mat I2 = img.clone();\n\t// const double radius = 50;\n\t// const std::vector<int> radIndices = kdtree.radiusSearch(query, radius);\n\t// for (int i : radIndices)\n\t// \tcv::circle(I2, cv::Point2d(points[i]), 1, cv::Scalar(255, 255, 0), -1);\n\t// cv::circle(I2, cv::Point2d(query), cvRound(radius), cv::Scalar(0, 0, 255));\n\n\t// show results\n\tcv::imshow(\"Nearest neigbor search\", I0);\n\t// cv::imshow(\"K-nearest neigbors search (k = 10)\", I1);\n\tcv::imshow(\"K-nearest neighbors search (k = \" + std::to_string(k) + \")\", I1);\n\tcv::imshow(\"Radius search (radius = 50)\", I2);\n\n\tcv::waitKey(0);\n\n\treturn 0;\n}\n"
  },
  {
    "path": "sort_by_r.m",
    "content": "function X_sorted = sort_by_r(X,r)\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n% ݵ㼯rά\n% Xݵ㼯[dim,num]\n% rά\n% X_sorted㼯\n% ð\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n% num = size(X,2);\n% for i = 1:num-1\n%     for j = 1:num-i\n%         if X(r,j+1)<X(r,j)\n%             X(:,[j,j+1]) = X(:,[j+1,j]);\n%         end\n%     end\n% end\n% X_sorted = X;\nX_sorted = sortrows(X',r)';"
  },
  {
    "path": "test.m",
    "content": "clear;clc;close all;\n\n\n%% kd\ne = 0;\nk = 5;\nsamples = 100;\ndims = 4;\nfor sim = 1:1e3\n    X = randn(dims, samples);\n    [rootIndex,Tree] = kd_build(X);\n    target = randn(dims,1);\n    [nearest,index] = kd_search(rootIndex,Tree,target, k);\n    dist = zeros(samples, 2);\n    for i = 1:samples\n        dist(i,1) = norm(X(:,i)-target);\n        dist(i,2) = i;\n    end\n    dist = sortrows(dist);\n    index1 = dist(1:k,2);\n    if index ~= index1\n        e = e+1;\n    end\nend\ndisp(['error cnt:', int2str(e)])\n\n\n"
  }
]