Skip to content

Commit

Permalink
Merge 1aec62c into fe685d2
Browse files Browse the repository at this point in the history
  • Loading branch information
ColCarroll authored Dec 2, 2019
2 parents fe685d2 + 1aec62c commit dfc6fe6
Show file tree
Hide file tree
Showing 9 changed files with 467 additions and 94 deletions.
1 change: 0 additions & 1 deletion examples/api_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,3 @@

ax.set_title("Multivariate mixture trajectories!\nArrows show momentum!")
plt.savefig(os.path.join(HERE, "plot8.png"))

1 change: 1 addition & 0 deletions minimc/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from .minimc import *
from .distributions import *
from .integrators import *
196 changes: 196 additions & 0 deletions minimc/integrators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import autograd.numpy as np

__all__ = ["leapfrog"]


def naive(q, p, dVdq, path_len, step_size):
"""Naive integrator for Hamiltonian Monte Carlo. Don't use.
Parameters
----------
q : np.floatX
Initial position
p : np.floatX
Initial momentum
dVdq : callable
Gradient of the velocity
path_len : float
How long to integrate for
step_size : float
How long each integration step should be
Returns
-------
q, p : np.floatX, np.floatX
New position and momentum
"""
q, p = np.copy(q), np.copy(p)

for _ in range(int(path_len / step_size)):
p -= step_size * dVdq(q) # whole step
q += step_size * p # whole step

# momentum flip at end
return q, -p


def leapfrog(q, p, dVdq, path_len, step_size):
"""Leapfrog integrator for Hamiltonian Monte Carlo.
Parameters
----------
q : np.floatX
Initial position
p : np.floatX
Initial momentum
dVdq : callable
Gradient of the velocity
path_len : float
How long to integrate for
step_size : float
How long each integration step should be
Returns
-------
q, p : np.floatX, np.floatX
New position and momentum
"""
q, p = np.copy(q), np.copy(p)

p -= step_size * dVdq(q) / 2 # half step
for _ in np.arange(np.round(path_len / step_size) - 1):
q += step_size * p # whole step
p -= step_size * dVdq(q) # whole step
q += step_size * p # whole step
p -= step_size * dVdq(q) / 2 # half step

# momentum flip at end
return q, -p


def leapfrog_twostage(q, p, dVdq, path_len, step_size):
"""A second order symplectic integration scheme.
Based on the implementation from Adrian Seyboldt in PyMC3. See
https://github.com/pymc-devs/pymc3/pull/1758 for a discussion.
References
----------
Blanes, Sergio, Fernando Casas, and J. M. Sanz-Serna. "Numerical
Integrators for the Hybrid Monte Carlo Method." SIAM Journal on
Scientific Computing 36, no. 4 (January 2014): A1556-80.
doi:10.1137/130932740.
Mannseth, Janne, Tore Selland Kleppe, and Hans J. Skaug. "On the
Application of Higher Order Symplectic Integrators in
Hamiltonian Monte Carlo." arXiv:1608.07048 [Stat],
August 25, 2016. http://arxiv.org/abs/1608.07048.
Parameters
----------
q : np.floatX
Initial position
p : np.floatX
Initial momentum
dVdq : callable
Gradient of the velocity
path_len : float
How long to integrate for
step_size : float
How long each integration step should be
Returns
-------
q, p : np.floatX, np.floatX
New position and momentum
"""
q, p = np.copy(q), np.copy(p)

a = (3 - np.sqrt(3)) / 6

p -= a * step_size * dVdq(q) # `a` momentum update
for _ in np.arange(np.round(path_len / step_size) - 1):
q += step_size * p / 2 # half position update
p -= (1 - 2 * a) * step_size * dVdq(q) # 1 - 2a position update
q += step_size * p / 2 # half position update
p -= 2 * a * step_size * dVdq(q) # `2a` momentum update
q += step_size * p / 2 # half position update
p -= (1 - 2 * a) * step_size * dVdq(q) # 1 - 2a position update
q += step_size * p / 2 # half position update
p -= a * step_size * dVdq(q) # `a` momentum update

return q, -p


def leapfrog_threestage(q, p, dVdq, path_len, step_size):
"""Perform a single step of a third order symplectic integration scheme.
Based on the implementation from Adrian Seyboldt in PyMC3. See
https://github.com/pymc-devs/pymc3/pull/1758 for a discussion.
References
----------
Blanes, Sergio, Fernando Casas, and J. M. Sanz-Serna. "Numerical
Integrators for the Hybrid Monte Carlo Method." SIAM Journal on
Scientific Computing 36, no. 4 (January 2014): A1556-80.
doi:10.1137/130932740.
Mannseth, Janne, Tore Selland Kleppe, and Hans J. Skaug. "On the
Application of Higher Order Symplectic Integrators in
Hamiltonian Monte Carlo." arXiv:1608.07048 [Stat],
August 25, 2016. http://arxiv.org/abs/1608.07048.
Parameters
----------
q : np.floatX
Initial position
p : np.floatX
Initial momentum
dVdq : callable
Gradient of the velocity
path_len : float
How long to integrate for
step_size : float
How long each integration step should be
Returns
-------
q, p : np.floatX, np.floatX
New position and momentum
"""
q, p = np.copy(q), np.copy(p)

a = 12_127_897.0 / 102_017_882
b = 4_271_554.0 / 14_421_423

# a step
p -= a * step_size * dVdq(q)

for _ in np.arange(np.round(path_len / step_size) - 1):
# b step
q += b * step_size * p
# (0.5 - a) step
p -= (0.5 - a) * step_size * dVdq(q)
# (1 - 2b) step
q += (1 - 2 * b) * step_size * p
# (0.5 - a) step
p -= (0.5 - a) * step_size * dVdq(q)
# b step
q += b * step_size * p
# 2a step
p -= 2 * a * step_size * dVdq(q)

# b step
q += b * step_size * p
# (0.5 - a) step
p -= (0.5 - a) * step_size * dVdq(q)
# (1 - 2b) step
q += (1 - 2 * b) * step_size * p
# (0.5 - a) step
p -= (0.5 - a) * step_size * dVdq(q)
# b step
q += b * step_size * p
# a step
p -= a * step_size * dVdq(q)

return q, -p
Loading

0 comments on commit dfc6fe6

Please sign in to comment.