fastalp 0.1.28

World's fastest and highest-ratio lossless floating-point compression / 全球最快、压缩比最高的通用时序浮点无损压缩
Documentation

English | 中文

crates.io docs.rs


fastalp : World's Fastest and Highest-Ratio Lossless Time-Series Floating-Point Compression

Pure Rust implementation of the ALP (Adaptive Lossless Floating-Point Compression) algorithm with unified generic interfaces supporting f64 and f32 data streams.


Overview

Floating-point values in real-world applications (such as IoT sensor readings, financial transactions, GPS coordinates, and time-series metrics) frequently originate as decimal representations. Traditional general-purpose compression algorithms and integer bitpackers operate inefficiently on IEEE 754 representations due to distributed exponent and mantissa bit patterns.

fastalp implements the ALP compression algorithm:

  • Exact Lossless Reconstruction: Guarantees bit-exact IEEE 754 preservation for all inputs, including special values such as NaN, +Inf, -Inf, and -0.0.

  • Compact Self-Describing Header & Large Array Support: Features a 2-bit length tag header layout where standard 1024-element blocks require only a 3-byte compressed header (and just 1 byte in raw fallback mode). Natively scales beyond 65,535 elements by auto-upgrading to 32-bit count and exception index fields, removing single-block size limits.

  • Adaptive Delta Differential Encoding (Delta-ALP): Automatically evaluates smooth and continuous physical time series (weather, hydrology, telemetry), adaptively applying first-order differences and branchless prefix sum accumulation to reduce bit widths by 15% to 38%.

  • Decimal Division Exact Mode: Completely eliminates IEEE 754 multiplication roundoff errors (such as * 0.1) by reconstructing via exact decimal division, driving outlier exception counts to zero on real-world telemetry.

  • Stack-Allocated LUT & SIMD Hybrid Decompression: Utilizes 256-entry stack lookup tables for division modes to eliminate hardware division latencies, coupled with pure-register SIMD auto-vectorization for linear arithmetic exceeding 55+ GB/s throughput.

  • Adaptive Parameter Estimation: Samples input sequences to derive optimal scaling parameters (exp, fac, use_div) that minimize bit-width requirements.

  • Frame-of-Reference & Bitpacking: Encodes converted integers using base subtraction (FOR / Delta) and dense bit-packing from 1 to 64 bits per value.

  • Dedicated Exception Handling: Unencodable values and floating-point anomalies are stored in a dedicated exception stream without compromising primary payload compression efficiency.

  • Raw Fallback Protection: Automatically falls back to uncompressed raw mode when noise or extreme precision values would cause negative compression.

  • Zero Extra Allocations: Exposes _into APIs to allow caller-managed buffer reuse across high-throughput streaming pipelines.

  • Unified Generic Interface: compress, compress_into, decompress, and decompress_into work across both f64 and f32.


Usage

Installation

cargo add fastalp

Basic Compression and Decompression

use fastalp::{compress, decompress, Result};

fn main() -> Result<()> {
  let sensor_data = vec![20.5, 20.6, 20.8, 21.0, 20.9, 21.2];

  // Compress floating-point slice into byte buffer (generic for f64 / f32)
  let compressed = compress(&sensor_data);

  // Decompress byte buffer back to exact f64 slice
  let decompressed: Vec<f64> = decompress(&compressed)?;

  assert_eq!(decompressed, sensor_data);
  Ok(())
}

In-Place Buffer Reuse

use fastalp::{compress_into, decompress_into, Result};

fn main() -> Result<()> {
  let batch = vec![100.12, 100.15, 100.18, 100.22];

  let mut compressed_buf = Vec::new();
  compress_into(&batch, &mut compressed_buf);

  let mut restored = Vec::new();
  decompress_into(&compressed_buf, &mut restored)?;

  assert_eq!(restored, batch);
  Ok(())
}

Stateful Encoding with Parameter Caching

For streaming and columnar scenarios, use Encoder to cache optimal parameters and reuse internal scratch memory across adjacent chunks:

use fastalp::{decompress, Encoder, Result};

fn main() -> Result<()> {
  let mut encoder = Encoder::<f64>::with_capacity(1024);

  let chunk1: Vec<f64> = (0..1024).map(|i| 25.0 + (i as f64) * 0.25).collect();
  let chunk2: Vec<f64> = (1024..2048).map(|i| 25.0 + (i as f64) * 0.25).collect();

  let mut compressed = Vec::new();

  // First chunk: samples and caches optimal parameters
  encoder.compress_into(&chunk1, &mut compressed);

  // Second chunk: hits cache and skips sampling, boosting throughput
  compressed.clear();
  encoder.compress_into(&chunk2, &mut compressed);

  let restored: Vec<f64> = decompress(&compressed)?;
  assert_eq!(restored, chunk2);

  // Reset cache when switching streams
  encoder.reset();
  Ok(())
}

Single-Precision Floating-Point Data

use fastalp::{compress, decompress, Result};

fn main() -> Result<()> {
  let coordinates = vec![116.4074f32, 39.9042f32, 121.4737f32, 31.2304f32];

  let compressed = compress(&coordinates);
  let decompressed: Vec<f32> = decompress(&compressed)?;

  assert_eq!(decompressed, coordinates);
  Ok(())
}

Features

  • Bit-Exact Precision: Decoded floats match original bit patterns (a.to_bits() == b.to_bits()).

  • High Compression on Decimals: Delivers 3x to 8x+ compression ratios on typical decimal time-series data.

  • Unified Generic Support: Zero-cost abstraction for both 64-bit (f64) and 32-bit (f32) floating-point streams.

  • Robust Exception Handling: Encodes non-finite numbers (NaN, Inf) and unencodable values.

  • Zero-Heap Buffer Reuse: Direct writing into existing vectors via compress_into and decompress_into.


Architecture & Design

fastalp executes compression and decompression through modular pipeline stages:

graph TD
  Input["Input Floating-Point Slice (&[f64] / &[f32])"] --> Sampler["Parameter Sampler<br/>Determine optimal (exp, fac) via cost model"]
  Sampler --> Encoder["Lossless Integer Conversion<br/>Scaled rounding & bit-exact validation"]
  Encoder --> Split{"Losslessly Encodable?"}
  Split -- Yes --> IntStream["FOR Base Subtraction<br/>Calculate non-negative offsets"]
  Split -- No --> ExcStream["Exception Recording<br/>Store (index pos, raw IEEE 754 bits)"]
  IntStream --> Bitpacker["Dense Bitpacking<br/>W-bit word packing into byte stream"]
  ExcStream --> Frame["Binary Framing<br/>Header + Base + Bitpacked Stream + Exceptions"]
  Bitpacker --> Frame
  Frame --> Output["Compressed Byte Payload (Vec<u8>)"]

Compression Pipeline

  • Constant Detection & Fallback Filter (encoder.rs): Quickly evaluates bit-exact identical sequences (v.is_exact_same(first)). When identical, writes a self-describing compact header and base value with zero heap allocation. When estimated payload exceeds raw size plus compact header overhead, switches to raw mode (1 byte for 1024 blocks) to guarantee zero data inflation.

  • Sampling (sampler.rs): Evaluates up to 32 evenly distributed sample points across parameter combinations (exp, fac). Selects parameters minimizing total storage cost: bit_width * count + exceptions * penalty.

  • Lossless Verification (sampler.rs, float.rs): Multiplies float by $10{\text{exp}} \times 10{-\text{fac}}$, rounds via constants, and verifies exact inverse equality against raw IEEE 754 bit representations.

  • Base Offset & Bitpacking (bitpack/pack.rs, encoder.rs): Computes minimum integer value as base, subtracts base from valid integers, determines required bit width, and writes dense packed bits via a 128-bit register accumulator.

  • Exception Stream (encoder.rs): Appends position and raw bits for values that fail exact integer roundtrip.

Decompression Pipeline

  • Header Parsing (header.rs, decoder.rs): Reads descriptor byte and decodes element count via 2-bit length tags to locate parameter offsets. For raw fallback chunks, performs direct zero-copy slice restoration. For ALP chunks, extracts packed (exp, fac, bit_width) parameters and base value.

  • Bit Unpacking & SIMD Register Reconstruction (bitpack/unpack.rs): Bit-widths of 8, 16, 32, and 64 bits employ pure register SIMD auto-vectorization, eliminating gather lookups and cache stalls; Ultra-small bit-widths (1, 2, 4 bits) leverage compact register-resident tables for rapid reconstruction.

  • Exception Patching (decoder.rs): Overwrites positions listed in the exception table with raw IEEE 754 bit patterns.


Tech Stack

  • Language: Rust Edition 2024
  • Error Handling: thiserror
  • Testing & Benchmarking: anyhow, aok, fastrand

Directory Structure

fastalp/
├── Cargo.toml          # Crate manifest and dependency configuration
├── README.md           # Generated multilingual documentation
├── README.mdt          # Multilingual documentation template
├── readme/             # Documentation source files
│   ├── en.md           # English documentation
│   └── zh.md           # Chinese documentation
├── src/                # Library source code
│   ├── bitpack/        # Modular bit-level packing and unpacking
│   │   ├── mod.rs      # Module facade and re-exports
│   │   ├── pack.rs     # Dense bitpacking with 128-bit register accumulator
│   │   └── unpack.rs   # Direct bit unpacking with stack LUT acceleration
│   ├── constants.rs    # Precomputed static power tables and format constants
│   ├── decoder/        # Generic decompression pipeline & decimal division reconstruction
│   │   ├── mod.rs      # Decompression facade and mode dispatch
│   │   ├── standard.rs # Standard FOR reconstruction
│   │   └── delta.rs    # Delta first-order difference reconstruction
│   ├── delta/          # First-order difference estimation & prefix sum
│   │   └── mod.rs
│   ├── encoder/        # Generic compression pipeline & parameter caching
│   │   ├── mod.rs      # Compression facade and top-level convenience functions
│   │   ├── state.rs    # Stateful Encoder struct and scratch buffer reuse
│   │   ├── engine.rs   # Compression orchestration engine and 3-tier validation
│   │   ├── kernel.rs   # 4-way branchless unrolled vectorized encoding kernels
│   │   ├── outlier.rs  # FOR mode outlier pruning algorithm
│   │   ├── exception.rs# Exception records and compact serialization
│   │   ├── standard.rs # Standard FOR frame assembly
│   │   └── delta.rs    # Delta differential frame assembly
│   ├── error.rs        # Error definitions and Result type alias
│   ├── float/          # AlpFloat abstraction trait and f32/f64 zero-cost implementation
│   │   ├── mod.rs      # AlpFloat trait and lookup table generator
│   │   ├── f32.rs      # Single-precision f32 implementation
│   │   └── f64.rs      # Double-precision f64 implementation
│   ├── header.rs       # Compact self-describing header encoding/decoding & 2-bit length tags
│   ├── lib.rs          # Public crate exports and high-level API
│   ├── params.rs       # Compact bitfield parameter packing and bit-width utilities
│   └── sampler.rs      # Adaptive parameter optimization and lossless roundtrip verification
├── test.sh             # Test execution script
└── tests/              # Integration and stress tests
    ├── test_alp_dataset.rs # ALP paper 31 real-world datasets roundtrip & ratio tests
    ├── test_delta.rs       # Delta differential time series test suite
    └── test_roundtrip.rs   # Roundtrip integrity and boundary tests

Benchmarks & Cross-Algorithm Comparison

Benchmark Environment & Toolchain

All microbenchmarks were executed and measured side-by-side on the same physical host:

  • Processor (CPU): Apple M2 Max (12 Cores: 8 Performance @ 3.68 GHz + 4 Efficiency @ 2.42 GHz, ARMv8.6-A NEON ISA)
  • Host OS: macOS Sequoia 26.5.1 (Darwin Kernel Version 25.5.0 arm64)
  • Rust Toolchain: rustc 1.98.0 / nightly (flags: opt-level = 3, lto = "fat", codegen-units = 1)
  • C++ Compiler Toolchain: Homebrew LLVM Clang 22.1.8 (-O3 -std=c++17 -DNDEBUG -march=native) / CMake 4.4.2
  • Memory Allocator: mimalloc 0.1.52
  • Benchmark Suites: Rust divan 0.1.20 vs C++ std::chrono::high_resolution_clock (steady-state median sampling)

Cross-Algorithm Benchmark Comparison

Evaluated side-by-side across industry-standard floating-point and time-series compression codecs on identical hardware and data streams:

  • fastalp (Rust Edition 2024, SIMD NEON)
  • C++ ALP (Official paper reference implementation, Clang 22.1.8 -O3)
  • Pcodec / pco 1.0.3 (Columnar numeric compression, ANS entropy coding)
  • Zstandard / zstd 0.13 (General dictionary compression, Level 3)
  • LZ4 / lz4_flex 0.14 (Ultra-fast general byte compressor)
  • Snappy / snap 1.1 (Google high-speed byte compressor)
  • Chimp128 (VLDB 2022 floating-point time series)
  • Gorilla (VLDB 2015 XOR floating-point time series)

C++ ALP Benchmark Methodology & Criteria Unification

  • C++ ALP Fork Repository: github.com/x-at-01/ALP
  • Methodology & Architectural Verification:
    • Zero Modifications to Core Logic: The fork preserves all core algorithm implementations in include/ 100% untouched, ensuring true reference fidelity;
    • End-to-End Pipeline vs. Kernel-Only Criteria Unification:
      • Kernel-Only Phase (Original Paper Criteria, ~4.3 GB/s): The original C++ ALP benchmark suite (ALP/benchmarks/benchmark.cpp) invoked alp::encoder<PT>::init outside the timing loop, assuming the optimal exponent and factor were pre-determined. It measured only the pure floating-point transform and bitpacking kernel, which yielded ~4 GB/s in the paper;
      • End-to-End Pipeline (Unified Criteria in this Benchmark, 0.8 GB/s): In real-world time-series ingestion, new blocks cannot know optimal parameters in advance and must undergo sampling. In our fork, init is integrated into the benchmark loop to measure realistic ingestion performance. Because C++ ALP employs exhaustive parameter search without pruning, sampling consumes over 80% of total CPU cycles, resulting in a measured end-to-end throughput of 0.8 GB/s;
      • fastalp End-to-End Performance (5.5 GB/s): fastalp likewise executes the complete end-to-end pipeline (including sampling analysis from scratch). Equipped with a 3-tier micro-architectural pruning pipeline (decimal early exit, 4-sample prescreening, division exception filtering), it achieves 5.5 GB/s end-to-end (7.0x speedup over C++ ALP);
    • Full 37 Datasets Evaluated:
      • All 6 industrial scenario datasets were integrated into data/samples/ and your_own_dataset.csv, ensuring C++ ALP executed the complete suite of all 37 datasets (31 paper datasets + 6 industrial scenarios) on the exact same physical host;
      • All algorithms adopt Geometric Mean across all 37 benchmarks without sampling bias.

Evaluation Datasets & Authoritative Data Sources (All 37 Benchmarks)

This benchmark adopts all 31 real-world public time-series and columnar datasets from the original ALP publication, augmented with 6 industrial scenarios (37 benchmarks in total) spanning 6 core domains:


Architecture Evolution & Optimization Breakdown

fastalp is not a literal translation, but an engineering overhaul engineered to fully exploit modern superscalar pipelines while solving the core pain points of columnar time-series storage.

1. Architecture Patterns Adopted & Refined from C++ ALP (And Their Purposes)

  1. Stateful Encoder & Parameter Caching:
    • Purpose: Eliminates the high cost of re-sampling and evaluating dozens of parameter combinations for every single chunk during continuous writes.
    • Mechanism: In continuous time-series streams, adjacent 1024-element blocks of the same column share identical unit magnitudes and decimal precision. fastalp caches the best exp and fac from previous blocks. When verified against the current block, it skips exhaustive sampling entirely, raising continuous compression throughput from ~4-5 GB/s to 15-20+ GB/s.
  2. 12.5% Exception Threshold RAW Fallback:
    • Purpose: Prevents space expansion ("negative compression") on high-entropy floats.
    • Mechanism: When exception counts exceed 128 (12.5% of a 1024 block), the block is proven unsuitable for decimal transformation. fastalp instantly aborts further encoding and falls back to a compact single-byte header RAW stream, preventing the 2x space expansion seen in naive schemes.
  3. Decimal Division Exact Mode:
    • Purpose: Eliminates "pseudo-exceptions" caused by IEEE 754 multiplication rounding errors.
    • Mechanism: Multiplying by floating-point powers (e.g., * 0.1) introduces inexact binary truncation. fastalp uses precise decimal division during reconstruction, eliminating pseudo-exceptions and reducing compressed size by 20% to 38% on real physical sensor data.

2. Novel High-Performance Optimizations Invented in fastalp (And Their Purposes)

To break through the throughput limits and compression ceiling of the original C++ reference, fastalp engineered the following architectural innovations:

  1. 3-Tier Microarchitectural Sampling Pruning Pipeline:
    • Purpose: Solves the severe bottleneck in C++ ALP where exhaustive factor exploration consumed over 80% of CPU time, throttling end-to-end ingestion throughput to 0.83 GB/s.
    • Mechanism: Introduces a 3-tier cascade: Tier 1 (Pure Decimal Early Exit) validates the basic decimal exponent against 32 samples; if 100% losslessly representable with zero exceptions, it immediately returns optimal parameters without testing any of the 170 candidate factors. Tier 2 (4-Sample and 16-Sample Prescreening) tests candidate factors with 4 samples first, discarding subpar candidates before evaluating all 32 samples. Tier 3 (Non-Decimal Scientific Early Exit) instantly halts factor search if the basic decimal exponent produces 100% exceptions. This drives end-to-end ingestion throughput from 0.83 GB/s to 3.91 GB/s (4.7x speedup, up to 7.0x in specific blocks).
  2. Pure-Register SIMD Auto-Vectorized Decoding:
    • Purpose: Eliminates memory gather latencies and cache miss stalls common in traditional bit-unpacking loops.
    • Mechanism: For common bit-widths (8, 16, 32, 64 bits), the decoder is implemented as branchless, unrolled parallel SIMD sequences targeting ARM NEON and x86 AVX2 vector registers, reaching 23.59 GB/s geometric mean.
  3. 256-Entry Stack-Allocated L1D Lookup Table:
    • Purpose: Eliminates multi-cycle hardware floating-point division latencies and dynamic memory allocations in inner loops.
    • Mechanism: For small bit-widths (1, 2, 4 bits) and decimal division reconstruction, constructs a 256-entry table directly on the stack frame. Operating 100% within CPU L1D cache, it replaces 30+ cycle hardware division instructions with single L1D cache lookups.
  4. Fused Delta Bitpacking Pipeline:
    • Purpose: Eliminates the memory bandwidth and cache pollution of allocating and writing an intermediate 8KB difference buffer.
    • Mechanism: Conventional compressors run two passes: compute diffs into an 8KB memory slice, then read it back for bitpacking. fastalp's 8-way register pipeline computes adjacent deltas, subtracts the baseline, and shifts bits into a 128-bit packing accumulator in a single fused pass with zero memory writes and zero heap allocations, boosting delta compression throughput by >30%.
  5. Mathematical Delta Early Pruning:
    • Purpose: Prevents expensive full-chunk differencing on disordered or oscillating series.
    • Mechanism: By the mathematical axiom that subset extrema difference is always $\le$ global extrema difference, fastalp samples the first 16 points. If their delta bit-width already matches or exceeds FOR bit-width, delta encoding is mathematically proven to be non-beneficial, exiting instantly.
  6. 4-Way Loop Unrolling & Zero-Closure Pipeline:
    • Purpose: Maximizes instruction-level parallelism (ILP) across modern CPU superscalar ALUs.
    • Mechanism: Completely avoids dynamic closures and indirect branches in the inner loop. Inlines a dedicated 4-way unrolled pipeline that processes 4 values per iteration through registers without exception checks when within range, achieving 4.4~6.8 GB/s compression throughput.
  7. Single-Cycle Identical Floats Fast-Skip:
    • Purpose: Instantaneous compression of idle sensor heartbeats and disconnected lines.
    • Mechanism: Uses a single slice[1] == slice[0] equality check at the encoder entrance. Non-identical blocks cost only 1 CPU cycle to bypass; identical blocks encode into an 11-byte packet in 350 ns (744x compression ratio).
  8. Outlier Pruning with 0-bit Compression:
    • Purpose: Unlocks >150x compression on series with 99% identical base values and rare spikes (e.g., gov30).
    • Mechanism: Isolates rare pulse values into the exception dictionary, allowing the main bitstream to use a 0-bit bit-width (storing only length and baseline). Combined with 16-sample outlier pre-screening, high-entropy blocks exit within 2 samples with zero penalty.
  9. Compact 2-bit Tagged Header & Large Array Scalability:
    • Purpose: Minimizes framing overhead and removes single-block 65,535 element truncation limits.
    • Mechanism: Uses a self-describing 2-bit length tag layout where standard 1024-element blocks require only 3 header bytes (and 1 byte in RAW fallback mode). Seamlessly auto-promotes to 32-bit count and exception offsets for large arrays, removing artificial chunking boundaries.
  10. Batched Stack Buffer for Exceptions:
    • Purpose: Eliminates memory fragmentation and vector reallocation during exception handling.
    • Mechanism: Gathers exception indices and IEEE 754 bit representations in fixed-size stack arrays and writes them to the output buffer in a single batch, halving vector management overhead.
  11. Zero-Heap Allocation Streaming APIs:
    • Purpose: Completely avoids garbage collection and heap allocation overhead in high-throughput streaming systems.
    • Mechanism: Exposes compress_into and decompress_into APIs that allow callers to reuse pre-allocated memory buffers across batches without extra heap allocations.
  12. Unified Zero-Cost Generic Abstraction with Precomputed Tables:
    • Purpose: Provides a single unified implementation for f64 and f32 with zero abstraction overhead.
    • Mechanism: Implemented via the AlpFloat trait, backed by compile-time static tables for powers of 10 and reciprocal multipliers, ensuring full compiler inlining and zero runtime branching overhead.

fastalp : 全球最快、压缩比最高的通用时序浮点无损压缩

纯 Rust 实现的自适应无损浮点数压缩 ALP 算法库,通过统一泛型接口支持 f64f32 数据流。


功能特性

在物联网传感器采集、金融量化交易、GPS 经纬度定位以及时序监控等场景中,浮点数据通常以十进制形式产生。 由于 IEEE 754 浮点数的阶码与尾数位分布离散,通用压缩算法与整型位打包算法难以获得理想的压缩效率。

fastalp 实现 ALP 压缩算法:

  • 严格无损重构 保证解码数据与原始 IEEE 754 二进制位严格一致,支持 NaN+Inf-Inf-0.0 等特殊值。

  • 紧凑自描述头与超大数组支持 采用 2-bit 长度标签紧凑头部架构,标准 1024 满块压缩头仅占 3 字节,RAW 保底模式仅占 1 字节; 原生支持超过 65,535 元素的超大数组,自动升级为 4 字节数量与 4 字节异常索引,解除单块长度截断限制。

  • 时序差分自适应编码 自动评估连续平滑的时序物理波形(气象、水文、传感器),自适应采用一阶相邻差分与前缀和递推,位宽进一步收窄 15% ~ 38%。

  • 十进制精确除法重构 消除 IEEE 754 浮点乘法(如 * 0.1)引起的无限循环二进制尾数截断误差,以十进制除法精确重构,将观测时序异常点直接归零。

  • 栈上 LUT 查表与 SIMD 混合加速 小位宽利用 256 项栈上查找表(L1D 缓存命中)消除循环内硬件除法延迟;对直接模式采用纯寄存器 SIMD 向量化计算,吞吐高达 55+ GB/s。

  • 自适应参数推导 通过对输入数据进行采样,计算使编码位宽最小的最优参数组合 (exp, fac, use_div)

  • 基准偏移与位打包 将转换后的整型序列进行基准值消除(FOR / Delta),并按 1 至 64 位动态位宽进行密集位打包。

  • 独立异常值处理 无法无损整型化的数值与特殊浮点数记录于独立异常流,避免降低主数据流压缩比。

  • 原始保底模式 当随机噪声或不可压缩数据导致编码后体积膨胀时,自动回退至原始保底模式,杜绝负压缩。

  • 零额外分配复用 提供 _into 系列接口,支持调用方直接复用已有内存缓冲区。

  • 统一泛型接口 compresscompress_intodecompressdecompress_into 统一适用于 f64f32


使用示例

添加依赖

cargo add fastalp

基础压缩与解压

use fastalp::{compress, decompress, Result};

fn main() -> Result<()> {
  let sensor_data = vec![20.5, 20.6, 20.8, 21.0, 20.9, 21.2];

  // 压缩浮点数切片为字节向量 (自动适配 f64 / f32)
  let compressed = compress(&sensor_data);

  // 解压字节向量恢复原始浮点数切片
  let decompressed: Vec<f64> = decompress(&compressed)?;

  assert_eq!(decompressed, sensor_data);
  Ok(())
}

内存缓冲区复用

use fastalp::{compress_into, decompress_into, Result};

fn main() -> Result<()> {
  let batch = vec![100.12, 100.15, 100.18, 100.22];

  let mut compressed_buf = Vec::new();
  compress_into(&batch, &mut compressed_buf);

  let mut restored = Vec::new();
  decompress_into(&compressed_buf, &mut restored)?;

  assert_eq!(restored, batch);
  Ok(())
}

状态化编码与参数缓存(消除重复采样)

针对连续数据块流式压缩场景,使用 Encoder 缓存采样参数并复用内部工作内存,消除重复采样开销:

use fastalp::{decompress, Encoder, Result};

fn main() -> Result<()> {
  let mut encoder = Encoder::<f64>::with_capacity(1024);

  let chunk1: Vec<f64> = (0..1024).map(|i| 25.0 + (i as f64) * 0.25).collect();
  let chunk2: Vec<f64> = (1024..2048).map(|i| 25.0 + (i as f64) * 0.25).collect();

  let mut compressed = Vec::new();

  // 第一个块:采样探测最优参数并缓存
  encoder.compress_into(&chunk1, &mut compressed);

  // 第二个块:命中参数缓存,跳过全量采样,吞吐大幅提升
  compressed.clear();
  encoder.compress_into(&chunk2, &mut compressed);

  let restored: Vec<f64> = decompress(&compressed)?;
  assert_eq!(restored, chunk2);

  // 切换不同数据流时重置缓存
  encoder.reset();
  Ok(())
}

单精度浮点数据处理

use fastalp::{compress, decompress, Result};

fn main() -> Result<()> {
  let coordinates = vec![116.4074f32, 39.9042f32, 121.4737f32, 31.2304f32];

  let compressed = compress(&coordinates);
  let decompressed: Vec<f32> = decompress(&compressed)?;

  assert_eq!(decompressed, coordinates);
  Ok(())
}

核心特性

  • 位级精确无损 解码浮点数与原始输入在二进制位层面保持一致(a.to_bits() == b.to_bits())。

  • 十进制高压缩比 在常见十进制浮点序列上可获得 3x 至 8x+ 压缩比。

  • 统一泛型支持 单一接口支持 f64f32 零成本抽象编解码。

  • 完整异常值支持 支持 NaN、无穷大与不可无损转换的高精度浮点数。

  • 零堆分配接口 通过 compress_intodecompress_into 直接写入现有缓冲区。


架构设计

fastalp 编解码流程划分为以下阶段:

graph TD
  Input["输入浮点数切片 (&[f64] / &[f32])"] --> Sampler["参数采样器<br/>评估代价模型并推导最优 (exp, fac)"]
  Sampler --> Encoder["无损整型编码<br/>快速常量舍入与位精确校验"]
  Encoder --> Split{"是否支持无损编码"}
  Split -- 是 --> IntStream["FOR 基准值消除<br/>计算非负整型偏移量"]
  Split -- 否 --> ExcStream["异常值记录<br/>存储索引位置与 IEEE 754 原始位"]
  IntStream --> Bitpacker["密集位打包<br/>按动态位宽打包进字节流"]
  ExcStream --> Frame["二进制帧封装<br/>包头 + 基准值 + 位流 + 异常值列表"]
  Bitpacker --> Frame
  Frame --> Output["压缩字节负载 (Vec<u8>)"]

压缩流程

  • 全等探测与保底分流 (encoder.rs) 先对数据进行常数序列快速校验;若全等且可编码,直接写入自描述紧凑头部与基准值; 若为不可压缩随机数据且编码体积超过原始大小加上极简头部,则自动回退至原始保底模式(1024 满块仅 1 字节头部),直接以原始字节流存储。

  • 采样评估 (sampler.rs) 在数据序列中均匀采样至多 32 个数值,遍历 (exp, fac) 参数组合, 选取使得 位宽 * 样本量 + 异常数 * 惩罚权重 最小的参数组合。

  • 无损转换与验证 (sampler.rs, float.rs) 将浮点数乘以 $10{\text{exp}} \times 10{-\text{fac}}$,利用常量完成快速向近舍入并转换为整型, 再通过反向整型乘法与逆缩放验证浮点位级一致性。

  • 基准消除与位打包 (bitpack/pack.rs, encoder.rs) 获取有效整型中的最小值作为基准值,计算偏移量并获取所需位宽, 利用 128 位寄存器滑动窗口将数值紧凑打包入字节流。

  • 异常流序列化 (encoder.rs) 无法无损转换的浮点数按索引位置与 IEEE 754 原始位记录于尾部异常表中。

解压流程

  • 自描述头解析 (header.rs, decoder.rs) 读取首字节描述符,由 2-bit 长度标签解码元素总数并确定参数偏移; 若类型为原始保底数据,通过内存复制直出恢复;若为 ALP 压缩数据,提取 (exp, fac, bit_width) 缩放参数与基准值。

  • 位流解包与 SIMD 寄存器流水重构 (bitpack/unpack.rs) 针对 8/16/32/64 bit 采用纯寄存器 SIMD 自动向量化计算,消除堆栈查表与内存间接 gather 寻址延迟;针对 1/2/4 bit 采用微型局部表快速还原。

  • 异常值覆盖 (decoder.rs) 若存在尾部异常表,读取对应索引位置的数值并覆盖为原始 IEEE 754 浮点值。


技术栈

  • 开发语言:Rust Edition 2024
  • 错误处理thiserror
  • 测试与基准anyhow, aok, fastrand

目录结构

fastalp/
├── Cargo.toml          # 项目配置与依赖声明
├── README.md           # 生成的多语言文档
├── README.mdt          # 多语言文档模板
├── readme/             # 文档源码目录
│   ├── en.md           # 英文技术文档
│   └── zh.md           # 中文技术文档
├── src/                # 核心源代码
│   ├── bitpack/        # 模块化位打包与位解包
│   │   ├── mod.rs      # 门面导出
│   │   ├── pack.rs     # 128 位累加器位打包算子
│   │   └── unpack.rs   # 局部查表与直接位解包算子
│   ├── constants.rs    # 静态幂次表与格式常量
│   ├── decoder/        # 泛型流式解压与除法重构
│   │   ├── mod.rs      # 解压门面与模式派发
│   │   ├── standard.rs # 标准 FOR 还原解压
│   │   └── delta.rs    # Delta 一阶差分解码
│   ├── delta/          # 一阶差分自适应收益评估与前缀和
│   │   └── mod.rs
│   ├── encoder/        # 泛型压缩流水线与参数缓存
│   │   ├── mod.rs      # 编码门面与顶层便捷函数
│   │   ├── state.rs    # 状态化 Encoder 结构体与工作缓冲区复用
│   │   ├── engine.rs   # 压缩编排引擎与参数三级校验
│   │   ├── kernel.rs   # 4-way 展开无分支向量化编码内核
│   │   ├── outlier.rs  # FOR 模式离群值剪枝算法
│   │   ├── exception.rs# 异常值结构与紧凑序列化
│   │   ├── standard.rs # 标准 FOR 编码组装
│   │   └── delta.rs    # Delta 一阶差分编码组装
│   ├── error.rs        # 错误枚举定义与 Result 类型别名
│   ├── float/          # AlpFloat 浮点抽象特征与泛型无损转换
│   │   ├── mod.rs      # AlpFloat trait 定义与查表构建
│   │   ├── f32.rs      # 单精度 f32 乘法/除法编解码实现
│   │   └── f64.rs      # 双精度 f64 乘法/除法编解码实现
│   ├── header.rs       # 紧凑自描述头部编解码与 2-bit 长度标签档位管理
│   ├── lib.rs          # 导出接口与高层封装
│   ├── params.rs       # 紧凑位域参数打包与位宽计算
│   └── sampler.rs      # 参数采样与无损重构验证
├── test.sh             # 测试运行脚本
└── tests/              # 集成与压力测试
    ├── test_alp_dataset.rs # ALP 论文 31 真实数据集往返与压缩比评测
    ├── test_delta.rs       # Delta 差分时序专项与异常测试
    └── test_roundtrip.rs   # 往返无损与边界测试

性能评测与多算法对比

测试环境与编译配置

所有基准测试均在同一物理机上执行并进行同机对比测试:

  • 处理器: Apple M2 Max (12 核心:8 性能核 @ 3.68 GHz + 4 能效核 @ 2.42 GHz, ARMv8.6-A NEON 指令集)
  • 操作系统: macOS Sequoia 26.5.1 (Darwin Kernel Version 25.5.0 arm64)
  • Rust 编译工具链: rustc 1.98.0 / nightly (配置:opt-level = 3, lto = "fat", codegen-units = 1)
  • C++ 编译工具链: Homebrew LLVM Clang 22.1.8 (-O3 -std=c++17 -DNDEBUG -march=native) / CMake 4.4.2
  • 内存分配器: mimalloc 0.1.52
  • 基准测试框架: Rust divan 0.1.20 微基准套件 vs C++ std::chrono::high_resolution_clock(稳态中位数采样)

主流浮点与时序压缩算法同机横向对比

在完全相同的测试硬件与数据负载下,对比业界主流浮点与时序压缩库:

  • fastalp (Rust Edition 2024, SIMD NEON)
  • C++ ALP (论文原版实现, Clang 22.1.8 -O3)
  • Pcodec / pco 1.0.3 (现代列式数值压缩, ANS 熵编码)
  • Zstandard / zstd 0.13 (通用流式字典压缩, Level 3)
  • LZ4 / lz4_flex 0.14 (极速通用字节压缩)
  • Snappy / snap 1.1 (Google 高速字节压缩)
  • Chimp128 (VLDB 2022 浮点时序压缩)
  • Gorilla (VLDB 2015 XOR 浮点时序压缩)

C++ ALP 测试机制与统计口径说明

  • C++ ALP Fork 仓库地址github.com/x-at-01/ALP
  • 统计口径统一与测试机制说明
    • 核心算法保持 100% 官方原貌:Fork 仓库未对 C++ ALP 的核心算法逻辑(include/ 目录)做任何修改,原汁原味保留官方实现的向量化与十进制反向映射逻辑;
    • 端到端全流程 vs 纯编码内核的口径统一
      • 纯编码内核(原论文测试口径,约 4.3 GB/s):C++ ALP 官方原版测试代码(ALP/benchmarks/benchmark.cpp)在计时循环外调用了 alp::encoder<PT>::init,假设已预先获知最佳指数与因子,仅测量跳过采样后的“纯浮点变换 + 位打包”内核速度,因此在原论文中录得约 4 GB/s 吞吐;
      • 端到端全量流水线(本文统一评测口径,0.8 GB/s):在真实时序写入时,新数据块无法预知最佳模型参数,必须经历采样分析。为了公平衡量工程实际性能,我们在 Fork 仓库中将 init 采样分析纳入计时循环。由于 C++ ALP 采用无剪枝的暴力全量穷举,采样阶段占用了 80% 以上的时间,其实际端到端吞吐测得为 0.8 GB/s
      • fastalp 的端到端表现(5.5 GB/s):fastalp 同样执行完整的全量端到端压缩(含从零采样分析),得益于 3 层采样微架构剪枝(纯十进制早停、4 采样快筛、除法异常过滤),端到端吞吐达到 5.5 GB/s(较 C++ ALP 端到端提速 7.0x);
    • 37 项数据集全量无偏实测
      • ALP/data/samples/your_own_dataset.csv 中补充了 6 大典型工业场景,使 C++ ALP 在本物理机上完整跑完全量全部 37 个评测数据集(31 个论文公开数据集 + 6 个工业场景补充数据集);
      • 所有算法统一采用全量 37 项评测数据计算几何平均值(Geometric Mean),杜绝任何采样偏倚。

评测数据集全景与公开数据源(共 37 项)

本评测采用 ALP 官方论文收录的全部 31 个公开时序与列存测试集,并补充 6 个典型工业场景样本(共 37 项基准),覆盖 6 大业务领域:


架构演进与优化全景

fastalp 并非简单的语言转译,而是在完整吸收 C++ ALP 论文精髓的基础上,针对现代多核流水线与时序数据库列存痛点重构的高性能压缩引擎。

一、参考与借鉴 C++ ALP 的架构设计

在架构演进中,fastalp 完整保留并吸收了 C++ ALP 经数学严密证明的优秀工业设计:

  1. 状态化编码器与跨块参数缓存
    • 用途:解决时序数据库连续写入时频繁重复采样的性能瓶颈。
    • 机制:在工业时序流中,同一指标列(如温度)相邻数据块的量纲和精度具有高度连续性。fastalp 借鉴 C++ 设计,支持跨 1024 块复用上一数据块探测出的指数 exp 与因子 fac。连续写入时直接跳过昂贵的全部样本扫描,使连续压缩吞吐由 45 GB/s 跃升至 **1520+ GB/s**。
  2. 12.5% 异常阈值保底回退
    • 用途:彻底消除高熵浮点数(如高精 GPS 坐标、科学计算随机数)压缩时空间膨胀的“负压缩”隐患。
    • 机制:当异常值数量超过 128 个(占 1024 元素的 12.5%)时,强制判定该数据块不可有效进行十进制变换,立即终止后续分析,直接降级存储为单字节头部的 RAW 紧凑原始流,杜绝 C++ 原版中曾出现的 2 倍体积膨胀。
  3. 十进制除法重构模式
    • 用途:消除 IEEE 754 乘法舍入误差导致的“虚假异常点”。
    • 机制:浮点乘法 x * 0.1 无法精确表示十进制小数,会导致大量本可无损还原的工业传感器数据(如 12.3)因尾数截断误差而被误判为不可缩放的异常。fastalp 借鉴并优化了除法重构模式,以精确除法将虚假异常彻底清零,使真实环境传感数据的每点占用减少 20%~38%。

二、fastalp 自主研发的极致原创优化

为了突破 C++ 原版的吞吐上限与时序压缩率天花板,fastalp 自主研发了以下核心架构创新:

  1. 三级级联微架构采样剪枝流水线
    • 用途:解决 C++ 原版暴力穷举导致采样耗时超 80%、端到端吞吐仅 0.83 GB/s 的核心瓶颈。
    • 机制:首创三级级联剪枝机制:第 1 级(纯十进制早停)对 32 个采样点进行基础十进制验证,无异常即刻确定参数返回,杜绝探索后续 170 种乘除因子;第 2 级(4 样本与 16 样本快筛)在评估候选因子时优先以 4 样本探测,超阈值即刻剪枝淘汰,避免全量 32 样本遍历;第 3 级(高熵科学浮点全面早停)若基础十进制异常率达 100%,判定为不可压缩科学高熵数据,直接跳出全部因子枚举。端到端编码吞吐因此从 0.83 GB/s 暴增至 3.91 GB/s(4.7x 提速,单场景最高达 7.0x)
  2. 纯寄存器 SIMD 自动向量化解压流水线
    • 用途:突破传统查表解压的内存寻址延迟与缓存未命中惩罚。
    • 机制:针对 8、16、32、64 等常见位宽,重构为零分支、纯寄存器的并行 SIMD 展开指令序列(利用 ARM NEON 与 x86 AVX2 硬件向量寄存器),消除 gather 内存间接读取与缓存停顿,几何平均解压吞吐达到 23.59 GB/s
  3. 256 项栈上 L1D 局部查找表加速除法与小位宽
    • 用途:消除循环体内耗费数十周期的硬件除法延迟与动态内存分配。
    • 机制:针对 1、2、4 位小位宽以及十进制除法重构模式,在函数栈上直接构建 256 项局部查找表,数据 100% 常驻 CPU L1D 缓存,将原本几十个时钟周期的浮点硬件除法运算转化为单次纳秒级 L1D 查表。
  4. 8 路寄存器级熔合差分位打包
    • 用途:消除差分压缩时 8KB 内存回写带来的内存带宽与缓存挤占开销。
    • 机制:传统实现采用“遍历计算差分写回 8KB 内存 + 读回内存做 Bitpacking”的双 pass 模式。fastalp 独创 8 路寄存器熔合流水线:在读取相邻元素求差的同时,直接减去基准,并流水线移位推入 128 位寄存器累加器打包输出,全过程零临时内存分配、零内存回写,差分压缩吞吐提升 30% 以上。
  5. 数学前置短路差分快筛
    • 用途:消除对无序/震荡数据无意义的全量一阶差分计算。
    • 机制:基于数学定理“局部子集的一阶极值跨度必小于等于全局极值跨度”,在决定是否启用差分模式时,仅探测前 16 个采样点。若前 16 项的差分位宽已大于等于 FOR 基准位宽,则数学证明全局差分绝不可能更优,即刻早停跳出,避免了 90% 非平滑序列的全量差分扫描。
  6. 4 路流水线无闭包展开编码
    • 用途:释放现代 CPU 超标量流水线的乱序执行与多算术逻辑单元(ALU)吞吐潜能。
    • 机制:将核心采样与整型缩放循环彻底消除动态闭包与间接跳转,特化为专用的 4 路展开指令流。连续 4 项无异常时走全寄存器极值更新路径,使压缩吞吐突破 4.4~6.8 GB/s
  7. 单次比较全等快跳
    • 用途:应对工业断线、设备待机与心跳常数流的极致瞬时压缩。
    • 机制:在编码入口仅用 1 次 slice[1] == slice[0] 快速比对。非全等序列仅耗费 1 个 CPU 时钟周期即可退出;全等序列仅需 11 字节即可压缩 1024 元素(压缩比高达 744x)。
  8. 智能离群点剪枝与 0-bit 稀疏常数压缩
    • 用途:针对 99% 为 0.0 仅有极少突变脉冲的数据集(如财政公共支出 gov30),实现百倍压缩比。
    • 机制:自动将少量脉冲离群值分离到异常字典中,主位流以 0-bit 存储,压缩体积从原版的 2100 字节骤降至 43 字节(压缩比突破 150x)。配合前 16 采样离群点快筛,高熵数据 2 个采样点即刻早停,零额外性能损耗。
  9. 2-bit 长度标签极简自描述帧头与超大数组原生支持
    • 用途:消除帧头冗余开销并打破 65,535 元素单块截断限制。
    • 机制:采用 2-bit 长度标签自描述格式,标准 1024 元素满块头仅需 3 字节,RAW 保底模式仅需 1 字节;对于超过 65,535 元素的超大数组,自动升级为 32 位数量与异常偏移字段,无需人为分块截断即可实现单帧无损编码。
  10. 栈缓冲融合与异常值单次批量提交
    • 用途:杜绝动态扩容与堆内存碎片。
    • 机制:解码与编码全程利用固定大小栈缓存;异常值位置索引与原始值在栈上定长组装后单次批量推入,将异常写出的系统开销降低 50%。
  11. 零堆分配流水线与内存缓冲区就地复用
    • 用途:高频流式管道中彻底杜绝 GC 与堆分配压力。
    • 机制:对外统一提供 compress_intodecompress_into 接口,支持上层应用预分配并永久复用底层向量缓冲区,在海量流式写入中实现真正的零额外堆内存分配
  12. 统一泛型零成本抽象与预计算常数表
    • 用途:一套代码兼顾 f64f32,杜绝代码膨胀与运行时分支开销。
    • 机制:通过 AlpFloat 特征将双精度与单精度浮点运算统一为泛型流水线,配合编译期预计算的 10 的幂次表与逆乘数表,实现无额外开销的极致内联。