Skip to content

Commit f5ecabb

Browse files
author
Ahmed Gad
committed
Edit gene_constraint callables
1 parent 079475f commit f5ecabb

File tree

8 files changed

+86
-12
lines changed

8 files changed

+86
-12
lines changed

.DS_Store

8 KB
Binary file not shown.

examples/example_gene_constraint.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ def fitness_func(ga_instance, solution, solution_idx):
2525
gene_type=int,
2626
sample_size=100,
2727
random_seed=10,
28-
gene_constraint=[lambda x, v: [val for val in v if val>=98],
29-
lambda x, v: [val for val in v if val>=98],
30-
lambda x, v: [val for val in v if 80<val<90],
28+
gene_constraint=[lambda x,v: [val for val in v if val>=98],
29+
lambda x,v: [val for val in v if val>=98],
30+
lambda x,v: [val for val in v if 80<val<90],
3131
None,
32-
lambda x, v: [val for val in v if 20<val<40],
32+
lambda x,v: [val for val in v if 20<val<40],
3333
None]
3434
)
3535

pygad/.DS_Store

10 KB
Binary file not shown.

pygad/helper/.DS_Store

6 KB
Binary file not shown.

pygad/pygad.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,8 +1434,15 @@ def initialize_population(self,
14341434
else:
14351435
raise Exception("The output from the gene_constraint callable/function must be a list or NumPy array that is subset of the passed values (second argument).")
14361436

1437-
# Check if the gene value satisfies the gene constraint.
1438-
if len(filtered_values) == 1 and filtered_values[0] == solution[gene_idx]:
1437+
if len(filtered_values) ==1 and filtered_values[0] != solution[gene_idx]:
1438+
# Error by the user's defined gene constraint callable.
1439+
raise Exception(f"It is expected to receive a list/numpy.ndarray from the gene_constraint callable with a single value equal to {values[0]}, but the value {filtered_values[0]} found.")
1440+
1441+
# Check if the gene value does not satisfy the gene constraint.
1442+
# Note that we already passed a list of a single value.
1443+
# It is expected to receive a list of either a single value or an empty list.
1444+
if len(filtered_values) < 1:
1445+
# Search for a value that satisfies the gene constraint.
14391446
range_min, range_max = self.get_initial_population_range(gene_index=gene_idx)
14401447
# While initializing the population, we follow a mutation by replacement approach. So, the original gene value is not needed.
14411448
values_filtered = self.get_valid_gene_constraint_values(range_min=range_min,
@@ -1450,6 +1457,12 @@ def initialize_population(self,
14501457
warnings.warn(f"No value satisfied the constraint for the gene at index {gene_idx} with value {solution[gene_idx]} while creating the initial population.")
14511458
else:
14521459
self.population[sol_idx, gene_idx] = random.choice(values_filtered)
1460+
elif len(filtered_values) == 1:
1461+
# The value already satisfied the gene constraint.
1462+
pass
1463+
else:
1464+
# Error by the user's defined gene constraint callable.
1465+
raise Exception(f"It is expected to receive a list/numpy.ndarray from the gene_constraint callable that is either empty or has a single value equal, but received a list/numpy.ndarray of length {len(filtered_values)}.")
14531466

14541467
# 4) Solve duplicate genes.
14551468
if allow_duplicate_genes == False:

pygad/utils/.DS_Store

6 KB
Binary file not shown.

pygad/visualize/.DS_Store

6 KB
Binary file not shown.

tests/test_gene_constraint.py

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,11 @@ def fitness_func_no_batch_multi(ga, solution, idx):
6969

7070
#### Single-Objective
7171
def test_initial_population_int_by_replacement():
72-
gene_constraint=[lambda x: x[0]>=8,lambda x: x[1]>=8,lambda x: 5>=x[2]>=1,lambda x: 5>x[3]>3,lambda x: x[4]<2]
72+
gene_constraint=[lambda x,v: [val for val in v if val>=8],
73+
lambda x,v: [val for val in v if val>=8],
74+
lambda x,v: [val for val in v if 5>=val>=1],
75+
lambda x,v: [val for val in v if 5>val>3],
76+
lambda x,v: [val for val in v if val<2]]
7377
ga_instance = population_gene_constraint(gene_constraint=gene_constraint,
7478
init_range_low=0,
7579
init_range_high=10,
@@ -79,17 +83,21 @@ def test_initial_population_int_by_replacement():
7983
gene_type=int,
8084
mutation_by_replacement=True)
8185
initial_population = ga_instance.initial_population
82-
# print(initial_population)
8386

8487
assert numpy.all(initial_population[:, 0] >= 8), "Not all values in column 0 are >= 8"
8588
assert numpy.all(initial_population[:, 1] >= 8), "Not all values in column 1 are >= 8"
8689
assert numpy.all(initial_population[:, 2] >= 1), "Not all values in column 2 are >= 1"
8790
assert numpy.all((initial_population[:, 2] >= 1) & (initial_population[:, 2] <= 5)), "Not all values in column 2 between 1 and 5 (inclusive)"
8891
assert numpy.all(initial_population[:, 3] == 4), "Not all values in column 3 between 3 and 5 (exclusive)"
8992
assert numpy.all(initial_population[:, 4] < 2), "Not all values in column 4 < 2"
93+
print("All constraints are met")
9094

9195
def test_initial_population_int_by_replacement_no_duplicates():
92-
gene_constraint=[lambda x: x[0]>=5,lambda x: x[1]>=5,lambda x: x[2]>=5,lambda x: x[3]>=5,lambda x: x[4]>=5]
96+
gene_constraint=[lambda x,v: [val for val in v if val>=5],
97+
lambda x,v: [val for val in v if val>=5],
98+
lambda x,v: [val for val in v if val>=5],
99+
lambda x,v: [val for val in v if val>=5],
100+
lambda x,v: [val for val in v if val>=5]]
93101
ga_instance = population_gene_constraint(gene_constraint=gene_constraint,
94102
init_range_low=1,
95103
init_range_high=10,
@@ -117,9 +125,15 @@ def test_initial_population_int_by_replacement_no_duplicates():
117125
assert numpy.all(initial_population[:, 2] >= 5), "Not all values in column 2 >= 5"
118126
assert numpy.all(initial_population[:, 3] >= 5), "Not all values in column 3 >= 5"
119127
assert numpy.all(initial_population[:, 4] >= 5), "Not all values in column 4 >= 5"
128+
print("All constraints are met")
120129

121130
def test_initial_population_int_by_replacement_no_duplicates2():
122-
gene_constraint=[lambda x: x[0]>=98,lambda x: x[1]>=98,lambda x: 20<x[2]<40,lambda x: x[3]<40,lambda x: x[4]<50,lambda x: x[5]<100]
131+
gene_constraint=[lambda x,v: [val for val in v if val>=98],
132+
lambda x,v: [val for val in v if val>=98],
133+
lambda x,v: [val for val in v if 20<val<40],
134+
lambda x,v: [val for val in v if val<40],
135+
lambda x,v: [val for val in v if val<50],
136+
lambda x,v: [val for val in v if val<100]]
123137
ga_instance = population_gene_constraint(gene_constraint=gene_constraint,
124138
random_mutation_min_val=1,
125139
random_mutation_max_val=100,
@@ -149,9 +163,14 @@ def test_initial_population_int_by_replacement_no_duplicates2():
149163
assert numpy.all(initial_population[:, 3] < 40), "Not all values in column 3 < 40"
150164
assert numpy.all(initial_population[:, 4] < 50), "Not all values in column 4 < 50"
151165
assert numpy.all(initial_population[:, 5] < 100), "Not all values in column 4 < 100"
166+
print("All constraints are met")
152167

153168
def test_initial_population_float_by_replacement_no_duplicates():
154-
gene_constraint=[lambda x: x[0]>=5,lambda x: x[1]>=5,lambda x: x[2]>=5,lambda x: x[3]>=5,lambda x: x[4]>=5]
169+
gene_constraint=[lambda x,v: [val for val in v if val>=5],
170+
lambda x,v: [val for val in v if val>=5],
171+
lambda x,v: [val for val in v if val>=5],
172+
lambda x,v: [val for val in v if val>=5],
173+
lambda x,v: [val for val in v if val>=5]]
155174
ga_instance = population_gene_constraint(gene_constraint=gene_constraint,
156175
init_range_low=1,
157176
init_range_high=10,
@@ -178,9 +197,48 @@ def test_initial_population_float_by_replacement_no_duplicates():
178197
assert numpy.all(initial_population[:, 2] >= 5), "Not all values in column 2 >= 5"
179198
assert numpy.all(initial_population[:, 3] >= 5), "Not all values in column 3 >= 5"
180199
assert numpy.all(initial_population[:, 4] >= 5), "Not all values in column 4 >= 5"
200+
print("All constraints are met")
181201

182202
def test_initial_population_float_by_replacement_no_duplicates2():
183-
gene_constraint=[lambda x: x[0]>=1,lambda x: x[1]>=1,lambda x: x[2]>=1,lambda x: x[3]>=1,lambda x: x[4]>=1]
203+
gene_constraint=[lambda x,v: [val for val in v if val>=1],
204+
lambda x,v: [val for val in v if val>=1],
205+
lambda x,v: [val for val in v if val>=1],
206+
lambda x,v: [val for val in v if val>=1],
207+
lambda x,v: [val for val in v if val>=1]]
208+
ga_instance = population_gene_constraint(gene_constraint=gene_constraint,
209+
init_range_low=1,
210+
init_range_high=2,
211+
gene_type=[float, 1],
212+
num_genes=5,
213+
crossover_type=None,
214+
mutation_by_replacement=False,
215+
allow_duplicate_genes=False)
216+
217+
num_duplicates = 0
218+
for idx, solution in enumerate(ga_instance.solutions):
219+
num = len(solution) - len(set(solution))
220+
if num != 0:
221+
print(solution, idx)
222+
num_duplicates += num
223+
224+
assert num_duplicates == 0
225+
226+
initial_population = ga_instance.initial_population
227+
# print(initial_population)
228+
229+
assert numpy.all(initial_population[:, 0] >= 1), "Not all values in column 0 >= 1"
230+
assert numpy.all(initial_population[:, 1] >= 1), "Not all values in column 1 >= 1"
231+
assert numpy.all(initial_population[:, 2] >= 1), "Not all values in column 2 >= 1"
232+
assert numpy.all(initial_population[:, 3] >= 1), "Not all values in column 3 >= 1"
233+
assert numpy.all(initial_population[:, 4] >= 1), "Not all values in column 4 >= 1"
234+
print("All constraints are met")
235+
236+
def test_initial_population_float_by_replacement_no_duplicates_None_constraints():
237+
gene_constraint=[lambda x,v: [val for val in v if val>=1],
238+
None,
239+
lambda x,v: [val for val in v if val>=1],
240+
None,
241+
lambda x,v: [val for val in v if val>=1]]
184242
ga_instance = population_gene_constraint(gene_constraint=gene_constraint,
185243
init_range_low=1,
186244
init_range_high=2,
@@ -207,6 +265,7 @@ def test_initial_population_float_by_replacement_no_duplicates2():
207265
assert numpy.all(initial_population[:, 2] >= 1), "Not all values in column 2 >= 1"
208266
assert numpy.all(initial_population[:, 3] >= 1), "Not all values in column 3 >= 1"
209267
assert numpy.all(initial_population[:, 4] >= 1), "Not all values in column 4 >= 1"
268+
print("All constraints are met")
210269

211270
if __name__ == "__main__":
212271
#### Single-objective
@@ -221,3 +280,5 @@ def test_initial_population_float_by_replacement_no_duplicates2():
221280
print()
222281
test_initial_population_float_by_replacement_no_duplicates2()
223282
print()
283+
test_initial_population_float_by_replacement_no_duplicates_None_constraints()
284+
print()

0 commit comments

Comments
 (0)