20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126 | class Solution:
"""
Class representing a solution in a genetic algorithm.
It contains the variables, objectives, constraints, and fitness of the solution.
"""
def __init__(
self,
variables: Optional[Iterable] = [],
objectives: Optional[Iterable] = [],
constraints: Optional[Iterable] = [],
fitness: np.float64 = np.float64(0.0),
dtype=np.uint32,
otype=np.float64,
):
"""Creates a new solution object.
The variables is a numpy array of the solution's genes.
The objectives and constraints are numpy arrays of the solution's objectives and constraints.
The fitness is a float representing the solution's fitness value.
Args:
variables (Optional[Iterable], optional): Tuple or any other iterable with the variables/variables. Defaults to None.
objectives (Optional[Iterable], optional): Tuple or any other iterable with the objectives values. Defaults to None.
constraints (Optional[Iterable], optional): Tuple or any other iterable with the constraint values. Defaults to None.
fitness (float, optional): Fitness of the solution. Defaults to 0.0.
"""
self._otype = otype
self._dtype = dtype
self.variables = np.asarray(variables, dtype=self.dtype)
self.objectives = np.array(objectives, dtype=self.otype)
self.constraints = np.array(constraints, dtype=self.otype)
self.fitness = otype(fitness)
@property
def dtype(self):
return self._dtype
@property
def otype(self):
return self._otype
def clone(self) -> Self:
"""Returns a deep copy of the solution. It is more efficient than using the copy module.
Returns:
Self: Solution object
"""
return Solution(
variables=list(self.variables),
objectives=list(self.objectives),
constraints=list(self.constraints),
fitness=self.fitness,
otype=self.otype,
)
def clone_with(self, **overrides):
"""Clones an Instance with overriden attributes
Returns:
Instance
"""
new_object = self.clone()
for key, value in overrides.items():
setattr(new_object, key, value)
return new_object
def __str__(self) -> str:
return f"Solution(dim={len(self.variables)},f={self.fitness},objs={self.objectives},const={self.constraints})"
def __repr__(self) -> str:
return f"Solution<dim={len(self.variables)},f={self.fitness},objs={self.objectives},const={self.constraints}>"
def __len__(self) -> int:
return len(self.variables)
def __iter__(self):
return iter(self.variables)
def __bool__(self):
return len(self) != 0
def __eq__(self, other) -> bool:
if isinstance(other, Solution):
try:
return all(a == b for a, b in zip(self, other, strict=True))
except ValueError:
return False
else:
return NotImplemented
def __gt__(self, other):
if not isinstance(other, Solution):
msg = f"Other of type {other.__class__.__name__} can not be compared with with {self.__class__.__name__}"
print(msg)
return NotImplemented
return self.fitness > other.fitness
def __getitem__(self, key):
if isinstance(key, slice):
cls = type(self) # To facilitate subclassing
return cls(self.variables[key])
index = operator.index(key)
return self.variables[index]
def __setitem__(self, key, value):
self.variables[key] = value
|