diff --git a/src/gradient_free_optimizers/optimizers/local_opt/hill_climbing_optimizer.py b/src/gradient_free_optimizers/optimizers/local_opt/hill_climbing_optimizer.py index f1e1354d..879c3a3f 100644 --- a/src/gradient_free_optimizers/optimizers/local_opt/hill_climbing_optimizer.py +++ b/src/gradient_free_optimizers/optimizers/local_opt/hill_climbing_optimizer.py @@ -191,8 +191,8 @@ def _iterate_discrete_batch(self) -> ndarray: max_positions = bounds[:, 1] sigmas = max_positions * self.epsilon - # Prevent zero sigma for single-value dimensions - sigmas = maximum(sigmas, 1e-10) + # Prevent getting stuck: ensure noise standard deviation is at least 1.0 index + sigmas = maximum(sigmas, 1.0) # Generate noise using the configured distribution noise_fn = self._DISTRIBUTIONS[self.distribution] diff --git a/src/gradient_free_optimizers/optimizers/pop_opt/particle_swarm_optimization.py b/src/gradient_free_optimizers/optimizers/pop_opt/particle_swarm_optimization.py index a1b6c9a1..5eceb14b 100644 --- a/src/gradient_free_optimizers/optimizers/pop_opt/particle_swarm_optimization.py +++ b/src/gradient_free_optimizers/optimizers/pop_opt/particle_swarm_optimization.py @@ -219,19 +219,25 @@ def _compute_pso_position(self) -> ndarray: ): return self.p_current.init.move_random_typed() - r1, r2 = random.random(), random.random() - pos_current = array(self.p_current._pos_current) pos_best = array(self.p_current._pos_best) global_pos_best = array(self.p_current.global_pos_best) + # Per-dimension random coefficients (Kennedy & Eberhart, 1995). + # Using scalar r1/r2 couples all dimensions to the same random factor, + # creating correlated diagonal movement and preventing independent + # per-dimension exploration. Vectors ensure stochastic independence. + n_dims = len(pos_current) + r1 = array([random.random() for _ in range(n_dims)]) + r2 = array([random.random() for _ in range(n_dims)]) + # Inertia term: maintain current direction A = self.inertia * array(self.p_current.velo) - # Cognitive term: attract toward personal best + # Cognitive term: attract toward personal best (per-dimension) B = self.cognitive_weight * r1 * (pos_best - pos_current) - # Social term: attract toward global best + # Social term: attract toward global best (per-dimension) C = self.social_weight * r2 * (global_pos_best - pos_current) # Update velocity