├── entities ├── Node.cpp ├── Node.h ├── NonLeafNode.h ├── NodeExtend.h ├── LeafNode.h ├── NodeExtend.cpp ├── Point.h ├── Mbr.h ├── Point.cpp ├── NonLeafNode.cpp ├── LeafNode.cpp └── Mbr.cpp ├── .gitignore ├── curves ├── z.H ├── z.cpp ├── hilbert.H ├── hilbert.cpp ├── hilbert4.H └── hilbert4.cpp ├── utils ├── util.h ├── FileReader.h ├── SearchHelper.h ├── FileWriter.h ├── Constants.h ├── ExpRecorder.h ├── Constants.cpp ├── SortTools.h ├── FileReader.cpp ├── ExpRecorder.cpp ├── FileWriter.cpp └── ModelTools.h ├── LICENSE ├── Makefile ├── README.md ├── data_generator.py ├── Exp.cpp └── indices └── RSMI.h /entities/Node.cpp: -------------------------------------------------------------------------------- 1 | #include "Node.h" 2 | 3 | nodespace::Node::Node() 4 | { 5 | } 6 | 7 | float nodespace::Node::cal_dist(Point point) 8 | { 9 | return mbr.cal_dist(point); 10 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/* 2 | *.o 3 | torch_models/* 4 | Exp 5 | *.sh 6 | files/* 7 | indices/ZM.h 8 | datasets/* 9 | 10 | PostgreSQL/ 11 | 12 | *.txt 13 | 14 | torch_models_zm/* 15 | 16 | *.eps 17 | *.png -------------------------------------------------------------------------------- /entities/Node.h: -------------------------------------------------------------------------------- 1 | #ifndef NODE_H 2 | #define NODE_H 3 | #include "Mbr.h" 4 | namespace nodespace 5 | { 6 | class Node 7 | { 8 | public: 9 | Mbr mbr; 10 | int order_in_level; 11 | Node(); 12 | virtual ~Node() {} 13 | float cal_dist(Point); 14 | }; 15 | }; 16 | #endif -------------------------------------------------------------------------------- /curves/z.H: -------------------------------------------------------------------------------- 1 | // 2 | // Description: source for computing Z-order curve value 3 | // Created: 2016/12/11 4 | // Last updated: 2019/10/17 5 | // Author: Yanchuan Chang 6 | // Mail: changyanchuan@gmail.com 7 | // 8 | 9 | #ifndef Z_H 10 | #define Z_H 11 | 12 | #include 13 | 14 | __uint128_t compute_Z_value(long long x[], const size_t& x_len, const long long& bits); 15 | long long compute_Z_value(long long x, long long y, int bit_num); 16 | #endif 17 | -------------------------------------------------------------------------------- /entities/NonLeafNode.h: -------------------------------------------------------------------------------- 1 | #ifndef NONLEAFNODE_H 2 | #define NONLEAFNODE_H 3 | 4 | #include 5 | #include "Node.h" 6 | 7 | class NonLeafNode : public nodespace::Node 8 | { 9 | public: 10 | int level; 11 | vector *children; 12 | NonLeafNode *parent; 13 | NonLeafNode(); 14 | NonLeafNode(Mbr mbr); 15 | void addNode(Node*); 16 | void addNodes(vector); 17 | bool is_full(); 18 | NonLeafNode* split(); 19 | }; 20 | 21 | #endif -------------------------------------------------------------------------------- /entities/NodeExtend.h: -------------------------------------------------------------------------------- 1 | #ifndef NODEEXTEND_H 2 | #define NODEEXTEND_H 3 | 4 | #include 5 | #include "Node.h" 6 | #include "Point.h" 7 | // #include "Mbr.h" 8 | // using namespace std; 9 | 10 | class NodeExtend{ 11 | 12 | public: 13 | nodespace::Node *node = NULL; 14 | Point point; 15 | float dist; 16 | NodeExtend(); 17 | NodeExtend(nodespace::Node*, float); 18 | NodeExtend(Point, float); 19 | bool is_leafnode(); 20 | }; 21 | 22 | #endif -------------------------------------------------------------------------------- /utils/util.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | namespace file_utils 8 | { 9 | inline int check_dir(string path); 10 | }; 11 | 12 | namespace file_utils 13 | { 14 | int check_dir(string path) 15 | { 16 | std::ifstream fin(path); 17 | if (!fin) 18 | { 19 | string command = "mkdir -p " + path; 20 | return system(command.c_str()); 21 | } 22 | return 0; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /entities/LeafNode.h: -------------------------------------------------------------------------------- 1 | #ifndef LEAFNODE_H 2 | #define LEAFNODE_H 3 | 4 | #include 5 | #include "Node.h" 6 | #include "Point.h" 7 | #include "Mbr.h" 8 | #include "NonLeafNode.h" 9 | using namespace std; 10 | 11 | class LeafNode : public nodespace::Node 12 | { 13 | public: 14 | int level; 15 | vector *children; 16 | NonLeafNode *parent; 17 | LeafNode(); 18 | LeafNode(Mbr mbr); 19 | void add_point(Point); 20 | void add_points(vector); 21 | bool delete_point(Point); 22 | bool is_full(); 23 | LeafNode *split(); 24 | LeafNode split1(); 25 | }; 26 | 27 | #endif -------------------------------------------------------------------------------- /entities/NodeExtend.cpp: -------------------------------------------------------------------------------- 1 | #include "NodeExtend.h" 2 | #include 3 | #include "NonLeafNode.h" 4 | #include 5 | using namespace std; 6 | 7 | NodeExtend::NodeExtend() 8 | { 9 | } 10 | 11 | NodeExtend::NodeExtend(Point point, float dist) 12 | { 13 | this->point = point; 14 | this->dist = dist; 15 | } 16 | 17 | NodeExtend::NodeExtend(nodespace::Node *node, float dist) 18 | { 19 | this->node = node; 20 | this->dist = dist; 21 | } 22 | 23 | bool NodeExtend::is_leafnode() 24 | { 25 | if (typeid(*node) == typeid(NonLeafNode)) 26 | { 27 | return false; 28 | } 29 | return true; 30 | } 31 | -------------------------------------------------------------------------------- /entities/Point.h: -------------------------------------------------------------------------------- 1 | #ifndef POINT_H 2 | #define POINT_H 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | class Point 8 | { 9 | 10 | public: 11 | 12 | float index; 13 | float x; 14 | float y; 15 | long long x_i; 16 | long long y_i; 17 | long long curve_val; 18 | float normalized_curve_val; 19 | 20 | float temp_dist = 0.0; 21 | 22 | Point(float, float); 23 | Point(); 24 | bool operator == (const Point& point); 25 | float cal_dist(Point); 26 | void print(); 27 | static vector get_points(vector, int); 28 | static vector get_inserted_points(long long); 29 | 30 | string get_self(); 31 | }; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /utils/FileReader.h: -------------------------------------------------------------------------------- 1 | #ifndef FILEREADER_H 2 | #define FILEREADER_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | // #include 8 | using namespace std; 9 | # include "../entities/Point.h" 10 | # include "../entities/Mbr.h" 11 | class FileReader 12 | { 13 | string filename; 14 | string delimeter; 15 | 16 | public: 17 | FileReader(); 18 | FileReader(string, string); 19 | vector> get_data(); 20 | vector> get_data(string); 21 | vector get_points(); 22 | vector get_mbrs(); 23 | vector get_points(string filename, string delimeter); 24 | vector get_mbrs(string filename, string delimeter); 25 | }; 26 | 27 | #endif -------------------------------------------------------------------------------- /entities/Mbr.h: -------------------------------------------------------------------------------- 1 | #ifndef MBR_H 2 | #define MBR_H 3 | #include 4 | #include 5 | #include "Point.h" 6 | using namespace std; 7 | 8 | class Mbr 9 | { 10 | public: 11 | float x1 = numeric_limits::max(); 12 | float x2 = numeric_limits::min(); 13 | float y1 = numeric_limits::max(); 14 | float y2 = numeric_limits::min(); 15 | Mbr(); 16 | Mbr(float, float, float, float); 17 | void update(float, float); 18 | void update(Point); 19 | void update(Mbr); 20 | bool contains(Point); 21 | bool strict_contains(Point); 22 | bool interact(Mbr); 23 | static vector get_mbrs(vector, float, int, float); 24 | float cal_dist(Point); 25 | void print(); 26 | vector get_corner_points(); 27 | static Mbr get_mbr(Point point, float knnquerySide); 28 | void clean(); 29 | string get_self(); 30 | }; 31 | 32 | #endif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /curves/z.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Description: source for computing Z-order curve value 3 | // Created: 2016/12/11 4 | // Last updated: 2019/10/17 5 | // Author: Yanchuan Chang 6 | // Mail: changyanchuan@gmail.com 7 | // 8 | 9 | #include "z.H" 10 | #include 11 | #include 12 | 13 | __uint128_t compute_Z_value(long long x[], const size_t& x_len, const long long& bits) 14 | { 15 | assert(bits > 0); 16 | assert(x_len > 0); 17 | for (size_t i = 0; i < x_len; ++i) 18 | { assert(x[i] > 0); } 19 | 20 | __uint128_t z = 0; 21 | for(long long i = 0; i < bits; ++i) 22 | { 23 | for (size_t j = 0; j < x_len; ++j) 24 | { 25 | z += (x[j]%2) * (__uint128_t)2<<(x_len*i+j); 26 | x[j] /= 2; 27 | } 28 | } 29 | return z; 30 | } 31 | 32 | long long compute_Z_value(long long x, long long y, int bit_num) 33 | { 34 | long long result = 0; 35 | for (int i = 0; i < bit_num; i++) 36 | { 37 | long seed = (long) pow(2, i); 38 | 39 | long temp = seed & x; 40 | temp = temp << i; 41 | result += temp; 42 | 43 | temp = seed & y; 44 | temp = temp << (i+1); 45 | result += temp; 46 | } 47 | return result; 48 | } 49 | -------------------------------------------------------------------------------- /utils/SearchHelper.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // #include 6 | using namespace std; 7 | 8 | class SearchHelper 9 | { 10 | public: 11 | template 12 | static long binarySearch(vector, T); 13 | }; 14 | 15 | template 16 | long SearchHelper::binarySearch(vector values, T target) 17 | { 18 | long begin = 0; 19 | long end = values.size() - 1; 20 | if (target <= values[begin]) 21 | { 22 | return begin; 23 | } 24 | if (target >= values[end]) 25 | { 26 | return end; 27 | } 28 | long mid = (begin + end) / 2; 29 | T current = values[mid]; 30 | while (values[mid] > target || values[mid + 1] < target) 31 | { 32 | if (values[mid] > target) 33 | { 34 | end = mid; 35 | } 36 | else if (values[mid] < target) 37 | { 38 | begin = mid; 39 | } 40 | else 41 | { 42 | return mid; 43 | } 44 | mid = (begin + end) / 2; 45 | current = values[mid]; 46 | } 47 | return mid; 48 | } -------------------------------------------------------------------------------- /curves/hilbert.H: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // $RCSfile: hilbert.H,v $ 4 | // $Date: 2001/01/29 14:25:56 $ 5 | // $Revision: 1.1 $ 6 | // $State: Exp $ 7 | // $Author: jan $ 8 | // 9 | // $Source: /u/jan/tpie_0.9.01b/work/RTreeTools/include/RCS/hilbert.H,v $ 10 | // $Locker: $ 11 | // 12 | // Description: declarations for Hilbert values 13 | // Created: 02.02.1998 14 | // Author: Jan Vahrenhold 15 | // mail: jan.vahrenhold@math.uni-muenster.de 16 | // 17 | // Copyright (C) 1998 by 18 | // 19 | // Jan Vahrenhold 20 | // Westfaelische Wilhelms-Universitaet Muenster 21 | // Institut fuer Informatik 22 | // Einsteinstr. 62 23 | // D-48149 Muenster 24 | // GERMANY 25 | // 26 | 27 | #ifndef HILBERT_H 28 | #define HILBERT_H 29 | 30 | #include 31 | #include "hilbert4.H" 32 | 33 | long long compute_Hilbert_value(long long x, long long y, long long side); 34 | 35 | // different hilbert value sequence against compute_Hilbert_value(long long, long long, long long); 36 | bitmask_t compute_Hilbert_value(bitmask_t x[], const size_t& x_len, const long long& bits); 37 | long long compute_Hilbert_value(long long x[], const size_t& x_len, const long long& bits); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /utils/FileWriter.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "ExpRecorder.h" 6 | #include "../entities/Point.h" 7 | #include "../entities/Mbr.h" 8 | // #include 9 | using namespace std; 10 | class FileWriter 11 | { 12 | string filename; 13 | 14 | public: 15 | FileWriter(string); 16 | void write_build(ExpRecorder); 17 | void write_point_query(ExpRecorder); 18 | void write_window_query(ExpRecorder); 19 | void write_kNN_query(ExpRecorder); 20 | void write_acc_window_query(ExpRecorder); 21 | void write_acc_kNN_query(ExpRecorder); 22 | void write_insert(ExpRecorder); 23 | void write_delete(ExpRecorder); 24 | 25 | void write_insert_point_query(ExpRecorder); 26 | void write_insert_window_query(ExpRecorder); 27 | void write_insert_acc_window_query(ExpRecorder); 28 | void write_insert_kNN_query(ExpRecorder); 29 | void write_insert_acc_kNN_query(ExpRecorder); 30 | 31 | void write_delete_point_query(ExpRecorder); 32 | void write_delete_window_query(ExpRecorder); 33 | void write_delete_kNN_query(ExpRecorder); 34 | void write_delete_acc_window_query(ExpRecorder); 35 | void write_delete_acc_kNN_query(ExpRecorder); 36 | 37 | void write_mbrs(vector mbrs, ExpRecorder expRecorder); 38 | void write_points(vector points, ExpRecorder expRecorder); 39 | void write_inserted_points(vector points, ExpRecorder expRecorder); 40 | }; 41 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=g++ -O3 -std=c++14 2 | SRCS=$(wildcard *.cpp */*.cpp) 3 | OBJS=$(patsubst %.cpp, %.o, $(SRCS)) 4 | 5 | # for MacOs 6 | # INCLUDE = -I/usr/local/include/libtorch/include -I/usr/local/include/libtorch/include/torch/csrc/api/include 7 | # LIB +=-L/usr/local/include/libtorch/lib -ltorch -lc10 -lpthread 8 | # FLAG = -Xlinker -rpath -Xlinker /usr/local/include/libtorch/lib 9 | 10 | TYPE = CPU 11 | TYPE = GPU 12 | 13 | # for linux 14 | ifeq ($(TYPE), GPU) 15 | INCLUDE = -I/home/liuguanli/Documents/libtorch_gpu/include -I/home/liuguanli/Documents/libtorch_gpu/include/torch/csrc/api/include 16 | LIB +=-L/home/liuguanli/Documents/libtorch_gpu/lib -ltorch -lc10 -lpthread 17 | FLAG = -Wl,-rpath=/home/liuguanli/Documents/libtorch_gpu/lib 18 | else 19 | INCLUDE = -I/home/liuguanli/Documents/libtorch/include -I/home/liuguanli/Documents/libtorch/include/torch/csrc/api/include 20 | LIB +=-L/home/liuguanli/Documents/libtorch/lib -ltorch -lc10 -lpthread 21 | FLAG = -Wl,-rpath=/home/liuguanli/Documents/libtorch/lib 22 | endif 23 | 24 | 25 | 26 | # INCLUDE = -I/home/liuguanli/Documents/libtorch/include -I/home/liuguanli/Documents/libtorch/include/torch/csrc/api/include 27 | # LIB +=-L/home/liuguanli/Documents/libtorch/lib -ltorch -lc10 -lpthread 28 | # FLAG = -Wl,-rpath=/home/liuguanli/Documents/libtorch/lib 29 | 30 | NAME=$(wildcard *.cpp) 31 | TARGET=$(patsubst %.cpp, %, $(NAME)) 32 | 33 | 34 | $(TARGET):$(OBJS) 35 | $(CC) -o $@ $^ $(INCLUDE) $(LIB) $(FLAG) 36 | %.o:%.cpp 37 | $(CC) -o $@ -c $< -g $(INCLUDE) 38 | 39 | clean: 40 | rm -rf $(TARGET) $(OBJS) 41 | 42 | # # g++ -std=c++11 Exp.cpp FileReader.o -ltensorflow -o Exp_tf 43 | -------------------------------------------------------------------------------- /utils/Constants.h: -------------------------------------------------------------------------------- 1 | #ifndef CONSTANTS_H 2 | #define CONSTANTS_H 3 | #include 4 | using namespace std; 5 | class Constants 6 | { 7 | public: 8 | static const int DIM = 2; 9 | static const int PAGESIZE = 100; 10 | static const int EACH_DIM_LENGTH = 8; 11 | static const int INFO_LENGTH = 8; 12 | static const int MAX_WIDTH = 16; 13 | static const int EPOCH = 500; 14 | static const int START_EPOCH = 300; 15 | static const int EPOCH_ADDED = 100; 16 | static const int HIDDEN_LAYER_WIDTH = 50; 17 | static const int THRESHOLD = 20000; 18 | 19 | static const int DEFAULT_SIZE = 16000000; 20 | static const int DEFAULT_SKEWNESS = 4; 21 | 22 | static const double LEARNING_RATE; 23 | static const string RECORDS; 24 | static const string QUERYPROFILES; 25 | static const string DATASETS; 26 | 27 | static const string DEFAULT_DISTRIBUTION; 28 | 29 | static const string BUILD; 30 | static const string UPDATE; 31 | static const string POINT; 32 | static const string WINDOW; 33 | static const string ACCWINDOW; 34 | static const string KNN; 35 | static const string ACCKNN; 36 | static const string INSERT; 37 | static const string DELETE; 38 | static const string INSERTPOINT; 39 | static const string INSERTWINDOW; 40 | static const string INSERTACCWINDOW; 41 | static const string INSERTKNN; 42 | static const string INSERTACCKNN; 43 | static const string DELETEPOINT; 44 | static const string DELETEWINDOW; 45 | static const string DELETEACCWINDOW; 46 | static const string DELETEKNN; 47 | static const string DELETEACCKNN; 48 | 49 | static const string TORCH_MODELS; 50 | Constants(); 51 | }; 52 | 53 | #endif -------------------------------------------------------------------------------- /entities/Point.cpp: -------------------------------------------------------------------------------- 1 | #include "Point.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | using namespace std; 13 | 14 | Point::Point() 15 | { 16 | } 17 | 18 | Point::Point(float x, float y) 19 | { 20 | this->x = x; 21 | this->y = y; 22 | } 23 | 24 | bool Point::operator==(const Point &point) 25 | { 26 | if (this == &point) 27 | { 28 | return true; 29 | } 30 | else if (this->x == point.x && this->y == point.y) 31 | { 32 | return true; 33 | } 34 | return false; 35 | } 36 | 37 | float Point::cal_dist(Point point) 38 | { 39 | if (temp_dist == 0) 40 | temp_dist = sqrt(pow((point.x - x), 2) + pow((point.y - y), 2)); 41 | return temp_dist; 42 | } 43 | 44 | void Point::print() 45 | { 46 | cout << "(x=" << x << ",y=" << y << ")" << " index=" << index << " curve_val=" << curve_val << endl; 47 | } 48 | 49 | vector Point::get_points(vector dataset, int num) 50 | { 51 | srand(time(0)); 52 | int length = dataset.size(); 53 | vector points; 54 | for (int i = 0; i < num; i++) 55 | { 56 | int index = rand() % length; 57 | points.push_back(dataset[index]); 58 | } 59 | return points; 60 | } 61 | 62 | vector Point::get_inserted_points(long long num) 63 | { 64 | srand(time(0)); 65 | vector points; 66 | for (int i = 0; i < num; i++) 67 | { 68 | float x = (float)(rand() % num) / num; 69 | float y = (float)(rand() % num) / num; 70 | Point point(x, y); 71 | points.push_back(point); 72 | } 73 | return points; 74 | } 75 | 76 | string Point::get_self() 77 | { 78 | return to_string(x) + "," + to_string(y) + "\n"; 79 | } 80 | -------------------------------------------------------------------------------- /entities/NonLeafNode.cpp: -------------------------------------------------------------------------------- 1 | #include "NonLeafNode.h" 2 | #include "LeafNode.h" 3 | #include "../utils/Constants.h" 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | NonLeafNode::NonLeafNode() 10 | { 11 | children = new vector(); 12 | } 13 | 14 | NonLeafNode::NonLeafNode(Mbr mbr) 15 | { 16 | children = new vector(); 17 | this->mbr = mbr; 18 | } 19 | 20 | void NonLeafNode::addNode(Node *node) 21 | { 22 | //assert(children->size() <= Constants::PAGESIZE); 23 | // add 24 | children->push_back(node); 25 | // update MBR 26 | mbr.update(node->mbr); 27 | 28 | if (typeid(*node) == typeid(NonLeafNode)) 29 | { 30 | NonLeafNode *nonLeafNode = dynamic_cast(node); 31 | nonLeafNode->parent = this; 32 | } 33 | else 34 | { 35 | LeafNode *leafNode = dynamic_cast(node); 36 | leafNode->parent = this; 37 | } 38 | } 39 | 40 | void NonLeafNode::addNodes(vector nodes) 41 | { 42 | for (int i = 0; i < nodes.size(); i++) 43 | { 44 | addNode(nodes[i]); 45 | } 46 | // cout<< mbr.x1 << " " << mbr.y1 << " " << mbr.x2 << " " << mbr.y2 << endl; 47 | } 48 | 49 | bool NonLeafNode::is_full() 50 | { 51 | return children->size() >= Constants::PAGESIZE; 52 | } 53 | 54 | NonLeafNode *NonLeafNode::split() 55 | { 56 | // build rightNode 57 | NonLeafNode *right = new NonLeafNode(); 58 | right->parent = this->parent; 59 | int mid = Constants::PAGESIZE / 2; 60 | auto bn = children->begin() + mid; 61 | auto en = children->end(); 62 | vector vec(bn, en); 63 | right->addNodes(vec); 64 | 65 | // build leftNode 66 | auto bn1 = children->begin(); 67 | auto en1 = children->begin() + mid; 68 | vector vec1(bn1, en1); 69 | children->clear(); 70 | addNodes(vec1); 71 | 72 | return right; 73 | } 74 | -------------------------------------------------------------------------------- /utils/ExpRecorder.h: -------------------------------------------------------------------------------- 1 | #ifndef EXPRECORDER_H 2 | #define EXPRECORDER_H 3 | 4 | #include 5 | #include "../entities/Point.h" 6 | #include 7 | #include "Constants.h" 8 | #include "SortTools.h" 9 | #include 10 | using namespace std; 11 | 12 | class ExpRecorder 13 | { 14 | 15 | public: 16 | 17 | priority_queue, sortForKNN2> pq; 18 | 19 | long long index_high; 20 | long long index_low; 21 | 22 | long long leaf_node_num; 23 | long long non_leaf_node_num; 24 | 25 | int max_error = 0; 26 | int min_error = 0; 27 | 28 | int depth = 0; 29 | 30 | long long total_depth; 31 | 32 | int N = Constants::THRESHOLD; 33 | 34 | long long average_max_error = 0; 35 | long long average_min_error = 0; 36 | 37 | int last_level_model_num = 0; 38 | 39 | string structure_name; 40 | string distribution; 41 | long dataset_cardinality; 42 | 43 | long long insert_num; 44 | long delete_num; 45 | float window_size; 46 | float window_ratio; 47 | int k_num; 48 | int skewness = 1; 49 | 50 | long time; 51 | long insert_time; 52 | long delete_time; 53 | long long rebuild_time; 54 | int rebuild_num; 55 | double page_access = 1.0; 56 | double accuracy; 57 | long size; 58 | 59 | int window_query_result_size; 60 | int acc_window_query_qesult_size; 61 | vector knn_query_results; 62 | vector acc_knn_query_results; 63 | 64 | vector window_query_results; 65 | ExpRecorder(); 66 | string get_time(); 67 | string get_time_pageaccess(); 68 | string get_time_accuracy(); 69 | string get_time_pageaccess_accuracy(); 70 | string get_insert_time_pageaccess_rebuild(); 71 | string get_size(); 72 | string get_time_size(); 73 | string get_time_size_errors(); 74 | 75 | string get_insert_time_pageaccess(); 76 | string get_delete_time_pageaccess(); 77 | void cal_size(); 78 | void clean(); 79 | }; 80 | 81 | #endif -------------------------------------------------------------------------------- /utils/Constants.cpp: -------------------------------------------------------------------------------- 1 | #include "Constants.h" 2 | 3 | #ifdef __APPLE__ 4 | // const string Constants::RECORDS = "/Users/guanli/Dropbox/records/VLDB20/"; 5 | // const string Constants::QUERYPROFILES = "/Users/guanli/Documents/datasets/RLRtree/queryprofile/"; 6 | // const string Constants::DATASETS = "/Users/guanli/Documents/datasets/RLRtree/raw/"; 7 | const string Constants::RECORDS = "./files/records/"; 8 | const string Constants::QUERYPROFILES = "./files/queryprofile/"; 9 | const string Constants::DATASETS = "./datasets/"; 10 | #else 11 | // const string Constants::RECORDS = "/home/liuguanli/Dropbox/records/VLDB20/"; 12 | // const string Constants::QUERYPROFILES = "/home/liuguanli/Documents/datasets/RLRtree/queryprofile/"; 13 | // const string Constants::DATASETS = "/home/liuguanli/Documents/datasets/RLRtree/raw/"; 14 | const string Constants::RECORDS = "./files/records/"; 15 | const string Constants::QUERYPROFILES = "./files/queryprofile/"; 16 | const string Constants::DATASETS = "./datasets/"; 17 | #endif 18 | const string Constants::DEFAULT_DISTRIBUTION = "skewed"; 19 | const string Constants::BUILD = "build/"; 20 | const string Constants::UPDATE = "update/"; 21 | const string Constants::POINT = "point/"; 22 | const string Constants::WINDOW = "window/"; 23 | const string Constants::ACCWINDOW = "accwindow/"; 24 | const string Constants::KNN = "knn/"; 25 | const string Constants::ACCKNN = "accknn/"; 26 | const string Constants::INSERT = "insert/"; 27 | const string Constants::DELETE = "delete/"; 28 | const string Constants::INSERTPOINT = "insertPoint/"; 29 | const string Constants::INSERTWINDOW = "insertWindow/"; 30 | const string Constants::INSERTACCWINDOW = "insertAccWindow/"; 31 | const string Constants::INSERTKNN = "insertKnn/"; 32 | const string Constants::INSERTACCKNN= "insertAccKnn/"; 33 | const string Constants::DELETEPOINT= "delete_point/"; 34 | const string Constants::DELETEWINDOW= "deleteWindow/"; 35 | const string Constants::DELETEACCWINDOW= "deleteAccWindow/"; 36 | const string Constants::DELETEKNN= "deleteKnn/"; 37 | const string Constants::DELETEACCKNN= "deleteAccKnn/"; 38 | 39 | const string Constants::TORCH_MODELS = "./torch_models/"; 40 | const double Constants::LEARNING_RATE = 0.05; 41 | Constants::Constants() 42 | { 43 | } 44 | -------------------------------------------------------------------------------- /entities/LeafNode.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Node.h" 3 | #include "LeafNode.h" 4 | #include "Point.h" 5 | #include "../utils/Constants.h" 6 | #include 7 | using namespace std; 8 | 9 | LeafNode::LeafNode() 10 | { 11 | children = new vector(); 12 | } 13 | 14 | LeafNode::LeafNode(Mbr mbr) 15 | { 16 | this->mbr = mbr; 17 | children = new vector(); 18 | } 19 | 20 | void LeafNode::add_point(Point point) 21 | { 22 | // add 23 | children->push_back(point); 24 | // update MBR 25 | mbr.update(point.x, point.y); 26 | } 27 | 28 | void LeafNode::add_points(vector points) 29 | { 30 | for (int i = 0; i < points.size(); i++) 31 | { 32 | add_point(points[i]); 33 | } 34 | } 35 | 36 | bool LeafNode::is_full() 37 | { 38 | return children->size() >= Constants::PAGESIZE; 39 | } 40 | 41 | LeafNode *LeafNode::split() 42 | { 43 | // build rightNode 44 | LeafNode *right = new LeafNode(); 45 | right->parent = this->parent; 46 | int mid = Constants::PAGESIZE / 2; 47 | vector vec(children->begin() + mid, children->end()); 48 | right->add_points(vec); 49 | 50 | // build leftNode 51 | vector vec1(children->begin(), children->begin() + mid); 52 | children->clear(); 53 | add_points(vec1); 54 | return right; 55 | } 56 | 57 | LeafNode LeafNode::split1() 58 | { 59 | // build rightNode 60 | LeafNode right; 61 | right.parent = this->parent; 62 | int mid = Constants::PAGESIZE / 2; 63 | vector vec(children->begin() + mid, children->end()); 64 | right.add_points(vec); 65 | 66 | // build leftNode 67 | vector vec1(children->begin(), children->begin() + mid); 68 | children->clear(); 69 | add_points(vec1); 70 | return right; 71 | } 72 | 73 | bool LeafNode::delete_point(Point point) 74 | { 75 | vector::iterator iter = find(children->begin(), children->end(), point); 76 | if (iter != children->end()) 77 | { 78 | // cout << "find it" << endl; 79 | children->erase(iter); 80 | // update mbr 81 | if (!mbr.strict_contains(point)) 82 | { 83 | mbr.clean(); 84 | for (int i = 0; i < children->size(); i++) 85 | { 86 | mbr.update(point.x, point.y); 87 | } 88 | } 89 | return true; 90 | } 91 | return false; 92 | } 93 | -------------------------------------------------------------------------------- /curves/hilbert.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // $RCSfile: hilbert.C,v $ 3 | // $Date: 2001/01/29 14:27:01 $ 4 | // $Revision: 1.1 $ 5 | // $State: Exp $ 6 | // $Author: jan $ 7 | // 8 | // $Source: /u/jan/tpie_0.9.01b/work/RTreeTools/src/RCS/hilbert.C,v $ 9 | // $Locker: $ 10 | // 11 | // Description: source for computing Hilbert values 12 | // Created: 02.02.1998 13 | // Author: Jan Vahrenhold 14 | // mail: jan.vahrenhold@math.uni-muenster.de 15 | // 16 | // Copyright (C) 1998 by 17 | // 18 | // Jan Vahrenhold 19 | // Westfaelische Wilhelms-Universitaet Muenster 20 | // Institut fuer Informatik 21 | // Einsteinstr. 62 22 | // D-48149 Muenster 23 | // GERMANY 24 | // 25 | 26 | // Workaround for a linker problem with STL and gcc-2.7.2 27 | 28 | #include "hilbert.H" 29 | #include 30 | #include 31 | #include 32 | 33 | // 34 | // This code is taken from: 35 | // 36 | // Jagadish, H.V.: "Linear Clustering of Objects with Multiple Attributes", 37 | // in: Proceedings of the 1990 ACM SIGMOD International Conference on 38 | // Management of Data (1990), 332-342. 39 | // 40 | 41 | int HILBERTrotation_table[4] = {3, 0, 0, 1}; 42 | int HILBERTsense_table[4] = {-1, 1, 1, -1}; 43 | int HILBERTquad_table[4][2][2] = { {{0, 1}, {3, 2}}, 44 | {{1, 2}, {0, 3}}, 45 | {{2, 3}, {1, 0}}, 46 | {{3, 0}, {2, 1}} }; 47 | 48 | long long compute_Hilbert_value(long long x, long long y, long long side) 49 | { 50 | 51 | assert(0 <= x); 52 | assert(0 <= y); 53 | assert(x <= side); 54 | assert(y <= side); 55 | assert(side >= 0); 56 | 57 | int rotation = 0; 58 | int sense = 1; 59 | long long num = 0; 60 | long long k = 0; 61 | long long xbit = 0; 62 | long long ybit = 0; 63 | int quad = 0; 64 | 65 | for(k = side/2; k > 0; k = k/2) { 66 | xbit = x/k; 67 | ybit = y/k; 68 | x -= k*xbit; 69 | y -= k*ybit; 70 | quad = HILBERTquad_table[rotation][xbit][ybit]; 71 | num += (sense == -1) ? k*k*(3-quad) : k*k*quad; 72 | rotation += HILBERTrotation_table[quad]; 73 | if (rotation >= 4) rotation -= 4; 74 | sense *= HILBERTsense_table[quad]; 75 | } 76 | return num; 77 | } 78 | 79 | bitmask_t compute_Hilbert_value(bitmask_t x[], const size_t& x_len, const long long& bits) 80 | { 81 | return hilbert_c2i((unsigned)x_len, (unsigned)bits, x); // reinterpret_cast(x)); 82 | } 83 | 84 | long long compute_Hilbert_value(long long x[], const size_t& x_len, const long long& bits) 85 | { 86 | assert(x_len == 2); 87 | return compute_Hilbert_value(x[0], x[1], (long long)pow(2, bits)); 88 | } 89 | 90 | // End (Jagadish) 91 | -------------------------------------------------------------------------------- /utils/SortTools.h: -------------------------------------------------------------------------------- 1 | #ifndef SORTTOOLS_H 2 | #define SORTTOOLS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "../utils/Constants.h" 15 | #include "../entities/Mbr.h" 16 | #include "../entities/Point.h" 17 | #include "../entities/NodeExtend.h" 18 | 19 | using namespace std; 20 | 21 | // long long diff(struct timespec start, struct timespec end) 22 | // { 23 | // struct timespec temp; 24 | // long long gap; 25 | // if ((end.tv_nsec - start.tv_nsec) < 0) 26 | // { 27 | // temp.tv_sec = end.tv_sec - start.tv_sec - 1; 28 | // temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec; 29 | // } 30 | // else 31 | // { 32 | // temp.tv_sec = end.tv_sec - start.tv_sec; 33 | // temp.tv_nsec = end.tv_nsec - start.tv_nsec; 34 | // } 35 | // gap = temp.tv_sec * 1000000000 + temp.tv_nsec; 36 | // return gap; 37 | // } 38 | 39 | // struct timespec diff(struct timespec start, struct timespec end) 40 | // { 41 | // struct timespec temp; 42 | // if ((end.tv_nsec - start.tv_nsec) < 0) 43 | // { 44 | // temp.tv_sec = end.tv_sec - start.tv_sec - 1; 45 | // temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec; 46 | // } 47 | // else 48 | // { 49 | // temp.tv_sec = end.tv_sec - start.tv_sec; 50 | // temp.tv_nsec = end.tv_nsec - start.tv_nsec; 51 | // } 52 | // return temp; 53 | // } 54 | 55 | struct sortPQ 56 | { 57 | bool operator()(const NodeExtend *node1, const NodeExtend *node2) 58 | { 59 | return (node1->dist > node2->dist); 60 | } 61 | }; 62 | 63 | struct sortPQ_Desc 64 | { 65 | bool operator()(const NodeExtend *node1, const NodeExtend *node2) 66 | { 67 | return (node1->dist < node2->dist); 68 | } 69 | }; 70 | 71 | struct sortForKNN 72 | { 73 | Point queryPoint; 74 | sortForKNN(Point &point) 75 | { 76 | queryPoint = point; 77 | } 78 | bool operator()(Point point1, Point point2) 79 | { 80 | return (point1.cal_dist(queryPoint) < point2.cal_dist(queryPoint)); 81 | } 82 | }; 83 | 84 | struct sortForKNN1 85 | { 86 | bool operator()(Point point1, Point point2) 87 | { 88 | return point1.temp_dist < point2.temp_dist; 89 | } 90 | }; 91 | 92 | struct sortForKNN2 93 | { 94 | bool operator()(Point point1, Point point2) 95 | { 96 | return point1.temp_dist > point2.temp_dist; 97 | } 98 | }; 99 | 100 | struct sortX 101 | { 102 | bool operator()(const Point point1, const Point point2) 103 | { 104 | return (point1.x < point2.x); 105 | } 106 | }; 107 | 108 | struct sortY 109 | { 110 | bool operator()(const Point point1, const Point point2) 111 | { 112 | return (point1.y < point2.y); 113 | } 114 | }; 115 | 116 | struct sort_curve_val 117 | { 118 | bool operator()(const Point point1, const Point point2) 119 | { 120 | return (point1.curve_val < point2.curve_val); 121 | } 122 | }; 123 | 124 | #endif -------------------------------------------------------------------------------- /utils/FileReader.cpp: -------------------------------------------------------------------------------- 1 | #include "FileReader.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // #include "../entities/Point.cpp" 12 | #include "../entities/Mbr.h" 13 | using namespace std; 14 | 15 | 16 | FileReader::FileReader() 17 | { 18 | } 19 | 20 | FileReader::FileReader(string filename, string delimeter) 21 | { 22 | this->filename = filename; 23 | this->delimeter = delimeter; 24 | } 25 | 26 | vector> FileReader::get_data(string path) 27 | { 28 | ifstream file(path); 29 | 30 | vector> data_list; 31 | 32 | string line = ""; 33 | // Iterate through each line and split the content using delimeter 34 | while (getline(file, line)) 35 | { 36 | vector vec; 37 | boost::algorithm::split(vec, line, boost::is_any_of(delimeter)); 38 | data_list.push_back(vec); 39 | } 40 | // Close the File 41 | file.close(); 42 | 43 | return data_list; 44 | } 45 | 46 | vector> FileReader::get_data() 47 | { 48 | return get_data(this->filename); 49 | } 50 | 51 | vector FileReader::get_points() 52 | { 53 | ifstream file(filename); 54 | vector points; 55 | string line = ""; 56 | delimeter = "\t"; 57 | 58 | while (getline(file, line)) 59 | { 60 | vector vec; 61 | boost::algorithm::split(vec, line, boost::is_any_of(delimeter)); 62 | if (vec.size() > 1) 63 | { 64 | Point point(stod(vec[0]), stod(vec[1])); 65 | points.push_back(point); 66 | } 67 | } 68 | // Close the File 69 | file.close(); 70 | 71 | return points; 72 | } 73 | 74 | vector FileReader::get_mbrs() 75 | { 76 | ifstream file(filename); 77 | 78 | vector mbrs; 79 | 80 | string line = ""; 81 | while (getline(file, line)) 82 | { 83 | vector vec; 84 | boost::algorithm::split(vec, line, boost::is_any_of(delimeter)); 85 | Mbr mbr(stod(vec[0]), stod(vec[1]), stod(vec[2]), stod(vec[3])); 86 | mbrs.push_back(mbr); 87 | } 88 | 89 | file.close(); 90 | 91 | return mbrs; 92 | } 93 | 94 | vector FileReader::get_points(string filename, string delimeter) 95 | { 96 | ifstream file(filename); 97 | 98 | vector points; 99 | 100 | string line = ""; 101 | while (getline(file, line)) 102 | { 103 | vector vec; 104 | boost::algorithm::split(vec, line, boost::is_any_of(delimeter)); 105 | Point point(stod(vec[0]), stod(vec[1])); 106 | points.push_back(point); 107 | } 108 | // Close the File 109 | file.close(); 110 | 111 | return points; 112 | } 113 | 114 | vector FileReader::get_mbrs(string filename, string delimeter) 115 | { 116 | ifstream file(filename); 117 | 118 | vector mbrs; 119 | 120 | string line = ""; 121 | while (getline(file, line)) 122 | { 123 | vector vec; 124 | boost::algorithm::split(vec, line, boost::is_any_of(delimeter)); 125 | Mbr mbr(stod(vec[0]), stod(vec[1]), stod(vec[2]), stod(vec[3])); 126 | mbrs.push_back(mbr); 127 | } 128 | 129 | file.close(); 130 | 131 | return mbrs; 132 | } 133 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RSMI 2 | 3 | 4 | 5 | 6 | ## How to use 7 | 8 | ### 1. Required libraries 9 | 10 | #### LibTorch 11 | homepage: https://pytorch.org/get-started/locally/ 12 | 13 | CPU version: https://download.pytorch.org/libtorch/cpu/libtorch-macos-1.4.0.zip 14 | 15 | For GPU version, choose according to your setup. 16 | 17 | #### boost 18 | 19 | homepage: https://www.boost.org/ 20 | 21 | #### 2. Change Makefile 22 | 23 | Choose CPU or GPU 24 | 25 | ``` 26 | # TYPE = CPU 27 | TYPE = GPU 28 | 29 | Change *home/liuguanli/Documents/libtorch_gpu* to your own path. 30 | 31 | ifeq ($(TYPE), GPU) 32 | INCLUDE = -I/home/liuguanli/Documents/libtorch_gpu/include -I/home/liuguanli/Documents/libtorch_gpu/include/torch/csrc/api/include 33 | LIB +=-L/home/liuguanli/Documents/libtorch_gpu/lib -ltorch -lc10 -lpthread 34 | FLAG = -Wl,-rpath=/home/liuguanli/Documents/libtorch_gpu/lib 35 | else 36 | INCLUDE = -I/home/liuguanli/Documents/libtorch/include -I/home/liuguanli/Documents/libtorch/include/torch/csrc/api/include 37 | LIB +=-L/home/liuguanli/Documents/libtorch/lib -ltorch -lc10 -lpthread 38 | FLAG = -Wl,-rpath=/home/liuguanli/Documents/libtorch/lib 39 | endif 40 | ``` 41 | #### 3. Change Exp.cpp 42 | 43 | comment *#define use_gpu* to use CPU version 44 | 45 | ```C++ 46 | #ifndef use_gpu 47 | #define use_gpu 48 | . 49 | . 50 | . 51 | #endif // use_gpu 52 | ``` 53 | 54 | #### 4. Change path 55 | 56 | Change the path if you do not want to store the datasets under the project's root path. 57 | 58 | Constants.h 59 | ```C++ 60 | const string Constants::RECORDS = "./files/records/"; 61 | const string Constants::QUERYPROFILES = "./files/queryprofile/"; 62 | const string Constants::DATASETS = "./datasets/"; 63 | ``` 64 | 65 | data_generator.py 66 | ```python 67 | if __name__ == '__main__': 68 | distribution, size, skewness, filename, dim = parser(sys.argv[1:]) 69 | if distribution == 'uniform': 70 | filename = "datasets/uniform_%d_1_%d_.csv" 71 | getUniformPoints(size, filename, dim) 72 | elif distribution == 'normal': 73 | filename = "datasets/normal_%d_1_%d_.csv" 74 | getNormalPoints(size, filename, dim) 75 | elif distribution == 'skewed': 76 | filename = "datasets/skewed_%d_%d_%d_.csv" 77 | getSkewedPoints(size, skewness, filename, dim) 78 | ``` 79 | 80 | 81 | #### 5. Prepare datasets 82 | 83 | ```bash 84 | python data_generator.py -d uniform -s 1000000 -n 1 -f datasets/uniform_1000000_1_2_.csv -m 2 85 | ``` 86 | 87 | ```bash 88 | python data_generator.py -d normal -s 1000000 -n 1 -f datasets/normal_1000000_1_2_.csv -m 2 89 | ``` 90 | 91 | ```bash 92 | python data_generator.py -d skewed -s 1000000 -n 4 -f datasets/skewed_1000000_4_2_.csv -m 2 93 | ``` 94 | 95 | #### 6. Run 96 | 97 | ```bash 98 | make clean 99 | make -f Makefile 100 | ./Exp -c 1000000 -d uniform -s 1 101 | ./Exp -c 1000000 -d normal -s 1 102 | ./Exp -c 1000000 -d skewed -s 4 103 | ``` 104 | 105 | ### Notions 106 | 107 | model save. If you do not record the training time, you can use trained models and load them. 108 | 109 | 110 | ```C++ 111 | //RSMI.h 112 | std::ifstream fin(this->model_path); 113 | if (!fin) 114 | { 115 | net->train_model(locations, labels); 116 | torch::save(net, this->model_path); 117 | } 118 | else 119 | { 120 | torch::load(net, this->model_path); 121 | } 122 | ``` 123 | 124 | ### Paper 125 | 126 | > Jianzhong Qi, Guanli Liu, Christian S. Jensen, Lars Kulik: [Effectively Learning Spatial Indices](http://www.vldb.org/pvldb/vol13/p2341-qi.pdf). Proc. VLDB Endow. 13(11): 2341-2354 (2020) 127 | 128 | ```tex 129 | @article{DBLP:journals/pvldb/QiLJK20, 130 | author = {Jianzhong Qi and 131 | Guanli Liu and 132 | Christian S. Jensen and 133 | Lars Kulik}, 134 | title = {Effectively Learning Spatial Indices}, 135 | journal = {{PVLDB}} 136 | volume = {13}, 137 | number = {11}, 138 | pages = {2341--2354}, 139 | year = {2020}, 140 | url = {http://www.vldb.org/pvldb/vol13/p2341-qi.pdf}, 141 | } 142 | ``` 143 | 144 | -------------------------------------------------------------------------------- /utils/ExpRecorder.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ExpRecorder.h" 4 | #include "Constants.h" 5 | using namespace std; 6 | 7 | ExpRecorder::ExpRecorder() 8 | { 9 | } 10 | 11 | string ExpRecorder::get_time() 12 | { 13 | return "time:" + to_string(time) + "\n"; 14 | } 15 | 16 | string ExpRecorder::get_time_size_errors() 17 | { 18 | string result = "time:" + to_string(time) + "\n" + "size:" + to_string(size) + "\n" + "maxError:" + to_string(max_error) + "\n" + "min_error:" + to_string(min_error) + "\n" + "leaf_node_num:" + to_string(leaf_node_num) + "\n" + "average_max_error:" + to_string(average_max_error) + "\n" + "average_min_error:" + to_string(average_min_error) + "\n" + "depth:" + to_string(depth) + "\n"; 19 | time = 0; 20 | size = 0; 21 | max_error = 0; 22 | min_error = 0; 23 | leaf_node_num = 0; 24 | depth = 0; 25 | return result; 26 | } 27 | 28 | string ExpRecorder::get_time_size() 29 | { 30 | string result = "time:" + to_string(time) + "\n" + "size:" + to_string(size) + "\n"; 31 | time = 0; 32 | size = 0; 33 | return result; 34 | } 35 | 36 | string ExpRecorder::get_time_accuracy() 37 | { 38 | string result = "time:" + to_string(time) + "\n" + "accuracy:" + to_string(accuracy) + "\n"; 39 | time = 0; 40 | accuracy = 0; 41 | return result; 42 | } 43 | 44 | string ExpRecorder::get_time_pageaccess_accuracy() 45 | { 46 | string result = "time:" + to_string(time) + "\n" + "pageaccess:" + to_string(page_access) + "\n" + "accuracy:" + to_string(accuracy) + "\n"; 47 | time = 0; 48 | page_access = 0; 49 | accuracy = 0; 50 | return result; 51 | } 52 | 53 | string ExpRecorder::get_time_pageaccess() 54 | { 55 | string result = "time:" + to_string(time) + "\n" + "pageaccess:" + to_string(page_access) + "\n"; 56 | time = 0; 57 | page_access = 0; 58 | return result; 59 | } 60 | 61 | string ExpRecorder::get_delete_time_pageaccess() 62 | { 63 | string result = "time:" + to_string(delete_time) + "\n" + "pageaccess:" + to_string(page_access) + "\n"; 64 | time = 0; 65 | page_access = 0; 66 | return result; 67 | } 68 | 69 | string ExpRecorder::get_insert_time_pageaccess() 70 | { 71 | string result = "time:" + to_string(insert_time) + "\n" + "pageaccess:" + to_string(page_access) + "\n"; 72 | time = 0; 73 | page_access = 0; 74 | return result; 75 | } 76 | 77 | string ExpRecorder::get_insert_time_pageaccess_rebuild() 78 | { 79 | string result = "time:" + to_string(insert_time) + "\n" + "pageaccess:" + to_string(page_access) + "\n" + "rebuild_num:" + to_string(rebuild_num) + "\n" + "rebuild_time:" + to_string(rebuild_time) + "\n"; 80 | time = 0; 81 | page_access = 0; 82 | return result; 83 | } 84 | 85 | string ExpRecorder::get_size() 86 | { 87 | string result = "size:" + to_string(size) + "\n"; 88 | size = 0; 89 | return result; 90 | } 91 | 92 | void ExpRecorder::cal_size() 93 | { 94 | size = (Constants::DIM * Constants::PAGESIZE * Constants::EACH_DIM_LENGTH + Constants::PAGESIZE * Constants::INFO_LENGTH + Constants::DIM * Constants::DIM * Constants::EACH_DIM_LENGTH) * leaf_node_num + non_leaf_node_num * Constants::EACH_DIM_LENGTH; 95 | } 96 | 97 | void ExpRecorder::clean() 98 | { 99 | index_high = 0; 100 | index_low = 0; 101 | 102 | leaf_node_num = 0; 103 | non_leaf_node_num = 0; 104 | 105 | window_query_result_size = 0; 106 | acc_window_query_qesult_size = 0; 107 | 108 | knn_query_results.clear(); 109 | knn_query_results.shrink_to_fit(); 110 | 111 | acc_knn_query_results.clear(); 112 | acc_knn_query_results.shrink_to_fit(); 113 | 114 | time = 0; 115 | page_access = 0; 116 | accuracy = 0; 117 | size = 0; 118 | 119 | window_query_results.clear(); 120 | window_query_results.shrink_to_fit(); 121 | 122 | rebuild_num = 0; 123 | rebuild_time = 0; 124 | max_error = 0; 125 | min_error = 0; 126 | 127 | average_min_error = 0; 128 | average_max_error = 0; 129 | 130 | last_level_model_num = 0; 131 | depth = 0; 132 | } 133 | -------------------------------------------------------------------------------- /data_generator.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/python 2 | # coding=utf-8 3 | 4 | import sys, getopt 5 | import os 6 | 7 | import random 8 | import numpy as np 9 | import matplotlib.pyplot as plt 10 | from sklearn import preprocessing 11 | import matplotlib.patches as patches 12 | from matplotlib.ticker import MultipleLocator 13 | import configparser 14 | import tensorflow as tf 15 | import time 16 | 17 | curPath = os.path.abspath(os.path.dirname(__file__)) 18 | rootPath = os.path.split(curPath)[0] 19 | sys.path.append(rootPath) 20 | 21 | os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" 22 | os.environ["CUDA_VISIBLE_DEVICES"] = "-1" 23 | 24 | def getUniformPoints(num, filename, dim): 25 | all_result = {} 26 | for i in range(dim - 1): 27 | all_result[i+2] = [] 28 | for i in range(num): 29 | node_string = '' 30 | for j in range(dim): 31 | val = random.uniform(0, 1) 32 | node_string = node_string + str(val) + "," 33 | if j >= 1: 34 | all_result[j + 1].append(node_string + str(i) + "\n") 35 | # node_string = node_string + str(i) + "\n" 36 | # all_result.append(node_string) 37 | 38 | for j in range(dim - 1): 39 | name = filename % (num, j + 2) 40 | all_fo = open(name, "w") 41 | for i in range(num): 42 | all_fo.write(all_result[j+2][i]) 43 | all_fo.close() 44 | 45 | def getNormalPoints(num, filename, dim): 46 | locations_tf = [] 47 | for i in range(dim): 48 | # locations_tf.append(tf.random.truncated_normal([num * 2, 1], mean=0.5, stddev=0.125, dtype=tf.float32)) 49 | locations_tf.append(tf.random_normal([num * 2, 1], mean=0.5, stddev=0.125, dtype=tf.float32)) 50 | with tf.compat.v1.Session() as sees: 51 | locations = [] 52 | for i in range(dim): 53 | locations.append(sees.run(locations_tf[i])) 54 | name = filename % (num, dim) 55 | index = 0 56 | with open(name, "w") as fo: 57 | 58 | # for i in range(num * 2): 59 | while index < num and i < 2 * num: 60 | while True: 61 | iswritable = True 62 | node_string = '' 63 | for j in range(dim): 64 | if locations[j][i][0] < 0 or locations[j][i][0] > 1: 65 | iswritable = False 66 | break 67 | node_string = node_string + str(locations[j][index][0]) + "," 68 | if iswritable: 69 | node_string = node_string + str(i) + "\n" 70 | fo.write(node_string) 71 | i += 1 72 | index += 1 73 | break 74 | else: 75 | i += 1 76 | 77 | def getSkewedPoints(num, a, filename, dim): 78 | # locations_tf = [] 79 | # for i in range(dim): 80 | # locations_tf.append(tf.random.truncated_normal([num, 1], mean=0.5, stddev=0.25, dtype=tf.float32)) 81 | 82 | graph = tf.Graph() 83 | with graph.as_default(): 84 | locations_tf = [tf.random.truncated_normal([num, 1], mean=0.5, stddev=0.25, dtype=tf.float32) for _ in range(dim)] 85 | with tf.compat.v1.Session(graph=graph) as sees: 86 | locations = sees.run(locations_tf) 87 | # for a in range(1, 9, 2): 88 | name = filename % (num, a, dim) 89 | with open(name, "w") as fo: 90 | for i in range(num): 91 | node_string = '' 92 | for j in range(dim - 1): 93 | node_string = node_string + str(locations[j][i][0]) + "," 94 | node_string = node_string + str(locations[dim - 1][i][0] ** a) + "," + str(i) + "\n" 95 | fo.write(node_string) 96 | 97 | 98 | def parser(argv): 99 | try: 100 | opts, args = getopt.getopt(argv, "d:s:n:f:m:") 101 | except getopt.GetoptError: 102 | sys.exit(2) 103 | for opt, arg in opts: 104 | if opt == '-d': 105 | distribution = arg 106 | elif opt == '-s': 107 | size = int(arg) 108 | elif opt == '-n': 109 | skewness = int(arg) 110 | elif opt == '-f': 111 | filename = arg 112 | elif opt == '-m': 113 | dim = int(arg) 114 | return distribution, size, skewness, filename, dim 115 | 116 | # python C:\Users\Leo\Dropbox\shared\RLR-trees\codes\python\RLRtree\structure\data_generator.py -d uniform -s 10000 -n 1 -f datasets/uniform_10000_1_2_.csv -m 2 117 | if __name__ == '__main__': 118 | distribution, size, skewness, filename, dim = parser(sys.argv[1:]) 119 | if distribution == 'uniform': 120 | filename = "datasets/uniform_%d_1_%d_.csv" 121 | getUniformPoints(size, filename, dim) 122 | elif distribution == 'normal': 123 | filename = "datasets/normal_%d_1_%d_.csv" 124 | getNormalPoints(size, filename, dim) 125 | elif distribution == 'skewed': 126 | filename = "datasets/skewed_%d_%d_%d_.csv" 127 | getSkewedPoints(size, skewness, filename, dim) -------------------------------------------------------------------------------- /entities/Mbr.cpp: -------------------------------------------------------------------------------- 1 | #include "Mbr.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | Mbr::Mbr() 13 | { 14 | } 15 | 16 | Mbr::Mbr(float x1, float y1, float x2, float y2) 17 | { 18 | this->x1 = x1; 19 | this->y1 = y1; 20 | this->x2 = x2; 21 | this->y2 = y2; 22 | } 23 | 24 | void Mbr::update(Point point) 25 | { 26 | update(point.x, point.y); 27 | } 28 | 29 | void Mbr::update(float x, float y) 30 | { 31 | if (x < x1) 32 | { 33 | x1 = x; 34 | } 35 | if (y < y1) 36 | { 37 | y1 = y; 38 | } 39 | if (x > x2) 40 | { 41 | x2 = x; 42 | } 43 | if (y > y2) 44 | { 45 | y2 = y; 46 | } 47 | } 48 | 49 | void Mbr::update(Mbr mbr) 50 | { 51 | if (mbr.x1 < x1) 52 | { 53 | x1 = mbr.x1; 54 | } 55 | if (mbr.y1 < y1) 56 | { 57 | y1 = mbr.y1; 58 | } 59 | if (mbr.x2 > x2) 60 | { 61 | x2 = mbr.x2; 62 | } 63 | if (mbr.y2 > y2) 64 | { 65 | y2 = mbr.y2; 66 | } 67 | } 68 | 69 | bool Mbr::contains(Point point) 70 | { 71 | if (x1 > point.x || point.x > x2 || y1 > point.y || point.y > y2) 72 | { 73 | return false; 74 | } 75 | else 76 | { 77 | return true; 78 | } 79 | } 80 | 81 | bool Mbr::strict_contains(Point point) 82 | { 83 | if (x1 < point.x && point.x < x2 && y1 < point.y && point.y < y2) 84 | { 85 | return true; 86 | } 87 | else 88 | { 89 | return false; 90 | } 91 | } 92 | 93 | bool Mbr::interact(Mbr mbr) 94 | { 95 | 96 | if (x2 < mbr.x1 || mbr.x2 < x1) { 97 | return false; 98 | } 99 | 100 | if (y2 < mbr.y1 || mbr.y2 < y1) { 101 | return false; 102 | } 103 | 104 | return true; 105 | 106 | 107 | // if ((x1 <= mbr.x1 && mbr.x1 <= x2 && y1 <= mbr.y1 && mbr.y1 <= y2) || (x1 <= mbr.x1 && mbr.x1 <= x2 && y1 <= mbr.y2 && mbr.y2 <= y2) || (x1 <= mbr.x2 && mbr.x2 <= x2 && y1 <= mbr.y1 && mbr.y1 <= y2) || (x1 <= mbr.x2 && mbr.x2 <= x2 && y1 <= mbr.y2 && mbr.y2 <= y2)) 108 | // { 109 | // return true; 110 | // } 111 | // if ((mbr.x1 <= x1 && x1 <= mbr.x2 && mbr.y1 <= y1 && y1 <= mbr.y2) || (mbr.x1 <= x1 && x1 <= mbr.x2 && mbr.y1 <= y2 && y2 <= mbr.y2) || (mbr.x1 <= x2 && x2 <= mbr.x2 && mbr.y1 <= y1 && y1 <= mbr.y2) || (mbr.x1 <= x2 && x2 <= mbr.x2 && mbr.y1 <= y2 && y2 <= mbr.y2)) 112 | // { 113 | // return true; 114 | // } 115 | // return false; 116 | } 117 | 118 | vector Mbr::get_mbrs(vector dataset, float area, int num, float ratio) 119 | { 120 | 121 | vector mbrs; 122 | srand(time(0)); 123 | int maxInt = numeric_limits::max(); 124 | float x = sqrt(area * ratio); 125 | float y = sqrt(area / ratio); 126 | int i = 0; 127 | int length = dataset.size(); 128 | while (i < num) 129 | { 130 | int index = rand() % length; 131 | Point point = dataset[index]; 132 | if (point.x + x <= 1 && point.y + y <= 1) 133 | { 134 | Mbr mbr(point.x, point.y, point.x + x, point.y + y); 135 | mbrs.push_back(mbr); 136 | i++; 137 | } 138 | } 139 | 140 | return mbrs; 141 | } 142 | 143 | float Mbr::cal_dist(Point point) 144 | { 145 | if (this->contains(point)) 146 | { 147 | return 0; 148 | } 149 | else 150 | { 151 | float dist; 152 | if (point.x < x1) 153 | { 154 | if (point.y < y1) 155 | { 156 | dist = sqrt(pow((point.x - x1), 2) + pow((point.y - y1), 2)); 157 | } 158 | else if (point.y <= y2) 159 | { 160 | dist = x1 - point.x; 161 | } 162 | else 163 | { 164 | dist = sqrt(pow((point.x - x1), 2) + pow((point.y - y2), 2)); 165 | } 166 | } 167 | else if (point.x <= x2) 168 | { 169 | if (point.y < y1) 170 | { 171 | dist = y1 - point.y; 172 | } 173 | else 174 | { 175 | dist = point.y - y2; 176 | } 177 | } 178 | else 179 | { 180 | if (point.y < y1) 181 | { 182 | dist = sqrt(pow((point.x - x2), 2) + pow((point.y - y1), 2)); 183 | } 184 | else if (point.y <= y2) 185 | { 186 | dist = point.x - x2; 187 | } 188 | else 189 | { 190 | dist = sqrt(pow((point.x - x2), 2) + pow((point.y - y2), 2)); 191 | } 192 | } 193 | return dist; 194 | } 195 | } 196 | 197 | void Mbr::print() 198 | { 199 | cout << "(x1=" << x1 << " y1=" << y1 << " x2=" << x2 << " y2=" << y2 << ")" << endl; 200 | } 201 | 202 | vector Mbr::get_corner_points() 203 | { 204 | vector result; 205 | Point point1(x1, y1); 206 | Point point2(x2, y1); 207 | Point point3(x1, y2); 208 | Point point4(x2, y2); 209 | result.push_back(point1); 210 | result.push_back(point2); 211 | result.push_back(point3); 212 | result.push_back(point4); 213 | return result; 214 | } 215 | 216 | Mbr Mbr::get_mbr(Point point, float knnquerySide) 217 | { 218 | float x1 = point.x - knnquerySide; 219 | float x2 = point.x + knnquerySide; 220 | float y1 = point.y - knnquerySide; 221 | float y2 = point.y + knnquerySide; 222 | 223 | x1 = x1 < 0 ? 0 : x1; 224 | y1 = y1 < 0 ? 0 : y1; 225 | 226 | x2 = x2 > 1 ? 1 : x2; 227 | y2 = y2 > 1 ? 1 : y2; 228 | 229 | Mbr mbr(x1, y1, x2, y2); 230 | return mbr; 231 | } 232 | 233 | void Mbr::clean() 234 | { 235 | x1 = 0; 236 | x2 = 0; 237 | y1 = 0; 238 | y2 = 0; 239 | } 240 | 241 | string Mbr::get_self() 242 | { 243 | return to_string(x1) + "," + to_string(y1) + "," + to_string(x2) + "," + to_string(y2) + "\n"; 244 | } -------------------------------------------------------------------------------- /curves/hilbert4.H: -------------------------------------------------------------------------------- 1 | /* C header file for Hilbert curve functions */ 2 | #if !defined(_hilbert_h_) 3 | #define _hilbert_h_ 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | /* define the bitmask_t type as an integer of sufficient size */ 10 | typedef __uint128_t bitmask_t; 11 | /* define the halfmask_t type as an integer of 1/2 the size of bitmask_t */ 12 | typedef unsigned long long halfmask_t; 13 | 14 | /***************************************************************** 15 | * hilbert_i2c 16 | * 17 | * Convert an index into a Hilbert curve to a set of coordinates. 18 | * Inputs: 19 | * nDims: Number of coordinate axes. 20 | * nBits: Number of bits per axis. 21 | * index: The index, contains nDims*nBits bits (so nDims*nBits must be <= 8*sizeof(bitmask_t)). 22 | * Outputs: 23 | * coord: The list of nDims coordinates, each with nBits bits. 24 | * Assumptions: 25 | * nDims*nBits <= (sizeof index) * (bits_per_byte) 26 | */ 27 | 28 | void hilbert_i2c(unsigned nDims, unsigned nBits, bitmask_t index, bitmask_t coord[]); 29 | 30 | /***************************************************************** 31 | * hilbert_c2i 32 | * 33 | * Convert coordinates of a point on a Hilbert curve to its index. 34 | * Inputs: 35 | * nDims: Number of coordinates. 36 | * nBits: Number of bits/coordinate. 37 | * coord: Array of n nBits-bit coordinates. 38 | * Outputs: 39 | * index: Output index value. nDims*nBits bits. 40 | * Assumptions: 41 | * nDims*nBits <= (sizeof bitmask_t) * (bits_per_byte) 42 | */ 43 | 44 | bitmask_t hilbert_c2i(unsigned nDims, unsigned nBits, bitmask_t const coord[]); 45 | 46 | /***************************************************************** 47 | * hilbert_cmp, hilbert_ieee_cmp 48 | * 49 | * Determine which of two points lies further along the Hilbert curve 50 | * Inputs: 51 | * nDims: Number of coordinates. 52 | * nBytes: Number of bytes of storage/coordinate (hilbert_cmp only) 53 | * nBits: Number of bits/coordinate. (hilbert_cmp only) 54 | * coord1: Array of nDims nBytes-byte coordinates (or doubles for ieee_cmp). 55 | * coord2: Array of nDims nBytes-byte coordinates (or doubles for ieee_cmp). 56 | * Return value: 57 | * -1, 0, or 1 according to whether 58 | coord1coord2 59 | * Assumptions: 60 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 61 | */ 62 | 63 | int hilbert_cmp(unsigned nDims, unsigned nBytes, unsigned nBits, void const* coord1, void const* coord2); 64 | int hilbert_ieee_cmp(unsigned nDims, double const* coord1, double const* coord2); 65 | 66 | /***************************************************************** 67 | * hilbert_box_vtx 68 | * 69 | * Determine the first or last vertex of a box to lie on a Hilbert curve 70 | * Inputs: 71 | * nDims: Number of coordinates. 72 | * nBytes: Number of bytes/coordinate. 73 | * nBits: Number of bits/coordinate. (hilbert_cmp only) 74 | * findMin: Is it the least vertex sought? 75 | * coord1: Array of nDims nBytes-byte coordinates - one corner of box 76 | * coord2: Array of nDims nBytes-byte coordinates - opposite corner 77 | * Output: 78 | * c1 and c2 modified to refer to selected corner 79 | * value returned is log2 of size of largest power-of-two-aligned box that 80 | * contains the selected corner and no other corners 81 | * Assumptions: 82 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 83 | */ 84 | unsigned 85 | hilbert_box_vtx(unsigned nDims, unsigned nBytes, unsigned nBits, 86 | int findMin, void* c1, void* c2); 87 | unsigned 88 | hilbert_ieee_box_vtx(unsigned nDims, 89 | int findMin, double* c1, double* c2); 90 | 91 | /***************************************************************** 92 | * hilbert_box_pt 93 | * 94 | * Determine the first or last point of a box to lie on a Hilbert curve 95 | * Inputs: 96 | * nDims: Number of coordinates. 97 | * nBytes: Number of bytes/coordinate. 98 | * nBits: Number of bits/coordinate. 99 | * findMin: Is it the least vertex sought? 100 | * coord1: Array of nDims nBytes-byte coordinates - one corner of box 101 | * coord2: Array of nDims nBytes-byte coordinates - opposite corner 102 | * Output: 103 | * c1 and c2 modified to refer to least point 104 | * Assumptions: 105 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 106 | */ 107 | unsigned 108 | hilbert_box_pt(unsigned nDims, unsigned nBytes, unsigned nBits, 109 | int findMin, void* coord1, void* coord2); 110 | unsigned 111 | hilbert_ieee_box_pt(unsigned nDims, 112 | int findMin, double* c1, double* c2); 113 | 114 | /***************************************************************** 115 | * hilbert_nextinbox 116 | * 117 | * Determine the first point of a box after a given point to lie on a Hilbert curve 118 | * Inputs: 119 | * nDims: Number of coordinates. 120 | * nBytes: Number of bytes/coordinate. 121 | * nBits: Number of bits/coordinate. 122 | * findPrev: Is the previous point sought? 123 | * coord1: Array of nDims nBytes-byte coordinates - one corner of box 124 | * coord2: Array of nDims nBytes-byte coordinates - opposite corner 125 | * point: Array of nDims nBytes-byte coordinates - lower bound on point returned 126 | * 127 | * Output: 128 | if returns 1: 129 | * c1 and c2 modified to refer to least point after "point" in box 130 | else returns 0: 131 | arguments unchanged; "point" is beyond the last point of the box 132 | * Assumptions: 133 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 134 | */ 135 | int 136 | hilbert_nextinbox(unsigned nDims, unsigned nBytes, unsigned nBits, 137 | int findPrev, void* coord1, void* coord2, 138 | void const* point); 139 | 140 | /***************************************************************** 141 | * hilbert_incr 142 | * 143 | * Advance from one point to its successor on a Hilbert curve 144 | * Inputs: 145 | * nDims: Number of coordinates. 146 | * nBits: Number of bits/coordinate. 147 | * coord: Array of nDims nBits-bit coordinates. 148 | * Output: 149 | * coord: Next point on Hilbert curve 150 | * Assumptions: 151 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 152 | */ 153 | 154 | void 155 | hilbert_incr(unsigned nDims, unsigned nBits, bitmask_t coord[]); 156 | 157 | #ifdef __cplusplus 158 | } 159 | #endif 160 | 161 | #endif /* _hilbert_h_ */ 162 | -------------------------------------------------------------------------------- /Exp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "utils/FileReader.h" 9 | // #include "indices/ZM.h" 10 | #include "indices/RSMI.h" 11 | #include "utils/ExpRecorder.h" 12 | #include "utils/Constants.h" 13 | #include "utils/FileWriter.h" 14 | #include "utils/util.h" 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | using namespace std; 23 | 24 | #ifndef use_gpu 25 | // #define use_gpu 26 | 27 | int ks[] = {1, 5, 25, 125, 625}; 28 | float areas[] = {0.000006, 0.000025, 0.0001, 0.0004, 0.0016}; 29 | float ratios[] = {0.25, 0.5, 1, 2, 4}; 30 | int Ns[] = {5000, 2500, 500}; 31 | 32 | int k_length = sizeof(ks) / sizeof(ks[0]); 33 | int window_length = sizeof(areas) / sizeof(areas[0]); 34 | int ratio_length = sizeof(ratios) / sizeof(ratios[0]); 35 | 36 | int n_length = sizeof(Ns) / sizeof(Ns[0]); 37 | 38 | int query_window_num = 1000; 39 | int query_k_num = 1000; 40 | 41 | long long cardinality = 10000; 42 | long long inserted_num = cardinality / 10; 43 | string distribution = Constants::DEFAULT_DISTRIBUTION; 44 | int inserted_partition = 5; 45 | int skewness = 1; 46 | 47 | double knn_diff(vector acc, vector pred) 48 | { 49 | int num = 0; 50 | for (Point point : pred) 51 | { 52 | for (Point point1 : acc) 53 | { 54 | if (point.x == point1.x && point.y == point1.y) 55 | { 56 | num++; 57 | } 58 | } 59 | } 60 | return num * 1.0 / pred.size(); 61 | } 62 | 63 | void exp_RSMI(FileWriter file_writer, ExpRecorder exp_recorder, vector points, map> mbrs_map, vector query_poitns, vector insert_points, string model_path) 64 | { 65 | exp_recorder.clean(); 66 | exp_recorder.structure_name = "RSMI"; 67 | RSMI::model_path_root = model_path; 68 | RSMI *partition = new RSMI(0, Constants::MAX_WIDTH); 69 | auto start = chrono::high_resolution_clock::now(); 70 | partition->model_path = model_path; 71 | partition->build(exp_recorder, points); 72 | auto finish = chrono::high_resolution_clock::now(); 73 | exp_recorder.time = chrono::duration_cast(finish - start).count(); 74 | cout << "build time: " << exp_recorder.time << endl; 75 | exp_recorder.size = (2 * Constants::HIDDEN_LAYER_WIDTH + Constants::HIDDEN_LAYER_WIDTH * 1 + Constants::HIDDEN_LAYER_WIDTH * 1 + 1) * Constants::EACH_DIM_LENGTH * exp_recorder.non_leaf_node_num + (Constants::DIM * Constants::PAGESIZE + Constants::PAGESIZE + Constants::DIM * Constants::DIM) * Constants::EACH_DIM_LENGTH * exp_recorder.leaf_node_num; 76 | file_writer.write_build(exp_recorder); 77 | exp_recorder.clean(); 78 | partition->point_query(exp_recorder, points); 79 | cout << "finish point_query: pageaccess:" << exp_recorder.page_access << endl; 80 | cout << "finish point_query time: " << exp_recorder.time << endl; 81 | file_writer.write_point_query(exp_recorder); 82 | exp_recorder.clean(); 83 | 84 | exp_recorder.window_size = areas[2]; 85 | exp_recorder.window_ratio = ratios[2]; 86 | partition->acc_window_query(exp_recorder, mbrs_map[to_string(areas[2]) + to_string(ratios[2])]); 87 | cout << "RSMI::acc_window_query time: " << exp_recorder.time << endl; 88 | cout << "RSMI::acc_window_query page_access: " << exp_recorder.page_access << endl; 89 | file_writer.write_acc_window_query(exp_recorder); 90 | partition->window_query(exp_recorder, mbrs_map[to_string(areas[2]) + to_string(ratios[2])]); 91 | exp_recorder.accuracy = ((double)exp_recorder.window_query_result_size) / exp_recorder.acc_window_query_qesult_size; 92 | cout << "window_query time: " << exp_recorder.time << endl; 93 | cout << "window_query page_access: " << exp_recorder.page_access << endl; 94 | cout<< "exp_recorder.accuracy: " << exp_recorder.accuracy << endl; 95 | file_writer.write_window_query(exp_recorder); 96 | 97 | exp_recorder.clean(); 98 | exp_recorder.k_num = ks[2]; 99 | partition->acc_kNN_query(exp_recorder, query_poitns, ks[2]); 100 | cout << "exp_recorder.time: " << exp_recorder.time << endl; 101 | cout << "exp_recorder.page_access: " << exp_recorder.page_access << endl; 102 | file_writer.write_acc_kNN_query(exp_recorder); 103 | partition->kNN_query(exp_recorder, query_poitns, ks[2]); 104 | cout << "exp_recorder.time: " << exp_recorder.time << endl; 105 | cout << "exp_recorder.page_access: " << exp_recorder.page_access << endl; 106 | exp_recorder.accuracy = knn_diff(exp_recorder.acc_knn_query_results, exp_recorder.knn_query_results); 107 | cout<< "exp_recorder.accuracy: " << exp_recorder.accuracy << endl; 108 | file_writer.write_kNN_query(exp_recorder); 109 | exp_recorder.clean(); 110 | 111 | partition->insert(exp_recorder, insert_points); 112 | cout << "exp_recorder.insert_time: " << exp_recorder.insert_time << endl; 113 | exp_recorder.clean(); 114 | partition->point_query(exp_recorder, points); 115 | cout << "finish point_query: pageaccess:" << exp_recorder.page_access << endl; 116 | cout << "finish point_query time: " << exp_recorder.time << endl; 117 | exp_recorder.clean(); 118 | } 119 | 120 | string RSMI::model_path_root = ""; 121 | int main(int argc, char **argv) 122 | { 123 | int c; 124 | static struct option long_options[] = 125 | { 126 | {"cardinality", required_argument,NULL,'c'}, 127 | {"distribution",required_argument, NULL,'d'}, 128 | {"skewness", required_argument, NULL,'s'} 129 | }; 130 | 131 | while(1) 132 | { 133 | int opt_index = 0; 134 | c = getopt_long(argc, argv,"c:d:s:", long_options,&opt_index); 135 | 136 | if(-1 == c) 137 | { 138 | break; 139 | } 140 | switch(c) 141 | { 142 | case 'c': 143 | cardinality = atoll(optarg); 144 | break; 145 | case 'd': 146 | distribution = optarg; 147 | break; 148 | case 's': 149 | skewness = atoi(optarg); 150 | break; 151 | } 152 | } 153 | 154 | ExpRecorder exp_recorder; 155 | exp_recorder.dataset_cardinality = cardinality; 156 | exp_recorder.distribution = distribution; 157 | exp_recorder.skewness = skewness; 158 | inserted_num = cardinality / 2; 159 | 160 | // TODO change filename 161 | string dataset_filename = Constants::DATASETS + exp_recorder.distribution + "_" + to_string(exp_recorder.dataset_cardinality) + "_" + to_string(exp_recorder.skewness) + "_2_.csv"; 162 | FileReader filereader(dataset_filename, ","); 163 | vector points = filereader.get_points(); 164 | exp_recorder.insert_num = inserted_num; 165 | vector query_poitns; 166 | vector insert_points; 167 | //***********************write query data********************* 168 | FileWriter query_file_writer(Constants::QUERYPROFILES); 169 | query_poitns = Point::get_points(points, query_k_num); 170 | query_file_writer.write_points(query_poitns, exp_recorder); 171 | insert_points = Point::get_inserted_points(exp_recorder.insert_num); 172 | query_file_writer.write_inserted_points(insert_points, exp_recorder); 173 | 174 | for (size_t i = 0; i < window_length; i++) 175 | { 176 | for (size_t j = 0; j < ratio_length; j++) 177 | { 178 | exp_recorder.window_size = areas[i]; 179 | exp_recorder.window_ratio = ratios[j]; 180 | vector mbrs = Mbr::get_mbrs(points, exp_recorder.window_size, query_window_num, exp_recorder.window_ratio); 181 | query_file_writer.write_mbrs(mbrs, exp_recorder); 182 | } 183 | } 184 | //**************************prepare knn, window query, and insertion data****************** 185 | FileReader knn_reader((Constants::QUERYPROFILES + Constants::KNN + exp_recorder.distribution + "_" + to_string(exp_recorder.dataset_cardinality) + "_" + to_string(exp_recorder.k_num) + ".csv"), ","); 186 | map> mbrs_map; 187 | FileReader query_filereader; 188 | 189 | query_poitns = query_filereader.get_points((Constants::QUERYPROFILES + Constants::KNN + exp_recorder.distribution + "_" + to_string(exp_recorder.dataset_cardinality) + "_" + to_string(exp_recorder.skewness) + ".csv"), ","); 190 | insert_points = query_filereader.get_points((Constants::QUERYPROFILES + Constants::UPDATE + exp_recorder.distribution + "_" + to_string(exp_recorder.dataset_cardinality) + "_" + to_string(exp_recorder.skewness) + "_" + to_string(exp_recorder.insert_num) + ".csv"), ","); 191 | 192 | for (size_t i = 0; i < window_length; i++) 193 | { 194 | for (size_t j = 0; j < ratio_length; j++) 195 | { 196 | exp_recorder.window_size = areas[i]; 197 | exp_recorder.window_ratio = ratios[j]; 198 | vector mbrs = query_filereader.get_mbrs((Constants::QUERYPROFILES + Constants::WINDOW + exp_recorder.distribution + "_" + to_string(exp_recorder.dataset_cardinality) + "_" + to_string(exp_recorder.skewness) + "_" + to_string(exp_recorder.window_size) + "_" + to_string(exp_recorder.window_ratio) + ".csv"), ","); 199 | mbrs_map.insert(pair>(to_string(areas[i]) + to_string(ratios[j]), mbrs)); 200 | } 201 | } 202 | string model_root_path = Constants::TORCH_MODELS + distribution + "_" + to_string(cardinality); 203 | file_utils::check_dir(model_root_path); 204 | string model_path = model_root_path + "/"; 205 | FileWriter file_writer(Constants::RECORDS); 206 | exp_RSMI(file_writer, exp_recorder, points, mbrs_map, query_poitns, insert_points, model_path); 207 | } 208 | 209 | #endif // use_gpu -------------------------------------------------------------------------------- /utils/FileWriter.cpp: -------------------------------------------------------------------------------- 1 | #include "FileWriter.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "ExpRecorder.h" 8 | #include "ExpRecorder.h" 9 | #include "util.h" 10 | #include "../entities/Point.h" 11 | #include "../entities/Mbr.h" 12 | 13 | using namespace std; 14 | 15 | FileWriter::FileWriter(string filename) 16 | { 17 | this->filename = filename; 18 | file_utils::check_dir(filename); 19 | } 20 | 21 | void FileWriter::write_mbrs(vector mbrs, ExpRecorder expRecorder) 22 | { 23 | ofstream write; 24 | string folder = Constants::WINDOW; 25 | file_utils::check_dir(filename + folder); 26 | write.open((filename + folder + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.window_size) + "_" + to_string(expRecorder.window_ratio) + ".csv"), ios::out); 27 | for (Mbr mbr : mbrs) 28 | { 29 | write << mbr.get_self(); 30 | } 31 | write.close(); 32 | } 33 | void FileWriter::write_points(vector points, ExpRecorder expRecorder) 34 | { 35 | ofstream write; 36 | string folder = Constants::KNN; 37 | file_utils::check_dir(filename + folder); 38 | write.open((filename + folder + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + ".csv"), ios::out); 39 | for (Point point : points) 40 | { 41 | write << point.get_self(); 42 | } 43 | write.close(); 44 | } 45 | void FileWriter::write_inserted_points(vector points, ExpRecorder expRecorder) 46 | { 47 | ofstream write; 48 | string folder = Constants::UPDATE; 49 | file_utils::check_dir(filename + folder); 50 | write.open((filename + folder + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.insert_num) + ".csv"), ios::out); 51 | for (Point point : points) 52 | { 53 | write << point.get_self(); 54 | } 55 | write.close(); 56 | } 57 | 58 | void FileWriter::write_build(ExpRecorder expRecorder) 59 | { 60 | ofstream write; 61 | string folder = Constants::BUILD; 62 | file_utils::check_dir(filename + folder); 63 | write.open((filename + folder + expRecorder.structure_name + "_" + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.N) + ".txt"), ios::app); 64 | if (expRecorder.structure_name == "ZM" || expRecorder.structure_name == "RSMI") 65 | { 66 | write << expRecorder.get_time_size_errors(); 67 | } 68 | else 69 | { 70 | write << expRecorder.get_time_size(); 71 | } 72 | write.close(); 73 | } 74 | 75 | void FileWriter::write_point_query(ExpRecorder expRecorder) 76 | { 77 | ofstream write; 78 | string folder = Constants::POINT; 79 | file_utils::check_dir(filename + folder); 80 | write.open((filename + folder + expRecorder.structure_name + "_" + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.N) + ".txt"), ios::app); 81 | write << expRecorder.get_time_pageaccess(); 82 | write.close(); 83 | } 84 | 85 | void FileWriter::write_acc_window_query(ExpRecorder expRecorder) 86 | { 87 | ofstream write; 88 | string folder = Constants::ACCWINDOW; 89 | file_utils::check_dir(filename + folder); 90 | write.open((filename + folder + expRecorder.structure_name + "_" + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.window_size) + "_" + to_string(expRecorder.window_ratio) + "_" + to_string(expRecorder.N) + ".txt"), ios::app); 91 | write << expRecorder.get_time_pageaccess_accuracy(); 92 | write.close(); 93 | } 94 | 95 | void FileWriter::write_window_query(ExpRecorder expRecorder) 96 | { 97 | ofstream write; 98 | string folder = Constants::WINDOW; 99 | file_utils::check_dir(filename + folder); 100 | write.open((filename + folder + expRecorder.structure_name + "_" + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.window_size) + "_" + to_string(expRecorder.window_ratio) + "_" + to_string(expRecorder.N) + ".txt"), ios::app); 101 | write << expRecorder.get_time_pageaccess_accuracy(); 102 | write.close(); 103 | } 104 | 105 | void FileWriter::write_acc_kNN_query(ExpRecorder expRecorder) 106 | { 107 | ofstream write; 108 | string folder = Constants::ACCKNN; 109 | file_utils::check_dir(filename + folder); 110 | write.open((filename + folder + expRecorder.structure_name + "_" + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.k_num) + "_" + to_string(expRecorder.N) + ".txt"), ios::app); 111 | write << expRecorder.get_time_pageaccess_accuracy(); 112 | write.close(); 113 | } 114 | 115 | void FileWriter::write_kNN_query(ExpRecorder expRecorder) 116 | { 117 | ofstream write; 118 | string folder = Constants::KNN; 119 | file_utils::check_dir(filename + folder); 120 | write.open((filename + folder + expRecorder.structure_name + "_" + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.k_num) + "_" + to_string(expRecorder.N) + ".txt"), ios::app); 121 | write << expRecorder.get_time_pageaccess_accuracy(); 122 | write.close(); 123 | } 124 | 125 | void FileWriter::write_insert(ExpRecorder expRecorder) 126 | { 127 | ofstream write; 128 | string folder = Constants::INSERT; 129 | file_utils::check_dir(filename + folder); 130 | write.open((filename + folder + expRecorder.structure_name + "_" + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.insert_num) + "_" + to_string(expRecorder.N) + ".txt"), ios::app); 131 | if (expRecorder.structure_name == "RSMI") 132 | { 133 | write << expRecorder.get_insert_time_pageaccess_rebuild(); 134 | } 135 | else 136 | { 137 | write << expRecorder.get_insert_time_pageaccess(); 138 | } 139 | write.close(); 140 | } 141 | 142 | void FileWriter::write_delete(ExpRecorder expRecorder) 143 | { 144 | ofstream write; 145 | string folder = Constants::DELETE; 146 | file_utils::check_dir(filename + folder); 147 | write.open((filename + folder + expRecorder.structure_name + "_" + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.delete_num) + "_" + to_string(expRecorder.N) + ".txt"), ios::app); 148 | write << expRecorder.get_delete_time_pageaccess(); 149 | write.close(); 150 | } 151 | 152 | void FileWriter::write_insert_point_query(ExpRecorder expRecorder) 153 | { 154 | ofstream write; 155 | string folder = Constants::INSERTPOINT; 156 | file_utils::check_dir(filename + folder); 157 | write.open((filename + folder + expRecorder.structure_name + "_" + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.insert_num) + "_" + to_string(expRecorder.N) + ".txt"), ios::app); 158 | write << expRecorder.get_time_pageaccess(); 159 | write.close(); 160 | } 161 | 162 | void FileWriter::write_insert_acc_window_query(ExpRecorder expRecorder) 163 | { 164 | ofstream write; 165 | string folder = Constants::INSERTACCWINDOW; 166 | file_utils::check_dir(filename + folder); 167 | write.open((filename + folder + expRecorder.structure_name + "_" + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.insert_num) + "_" + to_string(expRecorder.N) + ".txt"), ios::app); 168 | write << expRecorder.get_time_pageaccess_accuracy(); 169 | write.close(); 170 | } 171 | 172 | void FileWriter::write_insert_window_query(ExpRecorder expRecorder) 173 | { 174 | ofstream write; 175 | string folder = Constants::INSERTWINDOW; 176 | file_utils::check_dir(filename + folder); 177 | write.open((filename + folder + expRecorder.structure_name + "_" + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.insert_num) + "_" + to_string(expRecorder.N) + ".txt"), ios::app); 178 | write << expRecorder.get_time_pageaccess_accuracy(); 179 | write.close(); 180 | } 181 | 182 | void FileWriter::write_insert_acc_kNN_query(ExpRecorder expRecorder) 183 | { 184 | ofstream write; 185 | string folder = Constants::INSERTACCKNN; 186 | file_utils::check_dir(filename + folder); 187 | write.open((filename + folder + expRecorder.structure_name + "_" + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.insert_num) + "_" + to_string(expRecorder.N) + ".txt"), ios::app); 188 | write << expRecorder.get_time_pageaccess(); 189 | write.close(); 190 | } 191 | 192 | void FileWriter::write_insert_kNN_query(ExpRecorder expRecorder) 193 | { 194 | ofstream write; 195 | string folder = Constants::INSERTKNN; 196 | file_utils::check_dir(filename + folder); 197 | write.open((filename + folder + expRecorder.structure_name + "_" + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.insert_num) + "_" + to_string(expRecorder.N) + ".txt"), ios::app); 198 | write << expRecorder.get_time_pageaccess_accuracy(); 199 | write.close(); 200 | } 201 | 202 | void FileWriter::write_delete_point_query(ExpRecorder expRecorder) 203 | { 204 | ofstream write; 205 | string folder = Constants::DELETEPOINT; 206 | file_utils::check_dir(filename + folder); 207 | write.open((filename + folder + expRecorder.structure_name + "_" + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.delete_num) + "_" + to_string(expRecorder.N) + ".txt"), ios::app); 208 | write << expRecorder.get_time_pageaccess(); 209 | write.close(); 210 | } 211 | 212 | void FileWriter::write_delete_acc_window_query(ExpRecorder expRecorder) 213 | { 214 | ofstream write; 215 | string folder = Constants::DELETEACCWINDOW; 216 | file_utils::check_dir(filename + folder); 217 | write.open((filename + folder + expRecorder.structure_name + "_" + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.delete_num) + "_" + to_string(expRecorder.N) + ".txt"), ios::app); 218 | write << expRecorder.get_time_pageaccess_accuracy(); 219 | write.close(); 220 | } 221 | 222 | void FileWriter::write_delete_acc_kNN_query(ExpRecorder expRecorder) 223 | { 224 | ofstream write; 225 | string folder = Constants::DELETEACCKNN; 226 | file_utils::check_dir(filename + folder); 227 | write.open((filename + folder + expRecorder.structure_name + "_" + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.delete_num) + "_" + to_string(expRecorder.N) + ".txt"), ios::app); 228 | write << expRecorder.get_time_pageaccess_accuracy(); 229 | write.close(); 230 | } 231 | 232 | void FileWriter::write_delete_window_query(ExpRecorder expRecorder) 233 | { 234 | ofstream write; 235 | string folder = Constants::DELETEWINDOW; 236 | file_utils::check_dir(filename + folder); 237 | write.open((filename + folder + expRecorder.structure_name + "_" + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.delete_num) + "_" + to_string(expRecorder.N) + ".txt"), ios::app); 238 | write << expRecorder.get_time_pageaccess_accuracy(); 239 | write.close(); 240 | } 241 | 242 | void FileWriter::write_delete_kNN_query(ExpRecorder expRecorder) 243 | { 244 | ofstream write; 245 | string folder = Constants::DELETEACCKNN; 246 | file_utils::check_dir(filename + folder); 247 | write.open((filename + folder + expRecorder.structure_name + "_" + expRecorder.distribution + "_" + to_string(expRecorder.dataset_cardinality) + "_" + to_string(expRecorder.skewness) + "_" + to_string(expRecorder.delete_num) + "_" + to_string(expRecorder.N) + ".txt"), ios::app); 248 | write << expRecorder.get_time_pageaccess_accuracy(); 249 | write.close(); 250 | } -------------------------------------------------------------------------------- /utils/ModelTools.h: -------------------------------------------------------------------------------- 1 | #ifndef MODELTOOLS_H 2 | #define MODELTOOLS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include //SSE指令集需包含词头文件 25 | // #include 26 | 27 | using namespace at; 28 | using namespace torch::nn; 29 | using namespace torch::optim; 30 | using namespace std; 31 | 32 | struct Net : torch::nn::Module 33 | { 34 | 35 | public: 36 | int input_width; 37 | int max_error = 0; 38 | int min_error = 0; 39 | int width = 0; 40 | 41 | float learning_rate = Constants::LEARNING_RATE; 42 | 43 | float w1[Constants::HIDDEN_LAYER_WIDTH * 2]; 44 | float w1_[Constants::HIDDEN_LAYER_WIDTH]; 45 | float w2[Constants::HIDDEN_LAYER_WIDTH]; 46 | float b1[Constants::HIDDEN_LAYER_WIDTH]; 47 | 48 | float *w1_0 = (float *)_mm_malloc(Constants::HIDDEN_LAYER_WIDTH * sizeof(float), 32); 49 | float *w1_1 = (float *)_mm_malloc(Constants::HIDDEN_LAYER_WIDTH * sizeof(float), 32); 50 | float *w2_ = (float *)_mm_malloc(Constants::HIDDEN_LAYER_WIDTH * sizeof(float), 32); 51 | float *b1_ = (float *)_mm_malloc(Constants::HIDDEN_LAYER_WIDTH * sizeof(float), 32); 52 | 53 | float *w1__ = (float *)_mm_malloc(Constants::HIDDEN_LAYER_WIDTH * sizeof(float), 32); 54 | 55 | float b2 = 0.0; 56 | 57 | Net(int input_width) 58 | { 59 | this->width = Constants::HIDDEN_LAYER_WIDTH; 60 | this->input_width = input_width; 61 | fc1 = register_module("fc1", torch::nn::Linear(input_width, width)); 62 | fc2 = register_module("fc2", torch::nn::Linear(width, 1)); 63 | torch::nn::init::uniform_(fc1->weight, 0, 1); 64 | torch::nn::init::uniform_(fc2->weight, 0, 1); 65 | // torch::nn::init::normal_(fc1->weight, 0, 1); 66 | // torch::nn::init::normal_(fc2->weight, 0, 1); 67 | } 68 | 69 | // RSMI 70 | Net(int input_width, int width) 71 | { 72 | this->width = width; 73 | this->width = this->width >= Constants::HIDDEN_LAYER_WIDTH ? Constants::HIDDEN_LAYER_WIDTH : this->width; 74 | // this->width = Constants::HIDDEN_LAYER_WIDTH; 75 | // this->width = Constants::HIDDEN_LAYER_WIDTH; 76 | this->input_width = input_width; 77 | fc1 = register_module("fc1", torch::nn::Linear(input_width, this->width)); 78 | fc2 = register_module("fc2", torch::nn::Linear(this->width, 1)); 79 | torch::nn::init::uniform_(fc1->weight, 0, 0.1); 80 | torch::nn::init::uniform_(fc2->weight, 0, 0.1); 81 | // torch::nn::init::normal_(fc1->weight, 0, 1); 82 | // torch::nn::init::normal_(fc2->weight, 0, 1); 83 | } 84 | 85 | void get_parameters_ZM() 86 | { 87 | torch::Tensor p1 = this->parameters()[0]; 88 | torch::Tensor p2 = this->parameters()[1]; 89 | torch::Tensor p3 = this->parameters()[2]; 90 | torch::Tensor p4 = this->parameters()[3]; 91 | p1 = p1.reshape({width, 1}); 92 | for (size_t i = 0; i < width; i++) 93 | { 94 | w1_[i] = p1.select(0, i).item().toFloat(); 95 | } 96 | 97 | p2 = p2.reshape({width, 1}); 98 | for (size_t i = 0; i < width; i++) 99 | { 100 | b1[i] = p2.select(0, i).item().toFloat(); 101 | } 102 | 103 | p3 = p3.reshape({width, 1}); 104 | for (size_t i = 0; i < width; i++) 105 | { 106 | w2[i] = p3.select(0, i).item().toFloat(); 107 | } 108 | b2 = p4.item().toFloat(); 109 | } 110 | 111 | void get_parameters() 112 | { 113 | torch::Tensor p1 = this->parameters()[0]; 114 | torch::Tensor p2 = this->parameters()[1]; 115 | torch::Tensor p3 = this->parameters()[2]; 116 | torch::Tensor p4 = this->parameters()[3]; 117 | p1 = p1.reshape({2 * width, 1}); 118 | for (size_t i = 0; i < width; i++) 119 | { 120 | w1[i * 2] = p1.select(0, 2 * i).item().toFloat(); 121 | w1[i * 2 + 1] = p1.select(0, 2 * i + 1).item().toFloat(); 122 | 123 | w1_0[i] = p1.select(0, 2 * i).item().toFloat(); 124 | w1_1[i] = p1.select(0, 2 * i + 1).item().toFloat(); 125 | } 126 | 127 | p2 = p2.reshape({width, 1}); 128 | for (size_t i = 0; i < width; i++) 129 | { 130 | b1[i] = p2.select(0, i).item().toFloat(); 131 | 132 | b1_[i] = p2.select(0, i).item().toFloat(); 133 | } 134 | 135 | p3 = p3.reshape({width, 1}); 136 | for (size_t i = 0; i < width; i++) 137 | { 138 | w2[i] = p3.select(0, i).item().toFloat(); 139 | 140 | w2_[i] = p3.select(0, i).item().toFloat(); 141 | } 142 | b2 = p4.item().toFloat(); 143 | } 144 | 145 | void print_parameters() 146 | { 147 | for (size_t i = 0; i < width; i++) 148 | { 149 | cout << b1[i] << " " << b1[i] << " "; 150 | } 151 | cout << endl; 152 | for (size_t i = 0; i < width; i++) 153 | { 154 | cout << b1_[i] << " " << b1_[i] << " "; 155 | } 156 | cout << endl; 157 | } 158 | 159 | torch::Tensor forward(torch::Tensor x) 160 | { 161 | // Use one of many tensor manipulation functions. 162 | // x = torch::sigmoid(fc1->forward(x)); 163 | x = torch::relu(fc1->forward(x)); 164 | // x = fc1->forward(x); 165 | x = fc2->forward(x); 166 | // x = torch::dropout(x, /*p=*/0.5, /*train=*/is_training()); 167 | // x = torch::relu(fc2->forward(x)); 168 | // x = fc2->forward(x); 169 | return x; 170 | // return fc2->forward(fc1->forward(x)); 171 | } 172 | 173 | torch::Tensor predict(torch::Tensor x) 174 | { 175 | x = torch::relu(fc1->forward(x)); 176 | x = fc2->forward(x); 177 | return x; 178 | } 179 | 180 | // float predictZM(float key) 181 | // { 182 | // float result; 183 | // for (size_t i = 0; i < Constants::HIDDEN_LAYER_WIDTH; i++) 184 | // { 185 | // result += activation(key * w1_[i] + b1[i]) * w2[i]; 186 | // } 187 | // result += b2; 188 | // return result; 189 | // } 190 | 191 | float predict_ZM(float key) 192 | { 193 | int blocks = width / 4; 194 | int rem = width % 4; 195 | int move_back = blocks * 4; 196 | __m128 fLoad_w1, fLoad_b1, fLoad_w2; 197 | __m128 temp1, temp2, temp3; 198 | __m128 fSum0 = _mm_setzero_ps(); 199 | __m128 fLoad0_x, fLoad0_zeros; 200 | // _mm_load1_ps 201 | fLoad0_x = _mm_set_ps(key, key, key, key); 202 | fLoad0_zeros = _mm_set_ps(0, 0, 0, 0); 203 | float result; 204 | for (int i = 0; i < blocks; i++) 205 | { 206 | // TODO change w1 207 | fLoad_w1 = _mm_load_ps(w1__); 208 | fLoad_b1 = _mm_load_ps(b1_); 209 | fLoad_w2 = _mm_load_ps(w2_); 210 | temp1 = _mm_mul_ps(fLoad0_x, fLoad_w1); 211 | temp2 = _mm_add_ps(temp1, fLoad_b1); 212 | 213 | temp1 = _mm_max_ps(temp2, fLoad0_zeros); 214 | 215 | temp2 = _mm_mul_ps(temp1, fLoad_w2); 216 | fSum0 = _mm_add_ps(fSum0, temp2); 217 | 218 | w1__ += 4; 219 | b1_ += 4; 220 | w2_ += 4; 221 | } 222 | result = 0; 223 | if (blocks > 0) 224 | { 225 | result += fSum0[0] + fSum0[1] + fSum0[2] + fSum0[3]; 226 | } 227 | for (size_t i = 0; i < rem; i++) 228 | { 229 | result += activation(key * w1__[i] + b1_[i]) * w2_[i]; 230 | } 231 | result += b2; 232 | w1__ -= move_back; 233 | b1_ -= move_back; 234 | w2_ -= move_back; 235 | return result; 236 | } 237 | 238 | float predict(Point point) 239 | { 240 | float x1 = point.x; 241 | float x2 = point.y; 242 | int blocks = width / 4; 243 | int rem = width % 4; 244 | int move_back = blocks * 4; 245 | __m128 fLoad_w1_1, fLoad_w1_2, fLoad_b1, fLoad_w2; 246 | __m128 temp1, temp2, temp3; 247 | __m128 fSum0 = _mm_setzero_ps(); 248 | __m128 fLoad0_x1, fLoad0_x2, fLoad0_zeros; 249 | // _mm_load1_ps 250 | fLoad0_x1 = _mm_set_ps(x1, x1, x1, x1); 251 | fLoad0_x2 = _mm_set_ps(x2, x2, x2, x2); 252 | fLoad0_zeros = _mm_set_ps(0, 0, 0, 0); 253 | float result; 254 | for (int i = 0; i < blocks; i++) 255 | { 256 | // TODO change w1 257 | fLoad_w1_1 = _mm_load_ps(w1_0); 258 | fLoad_w1_2 = _mm_load_ps(w1_1); 259 | fLoad_b1 = _mm_load_ps(b1_); 260 | fLoad_w2 = _mm_load_ps(w2_); 261 | temp1 = _mm_mul_ps(fLoad0_x1, fLoad_w1_1); 262 | temp2 = _mm_mul_ps(fLoad0_x2, fLoad_w1_2); 263 | temp2 = _mm_add_ps(temp1, temp2); 264 | temp2 = _mm_add_ps(temp2, fLoad_b1); 265 | 266 | temp1 = _mm_max_ps(temp2, fLoad0_zeros); 267 | 268 | temp2 = _mm_mul_ps(temp1, fLoad_w2); 269 | fSum0 = _mm_add_ps(fSum0, temp2); 270 | 271 | w1_0 += 4; 272 | w1_1 += 4; 273 | b1_ += 4; 274 | w2_ += 4; 275 | } 276 | result = 0; 277 | if (blocks > 0) 278 | { 279 | result += fSum0[0] + fSum0[1] + fSum0[2] + fSum0[3]; 280 | } 281 | for (size_t i = 0; i < rem; i++) 282 | { 283 | result += activation(x1 * w1_0[i] + x2 * w1_1[i] + b1_[i]) * w2_[i]; 284 | } 285 | result += b2; 286 | w1_0 -= move_back; 287 | w1_1 -= move_back; 288 | b1_ -= move_back; 289 | w2_ -= move_back; 290 | return result; 291 | } 292 | 293 | // float predict(Point point) 294 | // { 295 | // float x1 = point.x; 296 | // float x2 = point.y; 297 | // float result; 298 | // for (int i = 0; i < width; ++i) 299 | // { 300 | // result += activation(x1 * w1[i * 2] + x2 * w1[i * 2 + 1] + b1[i]) * w2[i]; 301 | // } 302 | // result += b2; 303 | // return result; 304 | // } 305 | 306 | float activation(float val) 307 | { 308 | if (val > 0.0) 309 | { 310 | return val; 311 | } 312 | return 0.0; 313 | } 314 | 315 | void train_model(vector locations, vector labels) 316 | { 317 | long long N = labels.size(); 318 | 319 | #ifdef use_gpu 320 | torch::Tensor x = torch::tensor(locations, at::kCUDA).reshape({N, this->input_width}); 321 | torch::Tensor y = torch::tensor(labels, at::kCUDA).reshape({N, 1}); 322 | #else 323 | torch::Tensor x = torch::tensor(locations).reshape({N, this->input_width}); 324 | torch::Tensor y = torch::tensor(labels).reshape({N, 1}); 325 | #endif 326 | // torch::Tensor x = torch::tensor(locations).reshape({N, this->input_width}); 327 | // torch::Tensor y = torch::tensor(labels).reshape({N, 1}); 328 | // auto net = isRetrain ? this->net : std::make_shared(2, width); 329 | // auto net = std::make_shared(this->input_width, this->width); 330 | cout << "trained size: " << N << endl; 331 | 332 | torch::optim::Adam optimizer(this->parameters(), torch::optim::AdamOptions(this->learning_rate)); 333 | if (N > 64000000) 334 | { 335 | int batch_num = 4; 336 | 337 | auto x_chunks = x.chunk(batch_num, 0); 338 | auto y_chunks = y.chunk(batch_num, 0); 339 | for (size_t epoch = 0; epoch < Constants::EPOCH; epoch++) 340 | { 341 | for (size_t i = 0; i < batch_num; i++) 342 | { 343 | optimizer.zero_grad(); 344 | torch::Tensor loss = torch::mse_loss(this->forward(x_chunks[i]), y_chunks[i]); 345 | #ifdef use_gpu 346 | loss.to(torch::kCUDA); 347 | #endif 348 | loss.backward(); 349 | optimizer.step(); 350 | } 351 | } 352 | } 353 | else 354 | { 355 | for (size_t epoch = 0; epoch < Constants::EPOCH; epoch++) 356 | { 357 | optimizer.zero_grad(); 358 | torch::Tensor loss = torch::mse_loss(this->forward(x), y); 359 | #ifdef use_gpu 360 | loss.to(torch::kCUDA); 361 | #endif 362 | loss.backward(); 363 | optimizer.step(); 364 | } 365 | } 366 | cout << "finish training " << endl; 367 | } 368 | 369 | torch::nn::Linear fc1{nullptr}, fc2{nullptr}; 370 | }; 371 | 372 | #endif -------------------------------------------------------------------------------- /indices/RSMI.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../entities/Node.h" 4 | #include "../entities/Point.h" 5 | #include "../entities/Mbr.h" 6 | #include "../entities/NonLeafNode.h" 7 | #include "../entities/LeafNode.h" 8 | #include 9 | #include "../utils/ExpRecorder.h" 10 | #include "../utils/SortTools.h" 11 | #include "../utils/ModelTools.h" 12 | #include "../curves/hilbert.H" 13 | #include "../curves/hilbert4.H" 14 | #include "../curves/z.H" 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | using namespace at; 26 | using namespace torch::nn; 27 | using namespace torch::optim; 28 | using namespace std; 29 | 30 | class RSMI 31 | { 32 | 33 | private: 34 | int level; 35 | int index; 36 | int max_partition_num; 37 | long long N = 0; 38 | int max_error = 0; 39 | int min_error = 0; 40 | int width = 0; 41 | int leaf_node_num; 42 | 43 | bool is_last; 44 | Mbr mbr; 45 | std::shared_ptr net; 46 | 47 | public: 48 | string model_path; 49 | static string model_path_root; 50 | map children; 51 | vector leafnodes; 52 | 53 | RSMI(); 54 | RSMI(int index, int max_partition_num); 55 | RSMI(int index, int level, int max_partition_num); 56 | void build(ExpRecorder &exp_recorder, vector points); 57 | void print_index_info(ExpRecorder &exp_recorder); 58 | 59 | bool point_query(ExpRecorder &exp_recorder, Point query_point); 60 | void point_query(ExpRecorder &exp_recorder, vector query_points); 61 | 62 | void window_query(ExpRecorder &exp_recorder, vector query_windows); 63 | // vector window_query(ExpRecorder &exp_recorder, Mbr query_window); 64 | void window_query(ExpRecorder &exp_recorder, vector vertexes, Mbr query_window, float boundary, int k, Point query_point, float &); 65 | void window_query(ExpRecorder &exp_recorder, vector vertexes, Mbr query_window); 66 | void acc_window_query(ExpRecorder &exp_recorder, vector query_windows); 67 | vector acc_window_query(ExpRecorder &exp_recorder, Mbr query_windows); 68 | 69 | void kNN_query(ExpRecorder &exp_recorder, vector query_points, int k); 70 | vector kNN_query(ExpRecorder &exp_recorder, Point query_point, int k); 71 | void acc_kNN_query(ExpRecorder &exp_recorder, vector query_points, int k); 72 | vector acc_kNN_query(ExpRecorder &exp_recorder, Point query_point, int k); 73 | double cal_rho(Point point); 74 | double knn_diff(vector acc, vector pred); 75 | 76 | void insert(ExpRecorder &exp_recorder, Point); 77 | void insert(ExpRecorder &exp_recorder, vector); 78 | 79 | void remove(ExpRecorder &exp_recorder, Point); 80 | void remove(ExpRecorder &exp_recorder, vector); 81 | }; 82 | 83 | RSMI::RSMI() 84 | { 85 | // leafnodes = vector(10); 86 | } 87 | 88 | RSMI::RSMI(int index, int max_partition_num) 89 | { 90 | this->index = index; 91 | this->max_partition_num = max_partition_num; 92 | this->level = 0; 93 | } 94 | 95 | RSMI::RSMI(int index, int level, int max_partition_num) 96 | { 97 | this->index = index; 98 | this->level = level; 99 | this->max_partition_num = max_partition_num; 100 | } 101 | 102 | void RSMI::build(ExpRecorder &exp_recorder, vector points) 103 | { 104 | 105 | int page_size = Constants::PAGESIZE; 106 | auto start = chrono::high_resolution_clock::now(); 107 | if (points.size() <= exp_recorder.N) 108 | { 109 | this->model_path += "_" + to_string(level) + "_" + to_string(index); 110 | if (exp_recorder.depth < level) 111 | { 112 | exp_recorder.depth = level; 113 | } 114 | exp_recorder.last_level_model_num++; 115 | is_last = true; 116 | N = points.size(); 117 | long long side = pow(2, ceil(log(points.size()) / log(2))); 118 | sort(points.begin(), points.end(), sortX()); 119 | for (int i = 0; i < N; i++) 120 | { 121 | points[i].x_i = i; 122 | mbr.update(points[i].x, points[i].y); 123 | } 124 | sort(points.begin(), points.end(), sortY()); 125 | for (int i = 0; i < N; i++) 126 | { 127 | points[i].y_i = i; 128 | long long curve_val = compute_Hilbert_value(points[i].x_i, points[i].y_i, side); 129 | points[i].curve_val = curve_val; 130 | } 131 | sort(points.begin(), points.end(), sort_curve_val()); 132 | width = N - 1; 133 | if (N == 1) 134 | { 135 | points[0].index = 0; 136 | } 137 | else 138 | { 139 | for (long i = 0; i < N; i++) 140 | { 141 | points[i].index = i * 1.0 / (N - 1); 142 | } 143 | } 144 | leaf_node_num = points.size() / page_size; 145 | for (int i = 0; i < leaf_node_num; i++) 146 | { 147 | LeafNode leafNode; 148 | auto bn = points.begin() + i * page_size; 149 | auto en = points.begin() + i * page_size + page_size; 150 | vector vec(bn, en); 151 | // cout << vec.size() << " " << vec[0]->x_i << " " << vec[99]->x_i << endl; 152 | leafNode.add_points(vec); 153 | leafnodes.push_back(leafNode); 154 | } 155 | 156 | // for the last leafNode 157 | if (points.size() > page_size * leaf_node_num) 158 | { 159 | // TODO if do not delete will it last to the end of lifecycle? 160 | LeafNode leafNode; 161 | auto bn = points.begin() + page_size * leaf_node_num; 162 | auto en = points.end(); 163 | vector vec(bn, en); 164 | leafNode.add_points(vec); 165 | leafnodes.push_back(leafNode); 166 | leaf_node_num++; 167 | } 168 | exp_recorder.leaf_node_num += leaf_node_num; 169 | net = std::make_shared(2, leaf_node_num / 2 + 2); 170 | #ifdef use_gpu 171 | net->to(torch::kCUDA); 172 | #endif 173 | vector locations; 174 | vector labels; 175 | for (Point point : points) 176 | { 177 | locations.push_back(point.x); 178 | locations.push_back(point.y); 179 | labels.push_back(point.index); 180 | } 181 | 182 | std::ifstream fin(this->model_path); 183 | if (!fin) 184 | { 185 | net->train_model(locations, labels); 186 | // torch::save(net, this->model_path); 187 | } 188 | else 189 | { 190 | torch::load(net, this->model_path); 191 | } 192 | net->get_parameters(); 193 | 194 | exp_recorder.non_leaf_node_num++; 195 | for (int i = 0; i < N; i++) 196 | { 197 | Point point = points[i]; 198 | int predicted_index = (int)(net->predict(point) * leaf_node_num); 199 | predicted_index = predicted_index < 0 ? 0 : predicted_index; 200 | predicted_index = predicted_index >= leaf_node_num ? leaf_node_num - 1 : predicted_index; 201 | 202 | int error = i / page_size - predicted_index; 203 | 204 | if (error > 0) 205 | { 206 | if (error > max_error) 207 | { 208 | max_error = error; 209 | } 210 | } 211 | else 212 | { 213 | if (error < min_error) 214 | { 215 | min_error = error; 216 | } 217 | } 218 | } 219 | exp_recorder.average_max_error += max_error; 220 | exp_recorder.average_min_error += min_error; 221 | if ((max_error - min_error) > (exp_recorder.max_error - exp_recorder.min_error)) 222 | { 223 | exp_recorder.max_error = max_error; 224 | exp_recorder.min_error = min_error; 225 | } 226 | 227 | } 228 | else 229 | { 230 | is_last = false; 231 | N = (long long)points.size(); 232 | int bit_num = max_partition_num; 233 | int partition_size = ceil(points.size() * 1.0 / pow(bit_num, 2)); 234 | sort(points.begin(), points.end(), sortX()); 235 | long long side = pow(bit_num, 2); 236 | width = side - 1; 237 | map> points_map; 238 | int each_item_size = partition_size * bit_num; 239 | long long point_index = 0; 240 | 241 | vector locations(N * 2); 242 | vector labels(N); 243 | 244 | for (size_t i = 0; i < bit_num; i++) 245 | { 246 | long long bn_index = i * each_item_size; 247 | long long end_index = bn_index + each_item_size; 248 | if (bn_index >= N) 249 | { 250 | break; 251 | } 252 | else 253 | { 254 | if (end_index > N) 255 | { 256 | end_index = N; 257 | } 258 | } 259 | auto bn = points.begin() + bn_index; 260 | auto en = points.begin() + end_index; 261 | vector vec(bn, en); 262 | sort(vec.begin(), vec.end(), sortY()); 263 | for (size_t j = 0; j < bit_num; j++) 264 | { 265 | long long sub_bn_index = j * partition_size; 266 | long long sub_end_index = sub_bn_index + partition_size; 267 | if (sub_bn_index >= vec.size()) 268 | { 269 | break; 270 | } 271 | else 272 | { 273 | if (sub_end_index > vec.size()) 274 | { 275 | sub_end_index = vec.size(); 276 | } 277 | } 278 | auto sub_bn = vec.begin() + sub_bn_index; 279 | auto sub_en = vec.begin() + sub_end_index; 280 | vector sub_vec(sub_bn, sub_en); 281 | int Z_value = compute_Z_value(i, j, side); 282 | int sub_point_index = 1; 283 | long sub_size = sub_vec.size(); 284 | for (Point point : sub_vec) 285 | { 286 | point.index = Z_value * 1.0 / width; 287 | locations[point_index * 2] = point.x; 288 | locations[point_index * 2 + 1] = point.y; 289 | labels[point_index] = point.index; 290 | point_index++; 291 | mbr.update(point.x, point.y); 292 | sub_point_index++; 293 | } 294 | vector temp; 295 | points_map.insert(pair>(Z_value, temp)); 296 | } 297 | } 298 | 299 | int epoch = Constants::START_EPOCH; 300 | bool is_retrain = false; 301 | do 302 | { 303 | net = std::make_shared(2); 304 | #ifdef use_gpu 305 | net->to(torch::kCUDA); 306 | #endif 307 | 308 | this->model_path += "_" + to_string(level) + "_" + to_string(index); 309 | std::ifstream fin(this->model_path); 310 | net->train_model(locations, labels); 311 | 312 | // if (!fin) 313 | // { 314 | // net->train_model(locations, labels); 315 | // // torch::save(net, this->model_path); 316 | // } 317 | // else 318 | // { 319 | // torch::load(net, this->model_path); 320 | // } 321 | net->get_parameters(); 322 | 323 | for (Point point : points) 324 | { 325 | int predicted_index = (int)(net->predict(point) * width); 326 | 327 | predicted_index = predicted_index < 0 ? 0 : predicted_index; 328 | predicted_index = predicted_index >= width ? width - 1 : predicted_index; 329 | points_map[predicted_index].push_back(point); 330 | } 331 | 332 | map>::iterator iter1; 333 | iter1 = points_map.begin(); 334 | int map_size = 0; 335 | while (iter1 != points_map.end()) 336 | { 337 | if (iter1->second.size() > 0) 338 | { 339 | map_size++; 340 | } 341 | iter1++; 342 | } 343 | if (map_size < 2) 344 | { 345 | int predicted_index = (int)(net->predict(points[0]) * width); 346 | predicted_index = predicted_index < 0 ? 0 : predicted_index; 347 | predicted_index = predicted_index >= width ? width - 1 : predicted_index; 348 | 349 | points_map[predicted_index].clear(); 350 | points_map[predicted_index].shrink_to_fit(); 351 | is_retrain = true; 352 | epoch = Constants::EPOCH_ADDED; 353 | } 354 | else 355 | { 356 | is_retrain = false; 357 | } 358 | 359 | } while (is_retrain); 360 | auto finish = chrono::high_resolution_clock::now(); 361 | 362 | exp_recorder.non_leaf_node_num++; 363 | 364 | points.clear(); 365 | points.shrink_to_fit(); 366 | 367 | map>::iterator iter; 368 | iter = points_map.begin(); 369 | 370 | while (iter != points_map.end()) 371 | { 372 | if (iter->second.size() > 0) 373 | { 374 | RSMI partition(iter->first, level + 1, max_partition_num); 375 | partition.model_path = model_path; 376 | partition.build(exp_recorder, iter->second); 377 | iter->second.clear(); 378 | iter->second.shrink_to_fit(); 379 | children.insert(pair(iter->first, partition)); 380 | } 381 | iter++; 382 | } 383 | } 384 | } 385 | 386 | void RSMI::print_index_info(ExpRecorder &exp_recorder) 387 | { 388 | cout << "finish point_query max_error: " << exp_recorder.max_error << endl; 389 | cout << "finish point_query min_error: " << exp_recorder.min_error << endl; 390 | cout << "finish point_query average_max_error: " << exp_recorder.average_max_error << endl; 391 | cout << "finish point_query average_min_error: " << exp_recorder.average_min_error << endl; 392 | cout << "last_level_model_num: " << exp_recorder.last_level_model_num << endl; 393 | cout << "leaf_node_num: " << exp_recorder.leaf_node_num << endl; 394 | cout << "non_leaf_node_num: " << exp_recorder.non_leaf_node_num << endl; 395 | cout << "depth: " << exp_recorder.depth << endl; 396 | } 397 | 398 | bool RSMI::point_query(ExpRecorder &exp_recorder, Point query_point) 399 | { 400 | if (is_last) 401 | { 402 | int predicted_index = 0; 403 | predicted_index = net->predict(query_point) * leaf_node_num; 404 | predicted_index = predicted_index < 0 ? 0 : predicted_index; 405 | predicted_index = predicted_index >= leaf_node_num ? leaf_node_num - 1 : predicted_index; 406 | LeafNode leafnode = leafnodes[predicted_index]; 407 | if (leafnode.mbr.contains(query_point)) 408 | { 409 | exp_recorder.page_access += 1; 410 | vector::iterator iter = find(leafnode.children->begin(), leafnode.children->end(), query_point); 411 | if (iter != leafnode.children->end()) 412 | { 413 | return true; 414 | } 415 | } 416 | // predicted result is not correct 417 | int front = predicted_index + min_error; 418 | front = front < 0 ? 0 : front; 419 | int back = predicted_index + max_error; 420 | back = back >= leaf_node_num ? leaf_node_num - 1 : back; 421 | 422 | int gap = 1; 423 | int predicted_index_left = predicted_index - gap; 424 | int predicted_index_right = predicted_index + gap; 425 | while (predicted_index_left >= front && predicted_index_right <= back) 426 | { 427 | // search left 428 | LeafNode leafnode = leafnodes[predicted_index_left]; 429 | if (leafnode.mbr.contains(query_point)) 430 | { 431 | exp_recorder.page_access += 1; 432 | for (Point point : (*leafnode.children)) 433 | { 434 | if (query_point.x == point.x && query_point.y == point.y) 435 | { 436 | return true; 437 | } 438 | } 439 | } 440 | 441 | // search right 442 | leafnode = leafnodes[predicted_index_right]; 443 | if (leafnode.mbr.contains(query_point)) 444 | { 445 | exp_recorder.page_access += 1; 446 | for (Point point : (*leafnode.children)) 447 | { 448 | if (query_point.x == point.x && query_point.y == point.y) 449 | { 450 | return true; 451 | } 452 | } 453 | } 454 | gap++; 455 | predicted_index_left = predicted_index - gap; 456 | predicted_index_right = predicted_index + gap; 457 | } 458 | 459 | while (predicted_index_left >= front) 460 | { 461 | LeafNode leafnode = leafnodes[predicted_index_left]; 462 | 463 | if (leafnode.mbr.contains(query_point)) 464 | { 465 | exp_recorder.page_access += 1; 466 | for (Point point : (*leafnode.children)) 467 | { 468 | if (query_point.x == point.x && query_point.y == point.y) 469 | { 470 | return true; 471 | } 472 | } 473 | } 474 | gap++; 475 | predicted_index_left = predicted_index - gap; 476 | } 477 | 478 | while (predicted_index_right <= back) 479 | { 480 | LeafNode leafnode = leafnodes[predicted_index_right]; 481 | 482 | if (leafnode.mbr.contains(query_point)) 483 | { 484 | exp_recorder.page_access += 1; 485 | for (Point point : (*leafnode.children)) 486 | { 487 | if (query_point.x == point.x && query_point.y == point.y) 488 | { 489 | return true; 490 | } 491 | } 492 | } 493 | gap++; 494 | predicted_index_right = predicted_index + gap; 495 | } 496 | // cout<< "not find" << endl; 497 | // query_point.print(); 498 | return false; 499 | } 500 | else 501 | { 502 | int predicted_index = net->predict(query_point) * width; 503 | predicted_index = predicted_index < 0 ? 0 : predicted_index; 504 | predicted_index = predicted_index >= width ? width - 1 : predicted_index; 505 | if (children.count(predicted_index) == 0) 506 | { 507 | return false; 508 | } 509 | return children[predicted_index].point_query(exp_recorder, query_point); 510 | } 511 | } 512 | 513 | void RSMI::point_query(ExpRecorder &exp_recorder, vector query_points) 514 | { 515 | long size = query_points.size(); 516 | for (long i = 0; i < size; i++) 517 | { 518 | auto start = chrono::high_resolution_clock::now(); 519 | point_query(exp_recorder, query_points[i]); 520 | auto finish = chrono::high_resolution_clock::now(); 521 | exp_recorder.time += chrono::duration_cast(finish - start).count(); 522 | } 523 | exp_recorder.time /= size; 524 | exp_recorder.page_access = exp_recorder.page_access / size; 525 | } 526 | 527 | void RSMI::window_query(ExpRecorder &exp_recorder, vector query_windows) 528 | { 529 | long long time_cost = 0; 530 | int length = query_windows.size(); 531 | // length = 1; 532 | for (int i = 0; i < length; i++) 533 | { 534 | vector vertexes = query_windows[i].get_corner_points(); 535 | auto start = chrono::high_resolution_clock::now(); 536 | window_query(exp_recorder, vertexes, query_windows[i]); 537 | auto finish = chrono::high_resolution_clock::now(); 538 | exp_recorder.window_query_result_size += exp_recorder.window_query_results.size(); 539 | exp_recorder.window_query_results.clear(); 540 | exp_recorder.window_query_results.shrink_to_fit(); 541 | exp_recorder.time += chrono::duration_cast(finish - start).count(); 542 | } 543 | exp_recorder.time /= length; 544 | exp_recorder.page_access = (double)exp_recorder.page_access / length; 545 | } 546 | 547 | void RSMI::window_query(ExpRecorder &exp_recorder, vector vertexes, Mbr query_window) 548 | { 549 | if (is_last) 550 | { 551 | int leafnodes_size = leafnodes.size(); 552 | int front = leafnodes_size - 1; 553 | int back = 0; 554 | if (leaf_node_num == 0) 555 | { 556 | return; 557 | } 558 | else if (leaf_node_num < 2) 559 | { 560 | front = 0; 561 | back = 0; 562 | } 563 | else 564 | { 565 | int max = 0; 566 | int min = width; 567 | for (size_t i = 0; i < vertexes.size(); i++) 568 | { 569 | int predicted_index = net->predict(vertexes[i]) * leaf_node_num; 570 | predicted_index = predicted_index < 0 ? 0 : predicted_index; 571 | predicted_index = predicted_index > width ? width : predicted_index; 572 | int predicted_index_max = predicted_index + max_error; 573 | int predicted_index_min = predicted_index + min_error; 574 | if (predicted_index_min < min) 575 | { 576 | min = predicted_index_min; 577 | } 578 | if (predicted_index_max > max) 579 | { 580 | max = predicted_index_max; 581 | } 582 | } 583 | 584 | front = min < 0 ? 0 : min; 585 | back = max >= leafnodes_size ? leafnodes_size - 1 : max; 586 | } 587 | for (size_t i = front; i <= back; i++) 588 | { 589 | LeafNode leafnode = leafnodes[i]; 590 | if (leafnode.mbr.interact(query_window)) 591 | { 592 | exp_recorder.page_access += 1; 593 | for (Point point : (*leafnode.children)) 594 | { 595 | if (query_window.contains(point)) 596 | { 597 | exp_recorder.window_query_results.push_back(point); 598 | // exp_recorder.window_query_result_size++; 599 | } 600 | } 601 | } 602 | } 603 | return; 604 | } 605 | else 606 | { 607 | int children_size = width; 608 | int front = children_size - 1; 609 | int back = 0; 610 | for (size_t i = 0; i < vertexes.size(); i++) 611 | { 612 | int predicted_index = net->predict(vertexes[i]) * children_size; 613 | predicted_index = predicted_index < 0 ? 0 : predicted_index; 614 | predicted_index = predicted_index >= children_size ? children_size - 1 : predicted_index; 615 | if (predicted_index < front) 616 | { 617 | front = predicted_index; 618 | } 619 | if (predicted_index > back) 620 | { 621 | back = predicted_index; 622 | } 623 | } 624 | 625 | for (size_t i = front; i <= back; i++) 626 | { 627 | if (children.count(i) == 0) 628 | { 629 | continue; 630 | } 631 | if (children[i].mbr.interact(query_window)) 632 | { 633 | children[i].window_query(exp_recorder, vertexes, query_window); 634 | } 635 | } 636 | } 637 | } 638 | 639 | // this method is for knn query 640 | void RSMI::window_query(ExpRecorder &exp_recorder, vector vertexes, Mbr query_window, float boundary, int k, Point query_point, float &kth) 641 | { 642 | if (is_last) 643 | { 644 | int leafnodesSize = leafnodes.size(); 645 | int front = leafnodesSize - 1; 646 | int back = 0; 647 | if (leaf_node_num == 0) 648 | { 649 | return; 650 | } 651 | else if (leaf_node_num < 2) 652 | { 653 | front = 0; 654 | back = 0; 655 | } 656 | else 657 | { 658 | int max = 0; 659 | int min = width; 660 | for (size_t i = 0; i < vertexes.size(); i++) 661 | { 662 | auto start = chrono::high_resolution_clock::now(); 663 | int predicted_index = net->predict(vertexes[i]) * leaf_node_num; 664 | auto finish = chrono::high_resolution_clock::now(); 665 | predicted_index = predicted_index < 0 ? 0 : predicted_index; 666 | predicted_index = predicted_index > width ? width : predicted_index; 667 | int predictedIndexMax = predicted_index + max_error; 668 | int predictedIndexMin = predicted_index + min_error; 669 | if (predictedIndexMin < min) 670 | { 671 | min = predictedIndexMin; 672 | } 673 | if (predictedIndexMax > max) 674 | { 675 | max = predictedIndexMax; 676 | } 677 | } 678 | 679 | front = min < 0 ? 0 : min; 680 | back = max >= leafnodesSize ? leafnodesSize - 1 : max; 681 | } 682 | for (size_t i = front; i <= back; i++) 683 | { 684 | LeafNode leafnode = leafnodes[i]; 685 | float dis = leafnode.mbr.cal_dist(query_point); 686 | if (dis > boundary) 687 | { 688 | continue; 689 | } 690 | if (exp_recorder.pq.size() >= k && dis > kth) 691 | { 692 | continue; 693 | } 694 | if (leafnode.mbr.interact(query_window)) 695 | { 696 | exp_recorder.page_access += 1; 697 | for (Point point : (*leafnode.children)) 698 | { 699 | if (query_window.contains(point)) 700 | { 701 | if (point.cal_dist(query_point) <= boundary) 702 | { 703 | exp_recorder.pq.push(point); 704 | } 705 | } 706 | } 707 | } 708 | } 709 | return; 710 | } 711 | else 712 | { 713 | int front = width; 714 | int back = 0; 715 | for (size_t i = 0; i < vertexes.size(); i++) 716 | { 717 | auto start = chrono::high_resolution_clock::now(); 718 | int predicted_index = net->predict(vertexes[i]) * width; 719 | auto finish = chrono::high_resolution_clock::now(); 720 | predicted_index = predicted_index < 0 ? 0 : predicted_index; 721 | predicted_index = predicted_index >= width ? width - 1 : predicted_index; 722 | if (predicted_index < front) 723 | { 724 | front = predicted_index; 725 | } 726 | if (predicted_index > back) 727 | { 728 | back = predicted_index; 729 | } 730 | } 731 | for (size_t i = front; i <= back; i++) 732 | { 733 | if (children.count(i) == 0) 734 | { 735 | continue; 736 | } 737 | if (exp_recorder.pq.size() >= k && children[i].mbr.cal_dist(query_point) > kth) 738 | { 739 | continue; 740 | } 741 | if (children[i].mbr.interact(query_window)) 742 | { 743 | children[i].window_query(exp_recorder, vertexes, query_window, boundary, k, query_point, kth); 744 | } 745 | } 746 | } 747 | } 748 | 749 | vector RSMI::acc_window_query(ExpRecorder &exp_recorder, Mbr query_window) 750 | { 751 | vector window_query_results; 752 | if (is_last) 753 | { 754 | for (LeafNode leafnode : leafnodes) 755 | { 756 | if (leafnode.mbr.interact(query_window)) 757 | { 758 | exp_recorder.page_access += 1; 759 | for (Point point : (*leafnode.children)) 760 | { 761 | if (query_window.contains(point)) 762 | { 763 | window_query_results.push_back(point); 764 | } 765 | } 766 | } 767 | } 768 | } 769 | else 770 | { 771 | map::iterator iter = children.begin(); 772 | while (iter != children.end()) 773 | { 774 | if (iter->second.mbr.interact(query_window)) 775 | { 776 | vector tempResult = iter->second.acc_window_query(exp_recorder, query_window); 777 | window_query_results.insert(window_query_results.end(), tempResult.begin(), tempResult.end()); 778 | } 779 | iter++; 780 | } 781 | } 782 | return window_query_results; 783 | } 784 | 785 | void RSMI::acc_window_query(ExpRecorder &exp_recorder, vector query_windows) 786 | { 787 | int length = query_windows.size(); 788 | for (int i = 0; i < length; i++) 789 | { 790 | auto start = chrono::high_resolution_clock::now(); 791 | exp_recorder.acc_window_query_qesult_size += acc_window_query(exp_recorder, query_windows[i]).size(); 792 | auto finish = chrono::high_resolution_clock::now(); 793 | exp_recorder.time += chrono::duration_cast(finish - start).count(); 794 | } 795 | exp_recorder.time = exp_recorder.time / length; 796 | exp_recorder.page_access = (double)exp_recorder.page_access / length; 797 | } 798 | 799 | void RSMI::kNN_query(ExpRecorder &exp_recorder, vector query_points, int k) 800 | { 801 | int length = query_points.size(); 802 | exp_recorder.time = 0; 803 | exp_recorder.page_access = 0; 804 | // length = 2; 805 | for (int i = 0; i < length; i++) 806 | { 807 | priority_queue, sortForKNN2> temp_pq; 808 | exp_recorder.pq = temp_pq; 809 | auto start = chrono::high_resolution_clock::now(); 810 | vector knnresult = kNN_query(exp_recorder, query_points[i], k); 811 | auto finish = chrono::high_resolution_clock::now(); 812 | long long temp_time = chrono::duration_cast(finish - start).count(); 813 | exp_recorder.time += temp_time; 814 | exp_recorder.knn_query_results.insert(exp_recorder.knn_query_results.end(), knnresult.begin(), knnresult.end()); 815 | } 816 | exp_recorder.time /= length; 817 | exp_recorder.page_access = (double)exp_recorder.page_access / length; 818 | exp_recorder.k_num = k; 819 | } 820 | 821 | double RSMI::cal_rho(Point point) 822 | { 823 | // return 1; 824 | int predicted_index = net->predict(point) * width; 825 | predicted_index = predicted_index < 0 ? 0 : predicted_index; 826 | predicted_index = predicted_index >= width ? width - 1 : predicted_index; 827 | long long bk = 0; 828 | for (int i = 0; i < predicted_index; i++) 829 | { 830 | if (children[i].N == 0) 831 | { 832 | return 1; 833 | } 834 | bk += children[i].N; 835 | } 836 | if (children[predicted_index].N == 0) 837 | { 838 | return 1; 839 | } 840 | long long bk1 = bk + children[predicted_index].N; 841 | double result = bk1 * 1.0 / bk; 842 | // TODO use 4 to avoid a large number 843 | result = result > 1 ? result : 1; 844 | result = result > 4 ? 4 : result; 845 | return result; 846 | } 847 | 848 | vector RSMI::kNN_query(ExpRecorder &exp_recorder, Point query_point, int k) 849 | { 850 | // double rh0 = cal_rho(query_point); 851 | // float knnquery_side = sqrt((float)k / N) * rh0; 852 | vector result; 853 | float knnquery_side = sqrt((float)k / N) * 4; 854 | while (true) 855 | { 856 | Mbr mbr = Mbr::get_mbr(query_point, knnquery_side); 857 | vector vertexes = mbr.get_corner_points(); 858 | 859 | int size = 0; 860 | float kth = 0.0; 861 | window_query(exp_recorder, vertexes, mbr, knnquery_side, k, query_point, kth); 862 | size = exp_recorder.pq.size(); 863 | if (size >= k) 864 | { 865 | for (size_t i = 0; i < k; i++) 866 | { 867 | result.push_back(exp_recorder.pq.top()); 868 | exp_recorder.pq.pop(); 869 | } 870 | break; 871 | } 872 | knnquery_side *= 2; 873 | } 874 | return result; 875 | } 876 | 877 | void RSMI::acc_kNN_query(ExpRecorder &exp_recorder, vector query_points, int k) 878 | { 879 | int length = query_points.size(); 880 | // length = 1; 881 | for (int i = 0; i < length; i++) 882 | { 883 | auto start = chrono::high_resolution_clock::now(); 884 | vector knnresult = acc_kNN_query(exp_recorder, query_points[i], k); 885 | auto finish = chrono::high_resolution_clock::now(); 886 | exp_recorder.time += chrono::duration_cast(finish - start).count(); 887 | exp_recorder.acc_knn_query_results.insert(exp_recorder.acc_knn_query_results.end(), knnresult.begin(), knnresult.end()); 888 | } 889 | exp_recorder.time /= length; 890 | exp_recorder.k_num = k; 891 | exp_recorder.page_access = (double)exp_recorder.page_access / length; 892 | } 893 | 894 | vector RSMI::acc_kNN_query(ExpRecorder &exp_recorder, Point query_point, int k) 895 | { 896 | vector result; 897 | float knnquery_side = sqrt((float)k / N); 898 | while (true) 899 | { 900 | Mbr mbr = Mbr::get_mbr(query_point, knnquery_side); 901 | vector tempResult = acc_window_query(exp_recorder, mbr); 902 | if (tempResult.size() >= k) 903 | { 904 | sort(tempResult.begin(), tempResult.end(), sortForKNN(query_point)); 905 | Point last = tempResult[k - 1]; 906 | if (last.cal_dist(query_point) <= knnquery_side) 907 | { 908 | // TODO get top K from the vector. 909 | auto bn = tempResult.begin(); 910 | auto en = tempResult.begin() + k; 911 | vector vec(bn, en); 912 | result = vec; 913 | break; 914 | } 915 | } 916 | knnquery_side = knnquery_side * 2; 917 | } 918 | return result; 919 | } 920 | 921 | // TODO when rebuild!!! 922 | void RSMI::insert(ExpRecorder &exp_recorder, Point point) 923 | { 924 | int predicted_index = net->predict(point) * width; 925 | predicted_index = predicted_index < 0 ? 0 : predicted_index; 926 | predicted_index = predicted_index >= width ? width - 1 : predicted_index; 927 | if (is_last) 928 | { 929 | if (N == Constants::THRESHOLD) 930 | { 931 | // cout << "rebuild: " << endl; 932 | is_last = false; 933 | vector points; 934 | for (LeafNode leafNode : leafnodes) 935 | { 936 | points.insert(points.end(), leafNode.children->begin(), leafNode.children->end()); 937 | } 938 | points.push_back(point); 939 | auto start = chrono::high_resolution_clock::now(); 940 | build(exp_recorder, points); 941 | auto finish = chrono::high_resolution_clock::now(); 942 | exp_recorder.rebuild_time += chrono::duration_cast(finish - start).count(); 943 | exp_recorder.rebuild_num++; 944 | } 945 | else 946 | { 947 | int insertedIndex = predicted_index / Constants::PAGESIZE; 948 | LeafNode leafnode = leafnodes[insertedIndex]; 949 | if (leafnode.is_full()) 950 | { 951 | LeafNode right = leafnode.split1(); 952 | leafnodes.insert(leafnodes.begin() + insertedIndex + 1, right); 953 | leaf_node_num++; 954 | } 955 | leafnode.add_point(point); 956 | N++; 957 | width++; 958 | } 959 | } 960 | else 961 | { 962 | if (children.count(predicted_index) == 0) 963 | { 964 | // TODO 965 | return; 966 | } 967 | children[predicted_index].insert(exp_recorder, point); 968 | } 969 | } 970 | 971 | void RSMI::insert(ExpRecorder &exp_recorder, vector points) 972 | { 973 | auto start = chrono::high_resolution_clock::now(); 974 | for (Point point : points) 975 | { 976 | insert(exp_recorder, point); 977 | } 978 | auto finish = chrono::high_resolution_clock::now(); 979 | exp_recorder.insert_time = (chrono::duration_cast(finish - start).count()) / exp_recorder.insert_num; 980 | } 981 | 982 | void RSMI::remove(ExpRecorder &exp_recorder, Point point) 983 | { 984 | int predicted_index = net->predict(point) * width; 985 | predicted_index = predicted_index < 0 ? 0 : predicted_index; 986 | predicted_index = predicted_index >= N ? N - 1 : predicted_index; 987 | if (is_last) 988 | { 989 | // cout << "predicted_index: " << predicted_index << endl; 990 | int front = predicted_index + min_error; 991 | front = front < 0 ? 0 : front; 992 | int back = predicted_index + max_error; 993 | back = back >= N ? N - 1 : back; 994 | front = front / Constants::PAGESIZE; 995 | back = back / Constants::PAGESIZE; 996 | for (size_t i = front; i <= back; i++) 997 | { 998 | LeafNode leafnode = leafnodes[i]; 999 | vector::iterator iter = find(leafnode.children->begin(), leafnode.children->end(), point); 1000 | if (leafnode.mbr.contains(point) && leafnode.delete_point(point)) 1001 | { 1002 | N--; 1003 | break; 1004 | } 1005 | } 1006 | } 1007 | else 1008 | { 1009 | if (children.count(predicted_index) == 0) 1010 | { 1011 | return; 1012 | } 1013 | children[predicted_index].remove(exp_recorder, point); 1014 | } 1015 | } 1016 | 1017 | void RSMI::remove(ExpRecorder &exp_recorder, vector points) 1018 | { 1019 | auto start = chrono::high_resolution_clock::now(); 1020 | for (Point point : points) 1021 | { 1022 | remove(exp_recorder, point); 1023 | } 1024 | auto finish = chrono::high_resolution_clock::now(); 1025 | long long oldTimeCost = exp_recorder.delete_time * exp_recorder.delete_num; 1026 | exp_recorder.delete_num += points.size(); 1027 | exp_recorder.delete_time = (oldTimeCost + oldTimeCost + chrono::duration_cast(finish - start).count()) / exp_recorder.delete_num; 1028 | } -------------------------------------------------------------------------------- /curves/hilbert4.cpp: -------------------------------------------------------------------------------- 1 | /* See LICENSE below for information on rights to use, modify and distribute 2 | this code. */ 3 | 4 | /* 5 | * hilbert.c - Computes Hilbert space-filling curve coordinates, without 6 | * recursion, from integer index, and vice versa, and other Hilbert-related 7 | * calculations. Also known as Pi-order or Peano scan. 8 | * 9 | * Author: Doug Moore 10 | * Dept. of Computational and Applied Math 11 | * Rice University 12 | * http://www.caam.rice.edu/~dougm 13 | * Date: Sun Feb 20 2000 14 | * Copyright (c) 1998-2000, Rice University 15 | * 16 | * Acknowledgement: 17 | * This implementation is based on the work of A. R. Butz ("Alternative 18 | * Algorithm for Hilbert's Space-Filling Curve", IEEE Trans. Comp., April, 19 | * 1971, pp 424-426) and its interpretation by Spencer W. Thomas, University 20 | * of Michigan (http://www-personal.umich.edu/~spencer/Home.html) in his widely 21 | * available C software. While the implementation here differs considerably 22 | * from his, the first two interfaces and the style of some comments are very 23 | * much derived from his work. */ 24 | 25 | 26 | #include "hilbert4.H" 27 | 28 | /* implementation of the hilbert functions */ 29 | 30 | #define adjust_rotation(rotation,nDims,bits) \ 31 | do { \ 32 | /* rotation = (rotation + 1 + ffs(bits)) % nDims; */ \ 33 | bits &= -bits & nd1Ones; \ 34 | while (bits) \ 35 | bits >>= 1, ++rotation; \ 36 | if ( ++rotation >= nDims ) \ 37 | rotation -= nDims; \ 38 | } while (0) 39 | 40 | #define ones(T,k) ((((T)2) << (k-1)) - 1) 41 | 42 | #define rdbit(w,k) (((w) >> (k)) & 1) 43 | 44 | #define rotateRight(arg, nRots, nDims) \ 45 | ((((arg) >> (nRots)) | ((arg) << ((nDims)-(nRots)))) & ones(bitmask_t,nDims)) 46 | 47 | #define rotateLeft(arg, nRots, nDims) \ 48 | ((((arg) << (nRots)) | ((arg) >> ((nDims)-(nRots)))) & ones(bitmask_t,nDims)) 49 | 50 | #define DLOGB_BIT_TRANSPOSE 51 | static bitmask_t 52 | bitTranspose(unsigned nDims, unsigned nBits, bitmask_t inCoords) 53 | #if defined(DLOGB_BIT_TRANSPOSE) 54 | { 55 | unsigned const nDims1 = nDims-1; 56 | unsigned inB = nBits; 57 | unsigned utB; 58 | bitmask_t inFieldEnds = 1; 59 | bitmask_t inMask = ones(bitmask_t,inB); 60 | bitmask_t coords = 0; 61 | 62 | while ((utB = inB / 2)) 63 | { 64 | unsigned const shiftAmt = nDims1 * utB; 65 | bitmask_t const utFieldEnds = 66 | inFieldEnds | (inFieldEnds << (shiftAmt+utB)); 67 | bitmask_t const utMask = 68 | (utFieldEnds << utB) - utFieldEnds; 69 | bitmask_t utCoords = 0; 70 | unsigned d; 71 | if (inB & 1) 72 | { 73 | bitmask_t const inFieldStarts = inFieldEnds << (inB-1); 74 | unsigned oddShift = 2*shiftAmt; 75 | for (d = 0; d < nDims; ++d) 76 | { 77 | bitmask_t in = inCoords & inMask; 78 | inCoords >>= inB; 79 | coords |= (in & inFieldStarts) << oddShift++; 80 | in &= ~inFieldStarts; 81 | in = (in | (in << shiftAmt)) & utMask; 82 | utCoords |= in << (d*utB); 83 | } 84 | } 85 | else 86 | { 87 | for (d = 0; d < nDims; ++d) 88 | { 89 | bitmask_t in = inCoords & inMask; 90 | inCoords >>= inB; 91 | in = (in | (in << shiftAmt)) & utMask; 92 | utCoords |= in << (d*utB); 93 | } 94 | } 95 | inCoords = utCoords; 96 | inB = utB; 97 | inFieldEnds = utFieldEnds; 98 | inMask = utMask; 99 | } 100 | coords |= inCoords; 101 | return coords; 102 | } 103 | #else 104 | { 105 | bitmask_t coords = 0; 106 | unsigned d; 107 | for (d = 0; d < nDims; ++d) 108 | { 109 | unsigned b; 110 | bitmask_t in = inCoords & ones(bitmask_t,nBits); 111 | bitmask_t out = 0; 112 | inCoords >>= nBits; 113 | for (b = nBits; b--;) 114 | { 115 | out <<= nDims; 116 | out |= rdbit(in, b); 117 | } 118 | coords |= out << d; 119 | } 120 | return coords; 121 | } 122 | #endif 123 | 124 | /***************************************************************** 125 | * hilbert_i2c 126 | * 127 | * Convert an index into a Hilbert curve to a set of coordinates. 128 | * Inputs: 129 | * nDims: Number of coordinate axes. 130 | * nBits: Number of bits per axis. 131 | * index: The index, contains nDims*nBits bits 132 | * (so nDims*nBits must be <= 8*sizeof(bitmask_t)). 133 | * Outputs: 134 | * coord: The list of nDims coordinates, each with nBits bits. 135 | * Assumptions: 136 | * nDims*nBits <= (sizeof index) * (bits_per_byte) 137 | */ 138 | void 139 | hilbert_i2c(unsigned nDims, unsigned nBits, bitmask_t index, bitmask_t coord[]) 140 | { 141 | if (nDims > 1) 142 | { 143 | bitmask_t coords; 144 | halfmask_t const nbOnes = ones(halfmask_t,nBits); 145 | unsigned d; 146 | 147 | if (nBits > 1) 148 | { 149 | unsigned const nDimsBits = nDims*nBits; 150 | halfmask_t const ndOnes = ones(halfmask_t,nDims); 151 | halfmask_t const nd1Ones= ndOnes >> 1; /* for adjust_rotation */ 152 | unsigned b = nDimsBits; 153 | unsigned rotation = 0; 154 | halfmask_t flipBit = 0; 155 | bitmask_t const nthbits = ones(bitmask_t,nDimsBits) / ndOnes; 156 | index ^= (index ^ nthbits) >> 1; 157 | coords = 0; 158 | do 159 | { 160 | halfmask_t bits = (index >> (b-=nDims)) & ndOnes; 161 | coords <<= nDims; 162 | coords |= rotateLeft(bits, rotation, nDims) ^ flipBit; 163 | flipBit = (halfmask_t)1 << rotation; 164 | adjust_rotation(rotation,nDims,bits); 165 | } while (b); 166 | for (b = nDims; b < nDimsBits; b *= 2) 167 | coords ^= coords >> b; 168 | coords = bitTranspose(nBits, nDims, coords); 169 | } 170 | else 171 | coords = index ^ (index >> 1); 172 | 173 | for (d = 0; d < nDims; ++d) 174 | { 175 | coord[d] = coords & nbOnes; 176 | coords >>= nBits; 177 | } 178 | } 179 | else 180 | coord[0] = index; 181 | } 182 | 183 | /***************************************************************** 184 | * hilbert_c2i 185 | * 186 | * Convert coordinates of a point on a Hilbert curve to its index. 187 | * Inputs: 188 | * nDims: Number of coordinates. 189 | * nBits: Number of bits/coordinate. 190 | * coord: Array of n nBits-bit coordinates. 191 | * Outputs: 192 | * index: Output index value. nDims*nBits bits. 193 | * Assumptions: 194 | * nDims*nBits <= (sizeof bitmask_t) * (bits_per_byte) 195 | */ 196 | bitmask_t 197 | hilbert_c2i(unsigned nDims, unsigned nBits, bitmask_t const coord[]) 198 | { 199 | if (nDims > 1) 200 | { 201 | unsigned const nDimsBits = nDims*nBits; // 3 * 24 202 | bitmask_t index; 203 | unsigned d; 204 | bitmask_t coords = 0; 205 | // for (d = nDims; d--; ) 206 | for (d = 0; d < nDims; d++) 207 | { 208 | coords <<= nBits; 209 | coords |= coord[d]; 210 | } 211 | 212 | if (nBits > 1) 213 | { 214 | halfmask_t const ndOnes = ones(halfmask_t,nDims); 215 | halfmask_t const nd1Ones= ndOnes >> 1; /* for adjust_rotation */ 216 | unsigned b = nDimsBits; 217 | unsigned rotation = 0; 218 | halfmask_t flipBit = 0; 219 | bitmask_t const nthbits = ones(bitmask_t,nDimsBits) / ndOnes; 220 | coords = bitTranspose(nDims, nBits, coords); 221 | coords ^= coords >> nDims; 222 | index = 0; 223 | do 224 | { 225 | halfmask_t bits = (coords >> (b-=nDims)) & ndOnes; 226 | bits = rotateRight(flipBit ^ bits, rotation, nDims); 227 | index <<= nDims; 228 | index |= bits; 229 | flipBit = (halfmask_t)1 << rotation; 230 | adjust_rotation(rotation,nDims,bits); 231 | } while (b); 232 | index ^= nthbits >> 1; 233 | } 234 | else 235 | index = coords; 236 | for (d = 1; d < nDimsBits; d *= 2) 237 | index ^= index >> d; 238 | 239 | return index; 240 | } 241 | else 242 | return coord[0]; 243 | } 244 | 245 | /***************************************************************** 246 | * Readers and writers of bits 247 | */ 248 | 249 | typedef bitmask_t (*BitReader) (unsigned nDims, unsigned nBytes, 250 | char const* c, unsigned y); 251 | typedef void (*BitWriter) (unsigned d, unsigned nBytes, 252 | char* c, unsigned y, int fold); 253 | 254 | 255 | #if defined(sparc) 256 | #define __BIG_ENDIAN__ 257 | #endif 258 | 259 | #if defined(__BIG_ENDIAN__) 260 | #define whichByte(nBytes,y) (nBytes-1-y/8) 261 | #define setBytes(dst,pos,nBytes,val) \ 262 | memset(&dst[pos+1],val,nBytes-pos-1) 263 | #else 264 | #define whichByte(nBytes,y) (y/8) 265 | #define setBytes(dst,pos,nBytes,val) \ 266 | memset(&dst[0],val,pos) 267 | #endif 268 | 269 | static bitmask_t 270 | getIntBits(unsigned nDims, unsigned nBytes, char const* c, unsigned y) 271 | { 272 | unsigned const bit = y%8; 273 | unsigned const offs = whichByte(nBytes,y); 274 | unsigned d; 275 | bitmask_t bits = 0; 276 | c += offs; 277 | for (d = 0; d < nDims; ++d) 278 | { 279 | bits |= rdbit(*c, bit) << d; 280 | c += nBytes; 281 | } 282 | return bits; 283 | } 284 | 285 | #include 286 | static void 287 | propogateIntBits(unsigned d, unsigned nBytes, 288 | char* c, unsigned y, int fold) 289 | { 290 | unsigned const byteId = whichByte(nBytes,y); 291 | unsigned const b = y%8; 292 | char const bthbit = 1 << b; 293 | char* const target = &c[d*nBytes]; 294 | target[byteId] ^= bthbit; 295 | if (!fold) 296 | { 297 | char notbit = ((target[byteId] >> b) & 1) - 1; 298 | if (notbit) 299 | target[byteId] |= bthbit-1; 300 | else 301 | target[byteId] &= -bthbit; 302 | setBytes(target,byteId,nBytes,notbit); 303 | } 304 | } 305 | 306 | /* An IEEE double is treated as a 2100 bit number. In particular, 0 is treated 307 | as a 1 followed by 2099 zeroes, and negative 0 as a 0 followed by 2099 ones. 308 | Only 53 bits differ between a number and a zero of the same sign, with the 309 | position of the 53 determined by the exponent, and the values of the 53 by 310 | the significand (with implicit leading 1 bit). Although IEEE 754 uses the 311 | maximum exponent for NaN's and infinities, this implementation ignores that 312 | decision, so that infinities and NaN's are treated as very large numbers. 313 | Note that we do not explicitly construct a 2100 bit bitmask in the IEEE 314 | routines below. */ 315 | 316 | enum { IEEEexpBits = 11 }; 317 | enum { IEEEsigBits = 52 }; 318 | enum { IEEErepBits = (1 << IEEEexpBits) + IEEEsigBits }; 319 | 320 | typedef union ieee754_double 321 | { 322 | double d; 323 | 324 | /* This is the IEEE 754 double-precision format. */ 325 | struct 326 | { 327 | #if defined(__BIG_ENDIAN__) 328 | unsigned int negative:1; 329 | unsigned int exponent:11; 330 | /* Together these comprise the mantissa. */ 331 | unsigned int mantissa0:20; 332 | unsigned int mantissa1:32; 333 | #else /* Big endian. */ 334 | /* Together these comprise the mantissa. */ 335 | unsigned int mantissa1:32; 336 | unsigned int mantissa0:20; 337 | unsigned int exponent:11; 338 | unsigned int negative:1; 339 | #endif /* Little endian. */ 340 | } ieee; 341 | } ieee754_double; 342 | 343 | static bitmask_t 344 | getIEEESignBits(unsigned nDims, double const* c) 345 | { 346 | unsigned d; 347 | ieee754_double x; 348 | bitmask_t bits = 0; 349 | for (d = 0; d < nDims; ++d) 350 | { 351 | x.d = c[d]; 352 | bits |= x.ieee.negative << d; 353 | } 354 | return bits; 355 | } 356 | 357 | static bitmask_t 358 | getIEEEBits(unsigned nDims, 359 | unsigned ignoreMe, /* ignored */ 360 | char const* cP, 361 | unsigned y) 362 | /* retrieve bits y of elements of double array c, where an expanded IEEE 363 | double has 2100 bits. */ 364 | { 365 | unsigned d; 366 | double const* c = (double const*) cP; 367 | ieee754_double x; 368 | bitmask_t bits = 0; 369 | for (x.d = c[d=0]; d < nDims; x.d = c[++d]) 370 | { 371 | bitmask_t bit = x.ieee.negative; 372 | unsigned normalized = (x.ieee.exponent != 0); 373 | unsigned diff = y - (x.ieee.exponent - normalized); 374 | if (diff <= 52) 375 | bit ^= 1 & ((diff < 32)? x.ieee.mantissa1 >> diff: 376 | (diff < 52)? x.ieee.mantissa0 >> (diff - 32): 377 | /* else */ normalized); 378 | else 379 | bit ^= (y == IEEErepBits-1); 380 | 381 | bits |= bit << d; 382 | } 383 | return bits; 384 | } 385 | 386 | static void 387 | propogateIEEEBits(unsigned d, unsigned nBytes, 388 | char* cP, unsigned y, int fold) 389 | { 390 | ieee754_double* x = d + (ieee754_double*) cP; 391 | unsigned normalized = (x->ieee.exponent != 0); 392 | unsigned diff = y - (x->ieee.exponent - normalized); 393 | if (diff < 32) 394 | { 395 | unsigned b = 1 << diff; 396 | unsigned bit = x->ieee.mantissa1 & b; 397 | x->ieee.mantissa1 &= ~(b-1); 398 | x->ieee.mantissa1 |= b; 399 | if (bit) 400 | --x->ieee.mantissa1; 401 | } 402 | else if (diff < 52) 403 | { 404 | unsigned b = 1 << (diff - 32); 405 | unsigned bit = x->ieee.mantissa0 & b; 406 | x->ieee.mantissa0 &= ~(b-1); 407 | x->ieee.mantissa0 |= b; 408 | if (bit) 409 | --x->ieee.mantissa0; 410 | x->ieee.mantissa1 = bit?-1: 0; 411 | } 412 | else if (diff == 52) /* "flip" the implicit 1 bit */ 413 | { 414 | if (normalized) 415 | --x->ieee.exponent; 416 | else 417 | x->ieee.exponent = 1; 418 | x->ieee.mantissa0 = -normalized; 419 | x->ieee.mantissa1 = -normalized; 420 | } 421 | else if (diff < IEEErepBits) 422 | { 423 | if (y == IEEErepBits-1) 424 | { 425 | x->ieee.negative ^= 1; 426 | x->ieee.exponent = 0; 427 | } 428 | else 429 | x->ieee.exponent = y - 51; 430 | x->ieee.mantissa0 = 0; 431 | x->ieee.mantissa1 = 0; 432 | } 433 | } 434 | 435 | static unsigned 436 | getIEEEexptMax(unsigned nDims, double const* c) 437 | { 438 | unsigned max = 0; 439 | unsigned d; 440 | for (d = 0; d < nDims; ++d) 441 | { 442 | ieee754_double x; 443 | x.d = c[d]; 444 | if (max < x.ieee.exponent) 445 | max = x.ieee.exponent; 446 | } 447 | if (max) --max; 448 | return max; 449 | } 450 | 451 | static void 452 | getIEEEinitValues(double const* c1, 453 | unsigned y, 454 | unsigned nDims, 455 | unsigned* rotation, 456 | bitmask_t* bits, 457 | bitmask_t* index) 458 | { 459 | bitmask_t const one = 1; 460 | unsigned d; 461 | bitmask_t signBits = getIEEESignBits(nDims, c1); 462 | unsigned signParity, leastZeroBit, strayBit; 463 | 464 | /* compute the odd/evenness of the number of sign bits */ 465 | { 466 | bitmask_t signPar = signBits; 467 | for (d = 1; d < nDims; d *= 2) 468 | signPar ^= signPar >> d; 469 | signParity = signPar & 1; 470 | } 471 | 472 | /* find the position of the least-order 0 bit in among signBits and adjust it 473 | if necessary */ 474 | for (leastZeroBit = 0; leastZeroBit < nDims; ++leastZeroBit) 475 | if (rdbit(signBits, leastZeroBit) == 0) 476 | break; 477 | strayBit = 0; 478 | if (leastZeroBit == nDims-2) 479 | strayBit = 1; 480 | else if (leastZeroBit == nDims) 481 | leastZeroBit = nDims-1; 482 | 483 | if (y % 2 == 1) 484 | { 485 | *rotation = (IEEErepBits - y + 1 + leastZeroBit) % nDims; 486 | if (y < IEEErepBits-1) 487 | { 488 | *bits = signBits ^ (one << ((*rotation + strayBit) % nDims)); 489 | *index = signParity; 490 | } 491 | else /* y == IEEErepBits-1 */ 492 | { 493 | *bits = signBits ^ (ones(bitmask_t,nDims) &~ 1); 494 | *index = signParity ^ (nDims&1); 495 | } 496 | } 497 | else /* y % 2 == 0 */ 498 | if (y < IEEErepBits) 499 | { 500 | unsigned shift_amt = (IEEErepBits - y + leastZeroBit) % nDims; 501 | *rotation = (shift_amt + 2 + strayBit) % nDims; 502 | *bits = signBits ^ (one << shift_amt); 503 | *index = signParity ^ 1; 504 | } 505 | else /* y == IEEErepBits */ 506 | { 507 | *rotation = 0; 508 | *bits = one << (nDims-1); 509 | *index = 1; 510 | } 511 | } 512 | 513 | /***************************************************************** 514 | * hilbert_cmp, hilbert_ieee_cmp 515 | * 516 | * Determine which of two points lies further along the Hilbert curve 517 | * Inputs: 518 | * nDims: Number of coordinates. 519 | * nBytes: Number of bytes of storage/coordinate (hilbert_cmp only) 520 | * nBits: Number of bits/coordinate. (hilbert_cmp only) 521 | * coord1: Array of nDims nBytes-byte coordinates (or doubles for ieee_cmp). 522 | * coord2: Array of nDims nBytes-byte coordinates (or doubles for ieee_cmp). 523 | * Return value: 524 | * -1, 0, or 1 according to whether 525 | coord1coord2 526 | * Assumptions: 527 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 528 | */ 529 | 530 | static int 531 | hilbert_cmp_work(unsigned nDims, unsigned nBytes, unsigned nBits, 532 | unsigned max, unsigned y, 533 | char const* c1, char const* c2, 534 | unsigned rotation, 535 | bitmask_t bits, 536 | bitmask_t index, 537 | BitReader getBits) 538 | { 539 | bitmask_t const one = 1; 540 | bitmask_t const nd1Ones = ones(bitmask_t,nDims) >> 1; /* used in adjust_rotation macro */ 541 | while (y-- > max) 542 | { 543 | bitmask_t reflection = getBits(nDims, nBytes, c1, y); 544 | bitmask_t diff = reflection ^ getBits(nDims, nBytes, c2, y); 545 | bits ^= reflection; 546 | bits = rotateRight(bits, rotation, nDims); 547 | if (diff) 548 | { 549 | unsigned d; 550 | diff = rotateRight(diff, rotation, nDims); 551 | for (d = 1; d < nDims; d *= 2) 552 | { 553 | index ^= index >> d; 554 | bits ^= bits >> d; 555 | diff ^= diff >> d; 556 | } 557 | return (((index ^ y ^ nBits) & 1) == (bits < (bits^diff)))? -1: 1; 558 | } 559 | index ^= bits; 560 | reflection ^= one << rotation; 561 | adjust_rotation(rotation,nDims,bits); 562 | bits = reflection; 563 | } 564 | return 0; 565 | } 566 | 567 | int 568 | hilbert_cmp(unsigned nDims, unsigned nBytes, unsigned nBits, 569 | void const* c1, void const* c2) 570 | { 571 | bitmask_t const one = 1; 572 | bitmask_t bits = one << (nDims-1); 573 | return hilbert_cmp_work(nDims, nBytes, nBits, 0, nBits, 574 | (char const*)c1, (char const*)c2, 575 | 0, bits, bits, getIntBits); 576 | } 577 | 578 | int 579 | hilbert_ieee_cmp(unsigned nDims, double const* c1, double const* c2) 580 | { 581 | unsigned rotation, max; 582 | bitmask_t bits, index; 583 | if (getIEEESignBits(nDims, c1) != getIEEESignBits(nDims, c2)) 584 | max = 2047; 585 | else 586 | { 587 | unsigned max1 = getIEEEexptMax(nDims, c1); 588 | unsigned max2 = getIEEEexptMax(nDims, c2); 589 | max = (max1 > max2)? max1: max2; 590 | } 591 | 592 | getIEEEinitValues(c1, max+53, nDims, &rotation, &bits, &index); 593 | return hilbert_cmp_work(nDims, 8, 64, max, max+53, 594 | (char const*)c1, (char const*)c2, 595 | rotation, bits, index, getIEEEBits); 596 | } 597 | 598 | /***************************************************************** 599 | * hilbert_box_vtx 600 | * 601 | * Determine the first or last vertex of a box to lie on a Hilbert curve 602 | * Inputs: 603 | * nDims: Number of coordinates. 604 | * nBytes: Number of bytes/coordinate. 605 | * nBits: Number of bits/coordinate. 606 | * findMin: Is it the least vertex sought? 607 | * coord1: Array of nDims nBytes-byte coordinates - one corner of box 608 | * coord2: Array of nDims nBytes-byte coordinates - opposite corner 609 | * Output: 610 | * c1 and c2 modified to refer to selected corner 611 | * value returned is log2 of size of largest power-of-two-aligned box that 612 | * contains the selected corner and no other corners 613 | * Assumptions: 614 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 615 | */ 616 | 617 | 618 | static unsigned 619 | hilbert_box_vtx_work(unsigned nDims, unsigned nBytes, unsigned nBits, 620 | int findMin, 621 | unsigned max, unsigned y, 622 | char* c1, char* c2, 623 | unsigned rotation, 624 | bitmask_t bits, 625 | bitmask_t index, 626 | BitReader getBits) 627 | { 628 | bitmask_t const one = 1; 629 | bitmask_t const ndOnes = ones(bitmask_t,nDims); 630 | bitmask_t const nd1Ones= ndOnes >> 1; 631 | bitmask_t bitsFolded = 0; 632 | 633 | while (y--) 634 | { 635 | bitmask_t reflection = getBits(nDims, nBytes, c1, y); 636 | bitmask_t diff = reflection ^ getBits(nDims, nBytes, c2, y); 637 | if (diff) 638 | { 639 | unsigned d; 640 | bitmask_t smear = rotateRight(diff, rotation, nDims) >> 1; 641 | bitmask_t digit = rotateRight(bits ^ reflection, rotation, nDims); 642 | for (d = 1; d < nDims; d *= 2) 643 | { 644 | index ^= index >> d; 645 | digit ^= (digit >> d) &~ smear; 646 | smear |= smear >> d; 647 | } 648 | index &= 1; 649 | if ((index ^ y ^ findMin) & 1) 650 | digit ^= smear+1; 651 | digit = rotateLeft(digit, rotation, nDims) & diff; 652 | reflection ^= digit; 653 | 654 | for (d = 0; d < nDims; ++d) 655 | if (rdbit(diff, d)) 656 | { 657 | int way = rdbit(digit, d); 658 | char* target = d*nBytes + (way? c1: c2); 659 | char* const source = 2*d*nBytes + c1 - target + c2; 660 | memcpy(target, source, nBytes); 661 | } 662 | 663 | bitsFolded |= diff; 664 | if (bitsFolded == ndOnes) 665 | return y; 666 | } 667 | 668 | bits ^= reflection; 669 | bits = rotateRight(bits, rotation, nDims); 670 | index ^= bits; 671 | reflection ^= one << rotation; 672 | adjust_rotation(rotation,nDims,bits); 673 | bits = reflection; 674 | } 675 | return y; 676 | } 677 | 678 | unsigned 679 | hilbert_box_vtx(unsigned nDims, unsigned nBytes, unsigned nBits, 680 | int findMin, void* c1, void* c2) 681 | { 682 | bitmask_t const one = 1; 683 | bitmask_t bits = one << (nDims-1); 684 | return hilbert_box_vtx_work(nDims, nBytes, nBits, findMin, 685 | 0, nBits, (char*)c1, (char*)c2, 686 | 0, bits, bits, getIntBits); 687 | } 688 | 689 | unsigned 690 | hilbert_ieee_box_vtx(unsigned nDims, 691 | int findMin, double* c1, double* c2) 692 | { 693 | unsigned rotation, max; 694 | bitmask_t bits, index; 695 | if (getIEEESignBits(nDims, c1) != getIEEESignBits(nDims, c2)) 696 | max = 2047; 697 | else 698 | { 699 | unsigned max1 = getIEEEexptMax(nDims, c1); 700 | unsigned max2 = getIEEEexptMax(nDims, c2); 701 | max = (max1 > max2)? max1: max2; 702 | } 703 | 704 | getIEEEinitValues(c1, max+53, nDims, &rotation, &bits, &index); 705 | 706 | return hilbert_box_vtx_work(nDims, 8, 64, findMin, 707 | max, max+53, (char *)c1, (char *)c2, 708 | rotation, bits, index, getIEEEBits); 709 | } 710 | 711 | /***************************************************************** 712 | * hilbert_box_pt 713 | * 714 | * Determine the first or last point of a box to lie on a Hilbert curve 715 | * Inputs: 716 | * nDims: Number of coordinates. 717 | * nBytes: Number of bytes/coordinate. 718 | * nBits: Number of bits/coordinate. 719 | * findMin: Is it the least vertex sought? 720 | * coord1: Array of nDims nBytes-byte coordinates - one corner of box 721 | * coord2: Array of nDims nBytes-byte coordinates - opposite corner 722 | * Output: 723 | * c1 and c2 modified to refer to least point 724 | * Assumptions: 725 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 726 | */ 727 | unsigned 728 | hilbert_box_pt_work(unsigned nDims, unsigned nBytes, unsigned nBits, 729 | int findMin, 730 | unsigned max, unsigned y, 731 | char* c1, char* c2, 732 | unsigned rotation, 733 | bitmask_t bits, 734 | bitmask_t index, 735 | BitReader getBits, 736 | BitWriter propogateBits) 737 | { 738 | bitmask_t const one = 1; 739 | bitmask_t const nd1Ones = ones(bitmask_t,nDims) >> 1; 740 | bitmask_t fold1 = 0, fold2 = 0; 741 | unsigned smearSum = 0; 742 | 743 | while (y-- > max) 744 | { 745 | bitmask_t reflection = getBits(nDims, nBytes, c1, y); 746 | bitmask_t diff = reflection ^ getBits(nDims, nBytes, c2, y); 747 | if (diff) 748 | { 749 | bitmask_t smear = rotateRight(diff, rotation, nDims) >> 1; 750 | bitmask_t digit = rotateRight(bits ^ reflection, rotation, nDims); 751 | unsigned d; 752 | for (d = 1; d < nDims; d *= 2) 753 | { 754 | index ^= index >> d; 755 | digit ^= (digit >> d) &~ smear; 756 | smear |= smear >> d; 757 | } 758 | smearSum += smear; 759 | index &= 1; 760 | if ((index ^ y ^ findMin) & 1) 761 | digit ^= smear+1; 762 | digit = rotateLeft(digit, rotation, nDims) & diff; 763 | reflection ^= digit; 764 | 765 | for (d = 0; d < nDims; ++d) 766 | if (rdbit(diff, d)) 767 | { 768 | int way = rdbit(digit, d); 769 | char* c = way? c1: c2; 770 | bitmask_t fold = way? fold1: fold2; 771 | propogateBits(d, nBytes, c, y, rdbit(fold, d)); 772 | } 773 | diff ^= digit; 774 | fold1 |= digit; 775 | fold2 |= diff; 776 | } 777 | 778 | bits ^= reflection; 779 | bits = rotateRight(bits, rotation, nDims); 780 | index ^= bits; 781 | reflection ^= one << rotation; 782 | adjust_rotation(rotation,nDims,bits); 783 | bits = reflection; 784 | } 785 | return smearSum; 786 | } 787 | 788 | unsigned 789 | hilbert_box_pt(unsigned nDims, unsigned nBytes, unsigned nBits, 790 | int findMin, void* c1, void* c2) 791 | { 792 | bitmask_t const one = 1; 793 | bitmask_t bits = one << (nDims-1); 794 | return hilbert_box_pt_work(nDims, nBytes, nBits, findMin, 795 | 0, nBits, (char*)c1, (char*)c2, 796 | 0, bits, bits, 797 | getIntBits, propogateIntBits); 798 | } 799 | 800 | unsigned 801 | hilbert_ieee_box_pt(unsigned nDims, 802 | int findMin, double* c1, double* c2) 803 | { 804 | unsigned rotation, max; 805 | bitmask_t bits, index; 806 | bitmask_t c1Signs = getIEEESignBits(nDims, c1); 807 | bitmask_t c2Signs = getIEEESignBits(nDims, c2); 808 | if (c1Signs != c2Signs) 809 | { 810 | rotation = 0; 811 | bits = (bitmask_t)1 << (nDims-1); 812 | index = 1; 813 | hilbert_box_pt_work(nDims, 8, 64, findMin, 814 | IEEErepBits-1, IEEErepBits, (char *)c1, (char *)c2, 815 | rotation, bits, index, 816 | getIEEEBits, propogateIEEEBits); 817 | } 818 | 819 | /* having put everything in the same orthant, start */ 820 | { 821 | unsigned max1 = getIEEEexptMax(nDims, c1); 822 | unsigned max2 = getIEEEexptMax(nDims, c2); 823 | max = (max1 > max2)? max1: max2; 824 | } 825 | 826 | getIEEEinitValues(c1, max+53, nDims, &rotation, &bits, &index); 827 | 828 | return hilbert_box_pt_work(nDims, 8, 64, findMin, 829 | max, max+53, (char *)c1, (char *)c2, 830 | rotation, bits, index, 831 | getIEEEBits, propogateIEEEBits); 832 | } 833 | 834 | /***************************************************************** 835 | * hilbert_nextinbox 836 | * 837 | * Determine the first point of a box after or before a given point to lie on 838 | * a Hilbert curve 839 | * Inputs: 840 | * nDims: Number of coordinates. 841 | * nBytes: Number of bytes/coordinate. 842 | * nBits: Number of bits/coordinate. 843 | * findPrev: Is it a previous point that you want? 844 | * coord1: Array of nDims nBytes-byte coordinates - one corner of box 845 | * coord2: Array of nDims nBytes-byte coordinates - opposite corner 846 | * point: Array of nDims nBytes-byte coordinates - lower bound on point returned 847 | * 848 | * Output: 849 | if returns 1: 850 | * c1 and c2 modified to refer to least point after "point" in box 851 | else returns 0: 852 | arguments unchanged; "point" is beyond the last point of the box 853 | * Assumptions: 854 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 855 | */ 856 | int 857 | hilbert_nextinbox(unsigned nDims, unsigned nBytes, unsigned nBits, 858 | int findPrev, void* c1V, void* c2V, void const* ptV) 859 | { 860 | bitmask_t const one = 1; 861 | unsigned y = nBits; 862 | bitmask_t const ndOnes = ones(bitmask_t,nDims); 863 | bitmask_t const nd1Ones = ndOnes >> 1; 864 | unsigned rotation = 0; 865 | bitmask_t bits = 0; 866 | bitmask_t index = 0; 867 | bitmask_t fold1 = 0, fold2 = 0; 868 | bitmask_t valu1 = 0, valu2 = 0; 869 | unsigned p_y; 870 | bitmask_t p_separator = 0, p_firstSeparator; 871 | bitmask_t p_cornerdiff, p_reflection; 872 | bitmask_t p_fold1, p_fold2, p_valu1, p_valu2; 873 | 874 | char* c1 = (char*)c1V; 875 | char* c2 = (char*)c2V; 876 | char const* pt = (const char*)ptV; 877 | 878 | while (y-- > 0) 879 | { 880 | bitmask_t reflection = getIntBits(nDims, nBytes, pt, y); 881 | bitmask_t diff = reflection ^ /* planes that separate box and point */ 882 | ((getIntBits(nDims, nBytes, c1, y) &~ fold1) | valu1); 883 | 884 | if (diff) 885 | /* some coordinate planes separate point from box or 886 | dividing box or both; smear the bits of diff to reflect that 887 | after the first diff dimension, they might as well all be 888 | diffing; adjust the diff to reflect the fact that diffed 889 | dimensions don't matter. */ 890 | { 891 | /* compute (the complement of) a "digit" in the integer index of this 892 | point */ 893 | bitmask_t cornerdiff = (diff ^ reflection) ^ /* separate box crnrs */ 894 | ((getIntBits(nDims, nBytes, c2, y) &~ fold2) | valu2); 895 | bitmask_t separator = diff & ~cornerdiff; 896 | /* eventually, the most significant separating cutting plane */ 897 | bitmask_t firstSeparator; 898 | /* bits less significant than the msb of separator are irrelevant; 899 | for convenience, call them all separators too */ 900 | bitmask_t rotSep = rotateRight(separator, rotation, nDims); 901 | /* compute the (complement of the) digit of the hilbert code 902 | assoc with point */ 903 | bitmask_t digit = rotateRight(bits ^ reflection, rotation, nDims); 904 | unsigned d; 905 | for (d = 1; d < nDims; d *= 2) 906 | { 907 | index ^= index >> d; 908 | digit ^= digit >> d; 909 | rotSep |= rotSep >> d; 910 | } 911 | index &= 1; 912 | digit &= rotSep; 913 | if ((index ^ y ^ findPrev) & 1) 914 | digit ^= rotSep; 915 | 916 | separator = rotateLeft(rotSep, rotation, nDims); 917 | rotSep -= rotSep >> 1; 918 | firstSeparator = rotateLeft(rotSep, rotation, nDims); 919 | /* forget about all the planes that split the box, except those that 920 | are more significant than the most significant separator. */ 921 | cornerdiff &= ~separator; 922 | 923 | if (cornerdiff && digit) 924 | /* some coordinate planes divide the box. Call the part of the 925 | box in the same orthant as the point "here" and the part of 926 | the box in the next (or previous) orthant "there". Remember 927 | what the "there" orthant of the box looks like in case it 928 | turns out that the curve doesn't reenter the box "here" after 929 | (before) passing thru point. Continue working with the 930 | "here" part. If there is no "there" there, skip it */ 931 | { 932 | p_firstSeparator = digit & -digit; 933 | p_separator = 2*p_firstSeparator-1; 934 | p_separator = rotateLeft(p_separator, rotation, nDims); 935 | p_firstSeparator = rotateLeft(p_firstSeparator, rotation, nDims); 936 | p_cornerdiff = cornerdiff &~ (p_separator ^ p_firstSeparator); 937 | p_y = y; 938 | p_reflection = reflection ^ p_firstSeparator; 939 | p_fold1 = fold1; 940 | p_fold2 = fold2; 941 | p_valu1 = valu1; 942 | p_valu2 = valu2; 943 | } 944 | 945 | if (digit < rotSep) 946 | 947 | /* use next box */ 948 | { 949 | if (!p_separator) return 0; /* no next point */ 950 | separator = p_separator; 951 | firstSeparator = p_firstSeparator; 952 | y = p_y; 953 | cornerdiff = p_cornerdiff; 954 | reflection = p_reflection; 955 | fold1 = p_fold1; 956 | fold2 = p_fold2; 957 | valu1 = p_valu1; 958 | valu2 = p_valu2; 959 | } 960 | 961 | if (cornerdiff) 962 | { 963 | /* reduce currbox */ 964 | bitmask_t corner = diff & cornerdiff; 965 | cornerdiff ^= corner; 966 | fold1 |= corner; 967 | fold2 |= cornerdiff; 968 | valu1 |= ~reflection & corner; 969 | valu2 |= ~reflection & cornerdiff; 970 | } 971 | 972 | separator ^= firstSeparator; 973 | if (firstSeparator) 974 | /* we have completely separated the point from a part of the box 975 | ahead of it on the curve; almost done */ 976 | { 977 | unsigned byteId = whichByte(nBytes,y); 978 | bitmask_t bthbit = one << y%8; 979 | for (d = 0; d < nDims; ++d) 980 | { 981 | char lo1, lo2; 982 | char* cc1 = &c1[d*nBytes]; 983 | char* cc2 = &c2[d*nBytes]; 984 | char const* pnt = &pt[d*nBytes]; 985 | char hibits = -bthbit; 986 | char hipart = pnt[byteId] & hibits; 987 | memcpy(cc1, pnt, byteId); 988 | memcpy(cc2, pnt, byteId); 989 | 990 | if (rdbit(separator, d)) 991 | hibits ^= bthbit; 992 | if (rdbit(firstSeparator, d)) 993 | hipart ^= bthbit; 994 | 995 | if (rdbit(fold1, d)) 996 | { 997 | lo1 = -rdbit(valu1, d); 998 | setBytes(cc1,byteId,nBytes,lo1); 999 | } 1000 | else lo1 = cc1[byteId]; 1001 | cc1[byteId] = hipart | (lo1 &~ hibits); 1002 | 1003 | if (rdbit(fold2, d)) 1004 | { 1005 | lo2 = -rdbit(valu2, d); 1006 | setBytes(cc2,byteId,nBytes,lo2); 1007 | } 1008 | else lo2 = cc2[byteId]; 1009 | cc2[byteId] = hipart | (lo2 &~ hibits); 1010 | } 1011 | 1012 | hilbert_box_pt(nDims, nBytes, nBits, !findPrev, c1V, c2V); 1013 | return 1; 1014 | } 1015 | } 1016 | 1017 | bits ^= reflection; 1018 | bits = rotateRight(bits, rotation, nDims); 1019 | index ^= bits; 1020 | reflection ^= one << rotation; 1021 | adjust_rotation(rotation,nDims,bits); 1022 | bits = reflection; 1023 | } 1024 | 1025 | /* point is in box */ 1026 | { 1027 | unsigned d; 1028 | for (d = 0; d < nDims; ++d) 1029 | ((char*)c1)[d] = ((char*)c2)[d] = ((char*)pt)[d]; 1030 | } 1031 | return 1; 1032 | } 1033 | 1034 | 1035 | 1036 | /***************************************************************** 1037 | * hilbert_incr 1038 | * 1039 | * Advance from one point to its successor on a Hilbert curve 1040 | * Inputs: 1041 | * nDims: Number of coordinates. 1042 | * nBits: Number of bits/coordinate. 1043 | * coord: Array of nDims nBits-bit coordinates. 1044 | * Output: 1045 | * coord: Next point on Hilbert curve 1046 | * Assumptions: 1047 | * nBits <= (sizeof bitmask_t) * (bits_per_byte) 1048 | */ 1049 | 1050 | void 1051 | hilbert_incr(unsigned nDims, unsigned nBits, bitmask_t coord[]) 1052 | { 1053 | bitmask_t const one = 1; 1054 | bitmask_t const ndOnes = ones(bitmask_t,nDims); 1055 | bitmask_t const nd1Ones= ndOnes >> 1; 1056 | unsigned b, d; 1057 | unsigned rotation = 0; 1058 | bitmask_t reflection = 0; 1059 | bitmask_t index = 0; 1060 | unsigned rb = nBits-1; 1061 | bitmask_t rd = ndOnes; 1062 | 1063 | for (b = nBits; b--;) 1064 | { 1065 | bitmask_t bits = reflection; 1066 | reflection = 0; 1067 | for (d = 0; d < nDims; ++d) 1068 | reflection |= rdbit(coord[d], b) << d; 1069 | bits ^= reflection; 1070 | bits = rotateRight(bits, rotation, nDims); 1071 | index ^= bits; 1072 | for (d = 1; d < nDims; d *= 2) 1073 | index ^= index >> d; 1074 | if (index++ != ndOnes) 1075 | { 1076 | rb = b; 1077 | rd = index & -index; 1078 | rd = rotateLeft(rd, rotation, nDims); 1079 | 1080 | } 1081 | index &= 1; 1082 | index <<= nDims-1; 1083 | 1084 | reflection ^= one << rotation; 1085 | adjust_rotation(rotation,nDims,bits); 1086 | } 1087 | for (d = 0; !rdbit(rd, d); ++d) {} 1088 | coord[d] ^= (2 << rb) - 1; 1089 | } 1090 | 1091 | 1092 | /* LICENSE 1093 | * 1094 | * This software is copyrighted by Rice University. It may be freely copied, 1095 | * modified, and redistributed, provided that the copyright notice is 1096 | * preserved on all copies. 1097 | * 1098 | * There is no warranty or other guarantee of fitness for this software, 1099 | * it is provided solely "as is". Bug reports or fixes may be sent 1100 | * to the author, who may or may not act on them as he desires. 1101 | * 1102 | * You may include this software in a program or other software product, 1103 | * but must display the notice: 1104 | * 1105 | * Hilbert Curve implementation copyright 1998, Rice University 1106 | * 1107 | * in any place where the end-user would see your own copyright. 1108 | * 1109 | * If you modify this software, you should include a notice giving the 1110 | * name of the person performing the modification, the date of modification, 1111 | * and the reason for such modification. 1112 | */ 1113 | 1114 | 1115 | 1116 | /* Revision history: 1117 | 1118 | July 1998: Initial release 1119 | 1120 | Sept 1998: Second release 1121 | 1122 | Dec 1998: Fixed bug in hilbert_c2i that allowed a shift by number of bits in 1123 | bitmask to vaporize index, in last bit of the function. Implemented 1124 | hilbert_incr. 1125 | 1126 | August 1999: Added argument to hilbert_nextinbox so that you can, optionally, 1127 | find the previous point along the curve to intersect the box, rather than the 1128 | next point. 1129 | 1130 | Nov 1999: Defined fast bit-transpose function (fast, at least, if the number 1131 | of bits is large), and reimplemented i2c and c2i in terms of it. Collapsed 1132 | loops in hilbert_cmp, with the intention of reusing the cmp code to compare 1133 | more general bitstreams. 1134 | 1135 | Feb 2000: Implemented almost all the floating point versions of cmp, etc, so 1136 | that coordinates expressed in terms of double-precision IEEE floating point 1137 | can be ordered. Still have to do next-in-box, though. 1138 | 1139 | Oct 2001: Learned that some arbitrary coding choices caused some routines 1140 | to fail in one dimension, and changed those choices. 1141 | 1142 | version 2001-10-20-05:34 1143 | 1144 | */ 1145 | 1146 | /* What remains is test code that won't be compiled unless you define the 1147 | TEST_HILBERT preprocessor symbol */ 1148 | 1149 | #ifdef TEST_HILBERT 1150 | #include 1151 | #define abs(x) (((x)>=0)?(x):(-(x))) 1152 | 1153 | int main() 1154 | { 1155 | #define maxDim (8*sizeof(bitmask_t)) 1156 | bitmask_t coord[maxDim], coordPrev[maxDim]; 1157 | unsigned nDims, nBits, nPrints, orderCheck, i; 1158 | bitmask_t r, r1; 1159 | 1160 | for (;;) 1161 | { 1162 | printf( "Enter nDims, nBits, nPrints, orderCheck: " ); 1163 | scanf( "%d", &nDims); 1164 | if ( nDims == 0 ) 1165 | break; 1166 | scanf( "%d%d%d", &nBits, &nPrints, &orderCheck); 1167 | while ( (i = getchar()) != '\n' && i != EOF ) 1168 | ; 1169 | if ( i == EOF ) 1170 | break; 1171 | 1172 | if (nDims*nBits > 8*sizeof(r)) 1173 | { 1174 | printf("Product of nDims and nBits not exceed %d.\n", 8*sizeof(r)); 1175 | break; 1176 | } 1177 | 1178 | if (nBits == 0) 1179 | { 1180 | printf("nBits must be positive.\n"); 1181 | break; 1182 | } 1183 | 1184 | if (nPrints > (1ULL << (nDims*nBits))) 1185 | nPrints = 1ULL << (nDims*nBits); 1186 | 1187 | for (r = 0; r < nPrints; ++r) 1188 | { 1189 | bitmask_t coord1[maxDim]; 1190 | int miscount = 0; 1191 | hilbert_i2c( nDims, nBits, r, coord ); 1192 | printf("%d: ", (unsigned)r); 1193 | for (i = 0; i < nDims; ++i) 1194 | { 1195 | int diff = (int)(coord[i] - coordPrev[i]); 1196 | miscount += abs(diff); 1197 | coordPrev[i] = coord[i]; 1198 | printf(" %d", (unsigned)coord[i]); 1199 | } 1200 | if (r > 0 && miscount != 1) 1201 | printf(".....error"); 1202 | printf("\n"); 1203 | r1 = hilbert_c2i( nDims, nBits, coord ); 1204 | if ( r != r1 ) 1205 | printf( "r = 0x%x; r1 = 0x%x\n", (unsigned)r, (unsigned)r1); 1206 | for (i = 0; i < nDims; ++i) 1207 | coord[i] = coordPrev[i]; 1208 | 1209 | if (! orderCheck) 1210 | continue; 1211 | 1212 | for (r1 = 0; r1 < r; ++r1 ) 1213 | { 1214 | unsigned ans; 1215 | hilbert_i2c( nDims, nBits, r1, coord1 ); 1216 | ans = hilbert_cmp( nDims, sizeof(coord[0]), nBits, coord, coord1); 1217 | if (ans != 1) 1218 | { 1219 | int width = (nDims*nBits + 3) / 4; 1220 | printf( "cmp r = 0x%0*x; r1 = 0x%0*x, ans = %2d\n", 1221 | width, (unsigned)r, 1222 | width, (unsigned)r1, ans ); 1223 | } 1224 | } 1225 | hilbert_i2c( nDims, nBits, r1, coord1 ); 1226 | if (hilbert_cmp( nDims, sizeof(coord[0]), nBits, coord, coord1) != 0) 1227 | printf( "cmp r = 0x%0*x; r1 = 0x%0*x\n", (nDims*nBits+3)/4, (unsigned)r, 1228 | (nDims*nBits+3)/4, (unsigned)r1 ); 1229 | 1230 | } 1231 | } 1232 | return 0; 1233 | } 1234 | 1235 | #endif 1236 | 1237 | #ifdef TEST_IEEE 1238 | #include 1239 | #include 1240 | #include 1241 | 1242 | int cmp(const void* xv, const void* yv) 1243 | { 1244 | double const* x = xv; 1245 | double const* y = yv; 1246 | /* return hilbert_cmp(2, 8, 64, x, y); */ 1247 | return hilbert_ieee_cmp(2, x, y); 1248 | } 1249 | 1250 | int main() 1251 | { 1252 | double *a; 1253 | unsigned i; 1254 | unsigned n; 1255 | printf("How many points? "); 1256 | scanf("%d", &n); 1257 | a = (double*) malloc(2*n*sizeof(double)); 1258 | for (i = 0; i < n; ++i) 1259 | a[2*i] = drand48()-0.5, a[2*i+1] = drand48()-0.5; 1260 | 1261 | qsort(a, n, 2*sizeof(double), cmp); 1262 | 1263 | for (i = 0; i < n; ++i) 1264 | printf("%8g %8g\n", a[2*i], a[2*i+1]); 1265 | free(a); 1266 | return 0; 1267 | } 1268 | 1269 | #endif 1270 | 1271 | #ifdef TEST_CMP 1272 | #include 1273 | 1274 | #define maxDim (8*sizeof(bitmask_t)) 1275 | int main() 1276 | { 1277 | double coord[maxDim]; 1278 | unsigned nDims, i, k; 1279 | 1280 | printf( "Enter nDims: " ); 1281 | scanf( "%d", &nDims); 1282 | if ( nDims == 0 ) 1283 | return 0; 1284 | while ( (i = getchar()) != '\n' && i != EOF ) 1285 | ; 1286 | if ( i == EOF ) 1287 | return 0; 1288 | 1289 | for (k = 0; k < (1<>i)&1)? -1.: 1.; 1294 | 1295 | 1296 | hilbert_ieee_cmp( nDims, coord, coord); 1297 | } 1298 | return 0; 1299 | } 1300 | 1301 | #endif 1302 | 1303 | #ifdef TEST_VTX 1304 | #include 1305 | #include 1306 | 1307 | #define maxDim (8*sizeof(bitmask_t)) 1308 | 1309 | unsigned g_nDims; 1310 | 1311 | int cmp(void const* c1p, void const* c2p) 1312 | { 1313 | return hilbert_cmp(g_nDims, sizeof(unsigned), 8*sizeof(unsigned), c1p, c2p); 1314 | } 1315 | 1316 | int main() 1317 | { 1318 | unsigned corner0[maxDim], corner1[maxDim]; 1319 | unsigned cornerlo[maxDim], cornerhi[maxDim], work[maxDim]; 1320 | typedef unsigned array_t[maxDim]; 1321 | array_t* array; 1322 | 1323 | unsigned nDims, i, k; 1324 | 1325 | printf( "Enter nDims: " ); 1326 | scanf( "%d", &nDims); 1327 | if ( nDims == 0 ) 1328 | return 0; 1329 | while ( (i = getchar()) != '\n' && i != EOF ) 1330 | ; 1331 | if ( i == EOF ) 1332 | return 0; 1333 | 1334 | printf("Enter one corner (%d coordinates): ", nDims); 1335 | for (k = 0; k < nDims; ++k) 1336 | scanf("%d", &corner0[k]); 1337 | 1338 | printf("Enter other corner (%d coordinates): ", nDims); 1339 | for (k = 0; k < nDims; ++k) 1340 | scanf("%d", &corner1[k]); 1341 | 1342 | 1343 | /* find first corner */ 1344 | for (k = 0; k < nDims; ++k) 1345 | { 1346 | cornerlo[k] = corner0[k]; 1347 | work[k] = corner1[k]; 1348 | } 1349 | 1350 | hilbert_box_vtx(nDims, sizeof(unsigned), 8*sizeof(unsigned), 1351 | 1, cornerlo, work); 1352 | printf("Predicted lo corner: "); 1353 | for (k = 0; k < nDims; ++k) 1354 | printf("%4u", cornerlo[k]); 1355 | printf("\n"); 1356 | 1357 | 1358 | /* find last corner */ 1359 | for (k = 0; k < nDims; ++k) 1360 | { 1361 | work[k] = corner0[k]; 1362 | cornerhi[k] = corner1[k]; 1363 | } 1364 | 1365 | hilbert_box_vtx(nDims, sizeof(unsigned), 8*sizeof(unsigned), 1366 | 0, work, cornerhi); 1367 | printf("Predicted hi corner: "); 1368 | for (k = 0; k < nDims; ++k) 1369 | printf("%4u", cornerhi[k]); 1370 | printf("\n"); 1371 | 1372 | array = (array_t*) malloc(maxDim*sizeof(unsigned) << nDims); 1373 | for (k = 0; k < (1<>j)&1)? corner1: corner0; 1380 | eltk[j] = src[j]; 1381 | } 1382 | } 1383 | 1384 | g_nDims = nDims; 1385 | qsort(array, (1< 1404 | #include 1405 | #include 1406 | 1407 | #define maxDim (8*sizeof(bitmask_t)) 1408 | typedef double key_t; 1409 | 1410 | unsigned g_nDims; 1411 | 1412 | int cmp(void const* c1p, void const* c2p) 1413 | { 1414 | return hilbert_ieee_cmp(g_nDims, c1p, c2p); 1415 | } 1416 | 1417 | int main() 1418 | { 1419 | key_t corner0[maxDim], corner1[maxDim]; 1420 | key_t cornerlo[maxDim], cornerhi[maxDim], work[maxDim]; 1421 | typedef key_t array_t[maxDim]; 1422 | array_t* array; 1423 | 1424 | unsigned nDims, i, k; 1425 | 1426 | printf( "Enter nDims: " ); 1427 | scanf( "%d", &nDims); 1428 | if ( nDims == 0 ) 1429 | return 0; 1430 | 1431 | for (i = 0; i < 10000; ++i) 1432 | { 1433 | for (k = 0; k < nDims; ++k) 1434 | { 1435 | corner0[k] = 2.*drand48() - 1.; 1436 | corner1[k] = 2.*drand48() - 1.; 1437 | } 1438 | 1439 | /* find first corner */ 1440 | for (k = 0; k < nDims; ++k) 1441 | { 1442 | cornerlo[k] = corner0[k]; 1443 | work[k] = corner1[k]; 1444 | } 1445 | 1446 | hilbert_ieee_box_vtx(nDims, 1, cornerlo, work); 1447 | 1448 | /* find last corner */ 1449 | for (k = 0; k < nDims; ++k) 1450 | { 1451 | work[k] = corner0[k]; 1452 | cornerhi[k] = corner1[k]; 1453 | } 1454 | 1455 | hilbert_ieee_box_vtx(nDims, 0, work, cornerhi); 1456 | 1457 | array = (array_t*) malloc(maxDim*sizeof(key_t) << nDims); 1458 | for (k = 0; k < (1<>j)&1)? corner1: corner0; 1465 | eltk[j] = src[j]; 1466 | } 1467 | } 1468 | 1469 | g_nDims = nDims; 1470 | qsort(array, (1< 1492 | #include 1493 | 1494 | #define maxDim (8*sizeof(bitmask_t)) 1495 | 1496 | unsigned g_nDims; 1497 | 1498 | int cmp(void const* c1p, void const* c2p) 1499 | { 1500 | return hilbert_cmp(g_nDims, sizeof(unsigned), 8*sizeof(unsigned), c1p, c2p); 1501 | } 1502 | 1503 | int main() 1504 | { 1505 | unsigned point0[maxDim], point1[maxDim]; 1506 | unsigned pointlo[maxDim], pointhi[maxDim], work[maxDim]; 1507 | typedef unsigned array_t[maxDim]; 1508 | array_t* array; 1509 | 1510 | unsigned nDims, i, k, outvolume = 1, involume = 1; 1511 | unsigned nextItem; 1512 | 1513 | printf( "Enter nDims: " ); 1514 | scanf( "%d", &nDims); 1515 | if ( nDims == 0 ) 1516 | return 0; 1517 | while ( (i = getchar()) != '\n' && i != EOF ) 1518 | ; 1519 | if ( i == EOF ) 1520 | return 0; 1521 | 1522 | printf("Enter one point (%d coordinates): ", nDims); 1523 | for (k = 0; k < nDims; ++k) 1524 | scanf("%d", &point0[k]); 1525 | 1526 | printf("Enter other point (%d coordinates, strictly greater): ", nDims); 1527 | for (k = 0; k < nDims; ++k) 1528 | { 1529 | unsigned diff; 1530 | scanf("%d", &point1[k]); 1531 | diff = point1[k] - point0[k]; 1532 | outvolume *= diff + 1; 1533 | involume *= diff - 1; 1534 | } 1535 | 1536 | 1537 | /* find first point */ 1538 | for (k = 0; k < nDims; ++k) 1539 | { 1540 | pointlo[k] = point0[k]; 1541 | work[k] = point1[k]; 1542 | } 1543 | 1544 | hilbert_box_pt(nDims, sizeof(unsigned), 8*sizeof(unsigned), 1545 | 1, pointlo, work); 1546 | printf("Predicted lo point: "); 1547 | for (k = 0; k < nDims; ++k) 1548 | printf("%4u", pointlo[k]); 1549 | printf("\n"); 1550 | 1551 | 1552 | /* find last point */ 1553 | for (k = 0; k < nDims; ++k) 1554 | { 1555 | work[k] = point0[k]; 1556 | pointhi[k] = point1[k]; 1557 | } 1558 | 1559 | hilbert_box_pt(nDims, sizeof(unsigned), 8*sizeof(unsigned), 1560 | 0, work, pointhi); 1561 | printf("Predicted hi point: "); 1562 | for (k = 0; k < nDims; ++k) 1563 | printf("%4u", pointhi[k]); 1564 | printf("\n"); 1565 | 1566 | 1567 | 1568 | array = (array_t*) malloc(maxDim*sizeof(unsigned) * (outvolume-involume)); 1569 | if (array == 0) 1570 | { 1571 | fprintf(stderr, "Out of memory.\n"); 1572 | exit(-1); 1573 | } 1574 | nextItem = 0; 1575 | for (k = 0; k < outvolume; ++k) 1576 | { 1577 | unsigned kk = k; 1578 | unsigned j; 1579 | unsigned* eltk = &array[nextItem][0]; 1580 | int boundary = 0; 1581 | 1582 | for (j = 0; j < nDims; ++j) 1583 | { 1584 | unsigned diff1 = point1[j] - point0[j] + 1; 1585 | unsigned pos = point0[j] + (kk % diff1); 1586 | boundary |= (point0[j] == pos || pos == point1[j]); 1587 | eltk[j] = pos; 1588 | kk /= diff1; 1589 | } 1590 | if (boundary) 1591 | ++nextItem; 1592 | } 1593 | 1594 | g_nDims = nDims; 1595 | qsort(array, outvolume-involume, maxDim*sizeof(unsigned), cmp); 1596 | 1597 | printf("Result of sort\n"); 1598 | for (k = 0; k < outvolume-involume; k += outvolume-involume-1) 1599 | { 1600 | unsigned j; 1601 | unsigned* eltk = &array[k][0]; 1602 | for (j = 0; j < nDims; ++j) 1603 | printf("%4u", eltk[j]); 1604 | printf("\n"); 1605 | } 1606 | free((char*)array); 1607 | return 0; 1608 | } 1609 | 1610 | #endif 1611 | 1612 | #ifdef TEST_IEEE_PT 1613 | #include 1614 | #include 1615 | 1616 | #define maxDim (8*sizeof(bitmask_t)) 1617 | 1618 | int main() 1619 | { 1620 | double point0[maxDim], point1[maxDim]; 1621 | double pointlo[maxDim], pointhi[maxDim], work[maxDim]; 1622 | 1623 | unsigned nDims, k, i; 1624 | 1625 | printf( "Enter nDims: " ); 1626 | scanf( "%d", &nDims); 1627 | if ( nDims == 0 ) 1628 | return 0; 1629 | while ( (i = getchar()) != '\n' && i != EOF ) 1630 | ; 1631 | if ( i == EOF ) 1632 | return 0; 1633 | 1634 | printf("Enter one point (%d coordinates): ", nDims); 1635 | for (k = 0; k < nDims; ++k) 1636 | scanf("%lf", &point0[k]); 1637 | 1638 | printf("Enter other point (%d coordinates, strictly greater): ", nDims); 1639 | for (k = 0; k < nDims; ++k) 1640 | scanf("%lf", &point1[k]); 1641 | 1642 | /* find last point */ 1643 | for (k = 0; k < nDims; ++k) 1644 | { 1645 | work[k] = point0[k]; 1646 | pointhi[k] = point1[k]; 1647 | } 1648 | 1649 | hilbert_ieee_box_pt(nDims, 0, work, pointhi); 1650 | printf("Predicted hi point: "); 1651 | for (k = 0; k < nDims; ++k) 1652 | printf("%10lg", pointhi[k]); 1653 | printf("\n"); 1654 | 1655 | /* find first point */ 1656 | for (k = 0; k < nDims; ++k) 1657 | { 1658 | pointlo[k] = point0[k]; 1659 | work[k] = point1[k]; 1660 | } 1661 | 1662 | hilbert_ieee_box_pt(nDims, 1, pointlo, work); 1663 | printf("Predicted lo point: "); 1664 | for (k = 0; k < nDims; ++k) 1665 | printf("%10lg", pointlo[k]); 1666 | printf("\n"); 1667 | 1668 | /* validate by sorting random boundary points */ 1669 | #define nPts 1000000 1670 | assert(hilbert_ieee_cmp(nDims, pointlo, pointhi) < 0); 1671 | for (i = 0; i < nPts; ++i) 1672 | { 1673 | double pt1[maxDim], pt2[maxDim]; 1674 | for (k = 0; k < nDims; ++k) 1675 | { 1676 | if (i % nDims == k) 1677 | pt1[k] = point0[k]; 1678 | else 1679 | pt1[k] = point0[k] + drand48()*(point1[k]-point0[k]); 1680 | } 1681 | for (k = 0; k < nDims; ++k) 1682 | { 1683 | if (i % nDims == k) 1684 | pt2[k] = point1[k]; 1685 | else 1686 | pt2[k] = point0[k] + drand48()*(point1[k]-point0[k]); 1687 | } 1688 | if (hilbert_ieee_cmp(nDims, pt1, pt2) < 0) 1689 | { 1690 | if (hilbert_ieee_cmp(nDims, pt1, pointlo) < 0) 1691 | memcpy(pointlo, pt1, maxDim*sizeof(double)); 1692 | if (hilbert_ieee_cmp(nDims, pointhi, pt2) < 0) 1693 | memcpy(pointhi, pt2, maxDim*sizeof(double)); 1694 | } 1695 | else 1696 | { 1697 | if (hilbert_ieee_cmp(nDims, pt2, pointlo) < 0) 1698 | memcpy(pointlo, pt2, maxDim*sizeof(double)); 1699 | if (hilbert_ieee_cmp(nDims, pointhi, pt1) < 0) 1700 | memcpy(pointhi, pt1, maxDim*sizeof(double)); 1701 | } 1702 | } 1703 | 1704 | printf("Sorted hi and lo:\n"); 1705 | for (k = 0; k < nDims; ++k) 1706 | printf("%10lg", pointhi[k]); 1707 | printf("\n"); 1708 | for (k = 0; k < nDims; ++k) 1709 | printf("%10lg", pointlo[k]); 1710 | printf("\n"); 1711 | 1712 | return 0; 1713 | } 1714 | 1715 | #endif 1716 | 1717 | #ifdef TEST_NEXT 1718 | #include 1719 | 1720 | int main() 1721 | { 1722 | unsigned i; 1723 | unsigned c1[100], c2[100], pt[100]; 1724 | unsigned nDims, nBytes = 4; 1725 | int stat, findPrev; 1726 | printf("Enter nDims: " ); 1727 | scanf("%u", &nDims); 1728 | 1729 | printf("Enter 1st box corner: "); 1730 | for (i = 0; i < nDims; ++i) 1731 | scanf("%u", &c1[i]); 1732 | printf("Enter 2nd box corner: "); 1733 | for (i = 0; i < nDims; ++i) 1734 | scanf("%u", &c2[i]); 1735 | printf("Enter point: "); 1736 | for (i = 0; i < nDims; ++i) 1737 | scanf("%u", &pt[i]); 1738 | printf("Find prev?: "); 1739 | scanf("%d", &findPrev); 1740 | 1741 | stat = hilbert_nextinbox(nDims, nBytes, 8*nBytes, findPrev, c1, c2, pt); 1742 | 1743 | if (stat) 1744 | for (i = 0; i < nDims; ++i) 1745 | printf("%u ", c1[i]); 1746 | else 1747 | printf("No such point"); 1748 | 1749 | printf("\n"); 1750 | return 0; 1751 | } 1752 | #endif 1753 | --------------------------------------------------------------------------------