/*
* DistributionLikelihood.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.distribution;
import dr.math.distributions.Distribution;
import dr.util.Attribute;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* A class that returns the log likelihood of a set of data (statistics)
* being distributed according to the given parametric distribution.
*
* @author Alexei Drummond
* @version $Id: DistributionLikelihood.java,v 1.11 2005/05/25 09:35:28 rambaut Exp $
*/
public class DistributionLikelihood extends AbstractDistributionLikelihood {
public final static boolean DEBUG = false;
public static final String DISTRIBUTION_LIKELIHOOD = "distributionLikelihood";
private int from = -1;
private int to = Integer.MAX_VALUE;
private final boolean evaluateEarly;
public DistributionLikelihood(Distribution distribution) {
this(distribution, 0.0, false, 1.0);
}
public DistributionLikelihood(Distribution distribution, double offset) {
this(distribution, offset, offset > 0.0, 1.0);
}
public DistributionLikelihood(Distribution distribution, double offset, double scale){
this(distribution, offset, offset>0.0, scale);
}
public DistributionLikelihood(Distribution distribution, boolean evaluateEarly) {
this(distribution, 0.0, evaluateEarly, 1.0);
}
public DistributionLikelihood(Distribution distribution, double offset, boolean evaluateEarly, double scale) {
super(null);
this.distribution = distribution;
this.offset = offset;
this.evaluateEarly = evaluateEarly;
this.scale=scale;
}
public DistributionLikelihood(ParametricDistributionModel distributionModel) {
super(distributionModel);
this.distribution = distributionModel;
this.offset = 0.0;
this.evaluateEarly = false;
this.scale=1.0;
}
public Distribution getDistribution() {
return distribution;
}
public void setRange(int from, int to) {
this.from = from;
this.to = to;
}
// **************************************************************
// Likelihood IMPLEMENTATION
// **************************************************************
/**
* Calculate the log likelihood of the current state.
*
* @return the log likelihood.
*/
public double calculateLogLikelihood() {
if (DEBUG) {
System.out.println("Calling DistributionLikelihood.calculateLogLikelihood()");
System.out.println(distribution.toString());
System.out.println(dataList.toString() + "\n");
}
double logL = 0.0;
for( Attribute<double[]> data : dataList ) {
// Using this in the loop is incredibly wasteful, especially in the loop condition to get the length
final double[] attributeValue = data.getAttributeValue();
for (int j = Math.max(0, from); j < Math.min(attributeValue.length, to); j++) {
final double value = attributeValue[j] - offset;
if (offset > 0.0 && value < 0.0) {
// fixes a problem with the offset on exponential distributions not
// actually bounding the distribution. This only performs this check
// if a non-zero offset is actually given otherwise it assumes the
// parameter is either legitimately allowed to go negative or is bounded
// at zero anyway.
return Double.NEGATIVE_INFINITY;
}
logL += getLogPDF(value);
}
}
return logL;
}
protected double getLogPDF(double value){
return distribution.logPdf(value/scale)/scale;
}
@Override
public boolean evaluateEarly() {
return evaluateEarly;
}
// **************************************************************
// XMLElement IMPLEMENTATION
// **************************************************************
public Element createElement(Document d) {
throw new RuntimeException("Not implemented yet!");
}
@Override
public String prettyName() {
String s = distribution.getClass().getName();
String[] parts = s.split("\\.");
s = parts[parts.length - 1];
if( s.endsWith("Distribution") ) {
s = s.substring(0, s.length() - "Distribution".length());
}
s = s + '(';
for( Attribute<double[]> data : dataList ) {
String name = data.getAttributeName();
if( name == null ) {
name = "?";
}
s = s + name + ',';
}
s = s.substring(0,s.length()-1) + ')';
return s;
}
protected Distribution distribution;
private final double offset;
private final double scale;
}