//******************************************************************************
//
// File: Series.java
// Package: edu.rit.numeric
// Unit: Class edu.rit.numeric.Series
//
// This Java source file is copyright (C) 2011 by Alan Kaminsky. All rights
// reserved. For further information, contact the author, Alan Kaminsky, at
// ark@cs.rit.edu.
//
// This Java source file is part of the Parallel Java Library ("PJ"). PJ 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.
//
// PJ is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU General Public License for more details.
//
// A copy of the GNU General Public License is provided in the file gpl.txt. You
// may also obtain a copy of the GNU General Public License on the World Wide
// Web at http://www.gnu.org/licenses/gpl.html.
//
//******************************************************************************
package edu.rit.numeric;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Class Series is the abstract base class for a series of real values (type
* double).
*
* @author Alan Kaminsky
* @version 25-Jul-2011
*/
public abstract class Series
implements Iterable
{
// Exported helper classes.
/**
* Class Series.Stats holds the mean, variance, and standard deviation of a
* {@linkplain Series}.
*
* If the series is empty, the mean, variance, and standard deviation are
* set to Double.NaN (not-a-number).
*
* @author Alan Kaminsky
* @version 20-Jul-2011
*/
public static class Stats
{
/**
* Mean of the series' data values.
*/
public final double mean;
/**
* Variance of the series' data values.
*/
public final double var;
/**
* Standard deviation of the series' data values.
*/
public final double stddev;
/**
* Construct a new Series.Stats object.
*/
private Stats
(Series series)
{
int n = series.length();
if (n == 0)
{
mean = Double.NaN;
var = Double.NaN;
stddev = Double.NaN;
}
else
{
double sum = 0.0;
for (int i = 0; i < n; ++ i) sum += series.x(i);
mean = sum/n;
double sumdev = 0.0;
double sumdevsqr = 0.0;
for (int i = 0; i < n; ++ i)
{
double dev = series.x(i) - mean;
sumdev += dev;
sumdevsqr += dev*dev;
}
var = n == 1 ? 0.0 : (sumdevsqr - sumdev*sumdev/n)/(n - 1);
stddev = Math.sqrt (var);
}
}
}
/**
* Class Series.RobustStats holds the median, mean absolute deviation, and
* quantiles of a {@linkplain Series}.
*
* If the series is empty, the median, mean absolute deviation, and
* quantiles are set to Double.NaN (not-a-number), and the
* histogram bin counts are always 0.
*
* @author Alan Kaminsky
* @version 25-Jul-2011
*/
public static class RobustStats
{
/**
* Median of the series' data values, equal to quantile(0.5).
*/
public final double median;
/**
* Mean absolute deviation of the series' data values. The absolute
* deviation of one value x is
* |x − median|. The mean absolute
* deviation is the mean of all the absolute deviations.
*/
public final double meanAbsDev;
/**
* The series' data values in ascending order.
*/
private double[] data;
/**
* Construct a new Series.RobustStats object.
*/
private RobustStats
(Series series)
{
// Sort series data.
int n = series.length();
data = new double [n];
for (int i = 0; i < n; ++ i) data[i] = series.x(i);
Arrays.sort (data);
if (n == 0)
{
median = Double.NaN;
meanAbsDev = Double.NaN;
}
else
{
// Compute median.
median = quantile (0.5);
// Compute mean absolute deviation.
double sum = 0.0;
for (int i = 0; i < n; ++ i)
{
sum += Math.abs (data[i] - median);
}
meanAbsDev = sum/n;
}
}
/**
* Returns the given quantile of the series' data values. The
* q-th quantile is that value x such that a fraction
* q of the series' data values are less than or equal to
* x.
*
* If the series is empty, then Double.NaN (not-a-number) is
* returned. If q is 0, then Double.NEGATIVE_INFINITY is
* returned.
*
* @param q Quantile, 0.0 ≤ q ≤ 1.0.
*
* @return The q-th quantile of the series' data values.
*
* @exception IllegalArgumentException
* (unchecked exception) Thrown if q is out of range.
*/
public double quantile
(double q)
{
if (0.0 > q || q > 1.0)
{
throw new IllegalArgumentException
("Series.RobustStats.quantile(): q = "+q+" illegal");
}
return
data.length == 0 ?
Double.NaN :
q == 0.0 ?
Double.NEGATIVE_INFINITY :
data[(int)(Math.ceil (q*data.length)) - 1];
}
/**
* Returns the count for the given histogram bin. This is the number of
* data values in the series that are greater than or equal to
* lb and less than ub.
*
* @param lb Lower bound (inclusive) of histogram bin.
* @param ub Upper bound (exclusive) of histogram bin.
*
* @return Histogram bin count.
*
* @exception IllegalArgumentException
* (unchecked exception) Thrown if lb > ub.
*/
public int histogram
(double lb,
double ub)
{
if (lb > ub)
{
throw new IllegalArgumentException
("RobustStats.histogram(): lb ("+lb+") > ub ("+ub+
") illegal");
}
int n = data.length;
int i = 0;
while (i < n && data[i] < lb) ++ i;
int j = i;
while (j < n && data[j] < ub) ++ j;
return j - i;
}
}
// Exported constructors.
/**
* Construct a new series.
*/
public Series()
{
}
// Exported operations.
/**
* Returns the number of values in this series.
*
* @return Length.
*/
public abstract int length();
/**
* Determine if this series is empty.
*
* @return True if this series is empty (length = 0), false otherwise.
*/
public boolean isEmpty()
{
return length() == 0;
}
/**
* Returns the given X value in this series.
*
* @param i Index.
*
* @return The X value in this series at index i.
*
* @exception ArrayIndexOutOfBoundsException
* (unchecked exception) Thrown if i is not in the range
* 0 .. length()-1.
*/
public abstract double x
(int i);
/**
* Returns the minimum value in this series.
*
* @return Minimum X value.
*/
public double minX()
{
int n = length();
double result = Double.POSITIVE_INFINITY;
for (int i = 0; i < n; ++ i) result = Math.min (result, x(i));
return result;
}
/**
* Returns the maximum value in this series.
*
* @return Maximum X value.
*/
public double maxX()
{
int n = length();
double result = Double.NEGATIVE_INFINITY;
for (int i = 0; i < n; ++ i) result = Math.max (result, x(i));
return result;
}
/**
* Returns a {@linkplain Stats Stats} object containing statistics of this
* series.
*
* Note: The returned object contains the statistics of a
* snapshot of this series at the time stats() was called.
* Changing the data in this series will not change the contents of
* the returned object.
*
* @return Statistics.
*/
public Stats stats()
{
return new Stats (this);
}
/**
* Returns a {@linkplain RobustStats RobustStats} object containing robust
* statistics of this series.
*
* Note: The returned object contains the statistics of a
* snapshot of this series at the time robustStats() was
* called. Changing the data in this series will not change the
* contents of the returned object.
*
* @return Robust statistics.
*/
public RobustStats robustStats()
{
return new RobustStats (this);
}
/**
* Returns an iterator over the values in this series.
*
* @return Iterator.
*/
public Iterator iterator()
{
return new Iterator()
{
int i = 0;
public boolean hasNext()
{
return i < length();
}
public Double next()
{
try
{
return x (i ++);
}
catch (ArrayIndexOutOfBoundsException exc)
{
throw new NoSuchElementException();
}
}
public void remove()
{
throw new UnsupportedOperationException();
}
};
}
/**
* Print this series on the standard output. Each line of output consists of
* the index and the value, separated by a tab.
*/
public void print()
{
print (System.out);
}
/**
* Print this series on the given print stream. Each line of output consists
* of the index and the value, separated by a tab.
*
* @param theStream Print stream.
*/
public void print
(PrintStream theStream)
{
int n = length();
for (int i = 0; i < n; ++ i)
{
theStream.print (i);
theStream.print ('\t');
theStream.println (x(i));
}
}
/**
* Print this series on the given print writer. Each line of output consists
* of the index and the value, separated by a tab.
*
* @param theWriter Print writer.
*/
public void print
(PrintWriter theWriter)
{
int n = length();
for (int i = 0; i < n; ++ i)
{
theWriter.print (i);
theWriter.print ('\t');
theWriter.println (x(i));
}
}
}
Ads help maintain this website.