@Override
    public void add(long item, long count) {
        if (count < 0) {
            // Negative values are not implemented in the regular version, and do not
            // play nicely with this algorithm anyway
            throw new IllegalArgumentException("Negative increments not implemented");
        }
        int[] buckets = new int[depth];
        for (int i = 0; i < depth; ++i) {
            buckets[i] = hash(item, i);
        }
        long min = table[0][buckets[0]];
        for (int i = 1; i < depth; ++i) {
            min = Math.min(min, table[i][buckets[i]]);
        }
        for (int i = 0; i < depth; ++i) {
            long newVal = Math.max(table[i][buckets[i]], min + count);
            table[i][buckets[i]] = newVal;
        }
        size += count;
    }
@Test
    public void merge() throws CountMinSketch.CMSMergeException {
        int numToMerge = 5;
        int cardinality = 1000000;

        double epsOfTotalCount = 0.0001;
        double confidence = 0.99;
        int seed = 7364181;

        int maxScale = 20;
        Random r = new Random();
        TreeSet<Integer> vals = new TreeSet<Integer>();

        CountMinSketch baseline = new ConservativeAddSketch(epsOfTotalCount, confidence, seed);
        CountMinSketch stdMinSketch = new CountMinSketch(epsOfTotalCount, confidence, seed);
        CountMinSketch[] sketchs = new CountMinSketch[numToMerge];
        for (int i = 0; i < numToMerge; i++) {
            sketchs[i] = new ConservativeAddSketch(epsOfTotalCount, confidence, seed);
            for (int j = 0; j < cardinality; j++) {
                int scale = r.nextInt(maxScale);
                int val = r.nextInt(1 << scale);
                if (vals.add(val)) {
                    sketchs[i].add(val, 1);
                    baseline.add(val, 1);
                    stdMinSketch.add(val, 1);
                }
            }
        }

        CountMinSketch merged = CountMinSketch.merge(sketchs);

        assertEquals(baseline.size(), merged.size());
        assertEquals(baseline.getConfidence(), merged.getConfidence(), baseline.getConfidence() / 100);
        assertEquals(baseline.getRelativeError(), merged.getRelativeError(), baseline.getRelativeError() / 100);
        for (int val : vals) {
            long base = baseline.estimateCount(val);
            long merge = merged.estimateCount(val);
            long std = stdMinSketch.estimateCount(val);
            assertTrue(1 <= base);
            assertTrue(base <= std);
            assertTrue(1 <= merge);
            assertTrue(merge <= std);
        }
    }