From e800a57d8bad573f76e316691358c1288804be1d Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Sun, 7 Jun 2026 16:01:56 -0400 Subject: [PATCH 1/8] Uniformize monorepo structure to OrdinaryDiffEq canonical style Make the lib/* sublibrary project model real and route sublibrary testing through the centralized SublibraryCI/DowngradeSublibraries workflows, matching the OrdinaryDiffEq.jl canonical monorepo layout. - Add [sources] DataDrivenDiffEq = {path = "../.."} to each sublibrary (DataDrivenDMD/SR/Sparse/Lux). The sublibraries are leaves that depend on the in-repo root DataDrivenDiffEq; without [sources] they resolved against the registered release instead of the PR checkout. Root does not re-export the sublibraries, so no cyclic root->leaf [sources] edges are added. - Thread a single group-env-name (DATADRIVENDIFFEQ_TEST_GROUP) consistently: - SublibraryCI.yml: group-env-name + check-bounds: auto. - DowngradeSublibraries.yml: group-env-name/group-env-value: Core (no allow-reresolve; v1 removed that input). DataDrivenDiffEq is skipped (path-developed sibling) alongside stdlibs. - Every sublibrary test/runtests.jl now reads get(ENV, "DATADRIVENDIFFEQ_TEST_GROUP", get(ENV, "GROUP", "All")) and runs its functional suite on Core/All; DataDrivenSparse/SR previously had no group gate. - Root CI.yml: drop the hardcoded sublibrary GROUP rows (DataDrivenDMD/SR/ Sparse/Lux) so sublibraries are tested only via SublibraryCI's project model; keep a root-only group set (Core, nopre). Coverage scoped to src. - Root Downgrade.yml: group: Core, no allow-reresolve. - Root test/runtests.jl: replace the ad-hoc dispatcher with a _detect_sublibrary_group dispatcher (OrdinaryDiffEq style) that activates lib/, develops its [sources] on Julia < 1.11, sets the group env var, and Pkg.tests the sublibrary; otherwise runs the root @safetestset groups / nopre. - Add test/test_groups.toml ([Core] on lts/1.11/1/pre) to each sublibrary so the default QA group (which has no QA suite here) is not spawned. No [compat] floors lowered; no tests skipped/broken/loosened. No test/Project.toml exists (the per-group test/nopre/Project.toml is the canonical isolated-env pattern and is kept). No ReTestItems/@testitem present. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/CI.yml | 9 +- .github/workflows/Downgrade.yml | 4 + .github/workflows/DowngradeSublibraries.yml | 3 + .github/workflows/SublibraryCI.yml | 3 + lib/DataDrivenDMD/Project.toml | 3 + lib/DataDrivenDMD/test/runtests.jl | 4 +- lib/DataDrivenDMD/test/test_groups.toml | 4 + lib/DataDrivenLux/Project.toml | 3 + lib/DataDrivenLux/test/runtests.jl | 4 +- lib/DataDrivenLux/test/test_groups.toml | 4 + lib/DataDrivenSR/Project.toml | 3 + lib/DataDrivenSR/test/runtests.jl | 102 +++++++++++--------- lib/DataDrivenSR/test/test_groups.toml | 4 + lib/DataDrivenSparse/Project.toml | 2 + lib/DataDrivenSparse/test/runtests.jl | 26 ++--- lib/DataDrivenSparse/test/test_groups.toml | 4 + test/runtests.jl | 85 +++++++++++----- 17 files changed, 175 insertions(+), 92 deletions(-) create mode 100644 lib/DataDrivenDMD/test/test_groups.toml create mode 100644 lib/DataDrivenLux/test/test_groups.toml create mode 100644 lib/DataDrivenSR/test/test_groups.toml create mode 100644 lib/DataDrivenSparse/test/test_groups.toml diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 378a9f127..02743ea9d 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -19,12 +19,11 @@ jobs: strategy: fail-fast: false matrix: + # Root-only test groups. The lib/* sublibraries (DataDrivenDMD, DataDrivenSR, + # DataDrivenSparse, DataDrivenLux) are covered by SublibraryCI.yml via the + # project model and must not be double-tested through the root matrix. group: - Core - - DataDrivenDMD - - DataDrivenSR - - DataDrivenSparse - - DataDrivenLux - nopre version: - '1' @@ -37,5 +36,5 @@ jobs: with: julia-version: "${{ matrix.version }}" group: "${{ matrix.group }}" - coverage-directories: "src,lib/DataDrivenDMD/src,lib/DataDrivenSparse/src,lib/DataDrivenSR/src,lib/DataDrivenLux/src" + coverage-directories: "src" secrets: "inherit" diff --git a/.github/workflows/Downgrade.yml b/.github/workflows/Downgrade.yml index 60a30367c..9ff2d12f1 100644 --- a/.github/workflows/Downgrade.yml +++ b/.github/workflows/Downgrade.yml @@ -10,11 +10,15 @@ on: - master paths-ignore: - 'docs/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} jobs: test: name: "Downgrade" uses: "SciML/.github/.github/workflows/downgrade.yml@v1" with: julia-version: "1.10" + group: "Core" skip: "Pkg,TOML" secrets: "inherit" diff --git a/.github/workflows/DowngradeSublibraries.yml b/.github/workflows/DowngradeSublibraries.yml index 6fba9003e..32f924032 100644 --- a/.github/workflows/DowngradeSublibraries.yml +++ b/.github/workflows/DowngradeSublibraries.yml @@ -20,3 +20,6 @@ jobs: with: julia-version: "lts" skip: "Pkg,TOML,Statistics,LinearAlgebra,SparseArrays,InteractiveUtils,Random,Test,DataDrivenDiffEq" + group-env-name: "DATADRIVENDIFFEQ_TEST_GROUP" + group-env-value: "Core" + # Every lib/* sublibrary is downgrade-tested (projects auto-discovered, no exclusions). diff --git a/.github/workflows/SublibraryCI.yml b/.github/workflows/SublibraryCI.yml index 6cec66bb4..3a6d609fa 100644 --- a/.github/workflows/SublibraryCI.yml +++ b/.github/workflows/SublibraryCI.yml @@ -19,4 +19,7 @@ concurrency: jobs: sublibraries: uses: "SciML/.github/.github/workflows/sublibrary-project-tests.yml@v1" + with: + group-env-name: DATADRIVENDIFFEQ_TEST_GROUP + check-bounds: auto secrets: "inherit" diff --git a/lib/DataDrivenDMD/Project.toml b/lib/DataDrivenDMD/Project.toml index 110d22235..3d37dae8d 100644 --- a/lib/DataDrivenDMD/Project.toml +++ b/lib/DataDrivenDMD/Project.toml @@ -7,6 +7,9 @@ version = "0.1.3" DataDrivenDiffEq = "2445eb08-9709-466a-b3fc-47e12bd697a2" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +[sources] +DataDrivenDiffEq = {path = "../.."} + [compat] DataDrivenDiffEq = "1.14" OrdinaryDiffEq = "6, 7" diff --git a/lib/DataDrivenDMD/test/runtests.jl b/lib/DataDrivenDMD/test/runtests.jl index a9fe50b49..175f64b26 100644 --- a/lib/DataDrivenDMD/test/runtests.jl +++ b/lib/DataDrivenDMD/test/runtests.jl @@ -5,10 +5,10 @@ using Test @info "Finished loading packages" -const GROUP = get(ENV, "GROUP", "All") +const GROUP = get(ENV, "DATADRIVENDIFFEQ_TEST_GROUP", get(ENV, "GROUP", "All")) @time begin - if GROUP == "All" || GROUP == "DataDrivenDMD" + if GROUP == "All" || GROUP == "Core" || GROUP == "DataDrivenDMD" @safetestset "Linear autonomous" begin include("./linear_autonomous.jl") end diff --git a/lib/DataDrivenDMD/test/test_groups.toml b/lib/DataDrivenDMD/test/test_groups.toml new file mode 100644 index 000000000..3ab133501 --- /dev/null +++ b/lib/DataDrivenDMD/test/test_groups.toml @@ -0,0 +1,4 @@ +# Each sublibrary only defines functional ("Core") tests; there are no QA +# (Aqua/JET/AllocCheck) suites here, so the default QA group is not declared. +[Core] +versions = ["lts", "1.11", "1", "pre"] diff --git a/lib/DataDrivenLux/Project.toml b/lib/DataDrivenLux/Project.toml index 03cb2c793..ee51e4232 100644 --- a/lib/DataDrivenLux/Project.toml +++ b/lib/DataDrivenLux/Project.toml @@ -30,6 +30,9 @@ StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" TransformVariables = "84d833dd-6860-57f9-a1a7-6da5db126cff" WeightInitializers = "d49dbf32-c5c2-4618-8acc-27bb2598ef2d" +[sources] +DataDrivenDiffEq = {path = "../.."} + [compat] AbstractDifferentiation = "0.6" ChainRulesCore = "1.15" diff --git a/lib/DataDrivenLux/test/runtests.jl b/lib/DataDrivenLux/test/runtests.jl index 9db36e13d..c28ead4e5 100644 --- a/lib/DataDrivenLux/test/runtests.jl +++ b/lib/DataDrivenLux/test/runtests.jl @@ -5,10 +5,10 @@ using Test @info "Finished loading packages" -const GROUP = get(ENV, "GROUP", "All") +const GROUP = get(ENV, "DATADRIVENDIFFEQ_TEST_GROUP", get(ENV, "GROUP", "All")) @testset "DataDrivenLux" begin - if GROUP == "All" || GROUP == "DataDrivenLux" + if GROUP == "All" || GROUP == "Core" || GROUP == "DataDrivenLux" @testset "Lux" begin @safetestset "Nodes" include("nodes.jl") @safetestset "Layers" include("layers.jl") diff --git a/lib/DataDrivenLux/test/test_groups.toml b/lib/DataDrivenLux/test/test_groups.toml new file mode 100644 index 000000000..3ab133501 --- /dev/null +++ b/lib/DataDrivenLux/test/test_groups.toml @@ -0,0 +1,4 @@ +# Each sublibrary only defines functional ("Core") tests; there are no QA +# (Aqua/JET/AllocCheck) suites here, so the default QA group is not declared. +[Core] +versions = ["lts", "1.11", "1", "pre"] diff --git a/lib/DataDrivenSR/Project.toml b/lib/DataDrivenSR/Project.toml index 5da78b179..f1c377097 100644 --- a/lib/DataDrivenSR/Project.toml +++ b/lib/DataDrivenSR/Project.toml @@ -8,6 +8,9 @@ DataDrivenDiffEq = "2445eb08-9709-466a-b3fc-47e12bd697a2" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" SymbolicRegression = "8254be44-1295-4e6a-a16d-46603ac705cb" +[sources] +DataDrivenDiffEq = {path = "../.."} + [compat] Reexport = "1.2" DataDrivenDiffEq = "1.14" diff --git a/lib/DataDrivenSR/test/runtests.jl b/lib/DataDrivenSR/test/runtests.jl index be923bb8b..891bf806a 100644 --- a/lib/DataDrivenSR/test/runtests.jl +++ b/lib/DataDrivenSR/test/runtests.jl @@ -3,60 +3,66 @@ using DataDrivenSR using Test using StableRNGs -rng = StableRNG(42) -X = rand(rng, 2, 50) - -@testset "Simple" begin - alg = DataDrivenSR.EQSearch( - eq_options = Options( - unary_operators = [sin, exp], - binary_operators = [*], maxdepth = 1, - seed = 42, - verbosity = -1, progress = false +const GROUP = get(ENV, "DATADRIVENDIFFEQ_TEST_GROUP", get(ENV, "GROUP", "All")) + +if GROUP == "All" || GROUP == "Core" || GROUP == "DataDrivenSR" + + rng = StableRNG(42) + X = rand(rng, 2, 50) + + @testset "Simple" begin + alg = DataDrivenSR.EQSearch( + eq_options = Options( + unary_operators = [sin, exp], + binary_operators = [*], maxdepth = 1, + seed = 42, + verbosity = -1, progress = false + ) ) - ) - f(x) = [sin(x[1]); exp(x[2])] - Y = hcat(map(f, eachcol(X))...) - prob = DirectDataDrivenProblem(X, Y) - res = solve(prob, alg) - @test r2(res) >= 0.95 - @test rss(res) <= 1.0e-5 -end + f(x) = [sin(x[1]); exp(x[2])] + Y = hcat(map(f, eachcol(X))...) + prob = DirectDataDrivenProblem(X, Y) + res = solve(prob, alg) + @test r2(res) >= 0.95 + @test rss(res) <= 1.0e-5 + end -@testset "Univariate" begin - alg = DataDrivenSR.EQSearch( - eq_options = Options( - unary_operators = [sin, exp], - binary_operators = [*], maxdepth = 1, - seed = 42, - verbosity = -1, progress = false + @testset "Univariate" begin + alg = DataDrivenSR.EQSearch( + eq_options = Options( + unary_operators = [sin, exp], + binary_operators = [*], maxdepth = 1, + seed = 42, + verbosity = -1, progress = false + ) ) - ) - Y = sin.(X[1:1, :]) - prob = DirectDataDrivenProblem(X, Y) - res = solve(prob, alg) - @test r2(res) >= 0.95 - @test rss(res) <= 1.0e-5 -end + Y = sin.(X[1:1, :]) + prob = DirectDataDrivenProblem(X, Y) + res = solve(prob, alg) + @test r2(res) >= 0.95 + @test rss(res) <= 1.0e-5 + end -@testset "Lifted" begin - alg = DataDrivenSR.EQSearch( - eq_options = Options( - unary_operators = [sin, exp], - binary_operators = [+], maxdepth = 1, - seed = 42, - verbosity = -1, progress = false + @testset "Lifted" begin + alg = DataDrivenSR.EQSearch( + eq_options = Options( + unary_operators = [sin, exp], + binary_operators = [+], maxdepth = 1, + seed = 42, + verbosity = -1, progress = false + ) ) - ) - f(x) = [sin(x[1] .^ 2); exp(x[2] * x[1])] - Y = hcat(map(f, eachcol(X))...) + f(x) = [sin(x[1] .^ 2); exp(x[2] * x[1])] + Y = hcat(map(f, eachcol(X))...) + + @variables x y + basis = Basis([x; y; x^2; y^2; x * y], [x; y]) + prob = DirectDataDrivenProblem(X, Y) + res = solve(prob, basis, alg) + @test r2(res) >= 0.95 + @test rss(res) <= 1.0e-5 + end - @variables x y - basis = Basis([x; y; x^2; y^2; x * y], [x; y]) - prob = DirectDataDrivenProblem(X, Y) - res = solve(prob, basis, alg) - @test r2(res) >= 0.95 - @test rss(res) <= 1.0e-5 end diff --git a/lib/DataDrivenSR/test/test_groups.toml b/lib/DataDrivenSR/test/test_groups.toml new file mode 100644 index 000000000..3ab133501 --- /dev/null +++ b/lib/DataDrivenSR/test/test_groups.toml @@ -0,0 +1,4 @@ +# Each sublibrary only defines functional ("Core") tests; there are no QA +# (Aqua/JET/AllocCheck) suites here, so the default QA group is not declared. +[Core] +versions = ["lts", "1.11", "1", "pre"] diff --git a/lib/DataDrivenSparse/Project.toml b/lib/DataDrivenSparse/Project.toml index 00b82d729..744560256 100644 --- a/lib/DataDrivenSparse/Project.toml +++ b/lib/DataDrivenSparse/Project.toml @@ -9,6 +9,8 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +[sources] +DataDrivenDiffEq = {path = "../.."} [compat] julia = "1.10" diff --git a/lib/DataDrivenSparse/test/runtests.jl b/lib/DataDrivenSparse/test/runtests.jl index 9d797903f..7d899959d 100644 --- a/lib/DataDrivenSparse/test/runtests.jl +++ b/lib/DataDrivenSparse/test/runtests.jl @@ -2,18 +2,22 @@ using DataDrivenDiffEq using DataDrivenSparse using SafeTestsets -@safetestset "Basic Sparse Regression" begin - include("./sparse_linear_solve.jl") -end +const GROUP = get(ENV, "DATADRIVENDIFFEQ_TEST_GROUP", get(ENV, "GROUP", "All")) -@safetestset "Pendulum" begin - include("./pendulum.jl") -end +if GROUP == "All" || GROUP == "Core" || GROUP == "DataDrivenSparse" + @safetestset "Basic Sparse Regression" begin + include("./sparse_linear_solve.jl") + end -@safetestset "Michaelis Menten" begin - include("./michaelis_menten.jl") -end + @safetestset "Pendulum" begin + include("./pendulum.jl") + end + + @safetestset "Michaelis Menten" begin + include("./michaelis_menten.jl") + end -@safetestset "Cartpole" begin - include("./cartpole.jl") + @safetestset "Cartpole" begin + include("./cartpole.jl") + end end diff --git a/lib/DataDrivenSparse/test/test_groups.toml b/lib/DataDrivenSparse/test/test_groups.toml new file mode 100644 index 000000000..3ab133501 --- /dev/null +++ b/lib/DataDrivenSparse/test/test_groups.toml @@ -0,0 +1,4 @@ +# Each sublibrary only defines functional ("Core") tests; there are no QA +# (Aqua/JET/AllocCheck) suites here, so the default QA group is not declared. +[Core] +versions = ["lts", "1.11", "1", "pre"] diff --git a/test/runtests.jl b/test/runtests.jl index 22fbae2f6..3b1586279 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -4,26 +4,74 @@ using SafeTestsets, Test, Pkg const GROUP = get(ENV, "GROUP", "All") -function dev_subpkg(subpkg) - subpkg_path = joinpath(dirname(@__DIR__), "lib", subpkg) - return Pkg.develop(PackageSpec(path = subpkg_path)) -end - -function activate_subpkg_env(subpkg) - subpkg_path = joinpath(dirname(@__DIR__), "lib", subpkg) - Pkg.activate(subpkg_path) - Pkg.develop(PackageSpec(path = subpkg_path)) - return Pkg.instantiate() -end - function activate_nopre_env() Pkg.activate(joinpath(@__DIR__, "nopre")) Pkg.develop(PackageSpec(path = dirname(@__DIR__))) return Pkg.instantiate() end +# GROUP can name a sublibrary (e.g. "DataDrivenDMD" -> Core test group) or +# "{sublibrary}_{TEST_GROUP}" for a custom group (e.g. "DataDrivenDMD_QA"). +# Sublibraries declare any non-default groups in test/test_groups.toml; the +# DATADRIVENDIFFEQ_TEST_GROUP env var threads the group into the sublib's +# own runtests.jl. CI dispatches sublibraries through SublibraryCI.yml, so +# this branch is primarily for running a sublibrary's suite locally. +function _detect_sublibrary_group(group, lib_dir) + isdir(joinpath(lib_dir, group)) && return (group, "Core") + for i in length(group):-1:1 + if group[i] == '_' && isdir(joinpath(lib_dir, group[1:(i - 1)])) + return (group[1:(i - 1)], group[(i + 1):end]) + end + end + return (group, "Core") +end + @time begin - if GROUP == "All" || GROUP == "Core" || GROUP == "Downstream" + lib_dir = joinpath(dirname(@__DIR__), "lib") + base_group, test_group = _detect_sublibrary_group(GROUP, lib_dir) + + if isdir(joinpath(lib_dir, base_group)) + Pkg.activate(joinpath(lib_dir, base_group)) + # On Julia < 1.11 the [sources] section is not honored; develop the + # in-repo path dependencies (transitively) so the sublibrary tests run + # against this checkout of DataDrivenDiffEq rather than a released one. + if VERSION < v"1.11.0-DEV.0" + developed = Set{String}() + push!(developed, normpath(joinpath(lib_dir, base_group))) + specs = Pkg.PackageSpec[] + queue = [joinpath(lib_dir, base_group)] + while !isempty(queue) + pkg_dir = popfirst!(queue) + toml_path = joinpath(pkg_dir, "Project.toml") + isfile(toml_path) || continue + toml = Pkg.TOML.parsefile(toml_path) + if haskey(toml, "sources") + for (dep_name, source_spec) in toml["sources"] + if source_spec isa Dict && haskey(source_spec, "path") + dep_path = normpath(joinpath(pkg_dir, source_spec["path"])) + if isdir(dep_path) && !(dep_path in developed) + push!(developed, dep_path) + @info "Queuing local source dependency" dep_name dep_path + push!(specs, Pkg.PackageSpec(path = dep_path)) + push!(queue, dep_path) + end + end + end + end + end + isempty(specs) || Pkg.develop(specs) + end + withenv("DATADRIVENDIFFEQ_TEST_GROUP" => test_group) do + Pkg.test(base_group, coverage = true) + end + elseif GROUP == "nopre" + # nopre tests are excluded from Julia pre-release versions in CI + # to avoid failures from upstream changes (e.g., JET type inference) + activate_nopre_env() + @safetestset "JET Static Analysis" begin + include("nopre/jet_tests.jl") + end + elseif GROUP == "All" || GROUP == "Core" || GROUP == "Downstream" @testset "All" begin @safetestset "Basis" begin include("./basis/basis.jl") @@ -47,16 +95,5 @@ end include("./commonsolve/commonsolve.jl") end end - elseif GROUP == "nopre" - # nopre tests are excluded from Julia pre-release versions in CI - # to avoid failures from upstream changes (e.g., JET type inference) - activate_nopre_env() - @safetestset "JET Static Analysis" begin - include("nopre/jet_tests.jl") - end - else - dev_subpkg(GROUP) - subpkg_path = joinpath(dirname(@__DIR__), "lib", GROUP) - Pkg.test(PackageSpec(name = GROUP, path = subpkg_path); coverage = true) end end From 15edd0907af0f4f56946639cf703ef24b619f29b Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Sun, 7 Jun 2026 20:27:56 -0400 Subject: [PATCH 2/8] Add README.md to each lib/* sublibrary Match the OrdinaryDiffEq canonical monorepo style: every sublibrary gets a README with the standard SciML badge block (Zulip, Global Docs, ColPrac, SciML Code Style) and the "component of the DataDrivenDiffEq.jl monorepo" wording, plus a one-line description of the sublibrary's role and a link to the DataDrivenDiffEq documentation. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- lib/DataDrivenDMD/README.md | 12 ++++++++++++ lib/DataDrivenLux/README.md | 12 ++++++++++++ lib/DataDrivenSR/README.md | 12 ++++++++++++ lib/DataDrivenSparse/README.md | 12 ++++++++++++ 4 files changed, 48 insertions(+) create mode 100644 lib/DataDrivenDMD/README.md create mode 100644 lib/DataDrivenLux/README.md create mode 100644 lib/DataDrivenSR/README.md create mode 100644 lib/DataDrivenSparse/README.md diff --git a/lib/DataDrivenDMD/README.md b/lib/DataDrivenDMD/README.md new file mode 100644 index 000000000..dd66bc1c6 --- /dev/null +++ b/lib/DataDrivenDMD/README.md @@ -0,0 +1,12 @@ +# DataDrivenDMD.jl + +[![Join the chat at https://julialang.zulipchat.com #sciml-bridged](https://img.shields.io/static/v1?label=Zulip&message=chat&color=9558b2&labelColor=389826)](https://julialang.zulipchat.com/#narrow/stream/279055-sciml-bridged) +[![Global Docs](https://img.shields.io/badge/docs-SciML-blue.svg)](https://docs.sciml.ai/DataDrivenDiffEq/stable/) + +[![ColPrac: Contributor's Guide on Collaborative Practices for Community Packages](https://img.shields.io/badge/ColPrac-Contributor%27s%20Guide-blueviolet)](https://github.com/SciML/ColPrac) +[![SciML Code Style](https://img.shields.io/static/v1?label=code%20style&message=SciML&color=9558b2&labelColor=389826)](https://github.com/SciML/SciMLStyle) + +DataDrivenDMD.jl is a component of the [DataDrivenDiffEq.jl](https://github.com/SciML/DataDrivenDiffEq.jl) monorepo. Dynamic Mode Decomposition (DMD) and Koopman-based methods for discovering linear operator approximations of dynamical systems from data. +While completely independent and usable on its own, users wanting the full data-driven modeling suite should use [DataDrivenDiffEq.jl](https://github.com/SciML/DataDrivenDiffEq.jl). + +For a full description of the methods and their options, see the [DataDrivenDiffEq documentation](https://docs.sciml.ai/DataDrivenDiffEq/stable/). diff --git a/lib/DataDrivenLux/README.md b/lib/DataDrivenLux/README.md new file mode 100644 index 000000000..8f00d27eb --- /dev/null +++ b/lib/DataDrivenLux/README.md @@ -0,0 +1,12 @@ +# DataDrivenLux.jl + +[![Join the chat at https://julialang.zulipchat.com #sciml-bridged](https://img.shields.io/static/v1?label=Zulip&message=chat&color=9558b2&labelColor=389826)](https://julialang.zulipchat.com/#narrow/stream/279055-sciml-bridged) +[![Global Docs](https://img.shields.io/badge/docs-SciML-blue.svg)](https://docs.sciml.ai/DataDrivenDiffEq/stable/) + +[![ColPrac: Contributor's Guide on Collaborative Practices for Community Packages](https://img.shields.io/badge/ColPrac-Contributor%27s%20Guide-blueviolet)](https://github.com/SciML/ColPrac) +[![SciML Code Style](https://img.shields.io/static/v1?label=code%20style&message=SciML&color=9558b2&labelColor=389826)](https://github.com/SciML/SciMLStyle) + +DataDrivenLux.jl is a component of the [DataDrivenDiffEq.jl](https://github.com/SciML/DataDrivenDiffEq.jl) monorepo. Deep-learning-based structure search, built on Lux.jl, for discovering governing equations via differentiable directed-acyclic-graph candidate models. +While completely independent and usable on its own, users wanting the full data-driven modeling suite should use [DataDrivenDiffEq.jl](https://github.com/SciML/DataDrivenDiffEq.jl). + +For a full description of the methods and their options, see the [DataDrivenDiffEq documentation](https://docs.sciml.ai/DataDrivenDiffEq/stable/). diff --git a/lib/DataDrivenSR/README.md b/lib/DataDrivenSR/README.md new file mode 100644 index 000000000..3187d7cb0 --- /dev/null +++ b/lib/DataDrivenSR/README.md @@ -0,0 +1,12 @@ +# DataDrivenSR.jl + +[![Join the chat at https://julialang.zulipchat.com #sciml-bridged](https://img.shields.io/static/v1?label=Zulip&message=chat&color=9558b2&labelColor=389826)](https://julialang.zulipchat.com/#narrow/stream/279055-sciml-bridged) +[![Global Docs](https://img.shields.io/badge/docs-SciML-blue.svg)](https://docs.sciml.ai/DataDrivenDiffEq/stable/) + +[![ColPrac: Contributor's Guide on Collaborative Practices for Community Packages](https://img.shields.io/badge/ColPrac-Contributor%27s%20Guide-blueviolet)](https://github.com/SciML/ColPrac) +[![SciML Code Style](https://img.shields.io/static/v1?label=code%20style&message=SciML&color=9558b2&labelColor=389826)](https://github.com/SciML/SciMLStyle) + +DataDrivenSR.jl is a component of the [DataDrivenDiffEq.jl](https://github.com/SciML/DataDrivenDiffEq.jl) monorepo. Symbolic regression methods, built on SymbolicRegression.jl, for discovering closed-form governing equations from data. +While completely independent and usable on its own, users wanting the full data-driven modeling suite should use [DataDrivenDiffEq.jl](https://github.com/SciML/DataDrivenDiffEq.jl). + +For a full description of the methods and their options, see the [DataDrivenDiffEq documentation](https://docs.sciml.ai/DataDrivenDiffEq/stable/). diff --git a/lib/DataDrivenSparse/README.md b/lib/DataDrivenSparse/README.md new file mode 100644 index 000000000..2100d5562 --- /dev/null +++ b/lib/DataDrivenSparse/README.md @@ -0,0 +1,12 @@ +# DataDrivenSparse.jl + +[![Join the chat at https://julialang.zulipchat.com #sciml-bridged](https://img.shields.io/static/v1?label=Zulip&message=chat&color=9558b2&labelColor=389826)](https://julialang.zulipchat.com/#narrow/stream/279055-sciml-bridged) +[![Global Docs](https://img.shields.io/badge/docs-SciML-blue.svg)](https://docs.sciml.ai/DataDrivenDiffEq/stable/) + +[![ColPrac: Contributor's Guide on Collaborative Practices for Community Packages](https://img.shields.io/badge/ColPrac-Contributor%27s%20Guide-blueviolet)](https://github.com/SciML/ColPrac) +[![SciML Code Style](https://img.shields.io/static/v1?label=code%20style&message=SciML&color=9558b2&labelColor=389826)](https://github.com/SciML/SciMLStyle) + +DataDrivenSparse.jl is a component of the [DataDrivenDiffEq.jl](https://github.com/SciML/DataDrivenDiffEq.jl) monorepo. Sparse regression methods (e.g. SINDy, STLSQ, ADMM) for discovering parsimonious governing equations from data. +While completely independent and usable on its own, users wanting the full data-driven modeling suite should use [DataDrivenDiffEq.jl](https://github.com/SciML/DataDrivenDiffEq.jl). + +For a full description of the methods and their options, see the [DataDrivenDiffEq documentation](https://docs.sciml.ai/DataDrivenDiffEq/stable/). From 29156471d8fe5ac76d41e9e92a67503361d2b9d7 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Sun, 7 Jun 2026 20:28:11 -0400 Subject: [PATCH 3/8] Rename LICENSE -> LICENSE.md (root and all lib/* sublibraries) Match the OrdinaryDiffEq canonical monorepo style, where the root and every sublibrary ship a LICENSE.md. Content is preserved verbatim (git mv). Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- LICENSE => LICENSE.md | 0 lib/DataDrivenDMD/{LICENSE => LICENSE.md} | 0 lib/DataDrivenLux/{LICENSE => LICENSE.md} | 0 lib/DataDrivenSR/{LICENSE => LICENSE.md} | 0 lib/DataDrivenSparse/{LICENSE => LICENSE.md} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename LICENSE => LICENSE.md (100%) rename lib/DataDrivenDMD/{LICENSE => LICENSE.md} (100%) rename lib/DataDrivenLux/{LICENSE => LICENSE.md} (100%) rename lib/DataDrivenSR/{LICENSE => LICENSE.md} (100%) rename lib/DataDrivenSparse/{LICENSE => LICENSE.md} (100%) diff --git a/LICENSE b/LICENSE.md similarity index 100% rename from LICENSE rename to LICENSE.md diff --git a/lib/DataDrivenDMD/LICENSE b/lib/DataDrivenDMD/LICENSE.md similarity index 100% rename from lib/DataDrivenDMD/LICENSE rename to lib/DataDrivenDMD/LICENSE.md diff --git a/lib/DataDrivenLux/LICENSE b/lib/DataDrivenLux/LICENSE.md similarity index 100% rename from lib/DataDrivenLux/LICENSE rename to lib/DataDrivenLux/LICENSE.md diff --git a/lib/DataDrivenSR/LICENSE b/lib/DataDrivenSR/LICENSE.md similarity index 100% rename from lib/DataDrivenSR/LICENSE rename to lib/DataDrivenSR/LICENSE.md diff --git a/lib/DataDrivenSparse/LICENSE b/lib/DataDrivenSparse/LICENSE.md similarity index 100% rename from lib/DataDrivenSparse/LICENSE rename to lib/DataDrivenSparse/LICENSE.md From c9bbc6b800b0ebbe8b31bfed9b36320fd13614fb Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Sun, 7 Jun 2026 20:30:03 -0400 Subject: [PATCH 4/8] ci: canonical TagBot (with subpackages) and Downstream/IntegrationTest TagBot.yml: adopt the OrdinaryDiffEq canonical form -- top-level permissions block, workflow_dispatch.inputs.lookback default "3", a root TagBot-DataDrivenDiffEq job, and a TagBot-Subpackages matrix (fail-fast:false) over the four registered sublibraries (DataDrivenDMD, DataDrivenLux, DataDrivenSR, DataDrivenSparse), each tagging via subdir: lib/. All four are registered in the General registry. Downstream.yml (IntegrationTest): add the canonical downstream integration workflow. Develops the root umbrella DataDrivenDiffEq plus every lib/* sublibrary, then runs the downstream repo's tests; ResolverError is treated as an intentional breaking change (exit 0). Matrix covers the external General dependents SymbolicNumericIntegration.jl and ODINN.jl. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/Downstream.yml | 62 ++++++++++++++++++++++++++++++++ .github/workflows/TagBot.yml | 43 ++++++++++++++++++++-- 2 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/Downstream.yml diff --git a/.github/workflows/Downstream.yml b/.github/workflows/Downstream.yml new file mode 100644 index 000000000..8542fadf1 --- /dev/null +++ b/.github/workflows/Downstream.yml @@ -0,0 +1,62 @@ +name: IntegrationTest +on: + push: + branches: [master] + tags: [v*] + pull_request: +concurrency: + # Skip intermediate builds: always. + # Cancel intermediate builds: only if it is a pull request build. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} +jobs: + test: + name: ${{ matrix.package.repo }}/${{ matrix.package.group }}/${{ matrix.julia-version }} + runs-on: ${{ matrix.os }} + env: + GROUP: ${{ matrix.package.group }} + strategy: + fail-fast: false + matrix: + julia-version: ['1.10'] + os: [ubuntu-latest] + package: + - {user: SciML, repo: SymbolicNumericIntegration.jl, group: All} + - {user: ODINN-SciML, repo: ODINN.jl, group: Core1} + + steps: + - uses: actions/checkout@v6 + - uses: julia-actions/setup-julia@v3 + with: + version: ${{ matrix.julia-version }} + arch: x64 + - name: Clone Downstream + uses: actions/checkout@v6 + with: + repository: ${{ matrix.package.user }}/${{ matrix.package.repo }} + path: downstream + - name: Load this and run the downstream tests + shell: julia --color=yes --project=downstream {0} + run: | + using Pkg + try + # Develop the root umbrella DataDrivenDiffEq plus every lib/* sublibrary + # so the downstream tests run against this checkout rather than releases. + Pkg.develop(PackageSpec(path=".")); + Pkg.develop(map(path ->Pkg.PackageSpec.(;path="lib/$(path)"), readdir("./lib"))); + Pkg.test(coverage=true) # resolver may fail with test time deps + catch err + err isa Pkg.Resolve.ResolverError || rethrow() + # If we can't resolve that means this is incompatible by SemVer and this is fine + # It means we marked this as a breaking change, so we don't need to worry about + # mistakenly introducing a breaking change, as we have intentionally made one + @info "Not compatible with this release. No problem." exception=err + exit(0) # Exit immediately, as a success + end + - uses: julia-actions/julia-processcoverage@v1 + - uses: codecov/codecov-action@v6 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: lcov.info + fail_ci_if_error: false + disable_safe_directory: true diff --git a/.github/workflows/TagBot.yml b/.github/workflows/TagBot.yml index f49313b66..1b97463fe 100644 --- a/.github/workflows/TagBot.yml +++ b/.github/workflows/TagBot.yml @@ -1,15 +1,54 @@ name: TagBot + on: issue_comment: types: - created workflow_dispatch: + inputs: + lookback: + default: "3" + +permissions: + actions: read + checks: read + contents: write + deployments: read + issues: read + discussions: read + packages: read + pages: read + pull-requests: read + repository-projects: read + security-events: read + statuses: read + jobs: - TagBot: + TagBot-DataDrivenDiffEq: if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot' runs-on: ubuntu-latest steps: - - uses: JuliaRegistries/TagBot@v1 + - name: Tag DataDrivenDiffEq + uses: JuliaRegistries/TagBot@v1 with: token: ${{ secrets.GITHUB_TOKEN }} ssh: ${{ secrets.DOCUMENTER_KEY }} + + TagBot-Subpackages: + if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot' + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + package: + - DataDrivenDMD + - DataDrivenLux + - DataDrivenSR + - DataDrivenSparse + steps: + - name: Tag ${{ matrix.package }} + uses: JuliaRegistries/TagBot@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + ssh: ${{ secrets.DOCUMENTER_KEY }} + subdir: "lib/${{ matrix.package }}" From 3822495581cbeffe4efecf5a17ee0d44515aaf71 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Sun, 7 Jun 2026 20:34:26 -0400 Subject: [PATCH 5/8] compat: complete sublibrary [compat] bounds and bump DataDrivenDiffEq to 1.15 Every lib/* sublibrary now has a [compat] entry for each [deps] and [extras] package, removing the implicit-unbounded test/stdlib dependencies: - DataDrivenDMD: add LinearAlgebra, SafeTestsets, StableRNGs, StatsBase, Test. - DataDrivenLux: add Distributed, LinearAlgebra, Logging, Random, SafeTestsets, StableRNGs, Test. - DataDrivenSparse: add LinearAlgebra, Printf, Random, SafeTestsets, StableRNGs, StatsBase, Test. - DataDrivenSR: add StableRNGs, StatsBase, Test. Stdlib bounds track the julia = "1.10" floor ("1.10"); SafeTestsets = "0.1", StableRNGs = "1", StatsBase = "0.34". Bump the DataDrivenDiffEq compat floor in each sublibrary from "1.14" to "1.15" to match the in-repo umbrella version (1.15.0). All four sublibraries resolve against the in-repo umbrella via their [sources] path entries (verified with Pkg.resolve on Julia 1.11). No floors lowered; only additions and the umbrella-matching raise. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- lib/DataDrivenDMD/Project.toml | 7 ++++++- lib/DataDrivenLux/Project.toml | 11 +++++++++-- lib/DataDrivenSR/Project.toml | 5 ++++- lib/DataDrivenSparse/Project.toml | 11 +++++++++-- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/lib/DataDrivenDMD/Project.toml b/lib/DataDrivenDMD/Project.toml index 3d37dae8d..53280ed5e 100644 --- a/lib/DataDrivenDMD/Project.toml +++ b/lib/DataDrivenDMD/Project.toml @@ -11,9 +11,14 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" DataDrivenDiffEq = {path = "../.."} [compat] -DataDrivenDiffEq = "1.14" +DataDrivenDiffEq = "1.15" +LinearAlgebra = "1.10" OrdinaryDiffEq = "6, 7" OrdinaryDiffEqFunctionMap = "1, 2" +SafeTestsets = "0.1" +StableRNGs = "1" +StatsBase = "0.34" +Test = "1.10" julia = "1.10" [extras] diff --git a/lib/DataDrivenLux/Project.toml b/lib/DataDrivenLux/Project.toml index ee51e4232..aa6675bee 100644 --- a/lib/DataDrivenLux/Project.toml +++ b/lib/DataDrivenLux/Project.toml @@ -39,21 +39,28 @@ ChainRulesCore = "1.15" CommonSolve = "0.2.4" ComponentArrays = "0.15" ConcreteStructs = "0.2.3" -DataDrivenDiffEq = "1.14" -OrdinaryDiffEq = "6, 7" +DataDrivenDiffEq = "1.15" +Distributed = "1.10" Distributions = "0.25" DistributionsAD = "0.6" DocStringExtensions = "0.9.3" ForwardDiff = "0.10, 1" IntervalArithmetic = "0.22, 0.23, 1" InverseFunctions = "0.1" +LinearAlgebra = "1.10" +Logging = "1.10" Lux = "1" LuxCore = "1" Optim = "1.7, 2" Optimisers = "0.3, 0.4" +OrdinaryDiffEq = "6, 7" ProgressMeter = "1.7" +Random = "1.10" +SafeTestsets = "0.1" Setfield = "1" +StableRNGs = "1" StatsBase = "0.34.3" +Test = "1.10" TransformVariables = "0.8" WeightInitializers = "1" julia = "1.10" diff --git a/lib/DataDrivenSR/Project.toml b/lib/DataDrivenSR/Project.toml index f1c377097..dcff83e5a 100644 --- a/lib/DataDrivenSR/Project.toml +++ b/lib/DataDrivenSR/Project.toml @@ -12,9 +12,12 @@ SymbolicRegression = "8254be44-1295-4e6a-a16d-46603ac705cb" DataDrivenDiffEq = {path = "../.."} [compat] +DataDrivenDiffEq = "1.15" Reexport = "1.2" -DataDrivenDiffEq = "1.14" +StableRNGs = "1" +StatsBase = "0.34" SymbolicRegression = "1" +Test = "1.10" julia = "1.10" [extras] diff --git a/lib/DataDrivenSparse/Project.toml b/lib/DataDrivenSparse/Project.toml index 744560256..0ae180704 100644 --- a/lib/DataDrivenSparse/Project.toml +++ b/lib/DataDrivenSparse/Project.toml @@ -13,10 +13,17 @@ Reexport = "189a3867-3050-52da-a836-e630ba90ab69" DataDrivenDiffEq = {path = "../.."} [compat] -julia = "1.10" -DataDrivenDiffEq = "1.14" +DataDrivenDiffEq = "1.15" +LinearAlgebra = "1.10" OrdinaryDiffEq = "6, 7" +Printf = "1.10" +Random = "1.10" Reexport = "1.2" +SafeTestsets = "0.1" +StableRNGs = "1" +StatsBase = "0.34" +Test = "1.10" +julia = "1.10" [extras] OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" From 1540e530cd59651139135617fed2d00ab082eed7 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Sun, 7 Jun 2026 20:39:22 -0400 Subject: [PATCH 6/8] compat: complete root [compat] bounds for deps and test extras Add the missing [compat] entries so every root [deps] and [extras] package is bounded, matching the canonical fully-bounded monorepo style: LinearAlgebra, Random, Pkg, Test = "1" (stdlibs, consistent with the existing Statistics = "1") and SafeTestsets = "0.1". Root environment resolves cleanly with these bounds (verified with Pkg.resolve on Julia 1.11). Only additions; no floors lowered. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- Project.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Project.toml b/Project.toml index c91786457..19fb01491 100644 --- a/Project.toml +++ b/Project.toml @@ -31,15 +31,19 @@ CommonSolve = "0.2" DataInterpolations = "4, 5, 6, 7, 8" DiffEqBase = "6.211, 7" DocStringExtensions = "0.7, 0.8, 0.9" +LinearAlgebra = "1" MLUtils = "0.3, 0.4" ModelingToolkit = "11.21.0" OrdinaryDiffEqTsit5 = "1, 2" Parameters = "0.12.1" +Pkg = "1" PrecompileTools = "1" ProgressMeter = "1.6" QuadGK = "2.4" +Random = "1" RecipesBase = "1" Reexport = "1.0" +SafeTestsets = "0.1" SciMLBase = "2.155, 3" SciMLStructures = "1" Setfield = "1" @@ -47,6 +51,7 @@ Statistics = "1" StatsBase = "0.32.0, 0.33, 0.34" SymbolicUtils = "4" Symbolics = "7" +Test = "1" julia = "1.10" [extras] From 9ebaa90c98f9ac870faade7ade59c00ce956854f Mon Sep 17 00:00:00 2001 From: Chris Rackauckas Date: Mon, 8 Jun 2026 03:40:51 -0400 Subject: [PATCH 7/8] test: restructure into canonical GROUP-FOLDER layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move every test group's files into test// folders, per the OrdinaryDiffEq canonical dependency-driven group model, at both the root package and each lib/* sublibrary. Root (DataDrivenDiffEq): - Functional tests (basis, problem, solution, commonsolve, utils) move from their scattered subfolders into test/Core/; runtests.jl includes them from Core/. Core is the base-env group and the only group in All. - The nopre group (JET static analysis) already lives in test/nopre/ with its own Project.toml (JET) — a dep-adding group excluded from All. Its name stays lowercase to match the lowercase nopre input in CI.yml. - Add test/test_groups.toml declaring Core [lts,1,pre] and nopre [lts,1]. Sublibraries (DataDrivenDMD, DataDrivenLux, DataDrivenSparse, DataDrivenSR): - Each runs only a functional Core group (no QA tooling, no GPU). Move the Core test files into lib//test/Core/ and include from there. DataDrivenSR's inline runtests body is extracted to Core/symbolic_regression.jl. Core adds no deps beyond the base test set, so no per-group Project.toml is introduced. - Normalize each test_groups.toml Core version matrix from [lts,1.11,1,pre] to the canonical [lts,1,pre]. No compat floors lowered, no tests skipped/broken/loosened; every test that previously ran still runs in exactly one group. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- .../test/{ => Core}/linear_autonomous.jl | 0 .../test/{ => Core}/linear_forced.jl | 0 .../test/{ => Core}/nonlinear_autonomous.jl | 0 .../test/{ => Core}/nonlinear_forced.jl | 0 lib/DataDrivenDMD/test/runtests.jl | 8 +-- lib/DataDrivenDMD/test/test_groups.toml | 2 +- lib/DataDrivenLux/test/{ => Core}/cache.jl | 0 .../test/{ => Core}/candidate.jl | 0 .../test/{ => Core}/crossentropy_solve.jl | 0 lib/DataDrivenLux/test/{ => Core}/graphs.jl | 0 lib/DataDrivenLux/test/{ => Core}/layers.jl | 0 lib/DataDrivenLux/test/{ => Core}/nodes.jl | 0 .../test/{ => Core}/randomsearch_solve.jl | 0 .../test/{ => Core}/reinforce_solve.jl | 0 lib/DataDrivenLux/test/runtests.jl | 16 ++--- lib/DataDrivenLux/test/test_groups.toml | 2 +- .../test/Core/symbolic_regression.jl | 62 +++++++++++++++++++ lib/DataDrivenSR/test/runtests.jl | 60 +----------------- lib/DataDrivenSR/test/test_groups.toml | 2 +- .../test/{ => Core}/cartpole.jl | 0 .../test/{ => Core}/michaelis_menten.jl | 0 .../test/{ => Core}/pendulum.jl | 0 .../test/{ => Core}/sparse_linear_solve.jl | 0 lib/DataDrivenSparse/test/runtests.jl | 8 +-- lib/DataDrivenSparse/test/test_groups.toml | 2 +- test/{basis => Core}/basis.jl | 0 test/{commonsolve => Core}/commonsolve.jl | 0 test/{basis => Core}/generators.jl | 0 test/{basis => Core}/implicit_basis.jl | 0 test/{problem => Core}/problem.jl | 0 test/{problem => Core}/samplers.jl | 0 test/{solution => Core}/solution.jl | 0 test/{ => Core}/utils.jl | 0 test/runtests.jl | 14 ++--- test/test_groups.toml | 12 ++++ 35 files changed, 103 insertions(+), 85 deletions(-) rename lib/DataDrivenDMD/test/{ => Core}/linear_autonomous.jl (100%) rename lib/DataDrivenDMD/test/{ => Core}/linear_forced.jl (100%) rename lib/DataDrivenDMD/test/{ => Core}/nonlinear_autonomous.jl (100%) rename lib/DataDrivenDMD/test/{ => Core}/nonlinear_forced.jl (100%) rename lib/DataDrivenLux/test/{ => Core}/cache.jl (100%) rename lib/DataDrivenLux/test/{ => Core}/candidate.jl (100%) rename lib/DataDrivenLux/test/{ => Core}/crossentropy_solve.jl (100%) rename lib/DataDrivenLux/test/{ => Core}/graphs.jl (100%) rename lib/DataDrivenLux/test/{ => Core}/layers.jl (100%) rename lib/DataDrivenLux/test/{ => Core}/nodes.jl (100%) rename lib/DataDrivenLux/test/{ => Core}/randomsearch_solve.jl (100%) rename lib/DataDrivenLux/test/{ => Core}/reinforce_solve.jl (100%) create mode 100644 lib/DataDrivenSR/test/Core/symbolic_regression.jl rename lib/DataDrivenSparse/test/{ => Core}/cartpole.jl (100%) rename lib/DataDrivenSparse/test/{ => Core}/michaelis_menten.jl (100%) rename lib/DataDrivenSparse/test/{ => Core}/pendulum.jl (100%) rename lib/DataDrivenSparse/test/{ => Core}/sparse_linear_solve.jl (100%) rename test/{basis => Core}/basis.jl (100%) rename test/{commonsolve => Core}/commonsolve.jl (100%) rename test/{basis => Core}/generators.jl (100%) rename test/{basis => Core}/implicit_basis.jl (100%) rename test/{problem => Core}/problem.jl (100%) rename test/{problem => Core}/samplers.jl (100%) rename test/{solution => Core}/solution.jl (100%) rename test/{ => Core}/utils.jl (100%) create mode 100644 test/test_groups.toml diff --git a/lib/DataDrivenDMD/test/linear_autonomous.jl b/lib/DataDrivenDMD/test/Core/linear_autonomous.jl similarity index 100% rename from lib/DataDrivenDMD/test/linear_autonomous.jl rename to lib/DataDrivenDMD/test/Core/linear_autonomous.jl diff --git a/lib/DataDrivenDMD/test/linear_forced.jl b/lib/DataDrivenDMD/test/Core/linear_forced.jl similarity index 100% rename from lib/DataDrivenDMD/test/linear_forced.jl rename to lib/DataDrivenDMD/test/Core/linear_forced.jl diff --git a/lib/DataDrivenDMD/test/nonlinear_autonomous.jl b/lib/DataDrivenDMD/test/Core/nonlinear_autonomous.jl similarity index 100% rename from lib/DataDrivenDMD/test/nonlinear_autonomous.jl rename to lib/DataDrivenDMD/test/Core/nonlinear_autonomous.jl diff --git a/lib/DataDrivenDMD/test/nonlinear_forced.jl b/lib/DataDrivenDMD/test/Core/nonlinear_forced.jl similarity index 100% rename from lib/DataDrivenDMD/test/nonlinear_forced.jl rename to lib/DataDrivenDMD/test/Core/nonlinear_forced.jl diff --git a/lib/DataDrivenDMD/test/runtests.jl b/lib/DataDrivenDMD/test/runtests.jl index 175f64b26..81d9ddb21 100644 --- a/lib/DataDrivenDMD/test/runtests.jl +++ b/lib/DataDrivenDMD/test/runtests.jl @@ -10,16 +10,16 @@ const GROUP = get(ENV, "DATADRIVENDIFFEQ_TEST_GROUP", get(ENV, "GROUP", "All")) @time begin if GROUP == "All" || GROUP == "Core" || GROUP == "DataDrivenDMD" @safetestset "Linear autonomous" begin - include("./linear_autonomous.jl") + include("./Core/linear_autonomous.jl") end @safetestset "Linear forced" begin - include("./linear_forced.jl") + include("./Core/linear_forced.jl") end @safetestset "Nonlinear autonomous" begin - include("./nonlinear_autonomous.jl") + include("./Core/nonlinear_autonomous.jl") end @safetestset "Nonlinear forced" begin - include("./nonlinear_forced.jl") + include("./Core/nonlinear_forced.jl") end end end diff --git a/lib/DataDrivenDMD/test/test_groups.toml b/lib/DataDrivenDMD/test/test_groups.toml index 3ab133501..8f657c062 100644 --- a/lib/DataDrivenDMD/test/test_groups.toml +++ b/lib/DataDrivenDMD/test/test_groups.toml @@ -1,4 +1,4 @@ # Each sublibrary only defines functional ("Core") tests; there are no QA # (Aqua/JET/AllocCheck) suites here, so the default QA group is not declared. [Core] -versions = ["lts", "1.11", "1", "pre"] +versions = ["lts", "1", "pre"] diff --git a/lib/DataDrivenLux/test/cache.jl b/lib/DataDrivenLux/test/Core/cache.jl similarity index 100% rename from lib/DataDrivenLux/test/cache.jl rename to lib/DataDrivenLux/test/Core/cache.jl diff --git a/lib/DataDrivenLux/test/candidate.jl b/lib/DataDrivenLux/test/Core/candidate.jl similarity index 100% rename from lib/DataDrivenLux/test/candidate.jl rename to lib/DataDrivenLux/test/Core/candidate.jl diff --git a/lib/DataDrivenLux/test/crossentropy_solve.jl b/lib/DataDrivenLux/test/Core/crossentropy_solve.jl similarity index 100% rename from lib/DataDrivenLux/test/crossentropy_solve.jl rename to lib/DataDrivenLux/test/Core/crossentropy_solve.jl diff --git a/lib/DataDrivenLux/test/graphs.jl b/lib/DataDrivenLux/test/Core/graphs.jl similarity index 100% rename from lib/DataDrivenLux/test/graphs.jl rename to lib/DataDrivenLux/test/Core/graphs.jl diff --git a/lib/DataDrivenLux/test/layers.jl b/lib/DataDrivenLux/test/Core/layers.jl similarity index 100% rename from lib/DataDrivenLux/test/layers.jl rename to lib/DataDrivenLux/test/Core/layers.jl diff --git a/lib/DataDrivenLux/test/nodes.jl b/lib/DataDrivenLux/test/Core/nodes.jl similarity index 100% rename from lib/DataDrivenLux/test/nodes.jl rename to lib/DataDrivenLux/test/Core/nodes.jl diff --git a/lib/DataDrivenLux/test/randomsearch_solve.jl b/lib/DataDrivenLux/test/Core/randomsearch_solve.jl similarity index 100% rename from lib/DataDrivenLux/test/randomsearch_solve.jl rename to lib/DataDrivenLux/test/Core/randomsearch_solve.jl diff --git a/lib/DataDrivenLux/test/reinforce_solve.jl b/lib/DataDrivenLux/test/Core/reinforce_solve.jl similarity index 100% rename from lib/DataDrivenLux/test/reinforce_solve.jl rename to lib/DataDrivenLux/test/Core/reinforce_solve.jl diff --git a/lib/DataDrivenLux/test/runtests.jl b/lib/DataDrivenLux/test/runtests.jl index c28ead4e5..f3a27c553 100644 --- a/lib/DataDrivenLux/test/runtests.jl +++ b/lib/DataDrivenLux/test/runtests.jl @@ -10,20 +10,20 @@ const GROUP = get(ENV, "DATADRIVENDIFFEQ_TEST_GROUP", get(ENV, "GROUP", "All")) @testset "DataDrivenLux" begin if GROUP == "All" || GROUP == "Core" || GROUP == "DataDrivenLux" @testset "Lux" begin - @safetestset "Nodes" include("nodes.jl") - @safetestset "Layers" include("layers.jl") - @safetestset "Graphs" include("graphs.jl") + @safetestset "Nodes" include("Core/nodes.jl") + @safetestset "Layers" include("Core/layers.jl") + @safetestset "Graphs" include("Core/graphs.jl") end @testset "Caches" begin - @safetestset "Candidate" include("candidate.jl") - @safetestset "Cache" include("cache.jl") + @safetestset "Candidate" include("Core/candidate.jl") + @safetestset "Cache" include("Core/cache.jl") end @testset "Algorithms" begin - @safetestset "RandomSearch" include("randomsearch_solve.jl") - @safetestset "Reinforce" include("reinforce_solve.jl") - @safetestset "CrossEntropy" include("crossentropy_solve.jl") + @safetestset "RandomSearch" include("Core/randomsearch_solve.jl") + @safetestset "Reinforce" include("Core/reinforce_solve.jl") + @safetestset "CrossEntropy" include("Core/crossentropy_solve.jl") end end end diff --git a/lib/DataDrivenLux/test/test_groups.toml b/lib/DataDrivenLux/test/test_groups.toml index 3ab133501..8f657c062 100644 --- a/lib/DataDrivenLux/test/test_groups.toml +++ b/lib/DataDrivenLux/test/test_groups.toml @@ -1,4 +1,4 @@ # Each sublibrary only defines functional ("Core") tests; there are no QA # (Aqua/JET/AllocCheck) suites here, so the default QA group is not declared. [Core] -versions = ["lts", "1.11", "1", "pre"] +versions = ["lts", "1", "pre"] diff --git a/lib/DataDrivenSR/test/Core/symbolic_regression.jl b/lib/DataDrivenSR/test/Core/symbolic_regression.jl new file mode 100644 index 000000000..be923bb8b --- /dev/null +++ b/lib/DataDrivenSR/test/Core/symbolic_regression.jl @@ -0,0 +1,62 @@ +using DataDrivenDiffEq +using DataDrivenSR +using Test +using StableRNGs + +rng = StableRNG(42) +X = rand(rng, 2, 50) + +@testset "Simple" begin + alg = DataDrivenSR.EQSearch( + eq_options = Options( + unary_operators = [sin, exp], + binary_operators = [*], maxdepth = 1, + seed = 42, + verbosity = -1, progress = false + ) + ) + f(x) = [sin(x[1]); exp(x[2])] + Y = hcat(map(f, eachcol(X))...) + prob = DirectDataDrivenProblem(X, Y) + res = solve(prob, alg) + @test r2(res) >= 0.95 + @test rss(res) <= 1.0e-5 +end + +@testset "Univariate" begin + alg = DataDrivenSR.EQSearch( + eq_options = Options( + unary_operators = [sin, exp], + binary_operators = [*], maxdepth = 1, + seed = 42, + verbosity = -1, progress = false + ) + ) + + Y = sin.(X[1:1, :]) + prob = DirectDataDrivenProblem(X, Y) + res = solve(prob, alg) + @test r2(res) >= 0.95 + @test rss(res) <= 1.0e-5 +end + +@testset "Lifted" begin + alg = DataDrivenSR.EQSearch( + eq_options = Options( + unary_operators = [sin, exp], + binary_operators = [+], maxdepth = 1, + seed = 42, + verbosity = -1, progress = false + ) + ) + + f(x) = [sin(x[1] .^ 2); exp(x[2] * x[1])] + Y = hcat(map(f, eachcol(X))...) + + @variables x y + basis = Basis([x; y; x^2; y^2; x * y], [x; y]) + prob = DirectDataDrivenProblem(X, Y) + res = solve(prob, basis, alg) + @test r2(res) >= 0.95 + @test rss(res) <= 1.0e-5 +end diff --git a/lib/DataDrivenSR/test/runtests.jl b/lib/DataDrivenSR/test/runtests.jl index 891bf806a..83c48667a 100644 --- a/lib/DataDrivenSR/test/runtests.jl +++ b/lib/DataDrivenSR/test/runtests.jl @@ -6,63 +6,7 @@ using StableRNGs const GROUP = get(ENV, "DATADRIVENDIFFEQ_TEST_GROUP", get(ENV, "GROUP", "All")) if GROUP == "All" || GROUP == "Core" || GROUP == "DataDrivenSR" - - rng = StableRNG(42) - X = rand(rng, 2, 50) - - @testset "Simple" begin - alg = DataDrivenSR.EQSearch( - eq_options = Options( - unary_operators = [sin, exp], - binary_operators = [*], maxdepth = 1, - seed = 42, - verbosity = -1, progress = false - ) - ) - f(x) = [sin(x[1]); exp(x[2])] - Y = hcat(map(f, eachcol(X))...) - prob = DirectDataDrivenProblem(X, Y) - res = solve(prob, alg) - @test r2(res) >= 0.95 - @test rss(res) <= 1.0e-5 - end - - @testset "Univariate" begin - alg = DataDrivenSR.EQSearch( - eq_options = Options( - unary_operators = [sin, exp], - binary_operators = [*], maxdepth = 1, - seed = 42, - verbosity = -1, progress = false - ) - ) - - Y = sin.(X[1:1, :]) - prob = DirectDataDrivenProblem(X, Y) - res = solve(prob, alg) - @test r2(res) >= 0.95 - @test rss(res) <= 1.0e-5 + @testset "Symbolic Regression" begin + include("./Core/symbolic_regression.jl") end - - @testset "Lifted" begin - alg = DataDrivenSR.EQSearch( - eq_options = Options( - unary_operators = [sin, exp], - binary_operators = [+], maxdepth = 1, - seed = 42, - verbosity = -1, progress = false - ) - ) - - f(x) = [sin(x[1] .^ 2); exp(x[2] * x[1])] - Y = hcat(map(f, eachcol(X))...) - - @variables x y - basis = Basis([x; y; x^2; y^2; x * y], [x; y]) - prob = DirectDataDrivenProblem(X, Y) - res = solve(prob, basis, alg) - @test r2(res) >= 0.95 - @test rss(res) <= 1.0e-5 - end - end diff --git a/lib/DataDrivenSR/test/test_groups.toml b/lib/DataDrivenSR/test/test_groups.toml index 3ab133501..8f657c062 100644 --- a/lib/DataDrivenSR/test/test_groups.toml +++ b/lib/DataDrivenSR/test/test_groups.toml @@ -1,4 +1,4 @@ # Each sublibrary only defines functional ("Core") tests; there are no QA # (Aqua/JET/AllocCheck) suites here, so the default QA group is not declared. [Core] -versions = ["lts", "1.11", "1", "pre"] +versions = ["lts", "1", "pre"] diff --git a/lib/DataDrivenSparse/test/cartpole.jl b/lib/DataDrivenSparse/test/Core/cartpole.jl similarity index 100% rename from lib/DataDrivenSparse/test/cartpole.jl rename to lib/DataDrivenSparse/test/Core/cartpole.jl diff --git a/lib/DataDrivenSparse/test/michaelis_menten.jl b/lib/DataDrivenSparse/test/Core/michaelis_menten.jl similarity index 100% rename from lib/DataDrivenSparse/test/michaelis_menten.jl rename to lib/DataDrivenSparse/test/Core/michaelis_menten.jl diff --git a/lib/DataDrivenSparse/test/pendulum.jl b/lib/DataDrivenSparse/test/Core/pendulum.jl similarity index 100% rename from lib/DataDrivenSparse/test/pendulum.jl rename to lib/DataDrivenSparse/test/Core/pendulum.jl diff --git a/lib/DataDrivenSparse/test/sparse_linear_solve.jl b/lib/DataDrivenSparse/test/Core/sparse_linear_solve.jl similarity index 100% rename from lib/DataDrivenSparse/test/sparse_linear_solve.jl rename to lib/DataDrivenSparse/test/Core/sparse_linear_solve.jl diff --git a/lib/DataDrivenSparse/test/runtests.jl b/lib/DataDrivenSparse/test/runtests.jl index 7d899959d..8971b69e7 100644 --- a/lib/DataDrivenSparse/test/runtests.jl +++ b/lib/DataDrivenSparse/test/runtests.jl @@ -6,18 +6,18 @@ const GROUP = get(ENV, "DATADRIVENDIFFEQ_TEST_GROUP", get(ENV, "GROUP", "All")) if GROUP == "All" || GROUP == "Core" || GROUP == "DataDrivenSparse" @safetestset "Basic Sparse Regression" begin - include("./sparse_linear_solve.jl") + include("./Core/sparse_linear_solve.jl") end @safetestset "Pendulum" begin - include("./pendulum.jl") + include("./Core/pendulum.jl") end @safetestset "Michaelis Menten" begin - include("./michaelis_menten.jl") + include("./Core/michaelis_menten.jl") end @safetestset "Cartpole" begin - include("./cartpole.jl") + include("./Core/cartpole.jl") end end diff --git a/lib/DataDrivenSparse/test/test_groups.toml b/lib/DataDrivenSparse/test/test_groups.toml index 3ab133501..8f657c062 100644 --- a/lib/DataDrivenSparse/test/test_groups.toml +++ b/lib/DataDrivenSparse/test/test_groups.toml @@ -1,4 +1,4 @@ # Each sublibrary only defines functional ("Core") tests; there are no QA # (Aqua/JET/AllocCheck) suites here, so the default QA group is not declared. [Core] -versions = ["lts", "1.11", "1", "pre"] +versions = ["lts", "1", "pre"] diff --git a/test/basis/basis.jl b/test/Core/basis.jl similarity index 100% rename from test/basis/basis.jl rename to test/Core/basis.jl diff --git a/test/commonsolve/commonsolve.jl b/test/Core/commonsolve.jl similarity index 100% rename from test/commonsolve/commonsolve.jl rename to test/Core/commonsolve.jl diff --git a/test/basis/generators.jl b/test/Core/generators.jl similarity index 100% rename from test/basis/generators.jl rename to test/Core/generators.jl diff --git a/test/basis/implicit_basis.jl b/test/Core/implicit_basis.jl similarity index 100% rename from test/basis/implicit_basis.jl rename to test/Core/implicit_basis.jl diff --git a/test/problem/problem.jl b/test/Core/problem.jl similarity index 100% rename from test/problem/problem.jl rename to test/Core/problem.jl diff --git a/test/problem/samplers.jl b/test/Core/samplers.jl similarity index 100% rename from test/problem/samplers.jl rename to test/Core/samplers.jl diff --git a/test/solution/solution.jl b/test/Core/solution.jl similarity index 100% rename from test/solution/solution.jl rename to test/Core/solution.jl diff --git a/test/utils.jl b/test/Core/utils.jl similarity index 100% rename from test/utils.jl rename to test/Core/utils.jl diff --git a/test/runtests.jl b/test/runtests.jl index 3b1586279..8f418b2d1 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -74,25 +74,25 @@ end elseif GROUP == "All" || GROUP == "Core" || GROUP == "Downstream" @testset "All" begin @safetestset "Basis" begin - include("./basis/basis.jl") + include("./Core/basis.jl") end @safetestset "Implicit Basis" begin - include("./basis/implicit_basis.jl") + include("./Core/implicit_basis.jl") end @safetestset "Basis generators" begin - include("./basis/generators.jl") + include("./Core/generators.jl") end @safetestset "DataDrivenProblem" begin - include("./problem/problem.jl") + include("./Core/problem.jl") end @safetestset "DataDrivenSolution" begin - include("./solution/solution.jl") + include("./Core/solution.jl") end @safetestset "Utilities" begin - include("./utils.jl") + include("./Core/utils.jl") end @safetestset "CommonSolve" begin - include("./commonsolve/commonsolve.jl") + include("./Core/commonsolve.jl") end end end diff --git a/test/test_groups.toml b/test/test_groups.toml new file mode 100644 index 000000000..dfe8e1457 --- /dev/null +++ b/test/test_groups.toml @@ -0,0 +1,12 @@ +# Test group declarations for the DataDrivenDiffEq root package. +# The base-environment Core group runs in the package's main test env and is +# the only group in the `All` run. The `nopre` group is a dep-adding group: it +# carries JET in test/nopre/Project.toml, is excluded from `All`, and (as its +# name says) does not run on prerelease Julia. Its CI.yml matrix group input is +# lowercase, so the group name here is kept lowercase to stay consistent. + +[Core] +versions = ["lts", "1", "pre"] + +[nopre] +versions = ["lts", "1"] From 0daf7582854ca0dd0cc8ab8e16068760cf3094ee Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Mon, 8 Jun 2026 05:12:18 -0400 Subject: [PATCH 8/8] Canonicalize TagBot thin-caller and clean up downgrade callers - Replace TagBot.yml with the canonical thin caller to SciML/.github tagbot.yml@v1, plus a tagbot-subpackages matrix over the registered lib/* sublibraries (DataDrivenDMD, DataDrivenLux, DataDrivenSparse, DataDrivenSR; all confirmed in General). - Downgrade.yml: drop hand-listed stdlib skip (Pkg,TOML) and the julia-version: "1.10" pin (central default is lts; auto-populated skip). - DowngradeSublibraries.yml: drop hand-listed skip (stdlibs + caller package), now auto-populated by the centralized workflow. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/Downgrade.yml | 2 - .github/workflows/DowngradeSublibraries.yml | 1 - .github/workflows/TagBot.yml | 62 +++++---------------- 3 files changed, 15 insertions(+), 50 deletions(-) diff --git a/.github/workflows/Downgrade.yml b/.github/workflows/Downgrade.yml index 9ff2d12f1..514f6061e 100644 --- a/.github/workflows/Downgrade.yml +++ b/.github/workflows/Downgrade.yml @@ -18,7 +18,5 @@ jobs: name: "Downgrade" uses: "SciML/.github/.github/workflows/downgrade.yml@v1" with: - julia-version: "1.10" group: "Core" - skip: "Pkg,TOML" secrets: "inherit" diff --git a/.github/workflows/DowngradeSublibraries.yml b/.github/workflows/DowngradeSublibraries.yml index 32f924032..abe9f1078 100644 --- a/.github/workflows/DowngradeSublibraries.yml +++ b/.github/workflows/DowngradeSublibraries.yml @@ -19,7 +19,6 @@ jobs: secrets: "inherit" with: julia-version: "lts" - skip: "Pkg,TOML,Statistics,LinearAlgebra,SparseArrays,InteractiveUtils,Random,Test,DataDrivenDiffEq" group-env-name: "DATADRIVENDIFFEQ_TEST_GROUP" group-env-value: "Core" # Every lib/* sublibrary is downgrade-tested (projects auto-discovered, no exclusions). diff --git a/.github/workflows/TagBot.yml b/.github/workflows/TagBot.yml index 1b97463fe..576699a6a 100644 --- a/.github/workflows/TagBot.yml +++ b/.github/workflows/TagBot.yml @@ -1,54 +1,22 @@ -name: TagBot - +name: "TagBot" on: issue_comment: - types: - - created + types: [created] workflow_dispatch: - inputs: - lookback: - default: "3" - -permissions: - actions: read - checks: read - contents: write - deployments: read - issues: read - discussions: read - packages: read - pages: read - pull-requests: read - repository-projects: read - security-events: read - statuses: read - jobs: - TagBot-DataDrivenDiffEq: - if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot' - runs-on: ubuntu-latest - steps: - - name: Tag DataDrivenDiffEq - uses: JuliaRegistries/TagBot@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - ssh: ${{ secrets.DOCUMENTER_KEY }} - - TagBot-Subpackages: - if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot' - runs-on: ubuntu-latest + tagbot: + uses: "SciML/.github/.github/workflows/tagbot.yml@v1" + secrets: "inherit" + tagbot-subpackages: strategy: fail-fast: false matrix: - package: - - DataDrivenDMD - - DataDrivenLux - - DataDrivenSR - - DataDrivenSparse - steps: - - name: Tag ${{ matrix.package }} - uses: JuliaRegistries/TagBot@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - ssh: ${{ secrets.DOCUMENTER_KEY }} - subdir: "lib/${{ matrix.package }}" + subdir: + - "lib/DataDrivenDMD" + - "lib/DataDrivenLux" + - "lib/DataDrivenSparse" + - "lib/DataDrivenSR" + uses: "SciML/.github/.github/workflows/tagbot.yml@v1" + with: + subdir: "${{ matrix.subdir }}" + secrets: "inherit"