Skip to content

Commit 90fefa6

Browse files
committed
Merge pull request #221 from pymc-devs/slice
Slice sampler step function
2 parents 14cced0 + 3004bd1 commit 90fefa6

File tree

6 files changed

+90
-29
lines changed

6 files changed

+90
-29
lines changed

pymc/sample.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ def sample(draws, step, start=None, trace=None, track_progress=True, model=None)
1717
Parameters
1818
----------
1919
20-
model : Model (optional if in `with` context)
2120
draws : int
2221
The number of samples to draw
2322
step : function
@@ -26,8 +25,9 @@ def sample(draws, step, start=None, trace=None, track_progress=True, model=None)
2625
Starting point in parameter space (Defaults to trace.point(-1))
2726
trace : NpTrace
2827
A trace of past values (defaults to None)
29-
track : list of vars
30-
The variables to follow
28+
track_progress : bool
29+
Flag for progress bar
30+
model : Model (optional if in `with` context)
3131
3232
Examples
3333
--------

pymc/step_methods/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from compound import *
22
from hmc import *
3-
from metropolis import *
3+
from metropolis import *
44
from gibbs import *
5+
from slicer import *

pymc/step_methods/slicer.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Modified from original implementation by Dominik Wabersich (2013)
2+
3+
from ..core import *
4+
from arraystep import *
5+
from numpy import floor, abs, atleast_1d
6+
from numpy.random import standard_exponential, random, uniform
7+
8+
__all__ = ['Slice']
9+
10+
class Slice(ArrayStep):
11+
"""Slice sampler"""
12+
def __init__(self, vars, w=1, m=20, n_tune=0,
13+
tune=True, tune_interval=100, model=None):
14+
15+
model = modelcontext(model)
16+
17+
self.vars = vars
18+
self.w = w
19+
self.m = m
20+
self.n_tune = n_tune
21+
self.w_tune = []
22+
self.tune = tune
23+
self.tune_interval = tune_interval
24+
self.model = model
25+
26+
super(Slice,self).__init__(vars, [model.logpc])
27+
28+
def astep(self, q0, logp):
29+
30+
y = logp(q0) - standard_exponential()
31+
32+
# Stepping out procedure
33+
L = q0 - self.w*random()
34+
R = L + self.w
35+
J = floor(self.m*random())
36+
K = (self.m - 1) - J
37+
38+
while(J>0 and y<logp(L)):
39+
L = L - self.w
40+
J = J - 1
41+
42+
while(K>0 and y<logp(R)):
43+
R = R + self.w
44+
K = K - 1
45+
46+
# Sample uniformly from slice
47+
q_new = atleast_1d(uniform(L, R))
48+
y_new = logp(q_new)
49+
50+
while(y_new<y):
51+
# Shrink bounds of uniform
52+
if (q_new < q0):
53+
L = q_new
54+
else:
55+
R = q_new
56+
q_new = atleast_1d(uniform(L,R))
57+
y_new = logp(q_new)
58+
59+
if (len(self.w_tune) > self.n_tune):
60+
# Tune sampler parameters
61+
self.w_tune.append(abs(q0 - q_new))
62+
self.w = 2 * sum(self.w_tune)/len(self.w_tune)
63+
64+
return q_new

pymc/tests/models.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
from pymc import Model, Normal, Metropolis
2-
import numpy as np
2+
import numpy as np
33
import pymc as pm
44

5-
def simple_init():
6-
start, model, moments = simple_model()
7-
8-
step = Metropolis(model.vars, np.diag([1.]), model = model)
9-
return model, start, step, moments
10-
11-
125
def simple_model():
136
mu = -2.1
147
tau = 1.3
@@ -17,6 +10,12 @@ def simple_model():
1710

1811
return model.test_point, model, (mu, tau**-1)
1912

13+
def simple_init():
14+
start, model, moments = simple_model()
15+
16+
step = Metropolis(model.vars, np.diag([1.]), model = model)
17+
return model, start, step, moments
18+
2019
def simple_2model():
2120
mu = -2.1
2221
tau = 1.3
@@ -34,7 +33,7 @@ def mv_simple():
3433
[.05 , .1, 0],
3534
[1. ,-0.05,5.5]])
3635

37-
tau = np.dot(p,p.T)
36+
tau = np.dot(p,p.T)
3837

3938

4039
with pm.Model() as model:

pymc/tests/test_sampling.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ def test_sample():
1717
test_samplers.append(psample)
1818

1919
with model:
20-
for samplr in test_samplers:
21-
for n in [0, 10, 1000]:
22-
yield samplr, n, step, start
20+
for samplr in test_samplers:
21+
for n in [0, 10, 1000]:
22+
yield samplr, n, step, start
2323

2424

2525

pymc/tests/test_step.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from checks import *
2-
from models import simple_model, mv_simple
1+
from .checks import *
2+
from .models import simple_model, mv_simple
33
from theano.tensor import constant
44
from scipy.stats.mstats import moment
55

@@ -11,26 +11,23 @@ def check_stat(name, trace, var, stat, value, bound):
1111
def test_step_continuous():
1212
start, model, (mu, C) = mv_simple()
1313

14-
hmc = pm.HamiltonianMC(model.vars, C, is_cov = True, model = model)
15-
mh = pm.Metropolis(model.vars , C, is_cov = True, scaling = 2, model = model)
14+
hmc = pm.HamiltonianMC(model.vars, C, is_cov=True, model=model)
15+
mh = pm.Metropolis(model.vars, model=model)
16+
slicer = pm.Slice(model.vars, model=model)
1617
compound = pm.CompoundStep([hmc, mh])
1718

18-
steps = [mh, hmc, compound]
19+
steps = [mh, hmc, compound, slicer]
20+
1921

2022
unc = np.diag(C)**.5
2123
check = [('x', np.mean, mu, unc/10.),
2224
('x', np.std , unc, unc/10.)]
2325

2426
for st in steps:
2527
np.random.seed(1)
26-
h = sample(8000, st, start, track_progress=False, model = model)
28+
h = sample(8000, st, start, model=model)
2729
for (var, stat, val, bound) in check:
2830
np.random.seed(1)
29-
h = sample(8000, st, start, track_progess=False, model = model)
30-
31-
yield check_stat,repr(st), h, var, stat, val, bound
32-
33-
34-
35-
31+
h = sample(8000, st, start, model=model)
3632

33+
yield check_stat,repr(st), h, var, stat, val, bound

0 commit comments

Comments
 (0)