/*
* GMRFBivariateCurveAnalysis.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.evomodel.coalescent;
import dr.inference.trace.LogFileTraces;
import dr.inference.trace.TraceException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
public class GMRFBivariateCurveAnalysis {
private LogFileTraces[] lft;
private double endTime;
private final int[] defaultIntegrationPartitionSizes = {2,5,10,15,25,50,100,1000,5000,25000};
private final int[] defaultDensityPartitionSizes = {10};
public GMRFBivariateCurveAnalysis(String[] inputFileNames, double endTime, int burnIn)
throws TraceException, IOException{
this.endTime = endTime;
lft = new LogFileTraces[2];
for(int i = 0; i < 2; i++){
File file = new File(inputFileNames[i]);
lft[i] = new LogFileTraces(inputFileNames[i], file);
lft[i].loadTraces();
lft[i].setBurnIn(burnIn);
}
}
public void densityReport(){
for(int partitionSize : defaultDensityPartitionSizes){
densityReport(partitionSize);
}
}
private void densityReport(int partitionSize){
double[][] values = new double[2][];
values[0] = new double[lft[0].getTraceCount()];
values[1] = new double[lft[1].getTraceCount()];
ArrayList<DensityResult> results = new ArrayList<DensityResult>(lft[0].getStateCount());
for(int index = 0; index < lft[0].getStateCount(); index++){
lft[0].getStateValues(index, values[0],0);
lft[1].getStateValues(index, values[1],0);
results.add(new DensityResult(getDensityReport(values, partitionSize)));
}
Collections.sort(results);
double squareRootResultsSize = Math.sqrt(results.size());
int value = (int) Math.floor(squareRootResultsSize);
double radius = results.get(value).radius;
double logVolume = dr.math.MathUtils.logHyperSphereVolume(partitionSize,radius);
System.out.println("Approximate Density at 0 with " +
partitionSize + " partitions = " +
1.0/(squareRootResultsSize*Math.exp(logVolume)));
}
private class DensityResult implements Comparable<DensityResult>{
public double[] results;
public double radius;
public DensityResult(double[] results){
this.results = results;
double a = 0;
for(double result : results){
a += result*result;
}
radius = Math.pow(a, 1.0/results.length);
}
public int compareTo(DensityResult d){
if(this.radius < d.radius){
return -1;
}else if(this.radius == d.radius){
return 0;
}
return 1;
}
public String toString(){
String a = "(";
for(double result : results){
a += Double.toString(result) + ", ";
}
a += " Radius = " + radius + " )\n";
return a;
}
}
private double[] getDensityReport(double[][] values, int partitionSize){
double[] b = new double[partitionSize];
double timeInterval = endTime/partitionSize;
double startTime = timeInterval/2.0;
for(int i = 0; i < b.length; i++){
double[] a = {
getPopSizeAtTime(values[0], startTime, values[0].length/2),
getPopSizeAtTime(values[1], startTime, values[1].length/2)
};
startTime += timeInterval;
b[i] = a[0] - a[1];
}
return b;
}
public void integrationReport(){
System.out.println("Analyzing Difference Between Curves\n");
for(int partitionSize : defaultIntegrationPartitionSizes){
integrationReport(partitionSize);
}
}
private void integrationReport(int partitionSize){
double[] results = new double[lft[0].getStateCount()];
double[][] values = new double[2][];
values[0] = new double[lft[0].getTraceCount()];
values[1] = new double[lft[1].getTraceCount()];
double startTime = endTime/(partitionSize*2);
double timeLength = endTime/partitionSize;
for(int index = 0; index < lft[0].getStateCount(); index++){
lft[0].getStateValues(index, values[0],0);
lft[1].getStateValues(index, values[1],0);
results[index] = getPartitionReport(values, startTime, timeLength);
}
double sum = 0;
for(double a : results)
sum += a;
System.out.println("Partition Size " + partitionSize + " = " + sum/results.length);
}
private double getPartitionReport(double[][] values, double startTime, double timeLength){
double b = 0;
while(startTime < endTime){
b += getPopSizeDifference(values, startTime);
startTime += timeLength;
}
b *= timeLength;
return b;
}
private double getPopSizeDifference(double[][] values, double time){
double[] a = new double[2];
for(int i = 0; i < 2; i++){
a[i] = getPopSizeAtTime(values[i],time,values[i].length/2);
}
return Math.abs(a[0] - a[1]);
}
private double getPopSizeAtTime(double[] values, double time, int numberOfPopSizes){
for(int i = 0; i < numberOfPopSizes; i++){
if(time < values[i]){
return values[numberOfPopSizes + i];
}
}
return -99;
}
}