"""
Maximum Degree (MD)
===================
Rare-event estimation for the probability that the maximum degree of a
Gilbert random geometric graph G(X) does not exceed a threshold ℓ:

    P(MD(G(X)) ≤ ℓ)

Three estimators are provided: Naïve Monte Carlo, Conditional Monte Carlo,
and Importance Sampling Monte Carlo.

References
----------
Hirsch, C., Moka, S. B., Taimre, T., & Kroese, D. P. (2022).
    Rare events in random geometric graphs.
    *Methodology and Computing in Applied Probability*, 24, 1367–1383.

Moka, S., Hirsch, C., Schmidt, V., & Kroese, D. P. (2025).
    Efficient rare-event simulation for random geometric graphs via
    importance sampling. arXiv:2504.10530.
"""

from pyregg._md import (
    naiveMC       as _naiveMC,
    conditionalMC as _conditionalMC,
    ISMC          as _ISMC,
)

__all__ = ["naive_mc", "conditional_mc", "importance_sampling"]


def naive_mc(wind_len, kappa, int_range, level,
             max_iter=10**8, warm_up=100_000, tol=0.001, seed=None):
    """
    Estimate P(MD(G(X)) ≤ level) using Naïve Monte Carlo.

    Parameters
    ----------
    wind_len : float
        Side length of the square observation window [0, wind_len]².
    kappa : float
        Intensity of the Poisson point process (expected points per unit area).
    int_range : float
        Interaction range (connection radius) of the Gilbert graph.
    level : int
        Threshold ℓ. The rare event is {MD(G(X)) ≤ level}.
    max_iter : int, optional
        Maximum number of samples. Default is 10**8.
    warm_up : int, optional
        Minimum samples before checking convergence. Default is 100,000.
    tol : float, optional
        Stop when estimated RV / n < tol. Default is 0.001.
    seed : int or None, optional
        Random seed for reproducibility. Default is None.

    Returns
    -------
    probability : float
        Estimated rare-event probability P(MD(G(X)) ≤ level).
    rel_variance : float
        Estimated relative variance of the estimator.
    n_samples : int
        Number of samples used.

    Examples
    --------
    >>> import pyregg.md as md
    >>> Z, RV, n = md.naive_mc(wind_len=10, kappa=0.65, int_range=1.0, level=2)
    """
    return _naiveMC(wind_len, kappa, int_range, level, max_iter, warm_up, tol, seed)


def conditional_mc(wind_len, kappa, int_range, level,
                   max_iter=10**8, warm_up=1_000, tol=0.001, seed=None):
    """
    Estimate P(MD(G(X)) ≤ level) using Conditional Monte Carlo.

    Parameters
    ----------
    wind_len : float
        Side length of the square observation window [0, wind_len]².
    kappa : float
        Intensity of the Poisson point process (expected points per unit area).
    int_range : float
        Interaction range (connection radius) of the Gilbert graph.
    level : int
        Threshold ℓ. The rare event is {MD(G(X)) ≤ level}.
    max_iter : int, optional
        Maximum number of samples. Default is 10**8.
    warm_up : int, optional
        Minimum samples before checking convergence. Default is 1,000.
    tol : float, optional
        Stop when estimated RV / n < tol. Default is 0.001.
    seed : int or None, optional
        Random seed for reproducibility. Default is None.

    Returns
    -------
    probability : float
        Estimated rare-event probability P(MD(G(X)) ≤ level).
    rel_variance : float
        Estimated relative variance of the estimator.
    n_samples : int
        Number of samples used.

    Examples
    --------
    >>> import pyregg.md as md
    >>> Z, RV, n = md.conditional_mc(wind_len=10, kappa=0.65, int_range=1.0, level=2)
    """
    return _conditionalMC(wind_len, kappa, int_range, level, max_iter, warm_up, tol, seed)


def importance_sampling(wind_len, kappa, int_range, level, grid_res=100,
                        max_iter=10**8, warm_up=100, tol=0.001, seed=None):
    """
    Estimate P(MD(G(X)) ≤ level) using Importance Sampling Monte Carlo.

    Cells adjacent to any existing node with degree ≥ level, or with more
    than level existing neighbours, are blocked. A likelihood-ratio correction
    yields an unbiased estimate with substantially lower variance than CMC.

    Parameters
    ----------
    wind_len : float
        Side length of the square observation window [0, wind_len]².
    kappa : float
        Intensity of the Poisson point process (expected points per unit area).
    int_range : float
        Interaction range (connection radius) of the Gilbert graph.
    level : int
        Threshold ℓ. The rare event is {MD(G(X)) ≤ level}.
    grid_res : int, optional
        Number of grid cells per side (grid_res × grid_res total).
        Default is 100.
    max_iter : int, optional
        Maximum number of IS samples. Default is 10**8.
    warm_up : int, optional
        Minimum samples before checking convergence. Default is 100.
    tol : float, optional
        Stop when estimated RV / n < tol. Default is 0.001.
    seed : int or None, optional
        Random seed for reproducibility. Default is None.

    Returns
    -------
    probability : float
        Estimated rare-event probability P(MD(G(X)) ≤ level).
    rel_variance : float
        Estimated relative variance of the IS estimator.
    n_samples : int
        Number of IS samples used.

    Examples
    --------
    >>> import pyregg.md as md
    >>> Z, RV, n = md.importance_sampling(wind_len=10, kappa=0.65, int_range=1.0,
    ...                                   level=2, grid_res=100)
    """
    return _ISMC(wind_len, grid_res, kappa, int_range, level, max_iter, warm_up, tol, seed)
