geneticalgorithm2.data_types.generation
1from typing import Union, Dict, Literal, Tuple, Optional 2from typing_extensions import TypeAlias 3 4import os.path 5from dataclasses import dataclass 6 7import numpy as np 8 9from ..utils.aliases import array2D, array1D, PathLike 10from ..utils.files import mkdir_of_file 11from ..utils.funcs import union_to_matrix 12 13from .base import DictLikeGetSet 14 15GenerationConvertible: TypeAlias = Union[ 16 'Generation', 17 str, 18 Dict[Literal['population', 'scores'], Union[array2D, array1D]], 19 array2D, 20 Tuple[ 21 Optional[array2D], 22 Optional[array1D] 23 ] 24] 25""" 26The forms convertible to `Generation` object: 27 - `Generation` object 28 - path to saved generation 29 - dict {'population': pop_matrix, 'scores': scores_vector} 30 - wide population matrix 31 - pair (pop_matrix, scores_vector) 32""" 33 34 35@dataclass 36class Generation(DictLikeGetSet): 37 """wrapper on generation object (pair of samples matrix and samples scores vector)""" 38 variables: Optional[array2D] = None 39 scores: Optional[array1D] = None 40 41 def _check_dims(self) -> None: 42 if self.variables is not None: 43 assert len(self.variables.shape) == 2, ( 44 f"'variables' must be matrix with shape (objects, dimensions), not {self.variables.shape}" 45 ) 46 if self.scores is not None: 47 assert len(self.scores.shape) == 1, f"'scores' must be 1D-array, not with shape {self.scores.shape}" 48 assert self.variables.shape[0] == self.scores.size, ( 49 f"count of objects ({self.variables.shape[0]}) " 50 f"must be equal to count of scores ({self.scores.size})" 51 ) 52 53 @property 54 def size(self) -> int: 55 return self.scores.size 56 57 @property 58 def dim_size(self) -> int: 59 return self.variables.shape[1] 60 61 def as_wide_matrix(self) -> array2D: 62 # should not be used in main code -- was needed for old versions 63 return union_to_matrix(self.variables, self.scores) 64 65 def save(self, path: PathLike): 66 mkdir_of_file(path) 67 np.savez(path, population=self.variables, scores=self.scores) 68 69 @staticmethod 70 def load(path: PathLike): 71 try: 72 st = np.load(path) 73 except Exception as err: 74 raise Exception( 75 f"if generation object is a string, " 76 f"it must be path to npz file with needed content, but raised exception {repr(err)}" 77 ) 78 79 assert 'population' in st and 'scores' in st, ( 80 "saved generation object must contain 'population' and 'scores' fields" 81 ) 82 83 return Generation(variables=st['population'], scores=st['scores']) 84 85 @staticmethod 86 def from_object( 87 dim: int, 88 obj: GenerationConvertible 89 ): 90 """class constructor""" 91 92 if isinstance(obj, np.ndarray): 93 94 assert len(obj.shape) == 2 and (obj.shape[1] == dim or obj.shape[1] == dim + 1), ( 95 f"if start_generation is numpy array, " 96 f"it must be with shape (samples, dim) or (samples, dim+1), not {obj.shape}" 97 ) 98 99 generation = Generation(obj, None) if obj.shape[1] == dim else Generation.from_pop_matrix(obj) 100 101 elif isinstance(obj, tuple): 102 103 assert len(obj) == 2, ( 104 f"if start_generation is tuple, " 105 f"it must be tuple with 2 components, not {len(obj)}" 106 ) 107 108 variables, scores = obj 109 110 assert (variables is None or scores is None) or (variables.shape[0] == scores.size), ( 111 "start_generation object must contain variables and scores components " 112 "which are None or 2D- and 1D-arrays with same shape" 113 ) 114 115 generation = Generation(variables=variables, scores=scores) 116 117 elif isinstance(obj, dict): 118 assert ( 119 ('variables' in obj and 'scores' in obj) and 120 ( 121 (obj['variables'] is None or obj['scores'] is None) or 122 (obj['variables'].shape[0] == obj['scores'].size) 123 ) 124 ), ( 125 "start_generation object must contain 'variables' and 'scores' keys " 126 "which are None or 2D- and 1D-arrays with same shape" 127 ) 128 129 generation = Generation(variables=obj['variables'], scores=obj['scores']) 130 131 elif isinstance(obj, Generation): 132 generation = Generation(variables=obj['variables'], scores=obj['scores']) 133 else: 134 135 path = str(obj) 136 if not os.path.exists(path): 137 raise TypeError( 138 f"invalid type of generation! " 139 f"Must be in (Union[str, Dict[str, np.ndarray], Generation, np.ndarray, " 140 f"Tuple[Optional[np.ndarray], Optional[np.ndarray]]]), " 141 f"not {type(obj)}" 142 ) 143 generation = Generation.load(path) 144 145 generation._check_dims() 146 147 if generation.variables is not None: 148 assert generation.dim_size == dim, ( 149 f"generation dimension size {generation.dim_size} does not equal to target size {dim}" 150 ) 151 152 return generation 153 154 @staticmethod 155 def from_pop_matrix(pop: array2D): 156 import warnings 157 warnings.warn( 158 "depricated! pop matrix style will be removed at version 7, " 159 "use samples and scores separetly" 160 ) 161 return Generation( 162 variables=pop[:, :-1], 163 scores=pop[:, -1] 164 )
GenerationConvertible: typing_extensions.TypeAlias =
typing.Union[ForwardRef('Generation'), str, typing.Dict[typing.Literal['population', 'scores'], numpy.ndarray], numpy.ndarray, typing.Tuple[typing.Union[numpy.ndarray, NoneType], typing.Union[numpy.ndarray, NoneType]]]
The forms convertible to Generation
object:
- Generation
object
- path to saved generation
- dict {'population': pop_matrix, 'scores': scores_vector}
- wide population matrix
- pair (pop_matrix, scores_vector)
38class Generation(DictLikeGetSet): 39 """wrapper on generation object (pair of samples matrix and samples scores vector)""" 40 variables: Optional[array2D] = None 41 scores: Optional[array1D] = None 42 43 def _check_dims(self) -> None: 44 if self.variables is not None: 45 assert len(self.variables.shape) == 2, ( 46 f"'variables' must be matrix with shape (objects, dimensions), not {self.variables.shape}" 47 ) 48 if self.scores is not None: 49 assert len(self.scores.shape) == 1, f"'scores' must be 1D-array, not with shape {self.scores.shape}" 50 assert self.variables.shape[0] == self.scores.size, ( 51 f"count of objects ({self.variables.shape[0]}) " 52 f"must be equal to count of scores ({self.scores.size})" 53 ) 54 55 @property 56 def size(self) -> int: 57 return self.scores.size 58 59 @property 60 def dim_size(self) -> int: 61 return self.variables.shape[1] 62 63 def as_wide_matrix(self) -> array2D: 64 # should not be used in main code -- was needed for old versions 65 return union_to_matrix(self.variables, self.scores) 66 67 def save(self, path: PathLike): 68 mkdir_of_file(path) 69 np.savez(path, population=self.variables, scores=self.scores) 70 71 @staticmethod 72 def load(path: PathLike): 73 try: 74 st = np.load(path) 75 except Exception as err: 76 raise Exception( 77 f"if generation object is a string, " 78 f"it must be path to npz file with needed content, but raised exception {repr(err)}" 79 ) 80 81 assert 'population' in st and 'scores' in st, ( 82 "saved generation object must contain 'population' and 'scores' fields" 83 ) 84 85 return Generation(variables=st['population'], scores=st['scores']) 86 87 @staticmethod 88 def from_object( 89 dim: int, 90 obj: GenerationConvertible 91 ): 92 """class constructor""" 93 94 if isinstance(obj, np.ndarray): 95 96 assert len(obj.shape) == 2 and (obj.shape[1] == dim or obj.shape[1] == dim + 1), ( 97 f"if start_generation is numpy array, " 98 f"it must be with shape (samples, dim) or (samples, dim+1), not {obj.shape}" 99 ) 100 101 generation = Generation(obj, None) if obj.shape[1] == dim else Generation.from_pop_matrix(obj) 102 103 elif isinstance(obj, tuple): 104 105 assert len(obj) == 2, ( 106 f"if start_generation is tuple, " 107 f"it must be tuple with 2 components, not {len(obj)}" 108 ) 109 110 variables, scores = obj 111 112 assert (variables is None or scores is None) or (variables.shape[0] == scores.size), ( 113 "start_generation object must contain variables and scores components " 114 "which are None or 2D- and 1D-arrays with same shape" 115 ) 116 117 generation = Generation(variables=variables, scores=scores) 118 119 elif isinstance(obj, dict): 120 assert ( 121 ('variables' in obj and 'scores' in obj) and 122 ( 123 (obj['variables'] is None or obj['scores'] is None) or 124 (obj['variables'].shape[0] == obj['scores'].size) 125 ) 126 ), ( 127 "start_generation object must contain 'variables' and 'scores' keys " 128 "which are None or 2D- and 1D-arrays with same shape" 129 ) 130 131 generation = Generation(variables=obj['variables'], scores=obj['scores']) 132 133 elif isinstance(obj, Generation): 134 generation = Generation(variables=obj['variables'], scores=obj['scores']) 135 else: 136 137 path = str(obj) 138 if not os.path.exists(path): 139 raise TypeError( 140 f"invalid type of generation! " 141 f"Must be in (Union[str, Dict[str, np.ndarray], Generation, np.ndarray, " 142 f"Tuple[Optional[np.ndarray], Optional[np.ndarray]]]), " 143 f"not {type(obj)}" 144 ) 145 generation = Generation.load(path) 146 147 generation._check_dims() 148 149 if generation.variables is not None: 150 assert generation.dim_size == dim, ( 151 f"generation dimension size {generation.dim_size} does not equal to target size {dim}" 152 ) 153 154 return generation 155 156 @staticmethod 157 def from_pop_matrix(pop: array2D): 158 import warnings 159 warnings.warn( 160 "depricated! pop matrix style will be removed at version 7, " 161 "use samples and scores separetly" 162 ) 163 return Generation( 164 variables=pop[:, :-1], 165 scores=pop[:, -1] 166 )
wrapper on generation object (pair of samples matrix and samples scores vector)
Generation( variables: Union[numpy.ndarray, NoneType] = None, scores: Union[numpy.ndarray, NoneType] = None)
@staticmethod
def
load(path: Union[str, os.PathLike]):
71 @staticmethod 72 def load(path: PathLike): 73 try: 74 st = np.load(path) 75 except Exception as err: 76 raise Exception( 77 f"if generation object is a string, " 78 f"it must be path to npz file with needed content, but raised exception {repr(err)}" 79 ) 80 81 assert 'population' in st and 'scores' in st, ( 82 "saved generation object must contain 'population' and 'scores' fields" 83 ) 84 85 return Generation(variables=st['population'], scores=st['scores'])
@staticmethod
def
from_object( dim: int, obj: Union[Generation, str, Dict[Literal['population', 'scores'], numpy.ndarray], numpy.ndarray, Tuple[Union[numpy.ndarray, NoneType], Union[numpy.ndarray, NoneType]]]):
87 @staticmethod 88 def from_object( 89 dim: int, 90 obj: GenerationConvertible 91 ): 92 """class constructor""" 93 94 if isinstance(obj, np.ndarray): 95 96 assert len(obj.shape) == 2 and (obj.shape[1] == dim or obj.shape[1] == dim + 1), ( 97 f"if start_generation is numpy array, " 98 f"it must be with shape (samples, dim) or (samples, dim+1), not {obj.shape}" 99 ) 100 101 generation = Generation(obj, None) if obj.shape[1] == dim else Generation.from_pop_matrix(obj) 102 103 elif isinstance(obj, tuple): 104 105 assert len(obj) == 2, ( 106 f"if start_generation is tuple, " 107 f"it must be tuple with 2 components, not {len(obj)}" 108 ) 109 110 variables, scores = obj 111 112 assert (variables is None or scores is None) or (variables.shape[0] == scores.size), ( 113 "start_generation object must contain variables and scores components " 114 "which are None or 2D- and 1D-arrays with same shape" 115 ) 116 117 generation = Generation(variables=variables, scores=scores) 118 119 elif isinstance(obj, dict): 120 assert ( 121 ('variables' in obj and 'scores' in obj) and 122 ( 123 (obj['variables'] is None or obj['scores'] is None) or 124 (obj['variables'].shape[0] == obj['scores'].size) 125 ) 126 ), ( 127 "start_generation object must contain 'variables' and 'scores' keys " 128 "which are None or 2D- and 1D-arrays with same shape" 129 ) 130 131 generation = Generation(variables=obj['variables'], scores=obj['scores']) 132 133 elif isinstance(obj, Generation): 134 generation = Generation(variables=obj['variables'], scores=obj['scores']) 135 else: 136 137 path = str(obj) 138 if not os.path.exists(path): 139 raise TypeError( 140 f"invalid type of generation! " 141 f"Must be in (Union[str, Dict[str, np.ndarray], Generation, np.ndarray, " 142 f"Tuple[Optional[np.ndarray], Optional[np.ndarray]]]), " 143 f"not {type(obj)}" 144 ) 145 generation = Generation.load(path) 146 147 generation._check_dims() 148 149 if generation.variables is not None: 150 assert generation.dim_size == dim, ( 151 f"generation dimension size {generation.dim_size} does not equal to target size {dim}" 152 ) 153 154 return generation
class constructor