如何在R中求解线性编程模型

问题描述 投票:1回答:1

我需要解决以下微观经济问题。

  • 我有六项资产可以在五年内(2011-2015年)生产(资产1-6)。
  • 每项资产只能在一年内生产。
  • 每项资产必须在我的五年期间生产。
  • 生产并不是相互排斥的,我可以在一年内生产一种以上的商品,而不影响任何一种商品的生产。
  • 每种资产的固定生产成本等于30。
  • 我每年的利润必须为非负数;收入必须至少为30。

下面是一个矩阵,表示我在某一年(j)生产每种资产(i)的潜在收入。

          2011 2012 2013 2014 2015
  Asset1    35* 37  39  42  45
  Asset2    16  17  18  19  20*
  Asset3    125 130 136*139 144
  Asset4    15  27  29  30* 33
  Asset5    14  43* 46  50  52
  Asset6    5   7   8   10  11*

星号(*)代表的应该是最优解集。

我如何使用R来求解生产计划,使我的收入(因而利润)最大化,但要受到所列出的约束条件的限制。 我的输出应该是一个类似于6x5的矩阵,其内容是 0的和 1的,其中 1'的代表选择在某一年生产一种商品。

r matrix linear-programming
1个回答
4
投票

这是一个典型的问题,也是一个需要重新表述的问题。

首先重新表述你的问题

Max( sum_[i,t] (pi_[i,t] - C_[i,t]) * x_[i,t]) 
Sd. 
sum_t x_[i,t] = 1 [ for all i ]
sum_i x_[i,t] >= 30 [ for all t ]
x_[i,t] >= 0 [for all i, t]

lpSolve 包中的最大化问题是以线性表示方式给出的,例如,非矩阵格式。让我们先做一个向量来表示我们的 x_[i,t]. 为了方便起见,我们给它起个名字吧(虽然没有用到),这样我们就可以跟踪了。

n <- 6
t <- 5
#x ordered by column. 
x <- c(35, 16, 125, 15, 14, 5, 37, 17, 130, 27, 43, 7, 39, 18, 136, 29, 46, 8, 42, 19, 139, 30, 50, 10, 45, 20, 144, 33, 52, 11)
# if x is matrix use:
# x <- as.vector(x)
names(x) <- paste0('x_[', seq(n), ',', rep(seq(t), each = n), ']')
head(x, n * 2)
x_[1,1] x_[2,1] x_[3,1] x_[4,1] x_[5,1] x_[6,1] x_[1,2] x_[2,2] x_[3,2] x_[4,2] x_[5,2] x_[6,2] 
     35      16     125      15      14       5      37      17     130      27      43       7
length(x)
[1] 30

现在,我们需要创建我们的条件。从第一个条件开始

sum_t x_[i,t] = 1 [ for all i ]

我们可以很简单地创建这个。这里要注意的是,维度必须正确。我们有一个长度为30的向量,所以我们需要条件矩阵有30列。此外,我们有6个资产,所以我们需要6行来满足这个条件。再一次让我们给行和列命名,以便于我们自己跟踪。

cond1 <- matrix(0, ncol = t * n, 
                nrow = n, 
                dimnames = list(paste0('x_[', seq(n), ',t]'),
                                names(x)))
cond1[, seq(n + 1)]
        x_[1,1] x_[2,1] x_[3,1] x_[4,1] x_[5,1] x_[6,1] x_[1,2]
x_[1,t]       0       0       0       0       0       0       0
x_[2,t]       0       0       0       0       0       0       0
x_[3,t]       0       0       0       0       0       0       0
x_[4,t]       0       0       0       0       0       0       0
x_[5,t]       0       0       0       0       0       0       0
x_[6,t]       0       0       0       0       0       0       0

接下来我们填写正确的字段。x_[1,1] + x[1, 2] + ... = 1x_[2,1] + x_[2,2] + ... = 1 以此类推。对于这个问题,使用for循环是最简单的。

for(i in seq(n)){
  cond1[i, seq(i, 30, n)] <- 1
}
cond1[, seq(n + 1)]
        x_[1,1] x_[2,1] x_[3,1] x_[4,1] x_[5,1] x_[6,1] x_[1,2]
x_[1,t]       1       0       0       0       0       0       1
x_[2,t]       0       1       0       0       0       0       0
x_[3,t]       0       0       1       0       0       0       0
x_[4,t]       0       0       0       1       0       0       0
x_[5,t]       0       0       0       0       1       0       0
x_[6,t]       0       0       0       0       0       1       0

我们仍然需要创建RHS和指定方向,但我现在先不说这个。所以接下来让我们为第二个条件创建矩阵。

sum_i x_[i,t] >= 30 [ for all t ]

这个过程非常相似,但现在我们需要为每个时期插入一行,所以矩阵的维度是5x30。这里的主要区别是,我们需要插入的值是 x_[i, t]

cond2 <- matrix(0, ncol = t * n, 
                nrow = t, 
                dimnames = list(paste0('t=', seq(t)),
                                names(x)))
for(i in seq(t)){
   cond2[i, seq(n) + n * (i - 1)] <- x[seq(n) + n * (i - 1)]
}
cond2[, seq(1, n * t, n)]
    x_[1,1] x_[1,2] x_[1,3] x_[1,4] x_[1,5]
t=1      35       0       0       0       0
t=2       0      37       0       0       0
t=3       0       0      39       0       0
t=4       0       0       0      42       0
t=5       0       0       0       0      45

请注意,我打印的结果是 x_[1, t] 来说明我们的做法是正确的。最后我们有最后一个条件。为此,我们注意到 ?lpSolve::lp 有争议 all.bin读到这里,它说

逻辑:所有变量都应该是二进制的吗?默认值。FALSE.

因此,由于所有变量都是1或0,我们只需将这个值设置为 TRUE. 在继续之前,让我们把条件合并成一个矩阵

cond <- rbind(cond1, cond2)

现在RHS和方向都是简单的取自2个条件。从文件上看 const.dir 争论

字符串的向量,给出约束的方向:每个值应该是"<"、"<="、"="、"> "或">="中的一个。在每一对中,两个值都是相同的)。

在我们的条件中,我们有6行代表第一个条件,还有几行代表条件2。因此我们需要 n (6)次 ==t (5)次 >=.

cond_dir <- c(rep('==', n), rep('>=', t))

RHS是以类似的方式创建的

RHS <- c(rep(1, n), rep(30, t))

这就是了! 现在我们准备使用 lpSolve::lp 函数。

sol = lpSolve::lp(direction = 'max',
                  objective.in = x, 
                  const.mat = cond,
                  const.dir = cond_dir,
                  const.rhs = RHS,
                  all.bin = TRUE)                
sol$objval
[1] 275

解决方案的权重存储在 sol$solution

names(sol$solution) <- names(x)
sol$solution
x_[1,1] x_[2,1] x_[3,1] x_[4,1] x_[5,1] x_[6,1] x_[1,2] x_[2,2] x_[3,2] x_[4,2] x_[5,2] x_[6,2] x_[1,3] x_[2,3] x_[3,3] 
      1       0       0       0       0       0       0       0       0       0       1       0       0       0       1 
x_[4,3] x_[5,3] x_[6,3] x_[1,4] x_[2,4] x_[3,4] x_[4,4] x_[5,4] x_[6,4] x_[1,5] x_[2,5] x_[3,5] x_[4,5] x_[5,5] x_[6,5] 
      0       0       0       0       0       0       1       0       0       0       1       0       0       0       1
matrix(sol$solution, 
       ncol = t,
       dimnames = list(rownames(cond1), 
                       rownames(cond2)))
        t=1 t=2 t=3 t=4 t=5
x_[1,t]   1   0   0   0   0
x_[2,t]   0   0   0   0   1
x_[3,t]   0   0   1   0   0
x_[4,t]   0   0   0   1   0
x_[5,t]   0   1   0   0   0
x_[6,t]   0   0   0   0   1

我们很快就发现这是正确的解决方案。 :-)

关于成本的侧面说明

大家可能注意到了 "成本到底去哪儿了?"。在这个具体的案例中,成本是固定的,不是很有意思。这意味着我们在计算过程中可以忽略这些,因为我们知道总成本将是 30 * 6 = 180 (必须从目标值中减去)。然而,成本取决于各种因素,可能会影响最优解,这并不罕见。为了说明这一点,我将在这里包括我们如何在这个例子中加入成本。首先,我们必须扩展我们的目标向量,以纳入每个产品在每个时期的成本。

Fixed_C <- -30
x <- c(x, rep(Fixed_C, n * t))

接下来我们将添加一个 伪约束

x_[i,t] - C_[i,t] = 0 [for all i, t]

这个约束条件确保如果 x_[i,t] = 1 那么相关的成本就会加到问题中。有2种方法来创建这个约束。第一种是有一个矩阵,里面有 n * t 行,每个成本和周期都有一行。另外,我们也可以使用第一个约束条件,实际上只需要一个单一的约束条件即可。

sum_[i,t] x_[i,t] - C_[i,t] = 0

因为我们的第一个约束条件是确保 x[1, 1] != x[1, 2]. 所以我们的第三个约束条件是

cond3 <- c(rep(1, n * t), rep(-1, n * t))

最后我们要扩展我们的RHS和条件1、2矩阵。只需在条件矩阵中添加0,使尺寸合适即可。

cond1 <- cbind(cond1, matrix(0, nrow = n, ncol = n * t))
cond2 <- cbind(cond2, matrix(0, nrow = n, ncol = n * t))
cond <- rbind(cond1, cond2, cond3)
cond_dir <- c(cond_dir, '==')
RHS <- c(RHS, 0)

现在我们可以再一次用以下方法找到最优解 lpSolve::lp

solC = lpSolve::lp(direction = 'max',
                  objective.in = x, 
                  const.mat = cond,
                  const.dir = cond_dir,
                  const.rhs = RHS,
                  all.bin = TRUE)
solC$objval
[1] 95

相当于我们之前的数值 275 减去我们的固定成本 Fixed_C * n = 180.

© www.soinside.com 2019 - 2024. All rights reserved.