eckity.algorithms.simple_evolution

This module implements the SimpleEvolution class.

  1"""
  2This module implements the SimpleEvolution class.
  3"""
  4
  5from time import time
  6from overrides import overrides
  7
  8from eckity.algorithms.algorithm import Algorithm
  9from eckity.breeders.simple_breeder import SimpleBreeder
 10from eckity.evaluators.simple_population_evaluator import SimplePopulationEvaluator
 11from eckity.termination_checkers.threshold_from_target_termination_checker \
 12	import ThresholdFromTargetTerminationChecker
 13
 14
 15class SimpleEvolution(Algorithm):
 16	"""
 17	Simple case evolutionary algorithm.
 18
 19	Basic evolutionary algorithm that contains one subpopulation.
 20	Does not include and is not meant for multi-objective, co-evolution etc.
 21
 22	Parameters
 23	----------
 24	population: Population
 25		The population to be evolved. Contains only one subpopulation in simple case.
 26		Consists of a list of individuals.
 27
 28	statistics: Statistics or list of Statistics, default=None
 29		Provide multiple statistics on the population during the evolutionary run.
 30
 31	breeder: SimpleBreeder, default=SimpleBreeder instance
 32		Responsible for applying the selection method and operator sequence on the individuals
 33		in each generation. Applies on one subpopulation in simple case.
 34
 35	population_evaluator: SimplePopulationEvaluator, default=SimplePopulationEvaluator instance
 36		Responsible for evaluating each individual's fitness concurrently and returns the best individual
 37		of each subpopulation (returns a single individual in simple case).
 38
 39	max_generation: int, default=1000
 40		Maximal number of generations to run the evolutionary process.
 41		Note the evolution could end before reaching max_generation, depending on the termination checker.
 42
 43	events: dict(str, dict(object, function)), default=None
 44		Dictionary of events, where each event holds a dictionary of (subscriber, callback method).
 45
 46	event_names: list of strings, default=None
 47		Names of events to publish during the evolution.
 48
 49	termination_checker: TerminationChecker, default=ThresholdFromTargetTerminationChecker()
 50		Responsible for checking if the algorithm should finish before reaching max_generation.
 51
 52	max_workers: int, default=None
 53		Maximal number of worker nodes for the Executor object that evaluates the fitness of the individuals.
 54
 55	random_generator: module, default=random
 56		Random generator module.
 57
 58	random_seed: float or int, default=current system time
 59		Random seed for deterministic experiment.
 60
 61	generation_seed: int, default=None
 62		Current generation seed. Useful for resuming a previously paused experiment.
 63
 64	best_of_run_: Individual, default=None
 65		The individual that has the best fitness in the entire evolutionary run.
 66
 67	best_of_gen: Individual, default=None
 68		The individual that has the best fitness in the current generation.
 69
 70	worst_of_gen: Individual, default=None
 71		The individual that has the worst fitness in the current generation.
 72
 73	generation_num: int, default=0
 74		Current generation number
 75	"""
 76
 77	def __init__(self,
 78				 population,
 79				 statistics=None,
 80				 breeder=SimpleBreeder(),
 81				 population_evaluator=SimplePopulationEvaluator(),
 82				 max_generation=500,
 83				 events=None,
 84				 event_names=None,
 85				 termination_checker=ThresholdFromTargetTerminationChecker(threshold=0),
 86				 executor='thread',
 87				 max_workers=None,
 88				 random_generator=None,
 89				 random_seed=time(),
 90				 generation_seed=None,
 91				 best_of_run_=None,
 92				 best_of_gen=None,
 93				 worst_of_gen=None,
 94				 generation_num=0):
 95		
 96		if event_names is None:
 97			_event_names = ['before_eval', 'after_eval', 'before_breeding', 'after_breeding']
 98		else:
 99			_event_names = event_names
100
101		if statistics is None:
102			statistics = []
103
104		super().__init__(population, statistics=statistics, breeder=breeder, population_evaluator=population_evaluator,
105						 events=events, event_names=_event_names, executor=executor, max_workers=max_workers,
106						 random_generator=random_generator, random_seed=random_seed, generation_seed=generation_seed,
107						 termination_checker=termination_checker, generation_num=generation_num)
108
109		self.termination_checker = termination_checker
110		self.best_of_run_ = best_of_run_
111		self.best_of_gen = best_of_gen
112		self.worst_of_gen = worst_of_gen
113		self.max_generation = max_generation
114
115		self.final_generation_ = None
116
117	def initialize(self):
118		"""
119		Initialize the evolutionary algorithm
120
121		Register statistics to `after_generation` event
122		"""
123		super().initialize()
124		for stat in self.statistics:
125			self.register('after_generation', stat.write_statistics)
126
127	@overrides
128	def generation_iteration(self, gen):
129		"""
130		Performs one iteration of the evolutionary run, for the current generation
131
132		Parameters
133		----------
134		gen:
135			current generation number (for example, generation #100)
136
137		Returns
138		-------
139		None.
140		"""
141
142		# breed population
143		self.breeder.breed(self.population)
144
145		# Evaluate the entire population and get the best individual
146		self.best_of_gen = self.population_evaluator.act(self.population)
147
148		if self.best_of_gen.better_than(self.best_of_run_):
149			self.best_of_run_ = self.best_of_gen
150
151		self.worst_of_gen = self.population.sub_populations[0].get_worst_individual()
152
153	def execute(self, **kwargs):
154		"""
155		Compute output using best evolved individual.
156		Use `execute` in a non-sklearn setting.
157		Input keyword arguments that set variable values.
158		For example if `terminal_set=['x', 'y', 1, -1]` then call `execute(x=..., y=...)`.
159
160		Parameters
161		----------
162		**kwargs : keyword arguments
163			The input to the program (tree).
164
165		Returns
166		-------
167		object
168			Output as computed by the best individual of the evolutionary run.
169
170		"""
171		return self.best_of_run_.execute(**kwargs)
172
173	def finish(self):
174		"""
175		Finish the evolutionary run by showing the best individual and printing the best fitness
176		"""
177		# todo should move to finisher
178		self.best_of_run_.show()
179
180	def get_individual_evaluator(self):
181		return self.population.sub_populations[0].evaluator
182
183	def get_average_fitness(self):  # TODO check if it should be here or register statistic to breeder or sub pop
184		return self.population.get_average_fitness()
185
186	def event_name_to_data(self, event_name):
187		if event_name == "init":
188			return {
189				"population": self.population,
190				"statistics": self.statistics,
191				"breeder": self.breeder,
192				"termination_checker": self.termination_checker,
193				"max_generation": self.max_generation,
194				"events": self.events,
195				"max_workers": self.max_workers
196			}
197
198		# default case
199		return {
200			"population": self.population,
201			"best_of_run_": self.best_of_run_,
202			"best_of_gen": self.best_of_gen,
203			"generation_num": self.generation_num
204		}
205	
class SimpleEvolution(eckity.algorithms.algorithm.Algorithm):
 16class SimpleEvolution(Algorithm):
 17	"""
 18	Simple case evolutionary algorithm.
 19
 20	Basic evolutionary algorithm that contains one subpopulation.
 21	Does not include and is not meant for multi-objective, co-evolution etc.
 22
 23	Parameters
 24	----------
 25	population: Population
 26		The population to be evolved. Contains only one subpopulation in simple case.
 27		Consists of a list of individuals.
 28
 29	statistics: Statistics or list of Statistics, default=None
 30		Provide multiple statistics on the population during the evolutionary run.
 31
 32	breeder: SimpleBreeder, default=SimpleBreeder instance
 33		Responsible for applying the selection method and operator sequence on the individuals
 34		in each generation. Applies on one subpopulation in simple case.
 35
 36	population_evaluator: SimplePopulationEvaluator, default=SimplePopulationEvaluator instance
 37		Responsible for evaluating each individual's fitness concurrently and returns the best individual
 38		of each subpopulation (returns a single individual in simple case).
 39
 40	max_generation: int, default=1000
 41		Maximal number of generations to run the evolutionary process.
 42		Note the evolution could end before reaching max_generation, depending on the termination checker.
 43
 44	events: dict(str, dict(object, function)), default=None
 45		Dictionary of events, where each event holds a dictionary of (subscriber, callback method).
 46
 47	event_names: list of strings, default=None
 48		Names of events to publish during the evolution.
 49
 50	termination_checker: TerminationChecker, default=ThresholdFromTargetTerminationChecker()
 51		Responsible for checking if the algorithm should finish before reaching max_generation.
 52
 53	max_workers: int, default=None
 54		Maximal number of worker nodes for the Executor object that evaluates the fitness of the individuals.
 55
 56	random_generator: module, default=random
 57		Random generator module.
 58
 59	random_seed: float or int, default=current system time
 60		Random seed for deterministic experiment.
 61
 62	generation_seed: int, default=None
 63		Current generation seed. Useful for resuming a previously paused experiment.
 64
 65	best_of_run_: Individual, default=None
 66		The individual that has the best fitness in the entire evolutionary run.
 67
 68	best_of_gen: Individual, default=None
 69		The individual that has the best fitness in the current generation.
 70
 71	worst_of_gen: Individual, default=None
 72		The individual that has the worst fitness in the current generation.
 73
 74	generation_num: int, default=0
 75		Current generation number
 76	"""
 77
 78	def __init__(self,
 79				 population,
 80				 statistics=None,
 81				 breeder=SimpleBreeder(),
 82				 population_evaluator=SimplePopulationEvaluator(),
 83				 max_generation=500,
 84				 events=None,
 85				 event_names=None,
 86				 termination_checker=ThresholdFromTargetTerminationChecker(threshold=0),
 87				 executor='thread',
 88				 max_workers=None,
 89				 random_generator=None,
 90				 random_seed=time(),
 91				 generation_seed=None,
 92				 best_of_run_=None,
 93				 best_of_gen=None,
 94				 worst_of_gen=None,
 95				 generation_num=0):
 96		
 97		if event_names is None:
 98			_event_names = ['before_eval', 'after_eval', 'before_breeding', 'after_breeding']
 99		else:
100			_event_names = event_names
101
102		if statistics is None:
103			statistics = []
104
105		super().__init__(population, statistics=statistics, breeder=breeder, population_evaluator=population_evaluator,
106						 events=events, event_names=_event_names, executor=executor, max_workers=max_workers,
107						 random_generator=random_generator, random_seed=random_seed, generation_seed=generation_seed,
108						 termination_checker=termination_checker, generation_num=generation_num)
109
110		self.termination_checker = termination_checker
111		self.best_of_run_ = best_of_run_
112		self.best_of_gen = best_of_gen
113		self.worst_of_gen = worst_of_gen
114		self.max_generation = max_generation
115
116		self.final_generation_ = None
117
118	def initialize(self):
119		"""
120		Initialize the evolutionary algorithm
121
122		Register statistics to `after_generation` event
123		"""
124		super().initialize()
125		for stat in self.statistics:
126			self.register('after_generation', stat.write_statistics)
127
128	@overrides
129	def generation_iteration(self, gen):
130		"""
131		Performs one iteration of the evolutionary run, for the current generation
132
133		Parameters
134		----------
135		gen:
136			current generation number (for example, generation #100)
137
138		Returns
139		-------
140		None.
141		"""
142
143		# breed population
144		self.breeder.breed(self.population)
145
146		# Evaluate the entire population and get the best individual
147		self.best_of_gen = self.population_evaluator.act(self.population)
148
149		if self.best_of_gen.better_than(self.best_of_run_):
150			self.best_of_run_ = self.best_of_gen
151
152		self.worst_of_gen = self.population.sub_populations[0].get_worst_individual()
153
154	def execute(self, **kwargs):
155		"""
156		Compute output using best evolved individual.
157		Use `execute` in a non-sklearn setting.
158		Input keyword arguments that set variable values.
159		For example if `terminal_set=['x', 'y', 1, -1]` then call `execute(x=..., y=...)`.
160
161		Parameters
162		----------
163		**kwargs : keyword arguments
164			The input to the program (tree).
165
166		Returns
167		-------
168		object
169			Output as computed by the best individual of the evolutionary run.
170
171		"""
172		return self.best_of_run_.execute(**kwargs)
173
174	def finish(self):
175		"""
176		Finish the evolutionary run by showing the best individual and printing the best fitness
177		"""
178		# todo should move to finisher
179		self.best_of_run_.show()
180
181	def get_individual_evaluator(self):
182		return self.population.sub_populations[0].evaluator
183
184	def get_average_fitness(self):  # TODO check if it should be here or register statistic to breeder or sub pop
185		return self.population.get_average_fitness()
186
187	def event_name_to_data(self, event_name):
188		if event_name == "init":
189			return {
190				"population": self.population,
191				"statistics": self.statistics,
192				"breeder": self.breeder,
193				"termination_checker": self.termination_checker,
194				"max_generation": self.max_generation,
195				"events": self.events,
196				"max_workers": self.max_workers
197			}
198
199		# default case
200		return {
201			"population": self.population,
202			"best_of_run_": self.best_of_run_,
203			"best_of_gen": self.best_of_gen,
204			"generation_num": self.generation_num
205		}

Simple case evolutionary algorithm.

Basic evolutionary algorithm that contains one subpopulation. Does not include and is not meant for multi-objective, co-evolution etc.

Parameters
  • population (Population): The population to be evolved. Contains only one subpopulation in simple case. Consists of a list of individuals.
  • statistics (Statistics or list of Statistics, default=None): Provide multiple statistics on the population during the evolutionary run.
  • breeder (SimpleBreeder, default=SimpleBreeder instance): Responsible for applying the selection method and operator sequence on the individuals in each generation. Applies on one subpopulation in simple case.
  • population_evaluator (SimplePopulationEvaluator, default=SimplePopulationEvaluator instance): Responsible for evaluating each individual's fitness concurrently and returns the best individual of each subpopulation (returns a single individual in simple case).
  • max_generation (int, default=1000): Maximal number of generations to run the evolutionary process. Note the evolution could end before reaching max_generation, depending on the termination checker.
  • events (dict(str, dict(object, function)), default=None): Dictionary of events, where each event holds a dictionary of (subscriber, callback method).
  • event_names (list of strings, default=None): Names of events to publish during the evolution.
  • termination_checker (TerminationChecker, default=ThresholdFromTargetTerminationChecker()): Responsible for checking if the algorithm should finish before reaching max_generation.
  • max_workers (int, default=None): Maximal number of worker nodes for the Executor object that evaluates the fitness of the individuals.
  • random_generator (module, default=random): Random generator module.
  • random_seed (float or int, default=current system time): Random seed for deterministic experiment.
  • generation_seed (int, default=None): Current generation seed. Useful for resuming a previously paused experiment.
  • best_of_run_ (Individual, default=None): The individual that has the best fitness in the entire evolutionary run.
  • best_of_gen (Individual, default=None): The individual that has the best fitness in the current generation.
  • worst_of_gen (Individual, default=None): The individual that has the worst fitness in the current generation.
  • generation_num (int, default=0): Current generation number
SimpleEvolution( population, statistics=None, breeder=<eckity.breeders.simple_breeder.SimpleBreeder object>, population_evaluator=<eckity.evaluators.simple_population_evaluator.SimplePopulationEvaluator object>, max_generation=500, events=None, event_names=None, termination_checker=<eckity.termination_checkers.threshold_from_target_termination_checker.ThresholdFromTargetTerminationChecker object>, executor='thread', max_workers=None, random_generator=None, random_seed=1688113158.6392407, generation_seed=None, best_of_run_=None, best_of_gen=None, worst_of_gen=None, generation_num=0)
 78	def __init__(self,
 79				 population,
 80				 statistics=None,
 81				 breeder=SimpleBreeder(),
 82				 population_evaluator=SimplePopulationEvaluator(),
 83				 max_generation=500,
 84				 events=None,
 85				 event_names=None,
 86				 termination_checker=ThresholdFromTargetTerminationChecker(threshold=0),
 87				 executor='thread',
 88				 max_workers=None,
 89				 random_generator=None,
 90				 random_seed=time(),
 91				 generation_seed=None,
 92				 best_of_run_=None,
 93				 best_of_gen=None,
 94				 worst_of_gen=None,
 95				 generation_num=0):
 96		
 97		if event_names is None:
 98			_event_names = ['before_eval', 'after_eval', 'before_breeding', 'after_breeding']
 99		else:
100			_event_names = event_names
101
102		if statistics is None:
103			statistics = []
104
105		super().__init__(population, statistics=statistics, breeder=breeder, population_evaluator=population_evaluator,
106						 events=events, event_names=_event_names, executor=executor, max_workers=max_workers,
107						 random_generator=random_generator, random_seed=random_seed, generation_seed=generation_seed,
108						 termination_checker=termination_checker, generation_num=generation_num)
109
110		self.termination_checker = termination_checker
111		self.best_of_run_ = best_of_run_
112		self.best_of_gen = best_of_gen
113		self.worst_of_gen = worst_of_gen
114		self.max_generation = max_generation
115
116		self.final_generation_ = None
termination_checker
best_of_run_
best_of_gen
worst_of_gen
max_generation
final_generation_
def initialize(self):
118	def initialize(self):
119		"""
120		Initialize the evolutionary algorithm
121
122		Register statistics to `after_generation` event
123		"""
124		super().initialize()
125		for stat in self.statistics:
126			self.register('after_generation', stat.write_statistics)

Initialize the evolutionary algorithm

Register statistics to after_generation event

@overrides
def generation_iteration(self, gen):
128	@overrides
129	def generation_iteration(self, gen):
130		"""
131		Performs one iteration of the evolutionary run, for the current generation
132
133		Parameters
134		----------
135		gen:
136			current generation number (for example, generation #100)
137
138		Returns
139		-------
140		None.
141		"""
142
143		# breed population
144		self.breeder.breed(self.population)
145
146		# Evaluate the entire population and get the best individual
147		self.best_of_gen = self.population_evaluator.act(self.population)
148
149		if self.best_of_gen.better_than(self.best_of_run_):
150			self.best_of_run_ = self.best_of_gen
151
152		self.worst_of_gen = self.population.sub_populations[0].get_worst_individual()

Performs one iteration of the evolutionary run, for the current generation

Parameters
  • gen:: current generation number (for example, generation #100)
Returns
  • None.
def execute(self, **kwargs):
154	def execute(self, **kwargs):
155		"""
156		Compute output using best evolved individual.
157		Use `execute` in a non-sklearn setting.
158		Input keyword arguments that set variable values.
159		For example if `terminal_set=['x', 'y', 1, -1]` then call `execute(x=..., y=...)`.
160
161		Parameters
162		----------
163		**kwargs : keyword arguments
164			The input to the program (tree).
165
166		Returns
167		-------
168		object
169			Output as computed by the best individual of the evolutionary run.
170
171		"""
172		return self.best_of_run_.execute(**kwargs)

Compute output using best evolved individual. Use execute in a non-sklearn setting. Input keyword arguments that set variable values. For example if terminal_set=['x', 'y', 1, -1] then call execute(x=..., y=...).

Parameters
  • **kwargs (keyword arguments): The input to the program (tree).
Returns
  • object: Output as computed by the best individual of the evolutionary run.
def finish(self):
174	def finish(self):
175		"""
176		Finish the evolutionary run by showing the best individual and printing the best fitness
177		"""
178		# todo should move to finisher
179		self.best_of_run_.show()

Finish the evolutionary run by showing the best individual and printing the best fitness

def get_individual_evaluator(self):
181	def get_individual_evaluator(self):
182		return self.population.sub_populations[0].evaluator
def get_average_fitness(self):
184	def get_average_fitness(self):  # TODO check if it should be here or register statistic to breeder or sub pop
185		return self.population.get_average_fitness()
def event_name_to_data(self, event_name):
187	def event_name_to_data(self, event_name):
188		if event_name == "init":
189			return {
190				"population": self.population,
191				"statistics": self.statistics,
192				"breeder": self.breeder,
193				"termination_checker": self.termination_checker,
194				"max_generation": self.max_generation,
195				"events": self.events,
196				"max_workers": self.max_workers
197			}
198
199		# default case
200		return {
201			"population": self.population,
202			"best_of_run_": self.best_of_run_,
203			"best_of_gen": self.best_of_gen,
204			"generation_num": self.generation_num
205		}

Convert a given event name to relevant data of the Algorithm for the event

Parameters
  • event_name (string): name of the event that is happening
Returns
  • dict: Algorithm data regarding the given event