/*
* YuleModel.java
*
* Copyright (C) 2002-2009 Alexei Drummond and Andrew Rambaut
*
* 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.speciation;
import dr.evolution.tree.NodeRef;
import dr.evolution.util.Taxon;
import dr.evolution.tree.Tree;
import dr.evomodelxml.speciation.YuleModelParser;
import dr.inference.model.Parameter;
/**
* From Gernhard 2008, Yule density (p; conditioned on n nodes) should be:
* <p/>
* double p = 0.0;
* <p/>
* p = lambda^(n-1) * exp(-lambda*rootHeight);
* <p/>
* for (int i = 1; i < n; i++) {
* p *= exp(-lambda*height[i])
* }
*
* @author Alexei Drummond
* @author Roald Forsberg
*/
public class YuleModel extends UltrametricSpeciationModel {
public YuleModel(Parameter birthRateParameter, Type units) {
super("Will Chang's Yule Model", units);
this.birthRateParameter = birthRateParameter;
addVariable(birthRateParameter);
birthRateParameter.addBounds(new Parameter.DefaultBounds(Double.POSITIVE_INFINITY, 0.0, 1));
}
public double getBirthRate() {
return birthRateParameter.getParameterValue(0);
}
public void setBirthRate(double birthRate) {
birthRateParameter.setParameterValue(0, birthRate);
}
//
// functions that define a speciation model
//
public double logTreeProbability(int taxonCount) {
final double lambda = getBirthRate();
return (taxonCount - 1) * Math.log( lambda);
}
//
// functions that define a speciation model
//
public double logNodeProbability(Tree tree, NodeRef node) {
double nodeHeight = tree.getNodeHeight(node);
final double lambda = getBirthRate();
double logP = 0;
if (tree.isRoot(node)) {
logP += -2. * lambda * nodeHeight;
} else if (tree.getChildCount(node) == 0) {
Taxon taxon = tree.getNodeTaxon( node);
boolean isAdventitious = taxon != null && taxon.getAdventitious();
if( isAdventitious) {
// An adventitious doesn't count as a taxon
logP -= Math.log( lambda);
} else {
logP -= -lambda * nodeHeight;
}
} else {
Taxon taxon0 = tree.getNodeTaxon( tree.getChild(node, 0));
Taxon taxon1 = tree.getNodeTaxon( tree.getChild(node, 1));
boolean hasAdventitiousChild =
(taxon0 != null && taxon0.getAdventitious()) ||
(taxon1 != null && taxon1.getAdventitious());
// Don't reckon the branch leading up to an adventitious leaf.
if( !hasAdventitiousChild) {
logP += -lambda * nodeHeight;
}
}
return logP;
}
public boolean includeExternalNodesInLikelihoodCalculation() {
return true;
}
// **************************************************************
// XMLElement IMPLEMENTATION
// **************************************************************
public org.w3c.dom.Element createElement(org.w3c.dom.Document d) {
throw new RuntimeException("createElement not implemented");
}
//Protected stuff
Parameter birthRateParameter;
}