59
59
import numpy as np
60
60
from numpy .random import Generator
61
61
from pycommons .strings .string_conv import num_to_str
62
+ from pycommons .types import type_error
62
63
63
64
from moptipy .algorithms .so .fea1plus1 import SWITCH_TO_MAP_RANGE , log_h
64
65
from moptipy .algorithms .so .fitness import Fitness , FRecord
75
76
class FFA (Fitness ):
76
77
"""The frequency fitness assignment (FFA) process."""
77
78
78
- def __new__ (cls , f : Objective ) -> "FFA" :
79
+ def __new__ (cls , f : Objective , log_h_tbl : bool = True ) -> "FFA" :
79
80
"""
80
81
Create the frequency fitness assignment mapping.
81
82
82
83
:param f: the objective function
83
84
"""
85
+ if not isinstance (log_h_tbl , bool ):
86
+ raise type_error (log_h_tbl , "log_h_tbl" , bool )
84
87
check_objective (f )
85
88
if f .is_always_integer ():
86
89
lb : Final [int | float ] = f .lower_bound ()
87
90
ub : Final [int | float ] = f .upper_bound ()
88
91
if isinstance (ub , int ) and isinstance (lb , int ) \
89
92
and ((ub - lb ) <= SWITCH_TO_MAP_RANGE ):
90
93
if 0 <= lb <= SWITCH_TO_OFFSET_LB :
91
- return _IntFFA1 .__new__ (_IntFFA1 , cast (int , ub ))
94
+ return _IntFFA1 .__new__ (_IntFFA1 , cast (int , ub ), log_h_tbl )
92
95
return _IntFFA2 .__new__ (_IntFFA2 , cast (int , lb ),
93
- cast (int , ub ))
94
- return _DictFFA .__new__ (_DictFFA )
96
+ cast (int , ub ), log_h_tbl )
97
+ return _DictFFA .__new__ (_DictFFA , log_h_tbl )
95
98
96
99
def __str__ (self ):
97
100
"""
@@ -110,19 +113,23 @@ class _IntFFA1(FFA):
110
113
__h : np .ndarray
111
114
#: is this the first iteration?
112
115
__first : bool
116
+ #: log the h table?
117
+ __log_h_tbl : bool
113
118
114
- def __new__ (cls , ub : int ) -> "_IntFFA1" :
119
+ def __new__ (cls , ub : int , log_h_tbl : bool = True ) -> "_IntFFA1" :
115
120
"""Initialize the pure integer FFA."""
116
121
instance = object .__new__ (_IntFFA1 )
117
122
instance .__h = np .zeros (ub + 1 , dtype = DEFAULT_INT )
118
123
instance .__first = True
124
+ instance .__log_h_tbl = log_h_tbl
119
125
return instance
120
126
121
127
def log_information_after_run (self , process : Process ) -> None :
122
128
"""Write the H table."""
123
- log_h (process , range (len (self .__h )),
124
- cast (Callable [[int | float ], int ], self .__h .__getitem__ ),
125
- str )
129
+ if self .__log_h_tbl :
130
+ log_h (process , range (len (self .__h )),
131
+ cast (Callable [[int | float ], int ], self .__h .__getitem__ ),
132
+ str )
126
133
127
134
def assign_fitness (self , p : list [FRecord ], random : Generator ) -> None :
128
135
"""
@@ -131,7 +138,7 @@ def assign_fitness(self, p: list[FRecord], random: Generator) -> None:
131
138
:param p: the list of records
132
139
:param random: ignored
133
140
134
- >>> fit = _IntFFA1(100)
141
+ >>> fit = _IntFFA1(100, False )
135
142
>>> a = FRecord(None, 1)
136
143
>>> b = FRecord(None, 2)
137
144
>>> c = FRecord(None, 2)
@@ -201,20 +208,24 @@ class _IntFFA2(FFA):
201
208
__lb : int
202
209
#: is this the first iteration?
203
210
__first : bool
211
+ #: log the h table?
212
+ __log_h_tbl : bool
204
213
205
- def __new__ (cls , lb : int , ub : int ) -> "_IntFFA2" :
214
+ def __new__ (cls , lb : int , ub : int , log_h_tbl : bool = True ) -> "_IntFFA2" :
206
215
"""Initialize the pure integer FFA."""
207
216
instance = object .__new__ (_IntFFA2 )
208
217
instance .__h = np .zeros (ub - lb + 1 , dtype = DEFAULT_INT )
209
218
instance .__lb = lb
210
219
instance .__first = True
220
+ instance .__log_h_tbl = log_h_tbl
211
221
return instance
212
222
213
223
def log_information_after_run (self , process : Process ) -> None :
214
224
"""Write the H table."""
215
- log_h (process , range (len (self .__h )),
216
- cast (Callable [[int | float ], int ], self .__h .__getitem__ ),
217
- lambda i : str (i + self .__lb ))
225
+ if self .__log_h_tbl :
226
+ log_h (process , range (len (self .__h )),
227
+ cast (Callable [[int | float ], int ], self .__h .__getitem__ ),
228
+ lambda i : str (i + self .__lb ))
218
229
219
230
def assign_fitness (self , p : list [FRecord ], random : Generator ) -> None :
220
231
"""
@@ -223,7 +234,7 @@ def assign_fitness(self, p: list[FRecord], random: Generator) -> None:
223
234
:param p: the list of records
224
235
:param random: ignored
225
236
226
- >>> fit = _IntFFA2(-10, 100)
237
+ >>> fit = _IntFFA2(-10, 100, False )
227
238
>>> a = FRecord(None, -1)
228
239
>>> b = FRecord(None, 2)
229
240
>>> c = FRecord(None, 2)
@@ -296,19 +307,23 @@ class _DictFFA(FFA):
296
307
__h : Counter [int | float ]
297
308
#: is this the first iteration?
298
309
__first : bool
310
+ #: log the h table?
311
+ __log_h_tbl : bool
299
312
300
- def __new__ (cls ) -> "_DictFFA" :
313
+ def __new__ (cls , log_h_tbl : bool = True ) -> "_DictFFA" :
301
314
"""Initialize the pure integer FFA."""
302
315
instance = object .__new__ (_DictFFA )
303
316
instance .__h = Counter ()
304
317
instance .__first = True
318
+ instance .__log_h_tbl = log_h_tbl
305
319
return instance
306
320
307
321
def log_information_after_run (self , process : Process ) -> None :
308
322
"""Write the H table."""
309
- log_h (process , cast (Iterable [int | float ], self .__h .keys ()),
310
- cast (Callable [[int | float ], int ], self .__h .__getitem__ ),
311
- num_to_str )
323
+ if self .__log_h_tbl :
324
+ log_h (process , cast (Iterable [int | float ], self .__h .keys ()),
325
+ cast (Callable [[int | float ], int ], self .__h .__getitem__ ),
326
+ num_to_str )
312
327
313
328
def assign_fitness (self , p : list [FRecord ], random : Generator ) -> None :
314
329
"""
@@ -317,7 +332,7 @@ def assign_fitness(self, p: list[FRecord], random: Generator) -> None:
317
332
:param p: the list of records
318
333
:param random: ignored
319
334
320
- >>> fit = _DictFFA()
335
+ >>> fit = _DictFFA(False )
321
336
>>> a = FRecord(None, -1)
322
337
>>> b = FRecord(None, 2.9)
323
338
>>> c = FRecord(None, 2.9)
0 commit comments