Nothing
#!/usr/bin/env Rscript
source("inst/benchmarks/_helpers.R")
args <- benchmark_args()
iterations <- if (!is.na(args$iterations)) args$iterations else if (args$quick) 1L else 5L
tol <- 1e-8
failure_rows <- function(case, target, methods, requested, message) {
data.frame(
case = case,
kind = "generalized_eigen",
target = target,
method = methods,
median = NA_real_,
min = NA_real_,
mem_alloc = NA_real_,
max_residual = NA_real_,
max_backward_error = NA_real_,
orthogonality_loss = NA_real_,
certificate_passed = FALSE,
certificate_type = NA_character_,
norm_bound_type = NA_character_,
scale_is_estimate = NA,
nconv = 0L,
requested = requested,
iterations = NA_integer_,
matvecs = NA_integer_,
restarts = NA_integer_,
ortho_passes = NA_integer_,
locking_events = NA_integer_,
block_size = NA_integer_,
native = NA,
native_kernels = NA,
generalized = NA,
orthogonalization_native = NA,
orthogonalization_methods = NA_character_,
q_rank_final = NA_integer_,
constrained = NA,
constraints_rank = NA_integer_,
preconditioner_kind = NA_character_,
preconditioner_native = NA,
preconditioner_calls = NA_integer_,
metric_solve_kind = NA_character_,
metric_solve_label = NA_character_,
metric_solve_native = NA,
native_metric_solve = NA,
metric_factorization = NA_character_,
metric_solves = NA_integer_,
seed = NA_integer_,
pkg_version = as.character(utils::packageVersion("eigencore")),
solver_label = NA_character_,
error = message,
stringsAsFactors = FALSE
)
}
with_case <- function(case, target, methods, requested, expr) {
tryCatch({
rows <- expr
rows$case <- case
rows$kind <- "generalized_eigen"
rows$target <- target
rows$requested <- requested
rows$error <- ""
rows
}, error = function(e) {
failure_rows(case, target, methods, requested, conditionMessage(e))
})
}
generalized_lobpcg_tridiagonal_shift <- function(A, target) {
kind <- if (inherits(target, "eigencore_target")) target$kind else "largest"
if (!identical(kind, "largest")) {
return(1e-3)
}
n <- nrow(A)
if (!is.finite(n) || n < 1L) {
return(1e-3)
}
max(1e-3, as.numeric(n))
}
benchmark_generalized_lobpcg_case <- function(A, B, k, target = smallest(),
methods = c("eigencore", "base"),
iterations = 3L, tol = 1e-8,
seed = 1L, maxit = 200L,
constraints = NULL,
A_dense = NULL, B_dense = NULL) {
methods <- intersect(
methods,
c(
"eigencore_auto",
"eigencore",
"eigencore_lanczos_native",
"eigencore_lanczos_block_native",
"eigencore_lanczos_reference",
"eigencore_shifted_diagonal",
"eigencore_shifted_tridiagonal",
"eigencore_constrained",
"base"
)
)
A_cert <- A_dense %||% as.matrix(A)
B_cert <- B_dense %||% as.matrix(B)
rows <- lapply(methods, function(method) {
timed <- run_timed({
if (identical(method, "eigencore_auto")) {
eig_partial(
A,
B = B,
k = k,
target = target,
tol = tol,
allow_dense_fallback = "auto"
)
} else if (identical(method, "eigencore")) {
eig_partial(
A,
B = B,
k = k,
target = target,
method = lobpcg(maxit = maxit),
tol = tol,
allow_dense_fallback = "never"
)
} else if (identical(method, "eigencore_lanczos_block_native")) {
eig_partial(
A,
B = B,
k = k,
target = target,
method = lanczos(max_subspace = max(maxit, k), block = 2L),
tol = tol,
allow_dense_fallback = "never"
)
} else if (identical(method, "eigencore_lanczos_native") ||
identical(method, "eigencore_lanczos_reference")) {
eig_partial(
A,
B = B,
k = k,
target = target,
method = lanczos(max_subspace = max(maxit, k)),
tol = tol,
allow_dense_fallback = "never"
)
} else if (identical(method, "eigencore_shifted_diagonal")) {
preconditioner <- shifted_diagonal_preconditioner(Matrix::diag(A), shift = 1e-3)
eig_partial(
A,
B = B,
k = k,
target = target,
method = lobpcg(maxit = maxit, preconditioner = preconditioner),
tol = tol,
allow_dense_fallback = "never"
)
} else if (identical(method, "eigencore_shifted_tridiagonal")) {
preconditioner <- shifted_tridiagonal_preconditioner(
A,
shift = generalized_lobpcg_tridiagonal_shift(A, target)
)
eig_partial(
A,
B = B,
k = k,
target = target,
method = lobpcg(maxit = maxit, preconditioner = preconditioner),
tol = tol,
allow_dense_fallback = "never"
)
} else if (identical(method, "eigencore_constrained")) {
if (is.null(constraints)) {
constraints <- matrix(c(1, rep(0, nrow(A) - 1L)), ncol = 1L)
}
eig_partial(
A,
B = B,
k = k,
target = target,
method = lobpcg(maxit = maxit, constraints = constraints),
tol = tol,
allow_dense_fallback = "never"
)
} else {
eig <- eigencore:::dense_generalized_spd_eigen(A_cert, B_cert)
idx <- eigencore:::order_indices(eig$values, target)
idx <- idx[seq_len(k)]
list(values = eig$values[idx], vectors = eig$vectors[, idx, drop = FALSE])
}
}, iterations = iterations, seed = seed)
cert <- eigencore:::certify_eigen(
A_cert,
eigencore:::method_values(timed$value, kind = "eigen"),
timed$value$vectors,
B = B_cert,
tol = tol
)
data.frame(
method = method,
median = timed$median,
min = timed$min,
mem_alloc = timed$mem_alloc,
max_residual = cert$max_residual,
max_backward_error = cert$max_backward_error,
orthogonality_loss = cert$max_orthogonality_loss,
certificate_passed = cert$passed,
certificate_type = cert$certificate_type,
norm_bound_type = cert$norm_bound_type,
scale_is_estimate = cert$scale_is_estimate,
nconv = sum(cert$converged),
iterations = result_iterations(timed$value),
matvecs = result_matvecs(timed$value),
restarts = result_restarts(timed$value),
ortho_passes = result_ortho_passes(timed$value),
locking_events = result_locking_events(timed$value),
block_size = result_block_size(timed$value),
native = result_restart_logical(timed$value, "native"),
native_kernels = result_restart_logical(timed$value, "native_kernels"),
generalized = result_restart_logical(timed$value, "generalized"),
orthogonalization_native = result_restart_logical(timed$value, "orthogonalization_native"),
orthogonalization_methods = result_restart_character(timed$value, "orthogonalization_methods"),
q_rank_final = result_restart_integer(timed$value, "q_rank_final"),
constrained = result_restart_logical(timed$value, "constrained"),
constraints_rank = result_restart_integer(timed$value, "constraints_rank"),
preconditioner_kind = result_preconditioner_field(timed$value, "kind"),
preconditioner_native = result_preconditioner_field(timed$value, "native"),
preconditioner_calls = result_preconditioner_calls(timed$value),
metric_solve_kind = {
field <- result_restart_character(timed$value, "metric_solve_kind")
if (!is.na(field)) {
field
} else {
restart <- timed$value$restart %||% list()
metric_solve <- restart$metric_solve %||% NA_character_
if (is.list(metric_solve)) {
metric_solve$kind %||% NA_character_
} else {
NA_character_
}
}
},
metric_solve_label = {
restart <- timed$value$restart %||% list()
metric_solve <- restart$metric_solve %||% NA_character_
if (is.list(metric_solve)) {
metric_solve$label %||% NA_character_
} else {
metric_solve
}
},
metric_solve_native = result_restart_logical(timed$value, "metric_solve_native"),
native_metric_solve = result_restart_logical(timed$value, "native_metric_solve"),
metric_factorization = result_restart_character(timed$value, "metric_factorization"),
metric_solves = result_restart_integer(timed$value, "metric_solves"),
seed = seed,
pkg_version = as.character(utils::packageVersion("eigencore")),
solver_label = timed$value$method %||% NA_character_,
stringsAsFactors = FALSE
)
})
do.call(rbind, rows)
}
generalized_lobpcg_native_contract <- function(rows) {
internal <- rows[rows$method %in% c(
"eigencore",
"eigencore_lanczos_reference",
"eigencore_shifted_diagonal",
"eigencore_shifted_tridiagonal",
"eigencore_constrained"
), , drop = FALSE]
if ("solver_label" %in% names(internal)) {
native_label <- eigencore:::native_generalized_lobpcg_label()
internal <- internal[
internal$solver_label == native_label,
,
drop = FALSE
]
}
if (!nrow(internal)) {
return(data.frame())
}
out <- lapply(seq_len(nrow(internal)), function(i) {
row <- internal[i, , drop = FALSE]
certified <- isTRUE(row$certificate_passed) && row$nconv >= row$requested
native_gate <- certified &&
isTRUE(row$native) &&
isTRUE(row$native_kernels) &&
isTRUE(row$generalized) &&
isTRUE(row$orthogonalization_native)
preconditioner_gate <- if (identical(row$method, "eigencore_shifted_diagonal")) {
identical(row$preconditioner_kind, "shifted_diagonal") &&
isTRUE(row$preconditioner_native) &&
isTRUE(row$preconditioner_calls > 0L)
} else if (identical(row$method, "eigencore_shifted_tridiagonal")) {
identical(row$preconditioner_kind, "shifted_tridiagonal") &&
isTRUE(row$preconditioner_native) &&
isTRUE(row$preconditioner_calls > 0L)
} else {
TRUE
}
constraint_gate <- if (identical(row$method, "eigencore_constrained")) {
isTRUE(row$constrained) && isTRUE(row$constraints_rank > 0L)
} else {
TRUE
}
data.frame(
case = row$case,
method = row$method,
requested = row$requested,
nconv = row$nconv,
native_gate = native_gate,
preconditioner_gate = preconditioner_gate,
constraint_gate = constraint_gate,
passed = native_gate && preconditioner_gate && constraint_gate,
stringsAsFactors = FALSE
)
})
out <- do.call(rbind, out)
row.names(out) <- NULL
out
}
generalized_lanczos_reference_contract <- function(rows) {
internal <- rows[rows$method == "eigencore_lanczos_reference", , drop = FALSE]
if (!nrow(internal)) {
return(data.frame())
}
out <- lapply(seq_len(nrow(internal)), function(i) {
row <- internal[i, , drop = FALSE]
certificate_gate <- isTRUE(row$certificate_passed) && row$nconv >= row$requested
label_gate <- identical(row$solver_label, eigencore:::generalized_lanczos_label())
generalized_gate <- isTRUE(row$generalized)
native_metric_expected <- grepl(
"native_metric|native.*metric",
row$case,
ignore.case = TRUE
)
reference_gate <- !isTRUE(row$native) &&
!isTRUE(row$native_kernels) &&
isTRUE(row$metric_solves > 0L) &&
isTRUE(nzchar(row$metric_solve_label))
metric_boundary_gate <- if (isTRUE(native_metric_expected)) {
isTRUE(row$metric_solve_native) &&
identical(row$metric_solve_kind, "native_sparse_tridiagonal_thomas") &&
identical(row$metric_factorization, "tridiagonal_thomas")
} else {
!isTRUE(row$metric_solve_native) &&
identical(row$metric_solve_kind, "sparse_cholesky") &&
identical(row$metric_factorization, "Matrix::Cholesky")
}
orthogonality_gate <- certificate_gate &&
isTRUE(row$orthogonality_loss <= sqrt(.Machine$double.eps) * 10)
data.frame(
case = row$case,
method = row$method,
requested = row$requested,
nconv = row$nconv,
label_gate = label_gate,
generalized_gate = generalized_gate,
reference_gate = reference_gate,
metric_boundary_gate = metric_boundary_gate,
orthogonality_gate = orthogonality_gate,
certificate_gate = certificate_gate,
passed = label_gate && generalized_gate && reference_gate && metric_boundary_gate &&
orthogonality_gate && certificate_gate,
stringsAsFactors = FALSE
)
})
out <- do.call(rbind, out)
row.names(out) <- NULL
out
}
generalized_lanczos_native_contract <- function(rows) {
internal <- rows[rows$method == "eigencore_lanczos_native", , drop = FALSE]
if (!nrow(internal)) {
return(data.frame())
}
out <- lapply(seq_len(nrow(internal)), function(i) {
row <- internal[i, , drop = FALSE]
certificate_gate <- isTRUE(row$certificate_passed) && row$nconv >= row$requested
label_gate <- identical(row$solver_label, eigencore:::native_generalized_lanczos_label())
native_gate <- certificate_gate &&
isTRUE(row$native) &&
isTRUE(row$native_kernels) &&
isTRUE(row$generalized)
transform_gate <- isTRUE(nzchar(row$metric_solve_label)) &&
grepl("similarity transform", row$metric_solve_label, fixed = TRUE)
orthogonality_gate <- certificate_gate &&
isTRUE(row$orthogonality_loss <= sqrt(.Machine$double.eps) * 10)
data.frame(
case = row$case,
method = row$method,
requested = row$requested,
nconv = row$nconv,
label_gate = label_gate,
native_gate = native_gate,
transform_gate = transform_gate,
orthogonality_gate = orthogonality_gate,
certificate_gate = certificate_gate,
passed = label_gate && native_gate && transform_gate &&
orthogonality_gate && certificate_gate,
stringsAsFactors = FALSE
)
})
out <- do.call(rbind, out)
row.names(out) <- NULL
out
}
generalized_lanczos_block_native_contract <- function(rows) {
internal <- rows[rows$method == "eigencore_lanczos_block_native", , drop = FALSE]
if (!nrow(internal)) {
return(data.frame())
}
out <- lapply(seq_len(nrow(internal)), function(i) {
row <- internal[i, , drop = FALSE]
certificate_gate <- isTRUE(row$certificate_passed) && row$nconv >= row$requested
label_gate <- identical(row$solver_label, eigencore:::native_generalized_lanczos_label())
block_gate <- isTRUE(row$block_size > 1L)
native_gate <- certificate_gate &&
isTRUE(row$native) &&
isTRUE(row$native_kernels) &&
isTRUE(row$generalized)
transform_gate <- isTRUE(nzchar(row$metric_solve_label)) &&
grepl("similarity transform", row$metric_solve_label, fixed = TRUE)
orthogonality_gate <- certificate_gate &&
isTRUE(row$orthogonality_loss <= sqrt(.Machine$double.eps) * 10)
data.frame(
case = row$case,
method = row$method,
requested = row$requested,
nconv = row$nconv,
block_size = row$block_size,
label_gate = label_gate,
block_gate = block_gate,
native_gate = native_gate,
transform_gate = transform_gate,
orthogonality_gate = orthogonality_gate,
certificate_gate = certificate_gate,
passed = label_gate && block_gate && native_gate && transform_gate &&
orthogonality_gate && certificate_gate,
stringsAsFactors = FALSE
)
})
out <- do.call(rbind, out)
row.names(out) <- NULL
out
}
generalized_lobpcg_adversarial_b_specs <- function() {
csc_n <- 10L
csc_A <- Matrix::bandSparse(
csc_n,
k = c(-1, 0, 1),
diagonals = list(rep(-1, csc_n - 1L), rep(2.5, csc_n), rep(-1, csc_n - 1L))
)
csc_B <- methods::as(Matrix::bandSparse(
csc_n,
k = c(-1, 0, 1),
diagonals = list(
rep(-0.05, csc_n - 1L),
seq(1.2, 2, length.out = csc_n),
rep(-0.05, csc_n - 1L)
)
), "dgCMatrix")
mf_n <- 9L
mf_bdiag <- seq(0.75, 2.5, length.out = mf_n)
mf_B_dense <- diag(mf_bdiag)
mf_B <- linear_operator(
dim = c(mf_n, mf_n),
apply = function(X, alpha = 1, beta = 0, Y = NULL) {
out <- alpha * (mf_bdiag * X)
if (!is.null(Y) && beta != 0) {
out <- out + beta * Y
}
out
},
apply_adjoint = function(X, alpha = 1, beta = 0, Y = NULL) {
out <- alpha * (mf_bdiag * X)
if (!is.null(Y) && beta != 0) {
out <- out + beta * Y
}
out
},
structure = hermitian(),
metadata = list(
frobenius_norm = sqrt(sum(mf_bdiag^2)),
positive_definite = TRUE
)
)
cases <- list(
list(
name = "ill_conditioned_diagonal_b",
A = Matrix::Diagonal(x = c(1, 3, 7, 12, 20, 33, 50, 80)),
B = Matrix::Diagonal(x = 10^seq(-3, 3, length.out = 8L)),
B_dense = diag(10^seq(-3, 3, length.out = 8L)),
expected_orthogonalization = "native_diagonal_b_mgs2"
),
list(
name = "sparse_csc_b",
A = csc_A,
B = csc_B,
B_dense = as.matrix(csc_B),
expected_orthogonalization = "native_csc_b_mgs2"
),
list(
name = "explicit_spd_matrix_free_b",
A = Matrix::Diagonal(x = seq(2, 18, by = 2)),
B = mf_B,
B_dense = mf_B_dense,
expected_orthogonalization = "native_matrix_free_b_mgs2"
)
)
targets <- list(smallest = smallest(), largest = largest())
specs <- list()
for (case in cases) {
for (target_name in names(targets)) {
specs[[length(specs) + 1L]] <- list(
case = paste("adversarial", case$name, target_name, sep = "_"),
n = nrow(case$A),
k = 2L,
target = targets[[target_name]],
methods = c("eigencore", "base"),
subject = "eigencore",
A = case$A,
B = case$B,
B_dense = case$B_dense,
maxit = 220L,
adversarial_b = TRUE,
performance_gate = FALSE,
expected_orthogonalization = case$expected_orthogonalization
)
}
}
specs
}
generalized_lobpcg_adversarial_b_contract <- function(rows, case_specs) {
specs <- Filter(function(spec) isTRUE(spec$adversarial_b), case_specs)
if (!length(specs)) {
return(data.frame())
}
out <- lapply(specs, function(spec) {
row <- rows[
rows$case == spec$case & rows$method == "eigencore",
,
drop = FALSE
]
if (!nrow(row)) {
return(data.frame(
case = spec$case,
target = eigencore:::target_label(spec$target),
requested = spec$k,
nconv = 0L,
native_gate = FALSE,
orthogonalization_gate = FALSE,
certificate_gate = FALSE,
passed = FALSE,
stringsAsFactors = FALSE
))
}
row <- row[1L, , drop = FALSE]
certificate_gate <- isTRUE(row$certificate_passed) && row$nconv >= spec$k
native_gate <- certificate_gate &&
isTRUE(row$native) &&
isTRUE(row$native_kernels) &&
isTRUE(row$generalized) &&
isTRUE(row$orthogonalization_native)
orthogonalization_gate <- identical(
row$orthogonalization_methods,
spec$expected_orthogonalization
)
data.frame(
case = spec$case,
target = row$target,
requested = spec$k,
nconv = row$nconv,
native_gate = native_gate,
orthogonalization_gate = orthogonalization_gate,
certificate_gate = certificate_gate,
passed = native_gate && orthogonalization_gate && certificate_gate,
stringsAsFactors = FALSE
)
})
out <- do.call(rbind, out)
row.names(out) <- NULL
out
}
case_specs <- if (args$quick) {
list(
list(
case = "sparse_generalized_path_smallest",
n = 80L, k = 3L, target = smallest(), sparse = TRUE,
methods = c(
"eigencore",
"eigencore_shifted_diagonal",
"eigencore_shifted_tridiagonal",
"base"
),
subject = "eigencore"
),
list(
case = "sparse_generalized_path_largest",
n = 80L, k = 3L, target = largest(), sparse = TRUE,
methods = c(
"eigencore",
"eigencore_shifted_diagonal",
"eigencore_shifted_tridiagonal",
"base"
),
subject = "eigencore"
),
list(
case = "diagonal_generalized_constrained_largest",
n = 8L, k = 2L, target = largest(), sparse = FALSE,
methods = c("eigencore_constrained", "base"),
subject = "eigencore_constrained",
A = Matrix::Diagonal(x = c(0, 1, 4, 9, 16, 25, 36, 49)),
B = Matrix::Diagonal(x = c(1, 2, 3, 4, 5, 6, 7, 8)),
constraints = matrix(c(1, rep(0, 7L)), ncol = 1L)
),
list(
case = "diagonal_generalized_lanczos_native_smallest",
n = 8L, k = 2L, target = smallest(), sparse = FALSE,
methods = c("eigencore_lanczos_native", "eigencore", "base"),
subject = "eigencore_lanczos_native",
A = Matrix::Diagonal(x = c(1, 4, 9, 16, 25, 36, 49, 64)),
B = Matrix::Diagonal(x = c(1, 2, 3, 4, 5, 6, 7, 8)),
performance_gate = FALSE
),
list(
case = "diagonal_generalized_block_lanczos_native_smallest",
n = 8L, k = 2L, target = smallest(), sparse = FALSE,
methods = c("eigencore_lanczos_block_native", "base"),
subject = "eigencore_lanczos_block_native",
A = Matrix::Diagonal(x = c(1, 4, 9, 16, 25, 36, 49, 64)),
B = Matrix::Diagonal(x = c(1, 2, 3, 4, 5, 6, 7, 8)),
performance_gate = FALSE
),
list(
case = "dense_generalized_lanczos_native_largest",
n = 8L, k = 2L, target = largest(), sparse = FALSE,
methods = c("eigencore_lanczos_native", "base"),
subject = "eigencore_lanczos_native",
A = diag(c(2, 5, 9, 14, 20, 27, 35, 44)),
B = {
B <- diag(seq(1.2, 2.1, length.out = 8L))
B + 0.01 * tcrossprod(seq_len(8L))
},
performance_gate = FALSE
),
list(
case = "sparse_tridiagonal_b_generalized_lanczos_native_metric_smallest",
n = 10L, k = 2L, target = smallest(), sparse = TRUE,
methods = c("eigencore_lanczos_reference", "eigencore", "base"),
subject = "eigencore_lanczos_reference",
A = Matrix::bandSparse(
10L,
k = c(-1, 0, 1),
diagonals = list(rep(-1, 9L), rep(2.5, 10L), rep(-1, 9L))
),
B = methods::as(Matrix::bandSparse(
10L,
k = c(-1, 0, 1),
diagonals = list(
rep(-0.05, 9L),
seq(1.2, 2, length.out = 10L),
rep(-0.05, 9L)
)
), "dgCMatrix"),
performance_gate = FALSE
),
list(
case = "sparse_csc_generalized_lanczos_ref_cholesky_smallest",
n = 10L, k = 2L, target = smallest(), sparse = TRUE,
methods = c("eigencore_lanczos_reference", "eigencore", "base"),
subject = "eigencore_lanczos_reference",
A = Matrix::bandSparse(
10L,
k = c(-1, 0, 1),
diagonals = list(rep(-1, 9L), rep(2.5, 10L), rep(-1, 9L))
),
B = methods::as(
Matrix::Diagonal(x = seq(1.5, 2.4, length.out = 10L)) +
Matrix::bandSparse(
10L,
k = c(-2, 2),
diagonals = list(rep(0.04, 8L), rep(0.04, 8L))
),
"dgCMatrix"
),
performance_gate = FALSE
),
list(
case = "symmetric_csc_generalized_lobpcg_smallest_magnitude",
n = 14L, k = 2L, target = smallest_magnitude(), sparse = TRUE,
methods = c("eigencore", "base"),
subject = "eigencore",
A = methods::as(Matrix::forceSymmetric(Matrix::bandSparse(
14L,
k = c(0, 1),
diagonals = list(rep(2.5, 14L), rep(-1, 13L))
)), "CsparseMatrix"),
B = methods::as(Matrix::forceSymmetric(Matrix::bandSparse(
14L,
k = c(0, 1),
diagonals = list(seq(1.5, 2.4, length.out = 14L), rep(0.03, 13L))
)), "CsparseMatrix"),
performance_gate = FALSE
)
)
} else {
list(
list(
case = "sparse_generalized_path_smallest",
n = 1000L, k = 10L, target = smallest(), sparse = TRUE,
methods = c(
"eigencore_shifted_tridiagonal",
"base"
),
subject = "eigencore_shifted_tridiagonal"
),
list(
case = "sparse_generalized_path_largest",
n = 1000L, k = 10L, target = largest(), sparse = TRUE,
methods = c(
"eigencore_shifted_tridiagonal",
"base"
),
subject = "eigencore_shifted_tridiagonal",
maxit = 300L
),
list(
case = "dense_generalized_partial_smallest",
n = 180L, k = 8L, target = smallest(), sparse = FALSE,
methods = c("eigencore_auto", "base"),
subject = "eigencore_auto",
performance_gate = FALSE
),
list(
case = "dense_generalized_partial_largest",
n = 180L, k = 8L, target = largest(), sparse = FALSE,
methods = c("eigencore_auto", "base"),
subject = "eigencore_auto",
performance_gate = FALSE
),
list(
case = "diagonal_generalized_constrained_largest",
n = 80L, k = 8L, target = largest(), sparse = FALSE,
methods = c("eigencore_constrained", "base"),
subject = "eigencore_constrained",
A = Matrix::Diagonal(x = c(0, seq(1, 79)^2)),
B = Matrix::Diagonal(x = seq(1, 80)),
constraints = matrix(c(1, rep(0, 79L)), ncol = 1L),
performance_gate = FALSE
),
list(
case = "diagonal_generalized_lanczos_native_smallest",
n = 80L, k = 8L, target = smallest(), sparse = FALSE,
methods = c("eigencore_lanczos_native", "eigencore", "base"),
subject = "eigencore_lanczos_native",
A = Matrix::Diagonal(x = seq_len(80L)^2),
B = Matrix::Diagonal(x = seq_len(80L)),
performance_gate = FALSE
),
list(
case = "diagonal_generalized_block_lanczos_native_smallest",
n = 80L, k = 8L, target = smallest(), sparse = FALSE,
methods = c("eigencore_lanczos_block_native", "base"),
subject = "eigencore_lanczos_block_native",
A = Matrix::Diagonal(x = seq_len(80L)^2),
B = Matrix::Diagonal(x = seq_len(80L)),
performance_gate = FALSE
),
list(
case = "dense_generalized_lanczos_native_largest",
n = 80L, k = 8L, target = largest(), sparse = FALSE,
methods = c("eigencore_lanczos_native", "base"),
subject = "eigencore_lanczos_native",
A = diag(seq_len(80L)^2),
B = {
B <- diag(seq(1.2, 2.1, length.out = 80L))
B + 1e-4 * tcrossprod(seq_len(80L))
},
performance_gate = FALSE
),
list(
case = "sparse_tridiagonal_b_generalized_lanczos_native_metric_smallest",
n = 80L, k = 8L, target = smallest(), sparse = TRUE,
methods = c("eigencore_lanczos_reference", "eigencore", "base"),
subject = "eigencore_lanczos_reference",
A = Matrix::bandSparse(
80L,
k = c(-1, 0, 1),
diagonals = list(rep(-1, 79L), rep(2.5, 80L), rep(-1, 79L))
),
B = methods::as(Matrix::bandSparse(
80L,
k = c(-1, 0, 1),
diagonals = list(
rep(-0.05, 79L),
seq(1.2, 2, length.out = 80L),
rep(-0.05, 79L)
)
), "dgCMatrix"),
performance_gate = FALSE
),
list(
case = "sparse_csc_generalized_lanczos_ref_cholesky_smallest",
n = 80L, k = 8L, target = smallest(), sparse = TRUE,
methods = c("eigencore_lanczos_reference", "eigencore", "base"),
subject = "eigencore_lanczos_reference",
A = Matrix::bandSparse(
80L,
k = c(-1, 0, 1),
diagonals = list(rep(-1, 79L), rep(2.5, 80L), rep(-1, 79L))
),
B = methods::as(
Matrix::Diagonal(x = seq(1.5, 2.4, length.out = 80L)) +
Matrix::bandSparse(
80L,
k = c(-2, 2),
diagonals = list(rep(0.04, 78L), rep(0.04, 78L))
),
"dgCMatrix"
),
performance_gate = FALSE
),
list(
case = "symmetric_csc_generalized_lobpcg_smallest_magnitude",
n = 80L, k = 8L, target = smallest_magnitude(), sparse = TRUE,
methods = c("eigencore", "base"),
subject = "eigencore",
A = methods::as(Matrix::forceSymmetric(Matrix::bandSparse(
80L,
k = c(0, 1),
diagonals = list(rep(2.5, 80L), rep(-1, 79L))
)), "CsparseMatrix"),
B = methods::as(Matrix::forceSymmetric(Matrix::bandSparse(
80L,
k = c(0, 1),
diagonals = list(seq(1.5, 2.4, length.out = 80L), rep(0.03, 79L))
)), "CsparseMatrix"),
performance_gate = FALSE
)
)
}
case_specs <- c(case_specs, generalized_lobpcg_adversarial_b_specs())
case_specs <- filter_benchmark_cases(case_specs, args$cases)
rows <- lapply(seq_along(case_specs), function(i) {
spec <- case_specs[[i]]
message_benchmark_case("bench-generalized-lobpcg", spec)
pair <- if (!is.null(spec$A) && !is.null(spec$B)) {
list(A = spec$A, B = spec$B)
} else {
generalized_spd_pair(
spec$n,
rank = min(12L, spec$n),
sparse = spec$sparse,
seed = 12000L + spec$n + i
)
}
methods <- spec$methods %||% c("eigencore", "base")
if (!is.null(args$methods)) {
methods <- intersect(methods, args$methods)
if (!length(methods)) {
stop(
"--methods did not match any methods for case ",
benchmark_case_id(spec),
call. = FALSE
)
}
}
case_rows <- with_case(
spec$case,
eigencore:::target_label(spec$target),
methods,
spec$k,
benchmark_generalized_lobpcg_case(
pair$A,
pair$B,
k = spec$k,
target = spec$target,
methods = methods,
iterations = iterations,
tol = tol,
seed = 12100L + spec$n + spec$k + i,
constraints = spec$constraints %||% NULL,
maxit = spec$maxit %||% 200L,
A_dense = spec$A_dense %||% NULL,
B_dense = spec$B_dense %||% NULL
)
)
case_rows$adversarial_b <- isTRUE(spec$adversarial_b)
case_rows$expected_orthogonalization <- spec$expected_orthogonalization %||% NA_character_
case_rows
})
rows <- do.call(rbind, rows)
row.names(rows) <- NULL
case_by_name <- stats::setNames(case_specs, vapply(case_specs, `[[`, character(1), "case"))
gate_rows <- lapply(split(rows, rows$case), function(case_rows) {
requested <- unique(case_rows$requested)
spec <- case_by_name[[unique(case_rows$case)]]
subject <- args$subject %||% spec$subject %||% "eigencore"
if (!subject %in% unique(case_rows$method)) {
stop(
"--subject ", subject, " is not present for case ",
unique(case_rows$case),
call. = FALSE
)
}
internal_methods <- c(
"eigencore_auto",
"eigencore",
"eigencore_lanczos_native",
"eigencore_lanczos_block_native",
"eigencore_lanczos_reference",
"eigencore_shifted_diagonal",
"eigencore_shifted_tridiagonal",
"eigencore_constrained"
)
gate <- evaluate_reference_gate(
case_rows,
subject = subject,
references = setdiff(unique(case_rows$method), internal_methods),
requested = requested[[1L]],
speed_ratio_required = if (args$quick || isFALSE(spec$performance_gate %||% TRUE)) {
0
} else {
release_speed_gate("generalized_eigen")
},
memory_ratio_required = if (args$quick || isFALSE(spec$performance_gate %||% TRUE)) {
0
} else {
release_memory_gate("generalized_eigen")
}
)
gate$case <- unique(case_rows$case)
gate$target <- unique(case_rows$target)
gate$kind <- "generalized_eigen"
gate
})
gates <- do.call(rbind, gate_rows)
row.names(gates) <- NULL
native_contract <- generalized_lobpcg_native_contract(rows)
lanczos_contract <- generalized_lanczos_reference_contract(rows)
native_lanczos_contract <- generalized_lanczos_native_contract(rows)
block_lanczos_contract <- generalized_lanczos_block_native_contract(rows)
adversarial_contract <- generalized_lobpcg_adversarial_b_contract(rows, case_specs)
cat("Generalized SPD LOBPCG benchmark rows\n")
print(rows)
cat("\nGeneralized SPD LOBPCG gates\n")
print(gates)
cat("\nGeneralized SPD LOBPCG native contracts\n")
print(native_contract)
cat("\nGeneralized SPD B-orthogonal Lanczos reference contracts\n")
print(lanczos_contract)
cat("\nGeneralized SPD B-orthogonal Lanczos native contracts\n")
print(native_lanczos_contract)
cat("\nGeneralized SPD block B-orthogonal Lanczos native contracts\n")
print(block_lanczos_contract)
cat("\nGeneralized SPD LOBPCG adversarial B contracts\n")
print(adversarial_contract)
if (args$save) {
message("saved rows: ", save_benchmark_result(rows, "generalized-lobpcg-rows"))
message("saved gates: ", save_benchmark_result(gates, "generalized-lobpcg-gates"))
message("saved native contracts: ", save_benchmark_result(native_contract, "generalized-lobpcg-native-contracts"))
message("saved generalized Lanczos contracts: ", save_benchmark_result(lanczos_contract, "generalized-lanczos-reference-contracts"))
message("saved native generalized Lanczos contracts: ", save_benchmark_result(native_lanczos_contract, "generalized-lanczos-native-contracts"))
message("saved block native generalized Lanczos contracts: ", save_benchmark_result(block_lanczos_contract, "generalized-lanczos-block-native-contracts"))
message("saved adversarial B contracts: ", save_benchmark_result(adversarial_contract, "generalized-lobpcg-adversarial-b-contracts"))
}
if (args$strict && (
!all(gates$passed) ||
!all(native_contract$passed) ||
!all(lanczos_contract$passed) ||
!all(native_lanczos_contract$passed) ||
!all(block_lanczos_contract$passed) ||
!all(adversarial_contract$passed)
)) {
stop("Generalized SPD LOBPCG benchmark failed release gate.", call. = FALSE)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.