From 244207ef3d5e35974b4153931c28c3def90534c0 Mon Sep 17 00:00:00 2001 From: guimorg Date: Tue, 26 May 2020 14:02:23 -0300 Subject: [PATCH 01/10] Adding README as long_description --- setup.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/setup.py b/setup.py index eaee486..939cd1e 100644 --- a/setup.py +++ b/setup.py @@ -13,6 +13,9 @@ # Normalize version so `setup.py --version` show same version as twine. version = str(packaging.version.Version(version)) +with open("README.md", "r") as reader: + long_description = reader.read() + # Library dependencies INSTALL_REQUIRES = ["opencv-python==4.2.0.34", "numpy==1.18.4", "matplotlib==3.2.1", "scikit-image==0.17.2"] @@ -32,6 +35,7 @@ name="circle_evolution", version=version, description="Evolutionary Art Using Circles", + long_description=long_description, url="https://github.com/ahmedkhalf/Circle-Evolution/", packages=find_packages(), download_url="https://github.com/ahmedkhalf/Circle-Evolution/archive/v0.1.tar.gz", From e9b9b09a30c2ffcdd371647019ec5fee9fd63c83 Mon Sep 17 00:00:00 2001 From: guimorg Date: Wed, 27 May 2020 20:53:12 -0300 Subject: [PATCH 02/10] Adds observable Runner object --- circle_evolution/runner.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 circle_evolution/runner.py diff --git a/circle_evolution/runner.py b/circle_evolution/runner.py new file mode 100644 index 0000000..c15abd5 --- /dev/null +++ b/circle_evolution/runner.py @@ -0,0 +1,28 @@ +"""Base Class for Reported Objects. + +If you want to receive reports about any objects in Circle-Evolution you just +need to extend your class with the base Runner. It provides an interface for +attaching reporters and notifying all reporters of a particular event. +""" + + +class Runner: + """Base Runner class. + + The Runner class is responsible for managing reporters and sending events + to them. If you need to receive updates by a particular reporter you just + need to use this base class. + + Attributes: + _reporters: list of reporters that are going to receive reports. + """ + _reporters = [] + + def attach(self, reporter): + """Attaches reporter for notifications""" + self._reporters.append(reporter) + + def notify(self, report): + """Send report to all attached reporters""" + for reporter in self._reporters: + reporter.update(report) From 50045fd0b51ed07361a027454c61ef58de603592 Mon Sep 17 00:00:00 2001 From: guimorg Date: Wed, 27 May 2020 20:53:37 -0300 Subject: [PATCH 03/10] Adds base class for reporters - observers and a LoggerReporter --- circle_evolution/reporter.py | 85 ++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 circle_evolution/reporter.py diff --git a/circle_evolution/reporter.py b/circle_evolution/reporter.py new file mode 100644 index 0000000..c9523dc --- /dev/null +++ b/circle_evolution/reporter.py @@ -0,0 +1,85 @@ +"""Reporters for capturing events and notifying the user about them. + +You can make your own Reporter class or use the already implemented one's. +Notice the abstract class before implementing your Reporter to see which +functions should be implemented. +""" +from abc import ABC, abstractmethod + +import logging +import logging.config + + +class Reporter(ABC): + """Base Reporter class. + + The Reporter is responsible for capturing particular events and sending + them for visualization. Please, use this class if you want to implement + your own Reporter. + """ + def __init__(self): + """Initialization calls setup to configure Reporter""" + self.setup() + + def setup(self): + """Function for configuring the reporter. + + Some reporters may need configuring some internal parameters or even + creating objects to warmup. This function deals with this + """ + + @abstractmethod + def update(self, report): + """Receives report from subject. + + This is the main function for reporting events. The Reporter receives a + report and have to deal with what to do with that. For Circle-Evolution + you can expect anything from strings to `numpy.array`. + """ + + +class LoggerReporter(Reporter): + """Reporter for logging. + + This Reporter is responsible for setting up a Logger object and logging all + events that happened during circle-evolution cycle. Notice that this + reporter only cares about strings and will notify minimal details about + other types. + """ + def setup(self): + """Sets up Logger""" + config_initial = { + 'version': 1, + 'disable_existing_loggers': True, + 'formatters': { + 'simple': { + 'format': '%(asctime)s %(name)s %(message)s' + }, + }, + 'handlers': { + 'console': { + 'level': 'INFO', + 'class': 'logging.StreamHandler', + 'formatter': 'simple' + }, + }, + 'loggers': { + 'circle-evolution': { + 'handlers': ['console'], + 'level': 'DEBUG', + } + }, + 'root': { + 'handlers': ['console'], + 'level': 'DEBUG' + } + } + logging.config.dictConfig(config_initial) + self.logger = logging.getLogger(__name__) # Creating new logger + + def update(self, report): + """Logs events using logger""" + self.logger.debug("Received event...") + if isinstance(report, str): + # Only deals with string messages + self.logger.info(report) From f9fd45cb05b6d0c973b9b880824def1355a0e7c1 Mon Sep 17 00:00:00 2001 From: guimorg Date: Wed, 27 May 2020 20:54:08 -0300 Subject: [PATCH 04/10] Use of Runner and also notify --- circle_evolution/evolution.py | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/circle_evolution/evolution.py b/circle_evolution/evolution.py index 7aa7456..686bcd4 100644 --- a/circle_evolution/evolution.py +++ b/circle_evolution/evolution.py @@ -4,12 +4,14 @@ import numpy as np -from circle_evolution.species import Specie - import circle_evolution.fitness as fitness +from circle_evolution.runner import Runner + +from circle_evolution.species import Specie + -class Evolution: +class Evolution(Runner): """Logic for a Species Evolution. Use the Evolution class when you want to train a Specie to look like @@ -70,14 +72,6 @@ def mutate(self, specie): return new_specie - def print_progress(self, fit): - """Prints progress of Evolution. - - Args: - fit (float): fitness value of specie. - """ - print("GEN {}, FIT {:.8f}".format(self.generation, fit)) - def evolve(self, fitness=fitness.MSEFitness, max_generation=100000): """Genetic Algorithm for evolution. @@ -87,19 +81,22 @@ def evolve(self, fitness=fitness.MSEFitness, max_generation=100000): fitness (fitness.Fitness): fitness class to score species preformance. max_generation (int): amount of generations to train for. """ - fitness = fitness(self.target) + fitness_ = fitness(self.target) self.specie.render() - fit = fitness.score(self.specie.phenotype) + fit = fitness_.score(self.specie.phenotype) for i in range(max_generation): self.generation = i + 1 mutated = self.mutate(self.specie) mutated.render() - newfit = fitness.score(mutated.phenotype) + newfit = fitness_.score(mutated.phenotype) if newfit > fit: fit = newfit self.specie = mutated - self.print_progress(newfit) + self.notify( + f"Generation {self.generation}\t" + f"Fitness: {newfit}" + ) From db8b35d7bae687a60338a48378d9bb06c9c953ae Mon Sep 17 00:00:00 2001 From: guimorg Date: Wed, 27 May 2020 20:54:25 -0300 Subject: [PATCH 05/10] Attaches concrete Reporter --- circle_evolution/main.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/circle_evolution/main.py b/circle_evolution/main.py index 2afaa41..64cd626 100644 --- a/circle_evolution/main.py +++ b/circle_evolution/main.py @@ -8,6 +8,8 @@ import circle_evolution.helpers as helpers +from circle_evolution.reporter import LoggerReporter + def main(): """Entrypoint of application""" @@ -21,8 +23,11 @@ def main(): args = parser.parse_args() target = helpers.load_target_image(args.image, size=size_options[args.size]) + reporter_logger = LoggerReporter() evolution = Evolution(size_options[args.size], target, genes=args.genes) + evolution.attach(reporter_logger) + evolution.evolve(max_generation=args.max_generations) evolution.specie.render() From 68e8594d65d484c3f928f9b0aa75010bf968ac36 Mon Sep 17 00:00:00 2001 From: guimorg Date: Wed, 27 May 2020 21:02:43 -0300 Subject: [PATCH 06/10] Fixes stylecode --- circle_evolution/evolution.py | 5 +---- circle_evolution/fitness.py | 1 + circle_evolution/reporter.py | 32 ++++++++------------------------ circle_evolution/runner.py | 1 + 4 files changed, 11 insertions(+), 28 deletions(-) diff --git a/circle_evolution/evolution.py b/circle_evolution/evolution.py index 686bcd4..e31307e 100644 --- a/circle_evolution/evolution.py +++ b/circle_evolution/evolution.py @@ -96,7 +96,4 @@ def evolve(self, fitness=fitness.MSEFitness, max_generation=100000): if newfit > fit: fit = newfit self.specie = mutated - self.notify( - f"Generation {self.generation}\t" - f"Fitness: {newfit}" - ) + self.notify(f"Generation {self.generation}\t" f"Fitness: {newfit}") diff --git a/circle_evolution/fitness.py b/circle_evolution/fitness.py index 7d63b17..68517e8 100644 --- a/circle_evolution/fitness.py +++ b/circle_evolution/fitness.py @@ -48,6 +48,7 @@ class MSEFitness(Fitness): See: https://en.wikipedia.org/wiki/Mean_squared_error. """ + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._max_error = (np.square((1 - (self.target >= 127)) * 255 - self.target)).mean(axis=None) diff --git a/circle_evolution/reporter.py b/circle_evolution/reporter.py index c9523dc..ec10960 100644 --- a/circle_evolution/reporter.py +++ b/circle_evolution/reporter.py @@ -17,6 +17,7 @@ class Reporter(ABC): them for visualization. Please, use this class if you want to implement your own Reporter. """ + def __init__(self): """Initialization calls setup to configure Reporter""" self.setup() @@ -46,33 +47,16 @@ class LoggerReporter(Reporter): reporter only cares about strings and will notify minimal details about other types. """ + def setup(self): """Sets up Logger""" config_initial = { - 'version': 1, - 'disable_existing_loggers': True, - 'formatters': { - 'simple': { - 'format': '%(asctime)s %(name)s %(message)s' - }, - }, - 'handlers': { - 'console': { - 'level': 'INFO', - 'class': 'logging.StreamHandler', - 'formatter': 'simple' - }, - }, - 'loggers': { - 'circle-evolution': { - 'handlers': ['console'], - 'level': 'DEBUG', - } - }, - 'root': { - 'handlers': ['console'], - 'level': 'DEBUG' - } + "version": 1, + "disable_existing_loggers": True, + "formatters": {"simple": {"format": "%(asctime)s %(name)s %(message)s"}}, + "handlers": {"console": {"level": "INFO", "class": "logging.StreamHandler", "formatter": "simple"}}, + "loggers": {"circle-evolution": {"handlers": ["console"], "level": "DEBUG"}}, + "root": {"handlers": ["console"], "level": "DEBUG"}, } logging.config.dictConfig(config_initial) self.logger = logging.getLogger(__name__) # Creating new logger diff --git a/circle_evolution/runner.py b/circle_evolution/runner.py index c15abd5..52c9ab9 100644 --- a/circle_evolution/runner.py +++ b/circle_evolution/runner.py @@ -16,6 +16,7 @@ class Runner: Attributes: _reporters: list of reporters that are going to receive reports. """ + _reporters = [] def attach(self, reporter): From a4b41381902644d5dde898aa210a54de31e35575 Mon Sep 17 00:00:00 2001 From: guimorg Date: Wed, 27 May 2020 22:48:45 -0300 Subject: [PATCH 07/10] Fixes Observer Pattern - Uses Object --- circle_evolution/evolution.py | 9 +++++---- circle_evolution/main.py | 4 ++-- circle_evolution/reporter.py | 27 +++++++++++++++++---------- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/circle_evolution/evolution.py b/circle_evolution/evolution.py index e31307e..3980dc3 100644 --- a/circle_evolution/evolution.py +++ b/circle_evolution/evolution.py @@ -37,6 +37,7 @@ def __init__(self, size, target, genes=100): self.target = target # Target Image self.generation = 1 self.genes = genes + self.current_fitness = None self.specie = Specie(size=self.size, genes=genes) @@ -84,7 +85,7 @@ def evolve(self, fitness=fitness.MSEFitness, max_generation=100000): fitness_ = fitness(self.target) self.specie.render() - fit = fitness_.score(self.specie.phenotype) + self.current_fitness = fitness_.score(self.specie.phenotype) for i in range(max_generation): self.generation = i + 1 @@ -93,7 +94,7 @@ def evolve(self, fitness=fitness.MSEFitness, max_generation=100000): mutated.render() newfit = fitness_.score(mutated.phenotype) - if newfit > fit: - fit = newfit + if newfit > self.current_fitness: + self.current_fitness = newfit self.specie = mutated - self.notify(f"Generation {self.generation}\t" f"Fitness: {newfit}") + self.notify(self) diff --git a/circle_evolution/main.py b/circle_evolution/main.py index 64cd626..36cc145 100644 --- a/circle_evolution/main.py +++ b/circle_evolution/main.py @@ -8,7 +8,7 @@ import circle_evolution.helpers as helpers -from circle_evolution.reporter import LoggerReporter +from circle_evolution.reporter import LoggerMetricReporter def main(): @@ -23,7 +23,7 @@ def main(): args = parser.parse_args() target = helpers.load_target_image(args.image, size=size_options[args.size]) - reporter_logger = LoggerReporter() + reporter_logger = LoggerMetricReporter() evolution = Evolution(size_options[args.size], target, genes=args.genes) evolution.attach(reporter_logger) diff --git a/circle_evolution/reporter.py b/circle_evolution/reporter.py index ec10960..735b03c 100644 --- a/circle_evolution/reporter.py +++ b/circle_evolution/reporter.py @@ -34,18 +34,15 @@ def update(self, report): """Receives report from subject. This is the main function for reporting events. The Reporter receives a - report and have to deal with what to do with that. For Circle-Evolution - you can expect anything from strings to `numpy.array`. + report and have to deal with what to do with that. """ -class LoggerReporter(Reporter): +class LoggerMetricReporter(Reporter): """Reporter for logging. This Reporter is responsible for setting up a Logger object and logging all - events that happened during circle-evolution cycle. Notice that this - reporter only cares about strings and will notify minimal details about - other types. + events that happened during circle-evolution cycle. """ def setup(self): @@ -53,17 +50,27 @@ def setup(self): config_initial = { "version": 1, "disable_existing_loggers": True, - "formatters": {"simple": {"format": "%(asctime)s %(name)s %(message)s"}}, + "formatters": {"simple": {"format": "%(asctime)s %(name)s %(message)s", "datefmt": "%H:%M:%S"}}, "handlers": {"console": {"level": "INFO", "class": "logging.StreamHandler", "formatter": "simple"}}, "loggers": {"circle-evolution": {"handlers": ["console"], "level": "DEBUG"}}, "root": {"handlers": ["console"], "level": "DEBUG"}, } logging.config.dictConfig(config_initial) self.logger = logging.getLogger(__name__) # Creating new logger + self.last_fit = float("-inf") # Value for fresh run def update(self, report): """Logs events using logger""" self.logger.debug("Received event...") - if isinstance(report, str): - # Only deals with string messages - self.logger.info(report) + + # We are going to show the percentual improvement from last fit, but + # because don't want to slow perfomance we remove having to calculate + # really small values + improvement = report.current_fitness - self.last_fit + self.last_fit = report.current_fitness + if improvement > 0.00001: + improvement = improvement / self.last_fit * 100 + # Updating last_fit + self.logger.info( + "Generation %s - Fitness %.5f - Improvement %.5f%%", report.generation, report.current_fitness, improvement + ) From a509ca7b9f5de13c8f46d194374769ad8ea3d10b Mon Sep 17 00:00:00 2001 From: guimorg Date: Thu, 28 May 2020 16:23:18 -0300 Subject: [PATCH 08/10] Adds two other methods for reporters to deal with on_start and on_stop objects --- circle_evolution/reporter.py | 27 ++++++++++++++++++++++++++- circle_evolution/runner.py | 13 ++++++++++--- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/circle_evolution/reporter.py b/circle_evolution/reporter.py index 735b03c..8a9e124 100644 --- a/circle_evolution/reporter.py +++ b/circle_evolution/reporter.py @@ -34,7 +34,26 @@ def update(self, report): """Receives report from subject. This is the main function for reporting events. The Reporter receives a - report and have to deal with what to do with that. + report and have to deal with what to do with that. To accomodate with + context, it also receives an status. + """ + + @abstractmethod + def on_start(self, report): + """Receives report for when the Subject start processing. + + If a reporter needs to report an object being initialized or starts + processing, it can use this. Please note that ALL reporters need + to implement this, if it is not used you can just `return` or `pass` + """ + + @abstractmethod + def on_stop(self, report): + """Receives report for when the Subject finishes processing. + + If a reporter needs to report an object that finished + processing, it can use this. Please note that ALL reporters need + to implement this, if it is not used you can just `return` or `pass` """ @@ -74,3 +93,9 @@ def update(self, report): self.logger.info( "Generation %s - Fitness %.5f - Improvement %.5f%%", report.generation, report.current_fitness, improvement ) + + def on_start(self, report): + """Just logs the maximum generations""" + + def on_stop(self, report): + """Just logs the final fitness""" diff --git a/circle_evolution/runner.py b/circle_evolution/runner.py index 52c9ab9..8864aba 100644 --- a/circle_evolution/runner.py +++ b/circle_evolution/runner.py @@ -23,7 +23,14 @@ def attach(self, reporter): """Attaches reporter for notifications""" self._reporters.append(reporter) - def notify(self, report): + def notify(self, report, status="processing"): """Send report to all attached reporters""" - for reporter in self._reporters: - reporter.update(report) + if status == "start": + for reporter in self._reporters: + reporter.on_start(report) + elif status == "end": + for reporter in self._reporters: + reporter.on_stop(report) + else: + for reporter in self._reporters: + reporter.update(report) From 634850a8252ef20a0276fd15f2fcd95c7fdbe861 Mon Sep 17 00:00:00 2001 From: guimorg Date: Thu, 28 May 2020 23:18:09 -0300 Subject: [PATCH 09/10] Few changes for notifications - Adds CSV Reporter - Notify all generations --- circle_evolution/evolution.py | 21 +++++---- circle_evolution/main.py | 6 ++- circle_evolution/reporter.py | 81 ++++++++++++++++++++++++++++------- circle_evolution/runner.py | 12 ++++-- 4 files changed, 89 insertions(+), 31 deletions(-) diff --git a/circle_evolution/evolution.py b/circle_evolution/evolution.py index 3980dc3..a994bf1 100644 --- a/circle_evolution/evolution.py +++ b/circle_evolution/evolution.py @@ -6,12 +6,12 @@ import circle_evolution.fitness as fitness -from circle_evolution.runner import Runner +from circle_evolution import runner from circle_evolution.species import Specie -class Evolution(Runner): +class Evolution(runner.Runner): """Logic for a Species Evolution. Use the Evolution class when you want to train a Specie to look like @@ -37,7 +37,7 @@ def __init__(self, size, target, genes=100): self.target = target # Target Image self.generation = 1 self.genes = genes - self.current_fitness = None + self.best_fit = self.new_fit = 0 self.specie = Specie(size=self.size, genes=genes) @@ -82,19 +82,22 @@ def evolve(self, fitness=fitness.MSEFitness, max_generation=100000): fitness (fitness.Fitness): fitness class to score species preformance. max_generation (int): amount of generations to train for. """ + self.notify(self, runner.START) fitness_ = fitness(self.target) self.specie.render() - self.current_fitness = fitness_.score(self.specie.phenotype) + self.best_fit = fitness_.score(self.specie.phenotype) - for i in range(max_generation): + for i in range(0, max_generation): self.generation = i + 1 mutated = self.mutate(self.specie) mutated.render() - newfit = fitness_.score(mutated.phenotype) + self.new_fit = fitness_.score(mutated.phenotype) + self.notify(self) - if newfit > self.current_fitness: - self.current_fitness = newfit + if self.new_fit > self.best_fit: + self.best_fit = self.new_fit self.specie = mutated - self.notify(self) + + self.notify(self, runner.END) diff --git a/circle_evolution/main.py b/circle_evolution/main.py index 36cc145..a06a005 100644 --- a/circle_evolution/main.py +++ b/circle_evolution/main.py @@ -8,7 +8,7 @@ import circle_evolution.helpers as helpers -from circle_evolution.reporter import LoggerMetricReporter +from circle_evolution import reporter def main(): @@ -23,10 +23,12 @@ def main(): args = parser.parse_args() target = helpers.load_target_image(args.image, size=size_options[args.size]) - reporter_logger = LoggerMetricReporter() + reporter_logger = reporter.LoggerMetricReporter() + reporter_csv = reporter.CSVMetricReporter() evolution = Evolution(size_options[args.size], target, genes=args.genes) evolution.attach(reporter_logger) + evolution.attach(reporter_csv) evolution.evolve(max_generation=args.max_generations) diff --git a/circle_evolution/reporter.py b/circle_evolution/reporter.py index 8a9e124..93ed0ed 100644 --- a/circle_evolution/reporter.py +++ b/circle_evolution/reporter.py @@ -6,9 +6,15 @@ """ from abc import ABC, abstractmethod +import csv + +from datetime import datetime + import logging import logging.config +import tempfile + class Reporter(ABC): """Base Reporter class. @@ -69,33 +75,76 @@ def setup(self): config_initial = { "version": 1, "disable_existing_loggers": True, - "formatters": {"simple": {"format": "%(asctime)s %(name)s %(message)s", "datefmt": "%H:%M:%S"}}, - "handlers": {"console": {"level": "INFO", "class": "logging.StreamHandler", "formatter": "simple"}}, - "loggers": {"circle-evolution": {"handlers": ["console"], "level": "DEBUG"}}, - "root": {"handlers": ["console"], "level": "DEBUG"}, + "formatters": { + "simple": {"format": "Circle-Evolution %(message)s"}, + "complete": {"format": "%(asctime)s %(name)s %(message)s", "datefmt": "%H:%M:%S"}, + }, + "handlers": { + "console": {"level": "INFO", "class": "logging.StreamHandler", "formatter": "simple"}, + "file": { + "level": "DEBUG", + "class": "logging.FileHandler", + "filename": f"{tempfile.gettempdir()}/circle_evolution.log", + "mode": "w", + "formatter": "complete", + }, + }, + "loggers": {"circle-evolution": {"handlers": ["console", "file"], "level": "DEBUG"}}, + "root": {"handlers": ["console", "file"], "level": "DEBUG"}, } logging.config.dictConfig(config_initial) self.logger = logging.getLogger(__name__) # Creating new logger - self.last_fit = float("-inf") # Value for fresh run def update(self, report): """Logs events using logger""" self.logger.debug("Received event...") - # We are going to show the percentual improvement from last fit, but - # because don't want to slow perfomance we remove having to calculate - # really small values - improvement = report.current_fitness - self.last_fit - self.last_fit = report.current_fitness - if improvement > 0.00001: - improvement = improvement / self.last_fit * 100 - # Updating last_fit - self.logger.info( - "Generation %s - Fitness %.5f - Improvement %.5f%%", report.generation, report.current_fitness, improvement - ) + improvement = report.new_fit - report.best_fit + message = f"\tGeneration {report.generation} - Fitness {report.new_fit:.5f}" + + if improvement > 0: + improvement = improvement / report.best_fit * 100 + message += f" - Improvement {improvement:.5f}%%" + self.logger.info(message) + else: + message += " - No Improvement" + self.logger.info(message) def on_start(self, report): """Just logs the maximum generations""" + self.logger.info("Starting evolution...") def on_stop(self, report): """Just logs the final fitness""" + self.logger.info("Evolution ended! Enjoy your Circle-Evolved Image!\t" f"Final fitness: {report.best_fit:.5f}") + + +class CSVMetricReporter(Reporter): + """CSV Report for Data Analysis. + + In case one wants to extract evolution metrics for a CSV file. + """ + + def setup(self): + """Sets up Logger""" + now = datetime.now() + self.filename = f"circle-evolution-{now.strftime('%d-%m-%Y_%H-%M-%S')}.csv" + self._write_to_csv(["generation", "fitness"]) # header + + def _write_to_csv(self, content): + """Safely writes content to CSV file.""" + with open(self.filename, "a") as fd: + writer = csv.writer(fd) + writer.writerow(content) + + def update(self, report): + """Logs events using logger""" + self._write_to_csv([report.generation, report.new_fit]) + + def on_start(self, report): + # Nothing to do here + pass + + def on_stop(self, report): + # Nothing to do here + pass diff --git a/circle_evolution/runner.py b/circle_evolution/runner.py index 8864aba..4b2c3ab 100644 --- a/circle_evolution/runner.py +++ b/circle_evolution/runner.py @@ -4,6 +4,10 @@ need to extend your class with the base Runner. It provides an interface for attaching reporters and notifying all reporters of a particular event. """ +# Constants for Runners +START = 0 +PROCESSING = 1 +END = 2 class Runner: @@ -23,14 +27,14 @@ def attach(self, reporter): """Attaches reporter for notifications""" self._reporters.append(reporter) - def notify(self, report, status="processing"): + def notify(self, report, status=PROCESSING): """Send report to all attached reporters""" - if status == "start": + if status == START: for reporter in self._reporters: reporter.on_start(report) - elif status == "end": + elif status == END: for reporter in self._reporters: reporter.on_stop(report) - else: + elif status == PROCESSING: for reporter in self._reporters: reporter.update(report) From 1c349a9adead085777dd50de587c47e10a96fda6 Mon Sep 17 00:00:00 2001 From: guimorg Date: Thu, 28 May 2020 23:51:47 -0300 Subject: [PATCH 10/10] Only log improvements to the screen --- circle_evolution/reporter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle_evolution/reporter.py b/circle_evolution/reporter.py index 93ed0ed..abfec81 100644 --- a/circle_evolution/reporter.py +++ b/circle_evolution/reporter.py @@ -108,7 +108,7 @@ def update(self, report): self.logger.info(message) else: message += " - No Improvement" - self.logger.info(message) + self.logger.debug(message) def on_start(self, report): """Just logs the maximum generations"""