ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
hashmap.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "core/hashmap/HashMap.h"
9 
10 #include <Logging.h>
11 
12 #include "core/MemoryManager.h"
13 #include "core/Tensor.h"
14 #include "core/hashmap/HashSet.h"
16 #include "pybind/core/core.h"
18 #include "pybind/docstring.h"
19 
20 namespace cloudViewer {
21 namespace core {
22 const std::unordered_map<std::string, std::string> argument_docs = {
23  {"init_capacity", "Initial capacity of a hash container."},
24  {"key_dtype", "Data type for the input key tensor."},
25  {"key_element_shape",
26  "Element shape for the input key tensor. E.g. (3) for 3D "
27  "coordinate keys."},
28  {"value_dtype", "Data type for the input value tensor."},
29  {"value_dtypes", "List of data type for the input value tensors."},
30  {"value_element_shape",
31  "Element shape for the input value tensor. E.g. (1) for mapped "
32  "index."},
33  {"value_element_shapes",
34  "List of element shapes for the input value tensors. E.g. ((8,8,8,1), "
35  "(8,8,8,3)) for "
36  "mapped weights and RGB colors stored in 8^3 element arrays."},
37  {"device",
38  "Compute device to store and operate on the hash container."},
39  {"copy",
40  "If true, a new tensor is always created; if false, the copy is "
41  "avoided when the original tensor already has the targeted dtype."},
42  {"keys",
43  "Input keys stored in a tensor of shape (N, key_element_shape)."},
44  {"values",
45  "Input values stored in a tensor of shape (N, value_element_shape)."},
46  {"list_values",
47  "List of input values stored in tensors of corresponding shapes."},
48  {"capacity", "New capacity for rehashing."},
49  {"file_name", "File name of the corresponding .npz file."},
50  {"values_buffer_id", "Index of the value buffer tensor."},
51  {"device_id", "Target CUDA device ID."}};
52 
53 void pybind_core_hashmap(py::module& m) {
54  // Expose backend enum so Python users can select implementations
55  py::native_enum<HashBackendType>(m, "HashBackendType", "enum.Enum")
56  .value("Slab", HashBackendType::Slab)
57  .value("StdGPU", HashBackendType::StdGPU)
58  .value("TBB", HashBackendType::TBB)
59  .value("Default", HashBackendType::Default)
60  .finalize();
61 
62  py::class_<HashMap> hashmap(
63  m, "HashMap",
64  "A HashMap is a map from key to data wrapped by Tensors.");
65 
66  hashmap.def(py::init<int64_t, const Dtype&, const SizeVector&, const Dtype&,
67  const SizeVector&, const Device&>(),
68  "init_capacity"_a, "key_dtype"_a, "key_element_shape"_a,
69  "value_dtype"_a, "value_element_shape"_a,
70  "device"_a = Device("CPU:0"));
71  hashmap.def(py::init<int64_t, const Dtype&, const SizeVector&,
72  const std::vector<Dtype>&,
73  const std::vector<SizeVector>&, const Device&>(),
74  "init_capacity"_a, "key_dtype"_a, "key_element_shape"_a,
75  "value_dtypes"_a, "value_element_shapes"_a,
76  "device"_a = Device("CPU:0"));
77  docstring::ClassMethodDocInject(m, "HashMap", "__init__", argument_docs);
78 
79  hashmap.def(
80  "insert",
81  [](HashMap& h, const Tensor& keys, const Tensor& values) {
82  Tensor buf_indices, masks;
83  h.Insert(keys, values, buf_indices, masks);
84  return py::make_tuple(buf_indices, masks);
85  },
86  "Insert an array of keys and an array of values stored in Tensors.",
87  "keys"_a, "values"_a);
88  hashmap.def(
89  "insert",
90  [](HashMap& h, const Tensor& keys,
91  const std::vector<Tensor>& values) {
92  Tensor buf_indices, masks;
93  h.Insert(keys, values, buf_indices, masks);
94  return py::make_tuple(buf_indices, masks);
95  },
96  "Insert an array of keys and a list of value arrays stored in "
97  "Tensors.",
98  "keys"_a, "list_values"_a);
99  docstring::ClassMethodDocInject(m, "HashMap", "insert", argument_docs);
100 
101  hashmap.def(
102  "activate",
103  [](HashMap& h, const Tensor& keys) {
104  Tensor buf_indices, masks;
105  h.Activate(keys, buf_indices, masks);
106  return py::make_tuple(buf_indices, masks);
107  },
108  "Activate an array of keys stored in Tensors without copying "
109  "values.",
110  "keys"_a);
111  docstring::ClassMethodDocInject(m, "HashMap", "activate", argument_docs);
112 
113  hashmap.def(
114  "find",
115  [](HashMap& h, const Tensor& keys) {
116  Tensor buf_indices, masks;
117  h.Find(keys, buf_indices, masks);
118  return py::make_tuple(buf_indices, masks);
119  },
120  "Find an array of keys stored in Tensors.", "keys"_a);
121  docstring::ClassMethodDocInject(m, "HashMap", "find", argument_docs);
122 
123  hashmap.def(
124  "erase",
125  [](HashMap& h, const Tensor& keys) {
126  Tensor masks;
127  h.Erase(keys, masks);
128  return masks;
129  },
130  "Erase an array of keys stored in Tensors.", "keys"_a);
131  docstring::ClassMethodDocInject(m, "HashMap", "erase", argument_docs);
132 
133  hashmap.def(
134  "active_buf_indices",
135  [](HashMap& h) {
136  Tensor buf_indices;
137  h.GetActiveIndices(buf_indices);
138  return buf_indices;
139  },
140  "Get the buffer indices corresponding to active entries in the "
141  "hash map.");
142 
143  hashmap.def("save", &HashMap::Save, "Save the hash map into a .npz file.",
144  "file_name"_a);
145  docstring::ClassMethodDocInject(m, "HashMap", "save", argument_docs);
146 
147  hashmap.def_static("load", &HashMap::Load,
148  "Load a hash map from a .npz file.", "file_name"_a);
149  docstring::ClassMethodDocInject(m, "HashMap", "load", argument_docs);
150 
151  hashmap.def("reserve", &HashMap::Reserve,
152  "Reserve the hash map given the capacity.", "capacity"_a);
153  docstring::ClassMethodDocInject(m, "HashMap", "reserve", argument_docs);
154 
155  hashmap.def("key_tensor", &HashMap::GetKeyTensor,
156  "Get the key tensor stored in the buffer.");
157  hashmap.def("value_tensors", &HashMap::GetValueTensors,
158  "Get the list of value tensors stored in the buffer.");
159  hashmap.def(
160  "value_tensor", [](HashMap& h) { return h.GetValueTensor(); },
161  "Get the value tensor stored at index 0.");
162  hashmap.def(
163  "value_tensor",
164  [](HashMap& h, size_t i) { return h.GetValueTensor(i); },
165  "Get the value tensor stored at index i", "value_buffer_id"_a);
166  docstring::ClassMethodDocInject(m, "HashMap", "value_tensor",
167  argument_docs);
168 
169  hashmap.def("size", &HashMap::Size, "Get the size of the hash map.");
170  hashmap.def("capacity", &HashMap::GetCapacity,
171  "Get the capacity of the hash map.");
172 
173  hashmap.def("clone", &HashMap::Clone,
174  "Clone the hash map, including the data structure and the data "
175  "buffers.");
176  hashmap.def("to", &HashMap::To,
177  "Convert the hash map to a selected device.", "device"_a,
178  "copy"_a = false);
179  docstring::ClassMethodDocInject(m, "HashMap", "to", argument_docs);
180 
181  hashmap.def(
182  "cpu",
183  [](const HashMap& hashmap) {
184  return hashmap.To(core::Device("CPU:0"));
185  },
186  "Transfer the hash map to CPU. If the hash map "
187  "is already on CPU, no copy will be performed.");
188  hashmap.def(
189  "cuda",
190  [](const HashMap& hashmap, int device_id) {
191  return hashmap.To(core::Device("CUDA", device_id));
192  },
193  "Transfer the hash map to a CUDA device. If the hash map is "
194  "already "
195  "on the specified CUDA device, no copy will be performed.",
196  "device_id"_a = 0);
197  docstring::ClassMethodDocInject(m, "HashMap", "cuda", argument_docs);
198 
199  hashmap.def_property_readonly("device", &HashMap::GetDevice);
200  hashmap.def_property_readonly("is_cpu", &HashMap::IsCPU);
201  hashmap.def_property_readonly("is_cuda", &HashMap::IsCUDA);
202 }
203 
204 void pybind_core_hashset(py::module& m) {
205  py::class_<HashSet> hashset(
206  m, "HashSet",
207  "A HashSet is an unordered set of keys wrapped by Tensors.");
208  hashset.def(
209  py::init<int64_t, const Dtype&, const SizeVector&, const Device&>(),
210  "init_capacity"_a, "key_dtype"_a, "key_element_shape"_a,
211  "device"_a = Device("CPU:0"));
212  docstring::ClassMethodDocInject(m, "HashSet", "__init__", argument_docs);
213 
214  hashset.def(
215  "insert",
216  [](HashSet& h, const Tensor& keys) {
217  Tensor buf_indices, masks;
218  h.Insert(keys, buf_indices, masks);
219  return py::make_tuple(buf_indices, masks);
220  },
221  "Insert an array of keys stored in Tensors.", "keys"_a);
222  docstring::ClassMethodDocInject(m, "HashSet", "insert", argument_docs);
223 
224  hashset.def(
225  "find",
226  [](HashSet& h, const Tensor& keys) {
227  Tensor buf_indices, masks;
228  h.Find(keys, buf_indices, masks);
229  return py::make_tuple(buf_indices, masks);
230  },
231  "Find an array of keys stored in Tensors.", "keys"_a);
232  docstring::ClassMethodDocInject(m, "HashSet", "find", argument_docs);
233 
234  hashset.def(
235  "erase",
236  [](HashSet& h, const Tensor& keys) {
237  Tensor masks;
238  h.Erase(keys, masks);
239  return masks;
240  },
241  "Erase an array of keys stored in Tensors.", "keys"_a);
242  docstring::ClassMethodDocInject(m, "HashSet", "erase", argument_docs);
243 
244  hashset.def(
245  "active_buf_indices",
246  [](HashSet& h) {
247  Tensor buf_indices;
248  h.GetActiveIndices(buf_indices);
249  return buf_indices;
250  },
251  "Get the buffer indices corresponding to active entries in the "
252  "hash set.");
253 
254  hashset.def("save", &HashSet::Save, "Save the hash set into a .npz file.",
255  "file_name"_a);
256  docstring::ClassMethodDocInject(m, "HashSet", "save", argument_docs);
257 
258  hashset.def_static("load", &HashSet::Load,
259  "Load a hash set from a .npz file.", "file_name"_a);
260  docstring::ClassMethodDocInject(m, "HashSet", "load", argument_docs);
261 
262  hashset.def("reserve", &HashSet::Reserve,
263  "Reserve the hash set given the capacity.", "capacity"_a);
264  docstring::ClassMethodDocInject(m, "HashSet", "reserve", argument_docs);
265 
266  hashset.def("key_tensor", &HashSet::GetKeyTensor,
267  "Get the key tensor stored in the buffer.");
268 
269  hashset.def("size", &HashSet::Size, "Get the size of the hash set.");
270  hashset.def("capacity", &HashSet::GetCapacity,
271  "Get the capacity of the hash set.");
272 
273  hashset.def("clone", &HashSet::Clone,
274  "Clone the hash set, including the data structure and the data "
275  "buffers.");
276  hashset.def("to", &HashSet::To,
277  "Convert the hash set to a selected device.", "device"_a,
278  "copy"_a = false);
279  docstring::ClassMethodDocInject(m, "HashSet", "to", argument_docs);
280 
281  hashset.def(
282  "cpu",
283  [](const HashSet& hashset) {
284  return hashset.To(core::Device("CPU:0"));
285  },
286  "Transfer the hash set to CPU. If the hash set "
287  "is already on CPU, no copy will be performed.");
288  hashset.def(
289  "cuda",
290  [](const HashSet& hashset, int device_id) {
291  return hashset.To(core::Device("CUDA", device_id));
292  },
293  "Transfer the hash set to a CUDA device. If the hash set is "
294  "already "
295  "on the specified CUDA device, no copy will be performed.",
296  "device_id"_a = 0);
297  docstring::ClassMethodDocInject(m, "HashSet", "cuda", argument_docs);
298 
299  hashset.def_property_readonly("device", &HashSet::GetDevice);
300  hashset.def_property_readonly("is_cpu", &HashSet::IsCPU);
301  hashset.def_property_readonly("is_cuda", &HashSet::IsCUDA);
302 }
303 
304 } // namespace core
305 } // namespace cloudViewer
std::pair< Tensor, Tensor > Activate(const Tensor &input_keys)
Definition: HashMap.cpp:94
std::pair< Tensor, Tensor > Find(const Tensor &input_keys)
Definition: HashMap.cpp:100
HashMap To(const Device &device, bool copy=false) const
Convert the hash map to another device.
Definition: HashMap.cpp:229
std::vector< Tensor > GetValueTensors() const
Definition: HashMap.cpp:275
Tensor Erase(const Tensor &input_keys)
Definition: HashMap.cpp:106
static HashMap Load(const std::string &file_name)
Definition: HashMap.cpp:223
void Save(const std::string &file_name)
Definition: HashMap.cpp:219
int64_t GetCapacity() const
Get the capacity of the hash map.
Definition: HashMap.cpp:258
std::pair< Tensor, Tensor > Insert(const Tensor &input_keys, const Tensor &input_values)
Definition: HashMap.cpp:80
void Reserve(int64_t capacity)
Reserve the internal hash map with the given capacity by rehashing.
Definition: HashMap.cpp:48
Tensor GetActiveIndices() const
Definition: HashMap.cpp:112
Tensor GetKeyTensor() const
Definition: HashMap.cpp:266
Device GetDevice() const override
Get the device of the hash map.
Definition: HashMap.cpp:264
int64_t Size() const
Get the size (number of active entries) of the hash map.
Definition: HashMap.cpp:256
Tensor GetValueTensor(size_t index=0) const
Definition: HashMap.cpp:294
HashMap Clone() const
Clone the hash map with buffers.
Definition: HashMap.cpp:227
void Save(const std::string &file_name)
Definition: HashSet.cpp:79
std::pair< Tensor, Tensor > Find(const Tensor &input_keys)
Definition: HashSet.cpp:38
int64_t Size() const
Get the size (number of active entries) of the hash set.
Definition: HashSet.cpp:98
Tensor GetKeyTensor() const
Definition: HashSet.cpp:106
static HashSet Load(const std::string &file_name)
Load active keys and values from a npz file that contains 'key'.
Definition: HashSet.cpp:83
void Reserve(int64_t capacity)
Reserve the internal hash map with the capcity by rehashing.
Definition: HashSet.cpp:30
int64_t GetCapacity() const
Get the capacity of the hash set.
Definition: HashSet.cpp:100
Tensor GetActiveIndices() const
Definition: HashSet.cpp:50
std::pair< Tensor, Tensor > Insert(const Tensor &input_keys)
Definition: HashSet.cpp:32
HashSet To(const Device &device, bool copy=false) const
Convert the hash set to another device.
Definition: HashSet.cpp:93
HashSet Clone() const
Clone the hash set with buffers.
Definition: HashSet.cpp:88
Tensor Erase(const Tensor &input_keys)
Definition: HashSet.cpp:44
Device GetDevice() const override
Get the device of the hash set.
Definition: HashSet.cpp:104
bool IsCUDA() const
Definition: Device.h:99
bool IsCPU() const
Definition: Device.h:95
void pybind_core_hashmap(py::module &m)
Definition: hashmap.cpp:53
const std::unordered_map< std::string, std::string > argument_docs
Definition: hashmap.cpp:22
void pybind_core_hashset(py::module &m)
Definition: hashmap.cpp:204
void ClassMethodDocInject(py::module &pybind_module, const std::string &class_name, const std::string &function_name, const std::unordered_map< std::string, std::string > &map_parameter_body_docs)
Definition: docstring.cpp:27
Generic file read and write utility for python interface.