package test.beast.beast2vs1.trace; import beast.util.HeapSort; /** * @author Alexei Drummond * @author Andrew Rambaut * @author Walter Xie */ public class TraceStatistics { private static final int MAX_LAG = 2000; private boolean isValid = true; private boolean hasGeometricMean = false; private double minimum, maximum; private double mean; private double median; private double geometricMean; private double stdev; private double variance; private double cpdLower, cpdUpper, hpdLower, hpdUpper; private double ESS; private double stdErrorOfMean; private double autoCorrelationTime; private double stdevAutoCorrelationTime; public TraceStatistics(double[] values) { analyseDistributionContinuous(values, 0.95); } public TraceStatistics(double[] values, long stepSize) { this(values); if (isValid) { analyseCorrelationContinuous(values, stepSize); } } /** * @param valuesC the values to analyze * @param proportion the proportion of probability mass included within interval. */ private void analyseDistributionContinuous(double[] valuesC, double proportion) { mean = DiscreteStatistics.mean(valuesC); stdev = DiscreteStatistics.stdev(valuesC); variance = DiscreteStatistics.variance(valuesC); minimum = Double.POSITIVE_INFINITY; maximum = Double.NEGATIVE_INFINITY; for (double value : valuesC) { if (value < minimum) minimum = value; if (value > maximum) maximum = value; } if (minimum > 0) { geometricMean = DiscreteStatistics.geometricMean(valuesC); hasGeometricMean = true; } if (maximum == minimum) { isValid = false; return; } int[] indices = new int[valuesC.length]; HeapSort.sort(valuesC, indices); median = DiscreteStatistics.quantile(0.5, valuesC, indices); cpdLower = DiscreteStatistics.quantile(0.025, valuesC, indices); cpdUpper = DiscreteStatistics.quantile(0.975, valuesC, indices); calculateHPDInterval(proportion, valuesC, indices); ESS = valuesC.length; } /** * @param proportion the proportion of probability mass included within interval. * @param array the data array * @param indices the indices of the ranks of the values (sort order) */ private void calculateHPDInterval(double proportion, double[] array, int[] indices) { final double[] hpd = DiscreteStatistics.HPDInterval(proportion, array, indices); hpdLower = hpd[0]; hpdUpper = hpd[1]; } /** * Analyze trace * * @param values the values * @param stepSize the sampling frequency of the values */ private void analyseCorrelationContinuous(double[] values, long stepSize) { final int samples = values.length; int maxLag = Math.min(samples - 1, MAX_LAG); double[] gammaStat = new double[maxLag]; //double[] varGammaStat = new double[maxLag]; double varStat = 0.0; //double varVarStat = 0.0; //double assVarCor = 1.0; //double del1, del2; for (int lag = 0; lag < maxLag; lag++) { for (int j = 0; j < samples - lag; j++) { final double del1 = values[j] - mean; final double del2 = values[j + lag] - mean; gammaStat[lag] += (del1 * del2); //varGammaStat[lag] += (del1*del1*del2*del2); } gammaStat[lag] /= (samples - lag); //varGammaStat[lag] /= ((double) samples-lag); //varGammaStat[lag] -= (gammaStat[0] * gammaStat[0]); if (lag == 0) { varStat = gammaStat[0]; //varVarStat = varGammaStat[0]; //assVarCor = 1.0; } else if (lag % 2 == 0) { // fancy stopping criterion :) if (gammaStat[lag - 1] + gammaStat[lag] > 0) { varStat += 2.0 * (gammaStat[lag - 1] + gammaStat[lag]); // varVarStat += 2.0*(varGammaStat[lag-1] + varGammaStat[lag]); // assVarCor += 2.0*((gammaStat[lag-1] * gammaStat[lag-1]) + (gammaStat[lag] * gammaStat[lag])) / (gammaStat[0] * gammaStat[0]); } // stop else maxLag = lag; } } // standard error of mean stdErrorOfMean = Math.sqrt(varStat / samples); // auto correlation time autoCorrelationTime = stepSize * varStat / gammaStat[0]; // effective sample size ESS = (stepSize * samples) / autoCorrelationTime; // standard deviation of autocorrelation time stdevAutoCorrelationTime = (2.0 * Math.sqrt(2.0 * (2.0 * (maxLag + 1)) / samples) * (varStat / gammaStat[0]) * stepSize); isValid = true; } public double getMinimum() { return minimum; } public double getMaximum() { return maximum; } public double getMean() { return mean; } public double getMedian() { return median; } public double getGeometricMean() { if (hasGeometricMean) return geometricMean; return Double.NaN; } public double getStdev() { return stdev; } public double getVariance() { return variance; } public double getCpdLower() { return cpdLower; } public double getCpdUpper() { return cpdUpper; } public double getHpdLower() { return hpdLower; } public double getHpdUpper() { return hpdUpper; } public double getESS() { return ESS; } public double getStdErrorOfMean() { return stdErrorOfMean; } public double getAutoCorrelationTime() { return autoCorrelationTime; } public double getStdevAutoCorrelationTime() { return stdevAutoCorrelationTime; } }