/* * SliceOperator.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.operators; import dr.inference.distribution.DistributionLikelihood; import dr.inference.distribution.NormalDistributionModel; import dr.inference.distribution.ParametricDistributionModel; import dr.inference.model.CompoundLikelihood; import dr.inference.model.Likelihood; import dr.inference.model.Parameter; import dr.inference.model.Variable; import dr.math.MathUtils; import dr.math.distributions.NormalDistribution; import dr.util.Attribute; import java.util.ArrayList; import java.util.List; /** * Implements a generic univariate slice sampler. * * See: RM Neal (2003) Slice Sampling, Annals of Statistics, 31, 705-767 (with discussion) * * @author Marc A. Suchard */ public class SliceOperator extends SimpleMetropolizedGibbsOperator { public SliceOperator(Variable<Double> variable) { this(new SliceInterval.SteppingOut(), variable); } public SliceOperator(SliceInterval sliceInterval, Variable<Double> variable) { this.sliceInterval = sliceInterval; if (variable.getSize() != 1) { throw new RuntimeException("Generic slice sampler is currently for univariate parameters only"); } this.variable = variable; sliceInterval.setSliceSampler(this); } public Variable<Double> getVariable() { return variable; } public double doOperation(Likelihood likelihood) { double logPosterior = evaluate(likelihood, 1.0); double cutoffDensity = logPosterior + MathUtils.randomLogDouble(); sliceInterval.drawFromInterval(likelihood, cutoffDensity, width); // No need to set variable, as SliceInterval has already done this (and recomputed posterior) return 0; } public int getStepCount() { return 1; } public String getOperatorName() { return "genericSliceSampler"; } public static void main(String[] arg) { // Define normal model Parameter meanParameter = new Parameter.Default(1.0); // Starting value Variable<Double> stdev = new Variable.D(1.0, 1); // Fixed value ParametricDistributionModel densityModel = new NormalDistributionModel(meanParameter, stdev); DistributionLikelihood likelihood = new DistributionLikelihood(densityModel); // Define prior DistributionLikelihood prior = new DistributionLikelihood(new NormalDistribution(0.0, 1.0)); // Hyper-priors prior.addData(meanParameter); // Define data likelihood.addData(new Attribute.Default<double[]>("Data", new double[] {0.0, 1.0, 2.0})); List<Likelihood> list = new ArrayList<Likelihood>(); list.add(likelihood); list.add(prior); CompoundLikelihood posterior = new CompoundLikelihood(0, list); SliceOperator sliceSampler = new SliceOperator(meanParameter); final int length = 10000; double mean = 0; double variance = 0; for(int i = 0; i < length; i++) { sliceSampler.doOperation(posterior); double x = meanParameter.getValue(0); mean += x; variance += x*x; } mean /= length; variance /= length; variance -= mean*mean; System.out.println("E(x) = "+mean); System.out.println("V(x) = "+variance); } private final SliceInterval sliceInterval; private final double width = 1.0; private final Variable<Double> variable; }