vSMC
vSMC: 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 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 RealType normal_proposal_qa(RealType x, RealType &y, RealType z, RealType a)
388 {
389  y = a + (x - a) * std::exp(z);
390 
391  return z;
392 }
393 
394 template <typename RealType>
395 RealType normal_proposal_qb(RealType x, RealType &y, RealType z, RealType b)
396 {
397  y = b - (b - x) * std::exp(z);
398 
399  return z;
400 }
401 
402 template <typename RealType>
404  RealType x, RealType &y, RealType z, RealType a, RealType b)
405 {
406  RealType r = std::exp(z) * (x - a) / (b - x);
407  y = (a + b * r) / (1 + r);
408 
409  return std::log((y - a) / (x - a) * (b - y) / (b - x));
410 }
411 
412 } // namespace vsmc::internal
413 
416 template <typename RealType>
417 class NormalProposal
418 {
419  public:
420  using result_type = RealType;
421 
427  explicit NormalProposal(result_type stddev = 1,
428  result_type a = -std::numeric_limits<result_type>::infinity(),
429  result_type b = std::numeric_limits<result_type>::infinity())
430  : rnorm_(0, stddev), a_(a), b_(b), flag_(0)
431  {
432  unsigned lower = std::isfinite(a) ? 1 : 0;
433  unsigned upper = std::isfinite(b) ? 1 : 0;
434  flag_ = (lower << 1) + upper;
437  }
438 
439  result_type a() const { return a_; }
440  result_type b() const { return b_; }
441 
443  template <typename RNGType>
445  RNGType &rng, std::size_t, const result_type *x, result_type *y)
446  {
447  result_type z = rnorm_(rng);
448  switch (flag_) {
449  case 0: return internal::normal_proposal_q(*x, *y, z);
450  case 1: return internal::normal_proposal_qb(*x, *y, z, b_);
451  case 2: return internal::normal_proposal_qa(*x, *y, z, a_);
452  case 3: return internal::normal_proposal_qab(*x, *y, z, a_, b_);
453  default: return 0;
454  }
455  }
456 
457  private:
459  result_type a_;
460  result_type b_;
461  unsigned flag_;
462 }; // class NormalProposal
463 
466 template <typename RealType, std::size_t Dim>
467 class NormalMVProposal
468 {
469  public:
470  using result_type = RealType;
471 
486  explicit NormalMVProposal(const result_type *chol = nullptr,
487  const result_type *a = nullptr, const result_type *b = nullptr)
488  : rnorm_(nullptr, chol)
489  {
490  static_assert(Dim != Dynamic,
491  "**NormalMVProposal** OBJECT DECLARED WITH DYNAMIC DIMENSION");
492  init(Dim, a, b);
493  }
494 
495  explicit NormalMVProposal(std::size_t dim,
496  const result_type *chol = nullptr, const result_type *a = nullptr,
497  const result_type *b = nullptr)
498  : rnorm_(dim, nullptr, chol), a_(dim), b_(dim), z_(dim), flag_(dim)
499  {
500  static_assert(Dim == Dynamic,
501  "**NormalMVProposal** OBJECT DECLARED WITH FIXED DIMENSION");
502  init(dim, a, b);
503  }
504 
505  std::size_t dim() const { return rnorm_.dim(); }
506  const result_type *a() const { return a_.data(); }
507  const result_type *b() const { return b_.data(); }
508 
509  template <typename RNGType>
511  RNGType &rng, std::size_t, const result_type *x, result_type *y)
512  {
513  rnorm_(rng, z_.data());
514  result_type q = 0;
515  for (std::size_t i = 0; i != dim(); ++i) {
516  switch (flag_[i]) {
517  case 0:
518  q += internal::normal_proposal_q(x[i], y[i], z_[i]);
519  break;
520  case 1:
521  q +=
522  internal::normal_proposal_qb(x[i], y[i], z_[i], b_[i]);
523  break;
524  case 2:
525  q +=
526  internal::normal_proposal_qa(x[i], y[i], z_[i], a_[i]);
527  break;
528  case 3:
530  x[i], y[i], z_[i], a_[i], b_[i]);
531  break;
532  default: break;
533  }
534  }
535 
536  return q;
537  }
538 
539  private:
545 
546  void init(std::size_t dim, const result_type *a, const result_type *b)
547  {
548  if (a == nullptr) {
549  std::fill(a_.begin(), a_.end(),
550  -std::numeric_limits<result_type>::infinity());
551  } else {
552  std::copy_n(a, dim, a_.begin());
553  }
554 
555  if (b == nullptr) {
556  std::fill(b_.begin(), b_.end(),
557  std::numeric_limits<result_type>::infinity());
558  } else {
559  std::copy_n(b, dim, b_.begin());
560  }
561 
562  for (std::size_t i = 0; i != dim; ++i) {
563  unsigned lower = std::isfinite(a_[i]) ? 1 : 0;
564  unsigned upper = std::isfinite(b_[i]) ? 1 : 0;
565  flag_[i] = (lower << 1) + upper;
566  }
567 
570  dim, a_.data(), b_.data()),
571  NormalMV);
572  }
573 }; // class NormalMVProposal
574 
575 } // namespace vsmc
576 
577 #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:49
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.
Definition: common.hpp:537
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
Normal distribution.
Definition: common.hpp:582
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:146
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.
Definition: common.hpp:585
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.
Definition: common.hpp:540
typename std::conditional< Dim==Dynamic, Vector< T >, std::array< T, Dim >>::type Array
Definition: common.hpp:135
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
Standard uniform distribution.
Definition: common.hpp:597
Multivariate Normal random walk proposal.
Definition: common.hpp:543
void log(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:148
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