Skip to content

Commit baf628d

Browse files
add constraint-awareness
1 parent 539735c commit baf628d

File tree

1 file changed

+40
-5
lines changed

1 file changed

+40
-5
lines changed

kernel_tuner/strategies/diff_evo.py

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""A simple Different Evolution for parameter search."""
2-
2+
import random
33
import re
44
import numpy as np
55

@@ -14,6 +14,7 @@
1414
F=("mutation factor (differential weight)", 0.8),
1515
CR=("crossover rate", 0.9),
1616
method=("method", "best1bin"),
17+
constraint_aware=("constraint-aware optimization (True/False)", True),
1718
)
1819

1920
supported_methods = [
@@ -37,13 +38,13 @@ def tune(searchspace: Searchspace, runner, tuning_options):
3738
bounds = cost_func.get_bounds()
3839

3940
options = tuning_options.strategy_options
40-
popsize, maxiter, F, CR, method = common.get_options(options, _options)
41+
popsize, maxiter, F, CR, method, constraint_aware = common.get_options(options, _options)
4142

4243
if method not in supported_methods:
4344
raise ValueError(f"Error {method} not supported, {supported_methods=}")
4445

4546
try:
46-
differential_evolution(searchspace, cost_func, bounds, popsize, maxiter, F, CR, method, tuning_options.verbose)
47+
differential_evolution(searchspace, cost_func, bounds, popsize, maxiter, F, CR, method, constraint_aware, tuning_options.verbose)
4748
except util.StopCriterionReached as e:
4849
if tuning_options.verbose:
4950
print(e)
@@ -96,7 +97,7 @@ def random_draw(idxs, mutate, best):
9697
return np.random.choice(idxs, draw, replace=draw >= len(idxs))
9798

9899

99-
def differential_evolution(searchspace, cost_func, bounds, popsize, maxiter, F, CR, method, verbose):
100+
def differential_evolution(searchspace, cost_func, bounds, popsize, maxiter, F, CR, method, constraint_aware, verbose):
100101
"""
101102
A basic implementation of the Differential Evolution algorithm.
102103
@@ -114,7 +115,18 @@ def differential_evolution(searchspace, cost_func, bounds, popsize, maxiter, F,
114115
bounds = np.array(bounds)
115116

116117
# Initialize the population with random individuals within the bounds
117-
population = np.array(list(list(p) for p in searchspace.get_random_sample(popsize)))
118+
if constraint_aware:
119+
population = np.array(list(list(p) for p in searchspace.get_random_sample(popsize)))
120+
else:
121+
population = []
122+
dna_size = len(self.tune_params)
123+
for _ in range(self.pop_size):
124+
dna = []
125+
for key in self.tune_params:
126+
dna.append(random.choice(self.tune_params[key]))
127+
population.append(dna)
128+
population = np.array(population)
129+
118130
population[0] = cost_func.get_start_pos()
119131

120132
# Calculate the initial cost for each individual in the population
@@ -155,6 +167,10 @@ def differential_evolution(searchspace, cost_func, bounds, popsize, maxiter, F,
155167
# --- b. Crossover ---
156168
trial_vector = crossover_method(donor_vector, population[i], CR)
157169

170+
# Repair if constraint_aware
171+
if constraint_aware:
172+
trial_vector = repair(trial_vector, searchspace)
173+
158174
# Store for selection
159175
trial_population.append(trial_vector)
160176

@@ -319,6 +335,25 @@ def exponential_crossover(donor_vector, target, CR):
319335
return trial_idx
320336

321337

338+
def repair(trial_vector, searchspace):
339+
"""
340+
Attempts to repair trial_vector if trial_vector is invalid
341+
"""
342+
if not searchspace.is_param_config_valid(tuple(trial_vector)):
343+
# search for valid configurations neighboring trial_vector
344+
# start from strictly-adjacent to increasingly allowing more neighbors
345+
for neighbor_method in ["strictly-adjacent", "adjacent", "Hamming"]:
346+
neighbors = searchspace.get_neighbors_no_cache(tuple(trial_vector), neighbor_method=neighbor_method)
347+
348+
# if we have found valid neighboring configurations, select one at random
349+
if len(neighbors) > 0:
350+
new_trial_vector = np.array(list(random.choice(neighbors)))
351+
print(f"Differential evolution resulted in invalid config {trial_vector=}, repaired dna to {new_trial_vector=}")
352+
return new_trial_vector
353+
354+
return trial_vector
355+
356+
322357
mutation = {
323358
"1": mutate_de_1,
324359
"2": mutate_de_2,

0 commit comments

Comments
 (0)