Includes modified code from pymoo.
Sources: - dnsga2.py.
Licensed under the Apache License, Version 2.0. Original copyright and license terms are preserved.
The framework was adapted to enable efficient aggregation of change response strategies.
Classes
DNSGA2
DNSGA2(
perc_detect_change: float = 0.1,
eps: float = 0.0,
**kwargs,
)
Bases: NSGA2
Dynamic Non-dominated Sorting Genetic Algorithm II (DNSGA2).
Extension of NSGA2 for dynamic optimization problems.
Parameters:
| Name | Type | Description | Default |
perc_detect_change | float | Percentage of population to sample for change detection (0 to 1). | 0.1 |
eps | float | Threshold for change detection. Change is detected when mean squared difference exceeds this value. | 0.0 |
**kwargs | | Additional arguments passed to NSGA2 parent class. | {} |
Source code in pydmoo/algorithms/base/dmoo/dnsga2.py
| def __init__(self,
perc_detect_change: float = 0.1,
eps: float = 0.0,
**kwargs):
super().__init__(**kwargs)
self.perc_detect_change = perc_detect_change
self.eps = eps
|
Functions
_detect_change_sample_part_population
_detect_change_sample_part_population() -> bool
Detect environmental changes by sampling part of the population.
Returns:
| Name | Type | Description |
change_detected | bool | True if environmental change is detected, False otherwise. |
Source code in pydmoo/algorithms/base/dmoo/dnsga2.py
| def _detect_change_sample_part_population(self) -> bool:
"""
Detect environmental changes by sampling part of the population.
Returns
-------
change_detected : bool
True if environmental change is detected, False otherwise.
"""
pop = self.pop
X, F = pop.get("X", "F")
# the number of solutions to sample from the population to detect the change
n_samples = int(np.ceil(len(pop) * self.perc_detect_change))
# choose randomly some individuals of the current population to test if there was a change
I = self.random_state.choice(np.arange(len(pop)), size=n_samples)
samples = self.evaluator.eval(self.problem, Population.new(X=X[I]))
# calculate the differences between the old and newly evaluated pop
delta = ((samples.get("F") - F[I]) ** 2).mean()
# if there is an average deviation bigger than eps -> we have a change detected
change_detected = delta > self.eps
return change_detected
|
_infill_static_dynamic
_infill_static_dynamic() -> Population
Perform infill with dynamic change detection and response.
Returns:
| Type | Description |
Population | Current population after potential response to environmental change. |
Source code in pydmoo/algorithms/base/dmoo/dnsga2.py
| def _infill_static_dynamic(self) -> Population:
"""
Perform infill with dynamic change detection and response.
Returns
-------
Population
Current population after potential response to environmental change.
"""
# for dynamic environment
pop = self.pop
change_detected = self._detect_change_sample_part_population()
if change_detected:
start_time = time.time()
pop = self._response_mechanism()
# reevaluate because we know there was a change
self.evaluator.eval(self.problem, pop)
# do a survival to recreate rank and crowding of all individuals
# Modified by DynOpt on Dec 21, 2025
# n_survive=len(pop) -> n_survive=self.pop_size
pop = self.survival.do(self.problem, pop, n_survive=self.pop_size, random_state=self.random_state)
self.pop = pop
self.data["response_duration"] = time.time() - start_time
return pop
|
_response_mechanism
_response_mechanism() -> Population
Response mechanism for environmental change.
Returns:
| Type | Description |
Population | Population after applying response strategy. |
Raises:
| Type | Description |
NotImplementedError | Must be implemented by subclasses. |
Source code in pydmoo/algorithms/base/dmoo/dnsga2.py
| def _response_mechanism(self) -> Population:
"""
Response mechanism for environmental change.
Returns
-------
Population
Population after applying response strategy.
Raises
------
NotImplementedError
Must be implemented by subclasses.
"""
raise NotImplementedError
|
DNSGA2A
DNSGA2A(
perc_detect_change: float = 0.1,
eps: float = 0.0,
perc_diversity: float = 0.3,
**kwargs,
)
Bases: DNSGA2
DNSGA2A.
References
Deb, K., Rao N., U. B., and Karthik, S. (2007). Dynamic multi-objective optimization and decision-making using modified NSGA-II: A case study on hydro-thermal power scheduling. Evolutionary Multi-Criterion Optimization, 803–817. https://doi.org/10.1007/978-3-540-70928-2_60
Source code in pydmoo/algorithms/base/dmoo/dnsga2.py
| def __init__(self,
perc_detect_change: float = 0.1,
eps: float = 0.0,
perc_diversity: float = 0.3,
**kwargs):
super().__init__(perc_detect_change=perc_detect_change,
eps=eps,
**kwargs)
self.perc_diversity = perc_diversity
|
Functions
_response_mechanism
_response_mechanism() -> Population
Response mechanism.
Source code in pydmoo/algorithms/base/dmoo/dnsga2.py
| def _response_mechanism(self) -> Population:
"""Response mechanism."""
pop = self.pop
X = pop.get("X")
# recreate the current population without being evaluated
pop = Population.new(X=X)
# find indices to be replaced (introduce diversity)
I = np.where(self.random_state.random(len(pop)) < self.perc_diversity)[0]
# replace with randomly sampled individuals
pop[I] = self.initialization.sampling(self.problem, len(I), random_state=self.random_state)
return pop
|
DNSGA2B
DNSGA2B(
perc_detect_change: float = 0.1,
eps: float = 0.0,
perc_diversity: float = 0.3,
**kwargs,
)
Bases: DNSGA2
DNSGA2B.
References
Deb, K., Rao N., U. B., and Karthik, S. (2007). Dynamic multi-objective optimization and decision-making using modified NSGA-II: A case study on hydro-thermal power scheduling. Evolutionary Multi-Criterion Optimization, 803–817. https://doi.org/10.1007/978-3-540-70928-2_60
Source code in pydmoo/algorithms/base/dmoo/dnsga2.py
| def __init__(self,
perc_detect_change: float = 0.1,
eps: float = 0.0,
perc_diversity: float = 0.3,
**kwargs):
super().__init__(perc_detect_change=perc_detect_change,
eps=eps,
**kwargs)
self.perc_diversity = perc_diversity
|
Functions
_response_mechanism
_response_mechanism() -> Population
Response mechanism.
Source code in pydmoo/algorithms/base/dmoo/dnsga2.py
| def _response_mechanism(self) -> Population:
"""Response mechanism."""
pop = self.pop
X = pop.get("X")
# recreate the current population without being evaluated
pop = Population.new(X=X)
# find indices to be replaced (introduce diversity)
I = np.where(self.random_state.random(len(pop)) < self.perc_diversity)[0]
# replace by mutations of existing solutions (this occurs inplace)
self.mating.mutation(self.problem, pop[I])
return pop
|