From ad0c31777eb354d12349a9572c168adb567a5f98 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Mon, 15 Jun 2026 10:23:17 -0400 Subject: [PATCH 1/2] Raise PrecompileTools compat floor to 1.2 to fix Downgrade CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ExplicitImports 1.13+ (the package's declared test-dep floor is 1.14.0) requires PrecompileTools "1.2.0 - 1" in the registry. With the previous PrecompileTools = "1" compat (floor 1.0.0), the Downgrade job pins PrecompileTools to 1.0.0, which forces ExplicitImports <= 1.8.0 and is unsatisfiable against the 1.14.0 floor: Unsatisfiable requirements detected for package ExplicitImports: restricted by compatibility requirements with PrecompileTools to versions: 1.0.0-1.8.0 or uninstalled — no versions left Raising the floor to "1.2" matches what ExplicitImports actually needs. PrecompileTools 1.2 still supports julia >= 1.6, so the package's julia = "1.10" floor and its @compile_workload usage are unaffected. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index bc45575..d0a3a53 100644 --- a/Project.toml +++ b/Project.toml @@ -9,7 +9,7 @@ PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" [compat] ExplicitImports = "1.14.0" JET = "0.9, 0.10, 0.11" -PrecompileTools = "1" +PrecompileTools = "1.2" julia = "1.10" [extras] From 07430cb1fd168955cca4bb2c01d008836cdce8b3 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Tue, 16 Jun 2026 08:19:02 -0400 Subject: [PATCH 2/2] Fix cov(::AbstractMatrix) JET reports and complex-eltype bug on Julia 1.12 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The JET 'error analysis', 'different numeric types', and 'complex numbers' testsets failed under JET 0.11 / Julia 1.12 with 4 reports, all from cov(::Matrix) (and cor(::Matrix), which calls it). Each report bottomed out at the same Julia-1.12 LinearAlgebra inference artifact: broadcasting (`.*`) over two contiguous matrix-column SubArrays forces broadcast's `unaliascopy` path through `copyto_unaliased!` in LinearAlgebra transpose.jl, where inference yields a `Union{Adjoint{T,Union{}}, Transpose{T,Union{}}}` and JET flags an "invalid builtin getfield". This reproduces in a 7-line standalone function with no package code, so it is a Julia/LinearAlgebra false positive, but it is straightforward to avoid in source. Rewrite both cov branches to accumulate each covariance entry with an explicit index loop over the centered values instead of broadcasting over column/row views. This sidesteps the unaliascopy path entirely (JET now reports zero issues for both report_call and report_opt) and removes the per-pair temporary allocation. Also fix a latent correctness bug uncovered while doing this: the result matrix was allocated as `zeros(float(real(eltype(X))), p, p)` — a real matrix even for complex input. Whenever an off-diagonal covariance was genuinely complex, assigning it into the real array threw InexactError. The result is now `zeros(float(eltype(X)), ...)`, matching Statistics.cov (verified against Statistics.jl for a complex matrix with complex off-diagonals). Added a regression test for complex covariance matrices. Verified locally: full suite passes on Julia 1.12.6 (455/455) and on the 1.10.11 floor (422 pass / 1 pre-existing broken), and all JET report_call / report_opt entry points from jet_tests.jl return zero reports on 1.12. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- src/LightweightStats.jl | 30 +++++++++++++++++------------- test/regression_tests.jl | 13 +++++++++++++ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/LightweightStats.jl b/src/LightweightStats.jl index f6a065e..d53a95f 100644 --- a/src/LightweightStats.jl +++ b/src/LightweightStats.jl @@ -426,15 +426,17 @@ function cov(X::AbstractMatrix; dims::Int = 1, corrected::Bool = true) n == 0 && return fill(oftype(real(zero(eltype(X))) / 1, NaN), p, p) means = vec(mean(X; dims = 1)) - C = zeros(float(real(eltype(X))), p, p) - - # Center the data once using broadcasting - X_centered = X .- means' + Tc = float(eltype(X)) + C = zeros(Tc, p, p) for i in 1:p + mi = means[i] for j in i:p - # Use views and broadcasting for column operations - s = sum(view(X_centered, :, i) .* _conj(view(X_centered, :, j))) + mj = means[j] + s = zero(Tc) + for k in 1:n + s += (X[k, i] - mi) * _conj(X[k, j] - mj) + end C[i, j] = corrected ? s / (n - 1) : s / n if i != j C[j, i] = _conj(C[i, j]) @@ -443,19 +445,21 @@ function cov(X::AbstractMatrix; dims::Int = 1, corrected::Bool = true) end return C elseif dims == 2 - n, p = size(X') + p, n = size(X) n == 0 && return fill(oftype(real(zero(eltype(X))) / 1, NaN), p, p) means = vec(mean(X; dims = 2)) - C = zeros(float(real(eltype(X))), p, p) - - # Center the data once using broadcasting - X_centered = X .- means + Tc = float(eltype(X)) + C = zeros(Tc, p, p) for i in 1:p + mi = means[i] for j in i:p - # Use views and broadcasting for row operations - s = sum(view(X_centered, i, :) .* _conj(view(X_centered, j, :))) + mj = means[j] + s = zero(Tc) + for k in 1:n + s += (X[i, k] - mi) * _conj(X[j, k] - mj) + end C[i, j] = corrected ? s / (n - 1) : s / n if i != j C[j, i] = _conj(C[i, j]) diff --git a/test/regression_tests.jl b/test/regression_tests.jl index 897718b..6e6051a 100644 --- a/test/regression_tests.jl +++ b/test/regression_tests.jl @@ -208,6 +208,19 @@ using Random end end + @testset "cov - complex matrices" begin + # Off-diagonal covariances are genuinely complex here, so the result + # matrix must have a complex eltype (regression for an InexactError when + # the result was allocated as a real matrix). + Xc = ComplexF64[1 + 1im 2 + 3im; 3 - 1im 4 + 2im; 5 + 0im 6 - 1im] + for dims in (1, 2) + C_lw = LightweightStats.cov(Xc; dims = dims) + C_st = Statistics.cov(Xc; dims = dims) + @test eltype(C_lw) <: Complex + @test C_lw ≈ C_st + end + end + @testset "cor - correlation vectors" begin x = randn(30) y = randn(30)