💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

482 lines
14 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef ANTKEEPER_GEOM_HYPEROCTREE_HPP
  20. #define ANTKEEPER_GEOM_HYPEROCTREE_HPP
  21. #include <cstdint>
  22. #include <limits>
  23. #include <type_traits>
  24. #include <unordered_set>
  25. #include <stack>
  26. namespace geom {
  27. /**
  28. * Hashed linear hyperoctree.
  29. *
  30. * @see http://codervil.blogspot.com/2015/10/octree-node-identifiers.html
  31. * @see https://geidav.wordpress.com/2014/08/18/advanced-octrees-2-node-representations/
  32. *
  33. * @tparam N Number of dimensions.
  34. * @tparam D Max depth.
  35. *
  36. * Max depth can likely be determined by a generalized formula. 2D and 3D cases are given below:
  37. *
  38. * 2D:
  39. * 8 bit ( 1 byte) = max depth 1 ( 4 loc bits, 1 depth bits, 1 divider bit) = 6 bits
  40. * 16 bit ( 2 byte) = max depth 5 ( 12 loc bits, 3 depth bits, 1 divider bit) = 16 bits
  41. * 32 bit ( 4 byte) = max depth 12 ( 26 loc bits, 4 depth bits, 1 divider bit) = 31 bits
  42. * 64 bit ( 8 byte) = max depth 28 ( 58 loc bits, 5 depth bits, 1 divider bit) = 64 bits
  43. * 128 bit (16 byte) = max depth 59 (120 loc bits, 6 depth bits, 1 divider bit) = 127 bits
  44. * 256 bit (32 byte) = max depth 123 (248 loc bits, 7 depth bits, 1 divider bit) = 256 bits
  45. *
  46. * @see https://oeis.org/A173009
  47. *
  48. * 3D:
  49. * 8 bit ( 1 byte) = max depth 1 ( 6 loc bits, 1 depth bits, 1 divider bit) = 8 bits
  50. * 16 bit ( 2 byte) = max depth 3 ( 12 loc bits, 2 depth bits, 1 divider bit) = 15 bits
  51. * 32 bit ( 4 byte) = max depth 8 ( 27 loc bits, 4 depth bits, 1 divider bit) = 32 bits
  52. * 64 bit ( 8 byte) = max depth 18 ( 57 loc bits, 5 depth bits, 1 divider bit) = 63 bits
  53. * 128 bit (16 byte) = max depth 39 (120 loc bits, 6 depth bits, 1 divider bit) = 127 bits
  54. * 256 bit (32 byte) = max depth 81 (243 loc bits, 7 depth bits, 1 divider bit) = 251 bits
  55. *
  56. * @see https://oeis.org/A178420
  57. *
  58. * @tparam T Integer node type.
  59. */
  60. template <std::size_t N, std::size_t D, class T>
  61. class hyperoctree
  62. {
  63. private:
  64. /// Compile-time calculation of the minimum bits required to represent `n` state changes.
  65. static constexpr T ceil_log2(T n);
  66. public:
  67. /// Integral node type.
  68. typedef T node_type;
  69. /// Ensure the node type is integral
  70. static_assert(std::is_integral<T>::value, "Node type must be integral.");
  71. /// Maximum node depth.
  72. static constexpr std::size_t max_depth = D;
  73. /// Number of bits required to encode the depth of a node.
  74. static constexpr T depth_bits = ceil_log2(max_depth + 1);
  75. /// Number of bits required to encode the location of a node.
  76. static constexpr T location_bits = (max_depth + 1) * N;
  77. /// Number of bits in the node type.
  78. static constexpr T node_bits = sizeof(node_type) * 8;
  79. // Ensure the node type has enough bits
  80. static_assert(depth_bits + location_bits + 1 <= node_bits, "Size of hyperoctree node type is insufficient to encode the maximum depth");
  81. /// Number of children per node.
  82. static constexpr T children_per_node = (N) ? (2 << (N - 1)) : 1;
  83. /// Number of siblings per node.
  84. static constexpr T siblings_per_node = children_per_node - 1;
  85. /// Root node which is always guaranteed to exist.
  86. static constexpr node_type root = 0;
  87. /**
  88. * Accesses nodes in their internal hashmap order.
  89. */
  90. struct unordered_iterator
  91. {
  92. inline unordered_iterator(const unordered_iterator& other): set_iterator(other.set_iterator) {};
  93. inline unordered_iterator& operator=(const unordered_iterator& other) { this->set_iterator = other.set_iterator; return *this; };
  94. inline unordered_iterator& operator++() { ++(this->set_iterator); return *this; };
  95. inline unordered_iterator& operator--() { --(this->set_iterator); return *this; };
  96. inline bool operator==(const unordered_iterator& other) const { return this->set_iterator == other.set_iterator; };
  97. inline bool operator!=(const unordered_iterator& other) const { return this->set_iterator != other.set_iterator; };
  98. inline node_type operator*() const { return *this->set_iterator; };
  99. private:
  100. friend class hyperoctree;
  101. inline explicit unordered_iterator(const typename std::unordered_set<node_type>::const_iterator& it): set_iterator(it) {};
  102. typename std::unordered_set<node_type>::const_iterator set_iterator;
  103. };
  104. /**
  105. * Accesses nodes in z-order.
  106. *
  107. * @TODO Can this be implemented without a stack?
  108. */
  109. struct iterator
  110. {
  111. inline iterator(const iterator& other): hyperoctree(other.hyperoctree), stack(other.stack) {};
  112. inline iterator& operator=(const iterator& other) { this->hyperoctree = other.hyperoctree; this->stack = other.stack; return *this; };
  113. iterator& operator++();
  114. inline bool operator==(const iterator& other) const { return **this == *other; };
  115. inline bool operator!=(const iterator& other) const { return **this != *other; };
  116. inline node_type operator*() const { return stack.top(); };
  117. private:
  118. friend class hyperoctree;
  119. inline explicit iterator(const hyperoctree* hyperoctree, node_type node): hyperoctree(hyperoctree), stack({node}) {};
  120. const hyperoctree* hyperoctree;
  121. std::stack<node_type> stack;
  122. };
  123. /**
  124. * Returns the depth of a node.
  125. *
  126. * @param node Node.
  127. * @return Depth of the node.
  128. */
  129. static T depth(node_type node);
  130. /**
  131. * Returns the Morton code location of a node.
  132. *
  133. * @param node Node.
  134. * @return Morton code location of the node.
  135. */
  136. static T location(node_type node);
  137. /**
  138. * Returns the node at the given depth and location.
  139. *
  140. * @param depth Node depth.
  141. * @param location Node Morton code location.
  142. */
  143. static node_type node(T depth, T location);
  144. /**
  145. * Returns the ancestor of a node at the specified depth.
  146. *
  147. * @param node Node whose ancestor will be located.
  148. * @param depth Absolute depth of the ancestors.
  149. * @return Ancestral node.
  150. */
  151. static node_type ancestor(node_type node, T depth);
  152. /**
  153. * Returns the parent of a node.
  154. *
  155. * @param node Node.
  156. * @return Parent node.
  157. */
  158. static node_type parent(node_type node);
  159. /**
  160. * Returns the nth sibling of a node.
  161. *
  162. * @param node Node.
  163. * @param n Offset to next sibling. (Automatically wraps to `[0, siblings_per_node]`)
  164. * @return Next sibling node.
  165. */
  166. static node_type sibling(node_type node, T n);
  167. /**
  168. * Returns the nth child of a node.
  169. *
  170. * @param node Parent node.
  171. * @param n Offset to the nth sibling of the first child node. (Automatically wraps to 0..7)
  172. * @return nth child node.
  173. */
  174. static node_type child(node_type node, T n);
  175. /**
  176. * Calculates the first common ancestor of two nodes.
  177. *
  178. * @param a First node.
  179. * @param b Second node.
  180. * @return First common ancestor of the two nodes.
  181. */
  182. static node_type common_ancestor(node_type a, node_type b);
  183. /// Creates an hyperoctree with a single root node.
  184. hyperoctree();
  185. /// Returns a z-order iterator to the root node.
  186. iterator begin() const;
  187. /// Returns a z-order iterator indicating the end of a traversal.
  188. iterator end() const;
  189. /// Returns an iterator to the specified node.
  190. iterator find(node_type node) const;
  191. /// Returns an unordered iterator indicating the beginning of a traversal.
  192. unordered_iterator unordered_begin() const;
  193. /// Returns an unordered iterator indicating the end of a traversal.
  194. unordered_iterator unordered_end() const;
  195. /**
  196. * Inserts a node and its siblings into the hyperoctree, creating its ancestors as necessary. Note: The root node is persistent and cannot be inserted.
  197. *
  198. * @param node Node to insert.
  199. */
  200. void insert(node_type node);
  201. /**
  202. * Erases a node along with its siblings and descendants. Note: The root node is persistent and cannot be erased.
  203. *
  204. * @param node Node to erase.
  205. */
  206. void erase(node_type node);
  207. /**
  208. * Erases all nodes except the root.
  209. */
  210. void clear();
  211. /// Returns `true` if the node is contained within the hyperoctree, and `false` otherwise.
  212. bool contains(node_type node) const;
  213. /// Returns `true` if the node has no children, and `false` otherwise.
  214. bool is_leaf(node_type node) const;
  215. /// Returns the number of nodes in the hyperoctree.
  216. std::size_t size() const;
  217. private:
  218. /// Compile-time pow()
  219. static constexpr T pow(T x, T exponent);
  220. /// Count leading zeros
  221. static T clz(T x);
  222. std::unordered_set<node_type> nodes;
  223. };
  224. template <std::size_t N, std::size_t D, class T>
  225. typename hyperoctree<N, D, T>::iterator& hyperoctree<N, D, T>::iterator::operator++()
  226. {
  227. // Get next node from top of stack
  228. node_type node = stack.top();
  229. stack.pop();
  230. // If the node has children
  231. if (!hyperoctree->is_leaf(node))
  232. {
  233. // Push first child onto the stack
  234. for (T i = 0; i < children_per_node; ++i)
  235. stack.push(child(node, siblings_per_node - i));
  236. }
  237. if (stack.empty())
  238. stack.push(std::numeric_limits<T>::max());
  239. return *this;
  240. }
  241. template <std::size_t N, std::size_t D, class T>
  242. constexpr T hyperoctree<N, D, T>::ceil_log2(T n)
  243. {
  244. return (n <= 1) ? 0 : ceil_log2((n + 1) / 2) + 1;
  245. }
  246. template <std::size_t N, std::size_t D, class T>
  247. inline T hyperoctree<N, D, T>::depth(node_type node)
  248. {
  249. // Extract depth using a bit mask
  250. constexpr T mask = pow(2, depth_bits) - 1;
  251. return node & mask;
  252. }
  253. template <std::size_t N, std::size_t D, class T>
  254. inline T hyperoctree<N, D, T>::location(node_type node)
  255. {
  256. return node >> ((node_bits - 1) - depth(node) * N);
  257. }
  258. template <std::size_t N, std::size_t D, class T>
  259. inline typename hyperoctree<N, D, T>::node_type hyperoctree<N, D, T>::node(T depth, T location)
  260. {
  261. return (location << ((node_bits - 1) - depth * N)) | depth;
  262. }
  263. template <std::size_t N, std::size_t D, class T>
  264. inline typename hyperoctree<N, D, T>::node_type hyperoctree<N, D, T>::ancestor(node_type node, T depth)
  265. {
  266. const T mask = std::numeric_limits<T>::max() << ((node_bits - 1) - depth * N);
  267. return (node & mask) | depth;
  268. }
  269. template <std::size_t N, std::size_t D, class T>
  270. inline typename hyperoctree<N, D, T>::node_type hyperoctree<N, D, T>::parent(node_type node)
  271. {
  272. return ancestor(node, depth(node) - 1);
  273. }
  274. template <std::size_t N, std::size_t D, class T>
  275. inline typename hyperoctree<N, D, T>::node_type hyperoctree<N, D, T>::sibling(node_type node, T n)
  276. {
  277. constexpr T mask = (1 << N) - 1;
  278. T depth = hyperoctree::depth(node);
  279. T location = node >> ((node_bits - 1) - depth * N);
  280. return hyperoctree::node(depth, (location & (~mask)) | ((location + n) & mask));
  281. }
  282. template <std::size_t N, std::size_t D, class T>
  283. inline typename hyperoctree<N, D, T>::node_type hyperoctree<N, D, T>::child(node_type node, T n)
  284. {
  285. return sibling(node + 1, n);
  286. }
  287. template <std::size_t N, std::size_t D, class T>
  288. inline typename hyperoctree<N, D, T>::node_type hyperoctree<N, D, T>::common_ancestor(node_type a, node_type b)
  289. {
  290. T bits = std::min<T>(depth(a), depth(b)) * N;
  291. T marker = (T(1) << (node_bits - 1)) >> bits;
  292. T depth = clz((a ^ b) | marker) / N;
  293. return ancestor(a, depth);
  294. }
  295. template <std::size_t N, std::size_t D, class T>
  296. inline hyperoctree<N, D, T>::hyperoctree():
  297. nodes({0})
  298. {}
  299. template <std::size_t N, std::size_t D, class T>
  300. void hyperoctree<N, D, T>::insert(node_type node)
  301. {
  302. if (contains(node))
  303. return;
  304. // Insert node
  305. nodes.emplace(node);
  306. // Insert siblings
  307. for (T i = 1; i < children_per_node; ++i)
  308. nodes.emplace(sibling(node, i));
  309. // Insert parent as necessary
  310. node_type parent = hyperoctree::parent(node);
  311. if (!contains(parent))
  312. insert(parent);
  313. }
  314. template <std::size_t N, std::size_t D, class T>
  315. void hyperoctree<N, D, T>::erase(node_type node)
  316. {
  317. // Don't erase the root!
  318. if (node == root)
  319. return;
  320. for (T i = 0; i < children_per_node; ++i)
  321. {
  322. // Erase node
  323. nodes.erase(node);
  324. // Erase descendants
  325. if (!is_leaf(node))
  326. {
  327. for (T j = 0; j < children_per_node; ++j)
  328. erase(child(node, j));
  329. }
  330. // Go to next sibling
  331. if (i < siblings_per_node)
  332. node = sibling(node, i);
  333. }
  334. }
  335. template <std::size_t N, std::size_t D, class T>
  336. void hyperoctree<N, D, T>::clear()
  337. {
  338. nodes = {0};
  339. }
  340. template <std::size_t N, std::size_t D, class T>
  341. inline bool hyperoctree<N, D, T>::contains(node_type node) const
  342. {
  343. return (nodes.find(node) != nodes.end());
  344. }
  345. template <std::size_t N, std::size_t D, class T>
  346. inline bool hyperoctree<N, D, T>::is_leaf(node_type node) const
  347. {
  348. return !contains(child(node, 0));
  349. }
  350. template <std::size_t N, std::size_t D, class T>
  351. inline std::size_t hyperoctree<N, D, T>::size() const
  352. {
  353. return nodes.size();
  354. }
  355. template <std::size_t N, std::size_t D, class T>
  356. typename hyperoctree<N, D, T>::iterator hyperoctree<N, D, T>::begin() const
  357. {
  358. return iterator(this, hyperoctree::root);
  359. }
  360. template <std::size_t N, std::size_t D, class T>
  361. typename hyperoctree<N, D, T>::iterator hyperoctree<N, D, T>::end() const
  362. {
  363. return iterator(this, std::numeric_limits<T>::max());
  364. }
  365. template <std::size_t N, std::size_t D, class T>
  366. typename hyperoctree<N, D, T>::iterator hyperoctree<N, D, T>::find(node_type node) const
  367. {
  368. return contains(node) ? iterator(node) : end();
  369. }
  370. template <std::size_t N, std::size_t D, class T>
  371. typename hyperoctree<N, D, T>::unordered_iterator hyperoctree<N, D, T>::unordered_begin() const
  372. {
  373. return unordered_iterator(nodes.begin());
  374. }
  375. template <std::size_t N, std::size_t D, class T>
  376. typename hyperoctree<N, D, T>::unordered_iterator hyperoctree<N, D, T>::unordered_end() const
  377. {
  378. return unordered_iterator(nodes.end());
  379. }
  380. template <std::size_t N, std::size_t D, class T>
  381. constexpr T hyperoctree<N, D, T>::pow(T x, T exponent)
  382. {
  383. return (exponent == 0) ? 1 : x * pow(x, exponent - 1);
  384. }
  385. template <std::size_t N, std::size_t D, class T>
  386. T hyperoctree<N, D, T>::clz(T x)
  387. {
  388. if (!x)
  389. return sizeof(T) * 8;
  390. #if defined(__GNU__)
  391. return __builtin_clz(x);
  392. #else
  393. T n = 0;
  394. while ((x & (T(1) << (8 * sizeof(x) - 1))) == 0)
  395. {
  396. x <<= 1;
  397. ++n;
  398. }
  399. return n;
  400. #endif
  401. }
  402. } // namespace geom
  403. #endif // ANTKEEPER_GEOM_HYPEROCTREE_HPP