/*
* ReflectedNormalDistribution.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.math.distributions;
import dr.math.UnivariateFunction;
import org.apache.commons.math.ConvergenceException;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math.analysis.integration.RombergIntegrator;
import org.apache.commons.math.analysis.integration.UnivariateRealIntegrator;
/**
* reflected normal distribution (pdf, cdf, quantile)
*
* @author Alexei Drummond
* @author Marc Suchard
*/
public class ReflectedNormalDistribution implements Distribution {
//
// Public stuff
//
double lower;
double upper;
double precision;
double m;
double sd;
/**
* Constructor
*/
public ReflectedNormalDistribution(double mean, double sd, double lower, double upper, double precision) {
this.m = mean;
this.sd = sd;
this.lower = lower;
this.upper = upper;
this.precision = precision;
}
public double getMean() {
return m;
}
public void setMean(double value) {
m = value;
}
public double getSD() {
return sd;
}
public void setSD(double value) {
sd = value;
}
public double pdf(double x) {
if (x < lower) return 0;
if (x > upper) return 0;
double pdf = NormalDistribution.pdf(x, m, sd);
double newPDF = pdf;
System.out.println("N(" + x + ",m,sd)=" + pdf);
int i = 1;
do {
pdf = newPDF;
int A = 2 * ((i + 1) / 2); // 2 2 4 4 6 6
int B = 2 * (i / 2); // 0 2 2 4 4 6
int C = i % 2 == 0 ? -1 : 1; // 1 -1 1 -1 1 -1
double leftPDF = NormalDistribution.pdf(A * lower - C * x - B * upper, m, sd);
double rightPDF = NormalDistribution.pdf(A * upper - C * x - B * lower, m, sd);
newPDF = leftPDF + rightPDF + pdf;
i += 1;
System.out.println("newPDF=" + newPDF + " A=" + A + " B=" + B + " C=" + C);
} while (newPDF - pdf > precision);
return newPDF;
}
public double logPdf(double x) {
throw new RuntimeException("Not implemented!");
}
public double cdf(double x) {
throw new RuntimeException("Not implemented!");
}
public double quantile(double y) {
throw new RuntimeException("Not implemented!");
}
public double mean() {
throw new RuntimeException("Not implemented!");
}
public double variance() {
throw new RuntimeException("Not implemented!");
}
public final UnivariateFunction getProbabilityDensityFunction() {
return pdfFunction;
}
private final UnivariateFunction pdfFunction = new UnivariateFunction() {
public final double evaluate(double x) {
return pdf(x);
}
public final double getLowerBound() {
return lower;
}
public final double getUpperBound() {
return upper;
}
};
public static void main(String[] args) {
// final ReflectedNormalDistribution rnd = new ReflectedNormalDistribution(2, 2, 0.5, 2, 1e-6);
final ReflectedNormalDistribution rnd = new ReflectedNormalDistribution(2, 2, 1, 2, 1e-6);
rnd.pdf(1);
UnivariateRealFunction f = new UnivariateRealFunction() {
public double value(double v) throws FunctionEvaluationException {
return rnd.pdf(v);
}
};
final UnivariateRealIntegrator integrator = new RombergIntegrator();
integrator.setAbsoluteAccuracy(1e-14);
integrator.setMaximalIterationCount(16); // fail if it takes too much time
double x;
try {
x = integrator.integrate(f, rnd.lower, rnd.upper);
// ptotErr += cdf != 0.0 ? Math.abs(x-cdf)/cdf : x;
// np += 1;
//assertTrue("" + shape + "," + scale + "," + value + " " + Math.abs(x-cdf)/x + "> 1e-6", Math.abs(1-cdf/x) < 1e-6);
System.out.println("Integrated pdf = " + x);
//System.out.println(shape + "," + scale + " " + value);
} catch (ConvergenceException e) {
// can't integrate , skip test
// System.out.println(shape + "," + scale + " skipped");
} catch (FunctionEvaluationException e) {
throw new RuntimeException("I have no idea why I am here.");
}
}
}