/*
* HierarchicalModelComponentGenerator.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.components.hpm;
import dr.app.beauti.generator.BaseComponentGenerator;
import dr.app.beauti.options.BeautiOptions;
import dr.app.beauti.options.Parameter;
import dr.app.beauti.util.XMLWriter;
import dr.inference.distribution.DistributionLikelihood;
import dr.inference.model.ParameterParser;
import dr.inference.operators.MCMCOperator;
import dr.inference.operators.NormalGammaPrecisionGibbsOperator;
import dr.inference.operators.NormalNormalMeanGibbsOperator;
import dr.inferencexml.distribution.DistributionLikelihoodParser;
import dr.inferencexml.distribution.LogNormalDistributionModelParser;
import dr.inferencexml.distribution.NormalDistributionModelParser;
import dr.inferencexml.distribution.PriorParsers;
import dr.util.Attribute;
import dr.xml.XMLParser;
import java.util.List;
/**
* @author Marc A. Suchard
* @version $Id$
*/
public class HierarchicalModelComponentGenerator extends BaseComponentGenerator {
public static final String MEAN_SUFFIX = ".mean";
public static final String PRECISION_SUFFIX = ".precision";
public static final String MODEL_SUFFIX = ".model";
public static final String HPM_SUFFIX = ".hpm";
public static final String MEAN_PRIOR_SUFFIX = ".prior.mean";
public static final String PRECISION_PRIOR_SUFFIX = ".prior.precision";
public HierarchicalModelComponentGenerator(final BeautiOptions options) {
super(options);
}
public boolean usesInsertionPoint(final InsertionPoint point) {
HierarchicalModelComponentOptions comp = (HierarchicalModelComponentOptions)
options.getComponentOptions(HierarchicalModelComponentOptions.class);
switch (point) {
case AFTER_TREE_LIKELIHOOD:
case IN_OPERATORS:
case IN_MCMC_PRIOR:
case IN_FILE_LOG_PARAMETERS:
return !comp.isEmpty();
default:
return false;
}
}
protected void generate(final InsertionPoint point, final Object item, final String prefix, final XMLWriter writer) {
HierarchicalModelComponentOptions comp = (HierarchicalModelComponentOptions)
options.getComponentOptions(HierarchicalModelComponentOptions.class);
switch (point) {
case AFTER_TREE_LIKELIHOOD:
generateDistributions(comp.getHPMList(), writer);
break;
case IN_OPERATORS:
generateOperators(comp.getHPMList(), writer);
break;
case IN_MCMC_PRIOR:
generatePriors(comp.getHPMList(), writer);
break;
case IN_FILE_LOG_PARAMETERS:
generateLogs(comp.getHPMList(), writer);
break;
default:
throw new IllegalArgumentException("This insertion point is not implemented for " + this.getClass().getName());
}
}
private void generateOperators(List<HierarchicalPhylogeneticModel> hpmList, XMLWriter writer) {
for (HierarchicalPhylogeneticModel hpm : hpmList) {
generateOperators(hpm, writer);
}
}
private void generateOperators(HierarchicalPhylogeneticModel hpm, XMLWriter writer) {
// Generate Normal-normal operator on mean
writer.writeOpenTag(NormalNormalMeanGibbsOperator.OPERATOR_NAME, getOperatorAttributes());
writer.writeOpenTag(NormalNormalMeanGibbsOperator.LIKELIHOOD);
writer.writeIDref(DistributionLikelihoodParser.DISTRIBUTION, getDistributionName(hpm));
writer.writeCloseTag(NormalNormalMeanGibbsOperator.LIKELIHOOD);
writer.writeOpenTag(NormalNormalMeanGibbsOperator.PRIOR);
writer.writeIDref(PriorParsers.NORMAL_PRIOR, getMeanPriorName(hpm));
writer.writeCloseTag(NormalNormalMeanGibbsOperator.PRIOR);
writer.writeCloseTag(NormalNormalMeanGibbsOperator.OPERATOR_NAME);
// Generate Gamma-normal operator on precision
writer.writeOpenTag(NormalGammaPrecisionGibbsOperator.OPERATOR_NAME, getOperatorAttributes());
writer.writeOpenTag(NormalGammaPrecisionGibbsOperator.LIKELIHOOD);
writer.writeIDref(DistributionLikelihoodParser.DISTRIBUTION, getDistributionName(hpm));
writer.writeCloseTag(NormalGammaPrecisionGibbsOperator.LIKELIHOOD);
writer.writeOpenTag(NormalGammaPrecisionGibbsOperator.PRIOR);
writer.writeIDref(PriorParsers.GAMMA_PRIOR, getPrecisionPriorName(hpm));
writer.writeCloseTag(NormalGammaPrecisionGibbsOperator.PRIOR);
writer.writeCloseTag(NormalGammaPrecisionGibbsOperator.OPERATOR_NAME);
}
private void generateLogs(List<HierarchicalPhylogeneticModel> hpmList, XMLWriter writer) {
for (HierarchicalPhylogeneticModel hpm : hpmList) {
generateLog(hpm, writer);
}
}
private void generateLog(HierarchicalPhylogeneticModel hpm, XMLWriter writer) {
for (Parameter parameter : hpm.getConditionalParameterList()) {
writer.writeIDref(ParameterParser.PARAMETER, parameter.getName());
}
}
private void generatePriors(List<HierarchicalPhylogeneticModel> hpmList, XMLWriter writer) {
for (HierarchicalPhylogeneticModel hpm : hpmList) {
generatePrior(hpm, writer);
}
}
private void generatePrior(HierarchicalPhylogeneticModel hpm, XMLWriter writer) {
writer.writeIDref(DistributionLikelihood.DISTRIBUTION_LIKELIHOOD, getDistributionName(hpm));
writer.writeIDref(PriorParsers.NORMAL_PRIOR, getMeanPriorName(hpm));
writer.writeIDref(PriorParsers.GAMMA_PRIOR, getPrecisionPriorName(hpm));
}
private void generateDistributions(List<HierarchicalPhylogeneticModel> hpmList, XMLWriter writer) {
for (HierarchicalPhylogeneticModel hpm : hpmList) {
generateDistribution(hpm, writer);
generateNormalAndGammaPrior(hpm, writer);
}
}
private String getModelTagName(HierarchicalPhylogeneticModel hpm) {
switch (hpm.getPriorType()) {
case NORMAL_HPM_PRIOR:
return NormalDistributionModelParser.NORMAL_DISTRIBUTION_MODEL;
case LOGNORMAL_HPM_PRIOR:
return LogNormalDistributionModelParser.LOGNORMAL_DISTRIBUTION_MODEL;
default:
}
throw new RuntimeException("Unimplemented HPM prior type");
}
private String getDistributionName(HierarchicalPhylogeneticModel hpm) {
return hpm.getName() + HPM_SUFFIX;
}
private String getModelName(HierarchicalPhylogeneticModel hpm) {
return hpm.getName() + MODEL_SUFFIX;
}
private Attribute[] getOperatorAttributes() {
return new Attribute[] {
new Attribute.Default<Double>(MCMCOperator.WEIGHT, 1.0),
};
}
private Attribute[] getModelAttributes(HierarchicalPhylogeneticModel hpm) {
switch (hpm.getPriorType()){
case NORMAL_HPM_PRIOR:
return new Attribute[] {
new Attribute.Default<String>(XMLParser.ID, getModelName(hpm)),
};
case LOGNORMAL_HPM_PRIOR:
return new Attribute[] {
new Attribute.Default<String>(XMLParser.ID, getModelName(hpm)),
new Attribute.Default<Boolean>(LogNormalDistributionModelParser.MEAN_IN_REAL_SPACE, false),
};
default:
}
throw new RuntimeException("Unimplemented HPM prior type");
}
private Attribute[] getMeanPriorAttributes(HierarchicalPhylogeneticModel hpm) {
return new Attribute[] {
new Attribute.Default<String>(XMLParser.ID, getMeanPriorName(hpm)),
new Attribute.Default<Double>(PriorParsers.MEAN, hpm.getConditionalParameterList().get(0).mean),
new Attribute.Default<Double>(PriorParsers.STDEV, hpm.getConditionalParameterList().get(0).stdev),
};
}
private String getMeanPriorName(HierarchicalPhylogeneticModel hpm) {
return hpm.getName() + MEAN_PRIOR_SUFFIX;
}
private String getPrecisionPriorName(HierarchicalPhylogeneticModel hpm) {
return hpm.getName() + PRECISION_PRIOR_SUFFIX;
}
private Attribute[] getPrecisionPriorAttributes(HierarchicalPhylogeneticModel hpm) {
return new Attribute[] {
new Attribute.Default<String>(XMLParser.ID, getPrecisionPriorName(hpm)),
new Attribute.Default<Double>(PriorParsers.SHAPE, hpm.getConditionalParameterList().get(1).shape),
new Attribute.Default<Double>(PriorParsers.SCALE, hpm.getConditionalParameterList().get(1).scale),
new Attribute.Default<Double>(PriorParsers.OFFSET, 0.0),
};
}
private void generateDistribution(HierarchicalPhylogeneticModel hpm, XMLWriter writer) {
writer.writeOpenTag(DistributionLikelihood.DISTRIBUTION_LIKELIHOOD,
new Attribute[] {
new Attribute.Default<String>(XMLParser.ID, getDistributionName(hpm)),
});
// Add parameters as data
writer.writeOpenTag(DistributionLikelihoodParser.DATA);
for (Parameter parameter : hpm.getArgumentParameterList()) {
writeParameterRef(parameter.getName(), writer);
}
writer.writeCloseTag(DistributionLikelihoodParser.DATA);
// Add HPM model
writer.writeOpenTag(DistributionLikelihoodParser.DISTRIBUTION);
writer.writeOpenTag(getModelTagName(hpm), getModelAttributes(hpm));
writeParameter(NormalDistributionModelParser.MEAN,
hpm.getConditionalParameterList().get(0).getName(), 1, hpm.getConditionalParameterList().get(0).getInitial(),
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, writer);
writeParameter(NormalDistributionModelParser.PREC,
hpm.getConditionalParameterList().get(1).getName(), 1, hpm.getConditionalParameterList().get(1).getInitial(),
0.0, Double.POSITIVE_INFINITY, writer);
writer.writeCloseTag(getModelTagName(hpm));
writer.writeCloseTag(DistributionLikelihoodParser.DISTRIBUTION);
writer.writeCloseTag(DistributionLikelihood.DISTRIBUTION_LIKELIHOOD);
}
private void generateNormalAndGammaPrior(HierarchicalPhylogeneticModel hpm, XMLWriter writer) {
// Normal prior on mean
writer.writeOpenTag(PriorParsers.NORMAL_PRIOR, getMeanPriorAttributes(hpm));
writer.writeIDref(ParameterParser.PARAMETER, hpm.getConditionalParameterList().get(0).getName());
writer.writeCloseTag(PriorParsers.NORMAL_PRIOR);
// Gamma prior on precision
writer.writeOpenTag(PriorParsers.GAMMA_PRIOR, getPrecisionPriorAttributes(hpm));
writer.writeIDref(ParameterParser.PARAMETER, hpm.getConditionalParameterList().get(1).getName());
writer.writeCloseTag(PriorParsers.GAMMA_PRIOR);
}
protected String getCommentLabel() {
return "Hierarchical phylogenetic models";
}
}