I was using Rsymphony and decided that I would like to use CPLEX. I am working through the cplexAPI in R and would rather use my existing structure for building a constraint matrix. The documentation says that the API takes the constraint matrix in column major order format with only the non-zero elements. So I need a way to (elegantly, I hope) convert a matrix into this form.
For example:
3.2 Creating and solving a mixed integer programming (MIP) problem In the following, an example MIP will be created and solved: ...
subject to:
Currently, this is implemented as a matrix
> mat = matrix(c(-1, 1, 1, 10,
+ 1, -3, 1, 0,
+ 0, 1, 0, -3.5),byrow = TRUE, nrow=3,ncol=4)
> mat
[,1] [,2] [,3] [,4]
[1,] -1 1 1 10.0
[2,] 1 -3 1 0.0
[3,] 0 1 0 -3.5
From the documentation, I need the following elements.
The constraint matrix is passed in column major order format. Be careful here: all indices start with 0! Begin indices of rows.
beg <- c(0, 2, 5, 7)
You will note that working from the top left down is how this works. In the first position (0) the second column begins with the third non-zero element, the third with the fifth, etc.
Number of non-zero elements per row.
cnt <- c(2, 3, 2, 2)
Again, what I would have said was columns.
Column indices.
ind <- c(0, 1, 0, 1, 2, 0, 1, 0, 2)
This is the column index of each non-zero element.
Non-zero elements.
val <- c(-1.0, 1.0, 1.0, -3.0, 1.0, 1.0, 1.0, 10.0, -3.5)
I am stumped on finding a way to get this done.
I know I can create val easily by:
c(mat)
[1] -1.0 1.0 0.0 1.0 -3.0 1.0 1.0 1.0 0.0 10.0 0.0 -3.5
val2 <- mat[mat !=0]
val <- c(-1.0, 1.0, 1.0, -3.0, 1.0, 1.0, 1.0, 10.0, -3.5)
val2 & val
[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
I can create cnt easily by:
cnt <- apply(mat,2,function(x) Matrix::nnzero(x, na.counted = NA))
cnt
[1] 2 3 2 2
Thanks to @42-
ind2 <- row(mat)[which(mat != 0)]-1
ind <- c(0, 1, 0, 1, 2, 0, 1, 0, 2)
ind2 == ind
[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
Now for beg.
Restating the pieces,
mat
[,1] [,2] [,3] [,4]
[1,] -1 1 1 10.0
[2,] 1 -3 1 0.0
[3,] 0 1 0 -3.5
beg <- c(0, 2, 5, 7)
val <- c(-1.0, 1.0, 1.0, -3.0, 1.0, 1.0, 1.0, 10.0, -3.5)
beg is an index that counts along the position of the non-zero element in val. So in mat[1,1] is the first non-zero element in mat and the first (0) element in val. In mat[,2] the first non-zero elment is the third element (2) in val. In mat[,3] the first non-zero element is the sixth (5) element in val and in mat[,4] the first non-zero element is the eighth (7) element of val.
Clear as mud? Me too.

It's not exactly clear to me what you are hoping for but here is a method to generate the row and column numbers that would index the non-zero entries in that matrix using zero-based indexing (which is not normal for R-matrix indexing although as you have seen that rule does not apply to sparse matrices constructed with Matrix-package functions.):