
umontreal.iro.lecuyer.stat.list.ListOfTallies Maven / Gradle / Ivy
Show all versions of ssj Show documentation
/*
* Class: ListOfTallies
* Description: List of statistical collectors.
* Environment: Java
* Software: SSJ
* Copyright (C) 2001 Pierre L'Ecuyer and Université de Montréal
* Organization: DIRO, Université de Montréal
* @author Éric Buist
* @since 2007
* SSJ is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License (GPL) as published by the
* Free Software Foundation, either version 3 of the License, or
* any later version.
* SSJ 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 available at
GPL licence site.
*/
package umontreal.iro.lecuyer.stat.list;
import umontreal.iro.lecuyer.util.PrintfFormat;
import cern.colt.list.DoubleArrayList;
import cern.colt.matrix.DoubleMatrix1D;
import cern.colt.matrix.DoubleMatrix2D;
import umontreal.iro.lecuyer.stat.Tally;
import umontreal.iro.lecuyer.stat.TallyStore;
/**
* Represents a list of tally statistical collectors.
* Each element of the list is an instance of {@link umontreal.iro.lecuyer.stat.Tally Tally},
* and a vector of observations can be added with
* the {@link #add((double[])) add} method.
* This class defines factory methods to fill a newly-constructed list
* with Tally or TallyStore instances.
*
*/
public class ListOfTallies extends ListOfStatProbes {
/**
* Constructs a new empty list of tallies.
*
*/
public ListOfTallies() {
super();
}
/**
* Constructs a new empty list of tallies with name name.
*
* @param name the name of the new list.
*
*
*/
public ListOfTallies (String name) {
super (name);
}
/**
* This factory method constructs and returns a list of tallies with size instances of
* {@link Tally}.
*
* @param size the size of the list.
*
* @return the created list.
*
*/
public static ListOfTallies createWithTally (int size) {
ListOfTallies list = new ListOfTallies();
for (int i = 0; i < size; i++)
list.add (new Tally());
return list;
}
/**
* This factory method constructs and returns a list of tallies with size instances of
* {@link TallyStore}.
*
* @param size the size of the list.
*
* @return the created list.
*
*/
public static ListOfTallies createWithTallyStore (int size) {
ListOfTallies list = new ListOfTallies();
for (int i = 0; i < size; i++)
list.add (new TallyStore());
return list;
}
/**
* Adds the observation x[i] in
* tally i of this list, for i = 0,..., size() - 1.
* No observation is added if the value is Double.NaN,
* or if collecting is turned OFF.
* If broadcasting is ON, the given array is notified
* to all registered observers.
* The given array x not being stored by this object,
* it can be freely used and modified after the call to this method.
*
* @param x the array of observations.
*
* @exception NullPointerException if x is null.
*
* @exception IllegalArgumentException if the length of
* x does not correspond to size().
*
*
*/
public void add (double[] x) {
int l = size();
if (x.length != l)
throw new IllegalArgumentException
("Incompatible array length: given " +
x.length + ", required " + l);
if (collect)
for (int i = 0; i < l; i++) {
double v = x[i];
Tally ta = get (i);
if (!Double.isNaN (v) && ta != null)
ta.add (v);
}
notifyListeners (x);
}
/**
* Assuming that each tally in this list contains
* the same number of observations, returns
* the number of observations in tally 0, or
* 0 if this list is empty.
*
* @return the number of observations.
*
*/
public int numberObs() {
if (size() == 0)
return 0;
Tally t0 = get (0);
return t0 == null ? 0 : t0.numberObs();
}
/**
* Tests that every tally in this list contains the
* same number of observations.
* This returns true if and only if all
* tallies have the same number of observations, or if this list is empty.
* If observations are always added using the
* {@link #add((double[])) add} method from this class, and not
* {@link umontreal.iro.lecuyer.stat.Tally#add((double)) add} from
* {@link Tally}, this method always returns true.
*
* @return the success indicator of the test.
*
*/
public boolean areAllNumberObsEqual() {
final int l = size();
int n = numberObs();
for (int i = 1; i < l; i++) {
Tally t = get (i);
if (t.numberObs() != n)
return false;
}
return true;
}
/**
* Computes the average for each tally
* in this list, and stores the averages in the array r.
* If the tally i has no observation,
* the Double.NaN value is stored
* in the array, at index i.
*
*/
public void average (double[] r) {
final int l = size();
for (int i = 0; i < l; i++) {
// Manual check to avoid repetitive logs when all tallies
// have 0 observation.
Tally ta = get (i);
double v = ta == null || ta.numberObs() == 0 ? Double.NaN : ta.average();
r[i] = v;
}
}
/**
* For each tally in this list, computes
* the sample variance, and stores the variances into the array v.
* If, for some tally i, there are not enough
* observations for estimating the variance,
* Double.NaN is stored in the array.
*
* @param v the array to be filled with sample variances.
*
* @exception NullPointerException if v is null.
*
* @exception IllegalArgumentException if v.length
* does not correspond to {@link umontreal.iro.lecuyer.stat.list.ListOfStatProbes#size(()) size}.
*
*
*/
public void variance (double[] v) {
if (size() != v.length)
throw new IllegalArgumentException
("Invalid length of given array");
for (int i = 0; i < v.length; i++) {
Tally tally = get (i);
if (tally == null || tally.numberObs() < 2)
v[i] = Double.NaN;
else
v[i] = tally.variance();
}
}
/**
* For each tally in this list, computes
* the sample standard deviation, and stores the standard deviations
* into the array std.
* This is equivalent to calling {@link #variance((double[])) variance} and
* performing a square root on every element
* of the filled array.
*
* @param std the array to be filled with standard deviations.
*
* @exception NullPointerException if std is null.
*
* @exception IllegalArgumentException if std.length
* does not correspond to size().
*
*
*/
public void standardDeviation (double[] std) {
if (size() != std.length)
throw new IllegalArgumentException
("Invalid length of given array");
for (int i = 0; i < std.length; i++) {
Tally tally = get (i);
if (tally == null || tally.numberObs() < 2)
std[i] = Double.NaN;
else
std[i] = tally.standardDeviation();
}
}
/**
* Returns the empirical covariance of the observations in tallies
* with indices i and j. If
* x1,…, xn represent the
* observations in tally i whereas
* y1,…, yn represent the
* observations in tally j, then the covariance is given by
*
*
*
* SX, Y =
∑k=1n(xk - bar(X)n)(yk - bar(Y)n) = [tex2html_wrap_indisplay273](∑k=1nxkyk -
∑k=1nxk∑r=1nyr).
*
* This returns Double.NaN
* if the tallies do not contain the same number of observations, or
* if they contain less than two observations.
* This method throws an exception if the
* underlying tallies are not capable of storing
* observations, i.e. if the tallies are not TallyStores.
* The {@link ListOfTalliesWithCovariance}
* subclass provides an alternative implementation
* of this method which does not require the
* observations to be stored.
*
* @param i the index of the first tally.
*
* @param j the index of the second tally.
*
* @return the value of the covariance.
* @exception ArrayIndexOutOfBoundsException if one or both
* indices are out of bounds.
*
*
*/
public double covariance (int i, int j) {
if (i == j)
return get (i).variance();
TallyStore tallyi = (TallyStore)get (i);
TallyStore tallyj = (TallyStore)get (j);
return tallyi.covariance (tallyj);
}
/**
* Returns the empirical correlation between
* the observations in tallies with indices i and j.
* If the tally i contains a sample of the random
* variate X and the tally j contains a sample of Y,
* this corresponds to
*
*
*
* Cor(X, Y) = Cov(X, Y)/((X)(Y))1/2.
*
*
*
* This method uses {@link #covariance((int, int)) covariance}
* to obtain an estimate of the covariance, and
* {@link umontreal.iro.lecuyer.stat.Tally#variance(()) variance} in
* class {@link Tally} to obtain the sample variances.
*
* @param i the index of the first tally.
*
* @param j the index of the second tally.
*
* @return the value of the correlation.
* @exception ArrayIndexOutOfBoundsException if one or both
* indices are out of bounds.
*
*
*/
public double correlation (int i, int j) {
if (i == j)
return 1.0;
double cov = covariance (i, j);
Tally tallyi = get (i);
Tally tallyj = get (j);
if (tallyi == null || tallyj == null)
return Double.NaN;
return cov/Math.sqrt (tallyi.variance()*tallyj.variance());
}
/**
* Constructs and returns the sample covariance matrix
* for the tallies in this list. The given d×d matrix c,
* where d = size(),
* is filled with the computed sample covariances.
* Element c.get (i, j) corresponds to
* the result of
* covariance (i, j).
*
* @param c the matrix to be filled with the sample covariances.
*
* @exception NullPointerException if c is null.
*
* @exception IllegalArgumentException if the number of rows or columns
* in c does not correspond to size().
*
*
*/
public void covariance (DoubleMatrix2D c) {
int l = size();
if (c.rows() != l)
throw new IllegalArgumentException
("Invalid number of rows in covariance matrix");
if (c.columns() != l)
throw new IllegalArgumentException
("Invalid number of columns in covariance matrix");
for (int i1 = 0; i1 < l; i1++)
c.setQuick (i1, i1, get (i1).variance());
for (int i1 = 0; i1 < l - 1; i1++)
for (int i2 = i1 + 1; i2 < l; i2++) {
double cov = covariance (i1, i2);
c.setQuick (i1, i2, cov);
c.setQuick (i2, i1, cov);
}
}
/**
* Similar to {@link #covariance((DoubleMatrix2D)) covariance} for computing
* the sample correlation matrix.
*
* @param c the matrix to be filled with the correlations.
*
* @exception NullPointerException if c is null.
*
* @exception IllegalArgumentException if the number of rows or columns in c
* does not correspond to {@link umontreal.iro.lecuyer.stat.list.ListOfStatProbes#size(()) size}.
*
*
*/
public void correlation (DoubleMatrix2D c) {
int l = size();
if (c.rows() != l)
throw new IllegalArgumentException
("Invalid number of rows in correlation matrix");
if (c.columns() != l)
throw new IllegalArgumentException
("Invalid number of columns in correlation matrix");
for (int i1 = 0; i1 < l; i1++)
c.setQuick (i1, i1, 1.0);
for (int i1 = 0; i1 < l - 1; i1++)
for (int i2 = i1 + 1; i2 < l; i2++) {
double cor = correlation (i1, i2);
c.setQuick (i1, i2, cor);
c.setQuick (i2, i1, cor);
}
}
/**
* Clones this object. This makes a shallow copy
* of this list, i.e., this does not clone all the tallies in the list.
* The created clone is modifiable, even if the original list is unmodifiable.
*
*/
public ListOfTallies clone() {
return (ListOfTallies)super.clone();
}
}