vSMC  v3.0.0
Scalable Monte Carlo
random_walk.hpp
Go to the documentation of this file.
1 //============================================================================
2 // vSMC/include/vsmc/rng/random_walk.hpp
3 //----------------------------------------------------------------------------
4 // vSMC: Scalable Monte Carlo
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013-2016, Yan Zhou
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimer.
14 //
15 // Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimer in the documentation
17 // and/or other materials provided with the distribution.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 // POSSIBILITY OF SUCH DAMAGE.
30 //============================================================================
31 
32 #ifndef VSMC_RNG_RANDOM_WALK_HPP
33 #define VSMC_RNG_RANDOM_WALK_HPP
34 
39 
40 #define VSMC_RUNTIME_ASSERT_RNG_RANDOM_WALK_PROPOSAL_PARAM(flag, Name) \
41  VSMC_RUNTIME_ASSERT( \
42  (flag), "**" #Name "Proposal** CONSTRUCTED WITH INVALID PARAMETERS")
43 
44 namespace vsmc
45 {
46 
49 template <typename RealType, std::size_t Dim>
50 class RandomWalk
51 {
52  public:
53  using result_type = RealType;
54 
57  {
58  static_assert(Dim != Dynamic,
59  "**RandomWalk** OBJECT DECLARED WITH DYNAMIC DIMENSION");
60  }
61 
63  RandomWalk(std::size_t dim) : x_(dim), y_(dim)
64  {
65  static_assert(Dim == Dynamic,
66  "**RandomWalk** OBJECT DECLARED WITH FIXED DIMENSION");
67  }
68 
69  std::size_t dim() const { return x_.size(); }
70 
97  template <typename RNGType, typename LogTargetType, typename ProposalType>
98  std::size_t operator()(RNGType &rng, result_type *x, result_type *ltx,
99  LogTargetType &&log_target, ProposalType &&proposal)
100  {
102  result_type q = proposal(rng, dim(), x, y_.data());
103  result_type s = ltx == nullptr ? log_target(dim(), x) : *ltx;
104  result_type t = log_target(dim(), y_.data());
105  result_type p = t - s + q;
106  result_type u = std::log(u01(rng));
107 
108  if (u < p) {
109  std::copy(y_.begin(), y_.end(), x);
110  if (ltx != nullptr)
111  *ltx = t;
112  return 1;
113  }
114  return 0;
115  }
116 
126  template <typename RNGType, typename LogTargetType, typename ProposalType>
127  std::size_t operator()(RNGType &rng, std::size_t m, std::size_t idx,
128  result_type *x, result_type *ltx, LogTargetType &&log_target,
129  ProposalType &&proposal)
130  {
132  std::copy_n(x + idx, dim(), x_.begin());
133  result_type q = proposal(rng, dim(), x_.data(), y_.data());
134  result_type s = ltx == nullptr ? log_target(m, x) : *ltx;
135  std::copy(y_.begin(), y_.end(), x + idx);
136  result_type t = log_target(m, x);
137  result_type p = t - s + q;
138  result_type u = std::log(u01(rng));
139 
140  if (u < p) {
141  if (ltx != nullptr)
142  *ltx = t;
143  return 1;
144  }
145  std::copy(x_.begin(), x_.end(), x + idx);
146 
147  return 0;
148  }
149 
151  template <typename RNGType, typename LogTargetType, typename ProposalType>
152  std::size_t operator()(std::size_t n, RNGType &rng, result_type *x,
153  result_type *ltx, LogTargetType &&log_target, ProposalType &&proposal)
154  {
155  std::size_t acc = 0;
156  result_type s = ltx == nullptr ? log_target(dim(), x) : *ltx;
157  for (std::size_t i = 0; i != n; ++i) {
158  acc += operator()(rng, x, &s,
159  std::forward<LogTargetType>(log_target),
160  std::forward<ProposalType>(proposal));
161  }
162  if (ltx != nullptr)
163  *ltx = s;
164 
165  return acc;
166  }
167 
170  template <typename RNGType, typename LogTargetType, typename ProposalType>
171  std::size_t operator()(std::size_t n, RNGType &rng, std::size_t m,
172  std::size_t idx, result_type *x, result_type *ltx,
173  LogTargetType &&log_target, ProposalType &&proposal)
174  {
175  std::size_t acc = 0;
176  result_type s = ltx == nullptr ? log_target(m, x) : *ltx;
177  for (std::size_t i = 0; i != n; ++i) {
178  acc += operator()(rng, m, idx, x, &s,
179  std::forward<LogTargetType>(log_target),
180  std::forward<ProposalType>(proposal));
181  }
182  if (ltx != nullptr)
183  *ltx = s;
184 
185  return acc;
186  }
187 
188  private:
191 }; // class RandomWalk
192 
195 template <typename RealType, std::size_t DimX, std::size_t DimG>
196 class RandomWalkG
197 {
198  public:
199  using result_type = RealType;
200 
203  {
204  static_assert(DimX != Dynamic && DimG != Dynamic,
205  "**RandomWalk** OBJECT DECLARED WITH DYNAMIC DIMENSION");
206  }
207 
209  RandomWalkG(std::size_t dim_x, std::size_t dim_g)
210  : x_(dim_x), y_(dim_x), g_(dim_g)
211  {
212  static_assert(DimX == Dynamic && DimG == Dynamic,
213  "**RandomWalk** OBJECT DECLARED WITH FIXED DIMENSION");
214  }
215 
216  std::size_t dim_x() const { return x_.size(); }
217  std::size_t dim_g() const { return g_.size(); }
218 
251  template <typename RNGType, typename LogTargetType, typename ProposalType>
252  std::size_t operator()(RNGType &rng, result_type *x, result_type *ltx,
253  result_type *g, LogTargetType &&log_target, ProposalType &&proposal)
254  {
256  result_type q = proposal(rng, dim_x(), x, y_.data());
257  result_type s =
258  ltx == nullptr ? log_target(dim_x(), dim_g(), x, nullptr) : *ltx;
259  result_type t = log_target(
260  dim_x(), dim_g(), y_.data(), (g == nullptr ? nullptr : g_.data()));
261  result_type p = t - s + q;
262  result_type u = std::log(u01(rng));
263 
264  if (u < p) {
265  std::copy(y_.begin(), y_.end(), x);
266  if (ltx != nullptr)
267  *ltx = t;
268  if (g != nullptr)
269  std::copy(g_.begin(), g_.end(), g);
270  return 1;
271  }
272  return 0;
273  }
274 
284  template <typename RNGType, typename LogTargetType, typename ProposalType>
285  std::size_t operator()(RNGType &rng, std::size_t m, std::size_t idx,
286  result_type *x, result_type *ltx, result_type *g,
287  LogTargetType &&log_target, ProposalType &&proposal)
288  {
290  std::copy_n(x + idx, dim_x(), x_.begin());
291  result_type q = proposal(rng, dim_x(), x_.data(), y_.data());
292  result_type s =
293  ltx == nullptr ? log_target(m, dim_g(), x, nullptr) : *ltx;
294  std::copy(y_.begin(), y_.end(), x + idx);
295  result_type t =
296  log_target(m, dim_g(), x, (g == nullptr ? nullptr : g_.data()));
297  result_type p = t - s + q;
298  result_type u = std::log(u01(rng));
299 
300  if (u < p) {
301  if (ltx != nullptr)
302  *ltx = t;
303  if (g != nullptr)
304  std::copy(g_.begin(), g_.end(), g);
305  return 1;
306  }
307  std::copy(x_.begin(), x_.end(), x + idx);
308 
309  return 0;
310  }
311 
313  template <typename RNGType, typename LogTargetType, typename ProposalType>
314  std::size_t operator()(std::size_t n, RNGType &rng, result_type *x,
315  result_type *ltx, result_type *g, LogTargetType &&log_target,
316  ProposalType &&proposal)
317  {
318  std::size_t acc = 0;
319  result_type s =
320  ltx == nullptr ? log_target(dim_x(), dim_g(), x, nullptr) : *ltx;
321  for (std::size_t i = 0; i != n; ++i) {
322  acc += operator()(rng, x, &s, g,
323  std::forward<LogTargetType>(log_target),
324  std::forward<ProposalType>(proposal));
325  }
326  if (ltx != nullptr)
327  *ltx = s;
328 
329  return acc;
330  }
331 
334  template <typename RNGType, typename LogTargetType, typename ProposalType>
335  std::size_t operator()(std::size_t n, RNGType &rng, std::size_t m,
336  std::size_t idx, result_type *x, result_type *ltx, result_type *g,
337  LogTargetType &&log_target, ProposalType &&proposal)
338  {
339  std::size_t acc = 0;
340  result_type s =
341  ltx == nullptr ? log_target(m, dim_g(), x, nullptr) : *ltx;
342  for (std::size_t i = 0; i != n; ++i) {
343  acc += operator()(rng, m, idx, x, &s, g,
344  std::forward<LogTargetType>(log_target),
345  std::forward<ProposalType>(proposal));
346  }
347  if (ltx != nullptr)
348  *ltx = s;
349 
350  return acc;
351  }
352 
353  private:
357 }; // class RandomWalkG
358 
359 namespace internal
360 {
361 
362 template <typename RealType>
363 inline bool normal_proposal_check_param(RealType a, RealType b)
364 {
365  return a < b;
366 }
367 
368 template <typename RealType>
370  std::size_t dim, const RealType *a, const RealType *b)
371 {
372  for (std::size_t i = 0; i != dim; ++i)
373  if (a[i] >= b[i])
374  return false;
375  return true;
376 }
377 
378 template <typename RealType>
379 inline RealType normal_proposal_q(RealType x, RealType &y, RealType z)
380 {
381  y = x + z;
382 
383  return 0;
384 }
385 
386 template <typename RealType>
387 inline RealType normal_proposal_qa(
388  RealType x, RealType &y, RealType z, RealType a)
389 {
390  y = a + (x - a) * std::exp(z);
391 
392  return z;
393 }
394 
395 template <typename RealType>
396 inline RealType normal_proposal_qb(
397  RealType x, RealType &y, RealType z, RealType b)
398 {
399  y = b - (b - x) * std::exp(z);
400 
401  return z;
402 }
403 
404 template <typename RealType>
405 inline RealType normal_proposal_qab(
406  RealType x, RealType &y, RealType z, RealType a, RealType b)
407 {
408  RealType r = std::exp(z) * (x - a) / (b - x);
409  y = (a + b * r) / (1 + r);
410 
411  return std::log((y - a) / (x - a) * (b - y) / (b - x));
412 }
413 
414 } // namespace vsmc::internal
415 
418 template <typename RealType>
419 class NormalProposal
420 {
421  public:
422  using result_type = RealType;
423 
429  explicit NormalProposal(result_type stddev = 1,
430  result_type a = -std::numeric_limits<result_type>::infinity(),
431  result_type b = std::numeric_limits<result_type>::infinity())
432  : rnorm_(0, stddev), a_(a), b_(b), flag_(0)
433  {
434  unsigned lower = std::isfinite(a) ? 1 : 0;
435  unsigned upper = std::isfinite(b) ? 1 : 0;
436  flag_ = (lower << 1) + upper;
439  }
440 
441  result_type a() const { return a_; }
442  result_type b() const { return b_; }
443 
445  template <typename RNGType>
447  RNGType &rng, std::size_t, const result_type *x, result_type *y)
448  {
449  result_type z = rnorm_(rng);
450  switch (flag_) {
451  case 0: return internal::normal_proposal_q(*x, *y, z);
452  case 1: return internal::normal_proposal_qb(*x, *y, z, b_);
453  case 2: return internal::normal_proposal_qa(*x, *y, z, a_);
454  case 3: return internal::normal_proposal_qab(*x, *y, z, a_, b_);
455  default: return 0;
456  }
457  }
458 
459  private:
461  result_type a_;
462  result_type b_;
463  unsigned flag_;
464 }; // class NormalProposal
465 
468 template <typename RealType, std::size_t Dim>
469 class NormalMVProposal
470 {
471  public:
472  using result_type = RealType;
473 
488  explicit NormalMVProposal(const result_type *chol = nullptr,
489  const result_type *a = nullptr, const result_type *b = nullptr)
490  : rnorm_(nullptr, chol)
491  {
492  static_assert(Dim != Dynamic,
493  "**NormalMVProposal** OBJECT DECLARED WITH DYNAMIC DIMENSION");
494  init(Dim, a, b);
495  }
496 
497  explicit NormalMVProposal(std::size_t dim,
498  const result_type *chol = nullptr, const result_type *a = nullptr,
499  const result_type *b = nullptr)
500  : rnorm_(dim, nullptr, chol), a_(dim), b_(dim), z_(dim), flag_(dim)
501  {
502  static_assert(Dim == Dynamic,
503  "**NormalMVProposal** OBJECT DECLARED WITH FIXED DIMENSION");
504  init(dim, a, b);
505  }
506 
507  std::size_t dim() const { return rnorm_.dim(); }
508  const result_type *a() const { return a_.data(); }
509  const result_type *b() const { return b_.data(); }
510 
511  template <typename RNGType>
513  RNGType &rng, std::size_t, const result_type *x, result_type *y)
514  {
515  rnorm_(rng, z_.data());
516  result_type q = 0;
517  for (std::size_t i = 0; i != dim(); ++i) {
518  switch (flag_[i]) {
519  case 0:
520  q += internal::normal_proposal_q(x[i], y[i], z_[i]);
521  break;
522  case 1:
523  q +=
524  internal::normal_proposal_qb(x[i], y[i], z_[i], b_[i]);
525  break;
526  case 2:
527  q +=
528  internal::normal_proposal_qa(x[i], y[i], z_[i], a_[i]);
529  break;
530  case 3:
532  x[i], y[i], z_[i], a_[i], b_[i]);
533  break;
534  default: break;
535  }
536  }
537 
538  return q;
539  }
540 
541  private:
547 
548  void init(std::size_t dim, const result_type *a, const result_type *b)
549  {
550  if (a == nullptr) {
551  std::fill(a_.begin(), a_.end(),
552  -std::numeric_limits<result_type>::infinity());
553  } else {
554  std::copy_n(a, dim, a_.begin());
555  }
556 
557  if (b == nullptr) {
558  std::fill(b_.begin(), b_.end(),
559  std::numeric_limits<result_type>::infinity());
560  } else {
561  std::copy_n(b, dim, b_.begin());
562  }
563 
564  for (std::size_t i = 0; i != dim; ++i) {
565  unsigned lower = std::isfinite(a_[i]) ? 1 : 0;
566  unsigned upper = std::isfinite(b_[i]) ? 1 : 0;
567  flag_[i] = (lower << 1) + upper;
568  }
569 
572  dim, a_.data(), b_.data()),
573  NormalMV);
574  }
575 }; // class NormalMVProposal
576 
577 } // namespace vsmc
578 
579 #endif // VSMC_RNG_RANDOM_WALK_HPP
#define VSMC_RUNTIME_ASSERT_RNG_RANDOM_WALK_PROPOSAL_PARAM(flag, Name)
Definition: random_walk.hpp:40
Definition: monitor.hpp:48
bool normal_mv_proposal_check_param(std::size_t dim, const RealType *a, const RealType *b)
RealType normal_proposal_qa(RealType x, RealType &y, RealType z, RealType a)
NormalMVProposal(std::size_t dim, const result_type *chol=nullptr, const result_type *a=nullptr, const result_type *b=nullptr)
std::size_t operator()(std::size_t n, RNGType &rng, std::size_t m, std::size_t idx, result_type *x, result_type *ltx, result_type *g, LogTargetType &&log_target, ProposalType &&proposal)
Multi-step random walk update of a block of element within a vector state.
RealType normal_proposal_qb(RealType x, RealType &y, RealType z, RealType b)
RandomWalkG(std::size_t dim_x, std::size_t dim_g)
Only usable when DimX == Dynamic and DimG == Dynamic
result_type b() const
std::size_t operator()(std::size_t n, RNGType &rng, std::size_t m, std::size_t idx, result_type *x, result_type *ltx, LogTargetType &&log_target, ProposalType &&proposal)
Multi-step random walk update of a block of element within a vector state.
std::size_t operator()(std::size_t n, RNGType &rng, result_type *x, result_type *ltx, LogTargetType &&log_target, ProposalType &&proposal)
Multi-step random walk update.
Random walk MCMC update with test function.
RealType normal_proposal_q(RealType x, RealType &y, RealType z)
std::size_t dim_g() const
std::size_t dim_x() const
const result_type * b() const
RealType u01(UIntType u) noexcept
Convert uniform unsigned integers to floating points within [0, 1].
Definition: u01.hpp:213
RealType result_type
Definition: random_walk.hpp:53
std::size_t operator()(RNGType &rng, result_type *x, result_type *ltx, result_type *g, LogTargetType &&log_target, ProposalType &&proposal)
One-step random walk update.
void exp(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:115
std::size_t dim() const
std::size_t dim() const
Definition: random_walk.hpp:69
RealType normal_proposal_qab(RealType x, RealType &y, RealType z, RealType a, RealType b)
RandomWalk()
Only usable when Dim != Dynamic
Definition: random_walk.hpp:56
result_type operator()(RNGType &rng, std::size_t, const result_type *x, result_type *y)
NormalProposal(result_type stddev=1, result_type a=-std::numeric_limits< result_type >::infinity(), result_type b=std::numeric_limits< result_type >::infinity())
Construct a Normal random walk proposal.
Multivariate Normal distribution.
result_type operator()(RNGType &rng, std::size_t, const result_type *x, result_type *y)
Propose new value y and return .
bool normal_proposal_check_param(RealType a, RealType b)
std::size_t operator()(RNGType &rng, std::size_t m, std::size_t idx, result_type *x, result_type *ltx, result_type *g, LogTargetType &&log_target, ProposalType &&proposal)
One-step random walk update of a block of elements within a vector state.
Normal random walk proposal.
std::size_t operator()(std::size_t n, RNGType &rng, result_type *x, result_type *ltx, result_type *g, LogTargetType &&log_target, ProposalType &&proposal)
Multi-step random walk update.
result_type a() const
const result_type * a() const
std::size_t operator()(RNGType &rng, result_type *x, result_type *ltx, LogTargetType &&log_target, ProposalType &&proposal)
One-step random walk update.
Definition: random_walk.hpp:98
RandomWalk(std::size_t dim)
Only usable when Dim == Dynamic
Definition: random_walk.hpp:63
NormalMVProposal(const result_type *chol=nullptr, const result_type *a=nullptr, const result_type *b=nullptr)
Only usable when Dim != Dynamic
Multivariate Normal random walk proposal.
typename std::conditional< N==Dynamic, Vector< T >, std::array< T, N >>::type StaticVector
void log(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:117
std::size_t operator()(RNGType &rng, std::size_t m, std::size_t idx, result_type *x, result_type *ltx, LogTargetType &&log_target, ProposalType &&proposal)
One-step random walk update of a block of elements within a vector state.
RandomWalkG()
Only usable when DimX != Dynamic and DimG != Dynamic