Your attempt does not work mainly because const.mat
should be a matrix with one column per variable but your const.mat
is a column matrix with 10 rows. Also, objective.in
is supposed to be a vector, not a matrix (but this probably does not cause any trouble). So if you use const.mat <- t(price)
, you will get your solution which will be rather trivial, maximizing the quantity (about 1.9) of the first item – the one with the best calories/price ratio.
As for other constraints, here's how you can do it. I increased the financial limit to $60 for higher flexibility and gradually build the matrix of constraint coefficients (f.con
), vector of constraint directions (f.dir
) and vector of right-hand sides (f.rhs
) to incorporate the individual constraints. In the comments, the vector of optimal coefficients is X = [x1, x2, ..., x10].
cals <- c(830, 110, 600, 710, 210, 70, 200, 380, 460, 634)
price <- c(7.89, 9.96, 11.31, 7.87, 7.04, 7.18, 4.43, 9.10, 6.72, 6.20)
n <- length(cals)
# total price cap of $60
# sum(X * price) <= 60
f.con <- matrix(price, nrow=1)
f.dir <- c('<=')
f.rhs <- 60
# buy no more than 3 of each item
# x1 <= 3, x2 <= 3, ..., x10 <= 3
f.con <- rbind(f.con, diag(n))
f.dir <- c(f.dir, rep('<=', n))
f.rhs <- c(f.rhs, rep(3, n))
# buy minimum of 10 items in total
# sum(X) >= 10
f.con <- rbind(f.con, rep(1, n))
f.dir <- c(f.dir, '>=')
f.rhs <- c(f.rhs, 10)
The solution can be restricted so that all variables are integer (or not):
# all.int=T: only integer numbers
opt <- lp(cals, const.mat=f.con, const.dir=f.dir, const.rhs=f.rhs,
direction='max', all.int=T)
opt$solution
# [1] 1 0 0 0 0 0 3 0 3 3
# all.int=F: non-integer numbers possible
opt <- lp(cals, f.con, f.dir, f.rhs, direction='max', all.int=F)
opt$solution
# [1] 1.051282 0.000000 0.000000 0.000000 0.000000 0.000000 3.000000 0.000000
# [9] 2.948718 3.000000
The final set of constraints is as follows:
paste(apply(f.con, 1, function(x) paste0(x, paste0('*x', seq_len(n)), collapse=' + ')),
f.dir,
f.rhs)
# [1] "7.89*x1 + 9.96*x2 + 11.31*x3 + 7.87*x4 + 7.04*x5 + 7.18*x6 + 4.43*x7 + 9.1*x8 + 6.72*x9 + 6.2*x10 <= 60"
# [2] "1*x1 + 0*x2 + 0*x3 + 0*x4 + 0*x5 + 0*x6 + 0*x7 + 0*x8 + 0*x9 + 0*x10 <= 3"
# [3] "0*x1 + 1*x2 + 0*x3 + 0*x4 + 0*x5 + 0*x6 + 0*x7 + 0*x8 + 0*x9 + 0*x10 <= 3"
# [4] "0*x1 + 0*x2 + 1*x3 + 0*x4 + 0*x5 + 0*x6 + 0*x7 + 0*x8 + 0*x9 + 0*x10 <= 3"
# [5] "0*x1 + 0*x2 + 0*x3 + 1*x4 + 0*x5 + 0*x6 + 0*x7 + 0*x8 + 0*x9 + 0*x10 <= 3"
# [6] "0*x1 + 0*x2 + 0*x3 + 0*x4 + 1*x5 + 0*x6 + 0*x7 + 0*x8 + 0*x9 + 0*x10 <= 3"
# [7] "0*x1 + 0*x2 + 0*x3 + 0*x4 + 0*x5 + 1*x6 + 0*x7 + 0*x8 + 0*x9 + 0*x10 <= 3"
# [8] "0*x1 + 0*x2 + 0*x3 + 0*x4 + 0*x5 + 0*x6 + 1*x7 + 0*x8 + 0*x9 + 0*x10 <= 3"
# [9] "0*x1 + 0*x2 + 0*x3 + 0*x4 + 0*x5 + 0*x6 + 0*x7 + 1*x8 + 0*x9 + 0*x10 <= 3"
# [10] "0*x1 + 0*x2 + 0*x3 + 0*x4 + 0*x5 + 0*x6 + 0*x7 + 0*x8 + 1*x9 + 0*x10 <= 3"
# [11] "0*x1 + 0*x2 + 0*x3 + 0*x4 + 0*x5 + 0*x6 + 0*x7 + 0*x8 + 0*x9 + 1*x10 <= 3"
# [12] "1*x1 + 1*x2 + 1*x3 + 1*x4 + 1*x5 + 1*x6 + 1*x7 + 1*x8 + 1*x9 + 1*x10 >= 10"