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