Repository navigation
Conversation
The generic implementations of `norm` in LinearAlgebra and StaticArrays rescale by the maximum absolute value to avoid overflow and underflow. Their branches (`iszero`, `isfinite`, `<`) take partials into account for `Dual`s, resulting in NaNs, Infs, and even incorrect primal values (e.g., at zero or for very small or large inputs). Instead, the norm of the primal values is computed and the chain rule is applied with weights that are bounded by 1 in absolute value. At zero, the subgradient zero is used (as in ChainRules). Derivatives with respect to `p` are supported as well. Additionally, `hypot` uses the same convention at zero, and the three-argument `hypot` no longer drops the partials of outer tags in nested differentiation. Fixes #243, fixes #794. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #872 +/- ##
==========================================
+ Coverage 91.24% 91.78% +0.54%
==========================================
Files 11 12 +1
Lines 1085 1157 +72
==========================================
+ Hits 990 1062 +72
Misses 95 95 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #243, fixes #794.
Problem
The generic implementations of
norm(LinearAlgebra.generic_norm2/generic_normpand StaticArrays'_norm/_norm_scaled) rescale by the maximum absolute value to avoid overflow and underflow. Their branches (iszero,isfinite,<) take partials into account forDuals (<since #791), soDuals end up in the wrong branch:gradient(norm, [0.0, 0.0])[NaN, NaN][0.0, 0.0]gradient(x -> norm(x)^2, [0.0, 0.0])[NaN, NaN][0.0, 0.0]gradient(x -> norm(x, 3), [0.0, 0.0])[NaN, NaN][0.0, 0.0]norm([Dual(1e-200, 1e-100), Dual(0.0, 0.0)])Dual(0.0, Inf)(wrong primal)Dual(1e-200, 1e-100)gradient(norm, [1e-200, 1e-200])[Inf, Inf][0.707, 0.707]norm(SA[Dual(0, 1), Dual(0, 1), Dual(0, 1)])Dual(NaN, NaN)Dual(0.0, 0.0)derivative(p -> norm([3.0, 4.0], p), 3.0)MethodError-0.304hypot(Dual(0.0, 1.0), Dual(0.0, 1.0))Dual(0.0, NaN)Dual(0.0, 0.0)All of these fail with NaN-safe mode enabled as well.
Approach
Similar to the rules in ChainRules, the norm of the primal values is computed with the existing (scale-robust) implementations and the chain rule is applied with weights that are bounded by 1 in absolute value (no overflow/underflow):
x:w_i = |u_i|^(p-1) * sign(u_i)withu_i = x_i / norm(x, p)(u_iforp = 2; only the first maximum forp = Inf);p ∈ {0, 1, -Inf}keep the generic implementation, which is not affected by the scaling issuesp:norm(x, p) / p * sum(|u_i|^p * log(|u_i|)), which is bounded and avoids the cancellation ofsum(|x_i|^p * log(|x_i|)) - norm(x, p) * log(norm(x, p))norm(x, p) == 0, the subgradient zero is used (ChainRules uses the same convention viapinv)Complex arrays, nested differentiation (with all tag orderings of
xandp),StaticArrays,Adjoint/Transpose, and sparse arrays are supported. Method ambiguities with LinearAlgebra, StaticArrays, and SparseArrays (new weak dependency/extension) are resolved explicitly.hypotuses the same convention at zero. Additionally, the three-argumenthypotno longer drops the partials of outer tags in nested differentiation (it used the tag-agnosticvalue/partials).Limitations
Second-order derivatives through
normat zero remain incorrect (e.g.,hessian(x -> norm(x)^2, zeros(2))returns zeros instead of2I): Sincenormis not differentiable at zero, no choice of partials ofnorm(x)can recover the correct result. This is documented in the limitations section of the docs;sum(abs2, x)should be used instead.🤖 Generated with Claude Code