/*
* TraceCorrelation.java
*
* Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard
*
* This file is part of BEAST.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership and licensing.
*
* BEAST is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* BEAST 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with BEAST; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package dr.inference.trace;
import java.util.List;
/**
* A class that stores the correlation statistics for a trace.
* The difference to TraceDistribution is mainly to add ACT and ESS
* which require stepSize.
*
* @author Andrew Rambaut
* @author Alexei Drummond
* @version $Id: TraceCorrelation.java,v 1.2 2006/11/29 14:53:53 rambaut Exp $
*/
public class TraceCorrelation<T> extends TraceDistribution<T> {
final long stepSize;
public TraceCorrelation(List<T> values, TraceType traceType, long stepSize) {
super(values, traceType);
this.stepSize = stepSize;
if (stepSize > 0) {
analyseCorrelation(values, stepSize);
}
}
public double getStdErrorOfMean() {
return stdErrorOfMean;
}
public double getACT() {
return ACT;
}
public double getESS() {
return ESS;
}
//************************************************************************
// private methods
//************************************************************************
protected double stdErrorOfMean;
protected double stdErrorOfVariance;
protected double ACT;
protected double stdErrOfACT;
protected double ESS;
private static final int MAX_LAG = 2000;
private void analyseCorrelation(List<T> values, long stepSize) {
// this.values = values; // move to TraceDistribution(T[] values)
if (stepSize > 0) {
if (getTraceType().isNumber()) {
double[] doubleValues = new double[values.size()];
for (int i = 0; i < values.size(); i++) {
doubleValues[i] = ((Number) values.get(i)).doubleValue();
}
analyseCorrelationNumeric(doubleValues, stepSize);
} else if (getTraceType() == TraceType.CATEGORICAL) {
//todo Do not know how to calculate
stdErrorOfMean = Double.NaN;
ACT = Double.NaN;
ESS = Double.NaN;
stdErrOfACT = Double.NaN;
// throw new UnsupportedOperationException("should not be categorical");
} else {
throw new RuntimeException("Trace type is not recognized");
}
}
}
/**
* Analyze trace for numeric values
*
* @param values the values
* @param stepSize the sampling frequency of the values
*/
private void analyseCorrelationNumeric(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] /= ((double) (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
if (gammaStat[0]==0)
ACT = 0;
else
ACT = stepSize * varStat / gammaStat[0];
// effective sample size
if (ACT==0)
ESS=1;
else
ESS = (stepSize * samples) / ACT;
// standard deviation of autocorrelation time
stdErrOfACT = (2.0 * Math.sqrt(2.0 * (2.0 * (double) (maxLag + 1)) / samples) * (varStat / gammaStat[0]) * stepSize);
// minEqualToMax = true;
}
}