1 /*
2 * Copyright © 2005 Ondra Kamenik
3 * Copyright © 2019 Dynare Team
4 *
5 * This file is part of Dynare.
6 *
7 * Dynare is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * Dynare is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Dynare. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "quasi_mcarlo.hh"
22
23 #include <cmath>
24 #include <iostream>
25 #include <iomanip>
26 #include <array>
27
28 /* Here in the constructor, we have to calculate a maximum length of ‘coeff’
29 array for a given ‘base’ and given maximum ‘maxn’. After allocation, we
30 calculate the coefficients. */
31
RadicalInverse(int n,int b,int mxn)32 RadicalInverse::RadicalInverse(int n, int b, int mxn)
33 : num(n), base(b), maxn(mxn),
34 coeff(static_cast<int>(floor(log(static_cast<double>(maxn))/log(static_cast<double>(b)))+2), 0)
35 {
36 int nr = num;
37 j = -1;
38 do
39 {
40 j++;
41 coeff[j] = nr % base;
42 nr = nr / base;
43 }
44 while (nr > 0);
45 }
46
47 /* This evaluates the radical inverse. If there was no permutation, we have to
48 calculate:
49
50 c₀ c₁ cⱼ
51 ── + ── + … + ────
52 b b² bʲ⁺¹
53
54 which is evaluated as:
55
56 ⎛ ⎛⎛cⱼ 1 cⱼ₋₁⎞ 1 cⱼ₋₂⎞ ⎞ 1 c₀
57 ⎢…⎢⎢──·─ + ────⎥·─ + ────⎥…⎥·─ + ──
58 ⎝ ⎝⎝ b b b ⎠ b b ⎠ ⎠ b b
59
60
61 Now with permutation π, we have:
62
63 ⎛ ⎛⎛π(cⱼ) 1 π(cⱼ₋₁)⎞ 1 π(cⱼ₋₂)⎞ ⎞ 1 π(c₀)
64 ⎢…⎢⎢─────·─ + ───────⎥·─ + ───────⎥…⎥·─ + ─────
65 ⎝ ⎝⎝ b b b ⎠ b b ⎠ ⎠ b b
66 */
67
68 double
eval(const PermutationScheme & p) const69 RadicalInverse::eval(const PermutationScheme &p) const
70 {
71 double res = 0;
72 for (int i = j; i >= 0; i--)
73 {
74 int cper = p.permute(i, base, coeff[i]);
75 res = (cper + res)/base;
76 }
77 return res;
78 }
79
80 /* We just add 1 to the lowest coefficient and check for overflow with respect
81 to the base. */
82 void
increase()83 RadicalInverse::increase()
84 {
85 // TODO: raise if num+1 > maxn
86 num++;
87 int i = 0;
88 coeff[i]++;
89 while (coeff[i] == base)
90 {
91 coeff[i] = 0;
92 coeff[++i]++;
93 }
94 if (i > j)
95 j = i;
96 }
97
98 /* Debug print. */
99 void
print() const100 RadicalInverse::print() const
101 {
102 std::cout << "n=" << num << " b=" << base << " c=";
103 coeff.print();
104 }
105
106 /* Here we have the first 170 primes. This means that we are not able to
107 integrate dimensions greater than 170. */
108
109 std::array<int, 170> HaltonSequence::primes =
110 {
111 2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
112 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
113 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
114 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
115 179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
116 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
117 283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
118 353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
119 419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
120 467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
121 547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
122 607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
123 661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
124 739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
125 811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
126 877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
127 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013
128 };
129
130 /* This takes first ‘dim’ primes and constructs ‘dim’ radical inverses and
131 calls eval(). */
132
HaltonSequence(int n,int mxn,int dim,const PermutationScheme & p)133 HaltonSequence::HaltonSequence(int n, int mxn, int dim, const PermutationScheme &p)
134 : num(n), maxn(mxn), per(p), pt(dim)
135 {
136 // TODO: raise if dim > num_primes
137 // TODO: raise if n > mxn
138 for (int i = 0; i < dim; i++)
139 ri.emplace_back(num, primes[i], maxn);
140 eval();
141 }
142
143 /* This calls RadicalInverse::increase() for all radical inverses and calls
144 eval(). */
145
146 void
increase()147 HaltonSequence::increase()
148 {
149 for (auto &i : ri)
150 i.increase();
151 num++;
152 if (num <= maxn)
153 eval();
154 }
155
156 /* This sets point ‘pt’ to radical inverse evaluations in each dimension. */
157 void
eval()158 HaltonSequence::eval()
159 {
160 for (unsigned int i = 0; i < ri.size(); i++)
161 pt[i] = ri[i].eval(per);
162 }
163
164 /* Debug print. */
165 void
print() const166 HaltonSequence::print() const
167 {
168 auto ff = std::cout.flags();
169 for (const auto &i : ri)
170 i.print();
171 std::cout << "point=[ "
172 << std::fixed << std::setprecision(6);
173 for (unsigned int i = 0; i < ri.size(); i++)
174 std::cout << std::setw(7) << pt[i] << ' ';
175 std::cout << ']' << std::endl;
176 std::cout.flags(ff);
177 }
178
qmcpit(const QMCSpecification & s,int n)179 qmcpit::qmcpit(const QMCSpecification &s, int n)
180 : spec(s), halton{n, s.level(), s.dimen(), s.getPerScheme()},
181 sig{s.dimen()}
182 {
183 }
184
185 bool
operator ==(const qmcpit & qpit) const186 qmcpit::operator==(const qmcpit &qpit) const
187 {
188 return &spec == &qpit.spec && halton.getNum() == qpit.halton.getNum();
189 }
190
191 qmcpit &
operator ++()192 qmcpit::operator++()
193 {
194 halton.increase();
195 return *this;
196 }
197
198 double
weight() const199 qmcpit::weight() const
200 {
201 return 1.0/spec.level();
202 }
203
204 int
permute(int i,int base,int c) const205 WarnockPerScheme::permute(int i, int base, int c) const
206 {
207 return (c+i) % base;
208 }
209
210 int
permute(int i,int base,int c) const211 ReversePerScheme::permute(int i, int base, int c) const
212 {
213 return (base-c) % base;
214 }
215