/*
* PriorType.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.app.beauti.types;
import dr.app.beauti.options.Parameter;
import dr.app.beauti.util.NumberUtil;
import dr.math.distributions.*;
/**
* @author Alexei Drummond
* @author Andrew Rambaut
*/
public enum PriorType {
UNDEFINED("undefined", false, false, false),
NONE_TREE_PRIOR("None (Tree Prior Only)", false, false, false),
NONE_STATISTIC("None (Statistic)", false, false, false),
NONE_IMPROPER("Infinite Uniform (Improper)", true, false, false),
NONE_FIXED("Fixed value", true, false, false),
UNIFORM_PRIOR("Uniform", true, false, false),
EXPONENTIAL_PRIOR("Exponential", true, true, true),
LAPLACE_PRIOR("Laplace", true, true, true),
NORMAL_PRIOR("Normal", true, true, true),
LOGNORMAL_PRIOR("Lognormal", true, true, true),
GAMMA_PRIOR("Gamma", true, true, true),
INVERSE_GAMMA_PRIOR("Inverse Gamma", true, true, true),
BETA_PRIOR("Beta", true, true, true),
ONE_OVER_X_PRIOR("1/x", true, true, false),
DIRICHLET_PRIOR("Dirichlet", false, false, false),
CTMC_RATE_REFERENCE_PRIOR("CTMC Rate Reference", true, false, false),
LOGNORMAL_HPM_PRIOR("Lognormal HPM", true, false, false),
NORMAL_HPM_PRIOR("Normal HPM", true, false, false),
LINKED_PARAMETER("Linked Parameter", false, false, false),
POISSON_PRIOR("Poisson", true, false, false);
PriorType(final String name, final boolean isInitializable, final boolean isTruncatable, final boolean isPlottable) {
this.name = name;
this.isInitializable = isInitializable;
this.isTruncatable = isTruncatable;
this.isPlottable = isPlottable;
}
public String toString() {
return name;
}
public Distribution getDistributionInstance(Parameter parameter) {
Distribution dist = null;
switch (this) {
case UNIFORM_PRIOR:
dist = new UniformDistribution(parameter.getLowerBound(), parameter.getUpperBound());
break;
case EXPONENTIAL_PRIOR:
if (parameter.mean == 0)
throw new IllegalArgumentException("The mean of exponential prior cannot be 0.");
dist = new OffsetPositiveDistribution(new ExponentialDistribution(1.0 / parameter.mean), parameter.offset);
break;
case LAPLACE_PRIOR:
dist = new LaplaceDistribution(parameter.mean, parameter.scale);
break;
case NORMAL_PRIOR:
dist = new NormalDistribution(parameter.mean, parameter.stdev);
break;
case LOGNORMAL_PRIOR:
dist = new OffsetPositiveDistribution(new LogNormalDistribution(parameter.mean, parameter.stdev), parameter.offset);
break;
case GAMMA_PRIOR:
dist = new OffsetPositiveDistribution(new GammaDistribution(parameter.shape, parameter.scale), parameter.offset);
break;
case INVERSE_GAMMA_PRIOR:
dist = new OffsetPositiveDistribution(new InverseGammaDistribution(parameter.shape, parameter.scale), parameter.offset);
break;
case POISSON_PRIOR:
dist = new OffsetPositiveDistribution(new PoissonDistribution(parameter.mean), parameter.offset);
break;
case BETA_PRIOR:
dist = new OffsetPositiveDistribution(new BetaDistribution(parameter.shape, parameter.shapeB), parameter.offset);
break;
// The rest do not give a distribution class (return null)
case UNDEFINED:
break;
case NONE_TREE_PRIOR:
break;
case NONE_STATISTIC:
break;
case NONE_FIXED:
break;
case ONE_OVER_X_PRIOR:
break;
case CTMC_RATE_REFERENCE_PRIOR:
break;
case LINKED_PARAMETER:
break;
case NORMAL_HPM_PRIOR:
break;
case LOGNORMAL_HPM_PRIOR:
break;
}
if (dist != null && parameter.isTruncated) {
dist = new TruncatedDistribution(dist, parameter.getLowerBound(), parameter.getUpperBound());
}
return dist;
}
public String getPriorString(Parameter parameter) {
// NumberFormat formatter = NumberFormat.getNumberInstance();
StringBuffer buffer = new StringBuffer();
if (parameter.priorType == PriorType.UNDEFINED) {
buffer.append("? ");
} else if (parameter.isPriorImproper()) {
buffer.append("! ");
} else if (!parameter.isPriorEdited()) {
buffer.append("* ");
} else {
buffer.append(" ");
}
double lower = parameter.getLowerBound();
double upper = parameter.getUpperBound();
switch (parameter.priorType) {
case NONE_IMPROPER:
buffer.append("Uniform infinite bounds");
break;
case NONE_TREE_PRIOR:
buffer.append("Using Tree Prior");
break;
case NONE_STATISTIC:
buffer.append("Indirectly Specified Through Other Parameter");
break;
case NONE_FIXED:
buffer.append("Fixed value");
break;
case UNDEFINED:
buffer.append("Not yet specified");
break;
case UNIFORM_PRIOR:
if (!parameter.isDiscrete) { // && !param.isStatistic) {
buffer.append("Uniform [");
buffer.append(NumberUtil.formatDecimal(lower, 10, 6));
buffer.append(", ");
buffer.append(NumberUtil.formatDecimal(upper, 10, 6));
buffer.append("]");
} else {
buffer.append("Uniform");
}
break;
case EXPONENTIAL_PRIOR:
buffer.append("Exponential [");
buffer.append(NumberUtil.formatDecimal(parameter.mean, 10, 6));
buffer.append("]");
break;
case LAPLACE_PRIOR:
buffer.append("Laplace [");
buffer.append(NumberUtil.formatDecimal(parameter.mean, 10, 6));
buffer.append(", ");
buffer.append(NumberUtil.formatDecimal(parameter.scale, 10, 6));
buffer.append("]");
break;
case NORMAL_PRIOR:
buffer.append("Normal [");
buffer.append(NumberUtil.formatDecimal(parameter.mean, 10, 6));
buffer.append(", ");
buffer.append(NumberUtil.formatDecimal(parameter.stdev, 10, 6));
buffer.append("]");
break;
case LOGNORMAL_PRIOR:
buffer.append("LogNormal [");
if (parameter.isMeanInRealSpace()) buffer.append("R");
buffer.append(NumberUtil.formatDecimal(parameter.mean, 10, 6));
buffer.append(", ");
buffer.append(NumberUtil.formatDecimal(parameter.stdev, 10, 6));
buffer.append("]");
break;
case GAMMA_PRIOR:
buffer.append("Gamma [");
buffer.append(NumberUtil.formatDecimal(parameter.shape, 10, 6));
buffer.append(", ");
buffer.append(NumberUtil.formatDecimal(parameter.scale, 10, 6));
buffer.append("]");
break;
case INVERSE_GAMMA_PRIOR:
buffer.append("Inverse Gamma [");
buffer.append(NumberUtil.formatDecimal(parameter.shape, 10, 6));
buffer.append(", ");
buffer.append(NumberUtil.formatDecimal(parameter.scale, 10, 6));
buffer.append("]");
break;
case DIRICHLET_PRIOR:
buffer.append("Dirichlet [1,1]");
break;
case ONE_OVER_X_PRIOR:
buffer.append("1/x");
break;
case POISSON_PRIOR:
buffer.append("Poisson [");
buffer.append(NumberUtil.formatDecimal(parameter.mean, 10, 6));
buffer.append("]");
break;
case BETA_PRIOR:
buffer.append("Beta [");
buffer.append(NumberUtil.formatDecimal(parameter.shape, 10, 6));
buffer.append(", ");
buffer.append(NumberUtil.formatDecimal(parameter.shapeB, 10, 6));
buffer.append("]");
break;
case CTMC_RATE_REFERENCE_PRIOR:
buffer.append("Approx. Reference Prior");
break;
case LINKED_PARAMETER:
buffer.append("Linked [");
buffer.append(parameter.linkedName);
buffer.append("]");
break;
case NORMAL_HPM_PRIOR:
buffer.append("Normal HPM [");
buffer.append(parameter.linkedName);
buffer.append("]");
break;
case LOGNORMAL_HPM_PRIOR:
buffer.append("Lognormal HPM [");
buffer.append(parameter.linkedName);
buffer.append("]");
break;
default:
throw new IllegalArgumentException("Unknown prior type");
}
if (parameter.isTruncated) {
buffer.append(" in [");
buffer.append(NumberUtil.formatDecimal(parameter.truncationLower, 10, 6));
buffer.append(", ");
buffer.append(NumberUtil.formatDecimal(parameter.truncationUpper, 10, 6));
buffer.append("]");
}
if (parameter.priorType == NONE_FIXED) {
buffer.append(", value=").append(NumberUtil.formatDecimal(parameter.getInitial(), 10, 6));
} else if (parameter.priorType.isInitializable && parameter.getInitial() != Double.NaN) {
buffer.append(", initial=").append(NumberUtil.formatDecimal(parameter.getInitial(), 10, 6));
}
return buffer.toString();
}
public String getPriorBoundString(Parameter parameter) {
if (parameter.isStatistic) {
return "n/a";
}
double lower = parameter.getLowerBound();
double upper = parameter.getUpperBound();
// NumberFormat formatter = NumberFormat.getNumberInstance();
StringBuffer buffer = new StringBuffer();
buffer.append("[");
buffer.append(NumberUtil.formatDecimal(lower, 10, 6));
buffer.append(", ");
buffer.append(NumberUtil.formatDecimal(upper, 10, 6));
buffer.append("]");
return buffer.toString();
}
public static PriorType[] getPriorTypes(Parameter parameter) {
if (parameter.isDiscrete) {
return new PriorType[]{
UNIFORM_PRIOR,
POISSON_PRIOR};
}
if (parameter.isNodeHeight) {
if (parameter.isCalibratedYule) {
return new PriorType[]{
NONE_TREE_PRIOR,
UNIFORM_PRIOR,
EXPONENTIAL_PRIOR,
NORMAL_PRIOR,
LOGNORMAL_PRIOR,
GAMMA_PRIOR};
} else {
return new PriorType[]{
NONE_TREE_PRIOR,
UNIFORM_PRIOR,
EXPONENTIAL_PRIOR,
LAPLACE_PRIOR,
NORMAL_PRIOR,
LOGNORMAL_PRIOR,
GAMMA_PRIOR,
INVERSE_GAMMA_PRIOR,
ONE_OVER_X_PRIOR};
}
}
if (parameter.isStatistic) {
if (parameter.isCalibratedYule) {
return new PriorType[]{
NONE_STATISTIC,
UNIFORM_PRIOR,
EXPONENTIAL_PRIOR,
NORMAL_PRIOR,
LOGNORMAL_PRIOR,
GAMMA_PRIOR};
} else {
return new PriorType[]{
NONE_STATISTIC,
UNIFORM_PRIOR,
EXPONENTIAL_PRIOR,
LAPLACE_PRIOR,
NORMAL_PRIOR,
LOGNORMAL_PRIOR,
GAMMA_PRIOR,
INVERSE_GAMMA_PRIOR,
ONE_OVER_X_PRIOR};
}
}
if (parameter.isCMTCRate) {
return new PriorType[]{
NONE_FIXED,
CTMC_RATE_REFERENCE_PRIOR,
NONE_IMPROPER,
UNIFORM_PRIOR,
EXPONENTIAL_PRIOR,
NORMAL_PRIOR,
LOGNORMAL_PRIOR,
GAMMA_PRIOR,
INVERSE_GAMMA_PRIOR,
ONE_OVER_X_PRIOR};
}
if (parameter.isHierarchical) {
return new PriorType[]{
LOGNORMAL_HPM_PRIOR,
NORMAL_HPM_PRIOR};
}
if (parameter.isMaintainedSum) {
return new PriorType[]{
NONE_FIXED,
NONE_IMPROPER,
DIRICHLET_PRIOR,
UNIFORM_PRIOR,
EXPONENTIAL_PRIOR,
NORMAL_PRIOR,
LOGNORMAL_PRIOR,
GAMMA_PRIOR,
INVERSE_GAMMA_PRIOR};
}
if (parameter.isZeroOne) {
return new PriorType[]{
NONE_FIXED,
UNIFORM_PRIOR,
EXPONENTIAL_PRIOR,
NORMAL_PRIOR,
LOGNORMAL_PRIOR,
GAMMA_PRIOR,
INVERSE_GAMMA_PRIOR,
BETA_PRIOR};
}
if (parameter.isNonNegative) {
return new PriorType[]{
NONE_FIXED,
NONE_IMPROPER,
UNIFORM_PRIOR,
EXPONENTIAL_PRIOR,
LAPLACE_PRIOR,
NORMAL_PRIOR,
LOGNORMAL_PRIOR,
GAMMA_PRIOR,
INVERSE_GAMMA_PRIOR,
ONE_OVER_X_PRIOR};
}
// just a continuous parameter
return new PriorType[]{
NONE_FIXED,
NONE_IMPROPER,
UNIFORM_PRIOR,
EXPONENTIAL_PRIOR,
LAPLACE_PRIOR,
NORMAL_PRIOR,
LOGNORMAL_PRIOR,
GAMMA_PRIOR,
INVERSE_GAMMA_PRIOR};
}
public String getName() {
return name;
}
public boolean isTruncatable() {
return isTruncatable;
}
public boolean isPlottable() {
return isPlottable;
}
private final String name;
public final boolean isInitializable;
public final boolean isTruncatable;
public final boolean isPlottable;
}