ENH: Tier the Eigen-backed convenience numerics as itk::bridge - #6768
Conversation
This comment was marked as resolved.
This comment was marked as resolved.
Is the recommendation for users of the old interface in the long term plan to directly use the Eigen interfaces but in the short term the unsupported interfaces can be used to aid in transitioning? |
@blowekamp I don't ever see that happening. It is what you proposed as an ideal solution, but it's pretty combersome for users to use the raw interfaces of Eigen. Personally, I don't like the "unsupported" naming because I think it indicates that it is unsafe. I like "convenience". Originally, ITK was conceived to strictly be algorithms (not have any IO included), but it was quickly realized that without the convenience of IO in ITK algorithms, imaging algorithms would not gain traction. I think of these algorithms the same way: without an SVD or reference CG optimizer readily available, ITK becomes much more burdensome to use. SVD is not part of the core mission of ITK, but without easy-to-access implementations, ITK is too clunky to use. I have accepted that my personal preference to have these common convenience methods in itk::Math was overruled, and I am trying to identify the desired pattern for an acceptable solution before ITKv6 become tagged. |
|
@hjmjohnson Thank you. So would it perhaps be better to so that it is recommended that new code directly use the Eigen library interface for numeric code, and that legacy code will be supported with this "bridge" interface between vnl data objects and Eigen algorithms? If so then maybe "bridge" would be a better namespace? |
I am much more supportive of "bridge" with documentation. (I'm not opposed to "unsupported"; it just rubs me the wrong way). |
547a37c to
be08a62
Compare
|
Force-pushed @dzenanz @N-Dekker — this is a whole-namespace rename since your last look, so a summary rather than asking you to re-read 83 files:
@greptileai — your P1 was correct and it was a live defect, not one the rename introduced. The extent was larger than reported: 13 VNL headers plus 2 Local verification
Two follow-ups I have not done here: the branch name still contains |
|
The rename is clean and comprehensive. Looking across the key touch-points: Verified consistent throughout:
One thing worth confirming: The two acknowledged follow-ups (ANTs #2019 / BRAINSTools #623 need updating to the |
|
Pointers to the documentation added in 1. The canonical statement — Two blocks:
2. A representative per-header pointer — /** \file
* Part of the \c itk::bridge migration-aid namespace: a convenience wrapper over a
* third-party numerical backend, not core ITK API. It is not maintained or validated
* to core ITK standards and may change API/ABI without a deprecation cycle.
* Downstream code should prefer calling Eigen directly.
* \see \ref BridgeNumericsPage
*/Identical text sits immediately after the include guard in all ten headers: CholeskySolve, EigenDecompositionSignConvention, EigenDecompositionSolverInfo, GeneralizedEigenDecomposition, MathDeterminant, MathLDLT, MathSVD, QRDecomposition, RealEigenDecomposition, SymmetricEigenDecomposition. It deliberately points at the page rather than restating it, so ten copies cannot drift — a change to the contract edits only the 3. Downstream-facing prose — ITK 6 migration guide, lines 754-777 Placed before the eigendecomposition section, so the contract is read before the replacement classes are named. Why three places rather than oneEach hits a different reader where they already are:
A single |
be08a62 to
c66b124
Compare
The VNL to Eigen migration has been adding general-purpose numerics to itk::Math and itk:: directly, where nothing distinguishes them from core contract API such as itk::Image. That is how VNL became ITK's permanent maintenance obligation: its symbols reached the public surface and could not be changed afterwards. Move the Eigen-backed convenience layer to itk::bridge, rename the headers to itkBridge*.h so downstream __has_include probes report the move truthfully instead of matching a header whose contents have changed, and prefix the GoogleTest suite names to match. The namespace names what the layer is for: bridging call sites off the deprecated VNL algorithms without the caller first learning Eigen's API. It is a migration aid, not a numerics library ITK undertakes to maintain or validate, and downstream code should prefer depending on Eigen directly. Documentation/Doxygen/BridgeNumerics.dox states that contract as a Doxygen page plus a namespace block, and the ITK 6 migration guide repeats it for downstream readers. itkCholeskySolve.h is included in the move: it is Eigen-backed, lives in itk::Math, and is one of the matrix solving methods this tier covers. A separate Modules/Core/CommonMath module was evaluated and rejected: itkMatrix.h includes itkBridgeMathSVD.h and itkBridgeMathDeterminant.h for GetInverse, while itkBridgeMathLDLT.h includes itkMatrix.h, so the surface straddles ITKCommon in both directions and cannot be split out without a dependency cycle. The VNL deprecation diagnostics named the pre-move spellings (itk::Math::SVD, itkMathSVD.h and siblings), so a consumer following them could not compile. They now name the itk::bridge spellings. ITK 6 is not released, so no deprecation window is owed. Renames the capability macro to ITK_BRIDGE_MATH_HAS_SOLVE_SYMMETRIC. Issue: InsightSoftwareConsortium#6620
c66b124 to
a2c58cc
Compare
|
Two force-pushes, kept separate so the compare links are readable:
Local verification on a2c58cc
@dzenanz — your approval was against |
Moves the Eigen-backed convenience numerics from
itk::Math/itk::intoitk::bridge, and renames their headers toitkBridge*.h, so the support tieris visible in the spelling. Implements #6620.
ITK 6 is not released, so no deprecation window is owed — this is the last
point at which the move is free.
The namespace names what the layer is for: bridging call sites off the
deprecated VNL algorithms without the caller first having to learn Eigen's
API. It is a migration aid, not a numerics library ITK undertakes to maintain
or validate — downstream code should prefer depending on Eigen directly.
That contract is now written down in three places (see below).
The support contract, and where it is documented
itk::bridgeholds convenience wrappers over third-party numerical backends,provided to ease the initial burden of migrating away from VNL. A
vnl_svdcall site becomes
itk::bridge::Math::SVDas a mechanical, low-risk edit.They are not part of the core ITK mission to maintain or validate:
ITK API changes receive.
accuracy, conditioning, or convergence, and does not guarantee bit-for-bit
stability across backend versions.
functionality will not necessarily be added.
Downstream users should prefer Eigen (or another numerical library)
directly rather than depending on the API/ABI of these wrappers. Using
itk::bridgeas a transitional step while retiring VNL is reasonable;treating it as a permanent dependency is not.
Documented at three levels, so the warning is reachable from wherever a reader
starts:
Documentation/Doxygen/BridgeNumerics.dox\pageplus a\namespace itk::bridgeblock\fileblock pointing at that pageWhy — the concern this addresses
VNL was vendored as an implementation detail, but its symbols reached ITK's
public surface. ITK thereby became the de-facto maintainer and compatibility
guarantor of general linear algebra for two decades, and could not change its
numerics backend without a deprecation campaign.
Every
itk::Math::*wrapper added by the VNL→Eigen migration is currentlyindistinguishable — in namespace, header location, and implied support level —
from core contract API like
itk::Image. Downstream adopts them as freely asit adopted
vnl_svd. Naming the tier, and stating its contract in thedocumentation, is what prevents the same trap closing a second time.
Scope — 10 headers
itkMathSVD.h,itkMathLDLT.h,itkMathDeterminant.h,itkCholeskySolve.h,itkQRDecomposition.h,itkSymmetricEigenDecomposition.h,itkRealEigenDecomposition.h,itkGeneralizedEigenDecomposition.h, and thetwo
itk::detailhelpers — each gaining anitkBridgeprefix.itkCholeskySolve.his included beyond the list in #6620: it is Eigen-backed,lives in
itk::Math, and is one of "the LU decomposition and the other matrixsolving methods" @blowekamp scoped. Two test consumers.
Out of scope, per @dzenanz:
itk::Math::abs, theitkMath.hconstants, andother long-standing utilities — core contract already.
The capability macro becomes
ITK_BRIDGE_MATH_HAS_SOLVE_SYMMETRIC.GoogleTest suite names gain the same prefix.
Fixes the VNL deprecation diagnostics (@greptileai P1)
Greptile found that the VNL deprecation messages still named the pre-move
itk::Math::SVD/itkMathSVD.h, so a consumer following the emittedguidance could not compile — it verified this by building an external
consumer. Correct, and it was a live defect on the previous head rather than
one introduced here.
The actual extent was larger than the four files reported. 13 VNL headers
plus 2
CMakeLists.txtcomments carried stale spellings across the wholefamily, not just SVD:
vnl_svd.h,vnl_svd_fixed.h,vnl_svd_economy.h,vnl_matrix_inverse.h,vnl_cholesky.h,vnl_ldl_cholesky.h,vnl_determinant.h,vnl_det.h,vnl_qr.h,vnl_real_eigensystem.h,vnl_symmetric_eigensystem.h,vnl_generalized_eigensystem.h,vnl_scatter_3x3.h, plusalgo/CMakeLists.txt.All now name the
itk::bridgespellings.Why no separate CommonMath module
A
Modules/Core/CommonMathmodule was evaluated and rejected: it cannot bebuilt without a dependency cycle.
itkMatrix.hincludesitkBridgeMathSVD.handitkBridgeMathDeterminant.hfor
GetInverse();itkImageBase.hxxanditkVersor.hxxcallMath::Determinant. So those headers must sit at-or-below ITKCommon.itkBridgeMathLDLT.hincludesitkMatrix.h,itkArray.h,itkArray2D.hand
itkVector.h. So it must sit at-or-above ITKCommon.The surface straddles ITKCommon in both directions.
Worth noting for the tiering discussion: ITK core depends on these APIs.
itk::Matrix::GetInverse()needs them. The tier can describe the publicspelling; it cannot describe the dependency.
Why the headers are renamed, not just the namespace
Downstream feature-detects with
__has_include(<itkMathSVD.h>). If only thenamespace moved, that probe would still succeed while the symbol inside had
changed — the guard would report the wrong answer and the build would fail at
the call site instead. Renaming makes the probe truthful: the old path
genuinely disappears, so
#eliffallbacks work as written.Test plan — forest build
Validated in the ITK forest testbed (ITK + downstream consumers built against
one locally built ITK):
The guard column is the one that matters: a rename like this can compile
cleanly while silently dropping downstream back to
vnl_svd. Symbolinspection confirms both consumers kept the Eigen path.
pre-commit run --all-filesclean, re-run after the rebase onto current main.⚠ ccache can serve stale objects across this rename
If you build a downstream project incrementally with a warm ccache, you may
see link errors naming the old
itk::Math::detail::RectangularSVDEigen.ccache direct mode keys an object on a manifest of the files it included. When
a header is renamed rather than edited, a compile can hash-hit an entry
recorded against the vanished include set and return an object compiled
against headers that no longer exist.
ninja -t cleandoes not help — itdeletes the object and ccache immediately re-serves the stale one.
CCACHE_RECACHE=1for the downstream build fixes it. CI does cold builds, sothis never appears there — it only affects local evaluation.