Docs: Audit and refresh the user manual under doc/
A sweep of every page under doc/, checking each documented claim against the checked-out tree and fixing what had drifted. Eleven commits, roughly in increasing order of invasiveness.
Code samples that did not compile
Verified by extracting each sample and compiling (and where meaningful, running) it against this tree:
TutorialSparse/SparseQuickReference:selfadjointView<>()has no defaultUpLoargument, so the documented call is a hard error — replaced withselfadjointView<Lower|Upper>(). Triangular solves were writtensm1.triangularView<Lower>(dm1), which is not an overload; they need.solve(...). AlsoColmajor/Rowmajorcasing,triangularview/selfadjointviewcasing, and ablock(startRow, startCol)overload that does not exist.CustomizingEigen_Plugins: theMatrixBaseAddons.hexample referencedinternal::sqrtandfast_inv_sqrt(both long gone) and had two-phase-lookup errors onConstant. It now compiles and runs as an actual plugin.AsciiQuickReference.txt: every line in the solver block had an unbalanced parenthesis, andA.qr()/A.svd()do not exist.TemplateKeyword: a missing)in thetypenameexample, plus an undeclaredm1.TutorialGeometry:AngleAxis3fandMatrix<float,N>are not types.StlContainers: the specialization example specializedMatrix2dand then usedstd::vector<Vector2d>.SparseLinearSystems: unbalanced template argument list in the preconditioner snippet.
Claims the code contradicts
Pitfallsdocumented an inconsistency wherefoo<3>()andfoo<10>()printed different results forboolmatrices, without explaining it. The page now states the actual semantics: forbool,+is logical OR and*is logical AND, so aboolmatrix product is a Boolean matrix product, while operators with no Boolean meaning (subtraction, negation) fall back to integer promotion. The reported inconsistency is real and still reproduces, so it is now documented as a warning rather than removed:dst = X - A * Bis rewritten todst = X; dst -= A * B, and the compound form scales the product byScalar(-1), which forboolistrue— so the subtraction becomes another logical OR. Fixed sizes and small dynamic sizes take a different product implementation and do give zero. Filed as #3113 (closed).TopicLazyEvaluationexplained assignment in terms ofEvalBeforeAssigningBit, which is deprecated and no longer drives that decision.TopicAssertionsjustifiedeigen_plain_assertwith a GCC ≤ 4.3 bug; the real current reasons are GPU device code and the__FILE__/ODR issue documented inAssert.h.EIGEN_FAST_MATHwas described as covering "SSE sin/cos and single-precision sqrt"; it actually gatessin,cos,tan,tanh,erf,erfc, reciprocal, andsqrt/rsqrtselection across backends.EIGEN_GEMM_THREADPOOLwas undocumented.SparseLinearSystemswas missing the built-in iterative solvers promoted since it was written (GMRES, DGMRES, MINRES, IDR(s), BiCGSTAB(L), IDR(s)STAB(L)) and theSimplicialNonHermitian{LLT,LDLT}variants.- Sample assertion messages in
TopicAliasingandUnalignedArrayAssertmatched internals from several refactors ago. UsingNVCCsaid the default index type islong int; it isstd::ptrdiff_t.- Roughly ten dead links (Bugzilla, the tuxfamily MKL redirector, PaStiX on gforge, ADOL-C on coin-or, Comeau, parashift).
Pages that were never written
TopicVectorization, TopicScalarTypes, and TopicEigenExpressionTemplates had been TODO: write this dox page! since 2013, while being linked from the Matrix-class, arithmetic, initialization, and aliasing tutorials — so a reader following those links hit a dead end. All three are now written:
- Vectorization: supported instruction sets per architecture, including the opt-in SVE/SME/RVV backends and their fixed-vector-length requirements; what gets vectorized; how it interacts with alignment; the controlling macros.
- Scalar types: what works out of the box (including
Eigen::halfandEigen::bfloat16), practical notes on mixing scalar types, integer andlong doublecaveats,NumTraits, and where to go for custom types. - Expression templates: what they are and the consequences users actually trip over (
auto, aliasing, writing functions that accept expressions,eval()), cross-linked to the deeper pages.
The Experimental page — which backs the \nonstableyet alias, so it is reachable from API docs — still described the Eigen 2.0 API freeze, said "for the 2.1 release (expected in July 2009)", and listed SVD, QR, Cholesky, Sparse and Geometry as entirely experimental. Rewritten around the current policy: semantic versioning since 5.0, the \nonstableyet marker, internal/src names, and the unsupported/ modules.
InsideEigenExample carried a "PLEASE HELP US IMPROVING THIS SECTION" box admitting its assignment walk-through described pre-3.3 Eigen. It now follows the real path: call_assignment, the assume-aliasing dispatch, shape-based Assignment dispatch, call_dense_assignment_loop with its evaluators, generic_dense_assignment_kernel, traversal/unrolling selection, and the LinearVectorizedTraversal loop down through assign_op, pstoret, the binary evaluator's packet(), and padd.
Structure
- The newly written pages,
TopicWritingEfficientProductExpression, andExperimentalmove out of "Unclassified pages" into General topics / Understanding Eigen; the now-empty Unclassified section is dropped. TopicUsingAOCLwas orphaned — reachable only by direct URL. Added to the TOC beside the MKL page.- The two remaining "PLEASE HELP US" boxes in
QuickReferenceare replaced with actual content (a slicing/indexing note andreshaped()entries), andAsciiQuickReferencegains slicing and reshape sections with their Matlab equivalents. WrongStackAlignmentis marked as historical (the GCC bug it documents was fixed in GCC 4.5) rather than telling readers to upgrade to GCC 4.5.
Decompositions: complete orthogonal, and how pivoting is framed
RandCompleteOrthogonalDecomposition appeared nowhere under doc/, and RandColPivHouseholderQR only in a single catalogue row. Both now appear in the decomposition tables, the least-squares guidance, the QR module's method list, and the in-place mechanism list; in-place support for both was confirmed by compiling against Ref<MatrixXd>. Their cost is described structurally -- nearly all work in level-3 BLAS, against sketch overhead that dominates on small matrices -- with no timings quoted, for the reason given under "Deliberately left alone".
While there, the manual's framing of pivoting is corrected. The catalogue rated FullPivLU and FullPivHouseholderQR "Proven" against "Good" or "Depends on condition number" for their partial- and column-pivoting counterparts, which implies the cheaper strategies lack rigorous error bounds. They do not: these factorizations are all backward stable and differ in the growth-factor constant. The "Proven" rating is removed, a new note explains what actually differs, and note 3 no longer presents FullPivHouseholderQRPreconditioner as the only provable preconditioner. The guidance on complete pivoting is also reframed as a trade-off. It previously called the full-pivoting classes "primarily useful for debugging, pedagogy, or the rare case where column pivoting is demonstrably insufficient", which undersells them: complete pivoting costs blocking and so scales badly, and the smaller growth factor rarely repays that on its own, but where an application depends on determining rank reliably the cost can be worth paying -- most of all for small matrices, where the lost blocking matters least. Column pivoting is reliable in practice but not guaranteed, Kahan's matrix being the standard counterexample. The recommendation now cites LAPACK, which exposes no complete-pivoting driver for LU or QR: getc2 is a complete-pivoting LU, but its only caller under SRC/ is tgsy2, the generalized Sylvester kernel, and no complete-pivoting QR exists at all -- geqp3 and geqp3rk are both column pivoting. Verified against the LAPACK tree at 51b349470, which also corrected an earlier overstatement in this branch: pstrf is a general-purpose complete-pivoting Cholesky, so the argument is scoped to LU and QR rather than to complete pivoting in general.
Two smaller gaps found in the same pass: CompleteOrthogonalDecomposition and RandCompleteOrthogonalDecomposition are the only classes exposing pseudoInverse(), which the manual never mentioned; and note 1 still claimed the block-diagonal LDLT variant was available only in LAPACK, although BunchKaufman provides it -- a class that was itself missing from TutorialLinearAlgebra entirely, table and recommendations alike.
Corrections from review
28e50b8b6 fixes six claims raised in review: the EIGEN_DONT_VECTORIZE alignment relationship in TopicVectorization (stated backwards -- it lowers alignof(Vector4f) rather than preserving it), the obsolete MKL licensing advice in UsingIntelMKL, two AsciiQuickReference blocks with scalar-type mismatches, the description of Nested versus ref_selector/nested_eval in NewExpressionType, and the packet-index arithmetic in InsideEigenExample.
801fc5941 addresses the second review round across eight pages: the bool product-subtraction warning described above; RandCompleteOrthogonalDecomposition presented as computing "the same factorization" as CompleteOrthogonalDecomposition, when the pivots and therefore the factors differ; std::complex<long double> missing from the supported scalar types; the SME backend's incompatibility with -msve-vector-bits, which would pin the kernels to one runtime streaming vector length; stale read-write annotations and a shadowed s in AsciiQuickReference; and a DenseStorage.h assertion message regenerated against this tree. It also rewrites notes 3 and 4 of the decomposition catalogue to separate what pivoting buys in each factorization — a growth-factor bound for LU, rank revelation for QR, where Householder QR is backward stable irrespective of pivoting — and to state the Demmel-Veselic condition under which JacobiSVD's high relative accuracy holds, with the citation.
c186505c9 finishes that column. HouseholderQR and LLT were still rated "Depends on condition number", which conflates backward stability with the forward error of the solve; that depends on the conditioning for every method in the table, PartialPivLU included. Neither factorization needs pivoting to be stable, so HouseholderQR now points at note 4, which covers exactly that, and LLT gets a note of its own: Cholesky's growth factor on a positive definite matrix is bounded by 1, and what conditioning governs is not the accuracy but whether the factorization completes, a computed pivot going non-positive being reported through info() rather than yielding a meaningless factor. The eigen-solver rows keep the old rating, where it is apt.
Deliberately left alone
ClassHierarchy / StorageOrders / TutorialArrayClass, which I checked and found still accurate.
The dense-decomposition benchmark table is also left as-is. It describes its own provenance, but that provenance is a laptop with no recorded Eigen version, compiler, or date, and it predates the randomized QR/COD classes and BunchKaufman. Refreshing it needs measurements this MR cannot supply, so the new speed guidance here is kept qualitative and structural rather than numeric. Filed as #3112, blocked on #3111 (closed) -- the benchmark CI pipeline has never produced a result, because run.benchmark.sh looks for the executables one directory above where CMake writes them.
Validation
All touched code samples compile and run against this tree: the plugin example, the sparse view/solve lines, all eight Ref-based in-place decompositions, reshaped(), and the cheat-sheet solver lines (the non-deprecated bdcSvd<Options>() form).
For Doxygen, the local 1.9.8 is too far from CI's pin to be meaningful, so I built the pinned Doxygen 1.13.2 from source and ran the full doc target on both this branch and its merge base, diffing the error sets: net zero new errors, with two baseline errors fixed. That measurement was taken before the rebases onto f5494736f and, later, 4aa66c4ed; both were clean and touched none of this content, and the all-tests label on this MR runs the authoritative build:linux:docs job.
The commits added since that measurement were re-checked with the local Doxygen 1.9.8, whose pinned counterpart no longer exists on this machine. That build emits a large set of false unable to resolve link errors across the tree, so only file-scoped diagnostics are meaningful from it; the pages touched by those commits draw none, and none of the added markup uses \ref or \link. This is weaker evidence than the original pinned A/B, and the all-tests label runs the authoritative build:linux:docs job.