knitr::opts_chunk$set( collapse = TRUE, comment = "#>", message = FALSE, warning = FALSE ) library(eigencore) library(Matrix)
cat(sprintf( paste0( '<script>document.addEventListener("DOMContentLoaded",function(){', 'document.body.classList.remove("palette-red","palette-lapis","palette-ochre","palette-teal","palette-green","palette-violet","preset-homage","preset-interaction","preset-study","preset-structural","preset-adobe","preset-midnight");', 'document.body.classList.add("palette-%s","preset-%s");', '});</script>' ), params$family, params$preset ))
A generalized eigenvalue problem asks for nonzero vectors $x$ and scalars $\lambda$ satisfying
$$ A x = \lambda B x. $$
The second matrix $B$ may define a positive-definite metric, or it may be part of a more general matrix pencil. eigencore supports both cases, along with partial solves when you need only a few eigenpairs and QZ decompositions when you need the full structure of a dense pencil.
When A is symmetric (or Hermitian) and B is symmetric positive definite,
pass B directly to eig_full(). The returned vectors are normalized in the
$B$ metric.
A <- diag(c(2, 8, 18)) B <- diag(c(1, 2, 3)) fit <- eig_full(A, B = B) values(fit) certificate(fit)$passed
Here the generalized eigenvalues are 2, 4, and 6: each diagonal entry of A
is divided by the corresponding entry of B.
stopifnot( isTRUE(certificate(fit)$passed), isTRUE(all.equal(sort(Re(values(fit))), c(2, 4, 6))) )
Use eig_partial() when you need only a few eigenpairs. A target such as
smallest() states which part of the spectrum to compute.
part <- eig_partial(A, B = B, k = 2, target = smallest()) values(part) part$method certificate(part)$passed
stopifnot( isTRUE(certificate(part)$passed), isTRUE(all.equal(sort(Re(values(part))), c(2, 4), tolerance = 1e-7)) )
The main choice is the structure of the problem and how much of its spectrum you need:
| Problem | Function |
| --- | --- |
| Symmetric/Hermitian A with positive-definite B, full spectrum | eig_full(A, B = B) |
| Symmetric/Hermitian A with positive-definite B, partial spectrum | eig_partial(A, B = B, k = ...) |
| Dense general pencil | eig_full(A, B = B, structure = general()) |
| Dense generalized Schur decomposition | generalized_schur(A, B) |
Use structure = general() when B is indefinite, singular, nonsymmetric, or
when the pair does not satisfy the symmetric/Hermitian positive-definite
contract. This path represents eigenvalues by homogeneous coordinates
$(\alpha, \beta)$, where a finite eigenvalue is $\alpha / \beta$.
A_general <- matrix(c(1, 4, 2, 3), 2, 2) B_general <- matrix(c(2, 1, 0, -1), 2, 2) pencil <- eig_full(A_general, B = B_general, structure = general()) values(pencil) alpha_beta(pencil)$classification certificate(pencil)$passed
stopifnot( isTRUE(certificate(pencil)$passed), all(alpha_beta(pencil)$classification == "finite") )
Homogeneous coordinates are especially useful when B is singular. eigencore
classifies finite, infinite, and undefined eigenvalues instead of forcing every
pair into an ordinary numeric ratio.
singular <- eig_full( diag(c(2, 3, 0)), B = diag(c(1, 0, 0)), structure = general() ) alpha_beta(singular)$classification certificate(singular)$failed_indices
stopifnot(identical( sort(alpha_beta(singular)$classification), sort(c("finite", "infinite", "undefined")) ))
generalized_schur() computes a dense generalized Schur, or QZ,
decomposition. Use values() for the finite ratios and alpha_beta() when you
need the homogeneous coordinates or finite/infinite classification.
qz <- generalized_schur(A_general, B_general) values(qz) alpha_beta(qz)$classification qz$method
stopifnot( length(values(qz)) == 2L, all(alpha_beta(qz)$classification == "finite") )
For pencils with singular B, sort = "finite" or sort = "infinite" moves
the requested class to the leading part of the decomposition.
qz_singular <- generalized_schur( diag(c(2, 3, 0)), diag(c(1, 0, 0)), sort = "infinite" ) alpha_beta(qz_singular)$classification
Sparse symmetric/Hermitian problems with a positive-definite metric use
eig_partial(). Set allow_dense_fallback = "never" when preserving sparsity
is a hard requirement.
A_sparse <- Diagonal(x = c(1, 4, 9, 16, 25, 36)) B_sparse <- Diagonal(x = c(1, 2, 3, 4, 5, 6)) sparse_fit <- eig_partial( A_sparse, B = B_sparse, k = 3, target = smallest(), method = lanczos(max_subspace = 6), allow_dense_fallback = "never" ) values(sparse_fit) sparse_fit$method certificate(sparse_fit)$passed
stopifnot( isTRUE(certificate(sparse_fit)$passed), isTRUE(all.equal( sort(Re(values(sparse_fit))), c(1, 2, 3), tolerance = 1e-7 )) )
Full-spectrum functions accept base dense matrices and reject sparse or operator inputs rather than silently converting them to dense storage.
The retired geigen package exposed related operations, but eigencore is not a
namespace-compatible replacement. When maintaining older code, translate the
mathematical operation: use eig_full() for a full generalized eigensolve,
generalized_schur() for QZ, and alpha_beta() to inspect homogeneous
eigenvalue coordinates.
For more on result validation, see vignette("certificates").
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.