3#include <cuda/std/cmath>
4#include <cuda/std/cstdint>
27static __device__
constexpr float ddl_cf_keys[] = {
42static __device__
constexpr float ddl_mean_m_cf[] = {
60 if (estimate <= ddl_cf_keys[0]) {
61 return ddl_mean_m_cf[0];
69 auto const middle = (
low +
high) / 2;
70 if (ddl_cf_keys[middle] <= estimate) {
76 auto const fraction = (estimate - ddl_cf_keys[
low]) / (ddl_cf_keys[
high] - ddl_cf_keys[
low]);
77 return ddl_mean_m_cf[
low] + fraction * (ddl_mean_m_cf[
high] - ddl_mean_m_cf[
low]);
81__device__
inline double lc_min(uint32_t
const* bins,
double bucket_count)
noexcept {
82 auto cumulative = bins[0];
83 if (cumulative > 0U) {
84 return bucket_count * cuda::std::log(bucket_count / cumulative);
86 for (int32_t tier = 0; tier + 1 <
nlz_bins; ++tier) {
87 cumulative += bins[tier + 1];
88 if (cumulative > 0U) {
89 return cuda::std::ldexp(
90 bucket_count * cuda::std::log(bucket_count / cumulative), tier + 1
98__device__
inline double dlc(uint32_t
const* bins,
double bucket_count,
double lc)
noexcept {
99 auto const empty = bins[0];
101 auto const maximum = bucket_count - minimum;
102 auto cumulative = empty;
103 double weight_sum = 0.0;
104 double weighted_log_sum = 0.0;
105 for (int32_t tier = 0; tier + 1 <
nlz_bins; ++tier) {
106 if (cumulative >= minimum && cumulative <= maximum) {
107 auto const occupied = bucket_count - cumulative;
108 auto const log_ratio = cuda::std::log(bucket_count / cumulative);
109 auto const tier_estimate = cuda::std::ldexp(bucket_count * log_ratio, tier);
111 auto const error = cuda::std::sqrt(2.0 / 3.14159265358979323846) *
112 cuda::std::sqrt(occupied / (bucket_count * cumulative)) / log_ratio;
116 auto const inv_error = 1.0 / error;
117 auto const inv_squared = inv_error * inv_error;
118 auto const weight = inv_squared * inv_squared * cuda::std::sqrt(inv_error);
119 weight_sum += weight;
120 weighted_log_sum += weight * cuda::std::log(tier_estimate);
122 cumulative += bins[tier + 1];
123 if (cumulative >= bucket_count) {
127 if (weight_sum == 0.0) {
130 auto const pure = cuda::std::exp(weighted_log_sum / weight_sum);
137 return t * lc + (1.0 - t) * pure;
145 double zone_estimate,
146 double corrected_mean,
151 if (zone_estimate <=
low) {
154 if (zone_estimate >=
high) {
155 return corrected_mean;
157 auto const t = cuda::std::log(zone_estimate /
low) / cuda::std::log(
high /
low);
158 return (1.0 - t) * low_estimate + t * corrected_mean;
162__device__
inline double
163bbtools_mean_m(
double bucket_count,
double filled,
double restored_sum)
noexcept {
164 if (filled <= 0.0 || restored_sum <= 0.0) {
167 auto const mean = restored_sum / filled;
168 auto const occupancy_correction = (filled + bucket_count) / (2.0 * bucket_count);
169 return hash_range / mean * filled * occupancy_correction;
175 auto const empty =
static_cast<double>(bins[0]);
176 auto const filled = bucket_count - empty;
177 auto const raw_mean =
bbtools_mean_m(bucket_count, filled, restored_sum);
178 auto const lc =
lc_min(bins, bucket_count);
179 auto const dlc_estimate =
dlc(bins, bucket_count, lc);
182 hybrid(lc, lc, corrected_mean, bucket_count),
183 hybrid(lc, dlc_estimate, corrected_mean, bucket_count),
201 if (estimate <= ddl_cf_keys[0]) {
202 return ddl_mean_m_cf[0];
210 auto const middle = (
low +
high) / 2;
211 if (ddl_cf_keys[middle] <= estimate) {
217 auto const fraction = (estimate - ddl_cf_keys[
low]) / (ddl_cf_keys[
high] - ddl_cf_keys[
low]);
218 return ddl_mean_m_cf[
low] + fraction * (ddl_mean_m_cf[
high] - ddl_mean_m_cf[
low]);
222__device__
inline float lc_min_f32(uint32_t
const* bins,
float bucket_count)
noexcept {
223 auto cumulative = bins[0];
224 if (cumulative > 0U) {
225 return bucket_count * cuda::std::log(bucket_count / cumulative);
227 for (int32_t tier = 0; tier + 1 <
nlz_bins; ++tier) {
228 cumulative += bins[tier + 1];
229 if (cumulative > 0U) {
230 return cuda::std::ldexp(
231 bucket_count * cuda::std::log(bucket_count / cumulative), tier + 1
239__device__
inline float dlc_f32(uint32_t
const* bins,
float bucket_count,
float lc)
noexcept {
240 auto const empty =
static_cast<float>(bins[0]);
241 auto const minimum = max(1.0f, bucket_count *
static_cast<float>(
dlc_min_fraction));
242 auto const maximum = bucket_count - minimum;
243 auto cumulative = empty;
244 float weight_sum = 0.0f;
245 float weighted_log_sum = 0.0f;
246 for (int32_t tier = 0; tier + 1 <
nlz_bins; ++tier) {
247 if (cumulative >= minimum && cumulative <= maximum) {
248 auto const occupied = bucket_count - cumulative;
249 auto const log_ratio = cuda::std::log(bucket_count / cumulative);
250 auto const tier_estimate = cuda::std::ldexp(bucket_count * log_ratio, tier);
252 auto const error = cuda::std::sqrt(2.0f / 3.14159265358979323846f) *
253 cuda::std::sqrt(occupied / (bucket_count * cumulative)) / log_ratio;
257 auto const inv_error = 1.0f / error;
258 auto const inv_squared = inv_error * inv_error;
259 auto const weight = inv_squared * inv_squared * cuda::std::sqrt(inv_error);
260 weight_sum += weight;
261 weighted_log_sum += weight * cuda::std::log(tier_estimate);
263 cumulative += bins[tier + 1];
264 if (cumulative >= bucket_count) {
268 if (weight_sum == 0.0f) {
271 auto const pure = cuda::std::exp(weighted_log_sum / weight_sum);
275 if (empty >
static_cast<float>(
dlc_blend_low) * bucket_count) {
276 auto const t = (empty -
static_cast<float>(
dlc_blend_low) * bucket_count) /
279 return t * lc + (1.0f - t) * pure;
288 float corrected_mean,
291 auto const low =
static_cast<float>(
hybrid_low) * bucket_count;
293 if (zone_estimate <=
low) {
296 if (zone_estimate >=
high) {
297 return corrected_mean;
299 auto const t = cuda::std::log(zone_estimate /
low) / cuda::std::log(
high /
low);
300 return (1.0f - t) * low_estimate + t * corrected_mean;
304__device__
inline float
306 if (filled <= 0.0f || restored_sum <= 0.0f) {
309 auto const mean = restored_sum / filled;
310 auto const occupancy_correction = (filled + bucket_count) / (2.0f * bucket_count);
311 return static_cast<float>(
hash_range) / mean * filled * occupancy_correction;
317 auto const empty =
static_cast<float>(bins[0]);
318 auto const filled = bucket_count - empty;
320 auto const lc =
lc_min_f32(bins, bucket_count);
321 auto const dlc_estimate =
dlc_f32(bins, bucket_count, lc);
324 static_cast<double>(
hybrid_f32(lc, lc, corrected_mean, bucket_count)),
325 static_cast<double>(
hybrid_f32(lc, dlc_estimate, corrected_mean, bucket_count)),
326 static_cast<double>(lc),
327 static_cast<double>(dlc_estimate),
328 static_cast<double>(raw_mean),
__device__ float dlc_f32(uint32_t const *bins, float bucket_count, float lc) noexcept
Single-precision dlc for the latency-bound hybrid scan.
__device__ double interpolate_mean_m_cf(double estimate) noexcept
Interpolates the MeanM correction factor for estimate from the calibration table.
constexpr double dlc_blend_low
__device__ hybrid_cardinality_estimates hybrid_estimates(uint32_t const *bins, double bucket_count, double restored_sum) noexcept
Fused BBTools, paper, linear-counting, DLC, and raw MeanM estimates.
constexpr double hybrid_low
constexpr double hybrid_high
__device__ float hybrid_f32(float low_estimate, float zone_estimate, float corrected_mean, float bucket_count) noexcept
Single-precision hybrid for the latency-bound hybrid scan.
__device__ float interpolate_mean_m_cf_f32(float estimate) noexcept
Single-precision variant of the hybrid estimator tail.
constexpr double hash_range
2^64, the range of the 64-bit hash used by the sketch.
__device__ hybrid_cardinality_estimates hybrid_estimates_f32(uint32_t const *bins, float bucket_count, float restored_sum) noexcept
Single-precision hybrid_estimates for the latency-bound hybrid scan.
constexpr double dlc_info_power
constexpr uint32_t ddl_cf_size
__device__ double dlc(uint32_t const *bins, double bucket_count, double lc) noexcept
Distributed linear-counting estimate, blended from per-tier estimates by precision.
constexpr double dlc_blend_high
hybrid_variant
Which HybridDDL blend the variant kernel computes.
__device__ double bbtools_mean_m(double bucket_count, double filled, double restored_sum) noexcept
BBTools occupancy-corrected MeanM estimate from restored magnitudes.
@ hybrid
CPU inflation, followed by GPU FASTA normalisation of the inflated bytes.
__device__ float bbtools_mean_m_f32(float bucket_count, float filled, float restored_sum) noexcept
Single-precision bbtools_mean_m for the latency-bound hybrid scan.
constexpr double dlc_min_fraction
__device__ float lc_min_f32(uint32_t const *bins, float bucket_count) noexcept
Single-precision lc_min for the latency-bound hybrid scan.
__device__ double lc_min(uint32_t const *bins, double bucket_count) noexcept
Linear-counting estimate from the first occupied NLZ tier.
constexpr int32_t nlz_bins
NLZ histogram bins for the hybrid estimator, including the empty tier.
Experimental DDL cardinality estimates computed from one register scan.