From e0696b50784150b13633bbad74245dd5be0bad8c Mon Sep 17 00:00:00 2001 From: Orjan Ameye Date: Sun, 26 Jul 2026 21:29:13 +0200 Subject: [PATCH 1/3] CompatHelper: bump compat for JET, LinearSolve and Peaks Collects the bumps from the four open CompatHelper PRs (#96, #99, #137, #138) into a single change, rebased onto current main: - JET: 0.9.18, 0.10 -> 0.9.18, 0.10, 0.11 - LinearSolve: 3.75 -> 3.75, 5 - Peaks: 0.5 -> 0.5, 0.6 PRs #137 and #138 are the same LinearSolve bump reported separately for [weakdeps] and [extras], so they collapse into one entry. --- Project.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Project.toml b/Project.toml index f7ce1c6..4c76a1f 100644 --- a/Project.toml +++ b/Project.toml @@ -50,17 +50,17 @@ ExplicitImports = "1.11" FunctionWrappers = "1.1.3" HarmonicBalance = "0.18" HomotopyContinuation = "2.12" -JET = "0.9.18, 0.10" +JET = "0.9.18, 0.10, 0.11" Latexify = "0.16" LinearAlgebra = "1.10" -LinearSolve = "3.75" +LinearSolve = "3.75, 5" ModelingToolkitBase = "1" NaNMath = "1.1" NonlinearSolve = "4.17" OrderedCollections = "1.8, 2" OrdinaryDiffEqRosenbrock = "2" OrdinaryDiffEqTsit5 = "2" -Peaks = "0.5" +Peaks = "0.5, 0.6" Plots = "1.40.9" PrecompileTools = "1.2" Printf = "1.10" From 8d957106736cedcf22be03b2eead89bdaf3748af Mon Sep 17 00:00:00 2001 From: Orjan Ameye Date: Mon, 27 Jul 2026 08:12:52 +0200 Subject: [PATCH 2/3] build: restrict OrderedCollections to 1.8 CI enables `force_latest_compatible_version` on `compathelper/*` branches, which pins OrderedCollections to 2.x. Latexify 0.16 does not support OrderedCollections 2, so the test environment no longer resolves. Restrict the bound to 1.8 so the forced-latest resolution picks 1.8.2 and Latexify 0.16.11 stays installable. --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 4c76a1f..30db6a3 100644 --- a/Project.toml +++ b/Project.toml @@ -57,7 +57,7 @@ LinearSolve = "3.75, 5" ModelingToolkitBase = "1" NaNMath = "1.1" NonlinearSolve = "4.17" -OrderedCollections = "1.8, 2" +OrderedCollections = "1.8" OrdinaryDiffEqRosenbrock = "2" OrdinaryDiffEqTsit5 = "2" Peaks = "0.5, 0.6" From 9efe09d4aa753b4430d357f4b9a3ab53b65ef138 Mon Sep 17 00:00:00 2001 From: Orjan Ameye Date: Mon, 27 Jul 2026 08:40:38 +0200 Subject: [PATCH 3/3] test: run JET in its own CI job and fix the reports it finds JET 0.10 and newer require Julia 1.12, so linting cannot run on the LTS runner. Follow the layout used in HarmonicBalance.jl: `runtests.jl` gates on `GROUP`, the matrix jobs run `GROUP=Core`, and a dedicated `jet` job runs `GROUP=JET` on Julia 1. Running JET on 1.12 for the first time surfaced 12 reports, none of which were visible before because the old `VERSION < v"1.12.0-beta"` guard meant JET only ever ran on the LTS at 0.9.x: - `LimitCycles` called `QuestBase.add_harmonic!` while only importing names from QuestBase, not the module itself. `add_pairs!` would have thrown an UndefVarError at runtime. - `bar` was assigned inside `if show_progress` and then read unconditionally in four functions. Bind it to `nothing` instead and guard on `isnothing`. - `idx_pairs` was assigned in an if/elseif with no fallback in `sort_2D`. Also disable `force_latest_compatible_version` on the LTS job. CompatHelper branches otherwise resolve every [compat] entry to its newest version, which the LTS cannot satisfy for dependencies that require Julia 1.12. --- .github/workflows/Tests.yml | 30 +++++++++++- src/LimitCycles/LimitCycles.jl | 1 + src/LinearResponse/response.jl | 24 ++++++---- src/solve_homotopy.jl | 8 ++-- src/sorting.jl | 31 +++++++----- test/code_quality.jl | 7 --- test/jet.jl | 3 ++ test/runtests.jl | 86 +++++++++++++++++++--------------- 8 files changed, 121 insertions(+), 69 deletions(-) create mode 100644 test/jet.jl diff --git a/.github/workflows/Tests.yml b/.github/workflows/Tests.yml index e2522e9..eefdd95 100644 --- a/.github/workflows/Tests.yml +++ b/.github/workflows/Tests.yml @@ -46,9 +46,13 @@ jobs: arch: ${{ matrix.arch }} - uses: julia-actions/cache@v3 - uses: julia-actions/julia-buildpkg@v1 + # CompatHelper branches otherwise resolve every [compat] entry to its newest + # version, which the LTS cannot satisfy for dependencies that require Julia 1.12. - uses: julia-actions/julia-runtest@v1 + with: + force_latest_compatible_version: ${{ matrix.version == 'lts' && 'false' || 'auto' }} env: - GROUP: ${{ matrix.group }} + GROUP: Core JULIA_NUM_THREADS: auto - uses: julia-actions/julia-processcoverage@v1 with: @@ -61,3 +65,27 @@ jobs: name: codecov-umbrella fail_ci_if_error: false if: ${{ matrix.version == 'lts' }} + + # JET >= 0.10 requires Julia 1.12, so linting cannot run on the LTS runner. + jet: + name: JET - ubuntu-latest - x64 + runs-on: ubuntu-latest + timeout-minutes: 120 + permissions: # needed to allow julia-actions/cache to proactively delete old caches that it has created + actions: write + contents: read + steps: + - uses: actions/checkout@v7 + with: + persist-credentials: false + - uses: julia-actions/setup-julia@v3 + with: + show-versioninfo: true + version: '1' + arch: x64 + - uses: julia-actions/cache@v3 + - uses: julia-actions/julia-buildpkg@v1 + - uses: julia-actions/julia-runtest@v1 + env: + GROUP: JET + JULIA_NUM_THREADS: auto diff --git a/src/LimitCycles/LimitCycles.jl b/src/LimitCycles/LimitCycles.jl index 87eb2a2..2add887 100644 --- a/src/LimitCycles/LimitCycles.jl +++ b/src/LimitCycles/LimitCycles.jl @@ -1,6 +1,7 @@ module LimitCycles using QuestBase: + QuestBase, get_all_terms, substitute_all, DifferentialEquation, diff --git a/src/LinearResponse/response.jl b/src/LinearResponse/response.jl index 7dd9614..a47739b 100644 --- a/src/LinearResponse/response.jl +++ b/src/LinearResponse/response.jl @@ -22,16 +22,18 @@ function get_jacobian_response( spectra = [JacobianSpectrum(res; branch=branch, index=i) for i in findall(stable)] C = Array{P,2}(undef, length(Ω_range), length(spectra)) - if show_progress - bar = Progress( + bar = if show_progress + Progress( length(CartesianIndices(C)); dt=1, desc="Diagonalizing the Jacobian for each solution ... ", barlen=50, ) + else + nothing end # evaluate the Jacobians for the different values of noise frequency Ω - _fill_response!(C, spectra, nat_var, Ω_range, show_progress ? bar : nothing) + _fill_response!(C, spectra, nat_var, Ω_range, bar) return C end function get_jacobian_response( @@ -48,16 +50,18 @@ function get_jacobian_response( ] C = Array{P,2}(undef, length(Ω_range), length(spectra)) - if show_progress - bar = Progress( + bar = if show_progress + Progress( length(CartesianIndices(C)); dt=1, desc="Diagonalizing the Jacobian for each solution ... ", barlen=50, ) + else + nothing end # evaluate the Jacobians for the different values of noise frequency Ω - _fill_response!(C, spectra, nat_var, Ω_range, show_progress ? bar : nothing) + _fill_response!(C, spectra, nat_var, Ω_range, bar) return C end @@ -100,13 +104,15 @@ function get_rotframe_jacobian_response( stableidx = findall(stable) C = zeros(P, length(Ω_range), sum(stable)) - if show_progress - bar = Progress( + bar = if show_progress + Progress( length(C); dt=1, desc="Solving the linear response ODE for each solution and input frequency ...", barlen=50, ) + else + nothing end for i in 1:sum(stable) @@ -122,7 +128,7 @@ function get_rotframe_jacobian_response( ) end end - show_progress ? next!(bar) : nothing + isnothing(bar) || next!(bar) end return C end diff --git a/src/solve_homotopy.jl b/src/solve_homotopy.jl index 4386cd5..4f7585f 100644 --- a/src/solve_homotopy.jl +++ b/src/solve_homotopy.jl @@ -229,17 +229,19 @@ function _get_raw_solution( show_progress, ) result_full = Array{Vector{Any},1}(undef, length(parameter_values)) - if show_progress - bar = Progress( + bar = if show_progress + Progress( length(parameter_values); dt=1, desc="Solving via $(nameof(typeof(method))) homotopy ...", barlen=50, ) + else + nothing end for i in eachindex(parameter_values) # do NOT thread this p = parameter_values[i] - show_progress ? ProgressMeter.next!(bar) : nothing + isnothing(bar) || ProgressMeter.next!(bar) result_full[i] = [ HC.solve( problem.system; diff --git a/src/sorting.jl b/src/sorting.jl index 772cd85..e43c771 100644 --- a/src/sorting.jl +++ b/src/sorting.jl @@ -105,13 +105,13 @@ function sort_1D(solns::Solutions(T); show_progress=true) where {T<:Number} # prefer real solution at first position sorted_solns[1] = sort(solns[1]; by=x -> abs.(imag(x))) - if show_progress - bar = Progress( - length(solns); dt=1, desc="Ordering solutions into branches ...", barlen=50 - ) + bar = if show_progress + Progress(length(solns); dt=1, desc="Ordering solutions into branches ...", barlen=50) + else + nothing end for i in eachindex(solns[1:(end - 1)]) - show_progress ? ProgressMeter.next!(bar) : nothing + isnothing(bar) || ProgressMeter.next!(bar) matched_indices = align_pair(sorted_solns[i], solns[i + 1]) next_indices = getindex.(matched_indices, 2) sorted_solns[i + 1] = (solns[i + 1])[next_indices] @@ -178,10 +178,12 @@ whether a progress bar should be displayed. function sort_2D(solns::Solutions(T); sorting=:nearest, show_progress=true) where {T} """match each 2D solution with all its surrounding neighbors, including the diagonal ones""" # determine a trajectory in 2D space where nodes will be visited - if sorting == :hilbert # propagating matching of solutions along a hilbert_curve in 2D - idx_pairs = hilbert_indices(solns) + idx_pairs = if sorting == :hilbert # propagating matching of solutions along a hilbert_curve in 2D + hilbert_indices(solns) elseif sorting == :nearest # propagate matching of solutions along rows - idx_pairs = naive_indices(solns) + naive_indices(solns) + else + error("Unknown sorting method: $(sorting). Use :hilbert or :nearest.") end # infinite solutions are ignored by the align_pair function. @@ -190,13 +192,18 @@ function sort_2D(solns::Solutions(T); sorting=:nearest, show_progress=true) wher # prefer real solution at first position sorted_solns[1, 1] = sort(solns[1, 1]; by=x -> abs.(imag(x))) - if show_progress - bar = Progress( - length(idx_pairs); dt=1, desc="Ordering solutions into branches ...", barlen=50 + bar = if show_progress + Progress( + length(idx_pairs); + dt=1, + desc="Ordering solutions into branches ...", + barlen=50, ) + else + nothing end for i in 1:(length(idx_pairs) - 1) - show_progress ? ProgressMeter.next!(bar) : nothing + isnothing(bar) || ProgressMeter.next!(bar) neighbors = get_nn_2D(idx_pairs[i + 1], size(solns, 1), size(solns, 2)) reference = [sorted_solns[ind...] for ind in neighbors] matched_indices = align_pair(reference, solns[idx_pairs[i + 1]...]) diff --git a/test/code_quality.jl b/test/code_quality.jl index 3b0c5c5..42fe776 100644 --- a/test/code_quality.jl +++ b/test/code_quality.jl @@ -66,10 +66,3 @@ end ) end end - -if VERSION < v"1.12.0-beta" - @testset "Code linting" begin - using JET - JET.test_package(HarmonicSteadyState; target_defined_modules=true) - end -end diff --git a/test/jet.jl b/test/jet.jl new file mode 100644 index 0000000..8f8f37b --- /dev/null +++ b/test/jet.jl @@ -0,0 +1,3 @@ +using JET + +JET.test_package(HarmonicSteadyState; target_modules=(HarmonicSteadyState,)) diff --git a/test/runtests.jl b/test/runtests.jl index 8b7ef4f..d563dfd 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,52 +6,64 @@ using Random const SEED = 0x8f88209c Random.seed!(SEED) -@testset "Code quality" begin - include("code_quality.jl") -end +# JET runs in its own CI job: JET >= 0.10 requires Julia 1.12, so it cannot be +# installed on the LTS runner. GROUP=Core skips it, GROUP=JET runs only it. +const GROUP = get(ENV, "GROUP", "All") -@testset "API" begin - include("API.jl") - include("Problem.jl") -end +if GROUP in ("All", "Core") + @testset "Code quality" begin + include("code_quality.jl") + end -@testset "Computing steady states" begin - @testset "parametron" begin - include("steady_states/parametron.jl") + @testset "API" begin + include("API.jl") + include("Problem.jl") end - # include("steady_states/krylov.jl") - include("steady_states/methods.jl") -end -@testset "Processing solutions" begin - include("Jacobian.jl") - include("transform_solutions.jl") - include("sorting.jl") - include("classification.jl") -end + @testset "Computing steady states" begin + @testset "parametron" begin + include("steady_states/parametron.jl") + end + # include("steady_states/krylov.jl") + include("steady_states/methods.jl") + end -@testset "Plotting" begin - include("plotting.jl") -end + @testset "Processing solutions" begin + include("Jacobian.jl") + include("transform_solutions.jl") + include("sorting.jl") + include("classification.jl") + end -@testset "Linear response" begin - include("linear_response.jl") - include("input_output.jl") -end + @testset "Plotting" begin + include("plotting.jl") + end -@testset "Limit cycle" begin - include("limit_cycle.jl") -end + @testset "Linear response" begin + include("linear_response.jl") + include("input_output.jl") + end -@testset "extensions" begin - @testset "QuantumCumulants extension" begin - include("extensions/QuantumCumulantsExt.jl") + @testset "Limit cycle" begin + include("limit_cycle.jl") end - @testset "Time evolution extension" begin - include("extensions/time_evolution.jl") - include("extensions/hysteresis_sweep.jl") + + @testset "extensions" begin + @testset "QuantumCumulants extension" begin + include("extensions/QuantumCumulantsExt.jl") + end + @testset "Time evolution extension" begin + include("extensions/time_evolution.jl") + include("extensions/hysteresis_sweep.jl") + end + @testset "SteadyState extension" begin + include("extensions/SteadyStateDiffEqExt.jl") + end end - @testset "SteadyState extension" begin - include("extensions/SteadyStateDiffEqExt.jl") +end + +if GROUP in ("All", "JET") + @testset "Code linting" begin + include("jet.jl") end end