Linear programming in R using lpsolve - r

I'm trying to solve a linear programming problem in R using lpsolve package.
Here is the problem:
Here is the sample in R for reproducible example:
library("lpSolve")
a <- matrix(c(1,2,5,
1/2,1,3,
1/5,1/3,1),nrow=3,byrow=T)
#
f.obj <- c(1,0,0,0)
f.con <- matrix (c(
1,1,-a[1,2],0, #Contraint 1 for a12
1,-1,a[1,2],0, #Contraint 2 for a12
1,1,0,-a[1,3], #Contraint 1 for a13
1,-1,0,a[1,3], #Contraint 2 for a13
1,0,1,-a[2,3], #Contraint 1 for a23
1,0,-1,a[2,3], #Contraint 2 for a23
0,1,1,1, #Contraint 3
0,1,0,0, #Constraint 4
0,0,1,0, #Constraint 4
0,0,0,1 #Constraint 4
), nrow=10, byrow=TRUE)
f.dir <- c(rep("<=",6), "=",rep(">",3))
f.rhs <- c(rep(1,6),1,rep(0,3))
g <- lp ("max", f.obj, f.con, f.dir, f.rhs)
g$solution
I'm able to solve this manually for a small problem, what if I had a 7 X 7 or a n x n matrix a. How would I specify the constraint 1 and 2, especially I'm struggling to define the constraint as it relates to a[i,j]?
a = matrix(
c(1,4,9,6,6,5,5,
1/4,1,7,5,5,3,4,
1/9,1/7,1,1/5,1/5,1/7,1/5,
1/6,1/5,5,1,1,1/3,1/3,
1/6,1/5,5,1,1,1/3,1/3,
1/5,1/3,7,3,3,1,2,
1/5,1/4,5,3,3,1/2,1
),nrow = 7,byrow =T)
the solution to the above matrix is 0.986 0.501 0.160 0.043 0.060 0.060 0.1 0.075 Any help would be greatly appreciated.

Have updated to incorporate revised constraint 4 and have made some minor code improvements.
Assuming the constraint matrix in the question is correct, this uses combn to iterate over all i < j setting the appropriate elements. Note that x[1] is the value of i and x[2] is the value of j in f. make_cons returns the constraint matrix in the same order as shown in the question but the rbind line in make_cons could be simplified to rbind(cons1, cons2, cons3, cons4) if it were OK to use such order.
make_cons <- function(a) {
n <- nrow(a)
f <- function(x) replace(numeric(n), x, c(1, -a[x[1], x[2]]))
cons1 <- cbind(1, t(combn(1:n, 2, f)))
cons2 <- cbind(1, -cons1[, -1])
cons3 <- c(0, rep(1, n))
cons4 <- cbind(0, diag(n))
rbind(t(matrix(rbind(t(cons1), t(cons2)), ncol(cons1))), cons3, cons4)
}
# test
# a and f.con from question
a <- matrix(c(1, 0.5, 0.2, 2, 1, 0.333333333333333, 5, 3, 1), 3)
f.con <- matrix(c(1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, -1, 1, -1, 0, 0,
1, 1, 0, 0, -2, 2, 0, 0, 1, -1, 1, 0, 1, 0, 0, 0, -5, 5, -3,
3, 1, 0, 0, 1), 10)
all.equal(f.con, make_cons(a), check.attributes = FALSE)
## [1] TRUE

here is one possibility which uses for loops.
As I mentioned in the commenst, I think that you got condition (4) wrong. Here is my suggestion.
My idea is to first set up a matrix for constraints (4), then for constraint (3)
and then add constraints (2) and (1) in a loop. Note that, in the beginning, I do not consider the column corresponding to \mu. I will add this column in the end.
n<- nrow(a)
f.cons<- diag(n)
f.cons<- rbind(f.cons, rep(1,n))
This sets up a matrix corresponding to constraints (4) (first n rows) and constraint (3). Now I add rows to this matrix, using loops and the command rbind.
for(i in 1:(n-1)){
for(j in (i+1): n){
x<- rep(0, n)
x[i]<- 1 #x corresponds to (1)
x[j]<- -a[i,j]
y<- -x #y corresponds to (2)
f.cons<- rbind(f.cons, rbind(x, y))
}
}
So far, I have ignored the first column, which corresponds to \mu.
I add it with these two simple lines:
f.cons<- cbind(rep(1, nrow(f.cons)), f.cons)
f.cons[1:(n+1), 1]=0
Note that in my matrix f.cond the first n+1 lines correspond to constraints (3) and (4)!

Related

Find unique elements in a matrix other than 0

I have a matrix of the following form
b < -matrix(c(1, 0.0000000, 0.0000000, 0.0000000,
0, 0.1266234, 0.1590909, 0.7142857,
0, 0.1266234, 0.1590909, 0.7142857,
0, 0.1266234, 0.1590909, 0.7142857),
nrow = 4, ncol = 4, byrow = TRUE)
I want to get all the unique element in each column of b other than 0. And it should be returned as a vector of the following form:-
qq <- c(1, 0.1266234, 0.1590909, 0.7142857)
Thanks in advance!!
select items that are non-zero and find unique ones:
qq <- unique(b[b != 0])
qq
[1] 1.0000000 0.1266234 0.1590909 0.7142857
uniqueValues <- apply(b, 2, function(x) setdiff(unique(x), 0))
Keep in mind, that calculating unique values on numeric vectors has a bias due to accuracy. E.g. 0.99999 and 0.99998 are treated as different elements.

R solver optimization

I am new to R solver and I want to have a simple example in R for the below problem:
I have four columns which I calculate the individual sums as the illustrated sample example below:
The problem I want to solve in R:
Find the optimal lines that satisfies, simultaneously, the below statements:
For the first two columns (a, b) the individual summations to be more close to 0
The sums of (c, d) to be more close to 5
I do not have restrictions of which package solver to use. It could be helpful to have an example of R code for this!
EDIT
For the same solution I would like to apply some rules:
I want the sum(c) > sum(d) AND sum(d) < (static number, like 5)
Also, if I want the sums to fall into a range of numbers and not just static numbers, how the solution could it be written?
Using M defined reproducibly in the Note at the end we find the b which minimizes the following objective where b is a 0/1 vector:
sum((b %*% M - c(0, 0, 5, 5))^2)
1) CVXR Using the CVXR package we get a solution c(1, 0, 0, 1, 1) which means choose rows 1, 4 and 5.
library(CVXR)
n <- nrow(M)
b <- Variable(n, boolean = TRUE)
pred <- t(b) %*% M
y <- c(0, 0, 5, 5)
objective <- Minimize(sum((t(y) - pred)^2))
problem <- Problem(objective)
soln <- solve(problem)
bval <- soln$getValue(b)
zapsmall(c(bval))
## [1] 1 0 0 1 1
2) Brute Force Alternately since there are only 5 rows there are only 2^5 possible solutions so we can try them all and pick the one which minimizes the objective. First we compute a matrix solns with 2^5 columns such that each column is one possible solution. Then we compute the objective function for each column and take the one which minimizes it.
n <- nrow(M)
inverse.which <- function(ix, n) replace(integer(n), ix, 1)
L <- lapply(0:n, function(i) apply(combn(n, i), 2, inverse.which, n))
solns <- do.call(cbind, L)
pred <- t(t(solns) %*% M)
obj <- colSums((pred - c(0, 0, 5, 5))^2)
solns[, which.min(obj)]
## [1] 1 0 0 1 1
Note
M <- matrix(c(.38, -.25, .78, .83, -.65,
.24, -.35, .44, -.88, .15,
3, 5, 13, -15, 18,
18, -7, 23, -19, 7), 5)

Setting NAs with zeros in matrix with lapply seems does not work well?

I have these matrices.
matr <- list()
matr[[i]] <- c(0, NA, 3, 4, 4,
0, 0, 3, 4, 1,
0, 0, 0, NA, 1,
0, 0, NA, 0, 3,
0, 0, 0, 0, 0)
matr[[i]] <- matrix(matr[[i]], 5, 5)
I want to set NA to zero using the following code:
x <- lapply(matr,function(x) x[is.na(x) <- 0])
Then I got this result:
> x
[[1]]
numeric(0)
[[2]]
numeric(0)
[[3]]
numeric(0)
Why it does not return the matrices? Is my code correct? any help please?
Since lapply works on lists and return lists I think that isn't what you want.
I think using apply here fits better.
Try x <- apply(matr[[1]], 2, function(x){
x[is.na(x)] <- 0
x
})
The number 2 here indicates that you want to operate column-wise instead of row-wise (1st margin are rows, and 2nd margin are columns).
Also notice that you had put the <- operator within the brackets which was a wrong sintax.
EDIT:
It seems that I have misunderstood your question.
Here follows a code that works for an entire list:
lapply(matr, function(x){
apply(x, 2, function(y){
y[is.na(y)] <- 0
y
})
})

Apply - creating a matrix by combining two other matrices, using value from a vector to select the one to combine column from

I have a task that I am doing with an ordinary for loop. I think it can be done by one of apply functions but can't find a way to do it. Can you please if it is possible to apply apply to the problem or if there is more efficient way of solving it ?
I am aware that I can make udf and do.call() but I think it would be the same as for loop.
The problem:
I have two matrices a and b, both (m x n) and a vector of length n. I want to create third matrix (m x n) which would recieve columns from a or b based on the values of a vector.
For example:
a=
[0, 0, 0, 0]
[0, 0, 0, 0]
[0, 0, 0, 0]
[0, 0, 0, 0]
b=
[1, 1, 1, 1]
[1, 1, 1, 1]
[1, 1, 1, 1]
[1, 1, 1, 1]
x=
[-1, -1, 1, 1]
if x[k] is -1, c recieves column from a, if x[k] is 1 then c recieves column from b, which yields:
c=
[0, 0, 1, 0]
[0, 0, 1, 0]
[0, 0, 1, 0]
[0, 0, 1, 0]
Reproducible example:
a <- matrix(rep(0, 16), nrow = 4, ncol = 4)
b <- matrix(rep(1, 16), nrow = 4, ncol = 4)
x <- c(-1,-1, 1,-1)
c <- matrix(NA, nrow = 4, ncol = 4)
for (i in 1:length(x)){
if (x[[i]] < 0){
c[,i] <- a[,i]
} else {
c[,i] <- b[,i]
}
}
Is there any more efficient solution ?
Regards,
P.
We can either use ifelse after making the 'x' as the same length as 'a/b' by replicating each of the 'x' elements. The col is a convenient function to do that.
c <- a
c[] <- ifelse(x[col(a)]==-1, a, b)
Or as in the previous step, we create a logical vector (x==1), coerce to binary with +, make the length the same as 'a', specify the ncol in the matrix.
matrix(+(x==1)[col(a)], ncol=ncol(a))
# [,1] [,2] [,3] [,4]
#[1,] 0 0 1 0
#[2,] 0 0 1 0
#[3,] 0 0 1 0
#[4,] 0 0 1 0

Linear Programs using R

How can we solve a linear program using R? I want to solve the following example:
min -a -2b +4c
Constraints
a + b + s1 = 5
a + 3c -s2 = 10
2b - 3c = 20
a >= 0, b >= 0, c >= 0, s1 >= 0, s2 >= 0
The equations might not make total sense. I just need to know the syntax of writing these equations in R.
I might write something like this for the above equations
require(lpSolve)
R.obj <- c(-1,-2,4)
R.con <- matrix(c(1,1,1,1,3,-1,2,-3),nrow=3,byrow=TRUE)
R.dir <- c("=","=","=")
R.rhs <- c(5,10,20)
lp("min",R.obj,R.con,R.dir,R.rhs)
Would this be correct? In the documentation, the matrix is always M*M, what if the matrix is M*N where N != M?
Your constraint matrix has 3 rows and 5 columns, but you've only provided the 8 non-zero values when building your constraint matrix. Further, you have 5 variables, so R.obj needs 5 values:
require(lpSolve)
R.obj <- c(-1, -2, 4, 0, 0)
R.con <- matrix(c(1, 1, 0, 1, 0, 2, 0, 3, -3, 1, 0, 0, 0, -1, 0), nrow=3)
R.dir <- c("=", "=", "=")
R.rhs <- c(5, 10, 20)
lp("min", R.obj, R.con, R.dir, R.rhs)
# Error: no feasible solution found
A bit of math shows that this LP is indeed infeasible. This LP is equivalent to -a - b >= -5, a + 3c >= 10, b = 10 + 1.5c. You can substitute the last equation into the first to yield -a - 1.5c >= 5 and a + 3c >= 10, and adding yields c >= 10. By your third equation, b >= 25, which means the first equation can never hold due to the non-negativity of a and s1.

Resources