72 "QuantizerConfig must fit in FZM_STAGE_CONFIG_SIZE");
73static_assert(
sizeof(QuantizerConfig) == 72,
74 "QuantizerConfig archive layout changed; add an explicit compatibility path");
135template<
typename TInput =
float,
typename TCode = u
int16_t>
196 int radius = 32768,
float outlier_cap = 0.05f)
207 const std::vector<void*>& inputs,
208 const std::vector<void*>& outputs,
209 const std::vector<size_t>& sizes
221 return (isLinearMode() || isInplaceMode()) ? 0 :
sizeof(uint32_t);
224 std::string
getName()
const override {
return "Quantizer"; }
226 size_t getNumInputs()
const override {
227 if (!is_inverse_)
return 1;
228 return (isLinearMode() || isInplaceMode()) ? 1 : 3;
230 size_t getNumOutputs()
const override {
231 if (is_inverse_)
return 1;
232 return (isLinearMode() || isInplaceMode()) ? 1 : 3;
236 if (is_inverse_)
return {
"reconstructed"};
237 if (isLinearMode() || isInplaceMode())
return {
"codes"};
238 return {
"codes",
"outlier_vals",
"outlier_idxs"};
242 const std::vector<size_t>& input_sizes
247 std::unordered_map<std::string, size_t> result;
248 for (
size_t i = 0; i < names.size() && i < actual_output_sizes_.size(); i++)
249 result[names[i]] = actual_output_sizes_[i];
253 return (index >= 0 && index <
static_cast<int>(actual_output_sizes_.size()))
254 ? actual_output_sizes_[index] : 0;
257 void setInverse(
bool inverse)
override { is_inverse_ = inverse; }
258 bool isInverse()
const override {
return is_inverse_; }
265 if (is_inverse_)
return {};
267 return FusionSpec{FusionAccess::Elementwise, 0};
270 return FusionSpec{FusionAccess::Elementwise, 0};
275 if (isSplitOutlierFusable())
return FusionSpec{FusionAccess::Elementwise, 0};
285 computed_abs_eb_ = resolveUniformBound();
287 computed_abs_eb_ = floorPowerOfTwo(computed_abs_eb_);
297 TInput getComputedAbsEb()
const {
return computed_abs_eb_; }
298 uint32_t getActualOutlierCount()
const {
return actual_outlier_count_; }
299 bool supportsChunkInverseFusion()
const {
300 return std::is_same<TInput, float>::value &&
301 std::is_same<TCode, uint32_t>::value &&
310 return std::is_same<TInput, float>::value &&
311 std::is_same<TCode, uint32_t>::value &&
317 actual_output_sizes_ = {output_bytes};
326 return FusionSpec{FusionAccess::Elementwise, 0};
334 d.strategy = FusionStrategy::WarpRegister;
339 return 2.0 *
static_cast<double>(computed_abs_eb_);
342 return 2.0 *
static_cast<double>(computed_abs_eb_);
349 if (!std::is_same<TInput, float>::value || is_inverse_)
return {};
356 return FusedOpDecl{FusionStrategy::WarpRegister,
"LinearQuant",
"", {}};
361 p.ebx2_r = 1.0f / (2.0f *
static_cast<float>(computed_abs_eb_));
365 d.strategy = FusionStrategy::ChunkCooperative;
366 d.
op_name =
"QuantInplaceZigzag";
368 d.
params.resize(
sizeof(p));
369 std::memcpy(d.
params.data(), &p,
sizeof(p));
375 if (isSplitOutlierFusable()) {
377 p.ebx2_r = 1.0f / (2.0f *
static_cast<float>(computed_abs_eb_));
381 d.strategy = FusionStrategy::ChunkCooperative;
382 d.
op_name =
"QuantSplitOutlier";
384 d.
params.resize(
sizeof(p));
385 std::memcpy(d.
params.data(), &p,
sizeof(p));
392 if (is_inverse_ || !isSplitOutlierFusable())
return {};
397 static_cast<uint8_t
>(DataType::UINT32), 1u, 0u, 1u},
404 fused_outlier_count_set_ =
false;
415 if (actual_output_sizes_.size() < 3) actual_output_sizes_.resize(3, 0);
416 if (output_index == 1) {
417 actual_outlier_count_ =
static_cast<uint32_t
>(bytes /
sizeof(TInput));
418 actual_output_sizes_[1] = bytes;
419 fused_outlier_count_set_ =
true;
420 }
else if (output_index == 2) {
421 actual_outlier_count_ =
static_cast<uint32_t
>(bytes /
sizeof(uint32_t));
422 actual_output_sizes_[2] = bytes;
423 fused_outlier_count_set_ =
true;
431 void setDims(
const std::array<size_t, 3>& dims)
override { dims_ = dims; }
434 return static_cast<uint16_t
>(StageType::QUANTIZER);
441 if (isLinearMode())
return static_cast<uint8_t
>(signedOf(getCodeDataType()));
442 if (isInplaceMode())
return static_cast<uint8_t
>(getCodeDataType());
443 switch (output_index) {
444 case 0:
return static_cast<uint8_t
>(getCodeDataType());
446 case 2:
return static_cast<uint8_t
>(DataType::UINT32);
447 default:
return static_cast<uint8_t
>(DataType::UINT8);
455 size_t serializeHeader(
size_t output_index, uint8_t* buf,
size_t max_size)
const override;
460 saved_config_ = config_;
461 saved_num_elements_ = num_elements_;
462 saved_actual_outlier_count_ = actual_outlier_count_;
463 saved_computed_abs_eb_ = computed_abs_eb_;
464 saved_computed_value_base_ = computed_value_base_;
465 saved_actual_output_sizes_ = actual_output_sizes_;
468 void restoreState()
override {
469 config_ = saved_config_;
470 num_elements_ = saved_num_elements_;
471 actual_outlier_count_ = saved_actual_outlier_count_;
472 computed_abs_eb_ = saved_computed_abs_eb_;
473 computed_value_base_ = saved_computed_value_base_;
474 actual_output_sizes_ = saved_actual_output_sizes_;
477 void setErrorBound(
double eb) { config_.
error_bound = eb; }
478 void setQuantRadius(
int r) { config_.
quant_radius = r; }
482 void setZigzagCodes(
bool enable) { config_.
zigzag_codes = enable; }
501 TInput getErrorBound()
const {
return static_cast<TInput
>(config_.
error_bound); }
502 int getQuantRadius()
const {
return config_.
quant_radius; }
503 ErrorBoundMode getErrorBoundMode()
const {
return config_.eb_mode; }
506 bool getZigzagCodes()
const {
return config_.
zigzag_codes; }
509 bool getLinearMode()
const {
return config_.
linear_mode; }
512 bool getDither()
const {
return config_.
dither; }
513 uint64_t getDitherSeed()
const {
return config_.
dither_seed; }
518 Config saved_config_;
519 std::array<size_t, 3> dims_ = {0, 1, 1};
520 std::vector<size_t> actual_output_sizes_;
521 std::vector<size_t> saved_actual_output_sizes_;
522 size_t num_elements_ = 0;
523 size_t saved_num_elements_ = 0;
524 uint32_t actual_outlier_count_= 0;
525 uint32_t saved_actual_outlier_count_ = 0;
530 bool fused_outlier_count_set_ =
false;
531 bool is_inverse_ =
false;
532 TInput computed_abs_eb_ =
static_cast<TInput
>(1e-4);
533 TInput saved_computed_abs_eb_ =
static_cast<TInput
>(1e-4);
534 TInput computed_value_base_ =
static_cast<TInput
>(0);
535 TInput saved_computed_value_base_ =
static_cast<TInput
>(0);
543 uint32_t* d_outlier_count_scratch_ =
nullptr;
546 uint32_t* d_linear_overflow_scratch_ =
nullptr;
549 MemoryPool* persistent_pool_ =
nullptr;
554 std::weak_ptr<const void> persistent_pool_alive_;
560 void initOutlierCountScratch(MemoryPool* pool);
561 void initLinearOverflowScratch(MemoryPool* pool);
569 void launchRelForward(fz::stream_t stream,
int grid,
int block,
570 const TInput* in,
size_t num_elements,
571 float log2eb,
float log2eb_r,
float opp_eb,
float oopp_eb,
573 TCode* codes, TInput* outlier_vals, uint32_t* outlier_idxs);
575 void launchLinearForward(fz::stream_t stream,
int grid,
int block,
576 const TInput* in,
size_t num_elements,
577 TInput ebx2_r,
double ebx2_r_f64, TCode* codes);
580 void launchInplaceForward(fz::stream_t stream,
int grid,
int block,
581 const TInput* in,
size_t num_elements,
582 TInput ebx2_r, TCode* codes);
584 void launchAbsNoaForward(fz::stream_t stream,
int grid,
int block,
585 const TInput* in,
size_t num_elements,
586 TInput ebx2_r, TInput ebx2, TInput abs_eb,
587 TInput dither_amp, uint64_t dither_seed,
589 TCode* codes, TInput* outlier_vals, uint32_t* outlier_idxs);
592 void launchRelInverse(fz::stream_t stream,
int grid,
int block,
593 const TCode* codes,
size_t num_elements,
594 float log2eb, TInput* out);
596 void launchLinearInverse(fz::stream_t stream,
int grid,
int block,
597 const TCode* codes,
size_t num_elements,
598 TInput ebx2,
double ebx2_f64, TInput* out);
600 void launchInplaceInverse(fz::stream_t stream,
int grid,
int block,
601 const TCode* codes,
size_t num_elements,
602 TInput ebx2, TInput* out);
604 void launchAbsNoaInverse(fz::stream_t stream,
int grid,
int block,
605 const TCode* codes,
size_t num_elements,
606 TInput ebx2, TInput dither_amp, uint64_t dither_seed,
609 bool isInplaceMode()
const {
610 return config_.inplace_outliers
614 bool isLinearMode()
const {
return config_.linear_mode; }
616 static TInput floorPowerOfTwo(TInput value) {
617 if (!(value > TInput(0)) || !std::isfinite(value))
618 throw std::runtime_error(
619 "QuantizerStage: power_of_two_bound requires a finite positive absolute bound");
621 std::frexp(value, &exponent);
622 return std::ldexp(TInput(1), exponent - 1);
625 TInput resolveUniformBound(TInput scale = TInput(1))
const {
626 const double resolved = config_.error_bound *
static_cast<double>(scale);
627 TInput bound =
static_cast<TInput
>(resolved);
631 if (config_.linear_high_precision &&
static_cast<double>(bound) > resolved)
632 bound = std::nextafter(bound, TInput(0));
636 void applyUniformBoundPolicy(TInput data_abs_max,
bool have_data_abs_max);
642 bool isSplitOutlierFusable()
const {
643 return std::is_same<TInput, float>::value && !is_inverse_
644 && !isInplaceMode() && !isLinearMode()
645 && config_.zigzag_codes && !config_.dither
654 case DataType::UINT8:
return DataType::INT8;
655 case DataType::UINT16:
return DataType::INT16;
656 case DataType::UINT32:
return DataType::INT32;
662 if (std::is_same<TInput, float>::value)
return DataType::FLOAT32;
663 if (std::is_same<TInput, double>::value)
return DataType::FLOAT64;
664 return DataType::FLOAT32;
667 if (std::is_same<TCode, uint8_t>::value)
return DataType::UINT8;
668 if (std::is_same<TCode, uint16_t>::value)
return DataType::UINT16;
669 if (std::is_same<TCode, uint32_t>::value)
return DataType::UINT32;
670 return DataType::UINT16;
672 size_t getMaxOutlierCount(
size_t n)
const {
673 return static_cast<size_t>(std::ceil(n * config_.outlier_capacity));
677extern template class QuantizerStage<float, uint16_t>;
678extern template class QuantizerStage<float, uint32_t>;
679extern template class QuantizerStage<double, uint16_t>;
680extern template class QuantizerStage<double, uint32_t>;
POD parameter blocks for the chunk-cooperative device-ops.
Definition quantizer.h:136
void setDither(bool enable)
Definition quantizer.h:495
void saveState() override
Definition quantizer.h:459
uint8_t getInputDataType(size_t) const override
Definition quantizer.h:451
uint8_t getOutputDataType(size_t output_index) const override
Definition quantizer.h:437
void setInplaceOutliers(bool enable)
ABS/NOA: encode outliers in-place (raw float bits in codes array; no scatter buffers).
Definition quantizer.h:486
void setPowerOfTwoBound(bool enable)
Uniform modes: tighten the resolved absolute EB to the next lower power of two.
Definition quantizer.h:492
std::vector< std::string > getOutputNames() const override
Definition quantizer.h:235
void setInverse(bool inverse) override
Definition quantizer.h:257
void deserializeHeader(const uint8_t *buf, size_t size) override
FusedOpDecl getFusedOp() const override
Definition quantizer.h:348
std::vector< FusedAuxOutputDecl > getFusedAuxOutputs() const override
Definition quantizer.h:391
double getFusedForwardQuantStep() const override
Definition quantizer.h:341
size_t estimateDeviceFootprintBytes(size_t) const override
Definition quantizer.h:220
void primeAbsEbForFusion()
Definition quantizer.h:283
void primeComputedAbsEb(const void *d_in, size_t scan_n, MemoryPool *pool, fz::stream_t stream)
void setDims(const std::array< size_t, 3 > &dims) override
Definition quantizer.h:431
FusedOpDecl getInverseFusedOp() const override
Definition quantizer.h:328
void setOutlierThreshold(float t)
ABS/NOA: |x| >= threshold → lossless outlier regardless of bin (LC reference parameter).
Definition quantizer.h:484
void onFinalize(size_t estimated_inlen, MemoryPool *pool) override
void setFusedInverseResult(size_t output_bytes) override
Definition quantizer.h:316
void setFusedSideOutput(int output_index, size_t bytes) override
Definition quantizer.h:414
void setDitherSeed(uint64_t seed)
Seed for the deterministic per-element dither offset (see Config::dither_seed).
Definition quantizer.h:497
std::string getName() const override
Definition quantizer.h:224
size_t serializeHeader(size_t output_index, uint8_t *buf, size_t max_size) const override
uint16_t getStageTypeId() const override
Definition quantizer.h:433
std::unordered_map< std::string, size_t > getActualOutputSizesByName() const override
Definition quantizer.h:245
bool supportsWarpInverseFusion() const
Definition quantizer.h:309
void setLinearHighPrecision(bool enable)
Linear mode: use double coordinate arithmetic and a strict rounding reserve.
Definition quantizer.h:490
void setDitherStrength(float strength)
Dither offset amplitude as a fraction of abs_eb, in (0,1]; see Config::dither_strength.
Definition quantizer.h:499
std::vector< size_t > estimateOutputSizes(const std::vector< size_t > &input_sizes) const override
FusionSpec getInverseFusionSpec() const override
Definition quantizer.h:324
void execute(fz::stream_t stream, MemoryPool *pool, const std::vector< void * > &inputs, const std::vector< void * > &outputs, const std::vector< size_t > &sizes) override
size_t getMaxHeaderSize(size_t) const override
Definition quantizer.h:456
void setLinearMode(bool enable)
ABS/NOA: linear / no-outlier mode (cuSZp-style signed codes; see Config::linear_mode).
Definition quantizer.h:488
size_t getActualOutputSize(int index) const override
Definition quantizer.h:252
void postStreamSync(fz::stream_t stream) override
double getFusedInverseDequantStep() const override
Definition quantizer.h:338
void primeFusedForwardState(const FusedPrimeContext &c) override
Definition quantizer.h:403
FusionSpec getFusionSpec() const override
Definition quantizer.h:264
Fused Lorenzo predictor and quantizer stage.
ErrorBoundMode
Definition lorenzo_quant.h:42
@ NOA
Value-range relative bound (norm-of-absolute).
@ ABS
Absolute error bound.
@ REL
Exact per-element point-wise relative bound (QuantizerStage only).
constexpr size_t FZM_STAGE_CONFIG_SIZE
Per-stage serialized config slot (bytes)
Definition fzm_format.h:65
DataType
Element data type identifiers used in buffer and stage descriptors.
Definition fzm_format.h:142
@ CompactedElements
runtime count * sizeof(element)
Base class interface for all compression stages.
A stage's contribution to a generated fused kernel — the device-op it maps to, where its source lives...
Definition fusion.h:161
std::vector< uint8_t > params
POD Params bytes; empty for stateless ops.
Definition fusion.h:165
std::string op_name
device-op type name, e.g. "DiffNegabinary"
Definition fusion.h:163
std::string include_header
header used by the generated source
Definition fusion.h:164
Minimal context a fused runner hands a stage so it can establish the forward-computed state its OWN i...
Definition fusion.h:205
fz::stream_t stream
stream to prime on
Definition fusion.h:209
MemoryPool * pool
scratch pool
Definition fusion.h:208
const void * d_input
device input buffer
Definition fusion.h:206
size_t input_bytes
its size in bytes
Definition fusion.h:207
A stage's fusion contract. Stages that can participate in a fused kernel override Stage::getFusionSpe...
Definition fusion.h:51
Definition quantizer.h:28
uint8_t inplace_outliers
1 if outliers are encoded in-place in the codes array.
Definition quantizer.h:43
double abs_error_bound_f64
Definition quantizer.h:57
uint32_t _pad2
Definition quantizer.h:51
uint8_t linear_mode
1 if linear/no-outlier mode (signed codes, no outlier ports).
Definition quantizer.h:44
uint8_t eb_mode
ErrorBoundMode cast to uint8_t.
Definition quantizer.h:40
uint64_t dither_seed
Deterministic per-element dither seed; meaningful only when dither.
Definition quantizer.h:49
uint32_t outlier_count
Actual number of outliers.
Definition quantizer.h:37
DataType code_type
Quantization code type (1B).
Definition quantizer.h:39
uint8_t zigzag_codes
1 if ABS/NOA codes are zigzag-encoded.
Definition quantizer.h:41
uint32_t num_elements
Total element count.
Definition quantizer.h:36
double value_base_f64
Full-precision value_base; 0 in pre-2026-08-07 headers.
Definition quantizer.h:58
uint8_t power_of_two_bound
1 if the uniform absolute EB was rounded down to a power of two.
Definition quantizer.h:47
uint32_t quant_radius
Quantization radius.
Definition quantizer.h:35
float user_error_bound
Definition quantizer.h:32
DataType input_type
Original input type (1B).
Definition quantizer.h:38
float abs_error_bound
Absolute EB after mode conversion (0 for REL).
Definition quantizer.h:31
float dither_strength
Dither offset amplitude as a fraction of abs_eb, in (0,1]; meaningful only when dither.
Definition quantizer.h:50
uint8_t _pad[3]
Alignment padding (dither_seed needs 8-byte alignment) — must be zero.
Definition quantizer.h:48
float outlier_threshold
ABS/NOA: |x| >= threshold → forced outlier (inf = disabled).
Definition quantizer.h:42
uint8_t dither
1 if "_R"-style dithered reconstruction is enabled (LC QUANT_*_R).
Definition quantizer.h:45
uint8_t linear_high_precision
1 if linear coordinates are evaluated in double precision.
Definition quantizer.h:46
float value_base
value_range (NOA); 0 for ABS/REL.
Definition quantizer.h:34
Definition quantizer.h:139
float outlier_threshold
ABS/NOA: |x| >= threshold → lossless outlier (LC reference threshold). Default: ∞.
Definition quantizer.h:150
bool dither
Definition quantizer.h:182
float outlier_capacity
Fraction of input size reserved for outliers.
Definition quantizer.h:142
bool zigzag_codes
Definition quantizer.h:148
bool power_of_two_bound
Definition quantizer.h:172
uint64_t dither_seed
Definition quantizer.h:185
float precomputed_value_base
Pre-computed value_base > 0 to skip the NOA data scan; 0 = auto.
Definition quantizer.h:145
bool inplace_outliers
Definition quantizer.h:154
int quant_radius
Quantization radius.
Definition quantizer.h:141
bool linear_mode
Definition quantizer.h:161
double error_bound
Error bound (interpretation set by eb_mode).
Definition quantizer.h:140
bool linear_high_precision
Definition quantizer.h:166
float dither_strength
Definition quantizer.h:192
Definition chunk_op_params.h:27
Backend-neutral GPU type aliases.