TheAlgorithms/C++ 1.0.0
All the algorithms implemented in C++
Loading...
Searching...
No Matches
integral_approximation2.cpp
Go to the documentation of this file.
1
24#define _USE_MATH_DEFINES
25#include <cmath>
26#include <cstdint>
27#include <ctime>
28#include <functional>
29#include <iostream>
30#include <random>
31#include <vector>
32
37namespace math {
44namespace monte_carlo {
45
46using Function = std::function<double(
47 double&)>;
48
64std::vector<double> generate_samples(const double& start_point,
65 const Function& pdf,
66 const uint32_t& num_samples,
67 const uint32_t& discard = 100000) {
68 std::vector<double> samples;
69 samples.reserve(num_samples);
70
71 double x_t = start_point;
72
73 std::default_random_engine generator;
74 std::uniform_real_distribution<double> uniform(0.0, 1.0);
75 std::normal_distribution<double> normal(0.0, 1.0);
76 generator.seed(time(nullptr));
77
78 for (uint32_t t = 0; t < num_samples + discard; ++t) {
79 // Generate a new proposal according to some mutation strategy.
80 // This is arbitrary and can be swapped.
81 double x_dash = normal(generator) + x_t;
82 double acceptance_probability = std::min(pdf(x_dash) / pdf(x_t), 1.0);
83 double u = uniform(generator);
84
85 // Accept "new state" according to the acceptance_probability
86 if (u <= acceptance_probability) {
87 x_t = x_dash;
88 }
89
90 if (t >= discard) {
91 samples.push_back(x_t);
92 }
93 }
94
95 return samples;
96}
97
112double integral_monte_carlo(const double& start_point, const Function& function,
113 const Function& pdf,
114 const uint32_t& num_samples = 1000000) {
115 double integral = 0.0;
116 std::vector<double> samples =
117 generate_samples(start_point, pdf, num_samples);
118
119 for (double sample : samples) {
120 integral += function(sample) / pdf(sample);
121 }
122
123 return integral / static_cast<double>(samples.size());
124}
125
126} // namespace monte_carlo
127} // namespace math
128
133static void test() {
134 std::cout << "Disclaimer: Because this is a randomized algorithm,"
135 << std::endl;
136 std::cout
137 << "it may happen that singular samples deviate from the true result."
138 << std::endl
139 << std::endl;
140 ;
141
142 math::monte_carlo::Function f;
143 math::monte_carlo::Function pdf;
144 double integral = 0;
145 double lower_bound = 0, upper_bound = 0;
146
147 /* \int_{-2}^{2} -x^2 + 4 dx */
148 f = [&](double& x) { return -x * x + 4.0; };
149
150 lower_bound = -2.0;
151 upper_bound = 2.0;
152 pdf = [&](double& x) {
153 if (x >= lower_bound && x <= -1.0) {
154 return 0.1;
155 }
156 if (x <= upper_bound && x >= 1.0) {
157 return 0.1;
158 }
159 if (x > -1.0 && x < 1.0) {
160 return 0.4;
161 }
162 return 0.0;
163 };
164
165 integral = math::monte_carlo::integral_monte_carlo(
166 (upper_bound - lower_bound) / 2.0, f, pdf);
167
168 std::cout << "This number should be close to 10.666666: " << integral
169 << std::endl;
170
171 /* \int_{0}^{1} e^x dx */
172 f = [&](double& x) { return std::exp(x); };
173
174 lower_bound = 0.0;
175 upper_bound = 1.0;
176 pdf = [&](double& x) {
177 if (x >= lower_bound && x <= 0.2) {
178 return 0.1;
179 }
180 if (x > 0.2 && x <= 0.4) {
181 return 0.4;
182 }
183 if (x > 0.4 && x < upper_bound) {
184 return 1.5;
185 }
186 return 0.0;
187 };
188
189 integral = math::monte_carlo::integral_monte_carlo(
190 (upper_bound - lower_bound) / 2.0, f, pdf);
191
192 std::cout << "This number should be close to 1.7182818: " << integral
193 << std::endl;
194
195 /* \int_{-\infty}^{\infty} sinc(x) dx, sinc(x) = sin(pi * x) / (pi * x)
196 This is a difficult integral because of its infinite domain.
197 Therefore, it may deviate largely from the expected result.
198 */
199 f = [&](double& x) { return std::sin(M_PI * x) / (M_PI * x); };
200
201 pdf = [&](double& x) {
202 return 1.0 / std::sqrt(2.0 * M_PI) * std::exp(-x * x / 2.0);
203 };
204
205 integral = math::monte_carlo::integral_monte_carlo(0.0, f, pdf, 10000000);
206
207 std::cout << "This number should be close to 1.0: " << integral
208 << std::endl;
209}
210
215int main() {
216 test(); // run self-test implementations
217 return 0;
218}
std::vector< double > generate_samples(const double &start_point, const Function &pdf, const uint32_t &num_samples, const uint32_t &discard=100000)
short-hand for std::functions used in this implementation
static void test()
Self-test implementations.
int main()
Main function.
double integral_monte_carlo(const double &start_point, const Function &function, const Function &pdf, const uint32_t &num_samples=1000000)
Compute an approximation of an integral using Monte Carlo integration.
for assert
Functions for the Monte Carlo Integration implementation.