params <- list(family = "lapis", preset = "homage") ## ----setup-opts, include = FALSE---------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "#>", message = FALSE, warning = FALSE, fig.width = 7, fig.height = 4.1, fig.align = "center", out.width = "92%", dpi = 100 ) ## ----albers-classes, echo=FALSE, results='asis'------------------------------- cat(sprintf( paste0( '' ), params$family, params$preset )) ## ----helpers, include = FALSE------------------------------------------------- # Shared plotting helper. Kept out of the reader's view: the reader sees # the API call and the picture, never the plotting boilerplate. ec_blue <- "#2166ac"; ec_red <- "#b2182b"; ec_tol <- "#ef8a62" # Per-pair backward error as a stem/dot plot, against the tolerance line. # Converged pairs are blue, failed pairs red. plot_backward_error <- function(cert, main = NULL, tol = cert$tolerance, ylim = NULL) { be <- pmax(cert$backward_error, .Machine$double.eps) k <- length(be) col_pt <- ifelse(cert$converged, ec_blue, ec_red) if (is.null(ylim)) { rng <- range(c(be, tol)) ylim <- c(rng[1] / 6, rng[2] * 6) } op <- par(mar = c(4, 4.6, if (is.null(main)) 1 else 2.4, 1)); on.exit(par(op)) plot(seq_len(k), be, log = "y", type = "n", xlim = c(0.5, k + 0.5), ylim = ylim, xaxt = "n", bty = "n", main = main, xlab = "returned pair", ylab = "backward error (log scale)") axis(1, at = seq_len(k)) segments(seq_len(k), ylim[1], seq_len(k), be, col = col_pt, lwd = 2) points(seq_len(k), be, pch = 19, cex = 1.3, col = col_pt) abline(h = tol, col = ec_tol, lty = 2, lwd = 2) text(k + 0.45, tol, sprintf("tol = %.0e", tol), col = ec_tol, pos = 3, cex = 0.85, xpd = NA) } ## ----setup-------------------------------------------------------------------- library(eigencore) ## ----anatomy------------------------------------------------------------------ set.seed(1) n <- 200 A <- crossprod(matrix(rnorm(n * n), n, n)) / n + diag(n) fit <- eig_partial(A, k = 5, target = largest()) cert <- fit$certificate cert ## ----anatomy-bars, echo = FALSE, fig.cap = "Per-pair backward error for the five returned eigenpairs. The `max_backward_error` field is simply the height of the tallest stem; `passed` is TRUE because every stem falls below the tolerance line.", fig.alt = "Stem plot of backward error for five eigenpairs on a log scale, all falling well below the dashed tolerance line."---- plot_backward_error(cert) ## ----pass-vs-fail-fits-------------------------------------------------------- # Largest eigenvalues are well separated -> easy, converges fast. fit_pass <- eig_partial(A, k = 10, target = largest()) # Smallest eigenvalues are densely clustered near 1 -> a tight maxit # budget leaves them short of tolerance. fit_fail <- eig_partial(A, k = 10, target = smallest(), maxit = 15) c(largest_passed = fit_pass$certificate$passed, smallest_passed = fit_fail$certificate$passed) ## ----pass-vs-fail, echo = FALSE, fig.width = 9, fig.height = 4, fig.cap = "Same matrix, same k, two targets. Left: the ten largest eigenpairs all clear the tolerance (blue, passed). Right: the ten smallest stall above it under a tight iteration budget (red, failed).", fig.alt = "Two side-by-side stem plots of per-pair backward error. Left panel shows ten blue points below the tolerance line; right panel shows ten red points above the tolerance line."---- op <- par(mfrow = c(1, 2)) ylim <- c(1e-16, 1e-1) plot_backward_error(fit_pass$certificate, main = "largest(): passed", ylim = ylim) plot_backward_error(fit_fail$certificate, main = "smallest(), maxit = 15: failed", ylim = ylim) par(op) ## ----clean-------------------------------------------------------------------- fit_pass$certificate$passed fit_pass$certificate$norm_bound_type fit_pass$certificate$scale_is_estimate ## ----failed------------------------------------------------------------------- fit_fail$certificate$passed fit_fail$certificate$failed_indices fit_fail$certificate$max_backward_error ## ----convergence-fits--------------------------------------------------------- fit_ok <- eig_partial(A, k = 10, target = smallest(), maxit = 40) fit_ok$certificate$passed ## ----convergence, echo = FALSE, fig.cap = "Worst backward error per restart for the ten smallest eigenpairs. A tight budget (red) stalls above the tolerance; a generous one (blue) drives the error under the line and the certificate passes.", fig.alt = "Line plot on a log scale of backward error versus restart number. The red maxit-15 curve plateaus above the tolerance line; the blue maxit-40 curve descends below it."---- h_fail <- diagnostics(fit_fail)$convergence_history h_ok <- diagnostics(fit_ok)$convergence_history tol <- fit_fail$certificate$tolerance yl <- range(c(h_fail$max_backward_error, h_ok$max_backward_error, tol)) op <- par(mar = c(4, 4.6, 1, 1)) tryCatch({ plot(h_fail$restart, h_fail$max_backward_error, log = "y", type = "l", lwd = 2, col = ec_red, bty = "n", ylim = yl, xlab = "restart", ylab = "max backward error (log scale)") lines(h_ok$restart, h_ok$max_backward_error, lwd = 2, col = ec_blue) abline(h = tol, col = ec_tol, lty = 2, lwd = 2) legend("right", c("maxit = 15 (failed)", "maxit = 40 (passed)", "tolerance"), col = c(ec_red, ec_blue, ec_tol), lwd = 2, lty = c(1, 1, 2), bty = "n", cex = 0.9, inset = 0.02) }, finally = par(op)) ## ----withheld----------------------------------------------------------------- set.seed(2) op <- linear_operator( dim = c(n, n), apply = function(X, alpha = 1, beta = 0, Y = NULL) { Z <- alpha * (A %*% X) if (is.null(Y) || beta == 0) Z else Z + beta * Y }, apply_adjoint = function(X, alpha = 1, beta = 0, Y = NULL) { Z <- alpha * (A %*% X) if (is.null(Y) || beta == 0) Z else Z + beta * Y }, structure = hermitian(), name = "matrix-free Hermitian wrapper" ) fit_mf <- eig_partial(op, k = 5, target = largest()) fit_mf$certificate$norm_bound_type fit_mf$certificate$scale_is_estimate fit_mf$certificate$passed fit_mf$certificate$notes ## ----generalized-------------------------------------------------------------- set.seed(4) B <- diag(seq(1, 5, length.out = n)) fit_gen <- eig_partial(A, k = 5, target = largest(), B = B, method = lobpcg(maxit = 200)) fit_gen$certificate$norm_bound_type fit_gen$certificate$max_orthogonality_loss fit_gen$certificate$passed ## ----rspectra----------------------------------------------------------------- res <- eigs_sym(A, k = 5, which = "LA") names(res) res$certificate