Lingo学习笔记——平均分配问题(MINLP混合整数非线性规划)

Lingo学习笔记

1、情景引入

班级采购了一批零食作为举行班级活动时的零嘴,采购列表如下:

商品编号份数单价
商品1391.79
商品2301.3
商品3500.95
商品4720.94
商品5600.84
商品6350.71
商品7780.69
商品8300.45
商品9300.45
商品10400.078

班级总人数为32,要公平地将零食分给每个人。

2、情景分析

要想实现公平,就必须做到以下几点:

  1. 每个人所分得的商品总价的方差尽量的小;
  2. 商品总价值尽量的大;
  3. 商品总数小于等于32的,分配时每个人所得该商品的个数不得大于1;
  4. 商品总数在33~64之间的,分配时每个人所得该商品的个数不得大于2个;
  5. 商品总数大于64的,分配时每个人所得该商品的个数不得大于3个;
  6. 商品总数大于等于32的,分配时每个人所得该商品的个数不得少于1个;
  7. 分得的商品个数均为整数。
3、模型建立

设商品编号为 i = 1,2,……,m(m=10),学生编号为 j = 1,2,……,n(n=32)。

x i j x_{ij} xij j j j 学生分得 i i i 商品的数量;

p j p_j pj j j j 学生分得商品的总价;

P i P_i Pi i i i 商品的单价;

N i N_i Ni i i i 商品的总份数;

a v g p avgp avgp: { p j p_j pj } 平均值;

s p sp sp: { p j p_j pj } 方差。

目标函数:

m i n s p = 1 n ∗ ∑ j = 1 n ( p j − a v g p ) 2 min\quad sp = \frac{1}{n} * ∑_{j=1}^{n}(p_j - avgp )^2 minsp=n1j=1n(pjavgp)2
约束条件:

s . t { p j = ∑ i = 1 n x i j ∗ P i a v g p = 1 n ∗ ∑ j = 1 n p j ∑ j = 1 n x i j ≤ N i , i = 1 , 2 , . . . , m x i j ≥ 0 s.t\begin{cases} p_j=\sum_{i=1}^{n}x_{ij}*P_i \\\\ avgp = \frac{1}{n} * \sum_{j=1}^{n} p_j \\ \\ \sum_{j=1}^{n} x_{ij} \leq N_i \quad , \quad i=1,2,...,m \\ \\ x_{ij} \geq 0 \end{cases} s.tpj=i=1nxijPiavgp=n1j=1npjj=1nxijNi,i=1,2,...,mxij0

但是在实际运行过程中,发现运行时长过长,久久不能出结果,于是换了目标函数,转而求
m a x z = ∑ j = 1 n p j \quad max\quad z=\sum_{j=1}^{n}p_j maxz=j=1npj
然后对方差进行约束,根据一次次的运行结果依次取了0.4、0.3、0.2、0.15、0.13,当方差约束为小于0.13时,又出现了久久不能出结果的情况,于是最终只取到了小于0.15,结果得到方差为0.134。

4、代码实现
model:
!平均分配;
sets:
	goods/1..10/:num,price;
	stu/1..32/:;
	link(goods,stu):x;
endsets
data:
	num = 39,30,50,72,60,35,78,30,30,40;
	price = 1.79,1.30,0.95,0.94,0.84,0.71,0.69,0.45,0.45,0.078;
enddata

max = @sum(link(i,j):price(i)*x(i,j));

totalprice = @sum(goods(i):price(i)*num(i));
totalnum = @sum(link:x);
avgprice = 1/32*@sum(link(i,j):price(i)*x(i,j));

!方差约束;
variance = @sum(stu(j):(@sum(goods(i):x(i,j)*price(i))-avgprice)^2)/32;
variance < 0.15;

!每种商品分配的总和不得大于该商品的总数量;
@for(goods(i):@sum(stu(j):x(i,j))<=num(i));
!每个学生分得的商品总数不得少于13,即以平均数14.5为参考;
@for(stu(j):@sum(goods(i):x(i,j))>=13);
!商品总数大于32的商品分配时分给每个学生的商品数量不得小于1;
@for(link(i,j):x(i,j) >= @if(num(i)#ge#32,1,0));
!商品总数小于32的商品分配时分给每个学生的商品数量不得大于1,总数大于64的不得大于3,总数在32-64之间的不得大于2;
@for(link(i,j):x(i,j) <= @if(num(i)#le#32,1,@if(num(i)#ge#64,3,2)));
!分得每种商品的数量不得超过三个;
@for(link(i,j):x(i,j)<=3);
!分得的商品数量只能是整数;
@for(link:@gin(x));

end
5、运行结果

运行结果截图

Local optimal solution found.
Objective value: 383.1800
Objective bound: 383.1800
Infeasibilities: 0.000000
Extended solver steps: 11928
Total solver iterations: 3013236

Model Class: MINLP

Total variables: 323
Nonlinear variables: 321
Integer variables: 320

Total constraints: 1007
Nonlinear constraints: 1

Total nonzeros: 2885
Nonlinear nonzeros: 321

Model Title: Distribution
Variable Value
TOTALPRICE 383.1800
TOTALNUM 464.0000
AVGPRICE 11.97438
VARIANCE 0.1342741

……(太长了)

6、总结

在建模过程中,由于对于Lingo语法的不熟悉,导致花费的时间很长,在此记录一下本次学到的Lingo基本知识。

(1)基本框架

model:(这是一个模型)

​ sets:

​ ……(建立集合)

​ 集合名称/start…end/:属性1,属性2;

​ endsets

​ data:

​ ……(上面的属性赋值)

​ enddata

​ initial:

​ ……(据说是给结果进行一个初始化,缩短运行时间,我没有用这个)

​ endinitial

​ min = ……(或max)

​ ……(约束条件)

end

非常简单的线性规划可以直接写目标函数和约束条件,不用分模块写,可以直接运行。

(2)几个函数
① @sum(集合名(下标):包含其属性的表达式)

将其整体看作是一个数,最终的结果是数!

冒号前面的部分是作为循环变量的,不能为未知数,比如:

!在上例中新增集合的属性,但不在data块中赋值;
stu/1..32/:stuprice;
!不能作为循环变量;
@for(stu(j):stuprice(j)=@sum(goods(i):x(i,j)*price(i)));
!原报错语句不记得是不是这样写了,当时希望实现这个功能的时候确实是报错了的;
!报错explain的翻译说是循环变量不能为未知数(原话不记得了);
② @for(集合名(下标):包含其属性的表达式)

和@sum类似,冒号前面是循环变量,好像也不能为未知数。

③ @for和@sum的嵌套

for可以在里面套for;

for可以在里面套sum;

sum不可以在里面套for。

牢记@sum整体是一个数!

④ @if(判断,为真时的值,为假时的值)

牢记:整体是一个数!是数!!

为真和为假的值缺一不可,都得写。

判断里面的逻辑符号得用 #ge# 之类的形式,不能直接 >= 。

⑤ @gin(x)

意思是限制为整数,和 x ∈ Z 一个意思,不过,Lingo默认x非负,实际上和 x ∈ N 一个意思。

@gin(集合名:属性名),不用写下标,写了会报错。

⑥ @floor(x)

左取整。本来想用,没用上。

(3)其他注意事项
  • 左右括号配对要非常仔细!!!一不留神就会报错TAT
  • 每行末尾都要有分号,endxxx除外。
  • Ctrl+U→运行的快捷键,solve成功会有LocalOpt,不成功的话,有可能告诉你infeasible,有可能运行到海枯石烂……
  • Ctrl+D→调试的快捷键,只有模型是infeasible时才可以Debug。
  • solve不成功还有一种情况是报错 ill ,模型有问题,可能是逻辑有问题。
  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是一个利用Lingo和MATLAB求解非线性规划问题模型的案例: 假设有一个工厂需要生产两种产品A和B,生产A和B需要不同的原材料和工人数量,且有一些限制条件。假设每天工厂有8个小时的生产时间,每个工人每天最多工作6个小时,原材料的供应量也有限制。现在需要确定每天生产A和B的数量,以最大化收益。 根据以上问题,可以得到如下的非线性规划模型: 最大化收益:f(x) = 20x1 + 30x2 约束条件: - 原材料限制:2x1 + 3x2 <= 120 - 工人数量限制:4x1 + 3x2 <= 96 - 生产时间限制:x1 + x2 <= 8 - 非负限制:x1 >= 0, x2 >= 0 其中,x1表示生产A的数量,x2表示生产B的数量。 接下来,我们可以使用Lingo和MATLAB求解以上非线性规划模型。 首先,我们使用Lingo语言编写以上模型,得到以下的Lingo模型: ``` max = 20x1 + 30x2 c1: 2x1 + 3x2 <= 120 c2: 4x1 + 3x2 <= 96 c3: x1 + x2 <= 8 x1 >= 0 x2 >= 0 ``` 然后,我们可以在MATLAB中编写调用程序,调用LINGO软件求解以上模型。代码如下: ``` % Lingo and MATLAB nonlinear programming example % Define the Lingo model lingo_model = [ 'max = 20x1 + 30x2' 'c1: 2x1 + 3x2 <= 120' 'c2: 4x1 + 3x2 <= 96' 'c3: x1 + x2 <= 8' 'x1 >= 0' 'x2 >= 0' ]; % Write the Lingo model to a file lingo_file = 'nonlinear.lp'; fid = fopen(lingo_file, 'w'); fprintf(fid, '%s', lingo_model); fclose(fid); % Call Lingo to solve the nonlinear programming problem [status, result] = system(['lingo -s "', lingo_file, '"']); % Parse the Lingo solution if status == 0 pattern = '20X1 = %f, 30X2 = %f'; [tokens, matches] = regexp(result, pattern, 'tokens', 'match'); x1 = tokens{1}(1); x2 = tokens{1}(2); fprintf('Optimal solution: x1 = %f, x2 = %f\n', x1, x2); else fprintf('Error: Lingo solver failed\n'); end ``` 运行以上MATLAB程序,即可得到最优解为x1=24,x2=16,最优值为960。 以上就是一个利用Lingo和MATLAB求解非线性规划问题模型的案例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

键盘里的咬肌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值