Antithetic draws explicitly generatedΒΆ

Calculation of a simple integral using Monte-Carlo integration. It illustrates how to use antithetic draws, explicitly generated.

Michel Bierlaire, EPFL Sat Jun 28 2025, 21:09:19

import numpy as np
import pandas as pd
from IPython.core.display_functions import display

from biogeme.biogeme import BIOGEME
from biogeme.database import Database
from biogeme.draws import RandomNumberGeneratorTuple, get_halton_draws
from biogeme.expressions import Draws, MonteCarlo, exp
R = 2_000_000

We create a fake database with one entry, as it is required to store the draws

df = pd.DataFrame()
df['FakeColumn'] = [1.0]
database = Database('fake_database', df)
def halton13(sample_size: int, number_of_draws: int) -> np.array:
    """
    The user can define new draws. For example, Halton draws
    with base 13, skipping the first 10 draws.

    :param sample_size: number of observations for which draws must be
                       generated.
    :param number_of_draws: number of draws to generate.

    """
    return get_halton_draws(sample_size, number_of_draws, base=13, skip=10)
my_draws = {
    'HALTON13': RandomNumberGeneratorTuple(
        halton13, 'Halton draws, base 13, skipping 10'
    )
}
U = Draws('U', 'UNIFORM')
integrand = exp(U) + exp(1 - U)
simulated_integral = MonteCarlo(integrand) / 2.0
U_halton13 = Draws('U_halton13', 'HALTON13')
integrand_halton13 = exp(U_halton13) + exp(1 - U_halton13)
simulated_integral_halton13 = MonteCarlo(integrand_halton13) / 2.0
U_mlhs = Draws('U_mlhs', 'UNIFORM_MLHS')
integrand_mlhs = exp(U_mlhs) + exp(1 - U_mlhs)
simulated_integral_mlhs = MonteCarlo(integrand_mlhs) / 2.0
true_integral = exp(1.0) - 1.0
error = simulated_integral - true_integral
error_halton13 = simulated_integral_halton13 - true_integral
error_mlhs = simulated_integral_mlhs - true_integral
simulate = {
    'Analytical Integral': true_integral,
    'Simulated Integral': simulated_integral,
    'Error             ': error,
    'Simulated Integral (Halton13)': simulated_integral_halton13,
    'Error (Halton13)             ': error_halton13,
    'Simulated Integral (MLHS)': simulated_integral_mlhs,
    'Error (MLHS)             ': error_mlhs,
}
biosim = BIOGEME(
    database, simulate, random_number_generators=my_draws, number_of_draws=R
)
biosim.model_name = 'b03antithetic_explicit'
results = biosim.simulate(the_beta_values={})
display(results)
   Analytical Integral  ...  Error (MLHS)
0             1.718282  ...              -4.418821e-11

[1 rows x 7 columns]
print(f"Analytical integral: {results.iloc[0]['Analytical Integral']:.6f}")
print(
    f"         \t{'Uniform (Anti)':>15}\t{'Halton13 (Anti)':>15}\t{'MLHS (Anti)':>15}"
)
print(
    f"Simulated\t{results.iloc[0]['Simulated Integral']:>15.6g}\t"
    f"{results.iloc[0]['Simulated Integral (Halton13)']:>15.6g}\t"
    f"{results.iloc[0]['Simulated Integral (MLHS)']:>15.6g}"
)
print(
    f"Error\t\t{results.iloc[0]['Error             ']:>15.6g}\t"
    f"{results.iloc[0]['Error (Halton13)             ']:>15.6g}\t"
    f"{results.iloc[0]['Error (MLHS)             ']:>15.6g}"
)
Analytical integral: 1.718282
                 Uniform (Anti) Halton13 (Anti)     MLHS (Anti)
Simulated               1.71826         1.71828         1.71828
Error              -1.74385e-05     5.57648e-08    -4.41882e-11

Total running time of the script: (0 minutes 0.423 seconds)

Gallery generated by Sphinx-Gallery