com.davidbracewell.math.CompactCounter.java Source code

Java tutorial

Introduction

Here is the source code for com.davidbracewell.math.CompactCounter.java

Source

/*
 * (c) 2005 David B. Bracewell
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 com.davidbracewell.math;

import com.davidbracewell.collection.Counter;
import com.davidbracewell.tuple.Pair;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.primitives.Doubles;
import org.apache.mahout.math.list.DoubleArrayList;
import org.apache.mahout.math.map.OpenObjectDoubleHashMap;

import java.io.Serializable;
import java.util.*;

/**
 * The type Compact counter.
 *
 * @author David B. Bracewell
 */
public class CompactCounter<V> implements Serializable, Counter<V> {

    private static final long serialVersionUID = 6889762694761078118L;
    private final OpenObjectDoubleHashMap<V> map;
    private double sum;

    /**
     * Create fast counter.
     *
     * @param items the items
     * @return the fast counter
     */
    @SafeVarargs
    public static <V> CompactCounter<V> create(V... items) {
        Preconditions.checkNotNull(items);
        if (items.length == 0) {
            return new CompactCounter<>();
        }
        return new CompactCounter<>(Arrays.asList(items));
    }

    /**
     * Create fast counter.
     *
     * @param item the item
     * @param value the value
     * @return the fast counter
     */
    public static <V> CompactCounter<V> create(V item, double value) {
        CompactCounter<V> counter = new CompactCounter<>(1);
        counter.increment(item, value);
        return counter;
    }

    /**
     * Create fast counter.
     *
     * @param items the items
     * @param values the values
     * @return the fast counter
     */
    public static <V> CompactCounter<V> create(V[] items, double[] values) {
        Preconditions.checkNotNull(items);
        Preconditions.checkNotNull(values);
        Preconditions.checkArgument(items.length == values.length, "dimensions do not match.");
        CompactCounter<V> counter = new CompactCounter<>(items.length);
        for (int i = 0; i < items.length; i++) {
            counter.increment(items[i], values[i]);
        }
        return counter;
    }

    /**
     * Instantiates a new Compact counter.
     */
    public CompactCounter() {
        this(100);
    }

    /**
     * Instantiates a new Compact counter.
     *
     * @param iterable the iterable
     */
    public CompactCounter(Iterable<? extends V> iterable) {
        this(Iterables.size(Preconditions.checkNotNull(iterable)));
        incrementAll(Preconditions.checkNotNull(iterable));
    }

    /**
     * Instantiates a new Fast counter.
     *
     * @param map the map
     */
    public CompactCounter(Map<V, ? extends Number> map) {
        this(Preconditions.checkNotNull(map).size());
        for (Map.Entry<V, ? extends Number> e : map.entrySet()) {
            this.set(e.getKey(), e.getValue().doubleValue());
        }
    }

    /**
     * Instantiates a new Compact counter.
     *
     * @param initialSize the initial size
     */
    public CompactCounter(int initialSize) {
        Preconditions.checkArgument(initialSize > 0, "initialize size should be > 0.");
        this.map = new OpenObjectDoubleHashMap<>(initialSize);
    }

    @Override
    public double get(V item) {
        return map.get(item);
    }

    @Override
    public void increment(V item) {
        increment(item, 1d);
    }

    @Override
    public void increment(V item, double amount) {
        map.adjustOrPutValue(Preconditions.checkNotNull(item), amount, amount);
        sum += amount;
    }

    @Override
    public void incrementAll(Iterable<? extends V> iterable) {
        incrementAll(iterable, 1d);
    }

    @Override
    public void incrementAll(Iterable<? extends V> iterable, double amount) {
        for (V item : Preconditions.checkNotNull(iterable)) {
            increment(item, amount);
        }
    }

    @Override
    public void decrementAll(Iterable<? extends V> iterable) {
        incrementAll(iterable, -1d);
    }

    @Override
    public void decrementAll(Iterable<? extends V> iterable, double amount) {
        incrementAll(iterable, -amount);
    }

    @Override
    public void decrement(V item) {
        increment(item, -1);
    }

    @Override
    public void decrement(V item, double amount) {
        increment(item, -amount);
    }

    @Override
    public Map<V, Double> asMap() {
        return new AbstractMap<V, Double>() {
            @Override
            @SuppressWarnings("unchecked")
            public Double get(Object key) {
                return map.get((V) key);
            }

            @Override
            public int size() {
                return map.size();
            }

            @Override
            @SuppressWarnings("unchecked")
            public boolean containsKey(Object key) {
                return map.containsKey((V) key);
            }

            @Override
            public Set<V> keySet() {
                return Sets.newHashSet(map.keys());
            }

            @Override
            public Set<Entry<V, Double>> entrySet() {

                return new AbstractSet<Entry<V, Double>>() {
                    @Override
                    public Iterator<Entry<V, Double>> iterator() {
                        return new IteratorWrapper();
                    }

                    @Override
                    public int size() {
                        return map.size();
                    }
                };
            }
        };
    }

    private class IteratorWrapper implements Iterator<Map.Entry<V, Double>> {

        final Iterator<V> keyIterator = CompactCounter.this.iterator();

        @Override
        public boolean hasNext() {
            return keyIterator.hasNext();
        }

        @Override
        public Map.Entry<V, Double> next() {
            if (!keyIterator.hasNext()) {
                throw new NoSuchElementException();
            }
            V key = keyIterator.next();
            return Pair.of(key, map.get(key));
        }

        @Override
        public void remove() {
            keyIterator.remove();
        }
    }

    @Override
    public boolean isEmpty() {
        return map.isEmpty();
    }

    @Override
    public int size() {
        return map.size();
    }

    @Override
    public Set<V> items() {
        return Sets.newHashSet(map.keys());
    }

    @Override
    public Collection<Double> counts() {
        return new AbstractList<Double>() {
            final DoubleArrayList list = map.values();

            @Override
            public Double get(int index) {
                return list.get(index);
            }

            @Override
            public int size() {
                return list.size();
            }
        };
    }

    @Override
    public Counter<V> adjustValues(Function<Double, Double> function) {
        Preconditions.checkNotNull(function);
        CompactCounter<V> newCounter = new CompactCounter<>(map.size());
        for (V item : map.keys()) {
            Double out = function.apply(map.get(item));
            if (out != null) {
                newCounter.increment(item, out);
            }
        }
        return newCounter;
    }

    @Override
    public double sum() {
        return sum;
    }

    @Override
    public double average() {
        if (map.isEmpty()) {
            return 0d;
        }
        return sum / (double) map.size();
    }

    @Override
    public double standardDeviation() {
        if (map.isEmpty()) {
            return 0d;
        }
        return Math.sqrt(Math.abs(sumOfSquares() - average() * sum) / ((double) map.size() - 1));
    }

    @Override
    public double sumOfSquares() {
        if (map.isEmpty()) {
            return 0d;
        }
        double sumOfSq = 0d;
        for (V item : map.keys()) {
            sumOfSq += Math.pow(map.get(item), 2);
        }
        return sumOfSq;
    }

    @Override
    public double magnitude() {
        return Math.sqrt(sumOfSquares());
    }

    @Override
    public void merge(Counter<? extends V> other) {
        merge(other.asMap());
    }

    @Override
    public void removeZeroCounts() {
        for (V item : map.keys()) {
            if (map.get(item) == 0) {
                map.removeKey(item);
            }
        }
        map.trimToSize();
    }

    @Override
    public void merge(Map<? extends V, ? extends Number> other) {
        Preconditions.checkNotNull(other);
        for (Map.Entry<? extends V, ? extends Number> e : other.entrySet()) {
            increment(e.getKey(), e.getValue().doubleValue());
        }
    }

    @Override
    public List<V> itemsByCount(boolean ascending) {
        List<V> list = Lists.newArrayList();
        map.keysSortedByValue(list);
        if (!ascending) {
            Collections.reverse(list);
        }
        return list;
    }

    @Override
    public boolean contains(V item) {
        return map.containsKey(item);
    }

    @Override
    public double maximumCount() {
        if (map.isEmpty()) {
            return 0d;
        }
        return Doubles.max(map.values().elements());
    }

    @Override
    public double minimumCount() {
        if (map.isEmpty()) {
            return 0d;
        }
        return Doubles.min(map.values().elements());
    }

    @Override
    public void clear() {
        map.clear();
        sum = 0d;
    }

    @Override
    public double remove(V item) {
        double amt = map.get(item);
        map.removeKey(item);
        sum -= amt;
        return amt;
    }

    @Override
    public void set(V item, double count) {
        double amt = map.get(item);
        map.put(item, count);
        sum -= amt;
        sum += count;
    }

    @Override
    public void divideBySum() {
        if (map.isEmpty()) {
            return;
        }
        for (V item : map.keys()) {
            map.put(item, map.get(item) / sum);
        }
        sum = 1d;
    }

    @Override
    public Iterator<V> iterator() {
        return map.keys().iterator();
    }

    @Override
    public String toString() {
        return map.toString();
    }

}//END OF CompactCounter