--- title: "Comparing the Simulated Annealing and Robust Tabu Search Solvers" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Comparing the Simulated Annealing and Robust Tabu Search Solvers} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` ## Introduction The `qap` package provides two heuristics for the quadratic assignment problem (QAP), selected with the `method` argument of `qap()`: * `"SA"`: the simulated annealing heuristic of Burkard and Rendl (1984), and * `"RoTS"`: the robust tabu search of Taillard (1991). This vignette compares them on QAPLIB instances of increasing size, looking at the run time and at the quality of the solution. Quality is the percentage by which the objective value is above the known optimal (or best known) value stored with the instance. Run times depend on your machine and the results depend on the random seed, so your numbers will differ from those shown here. Each comparison below is a single seeded run on a small set of instances, so it illustrates typical behavior rather than being a rigorous benchmark. ```{r} library(qap) set.seed(2024) ``` ## Comparison We solve instances with 30 to 100 facilities from QAPLib. Each method gets 3 random restarts and uses its default settings. ```{r} instances <- c("tai30a", "tai50a", "tai80a", "sko100a") reps <- 3 run <- function(p, method, ...) { time <- system.time(a <- qap(p$A, p$B, method = method, ...))[["elapsed"]] c(obj = unname(attr(a, "obj")), time = time) } res <- do.call(rbind, lapply(instances, function(f) { p <- read_qaplib(system.file("qaplib", paste0(f, ".dat"), package = "qap")) sa <- run(p, "SA", rep = reps) ro <- run(p, "RoTS", rep = reps) data.frame( instance = f, n = nrow(p$A), opt = p$opt, SA_gap = (sa[["obj"]] - p$opt) / p$opt * 100, RoTS_gap = (ro[["obj"]] - p$opt) / p$opt * 100, SA_time = sa[["time"]], RoTS_time = ro[["time"]] ) })) ``` ```{r} knitr::kable(res, digits = 3, row.names = FALSE, col.names = c("Instance", "n", "Optimum", "SA gap (%)", "RoTS gap (%)", "SA time (s)", "RoTS time (s)")) ``` ```{r, fig.width = 7, fig.height = 3.5, fig.alt = "Solution gap and run time of both solvers by instance size."} op <- par(mfrow = c(1, 2), mar = c(4, 4, 2, 1)) matplot(res$n, res[, c("SA_gap", "RoTS_gap")], type = "b", pch = 1:2, lty = 1, col = 1:2, xlab = "n", ylab = "gap above optimum (%)", main = "Solution quality") legend("topleft", legend = c("SA", "RoTS"), pch = 1:2, col = 1:2, lty = 1) matplot(res$n, res[, c("SA_time", "RoTS_time")], type = "b", pch = 1:2, lty = 1, col = 1:2, log = "y", xlab = "n", ylab = "seconds", main = "Run time") par(op) ``` Simulated annealing finishes much faster, but its solutions are typically further from the optimum. The solution can be modestly improved by tuning (increasing) `ft` and `maxsteps`. Robust tabu search spends more time and finds better solutions. Its cost per iteration grows with the number of swap moves, which is quadratic in `n`, and its default number of iterations grows linearly with `n`. Its run time therefore grows roughly cubically with `n`. Larger QAPLIB instances such as `tai256c` (256 facilities) can be added to `instances`, but a single tabu search restart then takes tens of seconds, so we leave them out to keep this vignette fast to build. ## Recommendations * Use `method = "SA"` when you need a good solution very quickly, for example as a starting point or inside a loop that solves many problems. Increase `rep` or `ft` and `maxsteps` to trade time for quality. * Use `method = "RoTS"` when solution quality matters more than run time, or when you want better solutions from a single run. You can increase `iter` or `rep` for harder or larger instances. * Compare the objective value with the known optimum for benchmark instances, and use `set.seed()` to make runs reproducible. ## References * ```{r results = "asis", echo = FALSE} print(citation("qap"), style = "text") ``` * Burkard, R. E. and Rendl, F. (1984). A thermodynamically motivated simulation procedure for combinatorial optimization problems. _European Journal of Operational Research,_ 17(2), 169-174. * Taillard, E. (1991). Robust taboo search for the quadratic assignment problem. _Parallel Computing,_ 17(4-5), 443-455.