Skip to content

fix: restore Julia 1.10 support for Double64 intlog2 path + re-enable downgrade CI#223

Merged
ChrisRackauckas merged 3 commits into
SciML:masterfrom
ChrisRackauckas-Claude:fix-double64-julia110-and-downgrade
Jun 6, 2026
Merged

fix: restore Julia 1.10 support for Double64 intlog2 path + re-enable downgrade CI#223
ChrisRackauckas merged 3 commits into
SciML:masterfrom
ChrisRackauckas-Claude:fix-double64-julia110-and-downgrade

Conversation

@ChrisRackauckas-Claude

Copy link
Copy Markdown
Contributor

Ignore until reviewed by @ChrisRackauckas.

Problem

SciML policy requires every library to support Julia 1.10 (LTS), but the Core suite errored on 1.10 at latest compat and on master. The downgrade workflow was disabled (if: false, tracking #208).

The Issue-206 test "Double64 with pade order 13" errored on Julia 1.10:

exponential!(::Matrix{Double64}, ExpMethodGeneric{Val{13}()})
  -> intlog2(::Double64)
  -> ceil(UInt64, ::Double64)
  -> trunc(::Type{UInt64}, ::Double64)   # MethodError on Julia 1.10

Julia 1.11's Base added a generic trunc(::Type{<:Integer}, ::AbstractFloat) fallback; 1.10 lacks it, and DoubleFloats never defines trunc for Unsigned in any version. So exponential! errored on 1.10. Reproduced: 326 passed, 1 errored on Julia 1.10.

Fix (src/exp_generic.jl)

Route intlog2's integer-conversion path through a signed Int instead of UInt:

intlog2(x) = x > typemax(Int) ? ceil(Int, log2(x)) : intlog2(ceil(Int, x))

ceil(Int, x) only needs trunc(::Type{Int}, ::AbstractFloat), which DoubleFloats does define (it defines signed trunc for Int16/Int64/Int128/... but never Unsigned). The argument x is a positive operator norm bounded above by 2^62 (guarded just upstream), so the signed conversion is in-range and behavior is unchanged on 1.11+. Verified byte-for-byte equal to the old ceil(UInt, x) result across 10k random + boundary inputs (0 mismatches), including the 2^62 overflow guard.

Re-enable downgrade CI + corrected floors (Project.toml)

Removed if: false from .github/workflows/Downgrade.yml. Raised the lowest [compat] floors that resolve and pass the Core suite on Julia 1.10:

dep old new reason
DoubleFloats 1 1.1.14 DoubleFloats 1.0.x pins GenericSchur to <=0.4, conflicting with this package's GenericSchur 0.5.3; 1.1.14 is the first DoubleFloats allowing GenericSchur 0.5
StaticArrays 1.2 1.9.8 versions < 1.9.8 either fail to precompile on Julia 1.10 (require_one_based_indexing not defined) or hit an ambiguous lu(::StaticMatrix, ::Val{true}) against LinearAlgebra's deprecated method

(GenericSchur 0.5.3 and all other floors were left unchanged — they resolve fine.)

julia = "1.10" and the workflow's julia-version: "1.10" are unchanged, per the LTS policy.

Local test results (Julia 1.10.11)

Latest compat:

Quality Assurance | 10  10
Basic Tests       | 329  1(broken)  330
Testing ExponentialUtilities tests passed

Downgrade floors (DoubleFloats 1.1.14, GenericSchur 0.5.3, StaticArrays 1.9.8):

Quality Assurance | 10  10
Basic Tests       | 329  1(broken)  330
Testing ExponentialUtilities tests passed

The 1 broken is a pre-existing @test_broken (kiops, test/basictests.jl:293), untouched here. The previously-erroring Issue-206 Double64 test now passes.

🤖 Generated with Claude Code

ChrisRackauckas and others added 3 commits June 6, 2026 04:45
… downgrade CI

The Issue-206 test "Double64 with pade order 13" errored on Julia 1.10 because
intlog2(::Double64) routed through ceil(UInt64, ::Double64), which requires
trunc(::Type{UInt64}, ::Double64). Julia 1.11's Base added a generic
trunc(::Type{<:Integer}, ::AbstractFloat) fallback, but 1.10 lacks it and
DoubleFloats never defines trunc for Unsigned. Routing intlog2 through a signed
Int (ceil(Int, ...)), which DoubleFloats does define, restores 1.10 support
with identical behavior (the argument is a positive, bounded operator norm;
verified byte-for-byte equal to the old result across the full input range).

Re-enable the downgrade workflow (remove `if: false`) and raise the lowest
[compat] floors that resolve and pass the Core suite on Julia 1.10:
- DoubleFloats: 1 -> 1.1.14 (1.0.x pins GenericSchur to <=0.4, conflicting with
  GenericSchur 0.5.3; 1.1.14 is the first DoubleFloats allowing GenericSchur 0.5)
- StaticArrays: 1.2 -> 1.9.8 (versions < 1.9.8 either fail to precompile on
  Julia 1.10 with `require_one_based_indexing not defined`, or hit an ambiguous
  lu(::StaticMatrix, ::Val{true}) with LinearAlgebra's deprecated method)

Both suites run locally on Julia 1.10:
- latest compat: Quality Assurance 10/10, Basic Tests 329 pass / 1 broken
- downgrade floors: Quality Assurance 10/10, Basic Tests 329 pass / 1 broken
(the 1 broken is a pre-existing @test_broken; the Issue-206 Double64 test passes)

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Strict no-reresolve can't reconcile floored core deps against the
latest-floating transitive SciML stack; reresolve still enforces the
floor [compat] pins but resolves a consistent set. Verified locally.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Use the strict SciML default `allow-reresolve: false` so Pkg.test must
instantiate the exact deps-floor + latest-transitive set with no
reconciliation. Verified locally on Julia 1.10 (deps-mode: only [deps]
[compat] pinned to floors, allow_reresolve=false):
  Quality Assurance: 10/10
  Basic Tests: 329 pass, 1 broken (pre-existing @test_broken), 330 total
  "Testing ExponentialUtilities tests passed" (exit 0)
No floor raises needed — current [deps] floors are strict-consistent with
the latest transitive ecosystem.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ChrisRackauckas-Claude

Copy link
Copy Markdown
Contributor Author

Update: downgrade made strict (allow-reresolve: false)

Switched the Downgrade.yml caller to the strict SciML default allow-reresolve: false (was true). This forces Pkg.test to instantiate the exact deps-floor + latest-transitive set with no reconciliation, which is the rigorous downgrade check.

Verified locally on Julia 1.10.11, deps-mode (only [deps] [compat] pinned to floors), Pkg.test(; allow_reresolve=false), GROUP=Core:

Quality Assurance | 10  10
Basic Tests       | 329  1(broken)  330
Testing ExponentialUtilities tests passed

No floor raises were needed — the current [deps] floors (Adapt 3.4.0, ArrayInterface 7.1, GPUArraysCore 0.1, GenericSchur 0.5.3, PrecompileTools 1) are already strict-consistent with the latest transitive ecosystem on Julia 1.10. The 1 broken is the same pre-existing @test_broken (kiops, test/basictests.jl:293).

Ignore until reviewed by @ChrisRackauckas.

@ChrisRackauckas ChrisRackauckas marked this pull request as ready for review June 6, 2026 23:07
@ChrisRackauckas ChrisRackauckas merged commit 2f4e343 into SciML:master Jun 6, 2026
22 of 29 checks passed
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