Skip to content

Commit 8bf3b06

Browse files
Merge branch 'TheAlgorithms:master' into master
2 parents e55d7c0 + c0892a0 commit 8bf3b06

File tree

2 files changed

+53
-48
lines changed

2 files changed

+53
-48
lines changed

Diff for: .pre-commit-config.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ repos:
1616
- id: auto-walrus
1717

1818
- repo: https://github.com/charliermarsh/ruff-pre-commit
19-
rev: v0.0.263
19+
rev: v0.0.267
2020
hooks:
2121
- id: ruff
2222

@@ -33,7 +33,7 @@ repos:
3333
- tomli
3434

3535
- repo: https://github.com/tox-dev/pyproject-fmt
36-
rev: "0.11.1"
36+
rev: "0.11.2"
3737
hooks:
3838
- id: pyproject-fmt
3939

@@ -51,7 +51,7 @@ repos:
5151
- id: validate-pyproject
5252

5353
- repo: https://github.com/pre-commit/mirrors-mypy
54-
rev: v1.2.0
54+
rev: v1.3.0
5555
hooks:
5656
- id: mypy
5757
args:

Diff for: genetic_algorithm/basic_string.py

+50-45
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,54 @@
2121
random.seed(random.randint(0, 1000))
2222

2323

24+
def evaluate(item: str, main_target: str) -> tuple[str, float]:
25+
"""
26+
Evaluate how similar the item is with the target by just
27+
counting each char in the right position
28+
>>> evaluate("Helxo Worlx", "Hello World")
29+
('Helxo Worlx', 9.0)
30+
"""
31+
score = len([g for position, g in enumerate(item) if g == main_target[position]])
32+
return (item, float(score))
33+
34+
35+
def crossover(parent_1: str, parent_2: str) -> tuple[str, str]:
36+
"""Slice and combine two string at a random point."""
37+
random_slice = random.randint(0, len(parent_1) - 1)
38+
child_1 = parent_1[:random_slice] + parent_2[random_slice:]
39+
child_2 = parent_2[:random_slice] + parent_1[random_slice:]
40+
return (child_1, child_2)
41+
42+
43+
def mutate(child: str, genes: list[str]) -> str:
44+
"""Mutate a random gene of a child with another one from the list."""
45+
child_list = list(child)
46+
if random.uniform(0, 1) < MUTATION_PROBABILITY:
47+
child_list[random.randint(0, len(child)) - 1] = random.choice(genes)
48+
return "".join(child_list)
49+
50+
51+
# Select, crossover and mutate a new population.
52+
def select(
53+
parent_1: tuple[str, float],
54+
population_score: list[tuple[str, float]],
55+
genes: list[str],
56+
) -> list[str]:
57+
"""Select the second parent and generate new population"""
58+
pop = []
59+
# Generate more children proportionally to the fitness score.
60+
child_n = int(parent_1[1] * 100) + 1
61+
child_n = 10 if child_n >= 10 else child_n
62+
for _ in range(child_n):
63+
parent_2 = population_score[random.randint(0, N_SELECTED)][0]
64+
65+
child_1, child_2 = crossover(parent_1[0], parent_2)
66+
# Append new string to the population list.
67+
pop.append(mutate(child_1, genes))
68+
pop.append(mutate(child_2, genes))
69+
return pop
70+
71+
2472
def basic(target: str, genes: list[str], debug: bool = True) -> tuple[int, int, str]:
2573
"""
2674
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,
70118
total_population += len(population)
71119

72120
# Random population created. Now it's time to evaluate.
73-
def evaluate(item: str, main_target: str = target) -> tuple[str, float]:
74-
"""
75-
Evaluate how similar the item is with the target by just
76-
counting each char in the right position
77-
>>> evaluate("Helxo Worlx", Hello World)
78-
["Helxo Worlx", 9]
79-
"""
80-
score = len(
81-
[g for position, g in enumerate(item) if g == main_target[position]]
82-
)
83-
return (item, float(score))
84121

85122
# Adding a bit of concurrency can make everything faster,
86123
#
@@ -94,7 +131,7 @@ def evaluate(item: str, main_target: str = target) -> tuple[str, float]:
94131
#
95132
# but with a simple algorithm like this, it will probably be slower.
96133
# We just need to call evaluate for every item inside the population.
97-
population_score = [evaluate(item) for item in population]
134+
population_score = [evaluate(item, target) for item in population]
98135

99136
# Check if there is a matching evolution.
100137
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]:
121158
(item, score / len(target)) for item, score in population_score
122159
]
123160

124-
# Select, crossover and mutate a new population.
125-
def select(parent_1: tuple[str, float]) -> list[str]:
126-
"""Select the second parent and generate new population"""
127-
pop = []
128-
# Generate more children proportionally to the fitness score.
129-
child_n = int(parent_1[1] * 100) + 1
130-
child_n = 10 if child_n >= 10 else child_n
131-
for _ in range(child_n):
132-
parent_2 = population_score[ # noqa: B023
133-
random.randint(0, N_SELECTED)
134-
][0]
135-
136-
child_1, child_2 = crossover(parent_1[0], parent_2)
137-
# Append new string to the population list.
138-
pop.append(mutate(child_1))
139-
pop.append(mutate(child_2))
140-
return pop
141-
142-
def crossover(parent_1: str, parent_2: str) -> tuple[str, str]:
143-
"""Slice and combine two string at a random point."""
144-
random_slice = random.randint(0, len(parent_1) - 1)
145-
child_1 = parent_1[:random_slice] + parent_2[random_slice:]
146-
child_2 = parent_2[:random_slice] + parent_1[random_slice:]
147-
return (child_1, child_2)
148-
149-
def mutate(child: str) -> str:
150-
"""Mutate a random gene of a child with another one from the list."""
151-
child_list = list(child)
152-
if random.uniform(0, 1) < MUTATION_PROBABILITY:
153-
child_list[random.randint(0, len(child)) - 1] = random.choice(genes)
154-
return "".join(child_list)
155-
156161
# This is selection
157162
for i in range(N_SELECTED):
158-
population.extend(select(population_score[int(i)]))
163+
population.extend(select(population_score[int(i)], population_score, genes))
159164
# Check if the population has already reached the maximum value and if so,
160165
# break the cycle. If this check is disabled, the algorithm will take
161166
# forever to compute large strings, but will also calculate small strings in

0 commit comments

Comments
 (0)