@@ -84,7 +84,8 @@ def solve_duplicate_genes_randomly(self,
84
84
def solve_duplicate_genes_by_space (self ,
85
85
solution ,
86
86
gene_type ,
87
- num_trials = 10 ,
87
+ mutation_by_replacement ,
88
+ sample_size = 100 ,
88
89
build_initial_pop = False ):
89
90
90
91
"""
@@ -93,7 +94,7 @@ def solve_duplicate_genes_by_space(self,
93
94
Args:
94
95
solution (list): A solution containing genes, potentially with duplicate values.
95
96
gene_type (type): The data type of the gene (e.g., int, float).
96
- num_trials (int): The maximum number of attempts to resolve duplicates by selecting values from the gene space.
97
+ sample_size (int): The maximum number of attempts to resolve duplicates by selecting values from the gene space.
97
98
98
99
Returns:
99
100
tuple:
@@ -106,16 +107,16 @@ def solve_duplicate_genes_by_space(self,
106
107
107
108
_ , unique_gene_indices = numpy .unique (solution , return_index = True )
108
109
not_unique_indices = set (range (len (solution ))) - set (unique_gene_indices )
109
- # self.logger.info("not_unique_indices OUTSIDE", not_unique_indices)
110
110
111
111
# First try to solve the duplicates.
112
112
# For a solution like [3 2 0 0], the indices of the 2 duplicating genes are 2 and 3.
113
113
# The next call to the find_unique_value() method tries to change the value of the gene with index 3 to solve the duplicate.
114
114
if len (not_unique_indices ) > 0 :
115
- new_solution , not_unique_indices , num_unsolved_duplicates = self .unique_genes_by_space (new_solution = new_solution ,
115
+ new_solution , not_unique_indices , num_unsolved_duplicates = self .unique_genes_by_space (solution = new_solution ,
116
116
gene_type = gene_type ,
117
117
not_unique_indices = not_unique_indices ,
118
- num_trials = 10 ,
118
+ sample_size = sample_size ,
119
+ mutation_by_replacement = mutation_by_replacement ,
119
120
build_initial_pop = build_initial_pop )
120
121
else :
121
122
return new_solution , not_unique_indices , len (not_unique_indices )
@@ -260,30 +261,34 @@ def select_unique_value(self, gene_values, solution, gene_index):
260
261
values_to_select_from = list (set (list (gene_values )) - set (solution ))
261
262
262
263
if len (values_to_select_from ) == 0 :
264
+ print ("@@@@@@@@" )
265
+ print (solution )
266
+ print (gene_values )
263
267
# If there are no values, then keep the current gene value.
264
- if not self .suppress_warnings : warnings .warn (f"'allow_duplicate_genes=False' but cannot find a unique value for the gene at index { gene_index } ." )
268
+ if not self .suppress_warnings : warnings .warn (f"'allow_duplicate_genes=False' but cannot find a unique value for the gene at index { gene_index } with value { solution [ gene_index ] } ." )
265
269
selected_value = solution [gene_index ]
266
270
else :
267
271
selected_value = random .choice (values_to_select_from )
268
272
269
273
return selected_value
270
274
271
275
def unique_genes_by_space (self ,
272
- new_solution ,
276
+ solution ,
273
277
gene_type ,
274
- not_unique_indices ,
275
- num_trials = 10 ,
278
+ not_unique_indices ,
279
+ mutation_by_replacement ,
280
+ sample_size = 100 ,
276
281
build_initial_pop = False ):
277
282
278
283
"""
279
284
Iterates through all duplicate genes to find unique values from their gene spaces and resolve duplicates.
280
285
For each duplicate gene, a call is made to the `unique_gene_by_space()` function.
281
286
282
287
Args:
283
- new_solution (list): A solution containing genes with duplicate values.
288
+ solution (list): A solution containing genes with duplicate values.
284
289
gene_type (type): The data type of the all the genes (e.g., int, float).
285
290
not_unique_indices (list): The indices of genes with duplicate values.
286
- num_trials (int): The maximum number of attempts to resolve duplicates for each gene. Only works for floating-point numbers.
291
+ sample_size (int): The maximum number of attempts to resolve duplicates for each gene. Only works for floating-point numbers.
287
292
288
293
Returns:
289
294
tuple:
@@ -294,31 +299,33 @@ def unique_genes_by_space(self,
294
299
295
300
num_unsolved_duplicates = 0
296
301
for duplicate_index in not_unique_indices :
297
- temp_val = self .unique_gene_by_space (solution = new_solution ,
302
+ temp_val = self .unique_gene_by_space (solution = solution ,
298
303
gene_idx = duplicate_index ,
299
304
gene_type = gene_type ,
300
- build_initial_pop = build_initial_pop ,
301
- num_trials = num_trials )
305
+ mutation_by_replacement = mutation_by_replacement ,
306
+ sample_size = sample_size ,
307
+ build_initial_pop = build_initial_pop )
302
308
303
- if temp_val in new_solution :
304
- # self.logger.info("temp_val, duplicate_index", temp_val, duplicate_index, new_solution )
309
+ if temp_val in solution :
310
+ # self.logger.info("temp_val, duplicate_index", temp_val, duplicate_index, solution )
305
311
num_unsolved_duplicates = num_unsolved_duplicates + 1
306
- if not self .suppress_warnings : warnings .warn (f"Failed to find a unique value for gene with index { duplicate_index } whose value is { new_solution [duplicate_index ]} . Consider adding more values in the gene space or use a wider range for initial population or random mutation." )
312
+ if not self .suppress_warnings : warnings .warn (f"Failed to find a unique value for gene with index { duplicate_index } whose value is { solution [duplicate_index ]} . Consider adding more values in the gene space or use a wider range for initial population or random mutation." )
307
313
else :
308
- new_solution [duplicate_index ] = temp_val
314
+ solution [duplicate_index ] = temp_val
309
315
310
316
# Update the list of duplicate indices after each iteration.
311
- _ , unique_gene_indices = numpy .unique (new_solution , return_index = True )
312
- not_unique_indices = set (range (len (new_solution ))) - set (unique_gene_indices )
317
+ _ , unique_gene_indices = numpy .unique (solution , return_index = True )
318
+ not_unique_indices = set (range (len (solution ))) - set (unique_gene_indices )
313
319
314
- return new_solution , not_unique_indices , num_unsolved_duplicates
320
+ return solution , not_unique_indices , num_unsolved_duplicates
315
321
316
322
def unique_gene_by_space (self ,
317
323
solution ,
318
324
gene_idx ,
319
- gene_type ,
320
- build_initial_pop = False ,
321
- num_trials = 10 ):
325
+ gene_type ,
326
+ mutation_by_replacement ,
327
+ sample_size = 100 ,
328
+ build_initial_pop = False ):
322
329
323
330
"""
324
331
Returns a unique value for a specific gene based on its value space to resolve duplicates.
@@ -327,15 +334,47 @@ def unique_gene_by_space(self,
327
334
solution (list): A solution containing genes with duplicate values.
328
335
gene_idx (int): The index of the gene that has a duplicate value.
329
336
gene_type (type): The data type of the gene (e.g., int, float).
330
- num_trials (int): The maximum number of attempts to resolve duplicates for each gene. Only works for floating-point numbers.
337
+ sample_size (int): The maximum number of attempts to resolve duplicates for each gene. Only works for floating-point numbers.
331
338
332
339
Returns:
333
340
Any: A unique value for the gene, if one exists; otherwise, the original gene value.
334
341
"""
335
342
343
+ # When gene_value is None, this forces the gene value generators to select a value for use by the initial population.
344
+ # Otherwise, it considers selecting a value for mutation.
345
+ if build_initial_pop :
346
+ gene_value = None
347
+ else :
348
+ gene_value = solution [gene_idx ]
336
349
350
+ if self .gene_constraint and self .gene_constraint [gene_idx ]:
351
+ # A unique value is created out of the values that satisfy the constraint.
352
+ values = self .get_valid_gene_constraint_values (range_min = None ,
353
+ range_max = None ,
354
+ gene_value = gene_value ,
355
+ gene_idx = gene_idx ,
356
+ mutation_by_replacement = mutation_by_replacement ,
357
+ solution = solution ,
358
+ sample_size = sample_size )
359
+ # If there is no value satisfying the constraint, then return the current gene value.
360
+ if values is None :
361
+ return solution [gene_idx ]
362
+ else :
363
+ pass
364
+ else :
365
+ # There is no constraint for the current gene. Return the same range.
366
+ values = self .generate_gene_value (range_min = None ,
367
+ range_max = None ,
368
+ gene_value = gene_value ,
369
+ gene_idx = gene_idx ,
370
+ mutation_by_replacement = mutation_by_replacement ,
371
+ sample_size = sample_size )
337
372
338
- return value_from_space
373
+ selected_value = self .select_unique_value (gene_values = values ,
374
+ solution = solution ,
375
+ gene_index = gene_idx )
376
+
377
+ return selected_value
339
378
340
379
def find_two_duplicates (self ,
341
380
solution ,
0 commit comments