文章摘要:线性规划的Python实现。
参考书籍:数学建模算法与应用(第3版)司守奎 孙玺菁。
PS:只涉及了具体实现并不涉及底层理论。学习底层理论以及底层理论实现:可以参考1.最优化模型与算法——基于Python实现 渐令 粱锡军2.算法导论(原书第3版)Thomas H.Cormen Charles E.Leiserson、Ronald L.Rivest Clifford Stein
文章声明:如有发现错误,还望批评指正。
文章目录
- 线性规划简述
- 线性规划实现
- 模型一:固定风险,最大收益
- 模型二:固定收益,最小风险
- 模型三:目标函数加权求和
线性规划简述
目标函数:
max
o
r
min
y
=
∑
i
=
1
n
a
i
x
i
\max\;or\;\min\; y=\sum\limits_{i=1}^{n}a_ix_i
maxorminy=i=1∑naixi
约束条件:
∑
j
=
1
n
a
i
j
x
j
≤
o
r
=
o
r
≥
b
i
,
i
=
1
,
2
,
…
,
m
\sum\limits_{j=1}^{n}a_{ij}x_{j}\leq or = or \geq b_i,i=1,2,\dots,m
j=1∑naijxj≤or=or≥bi,i=1,2,…,m
x
j
≥
0
,
j
=
1
,
2
,
…
,
n
x_j\geq0,j=1,2,\dots,n
xj≥0,j=1,2,…,n
一些名词: 可行解,可行域与最优解。
PS:至于如何找到最优解的还请参考最前面的PS,没有兴趣可以不用进行研究。希望以后上了最优化的课程或者有时间了能够手搓。感觉工程量有点大,哈哈也许没有必要。所以博主没有学习过最优化相关理论,对于求解器的方法同样也不知道。但是从工程的角度,我们可以不用知道,那是理论学家需要去做的事。看需要,看兴趣。
线性规划实现
参考书籍例1.9
目标函数:
max
∑
i
=
0
n
(
r
i
−
p
i
)
x
i
\max\sum\limits_{i=0}^n(r_i-p_i)x_i
maxi=0∑n(ri−pi)xi
min
{
max
1
≤
i
≤
n
{
q
i
x
i
}
}
\min\{\max\limits_{1\leq i\leq n}\{ q_ix_i\} \}
min{1≤i≤nmax{qixi}}
约束条件:
∑
i
=
0
n
(
1
+
p
i
)
x
i
=
M
\sum\limits_{i=0}^{n}(1+p_i)x_i=M
i=0∑n(1+pi)xi=M
x
i
≥
0
,
i
=
0
,
1
,
2
,
…
,
n
x_i\geq0,i=0,1,2,\dots,n
xi≥0,i=0,1,2,…,n
模型一:固定风险,最大收益
目标函数:
max
∑
i
=
0
n
(
r
i
−
p
i
)
x
i
\max\sum\limits_{i=0}^n(r_i-p_i)x_i
maxi=0∑n(ri−pi)xi
约束条件:
q
i
x
i
M
≤
a
,
i
=
0
,
1
,
2
,
…
,
n
\frac{q_ix_i}{M}\leq a,i=0,1,2,\dots,n
Mqixi≤a,i=0,1,2,…,n
∑
i
=
0
n
(
1
+
p
i
)
x
i
=
M
\sum\limits_{i=0}^{n}(1+p_i)x_i=M
i=0∑n(1+pi)xi=M
x
i
≥
0
,
i
=
0
,
1
,
2
,
…
,
n
x_i\geq0,i=0,1,2,\dots,n
xi≥0,i=0,1,2,…,n
from scipy.optimize import linprog
import numpy as np
M=10000
lt1=np.array([0.05,0.28,0.21,0.23,0.25])
lt2=np.array([0,0.01,0.02,0.045,0.065])
c=lt1-lt2;c=-c
A_ub1=np.diag([0,0.025,0.015,0.055,0.026]);A_ub2=np.diag([-1,-1,-1,-1,-1]);A_ub=np.vstack((A_ub1,A_ub2))
A_eq=1+lt2;A_eq=A_eq.reshape(1,-1)
b_eq=np.array([M])
lt=[]
for i in range(0,50):
b_ub=np.array([i/1000*M for _ in range(5)]+[0 for _ in range(5)])
result=linprog(c,A_ub,b_ub,A_eq,b_eq)
lt.append(-result.fun)
import matplotlib.pyplot as plt
import seaborn as sns
plt.figure(figsize=(16,9));sns.set_style("darkgrid");plt.rcParams['font.sans-serif']=['SimHei']
plt.plot([i for i in range(len(lt))],lt,ms=10,marker="o",linestyle="--",linewidth=5,color="green")
plt.xlabel("a");plt.ylabel("收益");plt.show()
以下两个模型需要目标函数进行线性转换。但是这样会造成不等式约束右侧包含变量,scipy库无法解决所以使用cvxpy库(至少我没找功能函数)。
模型二:固定收益,最小风险
目标函数:
min
{
max
1
≤
i
≤
n
{
q
i
x
i
}
}
\min\{\max\limits_{1\leq i\leq n}\{ q_ix_i\} \}
min{1≤i≤nmax{qixi}}
约束条件:
∑
i
=
0
n
(
r
i
−
p
i
)
x
i
≥
k
M
\sum\limits_{i=0}^n(r_i-p_i)x_i\geq kM
i=0∑n(ri−pi)xi≥kM
∑
i
=
0
n
(
1
+
p
i
)
x
i
=
M
\sum\limits_{i=0}^{n}(1+p_i)x_i=M
i=0∑n(1+pi)xi=M
x
i
≥
0
,
i
=
0
,
1
,
2
…
,
n
x_i\geq0,i=0,1,2\dots,n
xi≥0,i=0,1,2…,n
import numpy as np
import cvxpy as cp
M=10000
x=cp.Variable(6,pos=True)
obj=cp.Minimize(x[5])
p=np.array([0,0.01,0.02,0.045,0.065])
con1=(1+p)@x[:-1]==M
q=np.array([0,0.025,0.015,0.055,0.026])
con2=cp.multiply(q,x[:5])<=x[5]
r=np.array([0.05,0.28,0.21,0.23,0.25])
lt=[]
for i in range(100):
con3=(r-p)@x[:-1]>=i/100*M
con=[con1,con2,con3]
pro=cp.Problem(obj,con)
pro.solve(solver='ECOS')
lt.append(x.value[5])
import matplotlib.pyplot as plt
import seaborn as sns
plt.figure(figsize=(16,9));sns.set_style("darkgrid");plt.rcParams['font.sans-serif']=['SimHei']
plt.plot([i for i in range(len(lt))],lt,ms=10,marker="o",linewidth=5,color="green")
plt.xlabel("k");plt.ylabel("风险");plt.savefig("figure")
分析:收益到0.26之后便就没有解了。
注释:(默认问题为凸问题,具体是不是我证明不了)ECOS是一个求解凸优化的方法(具体理论我不知道),具有数值稳定,求解效率等等优点,
模型三:目标函数加权求和
目标函数:
min
{
ω
{
max
1
≤
i
≤
n
{
q
i
x
i
}
}
−
(
1
−
ω
)
∑
i
=
0
n
(
r
i
−
p
i
)
x
i
\min \{\omega\{\max\limits_{1\leq i\leq n}\{ q_ix_i\} \}-(1-\omega) \sum\limits_{i=0}^n(r_i-p_i)x_i
min{ω{1≤i≤nmax{qixi}}−(1−ω)i=0∑n(ri−pi)xi}
约束条件:
∑
i
=
0
n
(
1
+
p
i
)
x
i
=
M
\sum\limits_{i=0}^{n}(1+p_i)x_i=M
i=0∑n(1+pi)xi=M
x
i
≥
0
,
i
=
0
,
1
,
2
,
…
,
n
x_i\geq0,i=0,1,2,\dots,n
xi≥0,i=0,1,2,…,n
import numpy as np
import cvxpy as cp
M=10000
x=cp.Variable(6,pos=True)
p=np.array([0,0.01,0.02,0.045,0.065])
con1=(1+p)@x[:-1]==M
q=np.array([0,0.025,0.015,0.055,0.026])
con2=cp.multiply(q,x[:5])<=x[5]
con=[con1,con2]
r=np.array([0.05,0.28,0.21,0.23,0.25])
lt1=[];lt2=[]
for i in range(100):
obj=cp.Minimize(i*x[5]-(1-i/100)*((r-p)@x[:-1]))
pro=cp.Problem(obj,con);pro.solve(solver='ECOS')
lt1.append((r-p)@x.value[:-1]);lt2.append(x[5].value)
import matplotlib.pyplot as plt
import seaborn as sns
plt.figure(figsize=(16,9));sns.set_style("darkgrid");plt.rcParams['font.sans-serif']=['SimHei']
plt.plot([i for i in range(len(lt1))],lt1,ms=10,marker="o",linewidth=5,color="green")
plt.xlabel("w");plt.ylabel("收益");plt.savefig("figure1")
plt.figure(figsize=(16,9));sns.set_style("darkgrid");plt.rcParams['font.sans-serif']=['SimHei']
plt.plot([i for i in range(len(lt2))],lt2,ms=10,marker="o",linewidth=5,color="green")
plt.xlabel("w");plt.ylabel("风险");plt.savefig("figure2")