## ----include = FALSE---------------------------------------------------------- knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ## ----------------------------------------------------------------------------- library(RcppTrust) # Rosenbrock's function, exactly the example from ?trust::trust objfun <- function(x) { f <- expression(100 * (x2 - x1^2)^2 + (1 - x1)^2) g1 <- D(f, "x1"); g2 <- D(f, "x2") h11 <- D(g1, "x1"); h12 <- D(g1, "x2"); h22 <- D(g2, "x2") x1 <- x[1]; x2 <- x[2] list( value = eval(f), gradient = c(eval(g1), eval(g2)), hessian = rbind(c(eval(h11), eval(h12)), c(eval(h12), eval(h22))) ) } out <- trust(objfun, c(3, 1), 1, 5) out[c("value", "argument", "converged", "iterations")] ## ----eval = requireNamespace("trust", quietly = TRUE) && requireNamespace("microbenchmark", quietly = TRUE)---- library(microbenchmark) # same Rosenbrock objfun as above: 2 parameters, ~20 iterations mb_small <- microbenchmark( trust = trust::trust(objfun, c(3, 1), 1, 5), RcppTrust = RcppTrust::trust(objfun, c(3, 1), 1, 5), times = 50 ) print(mb_small) ## ----eval = requireNamespace("trust", quietly = TRUE) && requireNamespace("microbenchmark", quietly = TRUE)---- d <- 30 mu <- seq_len(d) barrier_objfun <- function(x) { normxsq <- sum(x^2) omnormxsq <- 1 - normxsq if (normxsq >= 1) return(list(value = Inf)) f <- sum(x * mu) - log(omnormxsq) g <- mu + 2 * x / omnormxsq B <- 4 * outer(x, x) / omnormxsq^2 + 2 * diag(d) / omnormxsq list(value = f, gradient = g, hessian = B) } r1 <- trust::trust(barrier_objfun, rep(0, d), 1, 100) r2 <- RcppTrust::trust(barrier_objfun, rep(0, d), 1, 100) # same solution, different number of steps to get there (see above) c(trust_iterations = r1$iterations, RcppTrust_iterations = r2$iterations) max(abs(r1$argument - r2$argument)) mb_large <- microbenchmark( trust = trust::trust(barrier_objfun, rep(0, d), 1, 100), RcppTrust = RcppTrust::trust(barrier_objfun, rep(0, d), 1, 100), times = 30 ) print(mb_large) ## ----------------------------------------------------------------------------- cpp_code <- ' // [[Rcpp::depends(RcppTrust)]] #include extern "C" { #define iniRcppTrustPtrs _vignette_iniRcppTrustPtrs #include iniRcppTrust } // A thread-safe C objective function: Rosenbrock again, this time // filling value/gradient/hessian directly instead of returning a list. extern "C" int rosenbrock_c(int n, const double *par, double *value, double *gradient, double *hessian, void *ud) { double x1 = par[0], x2 = par[1]; double t = x2 - x1 * x1; *value = 100.0 * t * t + (1.0 - x1) * (1.0 - x1); gradient[0] = -400.0 * x1 * t - 2.0 * (1.0 - x1); gradient[1] = 200.0 * t; hessian[0] = -400.0 * x2 + 1200.0 * x1 * x1 + 2.0; hessian[1] = hessian[2] = -400.0 * x1; hessian[3] = 200.0; return 0; } // [[Rcpp::export]] Rcpp::List fit_rosenbrock(SEXP ptrTable, Rcpp::NumericVector parinit) { // normally done once, in .onLoad() -- see above _vignette_iniRcppTrustPtrs(ptrTable); trust_options_t opts = trust_options_default(1.0, 5.0); trust_result_t res; trust_solve_c_ptr(parinit.size(), parinit.begin(), rosenbrock_c, nullptr, &opts, &res); Rcpp::List out = Rcpp::List::create( Rcpp::_["argument"] = Rcpp::NumericVector(res.argument, res.argument + res.n), Rcpp::_["value"] = res.value, Rcpp::_["converged"] = res.converged != 0, Rcpp::_["iterations"] = res.iterations); trust_result_free_ptr(&res); return out; } ' Rcpp::sourceCpp(code = cpp_code) fit_rosenbrock(RcppTrust:::.RcppTrustPtr(), c(3, 1))