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 = $\displaystyle {\frac{{1}}{{n-1}}}$∑k=1n(xk - bar(X)n)(yk - bar(Y)n) = [tex2html_wrap_indisplay275](∑k=1nxkyk - $\displaystyle {\frac{{1}}{{n}}}$∑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(); } }

Ads help maintain this website.