前篇我们讲述了使用加权和法对多目标规划问题的优化,本篇将讲述使用目标规划法。
1. 原理
目标规划法,首先是为每个目标函数设定一个期望值(目标值)。
方案1: 然后构建一个新的目标函数,其形式如下:。其中,表示第个目标函数的权重。通过最小化,可以在满足各种约束的同时实现多目标的调和。这个距离也可以通过 范数来表达。此方法有些类似加权和法。
方案2:我们还可以把目标设定进约束里(类似层次分析法),将优先级高的目标设置为约束条件,从而降低目标函数的个数。即在约束里面增加 。
2.举例子
同样用之前的农场主问题:
假设一个农场主希望优化其土地上的作物种植布局,需要在以下两个目标之间取得平衡:
- 目标1:最大化农场产值(单位:元);
- 目标2:最小化化肥使用量(单位:千克)。
农场主有两种作物可以种植:作物A、作物B、作物C。设分别为种植作物A、B、C的面积。
- 已知A、B、C每亩作物的产值分别为1000元、1200元、1300元。则,目标1的函数:
- 每亩A、B、C作物分别需要化肥:20千克、30千克、33千克。则,目标2的函数:
- 总种植面积不超过100亩。即,
- 3种作物至少每个需要种10亩。
2.1. 设定目标值
在不清楚设什么目标值时候,我们还可以通过求解各个单目标的最优解,观察值,然后设目标值。
如我们使用 MindOpt APL建模语言对这个问题进行建模,并调用 MindOpt Solver 来求解。代码如下:
# ==================目标1======================= clear model; # ------建模-------Start----- # model_2_1.mapl # 变量 var x1 >= 10; var x2 >= 10; var x3 >= 10; # 目标 maximize obj: (1000 * x1 + 1200 * x2 + 1300 * x3); # 定义约束条件 subject to constraint1: x1 + x2 + x3 <= 100; # ------建模-------End----- #求解 option solver mindopt; # (可选)指定求解用的求解器,默认是MindOpt option mindopt_options 'print=0'; #设置求解器输出级别,减少过程打印 solve; # 求解 # 结果打印和检查结果 print "-----------------Display---------------"; display; print "其中,种", x1,"亩作物A,种",x2,"亩作物B,种",x3,"亩作物C。"; print "对应农场产值:", (1000 * x1 + 1200 * x2 + 1300 * x3),"千克。"; # ==================目标2======================= clear model; # ------建模-------Start----- # model_2_2.mapl # 变量 var x1 >= 10; var x2 >= 10; var x3 >= 10; # 目标 minimize obj: (20 * x1 + 30 * x2 + 33 * x3); # 定义约束条件 subject to constraint1: x1 + x2 + x3 <= 100; # ------建模-------End----- #求解 option solver mindopt; # (可选)指定求解用的求解器,默认是MindOpt option mindopt_options 'print=0'; #设置求解器输出级别,减少过程打印 solve; # 求解 # 结果打印和检查结果 print "-----------------Display---------------"; display; print "其中,种", x1,"亩作物A,种",x2,"亩作物B,种",x3,"亩作物C。"; print "对应化肥使用量:", (20 * x1 + 30 * x2 + 33 * x3),"千克。";
运行以上代码结果如下:
Running mindoptampl wantsol=1 print=0 MindOpt Version 0.25.1 (Build date: 20230816) Copyright (c) 2020-2023 Alibaba Cloud. Start license validation (current time : 13-OCT-2023 15:54:20). License validation terminated. Time : 0.004s OPTIMAL; objective 126000.00 0 simplex iterations Completed. -----------------Display--------------- Primal Solution: x1 = 10.0000000 x2 = 10.0000000 x3 = 80.0000000 其中,种10亩作物A,种10亩作物B,种80亩作物C。 对应农场产值:126000千克。 Running mindoptampl wantsol=1 print=0 MindOpt Version 0.25.1 (Build date: 20230816) Copyright (c) 2020-2023 Alibaba Cloud. Start license validation (current time : 13-OCT-2023 15:54:20). License validation terminated. Time : 0.004s OPTIMAL; objective 830.00 0 simplex iterations Completed. -----------------Display--------------- Primal Solution: x1 = 10.0000000 x2 = 10.0000000 x3 = 10.0000000 其中,种10亩作物A,种10亩作物B,种10亩作物C。 对应化肥使用量:830千克。
从上面可以看出,目标1的最优值是126000千克,目标2的最优值是不种植多余的,只消耗830千克。接下来我们把这两个数值作为目标。
2.2. 方法1:设定优化目标距离
考虑到变量的取值域,这里我们直接采用(大数-小数)的方式来表示距离。
然后类似加权和法,我们引入两个权重参数和,分别表示农场产值和化肥使用量的重要程度,且满足,然后考虑两个目标的单位和数据量级不一样,我们引入参数来给目标2调整数量级。
MAPL代码如下:
# ==================设定目标转换后======================= clear model; # ------建模-------Start----- # model_2_3.mapl # 变量 var x1 >= 10; var x2 >= 10; var x3 >= 10; # 权重参数 param w1 = 0.7; # 假设农场主更关心农场产值 param w2 = 1 - w1; param c = 50; # 根据数量级差异 1000/20 = 50来简单预估 # 目标 minimize obj: w1 *(126000 - (1000 * x1 + 1200 * x2 + 1300 * x3)) + c*w2*((20 * x1 + 30 * x2 + 33 * x3) - 830); # 定义约束条件 subject to constraint1: x1 + x2 + x3 <= 100; # ------建模-------End----- #求解 option solver mindopt; # (可选)指定求解用的求解器,默认是MindOpt option mindopt_options 'print=0'; #设置求解器输出级别,减少过程打印 solve; # 求解 # 结果打印和检查结果 print "-----------------Display---------------"; display; print "改造的单目标最优是:",w1 *(126000 - (1000 * x1 + 1200 * x2 + 1300 * x3)) + c*w2*((20 * x1 + 30 * x2 + 33 * x3) - 830); print "其中,种", x1,"亩作物A,种",x2,"亩作物B,种",x3,"亩作物C。"; print "对应农场产值:", (1000 * x1 + 1200 * x2 + 1300 * x3),"元。"; print "对应化肥使用量:", (20 * x1 + 30 * x2 + 33 * x3),"千克。";
运行代码结果如下:
Running mindoptampl wantsol=1 print=0 MindOpt Version 0.25.1 (Build date: 20230816) Copyright (c) 2020-2023 Alibaba Cloud. Start license validation (current time : 13-OCT-2023 15:55:49). License validation terminated. Time : 0.006s OPTIMAL; objective 34650.00 0 simplex iterations Completed. -----------------Display--------------- Primal Solution: x1 = 10.0000000 x2 = 10.0000000 x3 = 80.0000000 改造的单目标最优是:34650.00000000001 其中,种10亩作物A,种10亩作物B,种80亩作物C。 对应农场产值:126000元。 对应化肥使用量:3140千克。
从上面可以看出,在本案例里面,目标改造与前面的加权和方法类似。
2.3. 方案2:将目标作为约束来求解最优
除了改造进目标,我们还可以改进约束里。观察上面的目标函数的最优值们:
- 最优是:种10亩作物A,种10亩作物B,种80亩作物C。对应农场产值:126000千克。
- 最优是:种10亩作物A,种10亩作物B,种10亩作物C。对应化肥使用量:830千克。
这里我们将的最优值作为约束,改造后如下:
# ==================设定目标转换后======================= clear model; # ------建模-------Start----- # model_2_3.mapl # 变量 var x1 >= 10; var x2 >= 10; var x3 >= 10; # 目标 minimize obj: 20 * x1 + 30 * x2 + 33 * x3; # 仅有F2(x) # 定义约束条件 subject to constraint1: x1 + x2 + x3 <= 100; subject to constraint_new: (1000 * x1 + 1200 * x2 + 1300 * x3) == 126000 ; # ------建模-------End----- #求解 option solver mindopt; # (可选)指定求解用的求解器,默认是MindOpt option mindopt_options 'print=0'; #设置求解器输出级别,减少过程打印 solve; # 求解 # 结果打印和检查结果 print "-----------------Display---------------"; display; print "其中,种{:.9g}亩作物A,种{:.9g}亩作物B,种{:.9g}亩作物C。" % x1,x2,x3; print "对应农场产值:", (1000 * x1 + 1200 * x2 + 1300 * x3),"元。"; print "对应化肥使用量:", (20 * x1 + 30 * x2 + 33 * x3),"千克。";
运行代码结果如下:
Running mindoptampl wantsol=1 print=0 MindOpt Version 0.25.1 (Build date: 20230816) Copyright (c) 2020-2023 Alibaba Cloud. Start license validation (current time : 13-OCT-2023 15:56:49). License validation terminated. Time : 0.006s OPTIMAL; objective 3140.00 3 simplex iterations Completed. -----------------Display--------------- Primal Solution: x1 = 10.0000000 x2 = 10.0000000 x3 = 80.0000000 其中,种10亩作物A,种10亩作物B,种80亩作物C。 对应农场产值:126000元。 对应化肥使用量:3140千克。
如果是把第二个目标的最优值设置进约束,结果就有些不合适了。如下:
# ==================设定目标转换后======================= clear model; # ------建模-------Start----- # model_2_3.mapl # 变量 var x1 >= 10; var x2 >= 10; var x3 >= 10; # 目标 minimize obj: (1000 * x1 + 1200 * x2 + 1300 * x3); # 仅有F1(x) # 定义约束条件 subject to constraint1: x1 + x2 + x3 <= 100; subject to constraint_new: (20 * x1 + 30 * x2 + 33 * x3) == 830 ; # ------建模-------End----- #求解 option solver mindopt; # (可选)指定求解用的求解器,默认是MindOpt option mindopt_options 'print=0'; #设置求解器输出级别,减少过程打印 solve; # 求解 # 结果打印和检查结果 print "-----------------Display---------------"; display; print "其中,种{:.9g}亩作物A,种{:.9g}亩作物B,种{:.9g}亩作物C。" % x1,x2,x3; print "对应农场产值:", (1000 * x1 + 1200 * x2 + 1300 * x3),"元。"; print "对应化肥使用量:", (20 * x1 + 30 * x2 + 33 * x3),"千克。";
运行结果如下:
Running mindoptampl wantsol=1 print=0 MindOpt Version 0.25.1 (Build date: 20230816) Copyright (c) 2020-2023 Alibaba Cloud. Start license validation (current time : 29-AUG-2023 11:35:49). License validation terminated. Time : 0.007s OPTIMAL; objective 35000.00 0 simplex iterations Completed. -----------------Display--------------- Primal Solution: x1 = 10.0000000 x2 = 10.0000000 x3 = 10.0000000 其中,种10亩作物A,种10亩作物B,种10亩作物C。 对应农场产值:35000元。 对应化肥使用量:830千克。
3.分析和改进
从上面可以看到:
- 直接设置进目标里面,效果会和加权和法类似。
- 如果设置进约束,是个不一样的思路,也可以得到解。其原理类似设置不同目标的优先级。但是选用不同的目标进约束会导致效果并不合适。
因此多目标转换时候,建议多尝试。可以考虑下述改进思路:
- 结合其他方法:例如与加权法结合,可以在考虑目标优先级的同时,更好地平衡各个目标之间的权重。
- 求解多个解决方案:尝试使用不同的目标优先级或权重组合,以生成多个解决方案。这些解决方案可以提供多个选择方向,有助于在实际应用中找到满意的平衡点。
- 使用交互式方法:在实际应用中,可以使用交互式方法,让决策者参与到优化过程中。在每一轮迭代中,决策者可以根据当前解决方案提供反馈。根据决策者的反馈,可以调整目标优先级或权重,从而在多轮迭代中逐渐找到满意的解决方案。