#整数压缩 #数组 #解压缩 #速度 #编译 #mayda

nightly mayda_codec

由mayda_macros生成的函数的独立编译单元

5个版本

使用旧的Rust 2015

0.1.4 2017年9月21日
0.1.3 2016年7月13日
0.1.2 2016年6月20日
0.1.1 2016年6月13日
0.1.0 2016年6月11日

#492 in 压缩

37 每月下载量
mayda中使用

MIT/Apache

38KB
715

mayda

Build Status Latest Version Works on nightly

mayda是一个用于压缩整数数组的Rust库(支持所有原始整数类型)。设计上更注重解压缩速度和索引压缩数组的能力,而不是压缩比,基于压缩数组的使用在运行时应该尽可能小的原则。

此crate提供了一种压缩算法的三种变体。在2.6 GHz Intel Core i7-6700HQ处理器上,Uniform类型每秒可以解压缩约六十亿个u32,或24 GiB/s的解压缩整数(以下具体说明)。MonotoneUnimodal类型解压缩速度略低于一半,但根据整数的分布,可以具有更好的压缩比。总体性能与任何语言中最快的(已知)库相当。

编译mayda需要一个nightly编译器和支持SSE2指令集的CPU(任何2003年后制造的Intel或AMD处理器)。编译器版本在./rust-toolchain中进一步指定,以实现可重复性。基本方法在Zukowski2006Lemire2015中描述。

文档

模块文档提供了更多示例和涉及算法的更详细描述。

使用

将此添加到您的Cargo.toml

[dependencies]
mayda = "0.2"

并将此添加到您的crate根目录

extern crate mayda;

示例:编码和解码

Uniform结构推荐用于通用整数压缩。使用Encode特质来编码和解码数组。

extern crate mayda;

use mayda::{Uniform, Encode};

fn main() {
	// Integers in some interval of length 255, require one byte per integer
	let input: Vec<u32> = (0..128).map(|x| (x * 73) % 181 + 307).collect();

	let mut uniform = Uniform::new();
	uniform.encode(&input).unwrap();

	let i_bytes = std::mem::size_of_val(input.as_slice());
	let u_bytes = std::mem::size_of_val(uniform.storage());
	
	// 128 bytes for encoded entries, 12 bytes of overhead
	assert_eq!(i_bytes, 512);
	assert_eq!(u_bytes, 140);

	let output: Vec<u32> = uniform.decode();
	assert_eq!(input, output);
}

示例:索引

使用AccessAccessInto特质来索引压缩数组。这类似于Index,但返回一个向量而不是切片。

extern crate mayda;

use mayda::{Uniform, Encode, Access};

fn main() {
	// All primitive integer types supported
	let input: Vec<isize> = (-64..64).collect();

	let mut uniform = Uniform::new();
	uniform.encode(&input).unwrap();

	let val: isize = uniform.access(64);
	assert_eq!(val, 0);

	// Vector is returned to give ownership to the caller
	let range: Vec<isize> = uniform.access(..10);
	assert_eq!(range, (-64..-54).collect::<Vec<_>>());
}

性能

考虑以下三个向量

extern crate rand;

use rand::distributions::{IndependentSample, Range, Normal};

let mut rng = rand::thread_rng();
let length: usize = 1024;

// `input1` contains random integers
let mut input1: Vec<u32> = Vec::with_capacity(length);
let range = Range::new(0, 1024);
for _ in 0..length {
  input1.push(range.ind_sample(&mut rng));
}

// `input2` contains monotone increasing integers
let mut input2: Vec<u32> = input1.clone();
input2.sort();

// `input3` contains Gaussian distributed integers with outliers
let mut input3: Vec<u32> = Vec::with_capacity(length);
let gaussian = Normal::new(4086., 128.);
for _ in 0..length {
  input3.push(gaussian.ind_sample(&mut rng) as u32);
}
let index = Range::new(0, length);
let outliers = Range::new(0, std::u32::MAX);
for _ in 0..(length / 16) {
  input3[index.ind_sample(&mut rng)] = outliers.ind_sample(&mut rng);
}

以下是在2.6 GHz Intel Core i7-6700HQ处理器上对这些三个向量的UniformMonotoneUnimodal类型性能的测试结果。使用decode_into进行编码和解码的速度以每秒十亿个整数表示,索引最后一个条目所需时间以纳秒表示,压缩以每个整数比特数表示。本地编码和解码速度测量执行memcpy操作。香农熵是每个整数比特数的合理目标。

对于input1,香农熵为10.00。在一般情况下,Uniform在各个方面都是首选。

编码速度(BInt/s) 解码速度(BInt/s) 索引时间(ns) 比特/整数
Uniform 1.28 5.75 26 10.63
Monotone 1.34 2.49 63 32.63
Unimodal 0.21 2.01 59 11.16
本地 26.26 26.26 0 32

对于input2,香农熵为10.00,但Monotone使用了额外的结构来提高压缩。

编码速度(BInt/s) 解码速度(BInt/s) 索引时间(ns) 比特/整数
Uniform 1.23 5.88 26 8.00
Monotone 1.42 2.42 69 3.63
Unimodal 0.24 2.07 27 8.19
本地 26.26 26.26 0 32

对于input3,香农熵为12.46,但由于存在异常值,压缩困难。 Unimodal提供了最稳健的压缩。

编码速度(BInt/s) 解码速度(BInt/s) 索引时间(ns) 比特/整数
Uniform 1.26 6.10 26 32.63
Monotone 1.35 2.49 65 32.63
Unimodal 0.18 1.67 61 12.50
本地 26.26 26.26 0 32

许可证

mayda根据您的选择,可使用以下任一许可证:

自由选择。

贡献

除非您明确声明,否则您根据Apache-2.0许可证定义的工作中的任何有意提交的、旨在包含在内的贡献,将根据上述许可证双重许可,不附加任何额外条款或条件。

贡献者

Francis Lalonde


lib.rs:

此crate的目的是将mayda_macrosencode!decode!encode_simd!decode_simd!encode_util!语法扩展生成的函数归入一个单独的编译单元。更详细的文档可以在mayda_macros crate中找到。

依赖关系

~155KB