/*
* Likelihood.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.model;
import dr.inference.loggers.Loggable;
import dr.util.Identifiable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* classes that calculate likelihoods should implement this interface.
*
* @author Alexei Drummond
* @author Andrew Rambaut
* @version $Id: Likelihood.java,v 1.16 2005/05/24 20:26:00 rambaut Exp $
*/
public interface Likelihood extends Loggable, Identifiable {
/**
* Get the model.
*
* @return the model.
*/
Model getModel();
/**
* Get the log likelihood.
*
* @return the log likelihood.
*/
double getLogLikelihood();
/**
* Forces a complete recalculation of the likelihood next time getLikelihood is called
*/
void makeDirty();
/**
* @return A detailed name of likelihood for debugging.
*/
String prettyName();
/**
* Get the set of sub-component likelihoods that this likelihood uses
*
* @return
*/
Set<Likelihood> getLikelihoodSet();
/**
* @return is the likelihood used in the MCMC?
*/
boolean isUsed();
void setUsed();
/**
* @return true if this likelihood should be evaluated early (if for example it may return a zero likelihood
* and could terminate the evaluation early or is a required conditioning for another likelihood.
*/
boolean evaluateEarly();
/**
* A simple abstract base class for likelihood functions
*/
public abstract class Abstract implements Likelihood, ModelListener {
public Abstract(Model model) {
this.model = model;
if (model != null) model.addModelListener(this);
}
public void modelChangedEvent(Model model, Object object, int index) {
makeDirty();
}
// by default restore is the same as changed
public void modelRestored(Model model) {
makeDirty();
}
// **************************************************************
// Likelihood IMPLEMENTATION
// **************************************************************
/**
* Get the model.
*
* @return the model.
*/
public Model getModel() {
return model;
}
public final double getLogLikelihood() {
if (!getLikelihoodKnown()) {
logLikelihood = calculateLogLikelihood();
likelihoodKnown = true;
}
return logLikelihood;
}
public void makeDirty() {
likelihoodKnown = false;
}
/**
* Called to decide if the likelihood must be calculated. Can be overridden
* (for example, to always return false).
*
* @return true if no need to recompute likelihood
*/
protected boolean getLikelihoodKnown() {
return likelihoodKnown;
}
protected abstract double calculateLogLikelihood();
public Set<Likelihood> getLikelihoodSet() {
return new HashSet<Likelihood>(Arrays.asList(this));
}
public String toString() {
// don't call any "recalculating" stuff like getLogLikelihood() in toString -
// this interferes with the debugger.
//return getClass().getName() + "(" + getLogLikelihood() + ")";
return getClass().getName() + "(" + (getLikelihoodKnown() ? logLikelihood : "??") + ")";
}
static public String getPrettyName(Likelihood l) {
final Model m = l.getModel();
String s = l.getClass().getName();
String[] parts = s.split("\\.");
s = parts[parts.length - 1];
if (m != null) {
final String modelName = m.getModelName();
final String i = m.getId();
s = s + "(" + modelName;
if (i != null && !i.equals(modelName)) {
s = s + '[' + i + ']';
}
s = s + ")";
}
return s;
}
public String prettyName() {
return getPrettyName(this);
}
public boolean isUsed() {
return used;
}
public void setUsed() {
this.used = true;
}
public boolean evaluateEarly() {
return false;
}
// **************************************************************
// Loggable IMPLEMENTATION
// **************************************************************
/**
* @return the log columns.
*/
public dr.inference.loggers.LogColumn[] getColumns() {
return new dr.inference.loggers.LogColumn[]{
new LikelihoodColumn(getId())
};
}
private class LikelihoodColumn extends dr.inference.loggers.NumberColumn {
public LikelihoodColumn(String label) {
super(label);
}
public double getDoubleValue() {
return getLogLikelihood();
}
}
// **************************************************************
// Identifiable IMPLEMENTATION
// **************************************************************
private String id = null;
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
private final Model model;
private double logLikelihood;
private boolean likelihoodKnown = false;
private boolean used = false;
}
// set to store all created likelihoods
final static Set<Likelihood> FULL_LIKELIHOOD_SET = new HashSet<Likelihood>();
final static Set<Likelihood> CONNECTED_LIKELIHOOD_SET = new HashSet<Likelihood>();
}