2
2
Created on Mar 7, 2011
3
3
4
4
@author: johnsalvatier
5
- '''
5
+ '''
6
6
from numpy import floor
7
7
from quadpotential import *
8
8
from arraystep import *
9
- from ..core import *
9
+ from ..core import *
10
10
import numpy as np
11
+ from scipy .sparse import issparse
11
12
12
13
__all__ = ['HamiltonianMC' ]
13
14
14
- #TODO:
15
+ #TODO:
15
16
#add constraint handling via page 37 of Radford's http://www.cs.utoronto.ca/~radford/ham-mcmc.abstract.html
16
17
17
18
def unif (step_size , elow = .85 , ehigh = 1.15 ):
@@ -30,59 +31,62 @@ def __init__(self, vars, C, step_scale = .25, path_length = 2., is_cov = False,
30
31
step_scale : float, default=.25
31
32
Size of steps to take, automatically scaled down by 1/n**(1/4) (defaults to .25)
32
33
path_length : float, default=2
33
- total length to travel
34
+ total length to travel
34
35
is_cov : bool, default=False
35
36
Treat C as a covariance matrix/vector if True, else treat it as a precision matrix/vector
36
- step_rand : function float -> float, default=unif
37
- A function which takes the step size and returns an new one used to randomize the step size at each iteration.
38
- state
37
+ step_rand : function float -> float, default=unif
38
+ A function which takes the step size and returns an new one used to randomize the step size at each iteration.
39
+ state
39
40
State object
40
41
model : Model
41
42
"""
42
43
model = modelcontext (model )
43
44
n = C .shape [0 ]
44
-
45
+
45
46
self .step_size = step_scale / n ** (1 / 4. )
46
-
47
+
48
+ if issparse (C ):
49
+ raise ValueError ("Cannot use sparse matrix for scaling without scikits.sparse installed" )
47
50
self .potential = quad_potential (C , is_cov )
51
+
48
52
self .path_length = path_length
49
53
self .step_rand = step_rand
50
54
51
55
if state is None :
52
56
state = SamplerHist ()
53
57
self .state = state
54
58
55
- ArrayStep .__init__ (self ,
59
+ ArrayStep .__init__ (self ,
56
60
vars , [model .logpc , model .dlogpc (vars )]
57
61
)
58
62
59
63
def astep (self , q0 , logp , dlogp ):
60
-
61
-
64
+
65
+
62
66
#randomize step size
63
- e = self .step_rand (self .step_size )
67
+ e = self .step_rand (self .step_size )
64
68
nstep = int (floor (self .path_length / self .step_size ))
65
-
66
- q = q0
69
+
70
+ q = q0
67
71
p = p0 = self .potential .random ()
68
-
72
+
69
73
#use the leapfrog method
70
74
p = p - (e / 2 ) * - dlogp (q ) # half momentum update
71
-
72
- for i in range (nstep ):
75
+
76
+ for i in range (nstep ):
73
77
#alternate full variable and momentum updates
74
78
q = q + e * self .potential .velocity (p )
75
79
if i != nstep - 1 :
76
80
p = p - e * - dlogp (q )
77
-
81
+
78
82
p = p - (e / 2 ) * - dlogp (q ) # do a half step momentum update to finish off
79
-
80
- p = - p
81
-
83
+
84
+ p = - p
85
+
82
86
# - H(q*, p*) + H(q, p) = -H(q, p) + H(q0, p0) = -(- logp(q) + K(p)) + (-logp(q0) + K(p0))
83
87
mr = (- logp (q0 )) + self .potential .energy (p0 ) - ((- logp (q )) + self .potential .energy (p ))
84
88
85
89
self .state .metrops .append (mr )
86
-
90
+
87
91
return metrop_select (mr , q , q0 )
88
-
92
+
0 commit comments