Search code examples
rmathematical-optimizationlpsolve

Require integer optimization variables to take unique values


I used lp solve to solve a linear programming equation and the solution gives a vector

> lp("max", obj, con, ineqs, rhs, all.int=TRUE,)$solution
[1]  5  0 13 11  4  0  1 11  0

which is fine, but I want each entry in this vector to be an integer between 1-9 and each integer to only be used once. e.g like what the vector looks like underneath.

[1]  3  4 8 9  2  5  1 6  7

Is there any way this can be done? Thank you in advance!

EDIT

This is the code I have used for the lp function

 obj<-c(1,1,1,1,1,1,1,1,1)
con<-matrix(c(1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,0,0,1,1,0,1,1,0,0,0,0,0,0,1,1,0,1,1,0,0,0,0,0,1,1,0,1,1),nrow=5,byrow=TRUE)
ineqs<-c("=", "=", "=", "=", "=")
rhs<-c(45,20,17,27,15)

Basically what this does is it solves this optimisation problem for the 3x3 grid:

x1 x2 x3
x4 x5 x6
x7 x8 x9

Where the constraints are x1+x2+x4+x5=20, x2+x3+x5+x6=17, x4+x5+x7+x8=27, x5+x6+x8+x9=15, each x must be an integer between 1 and 9 and each x must be unique.


Solution

  • The problem with your formulation is that all you're doing is constraining the sum of the values to be 45; there are many sets of 9 integers that sum to 45 but don't take values 1 through 9.

    Instead of formulating this with 9 integer-valued variables, you'll probably find it easier to formulate this with 81 binary-valued variables x_ij, where each variable indicates if x_i (in the original formulation) takes value j.

    # Helper functions to index variables
    unit <- function(idx) as.numeric((1:9) == idx)
    ivals <- function(i) { ret <- rep(0, 81) ; ret[(9*i-8):(9*i)] <- 1:9 ; ret }
    ivars <- function(i) rep(unit(i), each=9)
    jvars <- function(j) rep(unit(j), 9)
    
    # Setup and solve optimization model
    obj <- rep(0, 81)
    const <- rbind(do.call(rbind, lapply(1:9, jvars)),  # Each value once
                   do.call(rbind, lapply(1:9, ivars)),  # Each var once
                   ivals(1) + ivals(2) + ivals(4) + ivals(5),
                   ivals(2) + ivals(3) + ivals(5) + ivals(6),
                   ivals(4) + ivals(5) + ivals(7) + ivals(8),
                   ivals(5) + ivals(6) + ivals(8) + ivals(9))
    ineqs <- rep("=", 22)
    rhs <- c(rep(1, 18), 20, 17, 27, 15)
    library(lpSolve)
    res <- lp("max", obj, const, ineqs, rhs, all.bin=TRUE)
    apply(matrix(res$solution, nrow=9), 2, which.max)
    # [1] 3 7 5 6 4 1 9 8 2