optimization and mathematical programming in r and roi - r optimization infrastructure
TRANSCRIPT
Prepared by VOLKAN OBAN
Optimization and Mathematical Programming in R.
&
ROI - R Optimization Infrastructure
Reference: https://cran.r-project.org/web/views/Optimization.html
Example: Non-linear Programming-nloptr package.
> install.packages("nloptr")
Ref: https://cran.r-project.org/web/packages/nloptr/vignettes/nloptr.pdf
Example:
library(Rsolnp)
> fn <- function(x) { # f(x,y) = 5x-3y + 5*x[1] - 3*x[2] + } > > # constraint z1: x^2+y^2=136 > eqn <- function(x) { + z1=x[1]^2 + x[2]^2 + return(c(z1)) + } > constraints = c(136) >
> x0 <- c(1, 1) # setup init values > sol1 <- solnp(x0, fun = fn, eqfun = eqn, eqB = constraints) Iter: 1 fn: 37.4378 Pars: 30.55472 38.44528 Iter: 2 fn: -147.9181 Pars: -6.57051 38.35517 Iter: 3 fn: -154.7345 Pars: -20.10545 18.06907 Iter: 4 fn: -96.4033 Pars: -14.71366 7.61165 Iter: 5 fn: -72.4915 Pars: -10.49919 6.66517 Iter: 6 fn: -68.1680 Pars: -10.04485 5.98124 Iter: 7 fn: -68.0006 Pars: -9.99999 6.00022 Iter: 8 fn: -68.0000 Pars: -10.00000 6.00000 Iter: 9 fn: -68.0000 Pars: -10.00000 6.00000 solnp--> Completed in 9 iterations Example:
fn <- function(x,...){ + -x[1]*x[2]*x[3] + } > > eqn <- function(x,...){ + 4*x[1]*x[2]+2*x[2]*x[3]+2*x[3]*x[1] + } > constraints = c(100) > > lx <- rep(1,3) > ux <- rep(10,3) > > pars <- c(1.1,1.1,9) # tricky setup > ctrl <- list(TOL=1e-6, trace=0) > sol3 <- solnp(pars, fun=fn, eqfun=eqn, eqB = constraints, LB=lx, UB=ux, control=ctrl) > sol3$pars [1] 2.886751 2.886751 5.773503
Reference: http://www.di.fc.ul.pt/~jpn/r/optimization/optimization.html
Example: Solve a Quadratic Programming Problem
solve.QP {quadprog}
>library(quadprog) > Dmat <- matrix(c(356.25808, 12.31581, 261.88302, 12.31581, 27.24840, 18.50515, 261.88302, 18.50515,535.45960), nrow=3, ncol=3) > dvec <- matrix(c(9.33, 3.33, 9.07), nrow=3, ncol=1) > A.Equality <- matrix(c(1,1,1), ncol=1)
> Amat <- cbind(A.Equality, dvec, diag(3), -diag(3)) > bvec <- c(1, 5.2, rep(0, 3), rep(-0.5, 3)) > qp <- solve.QP(Dmat, dvec, Amat, bvec, meq=1) > qp$solution [1] 0.3808733 0.5000000 0.1191267 Ref: http://stackoverflow.com/questions/24090037/r-portfolio-optimization-solve-qp-constraints-are-inconsistent
Example: Quadratic Programming library(quadprog) > mu_return_vector <- c(0.05, 0.04, 0.06) > sigma <- matrix(c(0.01, 0.002, 0.005, + 0.002, 0.008, 0.006, + 0.005, 0.006, 0.012), + nrow=3, ncol=3) > D.Matrix <- 2*sigma > d.Vector <- rep(0, 3) > A.Equality <- matrix(c(1,1,1), ncol=1) > A.Matrix <- cbind(A.Equality, mu_return_vector, diag(3)) > b.Vector <- c(1, 0.052, rep(0, 3)) > out <- solve.QP(Dmat=D.Matrix, dvec=d.Vector, Amat=A.Matrix, bvec=b.Vector, meq=1) > out$solution [1] 0.4 0.2 0.4 > out$value [1] 0.00672
Example. Unconstrained optimization
> f <- function(x){(x[1] - 5)^2 + (x[2] - 6)^2} > initial_x <- c(10, 11) > x_optimal <- optim(initial_x, f, method="CG") > x_min <- x_optimal$par > x_min [1] 5 6
Example: Linear Programming > library(lpSolve) > library(lpSolveAPI) > # Set the number of vars > model <- make.lp(0, 3) > # Define the object function: for Minimize, use -ve
> set.objfn(model, c(-0.05, -0.04, -0.06)) > # Add the constraints > add.constraint(model, c(1, 1, 1), "=", 1) > add.constraint(model, c(1, 1, -1), ">", 0) > add.constraint(model, c(1, -2, 0), "<", 0) > # Set the upper and lower bounds > set.bounds(model, lower=c(0.1, 0.1, 0.1), upper=c(1, 1, 1)) > # Compute the optimized model > solve(model) [1] 0 > get.variables(model) [1] 0.3333333 0.1666667 0.5000000 > get.objective(model) [1] -0.05333333 > # Get the value of the constraint > get.constraints(model) [1] 1 0 0
Reference: http://horicky.blogspot.com.tr/search?q=unconstrained Example: Regression
RSS = ( Y - X b )' ( Y - X b ) = Y Y' - 2 Y' X b + b X' X b # Sample data n <- 100 x1 <- rnorm(n) x2 <- rnorm(n) y <- 1 + x1 + x2 + rnorm(n) X <- cbind( rep(1,n), x1, x2 ) # Regression r <- lm(y ~ x1 + x2) # Optimization
library(quadprog) s <- solve.QP( t(X) %*% X, t(y) %*% X, matrix(nr=3,nc=0), numeric(), 0 ) coef(r) s$solution # Identical
> coef(r) (Intercept) x1 x2 0.9973739 0.9234925 0.9275238 > s$solution # Identical [1] 0.9973739 0.9234925 0.9275238
Ref: http://zoonek.free.fr/blosxom/R/2012-06-01_Optimization.html
Example: Gradient Descent algorithm in R The example provides a code listing Gradient Descent algorithm in R solving a two-dimensional nonlinear optimization function.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
# define a 2D basin function, optima is at (0,0) basin <- function(x) { x[1]^2 + x[2]^2 } # define the derivative for a 2D basin function derivative <- function(x) { c(2*x[1], 2*x[2]) } # definition of the gradient descent method in 2D gradient_descent <- function(func, derv, start, step=0.05, tol=1e-8) { pt1 <- start grdnt <- derv(pt1) pt2 <- c(pt1[1] - step*grdnt[1], pt1[2] - step*grdnt[2]) while (abs(func(pt1)-func(pt2)) > tol) { pt1 <- pt2 grdnt <- derv(pt1) pt2 <- c(pt1[1] - step*grdnt[1], pt1[2] - step*grdnt[2]) print(func(pt2)) # print progress } pt2 # return the last point } # locate the minimum of the function using the Gradient Descent method result <- gradient_descent( basin, # the function to optimize derivative, # the gradient of the function c(runif(1,-3,3), runif(1,-3,3)), # start point of the search 0.05, # step size (alpha) 1e-8) # relative tolerance for one step # display a summary of the results print(result) # coordinate of fucntion minimum print(basin(result)) # response of fucntion minimum # display the function as a contour plot x <- seq(-3, 3, length.out=100)
40 41 42 43 44 45
y <- seq(-3, 3, length.out=100) z <- basin(expand.grid(x, y)) contour(x, y, matrix(z, length(x)), xlab="x",ylab="y") # draw the optima as a point points(result[1], result[2], col="red", pch=19) # draw a square around the optima to highlight it rect(result[1]-0.2, result[2]-0.2, result[1]+0.2, result[2]+0.2, lwd=2)
Example: > library(lpSolve) > ac<- matrix (c(2, 7, 7, 2, 7, 7, 3, 2, 7, 2, 8, 10, 1, 9, 8, 2), 4, 4) > ac [,1] [,2] [,3] [,4] [1,] 2 7 7 1 [2,] 7 7 2 9 [3,] 7 3 8 8 [4,] 2 2 10 2 > library(lpSolve) > lp.assign(ac) Success: the objective function is 8 > lp.assign(ac)$solution [,1] [,2] [,3] [,4] [1,] 0 0 0 1 [2,] 0 0 1 0 [3,] 0 1 0 0 [4,] 1 0 0 0
Example:
lp.transport Integer Programming for the Transportation Problem > costs <- matrix (10000, 8, 5); costs[4,1] <- costs[-4,5] <- 0 > costs[1,2] <- costs[2,3] <- costs[3,4] <- 7; costs[1,3] <- costs[2,4] <- 7.7 > costs[5,1] <- costs[7,3] <- 8; costs[1,4] <- 8.4; costs[6,2] <- 9 > costs[8,4] <- 10; costs[4,2:4] <- c(.7, 1.4, 2.1) > > row.signs <- rep ("<", 8) > row.rhs <- c(200, 300, 350, 200, 100, 50, 100, 150) > col.signs <- rep (">", 5) > col.rhs <- c(250, 100, 400, 500, 200) > > lp.transport (costs, "min", row.signs, row.rhs, col.signs, col.rhs) Success: the objective function is 7790 > ## Not run: Success: the objective function is 7790 > lp.transport (costs, "min", row.signs, row.rhs, col.signs, col.rhs)$solution [,1] [,2] [,3] [,4] [,5] [1,] 0 100 100 0 0 [2,] 0 0 200 100 0 [3,] 0 0 0 350 0 [4,] 200 0 0 0 0 [5,] 50 0 0 0 50 [6,] 0 0 0 0 50 [7,] 0 0 100 0 0 [8,] 0 0 0 50 100
Example: >library(lpSolveAPI) > lprec <- make.lp(0, 4) > set.objfn(lprec, c(1, 3, 6.24, 0.1)) > add.constraint(lprec, c(0, 78.26, 0, 2.9), ">=", 92.3) > add.constraint(lprec, c(0.24, 0, 11.31, 0), "<=", 14.8) > add.constraint(lprec, c(12.68, 0, 0.08, 0.9), ">=", 4) > set.bounds(lprec, lower = c(28.6, 18), columns = c(1, 4)) > set.bounds(lprec, upper = 48.98, columns = 4) > RowNames <- c("THISROW", "THATROW", "LASTROW") > ColNames <- c("COLONE", "COLTWO", "COLTHREE", "COLFOUR") > dimnames(lprec) <- list(RowNames, ColNames) > lprec Model name: COLONE COLTWO COLTHREE COLFOUR Minimize 1 3 6.24 0.1 THISROW 0 78.26 0 2.9 >= 92.3 THATROW 0.24 0 11.31 0 <= 14.8 LASTROW 12.68 0 0.08 0.9 >= 4 Kind Std Std Std Std Type Real Real Real Real Upper Inf Inf Inf 48.98 Lower 28.6 0 0 18 > solve(lprec) [1] 0 > get.objective(lprec) [1] 31.78276 > get.variables(lprec)
[1] 28.60000 0.00000 0.00000 31.82759 > get.constraints(lprec) [1] 92.3000 6.8640 391.2928
Example: The Rsymphony package in R can solve this problem for you. You will need a vector of the distances ci,jci,j and 0's for each yiyi as well as a matrix to take care of the constraints (the three summations starting after "subject to"). If you aren't familiar with the constraint matrix, each column contains the coefficients for that variable. The help file for the Rsymphony package has a couple examples that should help with that. Don't forget to include columns for the yiyi in the matrix as well. You will also need to set the xi,jxi,j and yiyi to be binary by using library(Rsymphony) > obj <- c(2.8, 5.4, 1.4, 4.2, 3.0, 6.3, 0, 0) > mat <- matrix(c(1,0,0,1,0,0,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,-3,0,1,0,0,0,0,-3,1), nrow = 6) > dir <- c("==", "==", "==", "<=", "<=", "<=") > rhs <- c(1, 1, 1, 0, 0, 2) > max <- FALSE > types <- "B" > fac.loc <- Rsymphony_solve_LP(obj, mat, dir, rhs, types = types, max = max, write_lp = TRUE) > fac.loc $solution [1] 1 0 1 0 1 0 1 1 $objval [1] 7.2 $status TM_UNBOUNDED 237
Example: >library(clue) > > matrix1 <- matrix(c( 3, 2, 1, 4, 4, 4, 4, + 4, 4, 4, 4, 1, 2, 3, + 4, 1, 3, 2, 4, 4, 4, + 4, 4, 4, 1, 2, 3, 4, + 2, 4, 3, 4, 1, 4, 4, + 4, 3, 4, 4, 4, 2, 1, + 4, 1, 2, 4, 3, 4, 4), nrow=7, byrow=TRUE) > > matrix1 [,1] [,2] [,3] [,4] [,5] [,6] [,7] [1,] 3 2 1 4 4 4 4 [2,] 4 4 4 4 1 2 3 [3,] 4 1 3 2 4 4 4 [4,] 4 4 4 1 2 3 4 [5,] 2 4 3 4 1 4 4 [6,] 4 3 4 4 4 2 1 [7,] 4 1 2 4 3 4 4 > > solve_LSAP(matrix1, maximum = FALSE)
Optimal assignment: 1 => 3, 2 => 5, 3 => 2, 4 => 4, 5 => 1, 6 => 7, 7 => 6
Example: > students <- matrix(c(10, 9, 8, + 1, 2, 10, + 10, 2, 5, + 2, 5, 3, + 10, 2, 10, + 1, 10, 1, + 5, 5, 5), nrow=7, ncol=3, byrow=TRUE) > > projects <- matrix(c(10, 5, 1, + 1, 1, 5, + 10, 10, 10, + 2, 8, 3, + 4, 3, 2, + 1, 1, 1, + 5, 7, 2), nrow=7, ncol=3, byrow=TRUE) > > library(combinat) > > n <- nrow(students) > > assignments <- permn(1:n) > assignments <- do.call(rbind, assignments) > dim(assignments) [1] 5040 7 > > # column of assignments = student > # row of assignments = iteration > # cell of assignments = project > > cost <- matrix(NA, nrow=nrow(assignments), ncol=n) > > for(i in 1:(nrow(assignments))) { + for(student in 1:n) { + + project <- assignments[i,student] + student.cost <- rep(NA,3) + + for(k in 1:3) { + student.cost[k] <- abs(students[student,k] - projects[project,k]) + } + + cost[i,student] <- sum(student.cost) + } + } > > > total.costs <- rowSums(cost) > > assignment.costs <- cbind(assignments, total.costs) > head(assignment.costs)
total.costs [1,] 1 2 3 4 5 6 7 62 [2,] 1 2 3 4 5 7 6 68 [3,] 1 2 3 4 7 5 6 74 [4,] 1 2 3 7 4 5 6 80 [5,] 1 2 7 3 4 5 6 94 [6,] 1 7 2 3 4 5 6 102 >
> assignment.costs[assignment.costs[,(n+1)]==min(assignment.costs[,(n+1)]),] total.costs [1,] 3 2 5 4 1 6 7 48 [2,] 3 2 5 6 1 4 7 48 [3,] 3 2 1 6 5 4 7 48 [4,] 3 2 1 4 5 6 7 48
Ref: http://stackoverflow.com/questions/16703277/matching-algorithms-in-r-bipartite-matching-hungarian-algorithm
Example: > # TSP with 10 cities around a circular pattern > require(gaoptim) > > op <- par(mfrow = c(2, 1)) > n = 10 > R = 10 > angs = seq(0, 2*pi, length = n) > xp = R * cos(angs) + rnorm(n) > yp = R * sin(angs) + rnorm(n) > xp = c(xp, xp[1]) > yp = c(yp, yp[1]) > > base.M = matrix(c(xp, yp), ncol = 2) > dist.FUN = function(p) + { + p = c(p, p[1]) + M.diff = diff(base.M[p, ]) + dists = apply(M.diff, 1, function(x)x[1]^2 + x[2]^2) + 1/sum(dists) + } > > ga1 = GAPerm(dist.FUN, n, popSize = 100, mutRate = 0.3) > ga1$evolve(100) > plot(ga1) > plot(xp, yp, type = 'n', xlab = '', ylab = '', main = 'Best Tour') > res = ga1$bestIndividual() > res = c(res, res[1]) > > i = 1:n > xi = base.M[res[i], 1] > yi = base.M[res[i], 2] > xf = base.M[res[i + 1], 1] > yf = base.M[res[i + 1], 2] > > arrows(xi, yi, xf, yf, col = 'red', angle = 10) > text(base.M[res, 1], base.M[res, 2], 1:n, cex = 0.9, col = 'gray20') > par(op)
Ref: https://www.r-bloggers.com/combinatorial-optimization-with-gaoptim-package/
Example: require(quadprog) > Dmat <- 2*matrix(c(1,-1/2,-1/2,1), nrow = 2, byrow=TRUE) > dvec <- c(-3,2) > A <- matrix(c(1,1,-1,1,0,-1), ncol = 2 , byrow=TRUE) > bvec <- c(2,-2,-3) > Amat <- t(A) > sol <- solve.QP(Dmat, dvec, Amat, bvec, meq=0) > sol $solution [1] 0.1666667 1.8333333 $value [1] -0.08333333 $unconstrained.solution [1] -1.3333333 0.3333333 $iterations [1] 2 0 $Lagrangian [1] 1.5 0.0 0.0
$iact [1] 1
Example: > require(quadprog) > Dmat <- 2*matrix(c(1,-1/2,-1/2,1), nrow = 2, byrow=TRUE) > dvec <- c(-3,2) > A <- matrix(c(1,1,-1,1,0,-1), ncol = 2 , byrow=TRUE) > bvec <- c(2,-2,-3) > Amat <- t(A) > sol <- solve.QP(Dmat, dvec, Amat, bvec, meq=0) > sol $solution [1] 0.1666667 1.8333333 $value [1] -0.08333333 $unconstrained.solution [1] -1.3333333 0.3333333 $iterations [1] 2 0 $Lagrangian [1] 1.5 0.0 0.0 $iact [1] 1 > require(lattice) > qp_sol <- sol$solution > uc_sol <- sol$unconstrained.solution > x <- seq(-2, 5.5, length.out = 500) > y <- seq(-1, 3.5, length.out = 500) > grid <- expand.grid(x=x, y=y) > grid$z <- with(grid, x^2 + y^2 -x*y +3*x -2*y + 4) > levelplot(z~x*y, grid, cuts=30, + panel = function(...){ + panel.levelplot(...) + panel.polygon(c(2,5,-1),c(0,3,3), border=TRUE, lwd=4, col="transparent") + panel.points(c(uc_sol[1],qp_sol[1]), + c(uc_sol[2],qp_sol[2]), + lwd=5, col=c("red","yellow"), pch=19)}, + colorkey=FALSE, + col.regions = terrain.colors(30))
ROI - R Optimization Infrastructure Reference: http://roi.r-forge.r-project.org/jekyll/update/2016/06/17/new_roi_version.html
ROI install.packages("ROI")
ROI-Plugins
## ROI.plugin.glpk
## NOTE: Rglpk needs GLPK library
## "sudo apt-get libglpk-dev" on Debian/Ubuntu
install.packages("Rglpk")
install.packages("ROI.plugin.glpk")
## or install.packages("ROI.plugin.glpk", repos="http://R-Forge.R-project.org")
## ROI.plugin.quadprog
install.packages("quadprog")
install.packages("ROI.plugin.quadprog")
## or install.packages("ROI.plugin.quadprog", repos="http://R-Forge.R-project.org")
## ROI.plugin.symphony
install.packages("Rsymphony")
install.packages("ROI.plugin.symphony")
## or install.packages("ROI.plugin.nloptr", repos="http://R-Forge.R-project.org")
## ROI.plugin.ecos
install.packages("ECOSolveR")
install.packages("ROI.plugin.ecos")
## or install.packages("ROI.plugin.symphony", repos="http://R-Forge.R-project.org")
## ROI.plugin.scs
install.packages("scs")
install.packages("ROI.plugin.scs")
## or install.packages("ROI.plugin.scs", repos="http://R-Forge.R-project.org")
## ROI.plugin.nloptr
install.packages("nloptr")
install.packages("ROI.plugin.nloptr")
## or install.packages("ROI.plugin.nloptr", repos="http://R-Forge.R-project.org")
## ROI.plugin.cplex
## NOTE: Rcplex requires the IBM ILOG CPLEX libraries and headers.
install.packages("Rcplex")
install.packages("ROI.plugin.cplex")
## or install.packages("ROI.plugin.cplex", repos="http://R-Forge.R-project.org")
Example:
library("ROI")
> mat <- matrix(c(-1, 2, 1, + 0, 4, -3, + 1, -3, 2), nrow = 3, byrow=TRUE) > lp <- OP(objective = c(3, 1, 3), + constraints = L_constraint(L = mat, + dir = c("<=", "<=", "<="), + rhs = c(4, 2, 3)), + types = c("I", "C", "I"), + maximum = TRUE) > > sol <- ROI_solve(lp) > sol Optimal solution found. The objective value is: 2.675000e+01 > ## Optimal solution found. > ## The objective value is: 2.675000e+01 > solution(sol) [1] 5.00 2.75 3.00
Example:
> qp <- OP(objective = Q_objective(2*diag(2), L=c(0, 2)), + constraints = L_constraint(L = c(1, 1), dir = "==", rhs = 2), + maximum = FALSE) > > sol <- ROI_solve(qp)
> ## sol > ## Optimal solution found. > ## The objective value is: 3.500000e+00 > solution(sol) [1] 1.5 0.5 > ## [1] 1.5 0.5