Skip to content

Commit

Permalink
update ga inits
Browse files Browse the repository at this point in the history
  • Loading branch information
PasaOpasen committed Apr 13, 2024
1 parent ba5bfd5 commit 5397df4
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 40 deletions.
3 changes: 2 additions & 1 deletion geneticalgorithm2/callbacks/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from ..selections import SelectionFunc
from ..utils.aliases import array2D, array1D

from ..data_types.aliases import SetFunctionToMinimize
from ..data_types.generation import Generation
from ..data_types.base import DictLikeGetSet

Expand Down Expand Up @@ -42,7 +43,7 @@ class MiddleCallbackData(DictLikeGetSet):
parents_portion: float
elit_ratio: float

set_function: Callable[[array2D], array1D]
set_function: SetFunctionToMinimize


SimpleCallbackFunc: TypeAlias = Callable[[int, List[float], array2D, array1D], None]
Expand Down
4 changes: 4 additions & 0 deletions geneticalgorithm2/data_types/algorithm_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ class AlgorithmParams(DictLikeGetSet):
"""Base optimization parameters container"""

max_num_iteration: Optional[int] = None
"""max iterations count of the algorithm"""
max_iteration_without_improv: Optional[int] = None
"""max iteration without progress"""

population_size: int = 100

Expand All @@ -49,7 +51,9 @@ class AlgorithmParams(DictLikeGetSet):

crossover_type: Union[str, CrossoverFunc] = 'uniform'
mutation_type: Union[str, MutationFloatFunc] = 'uniform_by_center'
"""mutation type for real variable"""
mutation_discrete_type: Union[str, MutationIntFunc] = 'uniform_discrete'
"""mutation type for discrete variables"""
selection_type: Union[str, SelectionFunc] = 'roulette'

def validate(self) -> None:
Expand Down
22 changes: 22 additions & 0 deletions geneticalgorithm2/data_types/aliases.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

from typing import Callable
from typing_extensions import TypeAlias

from ..utils.aliases import array2D, array1D


FunctionToMinimize: TypeAlias = Callable[[array1D], float]
"""usual (vector -> value) function to minimize"""


SetFunctionToMinimize: TypeAlias = Callable[[array2D], array1D]
"""
(population -> scores) function to minimize
it is like a vectorized version of usual (vector -> value) function
performing to all population samples in the one call
but it can be written in more optimal way to speed up the calculations;
also it can contain any logic due to samples relations and so on -- depends on the task
"""

79 changes: 40 additions & 39 deletions geneticalgorithm2/geneticalgorithm2.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,30 @@

from .utils.aliases import array1D, array2D

from .data_types.aliases import FunctionToMinimize, SetFunctionToMinimize
from .data_types.algorithm_params import AlgorithmParams
from .data_types.generation import GenerationConvertible, Generation
from .data_types.result import GAResult
from .callbacks.data import MiddleCallbackData

from .population_initializer import get_population_initializer
from .utils.plotting import plot_pop_scores, plot_several_lines

from .utils.funcs import can_be_prob, is_numpy, is_current_gen_number, fast_min, random_indexes_pair

from .callbacks.data import MiddleCallbackData
from .callbacks import MiddleCallbackFunc, SimpleCallbackFunc

#endregion

#region ALIASES

VARIABLE_TYPE: TypeAlias = Literal['int', 'real', 'bool']
"""
the variable type for a given or all dimension, determines the values discretion:
real: double numbers
int: integer number only
bool: in the fact is integer with bounds [0, 1]
"""

#endregion

Expand Down Expand Up @@ -65,7 +72,7 @@ def needs_mutation(self) -> bool:

def __init__(
self,
function: Callable[[array1D], float],
function: FunctionToMinimize,

dimension: int,
variable_type: Union[VARIABLE_TYPE, Sequence[VARIABLE_TYPE]] = 'bool',
Expand All @@ -77,43 +84,37 @@ def __init__(
algorithm_parameters: Union[AlgorithmParams, Dict[str, Any]] = default_params
):
"""
Args:
function <Callable[[np.ndarray], float]> - the given objective function to be minimized
#NOTE: This implementation minimizes the given objective function.
(For maximization multiply function by a negative sign: the absolute
value of the output would be the actual objective function)
initializes the GA object and performs main checks
dimension <integer> - the number of decision variables
Args:
function: the given objective function to be minimized
dimension: the number of decision variables, the population samples dimention
variable_type <string> - 'bool' if all variables are Boolean;
'int' if all variables are integer; and 'real' if all variables are
real value or continuous. For mixed types use sequence of string of type for each variable
variable_type: string means the variable type for all variables,
for mixed types use sequence of strings of type for each variable
variable_boundaries <Optional[Union[np.ndarray, Sequence[Tuple[float, float]]]]> - Default None; leave it
None if variable_type is 'bool'; otherwise provide an array of tuples
of length two as boundaries for each variable;
the length of the array must be equal dimension. For example,
np.array([0,100],[0,200]) determines lower boundary 0 and upper boundary 100 for first
and upper boundary 200 for second variable where dimension is 2.
variable_boundaries: leave it None if variable_type is 'bool';
otherwise provide a sequence of tuples of length two as boundaries for each variable;
the length of the array must be equal dimension.
For example, ([0,100], [0,200]) determines
lower boundary 0 and upper boundary 100 for first
and upper boundary 200 for second variable
and dimension must be 2.
variable_type_mixed -- deprecated
function_timeout <float> - if the given function does not provide
output before function_timeout (unit is seconds) the algorithm raise error.
For example, when there is an infinite loop in the given function. `None` means disabling
algorithm_parameters <Union[AlgorithmParams, Dict[str, Any]]>:
@ max_num_iteration <int> - stopping criteria of the genetic algorithm (GA)
@ population_size <int>
@ mutation_probability <float in [0,1]>
@ elit_ratio <float in [0,1]>
@ crossover_probability <float in [0,1]>
@ parents_portion <float in [0,1]>
@ crossover_type <string/function> - Default is 'uniform'; 'one_point' or 'two_point' (not only) are other options
@ mutation_type <string/function> - Default is 'uniform_by_x'; see GitHub to check other options
@ mutation_discrete_type <string/function> - mutation type for discrete variables
@ selection_type <string/function> - Default is 'roulette'; see GitHub to check other options
@ max_iteration_without_improv <int> - maximum number of successive iterations without improvement. If None it is ineffective
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
algorithm_parameters: AlgorithmParams object or usual dictionary with algorithm parameter;
it is not mandatory to provide all possible parameters
Notes:
- This implementation minimizes the given objective function.
For maximization u can multiply the function by -1 (for instance): the absolute
value of the output would be the actual objective function
for more details and examples of implementation please visit:
https://github.com/PasaOpasen/geneticalgorithm2
Expand All @@ -122,7 +123,6 @@ def __init__(

# all default fields

self.param: AlgorithmParams = None
# self.crossover: Callable[[np.ndarray, np.ndarray], Tuple[np.ndarray, np.ndarray]] = None
# self.real_mutation: Callable[[float, float, float], float] = None
# self.discrete_mutation: Callable[[int, int, int], int] = None
Expand All @@ -149,9 +149,9 @@ def __init__(
)
if not isinstance(algorithm_parameters, AlgorithmParams):
algorithm_parameters = AlgorithmParams.from_dict(algorithm_parameters)

algorithm_parameters.validate()
self.param = algorithm_parameters

self.crossover, self.real_mutation, self.discrete_mutation, self.selection = algorithm_parameters.get_CMS_funcs()

# dimension and area bounds
Expand Down Expand Up @@ -203,7 +203,8 @@ def __init__(
self._set_parents_count(self.param.parents_portion)
self._set_elit_count(self.population_size, self.param.elit_ratio)
assert self.parents_count >= self.elit_count, (
f"\n number of parents ({self.parents_count}) must be greater than number of elits ({self.elit_count})"
f"\n number of parents ({self.parents_count}) "
f"must be greater than number of elits ({self.elit_count})"
)

self._set_max_iterations()
Expand Down Expand Up @@ -406,8 +407,8 @@ def _set_mutation_indexes(self, mutation_indexes: Optional[Sequence[int]]):
self.indexes_int_mut = self.indexes_int
else:
tmp_indexes = set(mutation_indexes)
self.indexes_int_mut = np.array(list(set(self.indexes_int).intersection(tmp_indexes)))
self.indexes_float_mut = np.array(list(set(self.indexes_float).intersection(tmp_indexes)))
self.indexes_int_mut = np.array(list(tmp_indexes.intersection(self.indexes_int)))
self.indexes_float_mut = np.array(list(tmp_indexes.intersection(self.indexes_float)))

if self.indexes_float_mut.size == 0 and self.indexes_int_mut.size == 0:
warnings.warn(f"No mutation dimensions!!! Check ur mutation indexes!!")
Expand All @@ -422,7 +423,7 @@ def run(
# deprecated
disable_progress_bar: bool = False,

set_function: Optional[Callable[[array2D], array1D]] = None,
set_function: SetFunctionToMinimize = None,
apply_function_to_parents: bool = False,
start_generation: GenerationConvertible = Generation(),
studEA: bool = False,
Expand Down

0 comments on commit 5397df4

Please sign in to comment.