这里发生了很多事情。
- 描述
描述好像有问题。“最高卖出/价格取决于库存水平。 ”这似乎是错误的。从数据来看,价格看起来是恒定的,但买卖限制取决于库存水平。
- 时间
把握好时机很重要。通常,我们将buy和视为在tsell期间发生的事情(我们称它们为流变量)。是一个存量变量,在t期末测量。这么说和依赖有点奇怪(我们在时间上倒退了)。当然,我们可以对其建模并求解(我们求解为联立方程,所以我们可以做这些事情)。但是,这在现实世界中可能没有意义。或许我们应该看看以改变和。invsell[t]buy[t]inv[t]inv[t-1]buy[t]sell[t]
- 细分库存水平。
我们需要将库存水平分成多个部分。我们有以下部分:
0%-30%
30%-65%
65%-70%
70%-100%
我们将二进制变量与每个段相关联:
inventory in [0%-30%] <=> δ[1,t] = 1, all other zero
[30%-65%] δ[2,t] = 1
[65%-70%] δ[3,t] = 1
[70%-100%] δ[4,t] = 1
因为我们需要在所有时间段都这样做,所以我们添加了一个额外的索引 t。警告:我们将关联δ[k,t]t 期开始时的库存,即inv[t-1]。我们可以通过根据我们所在的细分更改下限和上限δ[k,t]来链接。inv[t-1]
- 买入/卖出界限
类似于库存的界限,我们有以下买卖上限:
segment buy sell
0%-30% 4 4
30%-65% 3 6
65%-70% 2 6
70%-100% 2 8
第一步是建立一个数学模型。这里发生了太多事情,我们可以立即编写代码。数学模型是我们的“设计”。所以我们开始:

有了这个,我们可以开发一些 R 代码。在这里,我们使用 CVXR 作为建模工具,使用 GLPK 作为 MIP 求解器。
> library(CVXR)
>
> # data
> price = c(12, 11, 12, 13, 16, 17, 18, 17, 18, 16, 17, 13)
> capacity = 25
> max_units_buy = 4
> max_units_sell = 8
>
> # capacity segments
> s <- c(0,0.3,0.65,0.7,1)
>
> # corresponding lower and upper bounds
> invlb <- s[1:(length(s)-1)] * capacity
> invlb
[1] 0.00 7.50 16.25 17.50
> invub <- s[2:length(s)] * capacity
> invub
[1] 7.50 16.25 17.50 25.00
>
> buyub <- c(4,3,2,2)
> sellub <- c(4,6,6,8)
>
> # number of time periods
> NT <- length(price)
> NT
[1] 12
>
> # number of capacity segments
> NS <- length(s)-1
> NS
[1] 4
>
> # Decision variables
> inv = Variable(NT,integer=T)
> buy = Variable(NT,integer=T)
> sell = Variable(NT,integer=T)
> delta = Variable(NS,NT,boolean=T)
>
> # Lag operator
> L = cbind(rbind(0,diag(NT-1)),0)
>
> # optimization model
> problem <- Problem(Maximize(sum(price*(sell-buy))),
+ list(inv == L %*% inv + buy - sell,
+ sum_entries(delta,axis=2)==1,
+ L %*% inv >= t(delta) %*% invlb,
+ L %*% inv <= t(delta) %*% invub,
+ buy <= t(delta) %*% buyub,
+ sell <= t(delta) %*% sellub,
+ inv >= 0, inv <= capacity,
+ buy >= 0, sell >= 0))
> result <- solve(problem,verbose=T)
GLPK Simplex Optimizer, v4.47
120 rows, 84 columns, 369 non-zeros
0: obj = 0.000000000e+000 infeas = 1.200e+001 (24)
* 23: obj = 0.000000000e+000 infeas = 0.000e+000 (24)
* 85: obj = -9.875986758e+001 infeas = 0.000e+000 (2)
OPTIMAL SOLUTION FOUND
GLPK Integer Optimizer, v4.47
120 rows, 84 columns, 369 non-zeros
84 integer variables, 48 of which are binary
Integer optimization begins...
+ 85: mip = not found yet >= -inf (1; 0)
+ 123: >>>>> -8.800000000e+001 >= -9.100000000e+001 3.4% (17; 0)
+ 126: >>>>> -9.000000000e+001 >= -9.100000000e+001 1.1% (9; 11)
+ 142: mip = -9.000000000e+001 >= tree is empty 0.0% (0; 35)
INTEGER OPTIMAL SOLUTION FOUND
> cat("status:",result$status)
status: optimal
> cat("objective:",result$value)
objective: 90
> print(result$getValue(buy))
[,1]
[1,] 3
[2,] 4
[3,] 4
[4,] 3
[5,] 3
[6,] 1
[7,] 0
[8,] 0
[9,] 0
[10,] 4
[11,] 0
[12,] 0
> print(result$getValue(sell))
[,1]
[1,] 0
[2,] 0
[3,] 0
[4,] 0
[5,] 0
[6,] 0
[7,] 8
[8,] 6
[9,] 4
[10,] 0
[11,] 4
[12,] 0
> print(result$getValue(inv))
[,1]
[1,] 3
[2,] 7
[3,] 11
[4,] 14
[5,] 17
[6,] 18
[7,] 10
[8,] 4
[9,] 0
[10,] 4
[11,] 0
[12,] 0
> print(result$getValue(delta))
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
[1,] 1 1 1 0 0 0 0 0 1 1 1 1
[2,] 0 0 0 1 1 0 0 1 0 0 0 0
[3,] 0 0 0 0 0 1 0 0 0 0 0 0
[4,] 0 0 0 0 0 0 1 0 0 0 0 0
>
所以,我想有人为此欠我一瓶好干邑。