Skip to content

Commit c5d35dc

Browse files
committed
Apply constraints with duplicates
1 parent 1305536 commit c5d35dc

File tree

13 files changed

+965
-78
lines changed

13 files changed

+965
-78
lines changed

example.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,17 @@ def fitness_func(ga_instance, solution, solution_idx):
1717
num_genes=num_genes,
1818
mutation_num_genes=6,
1919
fitness_func=fitness_func,
20-
init_range_low=4,
21-
init_range_high=10,
20+
init_range_low=1,
21+
init_range_high=100,
2222
# suppress_warnings=True,
23-
random_mutation_min_val=4,
24-
random_mutation_max_val=10,
23+
random_mutation_min_val=1,
24+
random_mutation_max_val=100,
2525
mutation_by_replacement=True,
2626
gene_type=int,
27+
allow_duplicate_genes=False,
2728
# mutation_probability=0.4,
28-
gene_constraint=[lambda x: x[0]>=8,None,None,None,None,None])
29+
# gene_constraint=[lambda x: x[0]>=8,None,None,None,None,None],
30+
gene_constraint=[lambda x: x[0]>=98,lambda x: x[1]>=98,lambda x: x[2]<98,lambda x: x[3]<98,lambda x: x[4]<98,lambda x: x[5]<98],
31+
)
2932

3033
# ga_instance.run()
184 Bytes
Binary file not shown.
1.23 KB
Binary file not shown.
42 Bytes
Binary file not shown.

pygad/helper/misc.py

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,27 @@
99

1010
class Helper:
1111

12+
def get_gene_dtype(self, gene_index):
13+
14+
"""
15+
Returns the data type of the gene by its index.
16+
It accepts a single parameter:
17+
-gene_index: The index of the gene to get its data type. Only used if each gene has its own data type.
18+
It returns the data type of the gene.
19+
"""
20+
21+
if self.gene_type_single == True:
22+
dtype = self.gene_type
23+
else:
24+
dtype = self.gene_type[gene_index]
25+
return dtype
26+
1227
def get_random_mutation_range(self, gene_index):
1328

1429
"""
1530
Returns the minimum and maximum values of the mutation range.
1631
It accepts a single parameter:
17-
-gene_index: The index of the gene to get its range. Only used if the gene has a specific mutation range
32+
-gene_index: The index of the gene to get its range. Only used if the gene has a specific mutation range.
1833
It returns the minimum and maximum values of the gene mutation range.
1934
"""
2035

@@ -51,7 +66,8 @@ def generate_gene_random_value(self,
5166
gene_value,
5267
gene_idx,
5368
mutation_by_replacement,
54-
num_values=1):
69+
num_values=1,
70+
step=1):
5571
"""
5672
Randomly generate one or more values for the gene.
5773
It accepts:
@@ -60,15 +76,39 @@ def generate_gene_random_value(self,
6076
-gene_value: The original gene value before applying mutation.
6177
-gene_idx: The index of the gene in the solution.
6278
-mutation_by_replacement: A flag indicating whether mutation by replacement is enabled or not. The reason is to make this helper method usable while generating the initial population. In this case, mutation_by_replacement does not matter and should be considered False.
63-
-num_values: The number of random valus to generate. It tries to generate a number of values up to a maximum of num_values. But it is not always guranteed because the total number of values might not be enough or the random generator creates duplicate random values.
64-
If num_values=1, it returns a single numeric value. If num_values>1, it returns an array with number of values equal to num_values.
79+
-num_values: The number of random valus to generate. It tries to generate a number of values up to a maximum of num_values. But it is not always guranteed because the total number of values might not be enough or the random generator creates duplicate random values. For int data types, it could be None to keep all the values. For flaot data types, a None value returns only a single value.
80+
-step (int, optional): The step size for generating candidate values. Defaults to 1. Only used with genes of an integer data type.
81+
82+
It returns,
83+
-A single numeric value if num_values=1. Or
84+
-An array with number of values equal to num_values if num_values>1.
6585
"""
6686

67-
# Generating a random value.
68-
random_value = numpy.asarray(numpy.random.uniform(low=range_min,
69-
high=range_max,
70-
size=num_values),
71-
dtype=object)
87+
gene_type = self.get_gene_dtype(gene_index=gene_idx)
88+
if gene_type[0] in pygad.GA.supported_int_types:
89+
random_value = numpy.asarray(numpy.arange(range_min,
90+
range_max,
91+
step=step),
92+
dtype=gene_type[0])
93+
if num_values is None:
94+
# Keep all the values.
95+
pass
96+
else:
97+
if num_values >= len(random_value):
98+
# Number of values is larger than or equal to the number of elements in random_value.
99+
# Makes no sense to create a larger sample out of the population because it just creates redundant values.
100+
pass
101+
else:
102+
# Set replace=True to avoid selecting the same value more than once.
103+
random_value = numpy.random.choice(random_value,
104+
size=num_values,
105+
replace=False)
106+
else:
107+
# Generating a random value.
108+
random_value = numpy.asarray(numpy.random.uniform(low=range_min,
109+
high=range_max,
110+
size=num_values),
111+
dtype=object)
72112

73113
# Change the random mutation value data type.
74114
for idx, val in enumerate(random_value):
@@ -97,7 +137,8 @@ def get_valid_gene_constraint_values(self,
97137
gene_idx,
98138
mutation_by_replacement,
99139
solution,
100-
num_values=100):
140+
num_values=100,
141+
step=1):
101142
"""
102143
Randomly generate values for the gene that satisfy the constraint.
103144
It accepts:
@@ -108,14 +149,21 @@ def get_valid_gene_constraint_values(self,
108149
-mutation_by_replacement: A flag indicating whether mutation by replacement is enabled or not. The reason is to make this helper method usable while generating the initial population. In this case, mutation_by_replacement does not matter and should be considered False.
109150
-solution: The solution in which the gene exists.
110151
-num_values: The number of random valus to generate. It tries to generate a number of values up to a maximum of num_values. But it is not always guranteed because the total number of values might not be enough or the random generator creates duplicate random values.
111-
If num_values=1, it returns a single numeric value. If num_values>1, it returns an array with number of values equal to num_values.
152+
-step (int, optional): The step size for generating candidate values. Defaults to 1. Only used with genes of an integer data type.
153+
154+
It returns,
155+
-A single numeric value if num_values=1. Or
156+
-An array with number of values equal to num_values if num_values>1. Or
157+
-None if no value found that satisfies the constraint.
112158
"""
113159
random_values = self.generate_gene_random_value(range_min=range_min,
114160
range_max=range_max,
115161
gene_value=gene_value,
116162
gene_idx=gene_idx,
117163
mutation_by_replacement=mutation_by_replacement,
118-
num_values=num_values)
164+
num_values=num_values,
165+
step=step)
166+
# It returns None if no value found that satisfies the constraint.
119167
random_values_filtered = self.mutation_filter_values_by_constraint(random_values=random_values,
120168
solution=solution,
121169
gene_idx=gene_idx)

0 commit comments

Comments
 (0)