Skip to content

COMP: Use itk::Math::MatrixExponential instead of removed vnl_matrix_exp#1452

Draft
hjmjohnson wants to merge 1 commit into
SuperElastix:mainfrom
hjmjohnson:migrate-to-itk-matrix-exponential
Draft

COMP: Use itk::Math::MatrixExponential instead of removed vnl_matrix_exp#1452
hjmjohnson wants to merge 1 commit into
SuperElastix:mainfrom
hjmjohnson:migrate-to-itk-matrix-exponential

Conversation

@hjmjohnson

Copy link
Copy Markdown

VXL removed core/vnl/vnl_matrix_exp, which AffineLogTransform included via <vnl/vnl_matrix_exp.h> (InsightSoftwareConsortium/ITK#6452). This migrates the two call sites to itk::Math::MatrixExponential, an ITK-supported Eigen-backed replacement.

Depends on InsightSoftwareConsortium/ITK#6454 (adds itk::Math::MatrixExponential / itkMatrixExponential.h). Hold merge until an ITK containing it is required.

Change
-#include <vnl/vnl_matrix_exp.h>             →  #include "itkMatrixExponential.h"
-vnl_matrix_exp(... .GetVnlMatrix())         →  itk::Math::MatrixExponential(...)
-vnl_matrix_exp(A_bar)                        →  itk::Math::MatrixExponential(A_bar)

Call-site argument types (vnl_matrix_fixed, vnl_matrix) are unchanged; the new function provides matching overloads. Both AffineLogTransform and AffineLogStackTransform components rebuild clean against the new header.

VXL removed core/vnl/vnl_matrix_exp.h, breaking AffineLogTransform's
include of <vnl/vnl_matrix_exp.h> (InsightSoftwareConsortium/ITK#6452).
Switch to itk::Math::MatrixExponential (itkMatrixExponential.h), an
ITK-supported Eigen-backed replacement using Higham scaling-and-squaring.
Call-site argument types (vnl_matrix_fixed, vnl_matrix) are unchanged.
@hjmjohnson hjmjohnson force-pushed the migrate-to-itk-matrix-exponential branch from 2e19386 to c33e80a Compare June 16, 2026 22:04
@hjmjohnson

Copy link
Copy Markdown
Author

Performance impact of migrating AffineLogTransform from vnl_matrix_exp to itk::Math::MatrixExponential. Freshly benchmarked on this transform's two call patterns (-O3 -DNDEBUG, best-of-11 min ns/call). Net: ~1.7–2× faster matrix-exp work per parameter-update, more accurate, results unchanged in practice.

Per-call timing + net AffineLogTransform impact
operation vnl_matrix_exp itk (Eigen) Eigen vs vnl
log-domain 2×2 (SetParameters) ~99 ns ~410 ns 4.1× slower
log-domain 3×3 (SetParameters) ~150 ns ~510 ns 3.4× slower
A_bar 4×4 (Jacobian loop) ~1349 ns ~695 ns 1.95× faster
A_bar 6×6 (Jacobian loop) ~2681 ns ~1333 ns 2.0× faster

Per SetParameters (1 log-domain exp + d² augmented A_bar exps in PrecomputeJacobianOfSpatialJacobian):

old (vnl) new (Eigen) net
2D 95 + 4·1331 = 5419 ns 405 + 4·692 = 3173 ns ~1.7× faster
3D 149 + 9·2676 = 24233 ns 503 + 9·1315 = 12338 ns ~2.0× faster

The d² A_bar Jacobian loop dominates and Eigen wins there, so net it's faster despite the single small log-domain exp being slower. Matrix-exp is a negligible slice of full registration wall-time, so end-to-end timing is effectively unchanged.

Numerical equivalence + accuracy

For near-identity log-domain matrices the absolute output difference between the two methods is ~1e-12 — far below any registration tolerance, so registration results are unchanged. Eigen (Higham scaling-and-squaring) is also ~2–3 orders of magnitude more accurate than vnl's Taylor series on the exp(A)·exp(−A)=I identity at every norm, and stays robust where the Taylor series degrades for large norms.

This PR depends on itk::Math::MatrixExponential landing in ITK (InsightSoftwareConsortium/ITK#6454).

@N-Dekker

Copy link
Copy Markdown
Member

Thanks Hans. Would this compile for both ITK 5 and 6, when we add something like #if ITK >= 6 and put the original code in the #else?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants