/******************************************************************************* * Copyright 2013 Analog Devices, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ********************************************************************************/ package com.analog.lyric.dimple.solvers.gibbs.samplers.generic; import static com.analog.lyric.dimple.environment.DimpleEnvironment.*; import java.util.LinkedList; import java.util.List; import org.eclipse.jdt.annotation.Nullable; import com.analog.lyric.dimple.model.domains.Domain; import com.analog.lyric.dimple.model.values.Value; import com.analog.lyric.math.DimpleRandom; import com.analog.lyric.options.DoubleOptionKey; import com.analog.lyric.options.IOptionHolder; import com.analog.lyric.options.IntegerOptionKey; import com.analog.lyric.options.Option; public class SliceSampler extends AbstractGenericSampler implements IMCMCSampler { private double _initialSliceWidth = 1; // Default value private int _maximumDoublings = 10; // Default value private boolean _explicitInitialSliceWidth = false; private boolean _explicitMaximumDoublings = false; /** * <description> */ public static final DoubleOptionKey initialSliceWidth = new DoubleOptionKey(SliceSampler.class, "initialSliceWidth", 1.0); /** * <description> */ public static final IntegerOptionKey maximumDoublings = new IntegerOptionKey(SliceSampler.class, "maximumDoublings", 10); @Override public void initialize(Domain variableDomain) { } @Override public void configureFromOptions(IOptionHolder optionHolder) { if (!_explicitInitialSliceWidth) { _initialSliceWidth = optionHolder.getOptionOrDefault(initialSliceWidth); } if (!_explicitMaximumDoublings) { _maximumDoublings = optionHolder.getOptionOrDefault(maximumDoublings); } } @Override public List<Option<?>> getOptionConfiguration(@Nullable List<Option<?>> list) { if (list == null) { list = new LinkedList<Option<?>>(); } list.add(new Option<Double>(initialSliceWidth, _initialSliceWidth)); list.add(new Option<Integer>(maximumDoublings, _maximumDoublings)); return list; } @Override public boolean nextSample(Value sampleValue, ISamplerClient samplerClient) { final double y = sampleVerticalSlice(samplerClient); final double x = sampleHorizontalSlice(sampleValue.getDouble(), y, (IRealSamplerClient)samplerClient); ((IRealSamplerClient)samplerClient).setNextSampleValue(x); return true; } // Sample vertical slice in log domain // In probability domain this would be uniform from 0 to the value at the current horizontal location (in probability representation) public double sampleVerticalSlice(ISamplerClient samplerClient) { final double yValue = samplerClient.getCurrentSampleScore(); return yValue - Math.log(activeRandom().nextDouble()); } // Sample horizontal slice using doubling method public double sampleHorizontalSlice(double x, double y, IRealSamplerClient samplerClient) { final DimpleRandom rand = activeRandom(); // First finding slice using doubling method double L = x - _initialSliceWidth * rand.nextDouble(); double R = L + _initialSliceWidth; double fL = samplerClient.getSampleScore(L); double fR = samplerClient.getSampleScore(R); for (int k = 0; k < _maximumDoublings; k++) { if (y <= fL && y <= fR) break; if (rand.nextBoolean()) // Flip a coin { L -= (R - L); fL = samplerClient.getSampleScore(L); } else { R += (R - L); fR = samplerClient.getSampleScore(R); } } // Next, shrink the interval as necessary double xSample; double Ls = L; double Rs = R; while (true) { xSample = Ls + (Rs - Ls) * rand.nextDouble(); double fSample = samplerClient.getSampleScore(xSample); if (y >= fSample && accept(xSample, x, y, L, R, samplerClient)) break; // Accept // Not accepted yet, shrink the interval if (xSample < x) Ls = xSample; else Rs = xSample; } return xSample; } private boolean accept(double xSample, double x, double y, double L, double R, IRealSamplerClient samplerClient) { boolean D = false; double fL = samplerClient.getSampleScore(L); double fR = samplerClient.getSampleScore(R); while (R - L > 1.1 * _initialSliceWidth) { double M = (L + R) * 0.5; // Mid-point if ((x < M && xSample >= M) || (x >= M && xSample < M)) D = true; if (xSample < M) { R = M; fR = samplerClient.getSampleScore(R); } else { L = M; fL = samplerClient.getSampleScore(L); } if (D && (y <= fL) && (y <= fR)) return false; // The new point is not acceptable } return true; // The new point is acceptable } public double getInitialSliceWidth() { return _initialSliceWidth; } /** * @deprecated Will be removed in future release. Instead set {@link #initialSliceWidth} option on * variables or graphs that will be using this sampler. */ @Deprecated public void setInitialSliceWidth(double initialSliceWidth) { _initialSliceWidth = initialSliceWidth; _explicitInitialSliceWidth = true; } public double getMaximumDoublings() { return _maximumDoublings; } /** * @deprecated Will be removed in future release. Instead set {@link #maximumDoublings} option on * variables or graphs that will be using this sampler. */ @Deprecated public void setMaximumDoublings(double maximumDoublings) { _maximumDoublings = (int)maximumDoublings; _explicitMaximumDoublings = true; } }