Zip and Skip Tries
Loading...
Searching...
No Matches
ParallelZipTrie.cuh
Go to the documentation of this file.
1
12#pragma once
13
14#include "BitString.cuh" // Requires BitString definition with par_k_compare
15
16#include <compare> // For std::strong_ordering
17
18#include "ZipTrie.hpp" // Base class definition
19
20#include "cuda_utils.cuh" // CUDA utility functions like alloc_to_device, device_free
21
41template <typename CHAR_T, bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
42class ParallelZipTrie : public ZipTrie<CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS>
43{
44public:
47
49 using LCP_T = typename ZT::LCP_T;
51 using KEY_T = typename ZT::KEY_T;
52
63 ParallelZipTrie(unsigned max_size, unsigned max_lcp_length);
64
71
77 using ZT::size;
78
95 void insert(const KEY_T* key) noexcept;
96
103 // bool remove(const KEY_T& key) noexcept;
104
107
119 SearchResults search(const KEY_T* key) const noexcept override; // Mark as override
120
121protected:
122 // --- Inherited members from ZipTrie ---
124 using ZT::_root_index;
128 using ZT::_log_max_size;
130 using ZT::_buckets;
131
133 using ZT::NULLPTR;
134
135 // --- Inherited types/structs from ZipTrie ---
139 using Bucket = typename ZT::Bucket;
142
143 // --- Inherited methods from ZipTrie ---
153 using ZT::convert_lcp;
154
155private:
160
187 inline ComparisonResult k_compare(const KEY_T* x, const Bucket& v, const AncestorLCPs& ancestor_lcps, size_t& comparison_size, size_t& max_copied) const noexcept;
188};
189
190//-----------------------------------------------------------------------------
191// ParallelZipTrie Method Implementations
192//-----------------------------------------------------------------------------
193
194template<typename CHAR_T, bool MEMORY_EFFICIENT, typename RANK_T, unsigned CHAR_SIZE_BITS>
196 ZT(max_size, max_lcp_length) // Call base class constructor
197{
198 // Calculate required device buffer size in words based on max LCP length.
199 size_t max_lcp_length_words = (max_lcp_length + KEY_T::ALPHA - 1) / KEY_T::ALPHA;
200
201 // Allocate the primary device buffer.
203 // Allocate the auxiliary large block buffer (size calculation might depend on the parallel algorithm used).
204 // Use large block device allocation for temporary storage in parallel operations
206}
207
208template<typename CHAR_T, bool MEMORY_EFFICIENT, typename RANK_T, unsigned CHAR_SIZE_BITS>
210{
211 // Free the allocated device memory buffers.
212 device_free(d_a);
213 device_free(d_largeblock);
214}
215
216template<typename CHAR_T, bool MEMORY_EFFICIENT, typename RANK_T, unsigned CHAR_SIZE_BITS>
218{
219 size_t start_lcp_val = 0; // Initialize LCP offset for comparison.
220
221 if (auto prefix_result = k_compare_prefix_check(v, ancestor_lcps, start_lcp_val))
222 {
223 return *prefix_result; // Return early if comparison decided by LCPs.
224 }
225
226 // Initialize comparison result and final LCP with the value from prefix check.
227 std::strong_ordering final_comparison = std::strong_ordering::equal;
229
230 // Iteratively call parallel compare until a mismatch is found or keys are fully compared.
231 while (true)
232 {
233 // Call the parallel comparison function provided by the KEY_T (BitString) class.
234 // Pass the keys, current LCP offset, comparison block size, device buffers, and copy tracker.
235 auto [current_comparison, next_lcp] = x->par_k_compare(
237 d_a, d_largeblock, max_copied);
238
239 // Update the overall comparison result and the total LCP found so far.
242
243 // If the current block compared equal...
244 if (final_comparison == std::strong_ordering::equal)
245 {
246 // Check if we have compared the entire length of both keys.
247 // If keys are fully compared and equal, break the loop.
248 if (final_lcp_val == x->size() && final_lcp_val == v.key->size())
249 {
250 break;
251 }
252
253 // Otherwise, keys matched so far but aren't finished.
254 // Increase the comparison size (e.g., double it) for the next iteration to potentially speed up.
255 comparison_size *= 2;
256 // Continue to the next iteration to compare the next block.
257 continue;
258 }
259
260 // Mismatch found (comparison is less or greater).
261 // Reduce the comparison size for future comparisons (adaptive strategy).
262 // Ensure it doesn't go below a minimum threshold.
263 comparison_size = std::max(KEY_T::MIN_PAR_COMPARE_CHAR_SIZE, comparison_size / 2);
264 // Break the loop as the final comparison result is determined.
265 break;
266 }
267
268 // Convert the final exact LCP length to the appropriate LCP_T format and return the result.
269 return { final_comparison, convert_lcp(final_lcp_val) };
270}
271
272template<typename CHAR_T, bool MEMORY_EFFICIENT, typename RANK_T, unsigned CHAR_SIZE_BITS>
274{
275 // Initialize state variables for the parallel comparison process.
276 size_t comparison_size = KEY_T::MIN_PAR_COMPARE_CHAR_SIZE;
277 size_t max_copied = 0; // Tracks device memory copy status/optimization.
278
279 // Define a lambda function that captures the current state and calls the parallel k_compare method.
280 // This lambda will be passed to the base class's search_recursive helper.
281 auto parallel_compare = [&](const KEY_T* k, const Bucket& v, const AncestorLCPs& ancestor_lcps)
282 {
283 // Note: comparison_size and max_copied are captured by reference, allowing k_compare to modify them.
284 return k_compare(k, v, ancestor_lcps, comparison_size, max_copied);
285 };
286
287 // Call the inherited recursive search function, passing the key and the parallel comparison lambda.
288 return search_recursive(key, parallel_compare);
289}
290
291template <typename CHAR_T, bool MEMORY_EFFICIENT, typename RANK_T, unsigned CHAR_SIZE_BITS>
293{
294 // Initialize state variables for the parallel comparison process.
295 size_t comparison_size = KEY_T::MIN_PAR_COMPARE_CHAR_SIZE;
296 size_t max_copied = 0;
297
298 // Add a new bucket for the key with a random rank to the storage vector.
299 _buckets.push_back({ key, RANK_T::get_random() });
300 unsigned new_node_index = _buckets.size() - 1;
301
302 // Define the parallel comparison lambda, capturing state by reference.
303 auto parallel_compare = [&](const KEY_T* k, const Bucket& v, const AncestorLCPs& ancestor_lcps)
304 {
305 return k_compare(k, v, ancestor_lcps, comparison_size, max_copied);
306 };
307
308 // Call the inherited recursive insert function to place the node and perform zip operations.
309 // Pass the new node details, initial empty ancestor LCPs, and the parallel comparison lambda.
310 // Update the root index, as it might change due to zip operations.
311 _root_index = insert_recursive(&_buckets[new_node_index], new_node_index, _root_index, {}, parallel_compare);
312}
Defines the BitString class for compact character string storage and comparison.
Defines the ZipTrie class, a dynamic, ranked trie structure for efficient string storage and prefix o...
Extends the ZipTrie class to incorporate parallel key comparisons leveraging GPU acceleration (CUDA).
uintmax_t * d_largeblock
Pointer to auxiliary device memory buffer ('largeblock'), used as temporary storage or workspace duri...
void insert(const KEY_T *key) noexcept
Inserts a key into the parallel zip trie using parallel comparison logic.
typename ZT::Bucket Bucket
Alias for the Bucket (node) struct from the base class ZipTrie.
ParallelZipTrie(unsigned max_size, unsigned max_lcp_length)
Constructs a ParallelZipTrie.
typename ZT::SearchResults SearchResults
Removes a node with a given key from the zip tree. (Not implemented)
typename ZT::LCP_T LCP_T
Alias for the LCP type used, inherited from the base class (ZipTrie::LCP_T).
typename ZT::KEY_T KEY_T
Alias for the Key type used, inherited from the base class (ZipTrie::KEY_T).
typename ZT::ComparisonResult ComparisonResult
Alias for the ComparisonResult struct from the base class ZipTrie.
uintmax_t * d_a
Pointer to device memory buffer 'a', used as primary input/output for parallel key comparisons (e....
typename ZT::AncestorLCPs AncestorLCPs
Alias for the AncestorLCPs struct from the base class ZipTrie.
~ParallelZipTrie()
Destructor for ParallelZipTrie.
SearchResults search(const KEY_T *key) const noexcept override
Performs a search for a key within the ParallelZipTrie using parallel comparison logic.
ComparisonResult k_compare(const KEY_T *x, const Bucket &v, const AncestorLCPs &ancestor_lcps, size_t &comparison_size, size_t &max_copied) const noexcept
Performs key comparison using parallel logic, overriding the base class k_compare.
Implements a zip trie, a data structure combining properties of tries and zip trees for storing strin...
Definition ZipTrie.hpp:126
std::optional< ComparisonResult > k_compare_prefix_check(const Bucket &v, const AncestorLCPs &ancestor_lcps, size_t &out_start_lcp_val) const noexcept
Performs an initial check based on ancestor LCPs before full key comparison (k-compare optimization).
Definition ZipTrie.hpp:583
unsigned insert_recursive(Bucket *x, unsigned x_index, unsigned v_index, AncestorLCPs ancestor_lcps, CompareFunction compare_func) noexcept
Recursive helper function for inserting a new node x.
Definition ZipTrie.hpp:766
BitString< CHAR_T, CHAR_SIZE_BITS > KEY_T
The type used for keys, an instantiation of the BitString template.
Definition ZipTrie.hpp:137
static constexpr unsigned NULLPTR
Represents a null child pointer index using the maximum value of unsigned.
Definition ZipTrie.hpp:326
LCP_T convert_lcp(size_t val) const noexcept
Converts an exact LCP length (e.g., number of matching characters/bits) to the LCP_T type.
Definition ZipTrie.hpp:636
std::vector< Bucket > _buckets
A contiguous vector storing all the nodes (Buckets) of the trie.
Definition ZipTrie.hpp:379
MemoryEfficientLCP get_memory_efficient_lcp(size_t num) const noexcept
Converts a standard LCP length (size_t) into the MemoryEfficientLCP format.
Definition ZipTrie.hpp:928
uint8_t _log_max_size
Stores the approximate log base 2 of the max_size provided during construction.
Definition ZipTrie.hpp:323
unsigned _root_index
Index of the root node within the _buckets vector. Initialized to NULLPTR for an empty trie.
Definition ZipTrie.hpp:312
std::conditional_t< MEMORY_EFFICIENT, MemoryEfficientLCP, unsigned > LCP_T
The type used to store Longest Common Prefix values.
Definition ZipTrie.hpp:132
unsigned _max_lcp_length
Stores the maximum possible LCP length provided during construction.
Definition ZipTrie.hpp:317
SearchResults search_recursive(const KEY_T *key, CompareFunction compare_func) const noexcept
Recursive helper function for the public search method.
Definition ZipTrie.hpp:687
unsigned size() const noexcept
Returns the number of nodes (keys) currently stored in the trie.
Definition ZipTrie.hpp:857
Provides utility functions and classes for CUDA operations.
void device_free(T *d_arr)
Frees memory on the CUDA device.
T * alloc_to_device(size_t size)
Allocates memory on the CUDA device.
uintmax_t * alloc_large_block_to_device(size_t n)
Allocates a large block of device memory for parallel mismatch operations.
Definition msw.cu:256
Stores the Longest Common Prefix (LCP) values associated with the path from the root down to a node's...
Definition ZipTrie.hpp:339
Represents a single node (bucket) within the ZipTrie's internal storage.
Definition ZipTrie.hpp:352
Holds the result of comparing a search/insert key x with a node v's key, considering the context of a...
Definition ZipTrie.hpp:446
Holds the results returned by a search operation (search method).
Definition ZipTrie.hpp:271