前篇我们讲述了使用加权和法对多目标规划问题的优化,本篇将讲述使用目标规划法。
目标规划法,首先是为每个目标函数设定一个期望值(目标值) g i g_i gi。
方案1: 然后构建一个新的目标函数 F ( x ) F(x) F(x),其形式如下:
minimize F ( x ) = ∑ [ w i ∗ ∣ f i ( x ) − g i ∣ ] \text{minimize} \quad F(x) = \sum [w_i * |f_i(x) - g_i|] minimizeF(x)=∑[wi∗∣fi(x)−gi∣]。
其中, w i w_i wi表示第 i i i个目标函数的权重。通过最小化 F ( x ) F(x) F(x),可以在满足各种约束的同时实现多目标的调和。这个距离也可以通过 L 2 L_2 L2 范数来表达。此方法有些类似加权和法。
方案2:我们还可以把目标设定进约束里(类似层次分析法),将优先级高的目标设置为约束条件,从而降低目标函数的个数。即在约束里面增加 f 1 ( x ) = g 1 f_1(x) = g_1 f1(x)=g1。
同样用之前的农场主问题:
假设一个农场主希望优化其土地上的作物种植布局,需要在以下两个目标之间取得平衡:
农场主有两种作物可以种植:作物A、作物B、作物C。设 x 1 x_1 x1、 x 2 x_2 x2、 x 3 x_3 x3分别为种植作物A、B、C的面积。
在不清楚设什么目标值时候,我们还可以通过求解各个单目标的最优解,观察值,然后设目标值。
如我们使用 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千克。接下来我们把这两个数值作为目标。
考虑到变量的取值域,这里我们直接采用(大数-小数)的方式来表示距离。
然后类似加权和法,我们引入两个权重参数 w 1 w_1 w1和 w 2 w_2 w2,分别表示农场产值和化肥使用量的重要程度,且满足 w 1 + w 2 = 1 w_1 + w_2 = 1 w1+w2=1,然后考虑两个目标的单位和数据量级不一样,我们引入参数 c c c来给目标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千克。
从上面可以看出,在本案例里面,目标改造与前面的加权和方法类似。
除了改造进目标,我们还可以改进约束里。观察上面的目标函数的最优值们:
这里我们将 F 1 ( x ) F_1(x) F1(x)的最优值作为约束,改造后如下:
# ==================设定目标转换后=======================
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千克。
从上面可以看到:
因此多目标转换时候,建议多尝试。可以考虑下述改进思路: