Source code for cbx.dynamics.cbo_memory

import numpy as np
from typing import Union
#from scipy.special import logsumexp

from .cbo import CBO, cbo_update

#%% CBO_Memory
[docs] class CBOMemory(CBO): r"""Consensus-based optimization with memory effects (CBOMemory) class This class implements the CBO algorithm with memory effects as described in [1]_ and [2]_. The algorithm is a particle dynamic algorithm that is used to minimize the objective function :math:`f(x)`. Parameters ---------- f : objective The objective function :math:`f(x)` of the system. x : array_like, shape (N, d) The initial positions of the particles. For a system of :math:`N` particles, the i-th row of this array ``x[i,:]`` represents the position :math:`x_i` of the i-th particle. y : array_like, shape (N, d) The initial positions of the particles. For a system of :math:`N` particles, the i-th row of this array ``y[i,:]`` represents the or an approximation of the historical best position :math:`y_i` of the i-th particle. dt : float, optional The parameter :math:`dt` of the system. The default is 0.1. alpha : float, optional The heat parameter :math:`\alpha` of the system. The default is 1.0. lamda : float, optional The decay parameter :math:`\lambda` of the system. The default is 1.0. noise : noise_model, optional The noise model that is used to compute the noise vector. The default is ``normal_noise(dt=0.1)``. sigma : float, optional The parameter :math:`\sigma` of the noise model. The default is 1.0. lamda_memory : float, optional The decay parameter :math:`\lambda_{\text{memory}}` of the system. The default is 1.0. sigma_memory : float, optional The parameter :math:`\sigma_{\text{memory}}` of the noise model. The default is 1.0. References ---------- .. [1] Grassi, S. & Pareschi, L. (2021). From particle swarm optimization to consensus based optimization: stochastic modeling and mean-field limit. Math. Models Methods Appl. Sci., 31(8):1625–1657. .. [2] Riedl, K. (2023). Leveraging memory effects and gradient information in consensus-based optimization: On global convergence in mean-field law. Eur. J. Appl. Math., XX (X), XX-XX. """ def __init__(self, f, lamda_memory: float = 0.4, sigma_memory: Union[float, None] = None, **kwargs) -> None: super(CBOMemory, self).__init__(f, **kwargs) self.lamda_memory = lamda_memory # init historical best positions of particles self.y = self.copy(self.x) if sigma_memory is None: self.sigma_memory = self.lamda_memory * self.sigma else: self.sigma_memory = sigma_memory self.energy = self.f(self.x) self.num_f_eval += np.ones(self.M, dtype=int) * self.N # update number of function evaluations self.ergexp = tuple([Ellipsis] + [None for _ in range(self.x.ndim-2)])
[docs] def pre_step(self,): # save old positions self.x_old = self.copy(self.x) # save old positions self.y_old = self.copy(self.y) # save old positions # set new batch indices self.set_batch_idx()
def memory_step(self,): # add memory step, first define new drift self.drift = self.x[self.particle_idx] - self.y[self.particle_idx] self.x[self.particle_idx] += cbo_update( self.drift, self.lamda_memory, self.dt, self.sigma_memory, self.noise() )
[docs] def inner_step(self,) -> None: r"""Performs one step of the CBOMemory algorithm. Parameters ---------- None Returns ------- None """ # first perform regular cbo step self.cbo_step() self.memory_step() # evaluation of objective function on all particles energy_new = self.eval_f(self.x[self.particle_idx]) # historical best positions of particles self.y[self.particle_idx] += ( ((self.energy>energy_new)[self.ergexp]) * (self.x[self.particle_idx] - self.y[self.particle_idx]) ) self.energy = np.minimum(self.energy, energy_new)
[docs] def compute_consensus(self,) -> None: r"""Updates the weighted mean of the particles. Parameters ---------- None Returns ------- None """ self.consensus, _ = self._compute_consensus( self.energy, self.y[self.consensus_idx], self.alpha[self.active_runs_idx, :] )
[docs] def update_best_cur_particle(self,) -> None: self.f_min = self.energy.min(axis=-1) self.f_min_idx = self.energy.argmin(axis=-1) self.best_cur_particle = self.x[np.arange(self.M), self.f_min_idx, :] self.best_cur_energy = self.energy[np.arange(self.M), self.f_min_idx]