/* * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, * and the EPL 1.0 (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ package org.h2.test.unit; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Arrays; import java.util.Random; import org.h2.dev.util.AnsCompression; import org.h2.dev.util.BinaryArithmeticStream; import org.h2.dev.util.BitStream; import org.h2.test.TestBase; /** * Tests the ANS (Asymmetric Numeral Systems) compression tool. */ public class TestAnsCompression extends TestBase { /** * Run just this test. * * @param a ignored */ public static void main(String... a) throws Exception { TestBase.createCaller().init().test(); } @Override public void test() throws Exception { testScaleFrequencies(); testRandomized(); testCompressionRate(); } private void testCompressionRate() throws IOException { byte[] data = new byte[1024 * 1024]; Random r = new Random(1); for (int i = 0; i < data.length; i++) { data[i] = (byte) (r.nextInt(4) * r.nextInt(4)); } int[] freq = new int[256]; AnsCompression.countFrequencies(freq, data); int lenAns = AnsCompression.encode(freq, data).length; BitStream.Huffman huff = new BitStream.Huffman(freq); ByteArrayOutputStream out = new ByteArrayOutputStream(); BitStream.Out o = new BitStream.Out(out); for (byte x : data) { huff.write(o, x & 255); } o.flush(); int lenHuff = out.toByteArray().length; BinaryArithmeticStream.Huffman aHuff = new BinaryArithmeticStream.Huffman( freq); out = new ByteArrayOutputStream(); BinaryArithmeticStream.Out o2 = new BinaryArithmeticStream.Out(out); for (byte x : data) { aHuff.write(o2, x & 255); } o2.flush(); int lenArithmetic = out.toByteArray().length; assertTrue(lenAns < lenArithmetic); assertTrue(lenArithmetic < lenHuff); assertTrue(lenHuff < data.length); } private void testScaleFrequencies() { Random r = new Random(1); for (int j = 0; j < 100; j++) { int symbolCount = r.nextInt(200) + 1; int[] freq = new int[symbolCount]; for (int total = symbolCount * 2; total < 10000; total *= 2) { for (int i = 0; i < freq.length; i++) { freq[i] = r.nextInt(1000) + 1; } AnsCompression.scaleFrequencies(freq, total); } } int[] freq = new int[]{0, 1, 1, 1000}; AnsCompression.scaleFrequencies(freq, 100); assertEquals("[0, 1, 1, 98]", Arrays.toString(freq)); } private void testRandomized() { Random r = new Random(1); int symbolCount = r.nextInt(200) + 1; int[] freq = new int[symbolCount]; for (int i = 0; i < freq.length; i++) { freq[i] = r.nextInt(1000) + 1; } int seed = r.nextInt(); r.setSeed(seed); int len = 10000; byte[] data = new byte[len]; r.nextBytes(data); freq = new int[256]; AnsCompression.countFrequencies(freq, data); byte[] encoded = AnsCompression.encode(freq, data); byte[] decoded = AnsCompression.decode(freq, encoded, data.length); for (int i = 0; i < len; i++) { int expected = data[i]; assertEquals(expected, decoded[i]); } } }