问题定义
整数划分问题,是一种典型的数学规划问题,以分苹果为例,即将M个苹果,随机分到N个盘子中。传统的整数划分问题已经得到了广泛的求解,可以参考:https://blog.csdn.net/sunshine_lyn/article/details/79476355?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-5.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-5.channel_param。
我们这里提到的是有上下边界约束的整数划分,即:每个盘子最少放Low,最多不能超过Up个,且可以实现整分。
之所以要写这篇文章,因为网上现在找不到带有上下边界约束的整数划分的Python代码(也有可能是我找的姿势不对),所以写一个,分享给大家。
约束条件
(1)苹果总数为:M
(2)盘子总数为:N,且满足
N
<
M
N<M
N<M
(3)下边界:low,下边界:up,满足
l
o
w
<
u
p
low<up
low<up
(4)整体满足:
N
∗
l
o
w
<
=
M
<
=
N
∗
u
p
N*low<=M<=N*up
N∗low<=M<=N∗up
(5)苹果需整分,不可以出现小数;
实现思路
(1)随机产生N个有上下边界约束的整数,然后用M做缩放,此时会导致两个问题,①个是总和因取整导致接近M,不等于M,②是部分满足上下边界约束的整数超出了约束的范围。
(2)针对问题②,先判别出来,然后使之调整,满足上下边界约束,然后再针对问题①做随机调平。最终得到结果。
实现代码
import numpy as np
def initial_dsf_without_choice(low,up,x_dim,E_setting):
solution = np.random.randint(low=low, high=up + 1,size=(x_dim)) # 新建的设施
print("第1步:初始随机个体的基因值")
print(solution)
print(np.sum(solution))
solution = (solution * (E_setting / np.sum(solution))).astype(np.int) # 规模介于up和low之间
print("第2步:最大值整数约束")
print(solution)
print(np.sum(solution))
# 会存在部分因最大值整数约束,而超限的数值,需要先处理到【low,up】范围内
while np.sum(solution[solution<low])>0 or np.sum(solution[solution>up])>0:
solution[solution<low]+=1
solution[solution>up]-=1
print("第3步:超限的数值处理到【low,up】范围内")
print(solution)
print(np.sum(solution))
# 补齐因最大值整数约束导致的部分值丢失
#该方法对于极限情况,如:30,100,会存在多次循环的问题,所以增加一个判别条件,让其不至于循环很久,提高效率,但是这种方法有极小的可能性会导致值不准确,目前忽略未用
iteation_count=0
while np.sum(solution) != E_setting:
delate = np.sum(solution) - E_setting
if delate > 0:
adjust_mark = -1
else:
adjust_mark = +1
for adjust_i in range(np.abs(delate)):
adjust_index = np.random.choice(a=[i for i in range(x_dim)], size=1, replace=False)
if solution[adjust_index] > low and solution[adjust_index] < up:
solution[adjust_index] += adjust_mark
#特殊情况下会有BUG,补充一下语句
if delate > 0 and solution[adjust_index] == up:
solution[adjust_index] += adjust_mark
if delate < 0 and solution[adjust_index] == low:
solution[adjust_index] += adjust_mark
# if iteation_count<100:
# iteation_count+=1
# else:
# break
print("第4步:补齐因最大值整数约束导致的部分值丢失")
print(solution)
print(np.sum(solution))
return solution
def test_initial_dsf_without_choice():
#总和值大于等于30,小于等于100
print("#####################################################")
initial_dsf_without_choice(3,10,10,30)
print("#####################################################")
initial_dsf_without_choice(3,10,10,33)
print("#####################################################")
initial_dsf_without_choice(3,10,10,36)
print("#####################################################")
initial_dsf_without_choice(3,10,10,50)
print("#####################################################")
initial_dsf_without_choice(3,10,10,60)
print("#####################################################")
initial_dsf_without_choice(3,10,10,70)
print("#####################################################")
initial_dsf_without_choice(3,10,10,94)
print("#####################################################")
initial_dsf_without_choice(3,10,10,99)
print("#####################################################")
initial_dsf_without_choice(3,10,10,100)
if __name__=="__main__":
test_initial_dsf_without_choice()
测试结果
以下为测试结果,符合要求
E:\Anaconda\python.exe E:/02research/000github/E_multi-objective-optimization-NSGA2/B_MOO_NSGA3_0920_THEROY/function_test.py
#####################################################
第1步:初始随机个体的基因值
[9 9 5 4 5 4 3 4 9 7]
59
第2步:最大值整数约束
[4 4 2 2 2 2 1 2 4 3]
26
第3步:超限的数值处理到【low,up】范围内
[4 4 3 3 3 3 3 3 4 3]
33
第4步:补齐因最大值整数约束导致的部分值丢失
[3 3 3 3 3 3 3 3 3 3]
30
#####################################################
第1步:初始随机个体的基因值
[9 7 7 6 4 6 8 5 6 5]
63
第2步:最大值整数约束
[4 3 3 3 2 3 4 2 3 2]
29
第3步:超限的数值处理到【low,up】范围内
[4 3 3 3 3 3 4 3 3 3]
32
第4步:补齐因最大值整数约束导致的部分值丢失
[4 3 3 3 3 3 5 3 3 3]
33
#####################################################
第1步:初始随机个体的基因值
[10 10 7 7 6 8 5 7 7 5]
72
第2步:最大值整数约束
[5 5 3 3 3 4 2 3 3 2]
33
第3步:超限的数值处理到【low,up】范围内
[5 5 3 3 3 4 3 3 3 3]
35
第4步:补齐因最大值整数约束导致的部分值丢失
[6 5 3 3 3 4 3 3 3 3]
36
#####################################################
第1步:初始随机个体的基因值
[ 3 4 4 10 7 3 7 8 3 6]
55
第2步:最大值整数约束
[2 3 3 9 6 2 6 7 2 5]
45
第3步:超限的数值处理到【low,up】范围内
[3 3 3 9 6 3 6 7 3 5]
48
第4步:补齐因最大值整数约束导致的部分值丢失
[3 3 3 9 7 3 6 8 3 5]
50
#####################################################
第1步:初始随机个体的基因值
[4 6 3 8 4 5 9 9 5 5]
58
第2步:最大值整数约束
[4 6 3 8 4 5 9 9 5 5]
58
第3步:超限的数值处理到【low,up】范围内
[4 6 3 8 4 5 9 9 5 5]
58
第4步:补齐因最大值整数约束导致的部分值丢失
[ 4 6 3 8 4 5 10 9 5 6]
60
#####################################################
第1步:初始随机个体的基因值
[7 9 7 7 6 7 7 8 4 4]
66
第2步:最大值整数约束
[7 9 7 7 6 7 7 8 4 4]
66
第3步:超限的数值处理到【low,up】范围内
[7 9 7 7 6 7 7 8 4 4]
66
第4步:补齐因最大值整数约束导致的部分值丢失
[ 7 10 7 7 6 7 8 8 5 5]
70
#####################################################
第1步:初始随机个体的基因值
[9 7 6 4 9 4 5 6 3 5]
58
第2步:最大值整数约束
[14 11 9 6 14 6 8 9 4 8]
89
第3步:超限的数值处理到【low,up】范围内
[10 10 9 6 10 6 8 9 4 8]
80
第4步:补齐因最大值整数约束导致的部分值丢失
[10 10 10 10 10 7 10 10 7 10]
94
#####################################################
第1步:初始随机个体的基因值
[10 5 8 5 3 3 4 8 7 5]
58
第2步:最大值整数约束
[17 8 13 8 5 5 6 13 11 8]
94
第3步:超限的数值处理到【low,up】范围内
[10 8 10 8 5 5 6 10 10 8]
80
第4步:补齐因最大值整数约束导致的部分值丢失
[10 10 10 10 10 9 10 10 10 10]
99
#####################################################
第1步:初始随机个体的基因值
[ 9 4 5 10 6 5 7 9 3 10]
68
第2步:最大值整数约束
[13 5 7 14 8 7 10 13 4 14]
95
第3步:超限的数值处理到【low,up】范围内
[10 5 7 10 8 7 10 10 4 10]
81
第4步:补齐因最大值整数约束导致的部分值丢失
[10 10 10 10 10 10 10 10 10 10]
100
Process finished with exit code 0
讨论与拓展,增加 K K K随机选择约束
这种整数划分的难点在于增加了上下边界的约束,且是整数,目前存在的不足时极限条件下容易始终在while循环中,导致运行时间过长。
此外,还可以增加一种约束机制,即每次从
N
N
N个盘中,选
K
K
K个盘子,然后进行分苹果到
K
K
K个盘子中,存在
N
−
K
N-K
N−K的盘子为空,这需要增加一个Mark变量,来存放
0
,
1
0,1
0,1值。
def initial_dsf_with_choice(low,up,x_dim,E_setting,k):
#选择出k个盘子
choic_index_list = np.random.choice(a=[i for i in range(x_dim)], size=k,
replace=False)
creating_mark = np.full(shape=(x_dim), fill_value=0)
creating_mark[choic_index_list] = 1
solution = np.random.randint(low=low, high=up + 1,size=(x_dim)) # 新建的设施
solution=creating_mark*solution
print("第1步:初始随机个体的基因值")
print(solution)
print(np.sum(solution))
solution = (solution * (E_setting / np.sum(solution))).astype(np.int) # 规模介于up和low之间
print("第2步:最大值整数约束")
print(solution)
print(np.sum(solution))
# 会存在部分因最大值整数约束,而超限的数值,需要先处理到【low,up】范围内
#while np.sum(solution[choic_index_list][solution[choic_index_list]<low])>0 or np.sum(solution[solution>up])>0:
#solution[choic_index_list][solution[choic_index_list]<low]+=1
#solution[solution>up]-=1
#这一项不会有问题,之前的写法,会导致小于low的值更新不掉
while np.sum(solution[np.where((solution<low) & (solution!=0))])>0 or np.sum(solution[solution>up])>0:
solution[np.where((solution<low) & (solution!=0))]+=1
solution[solution>up]-=1
print("第3步:超限的数值处理到【low,up】范围内")
print(solution)
print(np.sum(solution))
# 补齐因最大值整数约束导致的部分值丢失
#该方法对于极限情况,如:30,100,会存在多次循环的问题,所以增加一个判别条件,让其不至于循环很久,提高效率,但是这种方法有极小的可能性会导致值不准确,目前忽略未用
iteation_count=0
while np.sum(solution) != E_setting:
delate = np.sum(solution) - E_setting
if delate > 0:
adjust_mark = -1
else:
adjust_mark = +1
for adjust_i in range(np.abs(delate)):
adjust_index = np.random.choice(a=choic_index_list, size=1, replace=False)
if solution[adjust_index] > low and solution[adjust_index] < up:
solution[adjust_index] += adjust_mark
#特殊情况下会有BUG,补充一下语句
if delate > 0 and solution[adjust_index] == up:
solution[adjust_index] += adjust_mark
if delate < 0 and solution[adjust_index] == low:
solution[adjust_index] += adjust_mark
# if iteation_count<100:
# iteation_count+=1
# else:
# break
print("第4步:补齐因最大值整数约束导致的部分值丢失")
print(solution)
print(np.sum(solution))
return solution
def test_initial_dsf_with_choice():
#总和值大于等于30,小于等于100
print("#####################################################")
initial_dsf_with_choice(3,10,10,30,4)
print("#####################################################")
initial_dsf_with_choice(3,10,10,33,4)
print("#####################################################")
initial_dsf_with_choice(3,10,10,36,5)
print("#####################################################")
initial_dsf_with_choice(3,10,10,50,8)
print("#####################################################")
initial_dsf_with_choice(3,10,10,60,6)
print("#####################################################")
initial_dsf_with_choice(3,10,10,70,8)
print("#####################################################")
initial_dsf_with_choice(3,10,10,94,10)
print("#####################################################")
initial_dsf_with_choice(3,10,10,99,10)
print("#####################################################")
initial_dsf_with_choice(3,10,10,100,10)
运行结果如下:
E:\Anaconda\python.exe E:/02research/000github/E_multi-objective-optimization-NSGA2/B_MOO_NSGA3_0920_THEROY/function_test.py
#####################################################
第1步:初始随机个体的基因值
[10 7 0 0 5 8 0 0 0 0]
30
第2步:最大值整数约束
[10 7 0 0 5 8 0 0 0 0]
30
第3步:超限的数值处理到【low,up】范围内
[10 7 0 0 5 8 0 0 0 0]
30
第4步:补齐因最大值整数约束导致的部分值丢失
[10 7 0 0 5 8 0 0 0 0]
30
#####################################################
第1步:初始随机个体的基因值
[ 0 0 0 0 8 8 9 0 0 10]
35
第2步:最大值整数约束
[0 0 0 0 7 7 8 0 0 9]
31
第3步:超限的数值处理到【low,up】范围内
[0 0 0 0 7 7 8 0 0 9]
31
第4步:补齐因最大值整数约束导致的部分值丢失
[0 0 0 0 8 7 9 0 0 9]
33
#####################################################
第1步:初始随机个体的基因值
[0 5 3 5 0 3 0 3 0 0]
19
第2步:最大值整数约束
[0 9 5 9 0 5 0 5 0 0]
33
第3步:超限的数值处理到【low,up】范围内
[0 9 5 9 0 5 0 5 0 0]
33
第4步:补齐因最大值整数约束导致的部分值丢失
[ 0 10 6 9 0 5 0 6 0 0]
36
#####################################################
第1步:初始随机个体的基因值
[ 7 10 6 4 7 4 5 0 0 3]
46
第2步:最大值整数约束
[ 7 10 6 4 7 4 5 0 0 3]
46
第3步:超限的数值处理到【low,up】范围内
[ 7 10 6 4 7 4 5 0 0 3]
46
第4步:补齐因最大值整数约束导致的部分值丢失
[ 7 10 7 4 8 5 6 0 0 3]
50
#####################################################
第1步:初始随机个体的基因值
[ 3 0 6 0 5 0 10 7 3 0]
34
第2步:最大值整数约束
[ 5 0 10 0 8 0 17 12 5 0]
57
第3步:超限的数值处理到【low,up】范围内
[ 5 0 10 0 8 0 10 10 5 0]
48
第4步:补齐因最大值整数约束导致的部分值丢失
[10 0 10 0 10 0 10 10 10 0]
60
#####################################################
第1步:初始随机个体的基因值
[ 3 4 4 0 7 0 10 8 8 8]
52
第2步:最大值整数约束
[ 4 5 5 0 9 0 13 10 10 10]
66
第3步:超限的数值处理到【low,up】范围内
[ 4 5 5 0 9 0 10 10 10 10]
63
第4步:补齐因最大值整数约束导致的部分值丢失
[ 7 5 8 0 10 0 10 10 10 10]
70
#####################################################
第1步:初始随机个体的基因值
[ 9 6 10 7 3 5 5 7 4 8]
64
第2步:最大值整数约束
[13 8 14 10 4 7 7 10 5 11]
89
第3步:超限的数值处理到【low,up】范围内
[10 8 10 10 4 7 7 10 5 10]
81
第4步:补齐因最大值整数约束导致的部分值丢失
[10 10 10 10 7 8 10 10 9 10]
94
#####################################################
第1步:初始随机个体的基因值
[ 9 9 9 9 10 8 10 6 10 8]
88
第2步:最大值整数约束
[10 10 10 10 11 9 11 6 11 9]
97
第3步:超限的数值处理到【low,up】范围内
[10 10 10 10 10 9 10 6 10 9]
94
第4步:补齐因最大值整数约束导致的部分值丢失
[10 10 10 10 10 10 10 9 10 10]
99
#####################################################
第1步:初始随机个体的基因值
[ 6 6 3 6 7 10 7 3 5 3]
56
第2步:最大值整数约束
[10 10 5 10 12 17 12 5 8 5]
94
第3步:超限的数值处理到【low,up】范围内
[10 10 5 10 10 10 10 5 8 5]
83
第4步:补齐因最大值整数约束导致的部分值丢失
[10 10 10 10 10 10 10 10 10 10]
100
Process finished with exit code 0