Zip and Skip Tries
Loading...
Searching...
No Matches
Public Types | Public Member Functions | Protected Types | Protected Member Functions | Protected Attributes | Static Protected Attributes | Private Member Functions | Private Attributes | List of all members
ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS > Class Template Reference

Extends the ZipTrie class to incorporate parallel key comparisons leveraging GPU acceleration (CUDA). More...

Inheritance diagram for ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >:
Inheritance graph
[legend]
Collaboration diagram for ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >:
Collaboration graph
[legend]

Public Types

using ZT = ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >
 Alias for the base ZipTrie class template instantiation for brevity.
 
using LCP_T = typename ZT::LCP_T
 Alias for the LCP type used, inherited from the base class (ZipTrie::LCP_T).
 
using KEY_T = typename ZT::KEY_T
 Alias for the Key type used, inherited from the base class (ZipTrie::KEY_T).
 
using SearchResults = typename ZT::SearchResults
 Removes a node with a given key from the zip tree. (Not implemented)
 
- Public Types inherited from ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >
using LCP_T = std::conditional_t< MEMORY_EFFICIENT, MemoryEfficientLCP, unsigned >
 The type used to store Longest Common Prefix values.
 
using KEY_T = BitString< CHAR_T, CHAR_SIZE_BITS >
 The type used for keys, an instantiation of the BitString template.
 

Public Member Functions

 ParallelZipTrie (unsigned max_size, unsigned max_lcp_length)
 Constructs a ParallelZipTrie.
 
 ~ParallelZipTrie ()
 Destructor for ParallelZipTrie.
 
void insert (const KEY_T *key) noexcept
 Inserts a key into the parallel zip trie using parallel comparison logic.
 
SearchResults search (const KEY_T *key) const noexcept override
 Performs a search for a key within the ParallelZipTrie using parallel comparison logic.
 
unsigned size () const noexcept
 Returns the number of nodes (keys) currently stored in the trie.
 
- Public Member Functions inherited from ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >
 ZipTrie (unsigned max_size, unsigned max_lcp_length) noexcept
 Constructs an empty ZipTrie.
 
int get_depth (const KEY_T *key) const noexcept
 Calculates the depth of a given key in the trie.
 
int height () const noexcept
 Calculates the height of the trie.
 
double get_average_height () const noexcept
 Calculates the average depth of all nodes currently in the trie.
 
unsigned size () const noexcept
 Returns the number of nodes (keys) currently stored in the trie.
 
bool contains (const KEY_T *key) const noexcept
 Checks if a key exists within the trie.
 
LCP_T lcp (const KEY_T *key) const noexcept
 Finds the Longest Common Prefix (LCP) between the search key and the path taken in the trie.
 
void insert (const KEY_T *key) noexcept
 Inserts a key into the zip trie.
 
const RANK_Tget_root_rank () const noexcept
 Removes a node with a given key from the zip tree. (Not implemented)
 
void set (const KEY_T *key, RANK_T rank, unsigned left, unsigned right, LCP_T predecessor_lcp, LCP_T successor_lcp) noexcept
 Directly adds a pre-constructed bucket to the internal storage vector.
 
void set_root_index (unsigned root_index) noexcept
 Directly sets the root index of the trie.
 
void to_dot (const std::string &file_path) const noexcept
 Generates a DOT language representation of the trie structure for visualization.
 

Protected Types

using AncestorLCPs = typename ZT::AncestorLCPs
 Alias for the AncestorLCPs struct from the base class ZipTrie.
 
using Bucket = typename ZT::Bucket
 Alias for the Bucket (node) struct from the base class ZipTrie.
 
using ComparisonResult = typename ZT::ComparisonResult
 Alias for the ComparisonResult struct from the base class ZipTrie.
 

Protected Member Functions

MemoryEfficientLCP get_memory_efficient_lcp (size_t num) const noexcept
 Using declaration for the LCP approximation helper (if MEMORY_EFFICIENT is true) from ZipTrie.
 
template<typename CompareFunction >
SearchResults search_recursive (const KEY_T *key, CompareFunction compare_func) const noexcept
 Using declaration for the recursive search helper from the base class ZipTrie.
 
template<typename CompareFunction >
unsigned insert_recursive (Bucket *x, unsigned x_index, unsigned v_index, AncestorLCPs ancestor_lcps, CompareFunction compare_func) noexcept
 Using declaration for the recursive insert helper from the base class ZipTrie.
 
std::optional< ComparisonResultk_compare_prefix_check (const Bucket &v, const AncestorLCPs &ancestor_lcps, size_t &out_start_lcp_val) const noexcept
 Using declaration for the LCP prefix check optimization helper from ZipTrie.
 
LCP_T convert_lcp (size_t val) const noexcept
 Using declaration for the LCP value conversion helper from ZipTrie.
 
- Protected Member Functions inherited from ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >
MemoryEfficientLCP get_memory_efficient_lcp (size_t num) const noexcept
 Converts a standard LCP length (size_t) into the MemoryEfficientLCP format.
 
template<typename CompareFunction >
SearchResults search_recursive (const KEY_T *key, CompareFunction compare_func) const noexcept
 Recursive helper function for the public search method.
 
template<typename CompareFunction >
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.
 
std::optional< ComparisonResultk_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).
 
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.
 

Protected Attributes

unsigned _root_index
 Using declaration for the root index from the base class ZipTrie.
 
unsigned _max_lcp_length
 Using declaration for the maximum LCP length storage from the base class ZipTrie.
 
uint8_t _log_max_size
 Using declaration for the log max size storage from the base class ZipTrie.
 
std::vector< Bucket_buckets
 Using declaration for the node storage vector (std::vector<Bucket>) from the base class ZipTrie.
 
- Protected Attributes inherited from ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >
unsigned _root_index
 Index of the root node within the _buckets vector. Initialized to NULLPTR for an empty trie.
 
unsigned _max_lcp_length
 Stores the maximum possible LCP length provided during construction.
 
uint8_t _log_max_size
 Stores the approximate log base 2 of the max_size provided during construction.
 
std::vector< Bucket_buckets
 A contiguous vector storing all the nodes (Buckets) of the trie.
 

Static Protected Attributes

static constexpr unsigned NULLPTR
 Using declaration for the null pointer constant (unsigned) from the base class ZipTrie.
 
- Static Protected Attributes inherited from ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >
static constexpr unsigned NULLPTR = std::numeric_limits<unsigned>::max()
 Represents a null child pointer index using the maximum value of unsigned.
 

Private Member Functions

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.
 

Private Attributes

uintmax_td_a
 Pointer to device memory buffer 'a', used as primary input/output for parallel key comparisons (e.g., via BitString::par_k_compare).
 
uintmax_td_largeblock
 Pointer to auxiliary device memory buffer ('largeblock'), used as temporary storage or workspace during parallel key comparisons by kernels like par_find_mismatch.
 

Detailed Description

template<typename CHAR_T, bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
class ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >

Extends the ZipTrie class to incorporate parallel key comparisons leveraging GPU acceleration (CUDA).

This class inherits the core structure and logic of ZipTrie but overrides key comparison-related methods (k_compare, search, insert) to utilize a parallel comparison function (par_k_compare from BitString). It manages CUDA device memory buffers (d_a, d_largeblock) required for these parallel comparisons, allocating them in the constructor and freeing them in the destructor. This allows for potentially faster trie operations when comparing long keys, at the cost of requiring CUDA-enabled hardware and managing GPU memory. The LCP-based prefix check optimization (k_compare_prefix_check) from the base class is still utilized to avoid unnecessary parallel comparisons when possible.

Template Parameters
CHAR_TThe underlying character type used in the keys (BitString).
MEMORY_EFFICIENTIf true, uses MemoryEfficientLCP; otherwise, uses unsigned for LCP storage.
RANK_TThe type used for node ranks (default: GeometricRank).
CHAR_SIZE_BITSThe number of significant bits per character in CHAR_T.
See also
ZipTrie
BitString::par_k_compare

Definition at line 42 of file ParallelZipTrie.cuh.

Member Typedef Documentation

◆ AncestorLCPs

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
using ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::AncestorLCPs = typename ZT::AncestorLCPs
protected

Alias for the AncestorLCPs struct from the base class ZipTrie.

Definition at line 137 of file ParallelZipTrie.cuh.

◆ Bucket

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
using ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::Bucket = typename ZT::Bucket
protected

Alias for the Bucket (node) struct from the base class ZipTrie.

Definition at line 139 of file ParallelZipTrie.cuh.

◆ ComparisonResult

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
using ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::ComparisonResult = typename ZT::ComparisonResult
protected

Alias for the ComparisonResult struct from the base class ZipTrie.

Definition at line 141 of file ParallelZipTrie.cuh.

◆ KEY_T

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
using ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::KEY_T = typename ZT::KEY_T

Alias for the Key type used, inherited from the base class (ZipTrie::KEY_T).

Definition at line 51 of file ParallelZipTrie.cuh.

◆ LCP_T

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
using ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::LCP_T = typename ZT::LCP_T

Alias for the LCP type used, inherited from the base class (ZipTrie::LCP_T).

Definition at line 49 of file ParallelZipTrie.cuh.

◆ SearchResults

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
using ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::SearchResults = typename ZT::SearchResults

Removes a node with a given key from the zip tree. (Not implemented)

Parameters
keykey of node to remove
Returns
true if a node was removed, false otherwise
Note
This functionality is declared but not implemented. Requires implementing 'unzip' operations.

Alias for the SearchResults struct defined in the base ZipTrie class.

Definition at line 106 of file ParallelZipTrie.cuh.

◆ ZT

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
using ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::ZT = ZipTrie<CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS>

Alias for the base ZipTrie class template instantiation for brevity.

Definition at line 46 of file ParallelZipTrie.cuh.

Constructor & Destructor Documentation

◆ ParallelZipTrie()

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T , unsigned CHAR_SIZE_BITS>
ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::ParallelZipTrie ( unsigned  max_size,
unsigned  max_lcp_length 
)

Constructs a ParallelZipTrie.

Initializes the base ZipTrie and allocates necessary CUDA device memory buffers (d_a, d_largeblock) required for the parallel key comparisons (BitString::par_k_compare). The size of the allocated buffers is determined by the max_lcp_length parameter.

Parameters
max_sizeHint for reserving memory for the expected maximum number of nodes (passed to base class constructor).
max_lcp_lengthThe maximum possible LCP length (in characters/bits), used for device memory allocation size calculation.
See also
alloc_to_device
alloc_large_block_to_device_s

Definition at line 195 of file ParallelZipTrie.cuh.

195 :
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}
uintmax_t * d_largeblock
Pointer to auxiliary device memory buffer ('largeblock'), used as temporary storage or workspace duri...
uintmax_t * d_a
Pointer to device memory buffer 'a', used as primary input/output for parallel key comparisons (e....
ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS > ZT
Alias for the base ZipTrie class template instantiation for brevity.
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

◆ ~ParallelZipTrie()

Destructor for ParallelZipTrie.

Frees the CUDA device memory buffers (d_a, d_largeblock) allocated in the constructor.

See also
device_free

Definition at line 209 of file ParallelZipTrie.cuh.

210{
211 // Free the allocated device memory buffers.
214}
void device_free(T *d_arr)
Frees memory on the CUDA device.

Member Function Documentation

◆ convert_lcp()

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::LCP_T ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::convert_lcp ( size_t  val) const
inlineprotectednoexcept

Using declaration for the LCP value conversion helper from ZipTrie.

Definition at line 492 of file ZipTrie.hpp.

637{
638 if constexpr (MEMORY_EFFICIENT) {
639 // If memory efficiency is enabled, call the approximation function.
641 } else {
642 // Otherwise, just cast the exact value to the LCP type (unsigned).
643 // Ensure the value fits; consider potential truncation if LCP_T were smaller than size_t.
644 return static_cast<LCP_T>(val);
645 }
646}
MemoryEfficientLCP get_memory_efficient_lcp(size_t num) const noexcept
Using declaration for the LCP approximation helper (if MEMORY_EFFICIENT is true) from ZipTrie.
Definition ZipTrie.hpp:928
typename ZT::LCP_T LCP_T
Alias for the LCP type used, inherited from the base class (ZipTrie::LCP_T).

◆ get_memory_efficient_lcp()

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
MemoryEfficientLCP ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::get_memory_efficient_lcp ( size_t  num) const
inlineprotectednoexcept

Using declaration for the LCP approximation helper (if MEMORY_EFFICIENT is true) from ZipTrie.

Definition at line 391 of file ZipTrie.hpp.

929{
930 // Handle LCPs smaller than the log of max size directly.
931 if (num < _log_max_size)
932 {
933 // Store the exact value in 'multiple', with exponent 0.
934 return { 0, static_cast<uint8_t>(num) };
935 }
936
937 // Otherwise, calculate exponent and multiple for approximation.
939 lcp.exp_of_2 = std::log2(num / _log_max_size);
940 lcp.multiple = num / (1u << lcp.exp_of_2);
941
942 return lcp;
943}
uint8_t _log_max_size
Using declaration for the log max size storage from the base class ZipTrie.
Definition ZipTrie.hpp:323
LCP_T lcp(const KEY_T *key) const noexcept
Finds the Longest Common Prefix (LCP) between the search key and the path taken in the trie.
Definition ZipTrie.hpp:576
Represents an approximate Longest Common Prefix (LCP) length in a memory-efficient format.
Definition ZipTrie.hpp:37
uint8_t exp_of_2
The exponent part of the LCP representation (base 2).
Definition ZipTrie.hpp:39

◆ insert()

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T , unsigned CHAR_SIZE_BITS>
void ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::insert ( const KEY_T key)
noexcept

Inserts a key into the parallel zip trie using parallel comparison logic.

This method overrides the base class insert. It adds the key with a random rank to the internal storage (_buckets) and then calls the recursive insertion helper (insert_recursive), providing a comparison function lambda that utilizes the parallel k_compare implementation of this class. The parallel k_compare leverages BitString::par_k_compare for GPU acceleration when beneficial.

Parameters
keyPointer to the new key to insert. Must be non-null and point to a valid KEY_T object.
Warning
Key Lifetime: The lifetime of the object pointed to by key must exceed the lifetime of the ParallelZipTrie.
Uniqueness: Assumes keys are unique. Inserting duplicate keys results in the insertion being skipped, but the initially added bucket might remain unused in storage.
See also
insert_recursive
k_compare(const KEY_T*, const Bucket&, const AncestorLCPs&, size_t&, size_t&) const
RANK_T::get_random

Definition at line 292 of file ParallelZipTrie.cuh.

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.
312}
typename ZT::Bucket Bucket
Alias for the Bucket (node) struct from the base class ZipTrie.
unsigned insert_recursive(Bucket *x, unsigned x_index, unsigned v_index, AncestorLCPs ancestor_lcps, CompareFunction compare_func) noexcept
Using declaration for the recursive insert helper from the base class ZipTrie.
Definition ZipTrie.hpp:766
std::vector< Bucket > _buckets
Using declaration for the node storage vector (std::vector<Bucket>) from the base class ZipTrie.
Definition ZipTrie.hpp:379
typename ZT::KEY_T KEY_T
Alias for the Key type used, inherited from the base class (ZipTrie::KEY_T).
typename ZT::AncestorLCPs AncestorLCPs
Alias for the AncestorLCPs struct from the base class ZipTrie.
unsigned _root_index
Using declaration for the root index from the base class ZipTrie.
Definition ZipTrie.hpp:312
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.

◆ insert_recursive()

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
unsigned ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::insert_recursive ( Bucket x,
unsigned  x_index,
unsigned  v_index,
AncestorLCPs  ancestor_lcps,
CompareFunction  compare_func 
)
protectednoexcept

Using declaration for the recursive insert helper from the base class ZipTrie.

Definition at line 433 of file ZipTrie.hpp.

767{
768 // Base case: Reached a null pointer, meaning this is the insertion spot.
769 if (v_index == NULLPTR)
770 {
771 // Set the ancestor LCPs for the new node 'x' based on the path taken.
772 x->ancestor_lcps = ancestor_lcps;
773 // Return the index of the new node 'x', indicating it's the root of this (now non-empty) subtree.
774 return x_index;
775 }
776
777 // Get a reference to the current node 'v'.
779
780 // Compare the new key 'x->key' with the current node's key 'v_node.key'.
781 auto [ comparison, lcp ] = compare_func(x->key, v_node, ancestor_lcps);
782
783 // If keys are equal, the key already exists. Do not insert duplicates.
784 // Return the current node's index, leaving the subtree unchanged.
785 if (comparison == std::strong_ordering::equal)
786 {
787 // Note: Could potentially update value associated with key here if storing values.
788 // Since we only store keys, we just return.
789 // Also, need to handle the bucket pushed back in `insert`. A robust implementation
790 // might check for existence *before* adding to _buckets or remove the unused bucket here.
791 // Current implementation leaves the unused bucket if key exists.
792 // We should pop the unused bucket here.
793 if (x_index == _buckets.size() - 1) { // Check if it's the last one added
794 _buckets.pop_back(); // Remove the unused bucket
795 } // Else, if not the last, it's harder to remove without messing up indices.
796
797 return v_index;
798 }
799
800 // Navigate left or right based on the comparison result.
801 if (comparison == std::strong_ordering::less)
802 {
803 // Go left. Recursively insert into the left subtree.
804 // Update the ancestor LCPs for the recursive call: predecessor stays the same,
805 // successor becomes the max of the current path's successor and the LCP just computed.
806 unsigned subroot_index = insert_recursive(x, x_index, v_node.left, { ancestor_lcps.predecessor, std::max(ancestor_lcps.successor, lcp) }, compare_func);
807
808 // If the recursive call returned an index other than the original left child,
809 // it means the structure below changed.
810 if (subroot_index == x_index && x->rank >= v_node.rank)
811 {
812 v_node.left = x->right; // v adopts x's right child as its left child.
813 x->right = v_index; // x takes v as its right child.
814 // Update LCPs stored *in the nodes* due to the structural change.
815 // v's predecessor LCP is now the LCP computed between x and v.
816 v_node.ancestor_lcps.predecessor = lcp;
817 // x's ancestor LCPs become those passed into this level (ancestor_lcps).
818 x->ancestor_lcps = ancestor_lcps;
819 // Return x_index as the new root of this subtree.
820 return x_index;
821 }
822 else
823 {
824 // Simply update v's left child pointer to the returned subtree root.
825 v_node.left = subroot_index;
826 }
827 // If subroot_index == v_node.left, the left subtree structure didn't change relative to v.
828 }
829 else // comparison == std::strong_ordering::greater
830 {
831 // Go right. Recursively insert into the right subtree.
832 // Update ancestor LCPs: successor stays same, predecessor updates.
833 unsigned subroot_index = insert_recursive(x, x_index, v_node.right, { std::max(ancestor_lcps.predecessor, lcp), ancestor_lcps.successor }, compare_func);
834
835 // If the recursive call returned an index other than the original right child.
836 if (subroot_index == x_index && x->rank >= v_node.rank)
837 {
838 v_node.right = x->left; // v adopts x's left child as its right child.
839 x->left = v_index; // x takes v as its left child.
840 // Update LCPs stored in the nodes.
841 v_node.ancestor_lcps.successor = lcp; // v's successor LCP is now the computed LCP.
842 x->ancestor_lcps = ancestor_lcps; // x inherits parent's LCPs.
843 // Return x_index as the new root.
844 return x_index;
845 }
846 else
847 {
848 v_node.right = subroot_index;
849 }
850 // If subroot_index == v_node.right, the right subtree structure didn't change relative to v.
851 }
852
853 return v_index;
854}
static constexpr unsigned NULLPTR
Using declaration for the null pointer constant (unsigned) from the base class ZipTrie.
Definition ZipTrie.hpp:326

◆ k_compare()

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T , unsigned CHAR_SIZE_BITS>
ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::ComparisonResult ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::k_compare ( const KEY_T x,
const Bucket v,
const AncestorLCPs ancestor_lcps,
size_t comparison_size,
size_t max_copied 
) const
inlineprivatenoexcept

Performs key comparison using parallel logic, overriding the base class k_compare.

This method implements the core parallel comparison strategy for ParallelZipTrie. It first leverages the inherited k_compare_prefix_check optimization. If a full comparison is necessary, it iteratively calls the BitString::par_k_compare function, which performs the comparison on the GPU. The comparison_size parameter controls the chunk size (number of characters) compared in each parallel step and is adapted dynamically: it increases if blocks match to compare larger chunks next time, and decreases if a mismatch is found to potentially refine the LCP more quickly in subsequent comparisons within the same search/insert operation.

Parameters
xPointer to the key being searched for or inserted.
vConstant reference to the current node (Bucket) being compared against.
ancestor_lcpsThe LCPs computed along the path from the root down to v's parent.
[in,out]comparison_sizeControls the block size (number of characters) for the parallel comparison step. Its value is adapted based on the comparison outcome.
[in,out]max_copiedTracks state related to data copied to device memory (d_a) by par_k_compare to potentially optimize subsequent copies within the same search/insert operation.
Returns
ComparisonResult A struct containing the relative ordering (comparison) of x vs v and the calculated Longest Common Prefix (lcp) between them (converted to LCP_T).
Note
This method directly interacts with the BitString::par_k_compare function and relies on the device memory buffers d_a and d_largeblock managed by this class.
See also
ZT::k_compare_prefix_check
BitString::par_k_compare
convert_lcp

Definition at line 217 of file ParallelZipTrie.cuh.

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(
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.
270}
std::optional< ComparisonResult > k_compare_prefix_check(const Bucket &v, const AncestorLCPs &ancestor_lcps, size_t &out_start_lcp_val) const noexcept
Using declaration for the LCP prefix check optimization helper from ZipTrie.
Definition ZipTrie.hpp:583
LCP_T convert_lcp(size_t val) const noexcept
Using declaration for the LCP value conversion helper from ZipTrie.
Definition ZipTrie.hpp:636

◆ k_compare_prefix_check()

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
std::optional< typename ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::ComparisonResult > ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::k_compare_prefix_check ( const Bucket v,
const AncestorLCPs ancestor_lcps,
size_t out_start_lcp_val 
) const
protectednoexcept

Using declaration for the LCP prefix check optimization helper from ZipTrie.

Definition at line 478 of file ZipTrie.hpp.

587{
588 // Get the LCPs from the current search path.
589 auto predecessor_lcp = ancestor_lcps.predecessor;
590 auto successor_lcp = ancestor_lcps.successor;
591
592 // Determine the maximum LCP encountered on the current search path.
593 auto x_max_lcp = std::max(predecessor_lcp, successor_lcp);
594 // Determine the corresponding LCP stored in node 'v' (from the path when 'v' was inserted).
595 // If the search path's max LCP came from the predecessor side, use v's predecessor LCP, otherwise use v's successor LCP.
596 auto corr_v_lcp = (predecessor_lcp > successor_lcp) ? v.ancestor_lcps.predecessor : v.ancestor_lcps.successor;
597
598 // If the maximum LCP on the current path (x_max_lcp) differs from the
599 // corresponding LCP recorded when node 'v' was inserted (corr_v_lcp)...
600 if (x_max_lcp != corr_v_lcp)
601 {
602 // ...we can determine the order based on which LCP is larger and which path it came from.
603 // The logic determines if x should be less or greater than v.
604 // `(x_max_lcp > corr_v_lcp)` is true if the current path's LCP is longer.
605 // `(predecessor_lcp > successor_lcp)` is true if the current path's max LCP came from the predecessor side.
606 // If these booleans match, x is less; otherwise, x is greater.
607 std::strong_ordering comparison_result =
608 ((x_max_lcp > corr_v_lcp) == (predecessor_lcp > successor_lcp)) ? std::strong_ordering::less : std::strong_ordering::greater;
609
610 // The resulting LCP for this comparison is the minimum of the two differing LCPs.
612
613 // Return the determined comparison result and LCP. No need for full key comparison.
615 }
616
617 // If the LCPs matched (x_max_lcp == corr_v_lcp), we cannot decide the order yet.
618 // We need to perform a full key comparison, but we know the keys match up to `x_max_lcp`.
619 // Set the starting offset for the key comparison.
620 if constexpr (MEMORY_EFFICIENT)
621 {
622 // If using approximate LCPs, get the actual value.
624 }
625 else
626 {
627 // If using exact LCPs (unsigned), the value is directly usable.
629 }
630
631 // Indicate that a full key comparison should proceed by returning nullopt.
632 return std::nullopt;
633}
typename ZT::ComparisonResult ComparisonResult
Alias for the ComparisonResult struct from the base class ZipTrie.

◆ search()

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T , unsigned CHAR_SIZE_BITS>
ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::SearchResults ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::search ( const KEY_T key) const
overridevirtualnoexcept

Performs a search for a key within the ParallelZipTrie using parallel comparison logic.

Overrides the base class search method. It initializes state required for parallel comparison (comparison_size, max_copied) and calls the recursive search helper (search_recursive) inherited from the base class. Crucially, it passes a comparison function lambda that invokes the parallel k_compare implementation defined within this ParallelZipTrie class.

Parameters
keyPointer to the key to search for.
Returns
SearchResults A struct containing the search outcome (found status, LCP, depth).
See also
search_recursive
k_compare(const KEY_T*, const Bucket&, const AncestorLCPs&, size_t&, size_t&) const

Reimplemented from ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >.

Definition at line 273 of file ParallelZipTrie.cuh.

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.
289}
SearchResults search_recursive(const KEY_T *key, CompareFunction compare_func) const noexcept
Using declaration for the recursive search helper from the base class ZipTrie.
Definition ZipTrie.hpp:687

◆ search_recursive()

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::SearchResults ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::search_recursive ( const KEY_T key,
CompareFunction  compare_func 
) const
protectednoexcept

Using declaration for the recursive search helper from the base class ZipTrie.

Definition at line 407 of file ZipTrie.hpp.

688{
689 // Handle empty trie case.
690 if (_root_index == NULLPTR)
691 {
692 // Return not found, default LCP, depth -1.
693 return { false, {}, -1 };
694 }
695
696 unsigned v_index = _root_index; // Start traversal at the root.
697 AncestorLCPs ancestor_lcps = {}; // Initialize ancestor LCPs to zero/default at the root.
698 int depth = 0; // Initialize depth counter.
699
700 // Iterate down the trie until a null pointer is reached or the key is found.
701 while (v_index != NULLPTR)
702 {
703 // Get a reference to the current node.
704 const Bucket& v_node = _buckets[v_index];
705
706 // Perform the comparison using the provided comparison function.
707 auto [ comparison, lcp ] = compare_func(key, v_node, ancestor_lcps);
708
709 // Check if the key is an exact match.
710 if (comparison == std::strong_ordering::equal)
711 {
712 // Key found. Return true, the final LCP, and the current depth.
713 return { true, lcp, depth };
714 }
715
716 // If not equal, decide whether to go left or right.
717 if (comparison == std::strong_ordering::less)
718 {
719 // Go left. Update the successor LCP for the path: it's the maximum of the
720 // current successor LCP and the LCP computed in this step.
721 ancestor_lcps.successor = std::max(ancestor_lcps.successor, lcp);
722 // Move to the left child.
723 v_index = v_node.left;
724 }
725 else // comparison == std::strong_ordering::greater
726 {
727 // Go right. Update the predecessor LCP similarly.
728 ancestor_lcps.predecessor = std::max(ancestor_lcps.predecessor, lcp);
729 // Move to the right child.
730 v_index = v_node.right;
731 }
732
733 // Increment depth for the next level.
734 ++depth;
735 }
736
737 // Key not found after traversing the path.
738 // Return false, the maximum LCP encountered along the path, and depth -1.
739 return { false, std::max(ancestor_lcps.predecessor, ancestor_lcps.successor), -1 };
740}

◆ size()

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
unsigned ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::size ( ) const
noexcept

Returns the number of nodes (keys) currently stored in the trie.

Inherited directly from the base ZipTrie class via the using declaration.

Returns
unsigned The number of nodes.

Definition at line 183 of file ZipTrie.hpp.

858{
859 // Simply return the current size of the underlying vector storing the nodes.
860 // Note: This assumes no gaps or marked-deleted nodes if removal were implemented differently.
861 // If duplicate keys caused buckets to be added but not used in `insert_recursive`,
862 // this size might be slightly inflated compared to unique keys. Consider adjusting if duplicates are handled differently.
863 return _buckets.size();
864}

Member Data Documentation

◆ _buckets

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
std::vector<Bucket> ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::_buckets
protected

Using declaration for the node storage vector (std::vector<Bucket>) from the base class ZipTrie.

Definition at line 379 of file ZipTrie.hpp.

◆ _log_max_size

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
uint8_t ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::_log_max_size
protected

Using declaration for the log max size storage from the base class ZipTrie.

Definition at line 323 of file ZipTrie.hpp.

◆ _max_lcp_length

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
unsigned ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::_max_lcp_length
protected

Using declaration for the maximum LCP length storage from the base class ZipTrie.

Definition at line 317 of file ZipTrie.hpp.

◆ _root_index

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
unsigned ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::_root_index
protected

Using declaration for the root index from the base class ZipTrie.

Definition at line 312 of file ZipTrie.hpp.

◆ d_a

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
uintmax_t* ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::d_a
private

Pointer to device memory buffer 'a', used as primary input/output for parallel key comparisons (e.g., via BitString::par_k_compare).

Definition at line 157 of file ParallelZipTrie.cuh.

◆ d_largeblock

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
uintmax_t* ParallelZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::d_largeblock
private

Pointer to auxiliary device memory buffer ('largeblock'), used as temporary storage or workspace during parallel key comparisons by kernels like par_find_mismatch.

Definition at line 159 of file ParallelZipTrie.cuh.

◆ NULLPTR

template<typename CHAR_T , bool MEMORY_EFFICIENT, typename RANK_T = GeometricRank, unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
constexpr unsigned ZipTrie< CHAR_T, MEMORY_EFFICIENT, RANK_T, CHAR_SIZE_BITS >::NULLPTR
staticconstexprprotected

Using declaration for the null pointer constant (unsigned) from the base class ZipTrie.

Definition at line 326 of file ZipTrie.hpp.


The documentation for this class was generated from the following file: