From b5022c398cd91d424a1a7904555e2ced724a8aef Mon Sep 17 00:00:00 2001 From: Borja Esteban Date: Thu, 15 Dec 2022 09:33:34 +0000 Subject: [PATCH 01/11] fix README MyFitness cache kwd --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9a779d8..b2ac8bd 100755 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ instantiating the experiment to store all phenotypes during the execution. import gevopy as ea experiment = ea.Experiment( - fitness=MyFitness(cached=True, schedule="synchronous"), + fitness=MyFitness(cache=True, schedule="synchronous"), algorithm=MyAlgorithm(survival_rate=0.2), ) From 26944b7be8d9c513d60bdffb4bc97368e52aa5e4 Mon Sep 17 00:00:00 2001 From: Borja Esteban Date: Fri, 16 Dec 2022 09:04:10 +0000 Subject: [PATCH 02/11] update readme fitness example --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b2ac8bd..b22c1e3 100755 --- a/README.md +++ b/README.md @@ -52,11 +52,13 @@ instance of the defined class. You can use the init arguments `cache` and ```py from genopy import fitness -class MyFitness1(fitness.FitnessModel): +class MyFitness(fitness.FitnessModel): def score(self, phenotype): - return phenotype.chromosome.count(1) + x1 = phenotype.chromosome_1.count(1) + x2 = phenotype.chromosome_2.count(0) + return x1 + x2 -fx = MyFitness1(cache=True, parallel=True) +fx = MyFitness(cache=True, parallel=True) ``` > You can additionally define `setup` as method to execute once at the begining of each generation before phenotypes are evaluated. From 0f992439bcf14c5e8c7da15f7964df93d0063a41 Mon Sep 17 00:00:00 2001 From: Borja Esteban Date: Sun, 15 Jan 2023 22:11:22 +0000 Subject: [PATCH 03/11] update README with pydantic notes --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index b22c1e3..cc2f0ca 100755 --- a/README.md +++ b/README.md @@ -130,3 +130,9 @@ Storing relationships at the record level makes sense in genotype relationships as it provides index-free adjacency. Graph traversal operations such 'genealogy tree' or certain matches can be performed with no index lookups leading to much better performance. + +### Why pydantic instead of dataclass? +Pydantic supports validation of fields during and after the +initialization process and makes parsing easier. +Parsing is a relevant step if you are planing to save your +phenotypes into the connected database. From ee128c1dccc9e7bfbabff53ee985d3acfdb6eac4 Mon Sep 17 00:00:00 2001 From: Borja Esteban Date: Sun, 15 Jan 2023 22:13:43 +0000 Subject: [PATCH 04/11] fix update of halloffame at generation 0 --- src/gevopy/experiments.py | 1 + tests/test_requirements/test_experiments.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gevopy/experiments.py b/src/gevopy/experiments.py index ece72be..d0deeaf 100644 --- a/src/gevopy/experiments.py +++ b/src/gevopy/experiments.py @@ -231,6 +231,7 @@ def run(self, session): try: logger.info("Start of evolutionary experiment execution") session.eval_phenotypes(fitness, save=True) # Evaluate first pop + self.halloffame.update(session.get_phenotypes()) while not self.completed: self.generation += 1 # Increase generation index session.generate_offspring(algorithm, save=False) diff --git a/tests/test_requirements/test_experiments.py b/tests/test_requirements/test_experiments.py index 315d578..3f8b59c 100755 --- a/tests/test_requirements/test_experiments.py +++ b/tests/test_requirements/test_experiments.py @@ -91,7 +91,7 @@ def test_generation_stop(self, execution, max_generation): def test_score_stop(self, execution, max_score): """Test execution stops when maximum score is reached""" assert execution.best_score >= max_score - assert execution.generation > 0 + assert execution.generation >= 0 def test_attr_generation(self, execution): """Test generation attr returns int after first execution""" From d73fcfb10ca1fec5a7ab2613089713861d6f8638 Mon Sep 17 00:00:00 2001 From: Borja Esteban Date: Sun, 15 Jan 2023 22:14:02 +0000 Subject: [PATCH 05/11] fix comment names at examples --- examples/evaluation.py | 2 +- examples/genotypes.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/evaluation.py b/examples/evaluation.py index 439ef3e..5e42359 100644 --- a/examples/evaluation.py +++ b/examples/evaluation.py @@ -16,7 +16,7 @@ def score(self, phenotype): # ------------------------------------------------------------------ -# Fitness ---------------------------------------------------------- +# Random ----------------------------------------------------------- # This fitness object scores each phenotypes completelly random. class Random(FitnessModel): """Fitness model assigns a random score between 0-1""" diff --git a/examples/genotypes.py b/examples/genotypes.py index b535325..59af149 100644 --- a/examples/genotypes.py +++ b/examples/genotypes.py @@ -9,7 +9,7 @@ # ------------------------------------------------------------------ -# Genotype --------------------------------------------------------- +# Bacteria --------------------------------------------------------- # This genotypes are known to have asexual reproduction and with a # unique chromosome. In this example values can be only between 0 and 1 # See https://pydantic-docs.helpmanual.io/usage/models/ @@ -19,7 +19,7 @@ class Bacteria(GenotypeModel): # ------------------------------------------------------------------ -# Genotype --------------------------------------------------------- +# JackJumper ------------------------------------------------------- # Although males are know to be composed by haploids, this is a good # example of how to design a chromosome where values can take more # values than 1 or 0 (0-3) due to that each value in the chromosome From a44b5ef1685ba04cf66f0868f9010884254af048 Mon Sep 17 00:00:00 2001 From: Borja Esteban Date: Sun, 15 Jan 2023 22:15:22 +0000 Subject: [PATCH 06/11] add whiteboard to gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index b6e4761..c5e84f5 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,6 @@ dmypy.json # Pyre type checker .pyre/ + +# Whiteboard files +whiteboard.py From d5c38d46fbcb06947087fb75cbb8a3708eae074e Mon Sep 17 00:00:00 2001 From: Borja Esteban Date: Wed, 8 Feb 2023 12:52:40 +0000 Subject: [PATCH 07/11] del node from devcontainer --- .devcontainer/devcontainer.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 98062a6..fb5323b 100755 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -16,9 +16,6 @@ // connected. This is typically a file mount in .devcontainer/docker-compose.yml "workspaceFolder": "/workspace", "features": { - "ghcr.io/devcontainers/features/node:1": { - "version": "lts" - }, "ghcr.io/devcontainers/features/common-utils:1": { }, "ghcr.io/devcontainers/features/git:1": { }, "ghcr.io/devcontainers/features/nvidia-cuda:1": { }, From b10ccf3b33cb8e8da08e34378f43f594f7b91be2 Mon Sep 17 00:00:00 2001 From: Borja Esteban Date: Wed, 8 Feb 2023 12:53:47 +0000 Subject: [PATCH 08/11] fix evolution using EmptyInterface --- src/gevopy/database.py | 2 +- tests/conftest.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gevopy/database.py b/src/gevopy/database.py index 053bfa8..dd314be 100755 --- a/src/gevopy/database.py +++ b/src/gevopy/database.py @@ -225,7 +225,7 @@ def add_phenotypes(cls, _container, phenotypes): """ phenotypes = list(phenotypes) cls.logger.debug('Adding phenotypes %s', phenotypes) - return list(str(p.id) for p in phenotypes) + return list(p['id'] for p in phenotypes) @classmethod def get_phenotypes(cls, _container, ids): diff --git a/tests/conftest.py b/tests/conftest.py index 1029c86..dbca632 100755 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -26,7 +26,7 @@ def driver_kwds(request): return request.param -@fixture(scope="session", params=["Neo4jInterface"]) +@fixture(scope="session", params=["Neo4jInterface", "EmptyInterface"]) def db_interface(request, driver_kwds): """Fixture to return the experiment interface for the database""" match request.param: From 979aada778940e2374c5a326fe3eb0e71bb4f0c0 Mon Sep 17 00:00:00 2001 From: Borja Esteban Date: Wed, 8 Feb 2023 12:54:05 +0000 Subject: [PATCH 09/11] add limitations to README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index cc2f0ca..c136bb8 100755 --- a/README.md +++ b/README.md @@ -136,3 +136,7 @@ Pydantic supports validation of fields during and after the initialization process and makes parsing easier. Parsing is a relevant step if you are planing to save your phenotypes into the connected database. + +### Limitations +Collections containing collections can not be stored in properties. +Property values can only be of primitive types or arrays in Neo4J Cypher queries. From 88081d5e8cdc852cca54c8c2683271a2be8222d0 Mon Sep 17 00:00:00 2001 From: Borja Esteban Date: Wed, 8 Feb 2023 12:54:22 +0000 Subject: [PATCH 10/11] increase patch version --- src/gevopy/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gevopy/VERSION b/src/gevopy/VERSION index afaf360..7f20734 100755 --- a/src/gevopy/VERSION +++ b/src/gevopy/VERSION @@ -1 +1 @@ -1.0.0 \ No newline at end of file +1.0.1 \ No newline at end of file From aef6b83aca39fdf898dda0fececadb01817c4f37 Mon Sep 17 00:00:00 2001 From: Borja Esteban Date: Wed, 8 Feb 2023 13:40:09 +0000 Subject: [PATCH 11/11] get_phenotypes return in same order than ids input --- src/gevopy/database.py | 5 +++-- tests/test_utilities/test_database.py | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/gevopy/database.py b/src/gevopy/database.py index dd314be..3f7da45 100755 --- a/src/gevopy/database.py +++ b/src/gevopy/database.py @@ -409,8 +409,9 @@ def get_phenotypes(tx, ids): "WITH x, e, collect(y.id) as p " "RETURN x{.*, .score, experiment:e.name, parents:p } " ) - result = tx.run(query, phenotypes_ids=ids) - return [dict(record["x"]) for record in result] + result = [dict(r["x"]) for r in tx.run(query, phenotypes_ids=ids)] + result.sort(key=lambda r: ids.index(r['id'])) + return result @neo4j.unit_of_work(timeout=config['timeout']) diff --git a/tests/test_utilities/test_database.py b/tests/test_utilities/test_database.py index 7dedb19..ba6b430 100755 --- a/tests/test_utilities/test_database.py +++ b/tests/test_utilities/test_database.py @@ -3,7 +3,7 @@ import uuid -from pytest import fixture +from pytest import fixture, mark @fixture(scope="module", autouse=True) @@ -52,8 +52,9 @@ def ids(population): return [str(ph.id) for ph in population] +@mark.parametrize("db_interface", ["Neo4jInterface"], indirect=True) def test_rwd_phenotypes(session, phenotypes, ids): """Test write, read and delete of phenotypes in db""" assert ids == session.add_phenotypes(phenotypes) assert phenotypes == session.get_phenotypes(ids) - assert ids == session.del_phenotypes(ids) + assert all([id in ids for id in session.del_phenotypes(ids)])