pydmoo 0.1.1__tar.gz → 0.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pydmoo-0.1.1 → pydmoo-0.1.3}/PKG-INFO +1 -1
- pydmoo-0.1.3/docs/user-guide/algorithms/algorithms.base.dmoo.dmoead.md +13 -0
- pydmoo-0.1.3/docs/user-guide/algorithms/algorithms.base.dmoo.dmoeadde.md +13 -0
- pydmoo-0.1.3/docs/user-guide/algorithms/algorithms.base.dmoo.dnsga2.md +13 -0
- pydmoo-0.1.3/docs/user-guide/algorithms/algorithms.classic.moeadde_svr.md +9 -0
- pydmoo-0.1.3/docs/user-guide/algorithms/algorithms.learning.nsga2_tr.md +9 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/user-guide/algorithms.md +8 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/base/core/genetic.py +2 -2
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/base/dmoo/dmoead.py +55 -8
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/base/dmoo/dmoeadde.py +55 -7
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/base/dmoo/dnsga2.py +81 -15
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/base/moo/moead.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/base/moo/moeadde.py +12 -7
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/classic/moead_ae.py +2 -2
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/classic/moead_pps.py +2 -2
- pydmoo-0.1.3/pydmoo/algorithms/classic/moead_svr.py +86 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/classic/moeadde_ae.py +2 -2
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/classic/moeadde_pps.py +2 -2
- pydmoo-0.1.3/pydmoo/algorithms/classic/moeadde_svr.py +86 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/classic/nsga2_ae.py +2 -2
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/classic/nsga2_pps.py +2 -2
- pydmoo-0.1.3/pydmoo/algorithms/learning/moead_tr.py +98 -0
- pydmoo-0.1.3/pydmoo/algorithms/learning/moeadde_tr.py +98 -0
- pydmoo-0.1.3/pydmoo/algorithms/learning/nsga2_tr.py +98 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/moead_imkt.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/moead_imkt_igp.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/moead_imkt_lstm.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/moead_imkt_n.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/moead_imkt_n_igp.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/moead_imkt_n_lstm.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/moead_ktmm.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/moeadde_imkt.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/moeadde_imkt_clstm.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/moeadde_imkt_igp.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/moeadde_imkt_lstm.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/moeadde_imkt_n.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/moeadde_imkt_n_clstm.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/moeadde_imkt_n_igp.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/moeadde_imkt_n_lstm.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/moeadde_ktmm.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/nsga2_imkt.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/nsga2_imkt_clstm.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/nsga2_imkt_igp.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/nsga2_imkt_lstm.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/nsga2_imkt_n.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/nsga2_imkt_n_clstm.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/nsga2_imkt_n_igp.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/nsga2_imkt_n_lstm.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/nsga2_ktmm.py +2 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/problems/dyn.py +28 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pyproject.toml +1 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/uv.lock +1 -1
- {pydmoo-0.1.1 → pydmoo-0.1.3}/.gitattributes +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/.github/workflows/docs.yml +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/.github/workflows/publish.yml +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/.github/workflows/release.yml +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/.gitignore +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/.python-version +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/CODE_OF_CONDUCT.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/LICENSE +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/README.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/dev-guide/bug-report.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/dev-guide/index.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/dev-guide/pull-request.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PF/GTS1.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PF/GTS10.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PF/GTS11.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PF/GTS2.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PF/GTS3.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PF/GTS4.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PF/GTS5.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PF/GTS6.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PF/GTS7.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PF/GTS8.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PF/GTS9.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PS/GTS1.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PS/GTS10.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PS/GTS11.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PS/GTS2.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PS/GTS3.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PS/GTS4.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PS/GTS5.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PS/GTS6.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PS/GTS7.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PS/GTS8.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/figs/PS/GTS9.png +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/getting-started.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/index.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/reference/algorithms/diversity-based.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/reference/algorithms/index.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/reference/algorithms/knowledge-based.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/reference/algorithms/memory-based.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/reference/algorithms/multi-population-based.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/reference/algorithms/prediction-based.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/reference/applications/index.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/reference/index.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/reference/metrics/index.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/reference/problems/benchmarks.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/reference/problems/index.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/requirements.txt +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/user-guide/algorithms/algorithms.classic.nsga2_ae.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/user-guide/algorithms/algorithms.classic.nsga2_pps.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/user-guide/algorithms/algorithms.modern.nsga2_imkt.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/user-guide/algorithms/algorithms.modern.nsga2_imkt_clstm.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/user-guide/algorithms/algorithms.modern.nsga2_imkt_lstm.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/user-guide/index.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/user-guide/problems/problems.dyn.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/user-guide/problems/problems.dynamic.gts.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/docs/user-guide/problems.md +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/mkdocs.yml +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/__init__.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/__init__.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/base/__init__.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/base/core/__init__.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/base/core/algorithm.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/base/dmoo/__init__.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/base/dmoo/dmopso.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/base/moo/__init__.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/base/moo/mopso.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/base/moo/nsga2.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/classic/__init__.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/modern/__init__.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/utils/__init__.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/algorithms/utils/utils.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/core/__init__.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/core/ar_model.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/core/bounds.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/core/distance.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/core/inverse.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/core/lstm/__init__.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/core/lstm/base.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/core/lstm/lstm.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/core/manifold.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/core/predictions.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/core/sample_gaussian.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/core/sample_uniform.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/core/transfer.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/problems/__init__.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/problems/dynamic/__init__.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/problems/dynamic/cec2015.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/problems/dynamic/df.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/problems/dynamic/gts.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/problems/real_world/__init__.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/problems/real_world/dsrp.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo/problems/real_world/dwbdp.py +0 -0
- {pydmoo-0.1.1 → pydmoo-0.1.3}/pydmoo.sublime-project +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydmoo
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Dynamic Multi-Objective Optimization in Python (pydmoo).
|
|
5
5
|
Project-URL: Homepage, https://github.com/dynoptimization/pydmoo
|
|
6
6
|
Project-URL: Repository, https://github.com/dynoptimization/pydmoo
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# algorithms.base.dmoo.dmoeadde
|
|
2
|
+
|
|
3
|
+
::: pydmoo.algorithms.base.dmoo.dmoeadde
|
|
4
|
+
options:
|
|
5
|
+
show_root_heading: false
|
|
6
|
+
members:
|
|
7
|
+
- DMOEADDE
|
|
8
|
+
- DMOEADDEA
|
|
9
|
+
- DMOEADDEB
|
|
10
|
+
show_submodules: true
|
|
11
|
+
heading_level: 2
|
|
12
|
+
show_source: true
|
|
13
|
+
show_category_heading: true
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
# Algorithms
|
|
2
2
|
|
|
3
|
+
## Base Response Mechanisms
|
|
4
|
+
|
|
5
|
+
- [algorithms.base.dmoo.dnsga2](algorithms/algorithms.base.dmoo.dnsga2.md)
|
|
6
|
+
- [algorithms.base.dmoo.dmoead](algorithms/algorithms.base.dmoo.dmoead.md)
|
|
7
|
+
- [algorithms.base.dmoo.dmoeadde](algorithms/algorithms.base.dmoo.dmoeadde.md)
|
|
8
|
+
|
|
3
9
|
## Classic Response Mechanisms
|
|
4
10
|
|
|
5
11
|
- [algorithms.classic.nsga2_ae](algorithms/algorithms.classic.nsga2_ae.md)
|
|
6
12
|
- [algorithms.classic.nsga2_pps](algorithms/algorithms.classic.nsga2_pps.md)
|
|
13
|
+
- [algorithms.classic.moeadde_svr](algorithms/algorithms.classic.moeadde_svr.md)
|
|
7
14
|
|
|
8
15
|
## Knowledge-Based Response Mechanisms
|
|
9
16
|
|
|
@@ -11,5 +18,6 @@
|
|
|
11
18
|
|
|
12
19
|
## Learning-Based Response Mechanisms
|
|
13
20
|
|
|
21
|
+
- [algorithms.learning.nsga2_tr](algorithms/algorithms.learning.nsga2_tr.md)
|
|
14
22
|
- [algorithms.modern.nsga2_imkt_lstm](algorithms/algorithms.modern.nsga2_imkt_lstm.md)
|
|
15
23
|
- [algorithms.modern.nsga2_imkt_clstm](algorithms/algorithms.modern.nsga2_imkt_clstm.md)
|
|
@@ -92,7 +92,7 @@ class GeneticAlgorithm(Algorithm):
|
|
|
92
92
|
random_state=self.random_state, algorithm=self, **kwargs)
|
|
93
93
|
|
|
94
94
|
def _infill(self):
|
|
95
|
-
# Added by DynOpt on Dec 21, 2025
|
|
95
|
+
# Added by DynOpt Team on Dec 21, 2025
|
|
96
96
|
pop = self._infill_static_dynamic()
|
|
97
97
|
|
|
98
98
|
# do the mating using the current population
|
|
@@ -110,7 +110,7 @@ class GeneticAlgorithm(Algorithm):
|
|
|
110
110
|
|
|
111
111
|
return off
|
|
112
112
|
|
|
113
|
-
# Added by DynOpt on Dec 21, 2025
|
|
113
|
+
# Added by DynOpt Team on Dec 21, 2025
|
|
114
114
|
def _infill_static_dynamic(self):
|
|
115
115
|
pop = self.pop
|
|
116
116
|
|
|
@@ -8,7 +8,21 @@ from pydmoo.algorithms.base.moo.moead import MOEAD
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class DMOEAD(MOEAD):
|
|
11
|
-
|
|
11
|
+
"""
|
|
12
|
+
Dynamic MOEA/D (DMOEAD).
|
|
13
|
+
|
|
14
|
+
Extension of MOEAD for dynamic optimization problems.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
perc_detect_change : float, default=0.1
|
|
19
|
+
Percentage of population to sample for change detection (0 to 1).
|
|
20
|
+
eps : float, default=0.0
|
|
21
|
+
Threshold for change detection. Change is detected when mean squared
|
|
22
|
+
difference exceeds this value.
|
|
23
|
+
**kwargs
|
|
24
|
+
Additional arguments passed to MOEAD parent class.
|
|
25
|
+
"""
|
|
12
26
|
def __init__(self,
|
|
13
27
|
perc_detect_change=0.1,
|
|
14
28
|
eps=0.0,
|
|
@@ -22,7 +36,15 @@ class DMOEAD(MOEAD):
|
|
|
22
36
|
assert not problem.has_constraints(), f"{self.__class__.__name__} only works for unconstrained problems."
|
|
23
37
|
return super().setup(problem, **kwargs)
|
|
24
38
|
|
|
25
|
-
def _detect_change_sample_part_population(self):
|
|
39
|
+
def _detect_change_sample_part_population(self) -> bool:
|
|
40
|
+
"""
|
|
41
|
+
Detect environmental changes by sampling part of the population.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
change_detected : bool
|
|
46
|
+
True if environmental change is detected, False otherwise.
|
|
47
|
+
"""
|
|
26
48
|
pop = self.pop
|
|
27
49
|
X, F = pop.get("X", "F")
|
|
28
50
|
|
|
@@ -40,7 +62,15 @@ class DMOEAD(MOEAD):
|
|
|
40
62
|
change_detected = delta > self.eps
|
|
41
63
|
return change_detected
|
|
42
64
|
|
|
43
|
-
def _next_static_dynamic(self):
|
|
65
|
+
def _next_static_dynamic(self) -> Population:
|
|
66
|
+
"""
|
|
67
|
+
Perform next with dynamic change detection and response.
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
Population
|
|
72
|
+
Current population after potential response to environmental change.
|
|
73
|
+
"""
|
|
44
74
|
# for dynamic environment
|
|
45
75
|
pop = self.pop
|
|
46
76
|
|
|
@@ -52,7 +82,7 @@ class DMOEAD(MOEAD):
|
|
|
52
82
|
|
|
53
83
|
start_time = time.time()
|
|
54
84
|
|
|
55
|
-
pop = self.
|
|
85
|
+
pop = self._response_mechanism()
|
|
56
86
|
|
|
57
87
|
# reevaluate because we know there was a change
|
|
58
88
|
self.evaluator.eval(self.problem, pop)
|
|
@@ -69,11 +99,25 @@ class DMOEAD(MOEAD):
|
|
|
69
99
|
|
|
70
100
|
return pop
|
|
71
101
|
|
|
72
|
-
def
|
|
73
|
-
|
|
102
|
+
def _response_mechanism(self):
|
|
103
|
+
"""
|
|
104
|
+
Response mechanism for environmental change.
|
|
105
|
+
|
|
106
|
+
Returns
|
|
107
|
+
-------
|
|
108
|
+
Population
|
|
109
|
+
Population after applying response strategy.
|
|
110
|
+
|
|
111
|
+
Raises
|
|
112
|
+
------
|
|
113
|
+
NotImplementedError
|
|
114
|
+
Must be implemented by subclasses.
|
|
115
|
+
"""
|
|
116
|
+
raise NotImplementedError
|
|
74
117
|
|
|
75
118
|
|
|
76
119
|
class DMOEADA(DMOEAD):
|
|
120
|
+
"""DMOEADA."""
|
|
77
121
|
|
|
78
122
|
def __init__(self,
|
|
79
123
|
perc_detect_change=0.1,
|
|
@@ -86,7 +130,8 @@ class DMOEADA(DMOEAD):
|
|
|
86
130
|
|
|
87
131
|
self.perc_diversity = perc_diversity
|
|
88
132
|
|
|
89
|
-
def
|
|
133
|
+
def _response_mechanism(self):
|
|
134
|
+
"""Response mechanism."""
|
|
90
135
|
pop = self.pop
|
|
91
136
|
X = pop.get("X")
|
|
92
137
|
|
|
@@ -103,6 +148,7 @@ class DMOEADA(DMOEAD):
|
|
|
103
148
|
|
|
104
149
|
|
|
105
150
|
class DMOEADB(DMOEAD):
|
|
151
|
+
"""DMOEADB."""
|
|
106
152
|
|
|
107
153
|
def __init__(self,
|
|
108
154
|
perc_detect_change=0.1,
|
|
@@ -115,7 +161,8 @@ class DMOEADB(DMOEAD):
|
|
|
115
161
|
|
|
116
162
|
self.perc_diversity = perc_diversity
|
|
117
163
|
|
|
118
|
-
def
|
|
164
|
+
def _response_mechanism(self):
|
|
165
|
+
"""Response mechanism."""
|
|
119
166
|
pop = self.pop
|
|
120
167
|
X = pop.get("X")
|
|
121
168
|
|
|
@@ -8,6 +8,21 @@ from pydmoo.algorithms.base.moo.moeadde import MOEADDE
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class DMOEADDE(MOEADDE):
|
|
11
|
+
"""
|
|
12
|
+
Dynamic MOEA/D-DE (DMOEADDE).
|
|
13
|
+
|
|
14
|
+
Extension of MOEADDE for dynamic optimization problems.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
perc_detect_change : float, default=0.1
|
|
19
|
+
Percentage of population to sample for change detection (0 to 1).
|
|
20
|
+
eps : float, default=0.0
|
|
21
|
+
Threshold for change detection. Change is detected when mean squared
|
|
22
|
+
difference exceeds this value.
|
|
23
|
+
**kwargs
|
|
24
|
+
Additional arguments passed to MOEADDE parent class.
|
|
25
|
+
"""
|
|
11
26
|
|
|
12
27
|
def __init__(self,
|
|
13
28
|
perc_detect_change=0.1,
|
|
@@ -22,7 +37,15 @@ class DMOEADDE(MOEADDE):
|
|
|
22
37
|
assert not problem.has_constraints(), f"{self.__class__.__name__} only works for unconstrained problems."
|
|
23
38
|
return super().setup(problem, **kwargs)
|
|
24
39
|
|
|
25
|
-
def _detect_change_sample_part_population(self):
|
|
40
|
+
def _detect_change_sample_part_population(self) -> bool:
|
|
41
|
+
"""
|
|
42
|
+
Detect environmental changes by sampling part of the population.
|
|
43
|
+
|
|
44
|
+
Returns
|
|
45
|
+
-------
|
|
46
|
+
change_detected : bool
|
|
47
|
+
True if environmental change is detected, False otherwise.
|
|
48
|
+
"""
|
|
26
49
|
pop = self.pop
|
|
27
50
|
X, F = pop.get("X", "F")
|
|
28
51
|
|
|
@@ -40,7 +63,15 @@ class DMOEADDE(MOEADDE):
|
|
|
40
63
|
change_detected = delta > self.eps
|
|
41
64
|
return change_detected
|
|
42
65
|
|
|
43
|
-
def _next_static_dynamic(self):
|
|
66
|
+
def _next_static_dynamic(self) -> Population:
|
|
67
|
+
"""
|
|
68
|
+
Perform next with dynamic change detection and response.
|
|
69
|
+
|
|
70
|
+
Returns
|
|
71
|
+
-------
|
|
72
|
+
Population
|
|
73
|
+
Current population after potential response to environmental change.
|
|
74
|
+
"""
|
|
44
75
|
# for dynamic environment
|
|
45
76
|
pop = self.pop
|
|
46
77
|
|
|
@@ -52,7 +83,7 @@ class DMOEADDE(MOEADDE):
|
|
|
52
83
|
|
|
53
84
|
start_time = time.time()
|
|
54
85
|
|
|
55
|
-
pop = self.
|
|
86
|
+
pop = self._response_mechanism()
|
|
56
87
|
|
|
57
88
|
# reevaluate because we know there was a change
|
|
58
89
|
self.evaluator.eval(self.problem, pop)
|
|
@@ -69,11 +100,25 @@ class DMOEADDE(MOEADDE):
|
|
|
69
100
|
|
|
70
101
|
return pop
|
|
71
102
|
|
|
72
|
-
def
|
|
73
|
-
|
|
103
|
+
def _response_mechanism(self) -> Population:
|
|
104
|
+
"""
|
|
105
|
+
Response mechanism for environmental change.
|
|
106
|
+
|
|
107
|
+
Returns
|
|
108
|
+
-------
|
|
109
|
+
Population
|
|
110
|
+
Population after applying response strategy.
|
|
111
|
+
|
|
112
|
+
Raises
|
|
113
|
+
------
|
|
114
|
+
NotImplementedError
|
|
115
|
+
Must be implemented by subclasses.
|
|
116
|
+
"""
|
|
117
|
+
raise NotImplementedError
|
|
74
118
|
|
|
75
119
|
|
|
76
120
|
class DMOEADDEA(DMOEADDE):
|
|
121
|
+
"""DMOEADDEA."""
|
|
77
122
|
|
|
78
123
|
def __init__(self,
|
|
79
124
|
perc_detect_change=0.1,
|
|
@@ -86,7 +131,8 @@ class DMOEADDEA(DMOEADDE):
|
|
|
86
131
|
|
|
87
132
|
self.perc_diversity = perc_diversity
|
|
88
133
|
|
|
89
|
-
def
|
|
134
|
+
def _response_mechanism(self):
|
|
135
|
+
"""Response mechanism."""
|
|
90
136
|
pop = self.pop
|
|
91
137
|
X = pop.get("X")
|
|
92
138
|
|
|
@@ -103,6 +149,7 @@ class DMOEADDEA(DMOEADDE):
|
|
|
103
149
|
|
|
104
150
|
|
|
105
151
|
class DMOEADDEB(DMOEADDE):
|
|
152
|
+
"""DMOEADDEB."""
|
|
106
153
|
|
|
107
154
|
def __init__(self,
|
|
108
155
|
perc_detect_change=0.1,
|
|
@@ -115,7 +162,8 @@ class DMOEADDEB(DMOEADDE):
|
|
|
115
162
|
|
|
116
163
|
self.perc_diversity = perc_diversity
|
|
117
164
|
|
|
118
|
-
def
|
|
165
|
+
def _response_mechanism(self):
|
|
166
|
+
"""Response mechanism."""
|
|
119
167
|
pop = self.pop
|
|
120
168
|
X = pop.get("X")
|
|
121
169
|
|
|
@@ -17,10 +17,25 @@ from pydmoo.algorithms.base.moo.nsga2 import NSGA2
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class DNSGA2(NSGA2):
|
|
20
|
+
"""
|
|
21
|
+
Dynamic Non-dominated Sorting Genetic Algorithm II (DNSGA2).
|
|
22
|
+
|
|
23
|
+
Extension of NSGA2 for dynamic optimization problems.
|
|
24
|
+
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
perc_detect_change : float, default=0.1
|
|
28
|
+
Percentage of population to sample for change detection (0 to 1).
|
|
29
|
+
eps : float, default=0.0
|
|
30
|
+
Threshold for change detection. Change is detected when mean squared
|
|
31
|
+
difference exceeds this value.
|
|
32
|
+
**kwargs
|
|
33
|
+
Additional arguments passed to NSGA2 parent class.
|
|
34
|
+
"""
|
|
20
35
|
|
|
21
36
|
def __init__(self,
|
|
22
|
-
perc_detect_change=0.1,
|
|
23
|
-
eps=0.0,
|
|
37
|
+
perc_detect_change: float = 0.1,
|
|
38
|
+
eps: float = 0.0,
|
|
24
39
|
**kwargs):
|
|
25
40
|
|
|
26
41
|
super().__init__(**kwargs)
|
|
@@ -31,7 +46,15 @@ class DNSGA2(NSGA2):
|
|
|
31
46
|
assert not problem.has_constraints(), f"{self.__class__.__name__} only works for unconstrained problems."
|
|
32
47
|
return super().setup(problem, **kwargs)
|
|
33
48
|
|
|
34
|
-
def _detect_change_sample_part_population(self):
|
|
49
|
+
def _detect_change_sample_part_population(self) -> bool:
|
|
50
|
+
"""
|
|
51
|
+
Detect environmental changes by sampling part of the population.
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
change_detected : bool
|
|
56
|
+
True if environmental change is detected, False otherwise.
|
|
57
|
+
"""
|
|
35
58
|
pop = self.pop
|
|
36
59
|
X, F = pop.get("X", "F")
|
|
37
60
|
|
|
@@ -49,7 +72,15 @@ class DNSGA2(NSGA2):
|
|
|
49
72
|
change_detected = delta > self.eps
|
|
50
73
|
return change_detected
|
|
51
74
|
|
|
52
|
-
def _infill_static_dynamic(self):
|
|
75
|
+
def _infill_static_dynamic(self) -> Population:
|
|
76
|
+
"""
|
|
77
|
+
Perform infill with dynamic change detection and response.
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
Population
|
|
82
|
+
Current population after potential response to environmental change.
|
|
83
|
+
"""
|
|
53
84
|
# for dynamic environment
|
|
54
85
|
pop = self.pop
|
|
55
86
|
|
|
@@ -59,7 +90,7 @@ class DNSGA2(NSGA2):
|
|
|
59
90
|
|
|
60
91
|
start_time = time.time()
|
|
61
92
|
|
|
62
|
-
pop = self.
|
|
93
|
+
pop = self._response_mechanism()
|
|
63
94
|
|
|
64
95
|
# reevaluate because we know there was a change
|
|
65
96
|
self.evaluator.eval(self.problem, pop)
|
|
@@ -75,16 +106,39 @@ class DNSGA2(NSGA2):
|
|
|
75
106
|
|
|
76
107
|
return pop
|
|
77
108
|
|
|
78
|
-
def
|
|
79
|
-
|
|
109
|
+
def _response_mechanism(self) -> Population:
|
|
110
|
+
"""
|
|
111
|
+
Response mechanism for environmental change.
|
|
112
|
+
|
|
113
|
+
Returns
|
|
114
|
+
-------
|
|
115
|
+
Population
|
|
116
|
+
Population after applying response strategy.
|
|
117
|
+
|
|
118
|
+
Raises
|
|
119
|
+
------
|
|
120
|
+
NotImplementedError
|
|
121
|
+
Must be implemented by subclasses.
|
|
122
|
+
"""
|
|
123
|
+
raise NotImplementedError
|
|
80
124
|
|
|
81
125
|
|
|
82
126
|
class DNSGA2A(DNSGA2):
|
|
127
|
+
"""DNSGA2A.
|
|
128
|
+
|
|
129
|
+
References
|
|
130
|
+
----------
|
|
131
|
+
Deb, K., Rao N., U. B., and Karthik, S. (2007).
|
|
132
|
+
Dynamic multi-objective optimization and decision-making using modified NSGA-II:
|
|
133
|
+
A case study on hydro-thermal power scheduling.
|
|
134
|
+
Evolutionary Multi-Criterion Optimization, 803–817.
|
|
135
|
+
https://doi.org/10.1007/978-3-540-70928-2_60
|
|
136
|
+
"""
|
|
83
137
|
|
|
84
138
|
def __init__(self,
|
|
85
|
-
perc_detect_change=0.1,
|
|
86
|
-
eps=0.0,
|
|
87
|
-
perc_diversity=0.3,
|
|
139
|
+
perc_detect_change: float = 0.1,
|
|
140
|
+
eps: float = 0.0,
|
|
141
|
+
perc_diversity: float = 0.3,
|
|
88
142
|
**kwargs):
|
|
89
143
|
super().__init__(perc_detect_change=perc_detect_change,
|
|
90
144
|
eps=eps,
|
|
@@ -92,7 +146,8 @@ class DNSGA2A(DNSGA2):
|
|
|
92
146
|
|
|
93
147
|
self.perc_diversity = perc_diversity
|
|
94
148
|
|
|
95
|
-
def
|
|
149
|
+
def _response_mechanism(self) -> Population:
|
|
150
|
+
"""Response mechanism."""
|
|
96
151
|
pop = self.pop
|
|
97
152
|
X = pop.get("X")
|
|
98
153
|
|
|
@@ -109,11 +164,21 @@ class DNSGA2A(DNSGA2):
|
|
|
109
164
|
|
|
110
165
|
|
|
111
166
|
class DNSGA2B(DNSGA2):
|
|
167
|
+
"""DNSGA2B.
|
|
168
|
+
|
|
169
|
+
References
|
|
170
|
+
----------
|
|
171
|
+
Deb, K., Rao N., U. B., and Karthik, S. (2007).
|
|
172
|
+
Dynamic multi-objective optimization and decision-making using modified NSGA-II:
|
|
173
|
+
A case study on hydro-thermal power scheduling.
|
|
174
|
+
Evolutionary Multi-Criterion Optimization, 803–817.
|
|
175
|
+
https://doi.org/10.1007/978-3-540-70928-2_60
|
|
176
|
+
"""
|
|
112
177
|
|
|
113
178
|
def __init__(self,
|
|
114
|
-
perc_detect_change=0.1,
|
|
115
|
-
eps=0.0,
|
|
116
|
-
perc_diversity=0.3,
|
|
179
|
+
perc_detect_change: float = 0.1,
|
|
180
|
+
eps: float = 0.0,
|
|
181
|
+
perc_diversity: float = 0.3,
|
|
117
182
|
**kwargs):
|
|
118
183
|
super().__init__(perc_detect_change=perc_detect_change,
|
|
119
184
|
eps=eps,
|
|
@@ -121,7 +186,8 @@ class DNSGA2B(DNSGA2):
|
|
|
121
186
|
|
|
122
187
|
self.perc_diversity = perc_diversity
|
|
123
188
|
|
|
124
|
-
def
|
|
189
|
+
def _response_mechanism(self) -> Population:
|
|
190
|
+
"""Response mechanism."""
|
|
125
191
|
pop = self.pop
|
|
126
192
|
X = pop.get("X")
|
|
127
193
|
|
|
@@ -105,6 +105,7 @@ class MOEAD(LoopwiseAlgorithm, GeneticAlgorithm):
|
|
|
105
105
|
self.ideal = np.min(self.pop.get("F"), axis=0)
|
|
106
106
|
|
|
107
107
|
def _next(self):
|
|
108
|
+
# Added by DynOpt Team on Dec 21, 2025
|
|
108
109
|
pop = self._next_static_dynamic()
|
|
109
110
|
|
|
110
111
|
# iterate for each member of the population in random order
|
|
@@ -124,7 +125,7 @@ class MOEAD(LoopwiseAlgorithm, GeneticAlgorithm):
|
|
|
124
125
|
# now actually do the replacement of the individual is better
|
|
125
126
|
self._replace(k, off)
|
|
126
127
|
|
|
127
|
-
# Added by DynOpt on Dec 21, 2025
|
|
128
|
+
# Added by DynOpt Team on Dec 21, 2025
|
|
128
129
|
def _next_static_dynamic(self):
|
|
129
130
|
pop = self.pop
|
|
130
131
|
|
|
@@ -7,13 +7,18 @@ from pydmoo.algorithms.base.moo.moead import MOEAD
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class MOEADDE(MOEAD):
|
|
10
|
-
"""MOEA/D-DE
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
"""MOEA/D-DE.
|
|
11
|
+
|
|
12
|
+
Notes
|
|
13
|
+
-----
|
|
14
|
+
It is worth noting that there is a distinct modification in line 28 compared with the original framework of
|
|
15
|
+
MOEA/D-DE. The newly generated solution competes with each member from the corresponding mating neighborhood
|
|
16
|
+
(denoted as Pool in Algorithm 2). But in the original MOEA/D-DE framework, it only competes with two members from
|
|
17
|
+
the corresponding mating neighborhood. This modification expands the replacement neighborhood to enhance the
|
|
18
|
+
exploitation capability that is extremely important in dealing with DMOPs (Cao et al., 2020).
|
|
19
|
+
|
|
20
|
+
References
|
|
21
|
+
----------
|
|
17
22
|
Cao, L., Xu, L., Goodman, E. D., Bao, C., and Zhu, S. (2020).
|
|
18
23
|
Evolutionary dynamic multiobjective optimization assisted by a support vector regression predictor.
|
|
19
24
|
IEEE Transactions on Evolutionary Computation, 24(2), 305–319.
|
|
@@ -25,8 +25,8 @@ class MOEADPPS(DMOEAD):
|
|
|
25
25
|
self.p = 3 # the order of the AR model
|
|
26
26
|
self.M = 23 # the length of history mean point series
|
|
27
27
|
|
|
28
|
-
def
|
|
29
|
-
"""Response."""
|
|
28
|
+
def _response_mechanism(self):
|
|
29
|
+
"""Response mechanism."""
|
|
30
30
|
pop = self.pop
|
|
31
31
|
X = pop.get("X")
|
|
32
32
|
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from pymoo.core.population import Population
|
|
3
|
+
from sklearn.svm import SVR
|
|
4
|
+
|
|
5
|
+
from pydmoo.algorithms.base.dmoo.dmoead import DMOEAD
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MOEADSVR(DMOEAD):
|
|
9
|
+
"""Support Vector Regression (SVR).
|
|
10
|
+
|
|
11
|
+
Notes
|
|
12
|
+
-----
|
|
13
|
+
[Official Python Code](https://github.com/LeileiCao/MOEA-D-SVR/blob/master/MOEAD-SVR%20.py)
|
|
14
|
+
|
|
15
|
+
References
|
|
16
|
+
----------
|
|
17
|
+
Cao, L., Xu, L., Goodman, E. D., Bao, C., and Zhu, S. (2020).
|
|
18
|
+
Evolutionary dynamic multiobjective optimization assisted by a support vector regression predictor.
|
|
19
|
+
IEEE Transactions on Evolutionary Computation, 24(2), 305–319.
|
|
20
|
+
https://doi.org/10.1109/TEVC.2019.2925722
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, **kwargs):
|
|
24
|
+
super().__init__(**kwargs)
|
|
25
|
+
|
|
26
|
+
# SVR
|
|
27
|
+
self._q = 4 # the number of preceding values that are correlated with the target value (dimension of input samples in the SVR model)
|
|
28
|
+
self._C = 1000 # the regularization constant in SVR model
|
|
29
|
+
self._epsilon = 0.05 # the insensitive tube size in SVR model
|
|
30
|
+
# self._gamma = 1/d # the Gaussian RBF kernel parameter used in SVR model, and d is the number of variables
|
|
31
|
+
|
|
32
|
+
def _response_mechanism(self):
|
|
33
|
+
"""Response mechanism."""
|
|
34
|
+
pop = self.pop
|
|
35
|
+
X = pop.get("X")
|
|
36
|
+
|
|
37
|
+
old = self.data.get("stacked_X", None)
|
|
38
|
+
if old is None:
|
|
39
|
+
stacked_X = np.expand_dims(X, axis=0)
|
|
40
|
+
else:
|
|
41
|
+
stacked_X = np.concatenate((old, np.expand_dims(X, axis=0)), axis=0)
|
|
42
|
+
self.data["stacked_X"] = stacked_X
|
|
43
|
+
|
|
44
|
+
N, d = X.shape
|
|
45
|
+
sol = np.zeros((N, d))
|
|
46
|
+
K = len(stacked_X)
|
|
47
|
+
|
|
48
|
+
if K < self._q + 2:
|
|
49
|
+
# recreate the current population without being evaluated
|
|
50
|
+
# Re-evaluate the current population, and update the reference point
|
|
51
|
+
pop = Population.new(X=X)
|
|
52
|
+
|
|
53
|
+
return pop
|
|
54
|
+
|
|
55
|
+
# Precompute sliding window indices to avoid redundant calculations
|
|
56
|
+
window_indices = np.lib.stride_tricks.sliding_window_view(np.arange(K), self._q + 1)
|
|
57
|
+
|
|
58
|
+
for i in range(N):
|
|
59
|
+
for j in range(d):
|
|
60
|
+
# Extract the time series for this (i,j) position
|
|
61
|
+
ts = stacked_X[:K, i, j]
|
|
62
|
+
|
|
63
|
+
# Create training data using vectorized sliding windows
|
|
64
|
+
train = ts[window_indices]
|
|
65
|
+
x_train = train[:, :-1]
|
|
66
|
+
y_train = train[:, -1]
|
|
67
|
+
|
|
68
|
+
# Train SVR model (consider moving this outside loops if possible)
|
|
69
|
+
# gamma if 'auto', uses 1 / n_features (not provided in code but provided in paper)
|
|
70
|
+
# versionchanged:: 0.22
|
|
71
|
+
# The default value of ``gamma`` changed from 'auto' to 'scale'.
|
|
72
|
+
svr = SVR(kernel='rbf', epsilon=self._epsilon, C=self._C, gamma=1/d)
|
|
73
|
+
model = svr.fit(x_train, y_train)
|
|
74
|
+
|
|
75
|
+
# Make prediction
|
|
76
|
+
sol[i, j] = model.predict(ts[-self._q:].reshape(1, -1))
|
|
77
|
+
|
|
78
|
+
# bounds
|
|
79
|
+
if self.problem.has_bounds():
|
|
80
|
+
xl, xu = self.problem.bounds()
|
|
81
|
+
sol = np.clip(sol, xl, xu) # provided in the original reference literature
|
|
82
|
+
|
|
83
|
+
# recreate the current population without being evaluated
|
|
84
|
+
pop = Population.new(X=sol)
|
|
85
|
+
|
|
86
|
+
return pop
|