使用Python numpy实现有上下边界约束的整数划分(分苹果)问题

问题定义

整数划分问题,是一种典型的数学规划问题,以分苹果为例,即将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 Nlow<=M<=Nup
(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 NK的盘子为空,这需要增加一个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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值