Skip to content

Commit 2f139d3

Browse files
committed
Fixes and more tests
1 parent 6b94152 commit 2f139d3

File tree

4 files changed

+345
-31
lines changed

4 files changed

+345
-31
lines changed

pygad/utils/mutation.py

+17-8
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,13 @@ def mutation_by_space(self, offspring):
7575
elif type(curr_gene_space) is dict:
7676
# The gene's space of type dict specifies the lower and upper limits of a gene.
7777
if 'step' in curr_gene_space.keys():
78+
# The numpy.random.choice() and numpy.random.uniform() functions return a NumPy array as the output even if the array has a single value.
79+
# We have to return the output at index 0 to force a numeric value to be returned not an object of type numpy.ndarray.
80+
# If numpy.ndarray is returned, then it will cause an issue later while using the set() function.
7881
value_from_space = numpy.random.choice(numpy.arange(start=curr_gene_space['low'],
7982
stop=curr_gene_space['high'],
8083
step=curr_gene_space['step']),
81-
size=1)
84+
size=1)[0]
8285
else:
8386
value_from_space = numpy.random.uniform(low=curr_gene_space['low'],
8487
high=curr_gene_space['high'],
@@ -104,7 +107,7 @@ def mutation_by_space(self, offspring):
104107
value_from_space = numpy.random.choice(numpy.arange(start=self.gene_space['low'],
105108
stop=self.gene_space['high'],
106109
step=self.gene_space['step']),
107-
size=1)
110+
size=1)[0]
108111
else:
109112
value_from_space = numpy.random.uniform(low=self.gene_space['low'],
110113
high=self.gene_space['high'],
@@ -186,7 +189,7 @@ def mutation_probs_by_space(self, offspring):
186189
value_from_space = numpy.random.choice(numpy.arange(start=curr_gene_space['low'],
187190
stop=curr_gene_space['high'],
188191
step=curr_gene_space['step']),
189-
size=1)
192+
size=1)[0]
190193
else:
191194
value_from_space = numpy.random.uniform(low=curr_gene_space['low'],
192195
high=curr_gene_space['high'],
@@ -211,7 +214,7 @@ def mutation_probs_by_space(self, offspring):
211214
value_from_space = numpy.random.choice(numpy.arange(start=self.gene_space['low'],
212215
stop=self.gene_space['high'],
213216
step=self.gene_space['step']),
214-
size=1)
217+
size=1)[0]
215218
else:
216219
value_from_space = numpy.random.uniform(low=self.gene_space['low'],
217220
high=self.gene_space['high'],
@@ -520,10 +523,13 @@ def adaptive_mutation_by_space(self, offspring):
520523
elif type(curr_gene_space) is dict:
521524
# Selecting a value randomly from the current gene's space in the 'gene_space' attribute.
522525
if 'step' in curr_gene_space.keys():
526+
# The numpy.random.choice() and numpy.random.uniform() functions return a NumPy array as the output even if the array has a single value.
527+
# We have to return the output at index 0 to force a numeric value to be returned not an object of type numpy.ndarray.
528+
# If numpy.ndarray is returned, then it will cause an issue later while using the set() function.
523529
value_from_space = numpy.random.choice(numpy.arange(start=curr_gene_space['low'],
524530
stop=curr_gene_space['high'],
525531
step=curr_gene_space['step']),
526-
size=1)
532+
size=1)[0]
527533
else:
528534
value_from_space = numpy.random.uniform(low=curr_gene_space['low'],
529535
high=curr_gene_space['high'],
@@ -548,7 +554,7 @@ def adaptive_mutation_by_space(self, offspring):
548554
value_from_space = numpy.random.choice(numpy.arange(start=self.gene_space['low'],
549555
stop=self.gene_space['high'],
550556
step=self.gene_space['step']),
551-
size=1)
557+
size=1)[0]
552558
else:
553559
value_from_space = numpy.random.uniform(low=self.gene_space['low'],
554560
high=self.gene_space['high'],
@@ -699,7 +705,7 @@ def adaptive_mutation_probs_by_space(self, offspring):
699705
value_from_space = numpy.random.choice(numpy.arange(start=curr_gene_space['low'],
700706
stop=curr_gene_space['high'],
701707
step=curr_gene_space['step']),
702-
size=1)
708+
size=1)[0]
703709
else:
704710
value_from_space = numpy.random.uniform(low=curr_gene_space['low'],
705711
high=curr_gene_space['high'],
@@ -721,10 +727,13 @@ def adaptive_mutation_probs_by_space(self, offspring):
721727
# Selecting a value randomly from the global gene space in the 'gene_space' attribute.
722728
if type(self.gene_space) is dict:
723729
if 'step' in self.gene_space.keys():
730+
# The numpy.random.choice() and numpy.random.uniform() functions return a NumPy array as the output even if the array has a single value.
731+
# We have to return the output at index 0 to force a numeric value to be returned not an object of type numpy.ndarray.
732+
# If numpy.ndarray is returned, then it will cause an issue later while using the set() function.
724733
value_from_space = numpy.random.choice(numpy.arange(start=self.gene_space['low'],
725734
stop=self.gene_space['high'],
726735
step=self.gene_space['step']),
727-
size=1)
736+
size=1)[0]
728737
else:
729738
value_from_space = numpy.random.uniform(low=self.gene_space['low'],
730739
high=self.gene_space['high'],

tests/test_crossover_mutation.py

+188
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
import pygad
2+
import random
3+
import numpy
4+
5+
num_generations = 1
6+
7+
initial_population = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
8+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
9+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
10+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
11+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
12+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
13+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
14+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
15+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
16+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]
17+
18+
def output_crossover_mutation(gene_space=None,
19+
gene_type=float,
20+
num_genes=10,
21+
mutation_by_replacement=False,
22+
random_mutation_min_val=-1,
23+
random_mutation_max_val=1,
24+
init_range_low=-4,
25+
init_range_high=4,
26+
initial_population=None,
27+
crossover_probability=None,
28+
mutation_probability=None,
29+
crossover_type=None,
30+
mutation_type=None):
31+
32+
def fitness_func(ga, solution, idx):
33+
return random.random()
34+
35+
ga_instance = pygad.GA(num_generations=num_generations,
36+
num_parents_mating=5,
37+
fitness_func=fitness_func,
38+
sol_per_pop=10,
39+
num_genes=num_genes,
40+
gene_space=gene_space,
41+
gene_type=gene_type,
42+
initial_population=initial_population,
43+
init_range_low=init_range_low,
44+
init_range_high=init_range_high,
45+
random_mutation_min_val=random_mutation_min_val,
46+
random_mutation_max_val=random_mutation_max_val,
47+
allow_duplicate_genes=True,
48+
mutation_by_replacement=mutation_by_replacement,
49+
save_solutions=True,
50+
crossover_probability=crossover_probability,
51+
mutation_probability=mutation_probability,
52+
crossover_type=crossover_type,
53+
mutation_type=mutation_type,
54+
suppress_warnings=True,
55+
random_seed=1)
56+
57+
ga_instance.run()
58+
59+
comparison_result = []
60+
for solution_idx, solution in enumerate(ga_instance.population):
61+
if list(solution) in ga_instance.initial_population.tolist():
62+
comparison_result.append(True)
63+
else:
64+
comparison_result.append(False)
65+
66+
comparison_result = numpy.array(comparison_result)
67+
result = numpy.all(comparison_result == True)
68+
69+
print("Comparison result is {result}".format(result=result))
70+
return result, ga_instance
71+
72+
def test_no_crossover_no_mutation():
73+
result, ga_instance = output_crossover_mutation()
74+
75+
assert result == True
76+
77+
def test_no_crossover_no_mutation_gene_space():
78+
result, ga_instance = output_crossover_mutation(gene_space=range(10))
79+
80+
assert result == True
81+
82+
def test_no_crossover_no_mutation_int_gene_type():
83+
result, ga_instance = output_crossover_mutation(gene_type=int)
84+
85+
assert result == True
86+
87+
88+
def test_no_crossover_no_mutation_gene_space_gene_type():
89+
result, ga_instance = output_crossover_mutation(gene_space={"low": 0, "high": 10},
90+
gene_type=[float, 2])
91+
92+
assert result == True
93+
94+
95+
def test_no_crossover_no_mutation_nested_gene_space():
96+
result, ga_instance = output_crossover_mutation(gene_space=[[0, 1, 2, 3, 4],
97+
numpy.arange(5, 10),
98+
range(10, 15),
99+
{"low": 15, "high": 20},
100+
{"low": 20, "high": 30, "step": 2},
101+
None,
102+
numpy.arange(30, 35),
103+
numpy.arange(35, 40),
104+
numpy.arange(40, 45),
105+
[45, 46, 47, 48, 49]])
106+
assert result == True
107+
108+
def test_no_crossover_no_mutation_nested_gene_type():
109+
result, ga_instance = output_crossover_mutation(gene_type=[int, float, numpy.float64, [float, 3], [float, 4], numpy.int16, [numpy.float32, 1], int, float, [float, 3]])
110+
111+
assert result == True
112+
113+
def test_no_crossover_no_mutation_nested_gene_space_nested_gene_type():
114+
result, ga_instance = output_crossover_mutation(gene_space=[[0, 1, 2, 3, 4],
115+
numpy.arange(5, 10),
116+
range(10, 15),
117+
{"low": 15, "high": 20},
118+
{"low": 20, "high": 30, "step": 2},
119+
None,
120+
numpy.arange(30, 35),
121+
numpy.arange(35, 40),
122+
numpy.arange(40, 45),
123+
[45, 46, 47, 48, 49]],
124+
gene_type=[int, float, numpy.float64, [float, 3], [float, 4], numpy.int16, [numpy.float32, 1], int, float, [float, 3]])
125+
126+
assert result == True
127+
128+
def test_no_crossover_no_mutation_initial_population():
129+
global initial_population
130+
result, ga_instance = output_crossover_mutation(initial_population=initial_population)
131+
132+
assert result == True
133+
134+
def test_no_crossover_no_mutation_initial_population_nested_gene_type():
135+
global initial_population
136+
result, ga_instance = output_crossover_mutation(initial_population=initial_population,
137+
gene_type=[int, float, numpy.float64, [float, 3], [float, 4], numpy.int16, [numpy.float32, 1], int, float, [float, 3]])
138+
139+
assert result == True
140+
141+
def test_crossover_no_mutation_zero_crossover_probability():
142+
global initial_population
143+
result, ga_instance = output_crossover_mutation(crossover_type="single_point",
144+
crossover_probability=0.0)
145+
146+
assert result == True
147+
148+
def test_zero_crossover_probability_zero_mutation_probability():
149+
global initial_population
150+
result, ga_instance = output_crossover_mutation(crossover_type="single_point",
151+
crossover_probability=0.0,
152+
mutation_type="random",
153+
mutation_probability=0.0)
154+
155+
assert result == True
156+
157+
if __name__ == "__main__":
158+
print()
159+
test_no_crossover_no_mutation()
160+
print()
161+
162+
test_no_crossover_no_mutation_int_gene_type()
163+
print()
164+
165+
test_no_crossover_no_mutation_gene_space()
166+
print()
167+
168+
test_no_crossover_no_mutation_gene_space_gene_type()
169+
print()
170+
171+
test_no_crossover_no_mutation_nested_gene_space()
172+
print()
173+
174+
test_no_crossover_no_mutation_nested_gene_type()
175+
print()
176+
177+
test_no_crossover_no_mutation_initial_population()
178+
print()
179+
180+
test_no_crossover_no_mutation_initial_population_nested_gene_type()
181+
print()
182+
183+
test_crossover_no_mutation_zero_crossover_probability()
184+
print()
185+
186+
test_zero_crossover_probability_zero_mutation_probability()
187+
print()
188+

0 commit comments

Comments
 (0)