/* * Copyright (C) 2011 Clearspring Technologies, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.streaminer.stream.cardinality; import org.streaminer.stream.cardinality.LinearCounting.Builder; import org.junit.Test; import java.util.Arrays; import static org.junit.Assert.*; public class TestLinearCounting { @Test public void testComputeCount() { LinearCounting lc = new LinearCounting(4); lc.offer(0); lc.offer(1); lc.offer(2); lc.offer(3); lc.offer(16); lc.offer(17); lc.offer(18); lc.offer(19); assertEquals(27, lc.computeCount()); } @Test public void testSaturation() { LinearCounting lc = new LinearCounting(1); for (int i = 0; i < 27; i++) { lc.offer(i); } assertTrue(lc.isSaturated()); assertEquals(0, lc.getCount()); assertEquals(Long.MAX_VALUE, lc.cardinality()); } @Test public void testBuilder() { assertEquals(630, Builder.onePercentError(1).sizeof()); assertEquals(630, Builder.onePercentError(99).sizeof()); assertEquals(630, Builder.onePercentError(100).sizeof()); assertEquals(630, Builder.onePercentError(101).sizeof()); assertEquals(759, Builder.onePercentError(3375).sizeof()); assertEquals(995, Builder.onePercentError(9999).sizeof()); assertEquals(995, Builder.onePercentError(10000).sizeof()); assertEquals(996, Builder.onePercentError(10001).sizeof()); assertEquals(7501, Builder.onePercentError(305028).sizeof()); assertEquals(19272, Builder.onePercentError(1000000).sizeof()); assertEquals(23027, Builder.onePercentError(1250000).sizeof()); assertEquals(74962, Builder.onePercentError(5000000).sizeof()); assertEquals(81372, Builder.onePercentError(5500000).sizeof()); assertEquals(131030, Builder.onePercentError(9500000).sizeof()); assertEquals(137073, Builder.onePercentError(10000000).sizeof()); assertEquals(137073, Builder.onePercentError(10000001).sizeof()); assertEquals(355055, Builder.onePercentError(30000000).sizeof()); assertEquals(573038, Builder.onePercentError(50000000).sizeof()); assertEquals(822207, Builder.onePercentError(75000000).sizeof()); assertEquals(1071377, Builder.onePercentError(100000000).sizeof()); assertEquals(1167722, Builder.onePercentError(110000000).sizeof()); assertEquals(1264067, Builder.onePercentError(120000000).sizeof()); assertEquals(2500000, Builder.onePercentError(240000000).sizeof()); } @Test public void testArbitraryStdErrorSize() { // Some sanity check with 1% error assertEquals(630, Builder.withError(0.01, 100).sizeof()); assertEquals(759, Builder.withError(0.01, 3375).sizeof()); // Checking for 10% error (values from original paper) assertEquals(10, Builder.withError(0.1, 100).sizeof()); assertEquals(34, Builder.withError(0.1, 1000).sizeof()); assertEquals(214, Builder.withError(0.1, 10000).sizeof()); assertEquals(1593, Builder.withError(0.1, 100000).sizeof()); assertEquals(12610, Builder.withError(0.1, 1000000).sizeof()); assertEquals(103977, Builder.withError(0.1, 10000000).sizeof()); assertEquals(882720, Builder.withError(0.1, 100000000).sizeof()); } @Test(expected = IllegalArgumentException.class) public void testBuilderIllegalArgumentZero() { Builder.onePercentError(0); } @Test(expected = IllegalArgumentException.class) public void testBuilderIllegalArgumentNegative() { Builder.onePercentError(-1); } @Test public void testSerialization() { LinearCounting lc = new LinearCounting(4); lc.offer("a"); lc.offer("b"); lc.offer("c"); lc.offer("d"); lc.offer("e"); LinearCounting lc2 = new LinearCounting(lc.getBytes()); assertArrayEquals(lc.map, lc2.map); assertEquals(lc.count, lc2.count); assertEquals(lc.length, lc2.length); } @Test public void testMerge() throws LinearCounting.LinearCountingMergeException { int numToMerge = 5; int size = 65536; int cardinality = 1000; LinearCounting[] lcs = new LinearCounting[numToMerge]; LinearCounting baseline = new LinearCounting(size); for (int i = 0; i < numToMerge; i++) { lcs[i] = new LinearCounting(size); for (int j = 0; j < cardinality; j++) { double val = Math.random(); lcs[i].offer(val); baseline.offer(val); } } int expectedCardinality = numToMerge * cardinality; long mergedEstimate = LinearCounting.mergeEstimators(lcs).cardinality(); double error = Math.abs(mergedEstimate - expectedCardinality) / (double) expectedCardinality; assertEquals(0.01, error, 0.01); LinearCounting lc = lcs[0]; lcs = Arrays.asList(lcs).subList(1, lcs.length).toArray(new LinearCounting[0]); mergedEstimate = lc.merge(lcs).cardinality(); error = Math.abs(mergedEstimate - expectedCardinality) / (double) expectedCardinality; assertEquals(0.01, error, 0.01); long baselineEstimate = baseline.cardinality(); assertEquals(baselineEstimate, mergedEstimate); } }