[R] Combinatorial Optimisation
Adrian Trapletti
adrian.trapletti@lmttrading.com
Fri, 25 Oct 2002 23:32:32 +0200
This is a multi-part message in MIME format.
--------------D871E36B191E8352EBC0EAA5
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
ripley@stats.ox.ac.uk wrote:
> Adrian,
>
> Thanks for the idea. If you were willing to contribute a patch to do this
> we would be happy to incorporate it.
Patches for optim.c and optim.Rd against R-1.6.0 source are attached. I didn't test too extensively, but the basic things and the
traveling salesman example seem to work cleanly. I would be glad if you could review and maybe enhance, in particular the S related
code, in optim.c, because there I am really not an expert.
Furthermore, as I was scanning through optim.c I was not sure if line 99 (original)
df[i] = REAL(s)[i] * (OS->parscale[i])/(OS->fnscale);
is correct. Shouldn't that be
df[i] = REAL(s)[i] / ((OS->parscale[i])*(OS->fnscale));
to get back to the optim-internal scaling?
best
Adrian
--
Dr. Adrian Trapletti Phone : +41 (0) 1 994 5631
Trapletti Statistical Computing Mobile: +41 (0)76 370 5631
Wildsbergstrasse 31 Fax : +41 (0) 1 994 5631
CH-8610 Uster Email : mailto:a.trapletti@bluewin.ch
Switzerland WWW : http://trapletti.homelinux.com
--------------D871E36B191E8352EBC0EAA5
Content-Type: text/plain; charset=us-ascii;
name="patch.optim.Rd"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="patch.optim.Rd"
7c7
< box-constrained optimization.
---
> box-constrained optimization and simulated annealing.
21,22c21,24
< \code{"Nelder-Mead"} and \code{"SANN"} method. If it is \code{NULL}
< and it is needed, a finite-difference approximation will be used.}
---
> \code{"Nelder-Mead"} method. If it is \code{NULL} and it is needed, a
> finite-difference approximation will be used. For the \code{"SANN"}
> method it is a function to generate a new candidate point. If it is
> \code{NULL} a default Gaussian Markov kernel is used.}
59c61
< Method \code{"SANN"} is a variant of simulated annealing
---
> Method \code{"SANN"} is by default a variant of simulated annealing
64,69c66,73
< acceptance probability. The next candidate point is generated from a
< Gaussian Markov kernel with scale proportional to the actual temperature.
< Temperatures are decreased according to the logarithmic cooling
< schedule as given in Belisle (1992, p. 890). Note that the
< \code{"SANN"} method depends critically on the settings of the
< control parameters. It is not a general-purpose method but can be
---
> acceptance probability. By default the next candidate point is
> generated from a Gaussian Markov kernel with scale proportional to the
> actual temperature. If a function to generate a new candidate point is
> given, method \code{"SANN"} can also be used to solve combinatorial
> optimization problems. Temperatures are decreased according to the
> logarithmic cooling schedule as given in Belisle (1992, p. 890). Note
> that the \code{"SANN"} method depends critically on the settings of
> the control parameters. It is not a general-purpose method but can be
176c180
<
---
>
240a245,290
>
> ## Combinatorial optimization: Traveling salesman problem
> library(mva)
>
> data(eurodist)
> eurodistmat <- as.matrix(eurodist)
>
> distance <- function(sq) { # Target function
> sq2 <- embed(sq, 2)
> return(sum(eurodistmat[cbind(sq2[,2],sq2[,1])]))
> }
>
> genseq <- function(sq) { # Generate new candidate sequence
> idx <- seq(2, NROW(eurodistmat)-1, by=1)
> changepoints <- sample(idx, size=2, replace=FALSE)
> tmp <- sq[changepoints[1]]
> sq[changepoints[1]] <- sq[changepoints[2]]
> sq[changepoints[2]] <- tmp
> return(sq)
> }
>
> sq <- c(1,2:NROW(eurodistmat),1) # Initial sequence
> distance(sq)
>
> res <- optim(sq, distance, genseq, method="SANN",
> control=list(maxit=20000, temp=2000 ,trace=T))
> res # Near optimum distance around 12842
>
> loc <- cmdscale(eurodist)
> rx <- range(x <- loc[,1])
> ry <- range(y <- -loc[,2])
> tspinit <- loc[sq,]
> tspres <- loc[res$par,]
> s <- seq(NROW(tspres)-1)
>
> plot(x, y, type="n", asp=1, xlab="", ylab="",
> main="initial solution of traveling salesman problem")
> arrows(tspinit[s,1], -tspinit[s,2], tspinit[s+1,1], -tspinit[s+1,2],
> angle=10, col="green")
> text(x, y, names(eurodist), cex=0.8)
>
> plot(x, y, type="n", asp=1, xlab="", ylab="",
> main="optim() 'solving' traveling salesman problem")
> arrows(tspres[s,1], -tspres[s,2], tspres[s+1,1], -tspres[s+1,2],
> angle=10, col="red")
> text(x, y, names(eurodist), cex=0.8)
--------------D871E36B191E8352EBC0EAA5
Content-Type: text/plain; charset=us-ascii;
name="patch.optim.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="patch.optim.c"
*** ./src/main/optim.c.origin Mon Apr 8 08:19:48 2002
--- ./src/main/optim.c Fri Oct 25 18:27:41 2002
***************
*** 155,164 ****
--- 155,193 ----
}
UNPROTECT(1); /* x */
}
}
+ static void genptry(int n, double *p, double *ptry, double scale, void *ex)
+ {
+ SEXP s, x;
+ int i;
+ OptStruct OS = (OptStruct) ex;
+ PROTECT_INDEX ipx;
+
+ if (!isNull(OS->R_gcall)) { /* user defined generation of candidate point */
+ PROTECT(x = allocVector(REALSXP, n));
+ for (i = 0; i < n; i++) {
+ if (!R_FINITE(p[i])) error("non-finite value supplied by optim");
+ REAL(x)[i] = p[i] * (OS->parscale[i]);
+ }
+ SETCADR(OS->R_gcall, x);
+ PROTECT_WITH_INDEX(s = eval(OS->R_gcall, OS->R_env), &ipx);
+ REPROTECT(s = coerceVector(s, REALSXP), ipx);
+ if(LENGTH(s) != n)
+ error("candidate point in optim evaluated to length %d not %d",
+ LENGTH(s), n);
+ for (i = 0; i < n; i++)
+ ptry[i] = REAL(s)[i] / (OS->parscale[i]);
+ UNPROTECT(2);
+ }
+ else { /* default Gaussian Markov kernel */
+ for (i = 0; i < n; i++)
+ ptry[i] = p[i] + scale * norm_rand(); /* new candidate point */
+ }
+ }
+
/* par fn gr method options */
SEXP do_optim(SEXP call, SEXP op, SEXP args, SEXP rho)
{
SEXP par, fn, gr, method, options, tmp, slower, supper;
SEXP res, value, counts, conv;
***************
*** 219,237 ****
for (i = 0; i < npar; i++)
REAL(par)[i] = opar[i] * (OS->parscale[i]);
grcount = NA_INTEGER;
}
! else if (strcmp(tn, "SANN") == 0) {
! tmax = asInteger(getListElement(options, "tmax"));
! temp = asReal(getListElement(options, "temp"));
! if (tmax == NA_INTEGER) error("tmax is not an integer");
! samin (npar, dpar, &val, fminfn, maxit, tmax, temp, trace, (void *)OS);
! for (i = 0; i < npar; i++)
! REAL(par)[i] = dpar[i] * (OS->parscale[i]);
! fncount = maxit;
! grcount = NA_INTEGER;
} else if (strcmp(tn, "BFGS") == 0) {
SEXP ndeps;
nREPORT = asInteger(getListElement(options, "REPORT"));
--- 248,273 ----
for (i = 0; i < npar; i++)
REAL(par)[i] = opar[i] * (OS->parscale[i]);
grcount = NA_INTEGER;
}
! else if (strcmp(tn, "SANN") == 0) {
! tmax = asInteger(getListElement(options, "tmax"));
! temp = asReal(getListElement(options, "temp"));
! if (tmax == NA_INTEGER) error("tmax is not an integer");
! if (!isNull(gr)) {
! if (!isFunction(gr)) error("gr is not a function");
! PROTECT(OS->R_gcall = lang2(gr, R_NilValue));
! } else {
! PROTECT(OS->R_gcall = R_NilValue); /* for balance */
! }
! samin (npar, dpar, &val, fminfn, maxit, tmax, temp, trace, (void *)OS);
! for (i = 0; i < npar; i++)
! REAL(par)[i] = dpar[i] * (OS->parscale[i]);
! fncount = maxit;
! grcount = NA_INTEGER;
! UNPROTECT(1); /* OS->R_gcall */
} else if (strcmp(tn, "BFGS") == 0) {
SEXP ndeps;
nREPORT = asInteger(getListElement(options, "REPORT"));
***************
*** 1056,1074 ****
Rprintf ("sann objective function values\n");
Rprintf ("initial value %f\n", *yb);
}
scale = 1.0/ti;
its = itdoc = 1;
! while (its < maxit) { /* cool down system */
t = ti/log((double)its + E1); /* temperature annealing schedule */
k = 1;
while ((k <= tmax) && (its < maxit)) /* iterate at constant temperature */
{
! for (i = 0; i < n; i++)
! dp[i] = scale * t * norm_rand(); /* random perturbation */
! for (i = 0; i < n; i++)
! ptry[i] = p[i] + dp[i]; /* new candidate point */
ytry = fminfn (n, ptry, ex);
if (!R_FINITE(ytry)) ytry = big;
dy = ytry - y;
if ((dy <= 0.0) || (unif_rand() < exp(-dy/t))) { /* accept new point? */
for (j = 0; j < n; j++) p[j] = ptry[j];
--- 1092,1107 ----
Rprintf ("sann objective function values\n");
Rprintf ("initial value %f\n", *yb);
}
scale = 1.0/ti;
its = itdoc = 1;
! while (its < maxit) { /* cool down system */
t = ti/log((double)its + E1); /* temperature annealing schedule */
k = 1;
while ((k <= tmax) && (its < maxit)) /* iterate at constant temperature */
{
! genptry(n, p, ptry, scale * t, ex); /* generate new candidate point */
ytry = fminfn (n, ptry, ex);
if (!R_FINITE(ytry)) ytry = big;
dy = ytry - y;
if ((dy <= 0.0) || (unif_rand() < exp(-dy/t))) { /* accept new point? */
for (j = 0; j < n; j++) p[j] = ptry[j];
--------------D871E36B191E8352EBC0EAA5--
-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
r-devel mailing list -- Read http://www.ci.tuwien.ac.at/~hornik/R/R-FAQ.html
Send "info", "help", or "[un]subscribe"
(in the "body", not the subject !) To: r-devel-request@stat.math.ethz.ch
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._