File: quasi_mcarlo.hh

package info (click to toggle)
dynare 4.6.3-4
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 74,896 kB
  • sloc: cpp: 98,057; ansic: 28,929; pascal: 13,844; sh: 5,947; objc: 4,236; yacc: 4,215; makefile: 2,583; lex: 1,534; fortran: 877; python: 647; ruby: 291; lisp: 152; xml: 22
file content (256 lines) | stat: -rw-r--r-- 6,972 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/*
 * Copyright © 2005 Ondra Kamenik
 * Copyright © 2019 Dynare Team
 *
 * This file is part of Dynare.
 *
 * Dynare is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Dynare is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
 */

// Quasi Monte Carlo quadrature.

/* This defines quasi Monte Carlo quadratures for cube and for a function
   multiplied by normal density. The quadrature for a cube is named
   QMCarloCubeQuadrature and integrates:

      ∫    f(x)dx
    [0,1]ⁿ

   The quadrature for a function of normally distributed parameters is named
   QMCarloNormalQuadrature and integrates:

        1
    ────────     ∫     f(x)e^{−½xᵀx}dx
    √{(2π)ⁿ}  [−∞,+∞]ⁿ

   For a cube we define qmcpit as iterator of QMCarloCubeQuadrature, and for
   the normal density multiplied function we define qmcnpit as iterator of
   QMCarloNormalQuadrature.

   The quasi Monte Carlo method generates low discrepancy points with equal
   weights. The one dimensional low discrepancy sequences are generated by
   RadicalInverse class, the sequences are combined for higher dimensions by
   HaltonSequence class. The Halton sequence can use a permutation scheme;
   PermutattionScheme is an abstract class for all permutaton schemes. We have
   three implementations: WarnockPerScheme, ReversePerScheme, and
   IdentityPerScheme. */

#ifndef QUASI_MCARLO_H
#define QUASI_MCARLO_H

#include "int_sequence.hh"
#include "quadrature.hh"

#include "Vector.hh"

#include <vector>

/* This abstract class declares permute() method which permutes coefficient ‘c’
   having index of ‘i’ fro the base ‘base’ and returns the permuted coefficient
   which must be in 0,…,base−1. */

class PermutationScheme
{
public:
  PermutationScheme() = default;
  virtual ~PermutationScheme() = default;
  virtual int permute(int i, int base, int c) const = 0;
};

/* This class represents an integer number ‘num’ as c₀+c₁b+c₂b²+…+cⱼbʲ, where b
   is ‘base’ and c₀,…,cⱼ is stored in ‘coeff’. The size of IntSequence coeff
   does not grow with growing ‘num’, but is fixed from the very beginning and
   is set according to supplied maximum ‘maxn’.

   The basic method is eval() which evaluates the RadicalInverse with a given
   permutation scheme and returns the point, and increase() which increases
   ‘num’ and recalculates the coefficients. */

class RadicalInverse
{
  int num;
  int base;
  int maxn;
  int j;
  IntSequence coeff;
public:
  RadicalInverse(int n, int b, int mxn);
  RadicalInverse(const RadicalInverse &ri) = default;
  RadicalInverse &operator=(const RadicalInverse &radi) = default;
  double eval(const PermutationScheme &p) const;
  void increase();
  void print() const;
};

/* This is a vector of RadicalInverses, each RadicalInverse has a different
   prime as its base. The static members ‘primes’ and ‘num_primes’ define a
   precalculated array of primes. The increase() method of the class increases
   indices in all RadicalInverse’s and sets point ‘pt’ to contain the points in
   each dimension. */

class HaltonSequence
{
private:
  static std::array<int, 170> primes;
protected:
  int num;
  int maxn;
  std::vector<RadicalInverse> ri;
  const PermutationScheme &per;
  Vector pt;
public:
  HaltonSequence(int n, int mxn, int dim, const PermutationScheme &p);
  HaltonSequence(const HaltonSequence &hs) = default;
  HaltonSequence &operator=(const HaltonSequence &hs) = delete;
  void increase();
  const Vector &
  point() const
  {
    return pt;
  }
  const int
  getNum() const
  {
    return num;
  }
  void print() const;
protected:
  void eval();
};

/* This is a specification of quasi Monte Carlo quadrature. It consists of
   dimension ‘dim’, number of points (or level) ‘lev’, and the permutation
   scheme. This class is common to all quasi Monte Carlo classes. */

class QMCSpecification
{
protected:
  int dim;
  int lev;
  const PermutationScheme &per_scheme;
public:
  QMCSpecification(int d, int l, const PermutationScheme &p)
    : dim(d), lev(l), per_scheme(p)
  {
  }
  virtual ~QMCSpecification() = default;
  int
  dimen() const
  {
    return dim;
  }
  int
  level() const
  {
    return lev;
  }
  const PermutationScheme &
  getPerScheme() const
  {
    return per_scheme;
  }
};

/* This is an iterator for quasi Monte Carlo over a cube QMCarloCubeQuadrature.
   The iterator maintains HaltonSequence of the same dimension as given by the
   specification. An iterator can be constructed from a given number ‘n’, or by
   a copy constructor. */

class qmcpit
{
protected:
  const QMCSpecification &spec;
  HaltonSequence halton;
  ParameterSignal sig;
public:
  qmcpit(const QMCSpecification &s, int n);
  qmcpit(const qmcpit &qpit) = default;
  virtual ~qmcpit() = default;
  bool operator==(const qmcpit &qpit) const;
  bool
  operator!=(const qmcpit &qpit) const
  {
    return !operator==(qpit);
  }
  qmcpit &operator=(const qmcpit &qpit) = delete;
  qmcpit &operator++();
  const ParameterSignal &
  signal() const
  {
    return sig;
  }
  const Vector &
  point() const
  {
    return halton.point();
  }
  double weight() const;
  void
  print() const
  {
    halton.print();
  }
};

/* This is an easy declaration of quasi Monte Carlo quadrature for a cube.
   Everything important has been done in its iterator qmcpit, so we only
   inherit from general Quadrature and reimplement begin() and numEvals(). */

class QMCarloCubeQuadrature : public QuadratureImpl<qmcpit>, public QMCSpecification
{
public:
  QMCarloCubeQuadrature(int d, int l, const PermutationScheme &p)
    : QuadratureImpl<qmcpit>(d), QMCSpecification(d, l, p)
  {
  }
  ~QMCarloCubeQuadrature() override = default;
  int
  numEvals(int l) const override
  {
    return l;
  }
protected:
  qmcpit
  begin(int ti, int tn, int lev) const override
  {
    return qmcpit(*this, ti*level()/tn + 1);
  }
};

/* Declares Warnock permutation scheme. */
class WarnockPerScheme : public PermutationScheme
{
public:
  int permute(int i, int base, int c) const override;
};

/* Declares reverse permutation scheme. */
class ReversePerScheme : public PermutationScheme
{
public:
  int permute(int i, int base, int c) const override;
};

/* Declares no permutation (identity) scheme. */
class IdentityPerScheme : public PermutationScheme
{
public:
  int
  permute(int i, int base, int c) const override
  {
    return c;
  }
};

#endif