Skip to content

Commit ec251b6

Browse files
committed
add history
1 parent 3823315 commit ec251b6

File tree

12 files changed

+78
-159
lines changed

12 files changed

+78
-159
lines changed

.vim/coc-settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"python.linting.pylintEnabled": true,
33
"python.linting.enabled": true,
4-
"python.formatting.provider": "autopep8"
4+
// "python.formatting.provider": "autopep8"
55
}

examples/knapsack/knapsack.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ def fitness(indv):
6969

7070

7171
# engine.create_seed(seed)
72-
engine.run()
72+
history = engine.run()
73+
print(history.history)
7374
ans = engine.get_best_indv()
7475
print(ans)
7576
# print(engine.population)

examples/zdt1/nsgaii.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ def eval_h(f: float, g: float) -> float:
5858
h = eval_h(solution[0], g)
5959
return h * g
6060

61-
engine.run()
61+
history = engine.run()
62+
print(history)
6263

6364
pareto_front = engine.get_pareto_front()
6465

geneticpython/callbacks/callback_list.py

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,37 +11,28 @@
1111
from typing import List
1212

1313
from .callback import Callback
14-
from .history import History, SingleObjectiveHistory, MultiObjectiveHistory
14+
from .history import History
1515
from .progbar_logger import ProgbarLogger
1616

1717

1818
class CallbackList():
19-
def __init__(self, callbacks: List[Callback] = None, add_so_history=False, add_mo_history=False, add_progbar=False):
19+
def __init__(self, callbacks: List[Callback] = None, add_history=False, add_progbar=False):
2020
self.callbacks = callbacks if callbacks else []
2121
self._add_default_callbacks(
22-
add_so_history, add_mo_history, add_progbar)
23-
24-
def _add_default_callbacks(self, add_so_history, add_mo_history, add_progbar):
25-
if add_mo_history and add_so_history:
26-
raise ValueError("Cannot add both SingleObjectiveHistory and MultiObjectiveHistory\n \
27-
Use one of them")
22+
add_history, add_progbar)
2823

24+
def _add_default_callbacks(self, add_history, add_progbar):
2925
self._history = None
3026
self._progbar = None
3127

3228
for cb in self.callbacks:
33-
if isinstance(cb, SingleObjectiveHistory) and add_so_history:
34-
self._history = cb
35-
elif isinstance(cb, MultiObjectiveHistory) and add_mo_history:
29+
if isinstance(cb, History) and add_history:
3630
self._history = cb
3731
elif isinstance(cb, ProgbarLogger):
3832
self._progbar = cb
3933

40-
if self._history is None and add_so_history:
41-
self._history = SingleObjectiveHistory()
42-
self.callbacks.append(self._history)
43-
if self._history is None and add_mo_history:
44-
self._history = MultiObjectiveHistory()
34+
if self._history is None and add_history:
35+
self._history = History()
4536
self.callbacks.append(self._history)
4637
if self._progbar is None and add_progbar:
4738
self._progbar = ProgbarLogger()

geneticpython/callbacks/history.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,15 @@
1414

1515

1616
class History(Callback):
17+
"""Callback that records events into a `History` object.
18+
This callback is automatically applied to
19+
every Genetic engine. The `History` object
20+
gets returned by the `run` method of engine.
21+
"""
22+
1723
def __init__(self):
18-
pass
24+
super(History, self).__init__()
25+
self.history = []
1926

2027
def on_init_population_end(self, logs=None):
2128
pass
@@ -24,12 +31,8 @@ def on_generation_begin(self, gen, logs=None):
2431
pass
2532

2633
def on_generation_end(self, gen, logs=None):
27-
pass
28-
29-
30-
class MultiObjectiveHistory(History):
31-
pass
32-
33-
34-
class SingleObjectiveHistory(History):
35-
pass
34+
logs = logs or {}
35+
self.history.append(logs)
36+
# Set the history attribute on the model after the epoch ends. This will
37+
# make sure that the state which is set is the latest one.
38+
self.engine.history = self

geneticpython/callbacks/progbar_logger.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,17 @@ def on_init_population_end(self, logs=None):
2323
self.progbar = tqdm(range(self.engine.MAX_ITER))
2424

2525
def on_generation_end(self, gen, logs=None):
26-
logs = self._update_logs(logs)
27-
self.progbar.set_postfix(logs, refresh=True)
26+
self._update_metrics()
27+
self.progbar.set_postfix(self.metrics, refresh=True)
2828
self.progbar.update()
2929

3030
def on_running_end(self, logs=None):
3131
self.progbar.close()
3232

33-
def _update_logs(self, logs):
34-
logs = logs or OrderedDict()
33+
def _update_metrics(self):
34+
self.metrics = self.metrics or OrderedDict()
3535
if self.default_metrics and self.engine.metrics:
3636
if not isinstance(self.engine.metrics, (dict, OrderedDict)):
3737
raise TypeError(
3838
f'engine.metrics (type : {type(self.engine.metrics).__name__}) has be an instance of Dict or OrderedDict')
39-
for name, value in self.engine.metrics.items():
40-
logs[name] = value
41-
42-
return logs
39+
self.metrics.update(self.engine.metrics)

geneticpython/engines/gaengine.py

Lines changed: 0 additions & 98 deletions
This file was deleted.

geneticpython/engines/geneticengine.py

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ def __init__(self, population: Population,
5252
self.callbacks = callbacks
5353
self.callbacks.set_engine(self)
5454
self.metrics = None
55+
self.history = None
5556

5657
def create_seed(self, seed: int):
5758
self.rand = random.Random(seed)
@@ -88,43 +89,48 @@ def do_evaluation(self, population: List[Individual]) -> List[Individual]:
8889
def do_replacement(self, new_population: List[Individual]) -> List[Individual]:
8990
pass
9091

91-
def _update_metrics(self):
92+
def _update_metrics(self) -> None:
93+
pass
94+
95+
def _update_logs(self, logs) -> None:
9296
pass
9397

9498
def run(self) -> History:
95-
self.callbacks.on_running_begin()
99+
logs = None
100+
self.callbacks.on_running_begin(logs=logs)
96101

97-
self.callbacks.on_init_population_begin()
102+
self.callbacks.on_init_population_begin(logs=logs)
98103
self.population.individuals = self.do_initialization()
99-
self.callbacks.on_init_population_end()
104+
self.callbacks.on_init_population_end(logs=logs)
100105

101106
for gen in range(self.MAX_ITER):
102-
self.callbacks.on_generation_begin(gen)
103-
self.callbacks.on_selection_begin(gen)
107+
self.callbacks.on_generation_begin(gen, logs=logs)
108+
self.callbacks.on_selection_begin(gen, logs=logs)
104109
mating_population = self.do_selection()
105-
self.callbacks.on_selection_end(gen)
110+
self.callbacks.on_selection_end(gen, logs=logs)
106111

107-
self.callbacks.on_reproduction_begin(gen)
112+
self.callbacks.on_reproduction_begin(gen, logs=logs)
108113
offspring_population = self.do_reproduction(mating_population)
109-
self.callbacks.on_reproduction_end(gen)
114+
self.callbacks.on_reproduction_end(gen, logs=logs)
110115

111-
self.callbacks.on_evaluation_begin(gen)
116+
self.callbacks.on_evaluation_begin(gen, logs=logs)
112117
offspring_population = self.do_evaluation(offspring_population)
113-
self.callbacks.on_evaluation_end(gen)
118+
self.callbacks.on_evaluation_end(gen, logs=logs)
114119

115120
new_population = self.population.individuals + offspring_population
116121

117-
self.callbacks.on_replacement_begin(gen)
122+
self.callbacks.on_replacement_begin(gen, logs=logs)
118123
self.population.individuals = self.do_replacement(new_population)
119-
self.callbacks.on_replacement_end(gen)
124+
self.callbacks.on_replacement_end(gen, logs=logs)
120125

121126
self._update_metrics()
127+
logs = self._update_logs(logs)
122128

123-
self.callbacks.on_generation_end(gen)
129+
self.callbacks.on_generation_end(gen, logs=logs)
124130

125-
self.callbacks.on_running_end()
131+
self.callbacks.on_running_end(logs=logs)
126132

127-
return self.callbacks._history
133+
return self.history
128134

129135
def get_all_solutions(self) -> List[Individual]:
130136
return self.population.individuals

geneticpython/engines/multi_objective/multi_objective_engine.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010

1111
from typing import Union, Callable, List
1212
from functools import wraps
13+
from abc import ABC, abstractmethod
1314

1415
from ..geneticengine import GeneticEngine
1516
from ...callbacks import Callback, CallbackList
16-
from ...callbacks import History, MultiObjectiveHistory
17+
from ...callbacks import History
1718
from ...core.population import Population
1819
from ...core.operators import Selection, Crossover, Mutation, Replacement
1920
from ...core.individual import Individual
@@ -33,7 +34,7 @@ def __init__(self, population: Population,
3334
max_iter: int = 100,
3435
random_state: int = None):
3536
callback_list = CallbackList(
36-
callbacks, add_mo_history=True, add_progbar=True)
37+
callbacks, add_history=True, add_progbar=True)
3738
super(MultiObjectiveEngine, self).__init__(population=population,
3839
selection=selection,
3940
selection_size=selection_size,
@@ -44,6 +45,19 @@ def __init__(self, population: Population,
4445
max_iter=max_iter,
4546
random_state=random_state)
4647

48+
@abstractmethod
49+
def get_pareto_front(self) -> List[Individual]:
50+
pass
51+
52+
def _update_logs(self, logs):
53+
logs = logs or {}
54+
pareto_front = [
55+
indv.objectives for indv in self.get_pareto_front()]
56+
logs.update({'pareto_front': pareto_front})
57+
solutions = [indv.objectives for indv in self.get_all_solutions()]
58+
logs.update({'solutions': solutions})
59+
return logs
60+
4761
def minimize_objective(self, fn):
4862
"""
4963
register objective function

geneticpython/engines/multi_objective/nsgaiiengine.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from ...core.population import Population
1515
from ...core.operators import Selection, Crossover, Mutation, Replacement, RankReplacement
1616
from ..geneticengine import GeneticEngine
17-
from ...callbacks import CallbackList, Callback, History, MultiObjectiveHistory
17+
from ...callbacks import CallbackList, Callback, History
1818
from .multi_objective_engine import MultiObjectiveEngine
1919

2020
import random
@@ -238,7 +238,7 @@ def do_replacement(self, new_population) -> List[Individual]:
238238
comparator=NSGAIIEngine.crowded_comparator,
239239
sorted=True,
240240
rand=self.rand)
241-
return new_population
241+
return new_population
242242

243243
def run(self) -> History:
244244
return super(NSGAIIEngine, self).run()

geneticpython/engines/single_objective/gaengine.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from ...core.operators import Selection, Crossover, Mutation, Replacement
1616
from ..geneticengine import GeneticEngine
1717
from .single_objective_engine import SingleObjectiveEngine
18-
from ...callbacks import Callback, History, SingleObjectiveHistory, CallbackList
18+
from ...callbacks import Callback, History, CallbackList
1919

2020
import random
2121
import math

0 commit comments

Comments
 (0)