Skip to content

Exact Solutions

dicex.analytical.linear.linear_directional_functional(beta, perturbation, alpha, c)

Compute the exact CVaR for a linear model under Gaussian directional noise.

Parameters:

Name Type Description Default
beta ndarray

Model coefficients.

required
perturbation BasePerturbation

Gaussian directional perturbation with additive noise.

required
alpha float

Risk level of the lower-tail CVaR.

required
c ndarray

Direction vector (unit norm).

required

Returns:

Name Type Description
float float

The exact robust directional value.

Raises:

Type Description
UnsupportedPerturbationError

If perturbation is not Gaussian.

Source code in src/dicex/analytical/linear.py
def linear_directional_functional(
    beta: np.ndarray,
    perturbation: BasePerturbation,
    alpha: float,
    c: np.ndarray,
) -> float:
    """Compute the exact CVaR for a linear model under Gaussian directional noise.

    Args:
        beta (np.ndarray): Model coefficients.
        perturbation (BasePerturbation): Gaussian directional perturbation with additive noise.
        alpha (float): Risk level of the lower-tail CVaR.
        c (np.ndarray): Direction vector (unit norm).

    Returns:
        float: The exact robust directional value.

    Raises:
        UnsupportedPerturbationError: If perturbation is not Gaussian.
    """
    weights = beta * c
    m_beta_env = perturbation.projected_env_mean(beta)
    v_beta_env = perturbation.projected_env_var(beta)

    if isinstance(perturbation, GaussianPerturbation):
        directional_mean, directional_var = directional_gaussian_mean_var(perturbation, weights)
        q_alpha = float(STANDARD_NORMAL.ppf(alpha))
        phi_q = float(STANDARD_NORMAL.pdf(q_alpha))
        lambda_alpha = phi_q / alpha

        return float(m_beta_env + directional_mean - lambda_alpha * np.sqrt(v_beta_env + directional_var))

    msg = f"Unsupported perturbation type: {type(perturbation)}"
    raise UnsupportedPerturbationError(msg)

dicex.analytical.linear.linear_optimal_direction(beta, perturbation, alpha, **kwargs)

Return an optimal direction for the exact linear objective on the sphere.

Parameters:

Name Type Description Default
beta ndarray

Model coefficients.

required
perturbation BasePerturbation

Gaussian directional perturbation.

required
alpha float

Risk level of the lower-tail CVaR.

required
**kwargs Any

Tuning options forwarded to the grid search. Supported keys:

  • n_grid_points: number of points of the outer 1-D grid over t (default: max(501, min(2000, 2 * int(||beta||)))).
  • n_top_candidates: number of best grid points refined by local zooming (default: 5).
{}

Returns:

Type Description
ndarray

np.ndarray: The optimal unit direction vector.

Raises:

Type Description
UnsupportedPerturbationError

If perturbation is not isotropic Gaussian.

Source code in src/dicex/analytical/linear.py
def linear_optimal_direction(
    beta: np.ndarray,
    perturbation: BasePerturbation,
    alpha: float,
    **kwargs: Any,  # noqa: ANN401
) -> np.ndarray:
    """Return an optimal direction for the exact linear objective on the sphere.

    Args:
        beta (np.ndarray): Model coefficients.
        perturbation (BasePerturbation): Gaussian directional perturbation.
        alpha (float): Risk level of the lower-tail CVaR.
        **kwargs (Any): Tuning options forwarded to the grid search. Supported keys:

            - ``n_grid_points``: number of points of the outer 1-D grid over t
              (default: ``max(501, min(2000, 2 * int(||beta||)))``).
            - ``n_top_candidates``: number of best grid points refined by local
              zooming (default: 5).

    Returns:
        np.ndarray: The optimal unit direction vector.

    Raises:
        UnsupportedPerturbationError: If perturbation is not isotropic Gaussian.
    """
    if not isinstance(perturbation, GaussianPerturbation):
        msg = f"Unsupported perturbation type: {type(perturbation)}"
        raise UnsupportedPerturbationError(msg)

    if not is_isotropic(perturbation):
        msg = "Exact linear optimization is only supported for isotropic Gaussian perturbations."
        raise UnsupportedPerturbationError(msg)

    return _isotropic_linear_optimal_direction(beta, perturbation, alpha, optimizer_kwargs=kwargs)

dicex.analytical.logistic.logistic_directional_functional(beta, b, x0, perturbation, alpha, c)

Compute the exact CVaR for a logistic model improvement.

Exact lower-tail functional under multidimensional Gaussian directional noise.

Parameters:

Name Type Description Default
beta ndarray

Model coefficients.

required
b float

Model intercept.

required
x0 ndarray

Baseline point.

required
perturbation BasePerturbation

Directional perturbation distribution.

required
alpha float

Risk level of the lower-tail CVaR.

required
c ndarray

Direction vector.

required

Returns:

Name Type Description
float float

The exact CVaR_alpha relative to the baseline Lambda(eta0).

Raises:

Type Description
UnsupportedPerturbationError

If perturbation is not Gaussian.

Source code in src/dicex/analytical/logistic.py
def logistic_directional_functional(
    beta: np.ndarray,
    b: float,
    x0: np.ndarray,
    perturbation: BasePerturbation,
    alpha: float,
    c: np.ndarray,
) -> float:
    """Compute the exact CVaR for a logistic model improvement.

    Exact lower-tail functional under multidimensional Gaussian directional noise.

    Args:
        beta (np.ndarray): Model coefficients.
        b (float): Model intercept.
        x0 (np.ndarray): Baseline point.
        perturbation (BasePerturbation): Directional perturbation distribution.
        alpha (float): Risk level of the lower-tail CVaR.
        c (np.ndarray): Direction vector.

    Returns:
        float: The exact CVaR_alpha relative to the baseline ``Lambda(eta0)``.

    Raises:
        UnsupportedPerturbationError: If perturbation is not Gaussian.
    """
    eta0 = float(np.dot(beta, x0) + b)
    weights = beta * c
    m_beta_env = perturbation.projected_env_mean(beta)
    v_beta_env = perturbation.projected_env_var(beta)

    if not isinstance(perturbation, GaussianPerturbation):
        msg = f"Unsupported perturbation type: {type(perturbation)}"
        raise UnsupportedPerturbationError(msg)

    directional_mean, directional_var = directional_gaussian_mean_var(perturbation, weights)
    m = eta0 + m_beta_env + directional_mean
    s = float(np.sqrt(v_beta_env + directional_var))
    h_val = logistic_h_alpha(m, s, alpha)

    baseline = _lambda(eta0)

    return float(h_val - baseline)

dicex.analytical.logistic.logistic_optimal_direction(beta, b, x0, perturbation, alpha, **kwargs)

Compute the optimal direction c* using the exact logistic objective.

Parameters:

Name Type Description Default
beta ndarray

Model coefficients.

required
b float

Model intercept.

required
x0 ndarray

Baseline point.

required
perturbation BasePerturbation

Gaussian directional perturbation.

required
alpha float

Risk level of the lower-tail CVaR.

required
**kwargs Any

Grid-search tuning options forwarded to the base optimizer (n_grid_points and n_top_candidates).

{}

Returns:

Type Description
ndarray

np.ndarray: The optimal unit direction vector.

Raises:

Type Description
UnsupportedPerturbationError

If perturbation is not Gaussian.

Source code in src/dicex/analytical/logistic.py
def logistic_optimal_direction(
    beta: np.ndarray,
    b: float,
    x0: np.ndarray,
    perturbation: BasePerturbation,
    alpha: float,
    **kwargs: Any,  # noqa: ANN401
) -> np.ndarray:
    """Compute the optimal direction c* using the exact logistic objective.

    Args:
        beta (np.ndarray): Model coefficients.
        b (float): Model intercept.
        x0 (np.ndarray): Baseline point.
        perturbation (BasePerturbation): Gaussian directional perturbation.
        alpha (float): Risk level of the lower-tail CVaR.
        **kwargs (Any): Grid-search tuning options forwarded to the base optimizer
            (``n_grid_points`` and ``n_top_candidates``).

    Returns:
        np.ndarray: The optimal unit direction vector.

    Raises:
        UnsupportedPerturbationError: If perturbation is not Gaussian.
    """
    if isinstance(perturbation, GaussianPerturbation):
        return _logistic_optimal_direction_base(
            beta, b, x0, perturbation, alpha, logistic_h_alpha, optimizer_kwargs=kwargs
        )

    msg = f"Unsupported perturbation type: {type(perturbation)}"
    raise UnsupportedPerturbationError(msg)