Consider some function of arguments x,y,z, where the latter have some domain of definition $\mathcal{R}$:
function[x_, y_, z_] = Exp[-x^2]/(y^2 + 1.23)*Exp[-z];
zmin[x_, y_] = x + y*Exp[-y^2];
zmax[x_, y_] = 3.4*(x + 1.2*y*Exp[-y]);
ymin[x_] = 0.1*x*Exp[-x^3 - x^2] + 0.1*Exp[-Cos[x]^2];
ymax[x_] = x*Exp[-x^((2/3.)) + 1] + 0.22*Exp[-Cos[x]^4];
xmin = 0;
xmax = 10;
I need to evaluate an integral $$ \mathcal{I} = \int \limits_{x_{\text{min}}}^{x_{\text{max}}}dx \ \int \limits_{y_{\text{min}}}^{y_{\text{max}}}dy \ \int \limits_{z_{\text{min}}}^{z_{\text{max}}}dz \ f(x,y,z) $$
For some reason, I would like to implement my own simple Monte Carlo integration. Namely, I start with the formula
$$ \tag 1 \mathcal{I} \approx \frac{\Phi}{N}\sum_{i = 1}^{N}f(x_{i},y_{i},z_{i}), \quad \text{where} \quad \Phi = \int \limits_{x_{\text{min}}}^{x_{\text{max}}}dx\ \int \limits_{y_{\text{min}}}^{y_{\text{max}}}dy \ \int \limits_{z_{\text{min}}}^{z_{\text{max}}}dz, \quad (x_{i},y_{i},z_{i}) \in \mathcal{R} $$
First, I evaluate the phase space $\Phi$:
Measure =
NIntegrate[
1, {x, xmin, xmax}, {y, ymin[x], ymax[x]}, {z, zmin[x, y],
zmax[x, y]}]
84.0468
Next, I generate random points belonging to $\mathcal{R}$:
RandomxValues[Nevents_] := RandomReal[{xmin, xmax}, Nevents]
RandomyValues =
Hold@Compile[{{RandomxValuesTable, _Real, 1}},
Table[RandomReal[{ymin[RandomxValuesTable[[i]]],
ymax[RandomxValuesTable[[i]]]}], {i, 1,
Length[RandomxValuesTable], 1}], CompilationTarget -> "C",
RuntimeOptions -> "Speed"] /. DownValues@ymin /.
DownValues@ymax // ReleaseHold;
RandomzValues =
Hold@Compile[{{RandomxValuesTable, _Real,
1}, {RandomyValuesTable, _Real, 1}},
Table[RandomReal[{zmin[RandomxValuesTable[[i]],
RandomyValuesTable[[i]]],
zmax[RandomxValuesTable[[i]], RandomyValuesTable[[i]]]}], {i,
1, Length[RandomxValuesTable], 1}], CompilationTarget -> "C",
RuntimeOptions -> "Speed"] /. DownValues@zmin /.
DownValues@zmax // ReleaseHold;
RandomxyzPoints[Nevents_] := Block[{},
RandomxValuesTable = Quiet[RandomxValues[Nevents]];
RandomyValuesTable = Quiet[RandomyValues[RandomxValuesTable]];
RandomzValuesTable =
Quiet[RandomzValues[RandomxValuesTable, RandomyValuesTable]];
Join[Partition[RandomxValuesTable, 1],
Partition[RandomyValuesTable, 1], Partition[RandomzValuesTable, 1],
2]
]
(*An example demonstrating the performance of RandomxyzPoints*)
randomPointsTable = RandomxyzPoints[10^6]; // AbsoluteTiming
{0.209248,Null}
It looks like the generator works properly:
randomPointsTable1 = RandomxyzPoints[10^4];
Show[ListPointPlot3D[randomPointsTable1],
DiscretizeRegion[
ImplicitRegion[
xmin < x < xmax && ymin[x] < y < ymax[x] &&
zmin[x, y] < z < zmax[x, y], {x, y, z}](*,{{xmin,xmax},{0,30},{0,
30}}*)]]
Finally, my Monte Carlo integral is
FunctionSum =
Hold@Compile[{{randomPointsTable, _Real, 2}},
Sum[function[randomPointsTable[[i]][[1]],
randomPointsTable[[i]][[2]], randomPointsTable[[i]][[3]]], {i,
1, Length[randomPointsTable], 1}], CompilationTarget -> "C",
RuntimeOptions -> "Speed"] /. DownValues@function // ReleaseHold
MonteCarloMy[Nevents_] :=
Measure/Nevents*FunctionSum[RandomxyzPoints[Nevents]]
Comparing with
MonteCarloMathematica =
NIntegrate[
function[x, y, z], {x, xmin, xmax}, {y, ymin[x], ymax[x]}, {z,
zmin[x, y], zmax[x, y]}, Method -> "MonteCarlo"]
0.131921
I find
MonteCarloMy[10^6]
1.49451
My question is: am I stupid since Eq. (1) is incorrect, or I made something wrong in the implementation?
An edit.
Let us simplify the domain of the definition of x,y,z, such that they are all independent:
zmin[x_, y_] = 0;
zmax[x_, y_] = 13;
ymin[x_] = 1.34;
ymax[x_] = 144;
xmin = 0;
xmax = 10;
and relaunch all the remaining code. The results, however, are still different:
MonteCarloMy[10^6]/MonteCarloMathematica
0.8007
I do not understand the reason for this discrepancy.
Edit 2.
So, if continuing with my method, following comments and the answer, I need to define $\Delta z[x,y] = \int\limits_{\mathcal{R}_{x,y}} dz$, $\Delta y[x] = \int\limits_{\mathcal{R}_{x}} dy$, and instead of pure sum of function
I need to multiply it with the weights $\Delta z
\times \Delta y$, and divide by the sum of $\Delta z \times \Delta y$.