Repository navigation
Improve numerical robustness of relative_gain_array - #1092
Open
dongxuelian2 wants to merge 4 commits into
Open
dongxuelian2 wants to merge 4 commits into
dongxuelian2 wants to merge 4 commits into
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1092 +/- ##
==========================================
+ Coverage 92.26% 92.39% +0.12%
==========================================
Files 42 42
Lines 6170 6299 +129
==========================================
+ Hits 5693 5820 +127
- Misses 477 479 +2 ☔ 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.
Part of #1081: the matrix
relative_gain_arraycalculation and its numerical tolerances.The exact
det(A) != 0branch can switch between an inverse and a generalized inverse after a change of units. For example, the third column below is the first plus twice the second:On master
9baa912a, the largest absolute entries are approximately0.843and6.92e15. Both are0.843after this change, agreeing with an independent 256-bit UC reference. The Float32 generalized path also promotes its result to Float64 and can interpret Float32 normalization noise as an independent direction: scaling[1 2 3;2 4 6;3 6 9]by1e-12gives entries around524288instead of1/9.There is a separate range failure even with a finite result:
[1e300 1e-300;1e300 2e-300]gives[1 -1;0 2]on master. Its correct RGA is[2 -1;-1 2], which the new calculation recovers.Simply always using geometric normalization/SVD is insufficient.
[1 1e-100 .1;1e-100 1 .1;.1 .1 1]has condition number1.33, but geometric normalization makes it extremely ill-conditioned. Truncating its canonical SVD can discard an independent direction after a channel-unit change. Conversely, a triangular matrix with unit diagonal can have an enormous inverse norm while its RGA remains exactly the identity. Both are regression tests.Numerical choices
κ∞*sqrt(eps(T)) < 1is a conservative screen for using that result, not a singularity threshold.[1,2)and all components below 2, without forming an intermediate row-scaled matrix. This follows the idea of matching-based scaling; it does not add MC64 or another dependency.γn*norm(L,Inf)*norm(U,Inf), withγn=n*eps(T)/(1-n*eps(T)). This is motivated by the LU backward-error bound, not a forward-error or exact-rank certificate. An exact complex rank-four regression has a spurious5.65e-6pivot aboven*eps*maximum(abs,U)but below the factor scale. The independent triangular diagonal is retained. Single row/column max-norm balancing in either order was considered but still missed six randomized unit-change cases.pinvcutoff,min(m,n)*eps(T)*σmax. Raw conditioning caused by channel units alone must not discard independent directions. Neither the LU nor SVD threshold is a certificate of mathematical singularity.[1 1;1 1+δ], withδ=2^-12in Float32 andδ=2^-40in Float64. High conditioning alone does not select a truncated result.S=Dl*A*Dr, thenAᵁ=Dr*pinv(S)*Dland the factors cancel:RGA(A)=S .* transpose(pinv(S)). This avoids recovering inverse scales. The original entries are scaled using split binary exponents and bounded factors;sign(A).*exp(L)can erase small differences, and separately formingexp(u)/exp(v)can exceed the exponent range.tol, a roundoff floor relative to the residual logs, and an explicitmaxiter=10000cap. Nonconvergence, nonfinite input and unrepresentable normalized support produce errors.The existing
tolkeyword still controls normalization, not numerical rank. The matrix method gains optionalmaxiter. Singular/rectangular Float32 output now remains Float32. Nonsingular non-BLAS square types retain their existing LU path, including exact rational inverses; generalized BigFloat cases still require an appropriate generic SVD implementation. No dependency is added.The UC construction preserves diagonal-unit changes; a Moore–Penrose inverse applied directly to the original matrix generally does not. References: Uhlmann's RGA paper and Appendix A, general UC construction, Theorem V.4, and Julia's
pinvcutoff.Validation
Windows x86_64, AMD Ryzen 7 7840H, one OpenBLAS ILP64 thread:
10812026,11081,21081; these include 800 checks of well-conditioned matrices with tiny interactions and two-sided units, and 400 complex rank/phase checks.git diff --checkpasses. Existing test tolerances are unchanged.The new regression file is included by
test_analysis.jl. It can also run separately withusing ControlSystemsBase, LinearAlgebra, Random, Test; import SparseArrays: sparse; include("lib/ControlSystemsBase/test/test_relative_gain_array.jl").Performance
BenchmarkTools 1.8.0, Julia 1.10.12, warmed functions, 1,000 samples, 10 evaluations/sample for ordinary matrices, one BLAS thread, no other Julia jobs running. Inputs are
randn(rng,T,n,n)+n*I, seed 1081. Median microseconds for Float64:Float32 sizes 2/4/8/16/64 likewise show no measured regression; allocated bytes/counts are identical to master for every ordinary case. Always taking the geometric UC path was considered, but adds iteration and SVD to every frequency slice and has the conditioning problem above. The rank-two 3×3 counterexample now costs 5.0 → 7.4 µs (10,464 → 8,480 bytes): the extra square-inverse safeguard has a real cost. A random 4×6 input improves from 9.8 to 5.4 µs (16,520 → 7,328 bytes), each measured with one evaluation/sample. These are local microbenchmarks, not universal speedup guarantees.
An ordinary square call remains O(n³), and storage is O(mn). The bounded generalized path costs O(Kmn + mn·min(m,n)); square fallback additionally pays for matching and O(n³) relaxation/factorization. A conservative bound for the existing matrix-form Munkres implementation is O(n⁴). Ordinary calls bypass matching and iteration.
Numerical limits
This supplies a numerical rank model, not a certificate of mathematical singularity. In 50 fixed-seed 4×4 cases per requested condition number, median relative errors against a 256-bit inverse of the rounded input were:
Generic Float32 inputs cannot reliably encode those smallest directions at the larger requested condition numbers. At Float64 10¹⁶, 40/50 cases discarded the small direction; others retained a sensitive inverse. A unit change can still cross the rank cutoff in this ambiguous region: maximum normalized scaling jumps reached
1.38(Float32) and2.50e14(Float64), with a possibly projected result in the denominator. A projected UC result is different from the classical inverse of a strictly invertible rounded input. Resolved pivots also do not guarantee an accurate sensitive inverse. These failures of universal invariance/accuracy are documented rather than counted as passing cases.Sparse support can converge slowly. A 32×33 bidiagonal-support matrix with values 2 and 3 reaches the default cap in Float64 and succeeds with
maxiter=50000; both behaviors are tested. A 64×65 chain can exceed even that larger cap. The path's small projection spectral gap also means local eps-sized corrections do not imply eps-sized global error: measured 32-row UC errors were5.20e-5(Float32) and1.02e-13(Float64). Normalized entries themselves must fit in the working exponent range. This PR does not claim universal scaling invariance at rank/range boundaries or add generic high-precision SVD support.Remaining generalized calculations can be sensitive after canonical scaling even when the raw input looks well-conditioned; they still apply the stated numerical rank model. Non-BLAS square types retain their existing LU behavior, without the new BLAS rank safeguards.
AI-assisted implementation, numerical experiments, and review with Codex. Independent references here refer to separate mathematical implementations, not a human review.