Docs: Correct documented claims that the code contradicts

An audit of Doxygen comments, module blocks and manual pages against the implementations they describe turned up claims a reader would act on and get a different result. This corrects them. No behaviour changes — the diff is comments and .dox/.md text only.

Companion MRs: !2813 (closed) (a configuration regression this audit uncovered) and !2814 (merged) (four code defects where the documentation was right and the code was wrong).

Claims that silently produce wrong code

  • PartialPivLU said A = P L U. permutationP() satisfies P A = L U, which is what solve() and reconstructedMatrix() use. Assembling the factors from the class doc gives a different matrix whenever P is not an involution.
  • GeneralizedSelfAdjointEigenSolver promised x* B x = 1 for all three problem types; the BAx_lx branch back-transforms with L rather than L^-* and normalises x* B^-1 x = 1.
  • SparseSelfAdjointView::rankUpdate documented this += alpha*(u u*), a no-op at alpha == 0; the code special-cases alpha == 0 into an overwrite. A zero coefficient arriving from a loop destroys the matrix.
  • SparseQuickReference labelled sm1*perm a row permutation and perm*sm1 a column permutation. Both are the other way round, and for a square matrix each spelling compiles and returns the same shape.
  • Transform said transforming Dim points packed in a Dim x Dim matrix "is not possible" and prescribed a workaround; the product does exactly that, translation included.
  • Tensor README gave extract_image_patches a 5-parameter signature ending in PaddingType. The 5th parameter is in_row_stride, and since PaddingType converts to Index, a call written from the doc compiles and selects the wrong padding mode.
  • IterativeSolverBase::error() was documented as approximating |Ax-b|/|b| for every solver; LeastSquaresConjugateGradient and LSMR report other measures. For an inconsistent least-squares problem the two are unrelated.
  • EulerAngles::inverse() called the negated angles the inverse rotation. They are only when the elemental rotations commute, or — for a proper Euler system, whose first and third axes coincide — when alpha == gamma.

Stale or dangling references

SPQR pointed at matrixQR() and SPQR::Index, neither of which exists (and its rank() equality was wrong for wide matrices); TutorialLinearAlgebra credited ColPivHouseholderQR and CompleteOrthogonalDecomposition with kernel()/image(); TutorialGeometry used DenseBase::start(), renamed to head() before 3.0; QuickReference listed three replicate() overloads with the wrong arity; the ThreadPool module advertised a second, deleted implementation; OrderingMethods said AMD/METIS symmetrise with A^T*A rather than A + A^T; MetisOrdering described the returned permutation as METIS's iperm while the code stores its inverse.

Configuration and capability claims

EIGEN_NO_STATIC_ASSERT was documented on two pages as downgrading static assertions to runtime eigen_asserts, and TopicAssertions still described the pre-C++11 internal::static_assertion<true> mechanism, which no longer exists anywhere in the tree. The macro removes the checks outright — and cannot do otherwise, since EIGEN_STATIC_ASSERT is used at class scope (log1p_impl, MathFunctions.h:480), where an eigen_assert would not compile.

Also: SuperLU 5.x was documented as unsupported despite a dedicated SUPERLU_MAJOR_VERSION >= 5 path; Cholmod claimed to support every SparseMatrix kind though row-major complex is static-asserted against; MINRES documented DiagonalPreconditioner as its default (it is IdentityPreconditioner); PaStiX documented a default UpLo it does not declare; RandomSetter documented a map-selection order it does not follow; the CMake guide named 3.5 where Eigen's own build requires 3.17.

Defaults and preconditions that had drifted

MapAligned's alignment (EIGEN_MAX_ALIGN_BYTES, not 16 — and the doc named a function, AlignedMap(), that does not exist), SVDBase's threshold (min(rows,cols) * epsilon, not epsilon), the iterative solvers' default iteration cap (2*cols(), not the problem size), SparseMatrix::insert's reserve amount, Ref's claim that foo2(A.row()) is a compile error, Matrix()'s claim that resizing to 0 is unsupported, operator[]'s LinearAccessBit claim, innerVectors()'s parameters, LLT's claim about which triangle need not be initialised, TriangularView::solve's forward/backward pairing, and the psinh/pcosh/psqrt_complex comments, which described algorithms other than the ones implemented.

Validation

Comments-only (verified: no code lines in the diff). git diff --check clean; codespell clean on added lines. Doxygen output is message-for-message identical to master — 188 unique messages on both sides, zero added, zero removed (the local build fails identically on master due to Doxygen 1.9.8 vs the pinned CI version).

Every correction was checked against the implementation and then re-reviewed by independent passes; several first-round corrections were themselves wrong and were fixed before this MR.

🤖 Generated with Claude Code

Merge request reports

Loading
Loading