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)
#> [1] 2 4 6
certificate(fit)$passed
#> [1] TRUEHere the generalized eigenvalues are 2, 4, and 6: each diagonal entry
of A is divided by the corresponding entry of
B.
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)
#> [1] 2 4
part$method
#> [1] "native dense generalized SPD LAPACK fallback"
certificate(part)$passed
#> [1] TRUEThe 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)
#> [1] -0.75+1.391941i -0.75-1.391941i
alpha_beta(pencil)$classification
#> [1] "finite" "finite"
certificate(pencil)$passed
#> [1] TRUEHomogeneous 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.
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)
#> [1] -0.75+1.391941i -0.75-1.391941i
alpha_beta(qz)$classification
#> [1] "finite" "finite"
qz$method
#> [1] "native dense generalized Schur QZ LAPACK full"For pencils with singular B,
sort = "finite" or sort = "infinite" moves the
requested class to the leading part of the decomposition.
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)
#> [1] 1 2 3
sparse_fit$method
#> [1] "native transformed generalized SPD B-orthogonal Lanczos"
certificate(sparse_fit)$passed
#> [1] TRUEFull-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").