PyGAD 中的惩罚函数未按预期工作
我正在尝试使用 PyGAD 来解决最小化问题,这是我正在尝试实现的更大算法的一部分,但我不知道包含约束的适当方法。我尝试在适应度函数中添加 if 结构来为目标添加惩罚值,但它并不总是有效。
我试图解决的是一个二元决策问题,这意味着将一个矩形放置在一组点中,这些点在一个更大的矩形内定义一个网格,其中可能已经放置了一些矩形。当前函数仅考虑到已放置矩形的距离,但我可能会以奖励和惩罚的形式添加更多参数。避免超出站点边界的约束、矩形之间的重叠以及将矩形放置在避免某些特定区域或内部的位置,使问题变得相当复杂,所以这就是为什么我尝试使用一组离散的可能位置和 GA 来解决它。
我想我可以重新设计一些约束,也必须添加其他约束。我尝试使用 1/Distance 和 -Distance,因为 PyGAD 总是尝试最大化而我想最小化所述距离。我当前的适应度函数如下:
def fitness_func(solution, solution_idx):
Distance = 0
xi = sum(LookUpList[i][0]*solution[i] for i in range(len(LookUpList)))
yi = sum(LookUpList[i][1]*solution[i] for i in range(len(LookUpList)))
alphai = sum(LookUpList[i][2]*solution[i] for i in range(len(LookUpList)))
LXi = Stages[Current]['LX']
LYi = Stages[Current]['LY']
VXi = (LXi/2*(alphai-1)**2,LYi/2*alphai)
VYi = (LYi/2*(alphai-1)**2,LXi/2*alphai)
Penalty = np.inf
# Only placed in one spot
if sum(solution) > 1:
Distance += Penalty
# Site boundary constraint
if xi+VXi[0]+VXi[1] >= Site[0] or xi-VXi[0]-VXi[1] <= 0 or yi+VYi[0]+VYi[1] >= Site[1] or yi-VYi[0]-VYi[1] <= 0:
Distance += 1000*max(Site)
# Avoid overlap between facilities
for p in Previous:
xp = Stages[p]['X']
yp = Stages[p]['Y']
alphap = Stages[p]['Alpha']
LXp = Stages[p]['LX']
LYp = Stages[p]['LY']
VXp = (LXp/2*(alphap-1)**2,LYp/2*alphap)
VYp = (LYp/2*(alphap-1)**2,LXp/2*alphap)
if xi+VXi[0]+VXi[1] <= xp+VXp[0]+VXp[1] and xi-VXi[0]-VXi[1] >= xp-VXp[0]-VXp[1] and yi+VYi[0]+VYi[1] <= xp+VYp[0]+VYp[1] and yi-VYi[0]-VYi[1] >= xp-VYp[0]-VYp[1]:
Distance += Penalty
# Zones where a certain facility can't be placed
for e in ExclusionZones:
if Current == ExclusionZones[e]['Facility']:
xp = ExclusionZones[e]['X']
yp = ExclusionZones[e]['Y']
LXp = ExclusionZones[e]['LX']
LYp = ExclusionZones[e]['LY']
if xi+VXi[0]+VXi[1] <= xp+LXp/2 and xi-VXi[0]-VXi[1] >= xp-LXp/2 and yi+VYi[0]+VYi[1] <= xp+LXp/2 and yi-VYi[0]-VYi[1] >= xp-LXp/2:
Distance += Penalty
for p in Previous:
Distance += abs(xi-Stages[p]['X']) + abs(yi-Stages[p]['Y'])
fitness = - Distance
return fitness
GA 的配置及其执行如下:
num_generations = 150
num_parents_mating = 2
sol_per_pop = 10
num_genes = 2*(Grid[0]-1)*(Grid[1]-1)
gene_type = int
init_range_low = random_mutation_min_val = 0
init_range_high = random_mutation_max_val = 2
parent_selection_type = 'sss'
keep_parents = 1
crossover_type = 'single_point'
mutation_type = 'random'
mutation_by_replacement = True
mutation_percent_genes = 10
save_solutions = False
ga_instance = pygad.GA(num_generations = num_generations,
num_parents_mating = num_parents_mating,
fitness_func = fitness_func,
sol_per_pop = sol_per_pop,
num_genes = num_genes,
gene_type = gene_type,
init_range_low = init_range_low,
init_range_high = init_range_high,
parent_selection_type = parent_selection_type,
keep_parents = keep_parents,
crossover_type = crossover_type,
mutation_type = mutation_type,
mutation_by_replacement = mutation_by_replacement,
mutation_percent_genes = mutation_percent_genes,
save_solutions = save_solutions
)
ga_instance.run()
我有一个函数,用于评估名为 Stages 的字典,该函数存储与算法相关的所有数据,从而给出最终的成本值。它与我运行 PyGAD 实例后得到的结果相匹配,但是当用另一个函数绘制解决方案时(我认为不相关,只是绘制了形状的 matplotlib 图),我可以看到解决方案并不总是在可行空间中。我可以理解由于网格有限而存在一些重叠,因此如果将新设施放置在一个位置稍低、稍高或稍侧,那么将这个位置放置在一个位置将是最佳解决方案。然而,如果惩罚函数考虑到重叠的程度,这可以调整,所以它不会让我那么困扰。
我不明白的是为什么成本函数只给我距离,不包括应该添加的惩罚值,因为它肯定违反了条件中规定的约束。我应该找到另一种方式来说明违反约束吗?
I'm trying to use PyGAD to solve a minimization problem which is part of a bigger algorithm I'm trying to implement, but I have no idea on the appropiate way to include the constraints. I've tried to add if structures to the fitness function to add a penalty value to the objective, but it isn't always working.
What I'm trying to solve is a binary decision problem, which is meant to place a rectangle in a set of points that define a grid inside a bigger rectangle in which some rectangles might have been already placed. The current function just takes into account the distance to the already placed rectangles, but I'll probably add more parameters in the form of rewards and penalties. The constraints to avoid exceeding the site boundaries, the overlap between rectangles and placing the rectangle avoiding or inside some specific zones, make the problem quite complex, so thats why I'm trying to use a discrete set of possible locations and the GA to solve it.
I think I can rework some constraints, also have to add others. I tried using 1/Distance and -Distance, due to the fact that PyGAD always tries to maximize and I want to minimize said Distance. My current fitness function is the following:
def fitness_func(solution, solution_idx):
Distance = 0
xi = sum(LookUpList[i][0]*solution[i] for i in range(len(LookUpList)))
yi = sum(LookUpList[i][1]*solution[i] for i in range(len(LookUpList)))
alphai = sum(LookUpList[i][2]*solution[i] for i in range(len(LookUpList)))
LXi = Stages[Current]['LX']
LYi = Stages[Current]['LY']
VXi = (LXi/2*(alphai-1)**2,LYi/2*alphai)
VYi = (LYi/2*(alphai-1)**2,LXi/2*alphai)
Penalty = np.inf
# Only placed in one spot
if sum(solution) > 1:
Distance += Penalty
# Site boundary constraint
if xi+VXi[0]+VXi[1] >= Site[0] or xi-VXi[0]-VXi[1] <= 0 or yi+VYi[0]+VYi[1] >= Site[1] or yi-VYi[0]-VYi[1] <= 0:
Distance += 1000*max(Site)
# Avoid overlap between facilities
for p in Previous:
xp = Stages[p]['X']
yp = Stages[p]['Y']
alphap = Stages[p]['Alpha']
LXp = Stages[p]['LX']
LYp = Stages[p]['LY']
VXp = (LXp/2*(alphap-1)**2,LYp/2*alphap)
VYp = (LYp/2*(alphap-1)**2,LXp/2*alphap)
if xi+VXi[0]+VXi[1] <= xp+VXp[0]+VXp[1] and xi-VXi[0]-VXi[1] >= xp-VXp[0]-VXp[1] and yi+VYi[0]+VYi[1] <= xp+VYp[0]+VYp[1] and yi-VYi[0]-VYi[1] >= xp-VYp[0]-VYp[1]:
Distance += Penalty
# Zones where a certain facility can't be placed
for e in ExclusionZones:
if Current == ExclusionZones[e]['Facility']:
xp = ExclusionZones[e]['X']
yp = ExclusionZones[e]['Y']
LXp = ExclusionZones[e]['LX']
LYp = ExclusionZones[e]['LY']
if xi+VXi[0]+VXi[1] <= xp+LXp/2 and xi-VXi[0]-VXi[1] >= xp-LXp/2 and yi+VYi[0]+VYi[1] <= xp+LXp/2 and yi-VYi[0]-VYi[1] >= xp-LXp/2:
Distance += Penalty
for p in Previous:
Distance += abs(xi-Stages[p]['X']) + abs(yi-Stages[p]['Y'])
fitness = - Distance
return fitness
The configuration of the GA and it's execution are done as follows:
num_generations = 150
num_parents_mating = 2
sol_per_pop = 10
num_genes = 2*(Grid[0]-1)*(Grid[1]-1)
gene_type = int
init_range_low = random_mutation_min_val = 0
init_range_high = random_mutation_max_val = 2
parent_selection_type = 'sss'
keep_parents = 1
crossover_type = 'single_point'
mutation_type = 'random'
mutation_by_replacement = True
mutation_percent_genes = 10
save_solutions = False
ga_instance = pygad.GA(num_generations = num_generations,
num_parents_mating = num_parents_mating,
fitness_func = fitness_func,
sol_per_pop = sol_per_pop,
num_genes = num_genes,
gene_type = gene_type,
init_range_low = init_range_low,
init_range_high = init_range_high,
parent_selection_type = parent_selection_type,
keep_parents = keep_parents,
crossover_type = crossover_type,
mutation_type = mutation_type,
mutation_by_replacement = mutation_by_replacement,
mutation_percent_genes = mutation_percent_genes,
save_solutions = save_solutions
)
ga_instance.run()
I have a function that evaluates the dictionary called Stages, which stores all the data relevant to the algorithm, that gives me the final cost value. It matches the one I get after running the PyGAD instance, but when plotting the solution with another function (I don't think is relevant, just a matplotlib figure with shapes drawn) I can see the solution isn´t always in the feasible space. I can understand some overlap due to the grid being finite so placing the new facility in one spot would be the best solution if this spot was placed a little bit lower, upper or to the side. However, this could be adjusted if the penalty function took into account how much it overlaps, so it doesn't bother me that much.
What I dont understand is why the cost function just gives me the distance, not including the penalty value that should be added as it's definitely violating the constraint stated in the condition. Should I find another way of stating constraint violation?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论