From 5da91d6e3f441207651932371b12dae2061ec9b5 Mon Sep 17 00:00:00 2001 From: MaximSmolskiy Date: Fri, 4 Nov 2022 01:31:37 +0300 Subject: [PATCH 1/5] Reduce the complexity of genetic_algorithm/basic_string.py --- genetic_algorithm/basic_string.py | 95 ++++++++++++++++--------------- 1 file changed, 50 insertions(+), 45 deletions(-) diff --git a/genetic_algorithm/basic_string.py b/genetic_algorithm/basic_string.py index 45b8be651f6e..c121fa75539a 100644 --- a/genetic_algorithm/basic_string.py +++ b/genetic_algorithm/basic_string.py @@ -21,6 +21,54 @@ random.seed(random.randint(0, 1000)) +def evaluate(item: str, main_target: str) -> tuple[str, float]: + """ + Evaluate how similar the item is with the target by just + counting each char in the right position + >>> evaluate("Helxo Worlx", Hello World) + ["Helxo Worlx", 9] + """ + score = len([g for position, g in enumerate(item) if g == main_target[position]]) + return (item, float(score)) + + +def crossover(parent_1: str, parent_2: str) -> tuple[str, str]: + """Slice and combine two string at a random point.""" + random_slice = random.randint(0, len(parent_1) - 1) + child_1 = parent_1[:random_slice] + parent_2[random_slice:] + child_2 = parent_2[:random_slice] + parent_1[random_slice:] + return (child_1, child_2) + + +def mutate(child: str, genes: list[str]) -> str: + """Mutate a random gene of a child with another one from the list.""" + child_list = list(child) + if random.uniform(0, 1) < MUTATION_PROBABILITY: + child_list[random.randint(0, len(child)) - 1] = random.choice(genes) + return "".join(child_list) + + +# Select, crossover and mutate a new population. +def select( + parent_1: tuple[str, float], + population_score: list[tuple[str, float]], + genes: list[str], +) -> list[str]: + """Select the second parent and generate new population""" + pop = [] + # Generate more children proportionally to the fitness score. + child_n = int(parent_1[1] * 100) + 1 + child_n = 10 if child_n >= 10 else child_n + for _ in range(child_n): + parent_2 = population_score[random.randint(0, N_SELECTED)][0] + + child_1, child_2 = crossover(parent_1[0], parent_2) + # Append new string to the population list. + pop.append(mutate(child_1, genes)) + pop.append(mutate(child_2, genes)) + return pop + + def basic(target: str, genes: list[str], debug: bool = True) -> tuple[int, int, str]: """ Verify that the target contains no genes besides the ones inside genes variable. @@ -70,17 +118,6 @@ def basic(target: str, genes: list[str], debug: bool = True) -> tuple[int, int, total_population += len(population) # Random population created. Now it's time to evaluate. - def evaluate(item: str, main_target: str = target) -> tuple[str, float]: - """ - Evaluate how similar the item is with the target by just - counting each char in the right position - >>> evaluate("Helxo Worlx", Hello World) - ["Helxo Worlx", 9] - """ - score = len( - [g for position, g in enumerate(item) if g == main_target[position]] - ) - return (item, float(score)) # Adding a bit of concurrency can make everything faster, # @@ -94,7 +131,7 @@ def evaluate(item: str, main_target: str = target) -> tuple[str, float]: # # but with a simple algorithm like this, it will probably be slower. # We just need to call evaluate for every item inside the population. - population_score = [evaluate(item) for item in population] + population_score = [evaluate(item, target) for item in population] # Check if there is a matching evolution. population_score = sorted(population_score, key=lambda x: x[1], reverse=True) @@ -121,41 +158,9 @@ def evaluate(item: str, main_target: str = target) -> tuple[str, float]: (item, score / len(target)) for item, score in population_score ] - # Select, crossover and mutate a new population. - def select(parent_1: tuple[str, float]) -> list[str]: - """Select the second parent and generate new population""" - pop = [] - # Generate more children proportionally to the fitness score. - child_n = int(parent_1[1] * 100) + 1 - child_n = 10 if child_n >= 10 else child_n - for _ in range(child_n): - parent_2 = population_score[ # noqa: B023 - random.randint(0, N_SELECTED) - ][0] - - child_1, child_2 = crossover(parent_1[0], parent_2) - # Append new string to the population list. - pop.append(mutate(child_1)) - pop.append(mutate(child_2)) - return pop - - def crossover(parent_1: str, parent_2: str) -> tuple[str, str]: - """Slice and combine two string at a random point.""" - random_slice = random.randint(0, len(parent_1) - 1) - child_1 = parent_1[:random_slice] + parent_2[random_slice:] - child_2 = parent_2[:random_slice] + parent_1[random_slice:] - return (child_1, child_2) - - def mutate(child: str) -> str: - """Mutate a random gene of a child with another one from the list.""" - child_list = list(child) - if random.uniform(0, 1) < MUTATION_PROBABILITY: - child_list[random.randint(0, len(child)) - 1] = random.choice(genes) - return "".join(child_list) - # This is selection for i in range(N_SELECTED): - population.extend(select(population_score[int(i)])) + population.extend(select(population_score[int(i)], population_score, genes)) # Check if the population has already reached the maximum value and if so, # break the cycle. If this check is disabled, the algorithm will take # forever to compute large strings, but will also calculate small strings in From 2cd0a48ee579a4cb011b807faff52e9768a85707 Mon Sep 17 00:00:00 2001 From: MaximSmolskiy Date: Sat, 24 Dec 2022 18:15:51 +0300 Subject: [PATCH 2/5] Increas the --max-complexity threshold in the file .flake8 --- .flake8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.flake8 b/.flake8 index 77ca7a328a77..b68ee8533a61 100644 --- a/.flake8 +++ b/.flake8 @@ -1,7 +1,7 @@ [flake8] max-line-length = 88 # max-complexity should be 10 -max-complexity = 17 +max-complexity = 19 extend-ignore = # Formatting style for `black` # E203 is whitespace before ':' From b7fa7a0138d755b315a21d81156659c25b89f167 Mon Sep 17 00:00:00 2001 From: MaximSmolskiy Date: Sat, 24 Dec 2022 18:21:38 +0300 Subject: [PATCH 3/5] Fix test --- genetic_algorithm/basic_string.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/genetic_algorithm/basic_string.py b/genetic_algorithm/basic_string.py index c121fa75539a..936aa537ee05 100644 --- a/genetic_algorithm/basic_string.py +++ b/genetic_algorithm/basic_string.py @@ -25,7 +25,7 @@ def evaluate(item: str, main_target: str) -> tuple[str, float]: """ Evaluate how similar the item is with the target by just counting each char in the right position - >>> evaluate("Helxo Worlx", Hello World) + >>> evaluate("Helxo Worlx", "Hello World") ["Helxo Worlx", 9] """ score = len([g for position, g in enumerate(item) if g == main_target[position]]) From b9d258271e7328783bdd6fd2b6d0e9ca2222bc1b Mon Sep 17 00:00:00 2001 From: MaximSmolskiy Date: Sat, 24 Dec 2022 18:26:08 +0300 Subject: [PATCH 4/5] Fix test --- genetic_algorithm/basic_string.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/genetic_algorithm/basic_string.py b/genetic_algorithm/basic_string.py index 936aa537ee05..388e7219f54b 100644 --- a/genetic_algorithm/basic_string.py +++ b/genetic_algorithm/basic_string.py @@ -26,7 +26,7 @@ def evaluate(item: str, main_target: str) -> tuple[str, float]: Evaluate how similar the item is with the target by just counting each char in the right position >>> evaluate("Helxo Worlx", "Hello World") - ["Helxo Worlx", 9] + ('Helxo Worlx', 9.0) """ score = len([g for position, g in enumerate(item) if g == main_target[position]]) return (item, float(score)) From 091d80eba9d49e961d6de8697d859b4922f12cb5 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sat, 1 Apr 2023 19:58:44 +0000 Subject: [PATCH 5/5] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 34967082b359..b1adc23f6e61 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -717,6 +717,7 @@ * [Archimedes Principle](physics/archimedes_principle.py) * [Casimir Effect](physics/casimir_effect.py) * [Centripetal Force](physics/centripetal_force.py) + * [Grahams Law](physics/grahams_law.py) * [Horizontal Projectile Motion](physics/horizontal_projectile_motion.py) * [Hubble Parameter](physics/hubble_parameter.py) * [Ideal Gas Law](physics/ideal_gas_law.py)