Monte Carlo Integration Library 1.0
High-performance Monte Carlo methods for numerical integration and optimization
VolumeEstimatorMC.tpp
Go to the documentation of this file.
1/**
2 * @file VolumeEstimatorMC.tpp
3 * @brief VolumeEstimatorMC template implementation.
4 * @details Implements hit-or-miss volume estimation with parallel sampling
5 * and standard error computation.
6 */
7// VolumeEstimatorMC.tpp
8//
9// Created by Giacomo Merlo on 12/01/26.
10//
11
12#include <algorithm>
13#include <cmath>
14#include <optional>
15#include <stdexcept>
16
17#include <omp.h>
18
19#include "montecarlo/rng/rng_factory.hpp"
20
21namespace mc::estimators {
22
23template <std::size_t dim>
24static geom::Point<dim>
25sample_uniform_in_box(const geom::Bounds<dim>& b, std::mt19937& rng)
26{
27 geom::Point<dim> x;
28 for (std::size_t k = 0; k < dim; ++k) {
29 std::uniform_real_distribution<double> unif(b[k].first, b[k].second);
30 x[k] = unif(rng);
31 }
32 return x;
33}
34
35template <std::size_t dim>
36VolumeEstimate<dim>
37VolumeEstimatorMC<dim>::estimate(const mc::domains::IntegrationDomain<dim>& domain,
38 std::uint32_t seed,
39 std::size_t n_samples) const
40{
41 if (n_samples == 0) throw std::invalid_argument("VolumeEstimatorMC: n_samples must be > 0.");
42
43 const geom::Bounds<dim> bounds = domain.getBounds();
44 const double boxV = domain.getBoxVolume();
45
46 const int T = omp_get_max_threads();
47 const std::size_t base = n_samples / static_cast<std::size_t>(T);
48 const std::size_t rem = n_samples % static_cast<std::size_t>(T);
49
50 std::size_t inside = 0;
51
52#pragma omp parallel for reduction(+:inside)
53 for (int tid = 0; tid < T; ++tid) {
54 const std::size_t n_local = base + (static_cast<std::size_t>(tid) < rem ? 1u : 0u);
55
56 auto rng = mc::rng::make_engine_with_seed(std::optional<std::uint32_t>{seed},
57 static_cast<std::uint64_t>(tid));
58
59 for (std::size_t i = 0; i < n_local; ++i) {
60 const auto x = sample_uniform_in_box<dim>(bounds, rng);
61 if (domain.isInside(x)) ++inside;
62 }
63 }
64
65 const double p = static_cast<double>(inside) / static_cast<double>(n_samples);
66 const double var_p = (p * (1.0 - p)) / static_cast<double>(n_samples);
67 const double se_p = std::sqrt(std::max(0.0, var_p));
68
69 VolumeEstimate<dim> out;
70 out.n_samples = n_samples;
71 out.inside_ratio = p;
72 out.volume = boxV * p;
73 out.stderr = boxV * se_p;
74 return out;
75}
76
77} // namespace mc::integrators