From 613025322d7807b6942c518635be220f1c96085e Mon Sep 17 00:00:00 2001 From: Nihat Engin Toklu Date: Fri, 4 Aug 2023 00:49:57 +0200 Subject: [PATCH] Fix division-by-zero while initializing CMAES While computing its default C decomposition frequency, under some conditions (e.g. with a problem of solution length 1000), initialization of CMAES failed due to division-by-zero. This commit aims to fix this issue. --- src/evotorch/algorithms/cmaes.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/evotorch/algorithms/cmaes.py b/src/evotorch/algorithms/cmaes.py index ec489dcc..b514e2ea 100644 --- a/src/evotorch/algorithms/cmaes.py +++ b/src/evotorch/algorithms/cmaes.py @@ -18,7 +18,7 @@ This namespace contains the CMAES class """ -from typing import Optional, Tuple +from typing import Optional, Tuple, Union import numpy as np import torch @@ -80,6 +80,13 @@ def _limit_stdev(sigma: torch.Tensor, C: torch.Tensor, stdev_min: Optional[float return C +def _safe_divide(a: Union[Real, torch.Tensor], b: Union[Real, torch.Tensor]) -> Union[torch.Tensor]: + tolerance = 1e-8 + if abs(b) < tolerance: + b = (-tolerance) if b < 0 else tolerance + return a / b + + class CMAES(SearchAlgorithm, SinglePopulationAlgorithmMixin): """ CMAES: Covariance Matrix Adaptation Evolution Strategy. @@ -360,9 +367,11 @@ def __init__( # Note that we could use the exact formulation with Gamma functions, but we'll retain this form for consistency self.unbiased_expectation = np.sqrt(d) * (1 - (1 / (4 * d)) + 1 / (21 * d**2)) + self.last_ex = None + # How often to decompose C if limit_C_decomposition: - self.decompose_C_freq = max(1, int(1 / np.floor(10 * d * (self.c_1.cpu() + self.c_mu.cpu())))) + self.decompose_C_freq = max(1, int(np.floor(_safe_divide(1, 10 * d * (self.c_1.cpu() + self.c_mu.cpu()))))) else: self.decompose_C_freq = 1