2

given a price and calorie matrix, I am trying to solve for the maximum amount of calories possible to buy with $15. I've read the docs for lpSolve + some older answers on here, but I am still having trouble setting up my equation. I also want to solve the diet problem assuming that I need to buy at least x items or by constraining the quantity purchased of each (say, only being able to buy one or two of each item). Here is my attempt so far:

library(tidyverse)
library(lpSolve)

# calorie data
cals <- as.matrix(c(
  830, 110, 600, 710, 210, 70, 200, 380, 460, 634
))

price <- as.matrix(c(
  7.89, 9.96, 11.31, 7.87, 7.04, 7.18, 4.43, 9.10, 6.72,
  6.20
))

# max. calories...
objective.in <- cals

# given price constraints...
const.mat <- price

# w/ a price cap of $15
const_price <- 15

opt <- lp(
  # find max
  direction = 'max',
  objective.in,
  const.mat,
  # can't go over price cap
  '<=',
  const_price
)
codeweird
  • 145
  • 3
  • 11

1 Answers1

0

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"   
Robert Hacken
  • 3,878
  • 1
  • 13
  • 15