Source code for mergen.criteria.cd2
"""
mergen.criteria.cd2
===================
Centered L2-Discrepancy (CD2) criterion.
Reference
---------
Hickernell, F. J. (1998). A generalized discrepancy and quadrature
error bound. *Mathematics of Computation*, 67(221), 299-322.
"""
from __future__ import annotations
import numpy as np
from .base import BaseCriterion, _EPS
[docs]
class CD2(BaseCriterion):
"""
Centred L2 discrepancy.
Measures deviation of the empirical distribution from the uniform
distribution on [0, 1]^d. Lower values indicate better uniformity.
Criterion (minimise)::
CD2 = sqrt(
(13/12)^d
- (2/n) Σ_i prod_v (1 + 0.5|x_iv - 0.5| - 0.5(x_iv - 0.5)²)
+ (1/n²) Σ_{i,k} prod_v (1 + 0.5|x_iv - 0.5|
+ 0.5|x_kv - 0.5|
- 0.5|x_iv - x_kv|)
)
References
----------
Hickernell, F. J. (1998).
*Mathematics of Computation*, 67(221), 299–322.
"""
[docs]
def evaluate(self, X: np.ndarray, space) -> float:
X = np.asarray(X, dtype=float)
n, d = X.shape
t1 = (13.0 / 12.0) ** d
ci = 1.0 + 0.5 * np.abs(X - 0.5) - 0.5 * (X - 0.5) ** 2
t2 = (2.0 / n) * np.prod(ci, axis=1).sum()
xi = X[:, np.newaxis, :] # (n, 1, d)
xk = X[np.newaxis, :, :] # (1, n, d)
cik = (1.0
+ 0.5 * np.abs(xi - 0.5)
+ 0.5 * np.abs(xk - 0.5)
- 0.5 * np.abs(xi - xk))
t3 = np.prod(cik, axis=2).sum() / n ** 2
return float(np.sqrt(max(t1 - t2 + t3, 0.0)))
[docs]
def incremental(self, X, i, new_pt, space, current_score):
# Build updated design and recompute — CD2 cross terms make a
# closed-form O(n·d) update possible but complex; full recompute
# is O(n²·d) and acceptable for typical design sizes (n ≤ 200).
X_new = X.copy()
X_new[i] = new_pt
new_score = self.evaluate(X_new, space)
log_delta = np.log(max(new_score, _EPS)) - np.log(max(current_score, _EPS))
return float(log_delta), float(new_score)
def __repr__(self) -> str:
return "CD2()"