gdsc.core.utils.StoredDataStatistics.java Source code

Java tutorial

Introduction

Here is the source code for gdsc.core.utils.StoredDataStatistics.java

Source

package gdsc.core.utils;

import java.util.Arrays;
import java.util.Iterator;

import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;

/*----------------------------------------------------------------------------- 
 * GDSC SMLM Software
 * 
 * Copyright (C) 2016 Alex Herbert
 * Genome Damage and Stability Centre
 * University of Sussex, UK
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *---------------------------------------------------------------------------*/

/**
 * Calculate the mean and standard deviation of data. Stores the data for later retrieval.
 */
public class StoredDataStatistics extends Statistics implements Iterable<Double>, DoubleData {
    private double[] values = new double[0];
    private DescriptiveStatistics stats = null;

    public StoredDataStatistics() {
    }

    public StoredDataStatistics(int capacity) {
        values = new double[capacity];
    }

    public StoredDataStatistics(float[] data) {
        add(data);
    }

    public StoredDataStatistics(double[] data) {
        add(data);
    }

    public StoredDataStatistics(int[] data) {
        add(data);
    }

    /**
     * Add the data
     * 
     * @param data
     */
    public void add(float[] data) {
        if (data == null)
            return;
        checkCapacity(data.length);
        for (int i = 0; i < data.length; i++) {
            final double value = data[i];
            values[n++] = value;
            s += value;
            ss += value * value;
        }
    }

    /**
     * Ensure that the specified number of elements can be added to the array.
     * <p>
     * This is not synchronized. However any class using the safeAdd() methods in different threads should be using the
     * same synchronized method to add data thus this method will be within synchronized code.
     * 
     * @param length
     */
    private void checkCapacity(int length) {
        stats = null;
        final int minCapacity = n + length;
        final int oldCapacity = values.length;
        if (minCapacity > oldCapacity) {
            int newCapacity = (oldCapacity * 3) / 2 + 1;
            if (newCapacity < minCapacity)
                newCapacity = minCapacity;
            double[] newValues = new double[newCapacity];
            System.arraycopy(values, 0, newValues, 0, n);
            values = newValues;
        }
    }

    /**
     * Add the data
     * 
     * @param data
     */
    public void add(double[] data) {
        if (data == null)
            return;
        checkCapacity(data.length);
        for (int i = 0; i < data.length; i++) {
            final double value = data[i];
            values[n++] = value;
            s += value;
            ss += value * value;
        }
    }

    /**
     * Add the data
     * 
     * @param data
     */
    public void add(int[] data) {
        if (data == null)
            return;
        checkCapacity(data.length);
        for (int i = 0; i < data.length; i++) {
            final double value = data[i];
            values[n++] = value;
            s += value;
            ss += value * value;
        }
    }

    /**
     * Add the value
     * 
     * @param value
     */
    public void add(final double value) {
        checkCapacity(1);
        values[n++] = value;
        s += value;
        ss += value * value;
    }

    /**
     * Add the value n times
     * 
     * @param n
     *            The number of times
     * @param value
     *            The value
     */
    public void add(int n, double value) {
        checkCapacity(n);
        for (int i = 0; i < n; i++)
            values[this.n++] = value;
        s += n * value;
        ss += n * value * value;
    }

    /**
     * Add the data. Synchronized for thread safety. (Multiple threads must all use the same safeAdd method to ensure
     * thread safety.)
     * 
     * @param data
     */
    synchronized public void safeAdd(float[] data) {
        if (data == null)
            return;
        checkCapacity(data.length);
        for (int i = 0; i < data.length; i++) {
            final double value = data[i];
            values[n++] = value;
            s += value;
            ss += value * value;
        }
    }

    /**
     * Add the data. Synchronized for thread safety. (Multiple threads must all use the same safeAdd method to ensure
     * thread safety.)
     * 
     * @param data
     */
    synchronized public void safeAdd(double[] data) {
        if (data == null)
            return;
        checkCapacity(data.length);
        for (int i = 0; i < data.length; i++) {
            final double value = data[i];
            values[n++] = value;
            s += value;
            ss += value * value;
        }
    }

    /**
     * Add the value. Synchronized for thread safety. (Multiple threads must all use the same safeAdd method to ensure
     * thread safety.)
     * 
     * @param value
     */
    synchronized public void safeAdd(final double value) {
        checkCapacity(1);
        values[n++] = value;
        s += value;
        ss += value * value;
    }

    /**
     * @return A copy of the values added
     */
    public double[] getValues() {
        return Arrays.copyOf(values, n);
    }

    /**
     * Gets the value.
     *
     * @param i
     *            the index
     * @return the value
     */
    public double getValue(int i) {
        return values[i];
    }

    /**
     * @return A copy of the values added
     */
    public float[] getFloatValues() {
        float[] data = new float[n];
        for (int i = 0; i < n; i++)
            data[i] = (float) values[i];
        return data;
    }

    /**
     * @return object used to compute descriptive statistics. The object is cached
     * @see {@link org.apache.commons.math3.stat.descriptive.DescriptiveStatistics }
     */
    public DescriptiveStatistics getStatistics() {
        if (stats == null)
            stats = new DescriptiveStatistics(values);
        return stats;
    }

    /*
     * (non-Javadoc)
     * 
     * @see gdsc.core.utils.Statistics#add(gdsc.core.utils.Statistics)
     */
    @Override
    public void add(Statistics statistics) {
        if (statistics instanceof StoredDataStatistics) {
            StoredDataStatistics extra = (StoredDataStatistics) statistics;
            if (extra.n > 0) {
                checkCapacity(extra.n);
                System.arraycopy(extra.values, 0, values, n, extra.n);
            }
        }
        super.add(statistics);
    }

    /*
     * (non-Javadoc)
     * 
     * @see gdsc.core.utils.Statistics#safeAdd(gdsc.core.utils.Statistics)
     */
    @Override
    synchronized public void safeAdd(Statistics statistics) {
        this.add(statistics);
    }

    /**
     * @return The median
     */
    public double getMedian() {
        // Check for negatives
        for (double d : values) {
            if (d < 0) {
                if (n == 0)
                    return Double.NaN;
                if (n == 1)
                    return values[0];

                double[] data = getValues();
                Arrays.sort(data);
                return (data[(data.length - 1) / 2] + data[data.length / 2]) * 0.5;
            }
        }

        // This does not work when the array contains negative data due to the 
        // implementation of the library using partially sorted data
        return getStatistics().getPercentile(50);
    }

    /**
     * Returns a list iterator over the elements in this list (in proper
     * sequence).
     *
     * @return a list iterator over the elements in this list (in proper
     *         sequence)
     */
    public Iterator<Double> iterator() {
        return new Itr();
    }

    /**
     * Copied from ArrayList and removed unrequired code
     */
    private class Itr implements Iterator<Double> {
        int cursor; // index of next element to return

        public boolean hasNext() {
            return cursor != n;
        }

        public Double next() {
            // Simple implementation. Will throw index-out-of-bounds eventually
            return StoredDataStatistics.this.values[cursor++];

            // Copied from ArrayList and removed unrequired code
            //int i = cursor;
            //if (i >= n)
            //   throw new NoSuchElementException();
            //final double[] elementData = StoredDataStatistics.this.values;
            //if (i >= elementData.length)
            //   throw new ConcurrentModificationException();
            //cursor = i + 1;
            //return elementData[i];
        }

        public void remove() {
            throw new UnsupportedOperationException("remove");
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see gdsc.core.utils.DoubleData#size()
     */
    public int size() {
        return n;
    }

    /*
     * (non-Javadoc)
     * 
     * @see gdsc.core.utils.DoubleData#values()
     */
    public double[] values() {
        return getValues();
    }
}