eckity.multi_objective_evolution.nsga2_fitness
1from typing import List 2 3from overrides import overrides 4 5from eckity.fitness.fitness import Fitness 6from eckity.individual import Individual 7import random as rd 8 9 10class NSGA2Fitness(Fitness): 11 def __init__(self, 12 fitness: List[float] = None, 13 higher_is_better=False): 14 is_evaluated = fitness is not None 15 super().__init__(higher_is_better=higher_is_better, is_evaluated=is_evaluated) 16 self.fitness: List[float] = fitness # list of objectivs 17 self.crowding = 0 18 self.front_rank = float("inf") 19 if self.fitness!=None and type(self.higher_is_better) is bool: 20 self.higher_is_better = [self.higher_is_better] * len(fitness) 21 22 23 24 def set_fitness(self, fitness): 25 if self._is_evaluated: 26 raise AttributeError('fitness already evaluated and set to', self.fitness) 27 self.fitness = fitness 28 self._is_evaluated = True 29 if type(self.higher_is_better) is bool: 30 self.higher_is_better = [self.higher_is_better] * len(fitness) 31 32 @overrides 33 def get_pure_fitness(self): 34 if not self._is_evaluated: 35 raise ValueError('Fitness not evaluated yet') 36 return self.fitness 37 38 @overrides 39 def set_not_evaluated(self): 40 self._is_evaluated = False 41 self.fitness = None 42 self.crowding = 0 43 self.front_rank = float("inf") 44 45 def check_comparable_fitnesses(self, other_fitness: Fitness, ind: Individual, other_ind: Individual): 46 if not isinstance(other_fitness, NSGA2Fitness): 47 raise TypeError('Expected NSGA2Fitness object in better_than, got', type(other_fitness)) 48 if not self.is_fitness_evaluated() or not other_fitness.is_fitness_evaluated(): 49 raise ValueError('Fitnesses must be evaluated before comparison') 50 if len(other_fitness.get_augmented_fitness(other_ind)) != len(self.get_augmented_fitness(ind)): 51 raise ValueError('Fitnesses must be of the same lngth') 52 53 def better_than(self, ind, other_fitness, other_ind): 54 ''' 55 56 Parameters 57 ---------- 58 ind:Individual 59 other_fitness:NSGA2Fitness 60 other_ind:Individual 61 62 Returns : True ind has lower rank or equal rank and bigger crwoding value 63 ------- 64 65 ''' 66 if self.front_rank == float("inf"): # first iteration 67 return bool(rd.getrandbits(1)) # random true false 68 else: 69 self.check_comparable_fitnesses(other_fitness, ind, other_ind) 70 if self.front_rank == other_ind.fitness.front_rank: 71 return self.crowding > other_ind.fitness.crowding 72 return self.front_rank > other_ind.fitness.front_rank 73 74 def equal_to(self, ind, other_fitness, other_ind): 75 return self.front_rank == other_ind.fitness.front_rank and \ 76 self.crowding == other_ind.fitness.crowding 77 78 def dominate(self, ind, other_fitness, other_ind): 79 self.check_comparable_fitnesses(other_fitness, ind, other_ind) 80 self_fit = self.get_augmented_fitness(ind) 81 other_fit = other_fitness.get_augmented_fitness(other_ind) 82 return all([self._o1_at_least_o2(o1, o2, h_is_b) for h_is_b, o1, o2 in 83 zip(self.higher_is_better, self_fit, other_fit)]) and \ 84 any([self._o1_better_then_o2(o1, o2, h_is_b) for h_is_b, o1, o2 in 85 zip(self.higher_is_better, self_fit, other_fit)]) 86 87 def _o1_at_least_o2(self, o1, o2, higher_is_better): 88 ''' 89 90 Parameters 91 ---------- 92 o1: objective i of individual 1 93 o2: objective i of individual 2 94 higher_is_better :boolean - is higher better for objective i of he fitness ? 95 96 Returns :x1 >= x2 or x1 <= x2 according to higher is better 97 ------- 98 99 ''' 100 if higher_is_better: 101 return o1 >= o2 102 else: 103 return o1 <= o2 104 105 def _o1_better_then_o2(self, o1, o2, higher_is_better): 106 ''' 107 108 Parameters 109 ---------- 110 o1: objective i of individual 1 111 o2: objective i of individual 2 112 higher_is_better :boolean - is higher better for objective i of he fitness ? 113 114 Returns :x1 > x2 or x1 < x2 according to higher is better 115 ------- 116 117 ''' 118 if higher_is_better: 119 return o1 > o2 120 else: 121 return o1 < o2 122 123 # def equal_to(self, ind, other_fitness, other_ind): 124 # self.check_comparable_fitnesses(other_fitness,ind,other_ind) 125 # self_fit = self.get_augmented_fitness(ind) 126 # other_fit = other_fitness.get_augmented_fitness(other_ind) 127 # all([x1 == x2 for x1, x2 in zip(self_fit, other_fit)]) 128 129 def __getstate__(self): 130 state = self.__dict__.copy() 131 if not self.should_cache_between_gens: 132 state['_is_evaluated'] = False 133 state['fitness'] = None 134 return state
11class NSGA2Fitness(Fitness): 12 def __init__(self, 13 fitness: List[float] = None, 14 higher_is_better=False): 15 is_evaluated = fitness is not None 16 super().__init__(higher_is_better=higher_is_better, is_evaluated=is_evaluated) 17 self.fitness: List[float] = fitness # list of objectivs 18 self.crowding = 0 19 self.front_rank = float("inf") 20 if self.fitness!=None and type(self.higher_is_better) is bool: 21 self.higher_is_better = [self.higher_is_better] * len(fitness) 22 23 24 25 def set_fitness(self, fitness): 26 if self._is_evaluated: 27 raise AttributeError('fitness already evaluated and set to', self.fitness) 28 self.fitness = fitness 29 self._is_evaluated = True 30 if type(self.higher_is_better) is bool: 31 self.higher_is_better = [self.higher_is_better] * len(fitness) 32 33 @overrides 34 def get_pure_fitness(self): 35 if not self._is_evaluated: 36 raise ValueError('Fitness not evaluated yet') 37 return self.fitness 38 39 @overrides 40 def set_not_evaluated(self): 41 self._is_evaluated = False 42 self.fitness = None 43 self.crowding = 0 44 self.front_rank = float("inf") 45 46 def check_comparable_fitnesses(self, other_fitness: Fitness, ind: Individual, other_ind: Individual): 47 if not isinstance(other_fitness, NSGA2Fitness): 48 raise TypeError('Expected NSGA2Fitness object in better_than, got', type(other_fitness)) 49 if not self.is_fitness_evaluated() or not other_fitness.is_fitness_evaluated(): 50 raise ValueError('Fitnesses must be evaluated before comparison') 51 if len(other_fitness.get_augmented_fitness(other_ind)) != len(self.get_augmented_fitness(ind)): 52 raise ValueError('Fitnesses must be of the same lngth') 53 54 def better_than(self, ind, other_fitness, other_ind): 55 ''' 56 57 Parameters 58 ---------- 59 ind:Individual 60 other_fitness:NSGA2Fitness 61 other_ind:Individual 62 63 Returns : True ind has lower rank or equal rank and bigger crwoding value 64 ------- 65 66 ''' 67 if self.front_rank == float("inf"): # first iteration 68 return bool(rd.getrandbits(1)) # random true false 69 else: 70 self.check_comparable_fitnesses(other_fitness, ind, other_ind) 71 if self.front_rank == other_ind.fitness.front_rank: 72 return self.crowding > other_ind.fitness.crowding 73 return self.front_rank > other_ind.fitness.front_rank 74 75 def equal_to(self, ind, other_fitness, other_ind): 76 return self.front_rank == other_ind.fitness.front_rank and \ 77 self.crowding == other_ind.fitness.crowding 78 79 def dominate(self, ind, other_fitness, other_ind): 80 self.check_comparable_fitnesses(other_fitness, ind, other_ind) 81 self_fit = self.get_augmented_fitness(ind) 82 other_fit = other_fitness.get_augmented_fitness(other_ind) 83 return all([self._o1_at_least_o2(o1, o2, h_is_b) for h_is_b, o1, o2 in 84 zip(self.higher_is_better, self_fit, other_fit)]) and \ 85 any([self._o1_better_then_o2(o1, o2, h_is_b) for h_is_b, o1, o2 in 86 zip(self.higher_is_better, self_fit, other_fit)]) 87 88 def _o1_at_least_o2(self, o1, o2, higher_is_better): 89 ''' 90 91 Parameters 92 ---------- 93 o1: objective i of individual 1 94 o2: objective i of individual 2 95 higher_is_better :boolean - is higher better for objective i of he fitness ? 96 97 Returns :x1 >= x2 or x1 <= x2 according to higher is better 98 ------- 99 100 ''' 101 if higher_is_better: 102 return o1 >= o2 103 else: 104 return o1 <= o2 105 106 def _o1_better_then_o2(self, o1, o2, higher_is_better): 107 ''' 108 109 Parameters 110 ---------- 111 o1: objective i of individual 1 112 o2: objective i of individual 2 113 higher_is_better :boolean - is higher better for objective i of he fitness ? 114 115 Returns :x1 > x2 or x1 < x2 according to higher is better 116 ------- 117 118 ''' 119 if higher_is_better: 120 return o1 > o2 121 else: 122 return o1 < o2 123 124 # def equal_to(self, ind, other_fitness, other_ind): 125 # self.check_comparable_fitnesses(other_fitness,ind,other_ind) 126 # self_fit = self.get_augmented_fitness(ind) 127 # other_fit = other_fitness.get_augmented_fitness(other_ind) 128 # all([x1 == x2 for x1, x2 in zip(self_fit, other_fit)]) 129 130 def __getstate__(self): 131 state = self.__dict__.copy() 132 if not self.should_cache_between_gens: 133 state['_is_evaluated'] = False 134 state['fitness'] = None 135 return state
This class is responsible for handling the fitness score of some Individual (checking if fitness is evaluated, comparing fitness scores with other individuals etc.)
context: list of Individuals individuals involved in calculating the fitness (co-evolution)
trials: list of floats fitness results for previous trials done to calculate fitness (co-evolution)
_is_evaluated: bool declares if fitness score is evaluated and updated in the current generation
is_relative_fitness: bool declares whether the fitness score is absolute or relative
should_cache_between_gens: bool declares whether the fitness score should reset at the end of each generation
higher_is_better: bool declares the fitness direction. i.e., if it should be minimized or maximized
12 def __init__(self, 13 fitness: List[float] = None, 14 higher_is_better=False): 15 is_evaluated = fitness is not None 16 super().__init__(higher_is_better=higher_is_better, is_evaluated=is_evaluated) 17 self.fitness: List[float] = fitness # list of objectivs 18 self.crowding = 0 19 self.front_rank = float("inf") 20 if self.fitness!=None and type(self.higher_is_better) is bool: 21 self.higher_is_better = [self.higher_is_better] * len(fitness)
25 def set_fitness(self, fitness): 26 if self._is_evaluated: 27 raise AttributeError('fitness already evaluated and set to', self.fitness) 28 self.fitness = fitness 29 self._is_evaluated = True 30 if type(self.higher_is_better) is bool: 31 self.higher_is_better = [self.higher_is_better] * len(fitness)
33 @overrides 34 def get_pure_fitness(self): 35 if not self._is_evaluated: 36 raise ValueError('Fitness not evaluated yet') 37 return self.fitness
Returns the pure fitness score of the individual (before applying balancing methods like bloat control)
39 @overrides 40 def set_not_evaluated(self): 41 self._is_evaluated = False 42 self.fitness = None 43 self.crowding = 0 44 self.front_rank = float("inf")
Set this fitness score status to be not evaluated
46 def check_comparable_fitnesses(self, other_fitness: Fitness, ind: Individual, other_ind: Individual): 47 if not isinstance(other_fitness, NSGA2Fitness): 48 raise TypeError('Expected NSGA2Fitness object in better_than, got', type(other_fitness)) 49 if not self.is_fitness_evaluated() or not other_fitness.is_fitness_evaluated(): 50 raise ValueError('Fitnesses must be evaluated before comparison') 51 if len(other_fitness.get_augmented_fitness(other_ind)) != len(self.get_augmented_fitness(ind)): 52 raise ValueError('Fitnesses must be of the same lngth')
54 def better_than(self, ind, other_fitness, other_ind): 55 ''' 56 57 Parameters 58 ---------- 59 ind:Individual 60 other_fitness:NSGA2Fitness 61 other_ind:Individual 62 63 Returns : True ind has lower rank or equal rank and bigger crwoding value 64 ------- 65 66 ''' 67 if self.front_rank == float("inf"): # first iteration 68 return bool(rd.getrandbits(1)) # random true false 69 else: 70 self.check_comparable_fitnesses(other_fitness, ind, other_ind) 71 if self.front_rank == other_ind.fitness.front_rank: 72 return self.crowding > other_ind.fitness.crowding 73 return self.front_rank > other_ind.fitness.front_rank
Parameters
ind (Individual):
other_fitness (NSGA2Fitness):
other_ind (Individual):
Returns (True ind has lower rank or equal rank and bigger crwoding value):
-------
75 def equal_to(self, ind, other_fitness, other_ind): 76 return self.front_rank == other_ind.fitness.front_rank and \ 77 self.crowding == other_ind.fitness.crowding
Compares between the current fitness of the individual ind
to the fitness score other_fitness
of other_ind
Parameters
- ind (Individual): the individual instance that holds this Fitness instance
- other_fitness (Fitness):
the Fitness instance of the
other
individual - other_ind (Individual):
the
other
individual instance which is being compared to the individualind
Returns
- bool: True if this fitness is equal to the
other
fitness, False otherwise
79 def dominate(self, ind, other_fitness, other_ind): 80 self.check_comparable_fitnesses(other_fitness, ind, other_ind) 81 self_fit = self.get_augmented_fitness(ind) 82 other_fit = other_fitness.get_augmented_fitness(other_ind) 83 return all([self._o1_at_least_o2(o1, o2, h_is_b) for h_is_b, o1, o2 in 84 zip(self.higher_is_better, self_fit, other_fit)]) and \ 85 any([self._o1_better_then_o2(o1, o2, h_is_b) for h_is_b, o1, o2 in 86 zip(self.higher_is_better, self_fit, other_fit)])