/*
* PathLikelihood.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.evomodel.continuous.SoftThresholdLikelihood;
import dr.xml.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
/**
* A likelihood function which is simply the product of a set of likelihood functions.
*
* @author Andrew Rambaut
* @author Alex Alekseyenko
* @author Marc Suchard
* @version $Id: CompoundLikelihood.java,v 1.19 2005/05/25 09:14:36 rambaut Exp $
*/
public class PathLikelihood implements Likelihood {
public static final String PATH_LIKELIHOOD = "pathLikelihood";
public static final String PATH_PARAMETER = "theta";
public static final String DIFFERENCE = "delta";
public static final String SOURCE = "source";
public static final String DESTINATION = "destination";
public static final String PSUEDO_SOURCE = "sourcePseudoPrior";
public static final String PSUEDO_DESTINATION = "destinationPseudoPrior";
public PathLikelihood(Likelihood source, Likelihood destination) {
this(source, destination, null, null);
}
public PathLikelihood(Likelihood source, Likelihood destination,
Likelihood pseudoSource, Likelihood pseudoDestination) {
this.source = source;
this.destination = destination;
this.pseudoSource = pseudoSource;
this.pseudoDestination = pseudoDestination;
if(source!=null) {
for (int j = 0; j < source.getModel().getModelCount(); j++) {
for (int i = 0; i < source.getModel().getModel(j).getModelCount(); i++) {
if (source.getModel().getModel(j).getModel(i) instanceof SoftThresholdLikelihood) {
thresholdSofteners.add((SoftThresholdLikelihood) source.getModel().getModel(j).getModel(i));
}
}
}
}
if(pseudoSource!=null){
for (int i = 0; i < pseudoSource.getModel().getModelCount(); i++) {
if(pseudoSource.getModel().getModel(i) instanceof SoftThresholdLikelihood){
thresholdSofteners.add((SoftThresholdLikelihood) pseudoSource.getModel().getModel(i));
}
}
}
compoundModel.addModel(source.getModel());
compoundModel.addModel(destination.getModel());
}
public double getPathParameter() {
return pathParameter;
}
public void setPathParameter(double pathParameter) {
this.pathParameter = pathParameter;
if(thresholdSofteners!=null){
for(SoftThresholdLikelihood threshold:thresholdSofteners){
threshold.setPathParameter(pathParameter);
}
}
}
// **************************************************************
// Likelihood IMPLEMENTATION
// **************************************************************
public Model getModel() {
return compoundModel;
}
public double getLogLikelihood() {
// Depends on complete model (include pseudo-densities)
return (source.getLogLikelihood() * pathParameter) + (destination.getLogLikelihood() * (1.0 - pathParameter));
}
public Likelihood getSourceLikelihood() {
return source;
}
public Likelihood getDestinationLikelihood() {
return destination;
}
@Override
public Set<Likelihood> getLikelihoodSet() {
Set<Likelihood> set = new HashSet<Likelihood>();
set.add(source);
set.add(destination);
return set;
}
public void makeDirty() {
source.makeDirty();
destination.makeDirty();
}
public boolean evaluateEarly() {
return false;
}
public String toString() {
return Double.toString(getLogLikelihood());
}
// **************************************************************
// Loggable IMPLEMENTATION
// **************************************************************
/**
* @return the log columns.
*/
public dr.inference.loggers.LogColumn[] getColumns() {
return new dr.inference.loggers.LogColumn[]{
new DeltaLogLikelihoodColumn(getId() + "." + DIFFERENCE),
new PosteriorColumn(getId() + "." + SOURCE),
new PriorColumn(getId() + "." + DESTINATION),
new ThetaColumn(getId() + "." + PATH_PARAMETER),
new PathLikelihoodColumn(getId() + "." + PATH_LIKELIHOOD)
};
}
private class PriorColumn extends dr.inference.loggers.NumberColumn {
public PriorColumn(String label) {
super(label);
}
public double getDoubleValue() {
//assume that the prior is the destination in the BEAST xml
return destination.getLogLikelihood();
}
}
private class PosteriorColumn extends dr.inference.loggers.NumberColumn {
public PosteriorColumn(String label) {
super(label);
}
public double getDoubleValue() {
//assume that the posterior is the source in the BEAST xml
return source.getLogLikelihood();
}
}
private class DeltaLogLikelihoodColumn extends dr.inference.loggers.NumberColumn {
public DeltaLogLikelihoodColumn(String label) {
super(label);
}
public double getDoubleValue() {
// Remove pseudo-densities
double totalLikelihoodCorrection = 0;
if(thresholdSofteners!=null){
for(SoftThresholdLikelihood threshold:thresholdSofteners){
totalLikelihoodCorrection += threshold.getLikelihoodCorrection();
}
}
double logDensity = source.getLogLikelihood() - destination.getLogLikelihood() + totalLikelihoodCorrection;
if (pseudoSource != null) {
logDensity -= pseudoSource.getLogLikelihood();
}
if (pseudoDestination != null) {
// System.err.println("value = "+pseudoDestination.getLogLikelihood());
// logDensity += pseudoDestination.getLogLikelihood();
}
return logDensity;
}
}
private class ThetaColumn extends dr.inference.loggers.NumberColumn {
public ThetaColumn(String label) {
super(label);
}
public double getDoubleValue() {
return pathParameter;
}
}
private class PathLikelihoodColumn extends dr.inference.loggers.NumberColumn {
public PathLikelihoodColumn(String label) {
super(label);
}
public double getDoubleValue() {
return getLogLikelihood();
}
}
public boolean isUsed() {
return isUsed;
}
public void setUsed() {
isUsed = true;
}
private boolean isUsed = false;
// **************************************************************
// Identifiable IMPLEMENTATION
// **************************************************************
private String id = null;
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
public String prettyName() {
return Abstract.getPrettyName(this);
}
public static XMLObjectParser PARSER = new AbstractXMLObjectParser() {
public String getParserName() {
return PATH_LIKELIHOOD;
}
public Object parseXMLObject(XMLObject xo) throws XMLParseException {
Likelihood source = (Likelihood) xo.getElementFirstChild(SOURCE);
Likelihood destination = (Likelihood) xo.getElementFirstChild(DESTINATION);
Likelihood pseudoSource = null;
if (xo.hasChildNamed(PSUEDO_SOURCE)) {
pseudoSource = (Likelihood) xo.getElementFirstChild(PSUEDO_SOURCE);
}
Likelihood pseudoDestination = null;
if (xo.hasChildNamed(PSUEDO_DESTINATION)) {
pseudoDestination = (Likelihood) xo.getElementFirstChild(PSUEDO_DESTINATION);
}
return new PathLikelihood(source, destination, pseudoSource, pseudoDestination);
}
//************************************************************************
// AbstractXMLObjectParser implementation
//************************************************************************
public String getParserDescription() {
return "A likelihood function used for estimating marginal likelihoods and Bayes factors using path sampling.";
}
public XMLSyntaxRule[] getSyntaxRules() {
return rules;
}
private final XMLSyntaxRule[] rules = {
new ElementRule(SOURCE,
new XMLSyntaxRule[]{new ElementRule(Likelihood.class)}),
new ElementRule(DESTINATION,
new XMLSyntaxRule[]{new ElementRule(Likelihood.class)}),
new ElementRule(PSUEDO_SOURCE,
new XMLSyntaxRule[]{new ElementRule(Likelihood.class)}, true),
new ElementRule(PSUEDO_DESTINATION,
new XMLSyntaxRule[]{new ElementRule(Likelihood.class)}, true),
};
public Class getReturnType() {
return CompoundLikelihood.class;
}
};
private final Likelihood source;
private final Likelihood destination;
private final Likelihood pseudoSource;
private final Likelihood pseudoDestination;
private double pathParameter;
private final CompoundModel compoundModel = new CompoundModel("compoundModel");
private ArrayList<SoftThresholdLikelihood> thresholdSofteners=new ArrayList<SoftThresholdLikelihood>();
}