Changelog
Source:NEWS.md
eigencore 1.3.0 (2026-08-25)
Certified positive-semidefinite geometry
- Add a frozen, additive real-double PSD surface:
psd_tolerance(),psd_policy(),psd_identity(),psd_factor(),psd_gram_factor(),psd_laplacian(),psd_capabilities(),psd_spectrum(),psd_rank(),psd_nullity(),psd_apply(),psd_operator(),psd_reduce(),psd_lift(),psd_solve(),psd_gram(),psd_orthonormalize(), andpsd_reduced_operator(). Identity, diagonal, dense spectral, and dense Gram factors expose complete numerical actions with typed validation, provenance, certificates, work, retained-memory, and RDS integrity records. - Define the singular geometry explicitly: the source is a seminorm in its original coordinates, while canonical reduction represents the metric on
image(K)or the quotient bynull(K). Roots, inverse roots, pseudoinverses, complementary projectors, reduction/lift, block orthonormalization, and reduced operators satisfy independently certified postconditions.psd_solve()is a strict equation solver and rejects RHS null components; pseudoinverse application remains total. - Freeze separate Frobenius-relative tolerances for symmetry, positivity, numerical rank, and RHS compatibility. Classification retains original and repaired spectra, exact threshold categories, and repair defects. No
max(1, scale)floor is inserted, so zero-absolute-tolerance classification remains invariant under finite positive rescaling.
Structural sparse paths
- Add non-densifying
dgCMatrixGram factors that certify form and Gram actions from a supplied factor while withholding unsupported roots, rank, projectors, reduction, and solves. - Add
dgCMatrix/dsCMatrixgraph-Laplacian validation for symmetry, non-positive off-diagonals, zero row sums, optional canonical diagonal repair, and connected-component algebraic nullity. The structural route exposes form and Gram actions without claiming a complete spectrum. - Generic sparse symmetric matrices and opaque callbacks remain unsupported PSD-factor sources. Capability failures are typed and occur before callback probing, dense conversion, or undocumented approximation. The existing generalized-eigen
B/metric=API remains SPD-only; singular PSD problems use explicit image-space reduction.
Certification and downstream conformance
- Add adversarial numerical coverage for exact threshold neighbors, scales from
1e-12through1e12, repeated eigenspaces, null contamination, permutation and block metamorphisms, mutation adequacy, strict-solve compatibility, serialization integrity, and fail-closed capability paths. - Certify 50,000-row sparse Gram and path-Laplacian fixtures without dense
nbynstate, recording retained bytes, cumulative R allocation, isolated-process peak RSS, and reusable-action timing separately. - Add a provenance-required installed-consumer gate using exported APIs only. gprocrustes O/SO and quotient-space checks and DKGE root, projector, orthonormalization, and K-Procrustes differential checks pass. A pre-existing DKGE tiny-scale threshold divergence remains explicit rather than weakening eigencore’s relative policy. rfugw adoption is deferred because its candidate spectral auxiliaries do not require the PSD factor algebra.
eigencore 1.2.0 (2026-08-25)
Reusable solver workflows
-
plan_solver()now returns a schema-versioned executable plan containing the problem, original method descriptor, selected route, canonical controls, execution arguments, all 20 route-affecting package options, operator identity/revision records, serialization capability, and retained-memory metadata.solve(plan)validates and executes that frozen route without invoking the planner.replan = TRUEis the explicit opt-in to a fresh decision under current policy; execution arguments cannot be overridden. -
linear_operator()gainsoperator_id,revision, andportableprovenance. Matrix-backed and built-in composite operators derive deterministic portable identities from dimensions, structure, transformation parameters, and values. Callback operators without explicit provenance receive opaque session-local identities and restored cross-session plans fail before the callback is invoked.operator_identity()exposes the typed records. - Eigen and SVD results distinguish
planned_methodfromactual_method(methodremains the compatibility alias for the latter), reportfallback_usedand a typedfallback_reason, and retain the exact immutable plan that governed execution. Legacy result fields remain available. -
work()returns a schema-versionedeigencore_workrecord with separate logical block-call and column counts for the operator, adjoint, metric, preconditioner, and current-certificate phases, plus iterations, restarts, and phase timings. Callback counts are captured at the operator boundary, including native callback cycles;matvecsremains unchanged aslegacy_matvecs. Routes whose native controller cannot yet prove a split useNAandcomplete = FALSErather than inventing equivalent work. -
restart_state()constructs immutable, schema-versioned basis states only from freshly certified eigen or SVD results, whileretained_bytes()reports their exact version-1 R retention.solve(plan, restart_state = ...)admits basis reuse only for standard real Hermitian Lanczos on dense double, CSC, and callback operators. Exact-revision reuse may retain a deterministic, target-safe fitted start block, but never recurrence, locks, cached operator actions, convergence, or certificates. Changed revisions and lineages use only the public basis; incompatible and unsupported routes fail before the current operator is applied.
Sparse operator performance
-
scale_cols(center(A, columns = TRUE), weights)now recognizes a realdgCMatrixand builds one fused native operator for(A - 1 mu^T) D. Forward and adjoint block application, includingalpha/betaaccumulation, stay in C++; native Golub-Kahan consumes the sparse matrix, means, and weights directly, without materializing the centered matrix or crossing an R callback boundary inside the iteration. One CSC moments pass supplies exact centered-and-scaled Frobenius metadata, so the resulting two-sided SVD certificate reportsnorm_bound_type = "frobenius_metadata"andscale_is_estimate = FALSE. Zero columns, zero/negative/extreme finite weights, transpose algebra, planner provenance, and strict installed-package execution are covered by the v1.2 sparse-PCA gate.
eigencore 1.1.0 (2026-08-24)
New features
-
eig_partial()andsolve()gain aninitial_subspaceargument: a public, certified warm-start seam for standard real Hermitian Lanczos — the native paths on explicit dense double anddgCMatrixoperators, the native matrix-free callback path selected bylanczos(block > 1), and the scalar matrix-free reference path selected bylanczos(block = 1). The supplied subspace is orthonormalized at the solver boundary and fitted to the method’s start block: accepted directions are augmented deterministically when short, and when the accepted rank exceeds the block width the block is a seeded random rotation of the full accepted basis, so every supplied direction contributes generic weight (a k-column continuation subspace handed to a scalar method warm-starts all k targets, not just the first). Rank detection is invariant to column scaling, and the fitted start block is orthonormal. The start is treated only as a hint — every solve recomputes projected quantities, residuals, orthogonality, convergence, and a fresh current-operator certificate. A fully supplied subspace already invariant at the requested tolerance is discarded to a cold start: residual certification proves eigenpair accuracy, not that an invariant block contains the requested extremal pairs.initial_subspace = NULLpreserves cold behavior exactly. Unsupported generalized, shift-invert, and dense-fallback plans error. Results, plans, anddiagnostics()report start provenance plus exact operator block calls, operator columns, and certification columns. Reusable restart-state objects and generalized/transformed promotion remain future work. -
lanczos()gainscheck_stride. The default0Lpreserves full-sweep convergence checks exactly; a positive stride lets native block thick-restart paths, including real Hermitian matrix-free callbacks, check and stop within a sweep without additional operator applications.
Performance
- Sparse tridiagonal shift-invert now parses and validates the three matrix bands once per solve and reuses that immutable representation for planning, shift perturbation, factorization, and certification. The native kernel forms and returns only the requested Ritz vectors instead of exposing its full Krylov basis to R. On the installed
path_laplacian:1000,k = 20release row this reduced cumulative R allocation from 3.82 MB to 1.51 MB while retaining a 20/20 original-coordinate certificate. The G1 gate now uses retained result size for its bounded memory envelope and reportsbench::mem_allocseparately as diagnostic evidence, because R allocation counters do not observe native C/C++ working heaps in any compared engine. - New production
autoroute for largest-target partial SVD: a native implicit normal-equations (Gram) thick-restart Lanczos that runs on or as an operator, without materializing the Gram matrix. It covers dense matrices and sparse operators whose smaller side exceeds the explicit-Gram caps — regimes that previously fell back to a full LAPACK SVD (dense) or a single unrestarted Golub-Kahan sweep (sparse). Representative same-machine speedups attol = 1e-8with certificates still passing: dense 4000x1000k = 10~12x, dense 2000x2000k = 10~80x, sparse 20000x5000k = 10andk = 50~2x. Results keep the exact two-sided residual certificate in original coordinates, and uncertified results still fall back to the native Golub-Kahan path. - The scalar Golub-Kahan kernel now uses BLAS (dgemv) classical Gram-Schmidt reorthogonalization on the sparse CSC, matrix-free, and retained-restart paths, matching the dense path; previously these used scalar loops.
- The projected Golub-Kahan convergence check now runs
dbdsqrdirectly on the projected bidiagonal, tracking only the last row of the left singular vectors, instead of a densedgesvdwith full vectors; scratch buffers are reused across checks. The check drops from O(iter^3) plus per-check allocations to O(iter^2). - The scalar Lanczos convergence estimate (used by the shift-invert paths) computes eigenvalues with
dsterfand recovers only the selected eigenvectors withdstevrinstead of a fulldstevdecomposition each iteration, with scratch reuse across iterations. - The CSC sparse matrix-multiply kernel now processes wide blocks in cache-friendly chunks of 10 columns instead of a strided generic loop.
-
as_operator()no longer forces a full copy of an already-double dense matrix (storage.mode<-is now conditional), removing an O(m*n) copy plus GC churn from every problem construction — operator construction on a 2000x2000 input drops from ~52ms to ~6ms. - The scalar thick-restart Hermitian Lanczos default subspace grows from
3k+20tomax(3k+20, 5k): unchanged for smallk, and atk = 30on a general sparse operator it cuts operator applications by ~25%.
Portability
- The package again compiles on R < 4.4: guarded compatibility typedefs for
La_INT/La_LGLand declarations for the complex QZ drivers (zggev,zgges) were added for headers that predate them, andcrossprod/tcrossprodare now imported from Matrix so sparse-matrix dispatch does not rely on the base generics added in R 4.4.
Bug fixes
- Generalized result contracts are now consistent across dense pencils, QZ, transformed sparse pencils, and GSVD. Every classified result exposes a
classification_policy; GSVD records exact structural-zero semantics and documents its length-nInf/NAvalue layout. Dense general-pencil left vectors now carry an original-coordinate adjoint-residual certificate andW^H B Vdiagnostics, anddiagnostics()consistently exposes the sameleft_vectorsmatrix returned byleft_vectors(). - Benchmark/validation timing helpers no longer error on R builds without memory profiling (e.g. r-devel Linux fedora, configured without
--enable-memory-profiling).bench::mark()memory measurement is now requested only whencapabilities("profmem")isTRUE; timing still runs otherwise andmem_allocis reported asNA. Benchmark smoke tests also usetestthat::skip_on_cran(). Backported in 1.0.1 and completed in 1.0.2.
eigencore 1.0.2
CRAN release: 2026-07-25
- Complete the no-memory-profiling fix from 1.0.1. The CRAN benchmark vignette and the installed README benchmark now also request
bench::mark()memory measurements only whencapabilities("profmem")is true. The vignette’s summary tables also report unavailable results instead of failing when a benchmark regime has no successful methods. - Add a regression test that audits every shipped benchmark entry point for unconditional
memory = TRUEand exercises the package timing helper on the current R build.
eigencore 1.0.1
CRAN release: 2026-07-24
- Fix an R CMD check ERROR on R builds without memory profiling (for example the r-devel Linux fedora flavors, which are configured without
--enable-memory-profiling). The internal benchmark/validation timing helpers passedmemory = TRUEtobench::mark(), which callsutils::Rprofmem()and aborts with “memory profiling is not available on this system” on those platforms. Memory measurement is now requested only whencapabilities("profmem")isTRUE; elsewhere timing still runs andmem_allocis reported asNA. - Benchmark smoke tests now use
testthat::skip_on_cran()so they are skipped on CRAN as intended (the previousSys.getenv("CRAN")guard never fired on the CRAN check farm).
eigencore 1.0.0
CRAN release: 2026-07-23
First CRAN release.
-
svd_partial()andeig_partial()compute the top-k singular triplets or eigenpairs of large dense, sparse (CSC), diagonal, banded/tridiagonal, and matrix-free operators through native C++ kernels. - Every result carries a numerical certificate: residuals for both singular relations, a backward-error bound, orthogonality loss, a labeled norm bound, and a single
passedflag. Bounds that can only be estimated (for example stochastic norm estimates on centered sparse operators) are reported as estimates and never produce an unqualifiedpassed. - Operator algebra —
center(),scale_cols(),compose(),crossprod_operator(),linear_operator()— solves centered, scaled, and composed problems without forming dense matrices. - Transparent method selection:
plan_solver()reports the chosen kernel before a solve, andfit$methodnames the path that actually ran. Problem classes without a production kernel carry explicitreferencelabels. - RSpectra-compatible wrappers
eigs(),eigs_sym(), andsvds()accept the samewhichcodes and additionally return certificates. - Benchmarked against ‘RSpectra’, ‘irlba’, and ‘PRIMME’; reproduce with
Rscript inst/benchmarks/bench-readme.R. - Generalized eigen support:
eig_full()for dense SPD and general pencils,generalized_schur()andgeneralized_svd()for dense QZ/GSVD, partial sparse general pencils with nonsingular diagonalBvia transformed native Arnoldi, left eigenvectors and conditioning diagnostics on supported dense paths, andpencil_norm_scaledalpha/beta classification. Sparse SPD partial paths remain undereig_partial()/ LOBPCG / B-orthogonal Lanczos; general sparse QZ and non-diagonal sparseBare explicit unsupported boundaries. The real dense GSVD path currently requires a linked LAPACK that provides the deprecateddggsvdroutine. - The exported API is stable as of 1.0.0; breaking changes from here follow semantic versioning.