|
Monte Carlo Integration Library 1.0
High-performance Monte Carlo methods for numerical integration and optimization
|
This project implements a Monte Carlo integration algorithm in C++ to calculate definite integrals over N-dimensional hyperspheres and hyperrectangles. The software can use the muParserX library to parse mathematical functions at runtime.
Ensure you have CMake, a C++ compiler, and muParserX installed.
From the root of the project:
Full API documentation is available via Doxygen:
See DOXYGEN_GUIDE.md for detailed instructions.
The project offers several run modes, divided into two main executables (montecarlo_1 for benchmarks/tests and drone_optimization for the specific application):
Executable: montecarlo_1 Uses the mathematical expression from function.txt via the muParserX library.
Use case: When you want to test custom functions without recompiling.
Performance: Slower due to runtime parsing overhead (~2-10x slower than hardcoded).
Gnuplot: Supports visualization (1D, 2D, 3D only).
Domains tested: Hypersphere, Hyperrectangle, Hypercylinder across various dimensions.
How it works: The parser reads your function expression from function.txt and performs Monte Carlo integration using uniform sampling over multiple geometric domains. Test functions include:
Benchmark output: Generates tables comparing sample counts (100, 1K, 10K, 100K, 1M) and execution times, with Gnuplot visualization of convergence.
Executable: montecarlo_1 Uses pre-compiled C++ lambda functions with multiple integration strategies.
Use case: When performance is critical and you're working with fixed test functions. Ideal for variance reduction studies.
Performance: Fast (no parsing overhead; ~10-100x faster than Mode 1).
Gnuplot: Supports visualization (1D, 2D, 3D only).
Domains tested: Hypersphere, Hyperrectangle, Hypercylinder, various dimensions up to 12D.
Integration methods tested:
Test functions include:
Benchmark output: For each domain, runs all 4 methods across sample counts (100โ1M) and reports execution times and convergence rates. Saves results to results_seed_*.txt files.
Executable: montecarlo_1 Uses pre-compiled C++ lambda functions with Metropolis-Hastings Markov Chain Monte Carlo sampling.
Use case: For complex or high-dimensional domains where uniform sampling is inefficient. Excellent for non-convex geometries.
Performance: Fast (compiled), with superior O(1/N) convergence vs O(1/โN) for classic MC.
Gnuplot: Supports visualization (1D, 2D, 3D only).
Domains tested: Hypersphere, Hyperrectangle, Hypercylinder.
Algorithm:
Configuration:
Benchmark output: Compares MH vs classic MC across same sample counts, showing convergence rates and acceptance statistics.
Executable: montecarlo_1 Integrates over arbitrary convex polytopes defined by user-provided points.
Use case: When your integration domain is a convex polytope (e.g., polyhedron in 3D, 4D+ convex polytope).
Performance: O(N ร F) where N = samples, F = number of facets. Scales well for moderate polytope complexity.
Gnuplot: Not applicable (higher-dimensional geometries).
Input files: points.txt (vertices), hull.txt (facet normals + offsets from Qhull).
How it works:
points.txthull.txt (half-space representation)**Input format (points.txt):**
Qhull command:
Executable: montecarlo_1 Runs optimization benchmarks using the Particle Swarm Optimization algorithm.
Use case: Finding global minima of continuous, smooth optimization landscapes.
Performance: 10-100x faster than GA for smooth functions; excellent scaling to high dimensions.
Gnuplot: Auto-generates convergence plots (run_pso.gp, run_pso_3d.gp).
Benchmark functions:
Algorithm configuration:
Output: Convergence plots showing best fitness vs iteration, comparison with GA results.
Executable: montecarlo_1 Runs optimization benchmarks using a Genetic Algorithm.
Use case: Finding global minima for non-smooth, noisy, or discrete-variable problems.
Performance: More robust than PSO for multimodal landscapes; slower on smooth functions.
Gnuplot: Auto-generates convergence plots (run_ga.gp, run_ga_3d.gp).
Benchmark functions: Same as PSO (Sphere, Rastrigin, Rosenbrock) for direct comparison.
Algorithm configuration:
Output: Convergence curves, final best solution, comparison vs PSO on same test functions.
Executable: drone_optimization Specialized application combining Monte Carlo integration with PSO for geometric optimization.
Use case: Optimizing hole placement and size in a drone arm to achieve target center of mass.
Performance: Parallelized PSO with OpenMP thread management (~10x speedup on 8 cores).
Output: High-precision verification with 1M samples, auto-generated 3D visualization script.
Physical domain (3D):
Optimization problem:
Algorithm phases:
Output files:
drone_frames/drone_domain.txt: Sampled points on geometry (for visualization)visualize_drone.gp: Auto-generated Gnuplot script for 3D renderingoptimization_log.txt: Per-iteration PSO statisticsfinal_solution.txt: Optimal hole parameters and final center of massThread management:
./drone_optimization [seed] [num_threads]Key Results:
The optimization successfully balances the drone arm achieving:
This confirms high fidelity and robustness of the stochastic solver.
Visualization:
After running, the script automatically generates visualize_drone.gp:
Images of the domain:
*(Note: The images below are from a similar simulation setup to clearly illustrate the hole placement; specific dimensions in the current build may vary slightly.)*
Command line:
seed: Random seed (optional, default: 12345; use - to keep default when specifying threads)num_threads: Number of threads (optional, default: max available; 0 = sequential for performance comparison)Examples:
Executable: wind_farm_simulator Optimizes wind turbine placement using hybrid Metropolis-Hastings Monte Carlo integration combined with PSO and Genetic Algorithm.
Use case: Finding the optimal layout of wind turbines in a farm to maximize power generation while respecting minimum distance constraints.
Performance: Parallel MH integration with OpenMP thread-safe RNG and optimizers running PSO vs GA comparison.
Output: Optimized turbine positions, convergence plots, and wind farm layout visualizations.
How it works:
Physical Model:
Algorithm Configuration:
Command line:
Output Files:
results_pso.dat - Optimized turbine positions from PSOresults_ga.dat - Optimized turbine positions from GAplot_pso.gp - Gnuplot script for PSO layout visualizationplot_ga.gp - Gnuplot script for GA layout visualizationwind_farm_layout_pso.png - PSO optimization result imagewind_farm_layout_ga.png - GA optimization result imageVisualization:
./montecarlo_1 <seed>./montecarlo_1 <seed> <num_threads> for montecarlo_1./drone_optimization [seed|-] [num_threads] for drone optimization0 for sequential execution, N > 0 for N threads- as seed placeholder to keep default seed when specifying threadsdrone_frames/ for the drone geometry outputs).gnuplot run_pso.gp, run_pso_3d.gp, run_ga.gp, run_ga_3d.gpgnuplot -persist visualize_drone.gp (auto-generated after running drone_optimization)
Before compiling the program, enter the function to integrate in the function.txt file located in the root of the repository.
Use standard mathematical notation such as:
x, y, z or x[0], x[1]).+, -, *, /, ^ (power).sin(), cos(), tan(), exp(), log(), sqrt(), abs()._pi, _e.Example Input:
This library implements several Monte Carlo methods for numerical integration and stochastic optimization. Below is the mathematical formulation for the core algorithms used.
The simplest Monte Carlo estimator approximates the integral of a function $f$ over a domain $\Omega$ by sampling points uniformly within a bounding box $B$ (where $\Omega \subseteq B$) and evaluating $f$.
$$I = \int_{\Omega} f(\mathbf{x}) \, d\mathbf{x} \approx V_B \cdot \frac{1}{N} \sum_{i=1}^{N} f(\mathbf{x}_i) \cdot \mathbb{1}_{\Omega}(\mathbf{x}_i)$$
Where:
Implementation Details: The method integrate generates random points in the bounding box. If a point falls inside the domain (checked via domain.isInside(p)), its contribution is added. Non-domain points effectively contribute 0.
Importance Sampling reduces variance by sampling points from a proposal distribution $q(\mathbf{x})$ that ideally resembles the shape of $f(\mathbf{x})$, rather than sampling uniformly.
$$I = \int_{\Omega} f(\mathbf{x}) \, d\mathbf{x} \approx \frac{1}{N} \sum_{i=1}^{N} \frac{f(\mathbf{x}_i)}{q(\mathbf{x}_i)}$$
Where:
Implementation Details: The ISMeanEstimator computes the mean of the weighted samples. The integrate_importance method uses this estimator. Note that for the integration to be correct over the domain volume, the weights must be properly scaled relative to the domain measure.
The quality of importance sampling depends critically on the choice of proposal distribution $q(\mathbf{x})$. The framework provides three pluggable proposal types, each optimized for different scenarios:
Standard rejection sampling over the bounding box.
$$q(\mathbf{x}) = \frac{1}{V_B}, \quad \mathbf{x} \in B$$
Characteristics:
Use when: Testing baseline performance or domain is roughly rectangular.
Example:
Isotropic Gaussian centered at domain centroid. Reduces variance when the integrand is smooth and bell-shaped.
$$q(\mathbf{x}) = \frac{1}{(2\pi\sigma^2)^{d/2}} \exp\left(-\frac{|\mathbf{x}-\boldsymbol{\mu}|^2}{2\sigma^2}\right)$$
Characteristics:
Best for: Low-to-medium dimensions (d < 10), smooth smooth integrands (e.g., Gaussians, polynomials).
Parameter guidance:
Example:
Convex combination of Gaussian and Uniform proposals. Balances exploitation (Gaussian focus) with exploration (Uniform coverage).
$$q(\mathbf{x}) = \lambda \cdot q_{\text{Gauss}}(\mathbf{x}) + (1-\lambda) \cdot q_{\text{Uniform}}(\mathbf{x}), \quad \lambda \in [0,1]$$
Characteristics:
Best for: Medium-high dimensions (d = 5โ20), unknown/non-smooth integrands.
Parameter guidance:
Example:
| Proposal | Variance Reduction | Dimension Scaling | Tuning Effort | Recommendation |
|---|---|---|---|---|
| Uniform | None (baseline) | O(1) | Zero | Baseline, testing |
| Gaussian | High (if $\sigma$ well-tuned) | Degrades in high-d | Medium (ฯ tuning) | d < 10, smooth f |
| Mixture | Medium-High | Better high-d scaling | Low (robust defaults) | d = 5โ20, unknown f |
This method is effective for complex domains where simple uniform sampling is inefficient. It separates the problem into two parts: estimating the domain volume and estimating the function mean.
$$I = V_{\Omega} \cdot \bar{f} \quad \text{where} \quad \bar{f} = \frac{1}{N} \sum_{i=1}^{N} f(\mathbf{x}_i)$$
Where $\mathbf{x}_i$ are samples generated by the MH sampler. The sampler accepts a candidate $\mathbf{x}'$ from current state $\mathbf{x}$ with probability:
$$\alpha = \min\left(1, \frac{\pi(\mathbf{x}')}{\pi(\mathbf{x})}\right)$$
(Note: The proposal distribution in the random walk is symmetric, so the Hastings ratio $\frac{q(\mathbf{x}|\mathbf{x}')}{q(\mathbf{x}'|\mathbf{x})}$ cancels out).
Implementation Details: The method integrate_with_mh first calls VolumeEstimatorMC to find $V_{\Omega}$. Then it runs a MetropolisHastingsSampler to gather samples $\mathbf{x}_i$ inside $\Omega$ and computes their average $\bar{f}$.
PSO optimizes a function by simulating a swarm of particles moving through the search space. Each particle $i$ has a position $\mathbf{x}_i$ and velocity $\mathbf{v}_i$. They are updated based on:
Update Equations:
$$\mathbf{v}_i(t+1) = w \cdot \mathbf{v}_i(t) + c_1 \cdot r_1 \cdot (\mathbf{p}_i - \mathbf{x}_i(t)) + c_2 \cdot r_2 \cdot (\mathbf{g} - \mathbf{x}_i(t))$$
$$\mathbf{x}_i(t+1) = \mathbf{x}_i(t) + \mathbf{v}_i(t+1)$$
Where:
Implementation Details: Found in PSO.cpp, the step() function applies these updates and enforces boundary constraints (damping velocity if a boundary is hit).
GA evolves a population of candidate solutions using biologically inspired operators.
Implementation Details: Found in GA.cpp, implementing tournament selection, uniform crossover, and Gaussian mutation within the step() loop.
The volume of an integration domain $\Omega$ is estimated using a Hit-or-Miss approach. By enclosing $\Omega$ in a bounding box $B$ of known volume $V_B$:
$$V_{\Omega} \approx V_B \cdot \frac{N_{\text{hits}}}{N_{\text{total}}}$$
The standard error of this estimate is derived from the variance of the Bernoulli distribution (inside/outside):
$$\sigma_V = V_B \cdot \sqrt{\frac{p(1-p)}{N}}$$
Where $p = \frac{N_{\text{hits}}}{N_{\text{total}}}$.
The program also supports Monte Carlo integration over convex polytopes in any dimension. To define a polytope, you provide a set of points and let Qhull compute its convex hull, including facet normals and offsets.
1๏ธโฃ Create the input file points.txt
The format must be:
Example for 3D:
2๏ธโฃ Compute the convex hull (normals + offsets)
Use Qhull with the n option to output facet normals and plane offsets:
Where: โข Qt โ triangulates the hull โข n โ prints one facet normal per line, followed by its offset d โข Qhull outputs hyperplanes in the form
n ยท x + d = 0
and the program internally converts them to
n' ยท x โค b
which defines the half-spaces forming the convex polytope.
3๏ธโฃ Run the program in polytope mode