Solved – How to use equalities as constrains with constrOptim in R

constraintlinear programmingoptimizationr

I want to solve a matrix system which have several solutions (infinite since it is overdetermined – 6 equations with 8 unknowns). However, the way I want to do it is to a criterion for the variables, which should be minimized, to find a specific solution. I am working in R

My first through was to use constrOptim in R However, this requires for me to set constraints that are equalities, and not "larger than or equal to", which is the the default in constrOptim.

The problem is essentially that I have a matrix, where I know none of the elements, and I want the the rowSums to have specific values, and the colSums to have specific values. This however, should be done while minimizing criterias that the i,j element divided by the sum of the i'th row, should be as close as possible to the sum of the j'th column divided by the sum of the whole matrix.

Does anyone know how I could solve this problem using constrOptim, or by using another function?

Best Answer

So I found a solution that works. This might be relevant for others who find the question in the future.

Here cat1 and cat2 are the sums which are requried from the matrices.

The code that works:

require(Rsolnp)


cat1 <- c(10000,3000,2000)
cat2 <- c(5000, 2500,7500)

sum(cat11) == sum(cat2)
elements <- length(cat2)*length(cat1)


cat1.share <- c(cat1/sum(cat1))
cat1.counter <- rep(1:length(cat1), 3)

#specify your function
min.func <- function(x) {
sum.holder <- cat1[cat1.counter[1]]/sum(cat1)*cat2[ceiling(1/length(cat1)]-x[1]
    for (i in 2:elements)  {
    sum.holder <- c(sum.holder,cat1[cat1.counter[i]]/sum(cat1)*cat2[ceiling(i/length(cat1))]-x[i])
}
  sum(abs(sum.holder))
}

#specify the equality function. The number 15 (to which the function is equal)
#is specified as an additional argument
equal <- function(x) {

  y <- x[1:elements]

  matrix.hold <- matrix(y, nrow = length(cat2), ncol = length(cat1), byrow = TRUE) 

  hold <- c(rowSums(matrix.hold),
            colSums(matrix.hold)
  ) 
  hold <- hold[-length(hold)]
  hold

}

x.start<- rep(min(cat2)/9, elements)
x.low <- rep(0, elements)
x.high <- rep(max(c(cat1,cat2)), elements)


#the optimiser
opt <- solnp(x.start, #starting values 
             min.func, #function to optimise
             eqfun=equal, #equality function 
             eqB=c(cat2[1:length(cat2)], cat1[1:(length(cat1)-1)]),       #equality constraint
             LB=x.low, #lower bound for parameters i.e. greater than zero
             UB=x.high,
             control = c(delta = 1.0e-8, tol = 1e-11)) #upper bound for parameters 

opt.matrix <- matrix(opt$pars, nrow = length(cat2), ncol = length(cat1), byrow=TRUE)

    opt.matrix
Related Question