diff --git a/README.md b/README.md index bc2be88..a1412fa 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ https://pasaopasen.github.io/geneticalgorithm2/ - [Updates information](#updates-information) - [**Future**](#future) - [**TODO firstly**](#todo-firstly) + - [6.9.1 refactor](#691-refactor) - [6.9.0 reborn](#690-reborn) - [6.8.7 minor update](#687-minor-update) - [6.8.6 minor update](#686-minor-update) @@ -133,12 +134,12 @@ Features of this package: # Installation -Install this package with standard dependencies to use the entire functional. +Install this package with standard light dependencies to use the base functional. ``` pip install geneticalgorithm2 ``` -Install this package with full dependencies to use all provided functional. +Install this package with full dependencies to use all provided functional including plotting and built-in parallelism tools. ``` pip install geneticalgorithm2[full] @@ -149,13 +150,16 @@ pip install geneticalgorithm2[full] ## **Future** - duplicates removing and revolutions will be moved to `MiddleCallbacks` and removed as alone `run()` parameters -- `function_timeout` and `function` will be moved to `run()` method - new stop criteria callbacks (min std, max functions evaluations) - `vartype` will support strings like `iiiiibbf` ## **TODO firstly** -- Remove old style mensions from README +- Remove old style mentions from README +## 6.9.1 refactor + +- Finally move `function_timeout` and `function` to `run()` method and deprecate its usage in init() +- `function` is not mandatory to be non-empty ## 6.9.0 reborn diff --git a/geneticalgorithm2/geneticalgorithm2.py b/geneticalgorithm2/geneticalgorithm2.py index e4448d0..596f683 100644 --- a/geneticalgorithm2/geneticalgorithm2.py +++ b/geneticalgorithm2/geneticalgorithm2.py @@ -74,9 +74,9 @@ def needs_mutation(self) -> bool: def __init__( self, - function: FunctionToMinimize, + function: FunctionToMinimize = None, - dimension: int, + dimension: int = 0, variable_type: Union[VARIABLE_TYPE, Sequence[VARIABLE_TYPE]] = 'bool', variable_boundaries: Optional[Union[array2D, Sequence[Tuple[float, float]]]] = None, @@ -89,8 +89,8 @@ def __init__( initializes the GA object and performs main checks Args: - function: the given objective function to be minimized - dimension: the number of decision variables, the population samples dimention + function: the given objective function to be minimized -- deprecated and moved to run() method + dimension: the number of decision variables, the population samples dimension variable_type: string means the variable type for all variables, for mixed types use sequence of strings of type for each variable @@ -108,7 +108,7 @@ def __init__( function_timeout: if the given function does not provide output before function_timeout (unit is seconds) the algorithm raises error. For example, when there is an infinite loop in the given function. - `None` means disabling + `None` means disabling -- deprecated and moved to run() algorithm_parameters: AlgorithmParams object or usual dictionary with algorithm parameter; it is not mandatory to provide all possible parameters @@ -118,9 +118,6 @@ def __init__( For maximization u can multiply the function by -1 (for instance): the absolute value of the output would be the actual objective function - - If u want to use set_function only and maybe u dont have usual function, - just set the function to something like lambda x: 0 but set function_timeout=None too - for more details and examples of implementation please visit: https://github.com/PasaOpasen/geneticalgorithm2 @@ -137,8 +134,10 @@ def __init__( self.dup_oppositor = None self.creator = None self.init_oppositors = None + self.f: Callable[[array1D], float] = None self.funtimeout: float = None + self.set_function: Callable[[np.ndarray], np.ndarray] = None # self.dim: int = None @@ -191,20 +190,18 @@ def __init__( ############################################################# # input function - assert (callable(function)), "function must be callable!" - self.f = function - - if function_timeout is not None and function_timeout > 0: - try: - from func_timeout import func_timeout, FunctionTimedOut - except ModuleNotFoundError: - raise ModuleNotFoundError( - "function_timeout > 0 needs additional package func_timeout\n" - "run `python -m pip install func_timeout`\n" - "or disable this parameter: function_timeout=None" - ) - - self.funtimeout = None if function_timeout is None else float(function_timeout) + if function: + warnings.warn( + f"function is deprecated in init constructor and will be removed in version 7. " + f"Move this argument to run() method" + ) + self._check_function(function) + if function_timeout: + warnings.warn( + f"function_timeout is deprecated in init constructor and will be removed in version 7. " + f"Move this argument to run() method" + ) + self._check_function_timeout(function_timeout) ############################################################# @@ -325,6 +322,24 @@ def _set_max_iterations(self): else: self.max_stagnations = math.ceil(max_it) + def _check_function(self, function: Callable[[array1D], float]): + assert callable(function), "function must be callable!" + self.f = function + + def _check_function_timeout(self, function_timeout: Optional[float]): + + if function_timeout is not None and function_timeout > 0: + try: + from func_timeout import func_timeout, FunctionTimedOut + except ModuleNotFoundError: + raise ModuleNotFoundError( + "function_timeout > 0 needs additional package func_timeout\n" + "run `python -m pip install func_timeout`\n" + "or disable this parameter: function_timeout=None" + ) + + self.funtimeout = None if function_timeout is None else float(function_timeout) + #endregion #region REPORT @@ -432,6 +447,9 @@ def run( # deprecated disable_progress_bar: bool = False, + function: FunctionToMinimize = None, + function_timeout: Optional[float] = None, + set_function: SetFunctionToMinimize = None, apply_function_to_parents: bool = False, start_generation: GenerationConvertible = Generation(), @@ -471,7 +489,15 @@ def run( disable_progress_bar: deprecated - set_function: set function to be used instead of usual function + function: the given objective function (sample -> its score) to be minimized; + + function_timeout: if the given function does not provide + output before function_timeout (unit is seconds) the algorithm raises error. + For example, when there is an infinite loop in the given function. + `None` means disabling + + set_function: set function (all samples -> score per sample) to be used instead of usual function + (usually for optimization purposes) apply_function_to_parents: whether to apply function to parents from previous generation (if it's needed) @@ -510,6 +536,9 @@ def run( {'population': 2D-array, 'scores': 1D-array}, None if doesn't need to save in file seed: random seed (None if doesn't matter) + + Notes: + if `function_timeout` is enabled then `function` must be set """ if disable_progress_bar: @@ -664,6 +693,16 @@ def total_middle_callback(): else (lambda: int(time.time() - start_time) >= time_limit_secs) ) + # combine with deprecated parts + function = function or self.f + function_timeout = function_timeout or self.funtimeout + + assert function or set_function, 'no function to minimize' + if function: + self._check_function(function) + if function_timeout: + self._check_function_timeout(function_timeout) + self.set_function = set_function or GeneticAlgorithm2.default_set_function(self.f) #region Initial population, duplicates filter, revolutionary diff --git a/tests/min of sum int.py b/tests/min of sum int.py index 2cc377e..62cf68d 100644 --- a/tests/min of sum int.py +++ b/tests/min of sum int.py @@ -24,16 +24,18 @@ def f(X): # check discrete mutation -varbound = [[0,10]]*300 - -model = ga(function=f, dimension=300, variable_type='int', - variable_boundaries=varbound, - algorithm_parameters={ - 'mutation_discrete_type': 'uniform_discrete', - 'max_num_iteration': 1000 - }) - -model.run(stop_when_reached=0) +varbound = [[0, 10]] * 300 + +model = ga( + dimension=300, variable_type='int', + variable_boundaries=varbound, + algorithm_parameters={ + 'mutation_discrete_type': 'uniform_discrete', + 'max_num_iteration': 1000 + } +) + +model.run(stop_when_reached=0, function=f,) model = ga(function=f, dimension=300, variable_type='int',