/* * PriorParsers.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.inferencexml.distribution; import java.io.File; import java.io.FileNotFoundException; import dr.inference.distribution.DistributionLikelihood; import dr.inference.model.Likelihood; import dr.inference.model.Statistic; import dr.inference.trace.LogFileTraces; import dr.inference.trace.TraceException; import dr.inferencexml.trace.MarginalLikelihoodAnalysisParser; import dr.math.distributions.*; import dr.util.DataTable; import dr.util.FileHelpers; import dr.xml.*; /** */ public class PriorParsers { public static final String UNIFORM_PRIOR = "uniformPrior"; public static final String EXPONENTIAL_PRIOR = "exponentialPrior"; public static final String POISSON_PRIOR = "poissonPrior"; public static final String NORMAL_PRIOR = "normalPrior"; public static final String NORMAL_REFERENCE_PRIOR = "normalReferencePrior"; public static final String LOG_NORMAL_PRIOR = "logNormalPrior"; public static final String GAMMA_PRIOR = "gammaPrior"; public static final String GAMMA_REFERENCE_PRIOR = "gammaReferencePrior"; public static final String INVGAMMA_PRIOR = "invgammaPrior"; public static final String INVGAMMA_PRIOR_CORRECT = "inverseGammaPrior"; public static final String LAPLACE_PRIOR = "laplacePrior"; public static final String BETA_PRIOR = "betaPrior"; public static final String PARAMETER_COLUMN = "parameterColumn"; public static final String UPPER = "upper"; public static final String LOWER = "lower"; public static final String MEAN = "mean"; public static final String MEAN_IN_REAL_SPACE = "meanInRealSpace"; public static final String STDEV = "stdev"; public static final String SHAPE = "shape"; public static final String SHAPEB = "shapeB"; public static final String SCALE = "scale"; public static final String OFFSET = "offset"; public static final String UNINFORMATIVE = "uninformative"; /** * A special parser that reads a convenient short form of priors on parameters. */ public static XMLObjectParser UNIFORM_PRIOR_PARSER = new AbstractXMLObjectParser() { public String getParserName() { return UNIFORM_PRIOR; } public Object parseXMLObject(XMLObject xo) throws XMLParseException { double lower = xo.getDoubleAttribute(LOWER); double upper = xo.getDoubleAttribute(UPPER); if (lower == Double.NEGATIVE_INFINITY || upper == Double.POSITIVE_INFINITY) throw new XMLParseException("Uniform prior " + xo.getName() + " cannot take a bound at infinity, " + "because it returns 1/(high-low) = 1/inf"); DistributionLikelihood likelihood = new DistributionLikelihood(new UniformDistribution(lower, upper)); for (int j = 0; j < xo.getChildCount(); j++) { if (xo.getChild(j) instanceof Statistic) { likelihood.addData((Statistic) xo.getChild(j)); } else { throw new XMLParseException("illegal element in " + xo.getName() + " element"); } } return likelihood; } public XMLSyntaxRule[] getSyntaxRules() { return rules; } private final XMLSyntaxRule[] rules = { AttributeRule.newDoubleRule(LOWER), AttributeRule.newDoubleRule(UPPER), new ElementRule(Statistic.class, 1, Integer.MAX_VALUE) }; public String getParserDescription() { return "Calculates the prior probability of some data under a given uniform distribution."; } public Class getReturnType() { return Likelihood.class; } }; /** * A special parser that reads a convenient short form of priors on parameters. */ public static XMLObjectParser EXPONENTIAL_PRIOR_PARSER = new AbstractXMLObjectParser() { public String getParserName() { return EXPONENTIAL_PRIOR; } public Object parseXMLObject(XMLObject xo) throws XMLParseException { double scale; if (xo.hasAttribute(SCALE)) { scale = xo.getDoubleAttribute(SCALE); } else { scale = xo.getDoubleAttribute(MEAN); } final double offset = xo.hasAttribute(OFFSET) ? xo.getDoubleAttribute(OFFSET) : 0.0; DistributionLikelihood likelihood = new DistributionLikelihood(new ExponentialDistribution(1.0 / scale), offset); for (int j = 0; j < xo.getChildCount(); j++) { if (xo.getChild(j) instanceof Statistic) { likelihood.addData((Statistic) xo.getChild(j)); } else { throw new XMLParseException("illegal element in " + xo.getName() + " element"); } } return likelihood; } public XMLSyntaxRule[] getSyntaxRules() { return rules; } private final XMLSyntaxRule[] rules = { new XORRule( AttributeRule.newDoubleRule(SCALE), AttributeRule.newDoubleRule(MEAN) ), AttributeRule.newDoubleRule(OFFSET, true), new ElementRule(Statistic.class, 1, Integer.MAX_VALUE) }; public String getParserDescription() { return "Calculates the prior probability of some data under a given exponential distribution."; } public Class getReturnType() { return Likelihood.class; } }; /** * A special parser that reads a convenient short form of priors on parameters. */ public static XMLObjectParser POISSON_PRIOR_PARSER = new AbstractXMLObjectParser() { public String getParserName() { return POISSON_PRIOR; } public Object parseXMLObject(XMLObject xo) throws XMLParseException { double mean = xo.getDoubleAttribute(MEAN); double offset = xo.getDoubleAttribute(OFFSET); DistributionLikelihood likelihood = new DistributionLikelihood(new PoissonDistribution(mean), offset); for (int j = 0; j < xo.getChildCount(); j++) { if (xo.getChild(j) instanceof Statistic) { likelihood.addData((Statistic) xo.getChild(j)); } else { throw new XMLParseException("illegal element in " + xo.getName() + " element"); } } return likelihood; } public XMLSyntaxRule[] getSyntaxRules() { return rules; } private final XMLSyntaxRule[] rules = { AttributeRule.newDoubleRule(MEAN), AttributeRule.newDoubleRule(OFFSET), new ElementRule(Statistic.class, 1, Integer.MAX_VALUE) }; public String getParserDescription() { return "Calculates the prior probability of some data under a given poisson distribution."; } public Class getReturnType() { return Likelihood.class; } }; /** * A special parser that reads a convenient short form of priors on parameters. */ public static XMLObjectParser NORMAL_PRIOR_PARSER = new AbstractXMLObjectParser() { public String getParserName() { return NORMAL_PRIOR; } public Object parseXMLObject(XMLObject xo) throws XMLParseException { double mean = xo.getDoubleAttribute(MEAN); double stdev = xo.getDoubleAttribute(STDEV); DistributionLikelihood likelihood = new DistributionLikelihood(new NormalDistribution(mean, stdev)); for (int j = 0; j < xo.getChildCount(); j++) { if (xo.getChild(j) instanceof Statistic) { likelihood.addData((Statistic) xo.getChild(j)); } else { throw new XMLParseException("illegal element in " + xo.getName() + " element"); } } return likelihood; } public XMLSyntaxRule[] getSyntaxRules() { return rules; } private final XMLSyntaxRule[] rules = { AttributeRule.newDoubleRule(MEAN), AttributeRule.newDoubleRule(STDEV), new ElementRule(Statistic.class, 1, Integer.MAX_VALUE) }; public String getParserDescription() { return "Calculates the prior probability of some data under a given normal distribution."; } public Class getReturnType() { return Likelihood.class; } }; /** * A special parser that reads a convenient short form of reference priors on parameters. */ public static XMLObjectParser GAMMA_REFERENCE_PRIOR_PARSER = new AbstractXMLObjectParser() { public String getParserName() { return GAMMA_REFERENCE_PRIOR; } public Object parseXMLObject(XMLObject xo) throws XMLParseException { String fileName = xo.getStringAttribute(FileHelpers.FILE_NAME); try { File file = new File(fileName); String parent = file.getParent(); if (!file.isAbsolute()) { parent = System.getProperty("user.dir"); } file = new File(parent, fileName); fileName = file.getAbsolutePath(); String parameterName = xo.getStringAttribute(PARAMETER_COLUMN); LogFileTraces traces = new LogFileTraces(fileName, file); traces.loadTraces(); int maxState = traces.getMaxState(); // leaving the burnin attribute off will result in 10% being used int burnin = xo.getAttribute("burnin", maxState / 10); if (burnin < 0 || burnin >= maxState) { burnin = maxState / 10; System.out.println("WARNING: Burn-in larger than total number of states - using 10%"); } traces.setBurnIn(burnin); int traceIndexParameter = -1; for (int i = 0; i < traces.getTraceCount(); i++) { String traceName = traces.getTraceName(i); if (traceName.trim().equals(parameterName)) { traceIndexParameter = i; } } if (traceIndexParameter == -1) { throw new XMLParseException("Column '" + parameterName + "' can not be found for " + getParserName() + " element."); } Double[] parameterSamples = new Double[traces.getStateCount()]; DistributionLikelihood likelihood = new DistributionLikelihood(new GammaKDEDistribution((Double[]) traces.getValues(traceIndexParameter).toArray(parameterSamples))); for (int j = 0; j < xo.getChildCount(); j++) { if (xo.getChild(j) instanceof Statistic) { likelihood.addData((Statistic) xo.getChild(j)); } else { throw new XMLParseException("illegal element in " + xo.getName() + " element"); } } return likelihood; } catch (FileNotFoundException fnfe) { throw new XMLParseException("File '" + fileName + "' can not be opened for " + getParserName() + " element."); } catch (java.io.IOException ioe) { throw new XMLParseException(ioe.getMessage()); } catch (TraceException e) { throw new XMLParseException(e.getMessage()); } } public XMLSyntaxRule[] getSyntaxRules() { return rules; } private final XMLSyntaxRule[] rules = { AttributeRule.newStringRule("fileName"), AttributeRule.newStringRule("parameterColumn"), AttributeRule.newIntegerRule("burnin"), new ElementRule(Statistic.class, 1, Integer.MAX_VALUE) }; public String getParserDescription() { return "Calculates the reference prior probability of some data under a given normal distribution."; } public Class getReturnType() { return Likelihood.class; } }; /** * A special parser that reads a convenient short form of reference priors on parameters. */ public static XMLObjectParser NORMAL_REFERENCE_PRIOR_PARSER = new AbstractXMLObjectParser() { public String getParserName() { return NORMAL_REFERENCE_PRIOR; } public Object parseXMLObject(XMLObject xo) throws XMLParseException { String fileName = xo.getStringAttribute(FileHelpers.FILE_NAME); try { File file = new File(fileName); String parent = file.getParent(); if (!file.isAbsolute()) { parent = System.getProperty("user.dir"); } file = new File(parent, fileName); fileName = file.getAbsolutePath(); String parameterName = xo.getStringAttribute(PARAMETER_COLUMN); LogFileTraces traces = new LogFileTraces(fileName, file); traces.loadTraces(); int maxState = traces.getMaxState(); // leaving the burnin attribute off will result in 10% being used int burnin = xo.getAttribute("burnin", maxState / 10); if (burnin < 0 || burnin >= maxState) { burnin = maxState / 10; System.out.println("WARNING: Burn-in larger than total number of states - using 10%"); } traces.setBurnIn(burnin); int traceIndexParameter = -1; for (int i = 0; i < traces.getTraceCount(); i++) { String traceName = traces.getTraceName(i); if (traceName.trim().equals(parameterName)) { traceIndexParameter = i; } } if (traceIndexParameter == -1) { throw new XMLParseException("Column '" + parameterName + "' can not be found for " + getParserName() + " element."); } Double[] parameterSamples = new Double[traces.getStateCount()]; DistributionLikelihood likelihood = new DistributionLikelihood(new NormalKDEDistribution((Double[]) traces.getValues(traceIndexParameter).toArray(parameterSamples))); for (int j = 0; j < xo.getChildCount(); j++) { if (xo.getChild(j) instanceof Statistic) { likelihood.addData((Statistic) xo.getChild(j)); } else { throw new XMLParseException("illegal element in " + xo.getName() + " element"); } } return likelihood; } catch (FileNotFoundException fnfe) { throw new XMLParseException("File '" + fileName + "' can not be opened for " + getParserName() + " element."); } catch (java.io.IOException ioe) { throw new XMLParseException(ioe.getMessage()); } catch (TraceException e) { throw new XMLParseException(e.getMessage()); } } public XMLSyntaxRule[] getSyntaxRules() { return rules; } private final XMLSyntaxRule[] rules = { AttributeRule.newStringRule("fileName"), AttributeRule.newStringRule("parameterColumn"), AttributeRule.newIntegerRule("burnin"), new ElementRule(Statistic.class, 1, Integer.MAX_VALUE) }; public String getParserDescription() { return "Calculates the reference prior probability of some data under a given normal distribution."; } public Class getReturnType() { return Likelihood.class; } }; /** * A special parser that reads a convenient short form of priors on parameters. * <p/> * If X ~ logNormal, then log(X) ~ Normal. * <br> * <br> * If meanInRealSpace=false, <code>mean</code> specifies the mean of log(X) and * <code>stdev</code> specifies the standard deviation of log(X). * <br> * <br> * If meanInRealSpace=true, <code>mean</code> specifies the mean of X, but <code> * stdev</code> specifies the standard deviation of log(X). * <br> */ public static XMLObjectParser LOG_NORMAL_PRIOR_PARSER = new AbstractXMLObjectParser() { public String getParserName() { return LOG_NORMAL_PRIOR; } public Object parseXMLObject(XMLObject xo) throws XMLParseException { double mean = xo.getDoubleAttribute(MEAN); final double stdev = xo.getDoubleAttribute(STDEV); final double offset = xo.getAttribute(OFFSET, 0.0); final boolean meanInRealSpace = xo.getAttribute(MEAN_IN_REAL_SPACE, false); if (meanInRealSpace) { if (mean <= 0) { throw new IllegalArgumentException("meanInRealSpace works only for a positive mean"); } mean = Math.log(mean) - 0.5 * stdev * stdev; } final DistributionLikelihood likelihood = new DistributionLikelihood(new LogNormalDistribution(mean, stdev), offset); for (int j = 0; j < xo.getChildCount(); j++) { if (xo.getChild(j) instanceof Statistic) { likelihood.addData((Statistic) xo.getChild(j)); } else { throw new XMLParseException("illegal element in " + xo.getName() + " element"); } } return likelihood; } public XMLSyntaxRule[] getSyntaxRules() { return rules; } private final XMLSyntaxRule[] rules = { AttributeRule.newDoubleRule(MEAN), AttributeRule.newDoubleRule(STDEV), AttributeRule.newDoubleRule(OFFSET, true), AttributeRule.newBooleanRule(MEAN_IN_REAL_SPACE, true), new ElementRule(Statistic.class, 1, Integer.MAX_VALUE) }; public String getParserDescription() { return "Calculates the prior probability of some data under a given lognormal distribution."; } public Class getReturnType() { return Likelihood.class; } }; /** * A special parser that reads a convenient short form of priors on parameters. */ public static XMLObjectParser GAMMA_PRIOR_PARSER = new AbstractXMLObjectParser() { public String getParserName() { return GAMMA_PRIOR; } public Object parseXMLObject(XMLObject xo) throws XMLParseException { final double shape = xo.getDoubleAttribute(SHAPE); final double scale = xo.getDoubleAttribute(SCALE); final double offset = xo.getAttribute(OFFSET, 0.0); DistributionLikelihood likelihood = new DistributionLikelihood(new GammaDistribution(shape, scale), offset); for (int j = 0; j < xo.getChildCount(); j++) { if (xo.getChild(j) instanceof Statistic) { likelihood.addData((Statistic) xo.getChild(j)); } else { throw new XMLParseException("illegal element in " + xo.getName() + " element"); } } return likelihood; } public XMLSyntaxRule[] getSyntaxRules() { return rules; } private final XMLSyntaxRule[] rules = { AttributeRule.newDoubleRule(SHAPE), AttributeRule.newDoubleRule(SCALE), AttributeRule.newDoubleRule(OFFSET, true), // AttributeRule.newBooleanRule(UNINFORMATIVE, true), new ElementRule(Statistic.class, 1, Integer.MAX_VALUE) }; public String getParserDescription() { return "Calculates the prior probability of some data under a given gamma distribution."; } public Class getReturnType() { return Likelihood.class; } }; /** * A special parser that reads a convenient short form of priors on parameters. */ public static XMLObjectParser INVGAMMA_PRIOR_PARSER = new AbstractXMLObjectParser() { public String getParserName() { return INVGAMMA_PRIOR; } public String[] getParserNames() { return new String[] { INVGAMMA_PRIOR, INVGAMMA_PRIOR_CORRECT }; } public Object parseXMLObject(XMLObject xo) throws XMLParseException { final double shape = xo.getDoubleAttribute(SHAPE); final double scale = xo.getDoubleAttribute(SCALE); final double offset = xo.getDoubleAttribute(OFFSET); DistributionLikelihood likelihood = new DistributionLikelihood(new InverseGammaDistribution(shape, scale), offset); for (int j = 0; j < xo.getChildCount(); j++) { if (xo.getChild(j) instanceof Statistic) { likelihood.addData((Statistic) xo.getChild(j)); } else { throw new XMLParseException("illegal element in " + xo.getName() + " element"); } } return likelihood; } public XMLSyntaxRule[] getSyntaxRules() { return rules; } private final XMLSyntaxRule[] rules = { AttributeRule.newDoubleRule(SHAPE), AttributeRule.newDoubleRule(SCALE), AttributeRule.newDoubleRule(OFFSET), new ElementRule(Statistic.class, 1, Integer.MAX_VALUE) }; public String getParserDescription() { return "Calculates the prior probability of some data under a given inverse gamma distribution."; } public Class getReturnType() { return Likelihood.class; } }; public static XMLObjectParser LAPLACE_PRIOR_PARSER = new AbstractXMLObjectParser() { public String getParserName() { return LAPLACE_PRIOR; } public Object parseXMLObject(XMLObject xo) throws XMLParseException { double mean = xo.getDoubleAttribute(MEAN); double scale = xo.getDoubleAttribute(SCALE); DistributionLikelihood likelihood = new DistributionLikelihood(new LaplaceDistribution(mean, scale)); for (int j = 0; j < xo.getChildCount(); j++) { if (xo.getChild(j) instanceof Statistic) { likelihood.addData((Statistic) xo.getChild(j)); } else { throw new XMLParseException("illegal element in " + xo.getName() + " element"); } } return likelihood; } public XMLSyntaxRule[] getSyntaxRules() { return rules; } private final XMLSyntaxRule[] rules = { AttributeRule.newDoubleRule(MEAN), AttributeRule.newDoubleRule(SCALE), new ElementRule(Statistic.class, 1, Integer.MAX_VALUE) }; public String getParserDescription() { return "Calculates the prior probability of some data under a given laplace distribution."; } public Class getReturnType() { return Likelihood.class; } }; /** * A special parser that reads a convenient short form of priors on parameters. */ public static XMLObjectParser BETA_PRIOR_PARSER = new AbstractXMLObjectParser() { public String getParserName() { return BETA_PRIOR; } public Object parseXMLObject(XMLObject xo) throws XMLParseException { final double shape = xo.getDoubleAttribute(SHAPE); final double shapeB = xo.getDoubleAttribute(SHAPEB); final double offset = xo.getAttribute(OFFSET, 0.0); DistributionLikelihood likelihood = new DistributionLikelihood(new BetaDistribution(shape, shapeB), offset); for (int j = 0; j < xo.getChildCount(); j++) { if (xo.getChild(j) instanceof Statistic) { likelihood.addData((Statistic) xo.getChild(j)); } else { throw new XMLParseException("illegal element in " + xo.getName() + " element"); } } return likelihood; } public XMLSyntaxRule[] getSyntaxRules() { return rules; } private final XMLSyntaxRule[] rules = { AttributeRule.newDoubleRule(SHAPE), AttributeRule.newDoubleRule(SHAPEB), AttributeRule.newDoubleRule(OFFSET, true), new ElementRule(Statistic.class, 1, Integer.MAX_VALUE) }; public String getParserDescription() { return "Calculates the prior probability of some data under a given beta distribution."; } public Class getReturnType() { return Likelihood.class; } }; }