From 15abe93f6ff6bbfa2ff2507f3e317978cc658da0 Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 11 Aug 2025 16:43:37 +0530 Subject: [PATCH 01/11] chore: add change_tunables --- src/parameters.jl | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/parameters.jl b/src/parameters.jl index 7633d8c1b7..927bdb523e 100644 --- a/src/parameters.jl +++ b/src/parameters.jl @@ -147,3 +147,27 @@ function split_parameters_by_type(ps) end end end + +""" + $(TYPEDSIGNATURES) + +Change the tunable parameters of a system to a new set of tunables. + +The new tunable parameters must be a subset of the current tunables as discovered by [`tunable_parameters`](@ref). +The remaining parameters will be set as constants in the system. +""" +function change_tunables(sys, new_tunables) + cur_tunables = tunable_parameters(sys, parameters(sys)) + diff_params = setdiff(cur_tunables, new_tunables) + + if !isempty(setdiff(new_tunables, cur_tunables)) + throw(ArgumentError("New tunables must be a subset of the current tunables. Found tunable parameters not in the system: $(setdiff(new_tunables, cur_tunables))")) + end + cur_ps = get_ps(sys) + const_ps = toconstant.(diff_params) + + new_ps = replace(cur_ps, (diff_params .=> const_ps)...) + new_ps = replace(new_ps, (Initial.(diff_params) .=> Initial.(const_ps))...) + @set! sys.ps = new_ps + complete(sys) +end From 397219274cddbce82fe0ab867aa728642dd5e389 Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 11 Aug 2025 17:43:30 +0530 Subject: [PATCH 02/11] test: add pendulum example for tests --- test/parameter_dependencies.jl | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/parameter_dependencies.jl b/test/parameter_dependencies.jl index 627df5913f..c3afddd714 100644 --- a/test/parameter_dependencies.jl +++ b/test/parameter_dependencies.jl @@ -173,6 +173,23 @@ end @test SciMLBase.successful_retcode(sol) end +@testset "Change Tunables" begin + @variables θ(t)=π/6 ω(t)=0. + @parameters g=9.81 L=1.0 b=0.1 errp=1 + eqs = [ + D(θ) ~ ω, + D(ω) ~ -(g/L)*sin(θ) - b*ω + ] + @named pendulum_sys = ODESystem(eqs, t, [θ, ω], [g, L, b]) + sys = mtkcompile(pendulum_sys) + + new_tunables = [L, b] + sys2 = ModelingToolkit.change_tunables(sys, new_tunables) + @test length(ModelingToolkit.tunable_parameters(sys2, ModelingToolkit.parameters(sys2))) == 2 + @test isempty(setdiff(ModelingToolkit.tunable_parameters(sys2, ModelingToolkit.parameters(sys2)), new_tunables)) + @test_throws ArgumentError ModelingToolkit.change_tunables(sys, [errp]) +end + struct CallableFoo p::Any end From 568651bfae4e69894ef7e7d64a8c21dd0dfad86c Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 11 Aug 2025 17:44:25 +0530 Subject: [PATCH 03/11] test: typo --- test/parameter_dependencies.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parameter_dependencies.jl b/test/parameter_dependencies.jl index c3afddd714..eced74bfd1 100644 --- a/test/parameter_dependencies.jl +++ b/test/parameter_dependencies.jl @@ -180,7 +180,7 @@ end D(θ) ~ ω, D(ω) ~ -(g/L)*sin(θ) - b*ω ] - @named pendulum_sys = ODESystem(eqs, t, [θ, ω], [g, L, b]) + @named pendulum_sys = System(eqs, t, [θ, ω], [g, L, b]) sys = mtkcompile(pendulum_sys) new_tunables = [L, b] From df7914fa58c402d5444bd97ec1b5b091fd09977a Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 11 Aug 2025 17:46:58 +0530 Subject: [PATCH 04/11] test: refactor --- test/parameter_dependencies.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/parameter_dependencies.jl b/test/parameter_dependencies.jl index eced74bfd1..7840e882a7 100644 --- a/test/parameter_dependencies.jl +++ b/test/parameter_dependencies.jl @@ -185,8 +185,9 @@ end new_tunables = [L, b] sys2 = ModelingToolkit.change_tunables(sys, new_tunables) - @test length(ModelingToolkit.tunable_parameters(sys2, ModelingToolkit.parameters(sys2))) == 2 - @test isempty(setdiff(ModelingToolkit.tunable_parameters(sys2, ModelingToolkit.parameters(sys2)), new_tunables)) + sys2_tunables = ModelingToolkit.tunable_parameters(sys2, ModelingToolkit.parameters(sys2)) + @test length(sys2_tunables) == 2 + @test isempty(setdiff(sys2_tunables, new_tunables)) @test_throws ArgumentError ModelingToolkit.change_tunables(sys, [errp]) end From 19d7ce46331da6b92375712204d0bcff4b360c34 Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 11 Aug 2025 18:15:44 +0530 Subject: [PATCH 05/11] chore: validate with complete and split systems --- src/parameters.jl | 13 +++++++++++-- test/parameter_dependencies.jl | 9 +++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/parameters.jl b/src/parameters.jl index 927bdb523e..3a9a04c590 100644 --- a/src/parameters.jl +++ b/src/parameters.jl @@ -156,12 +156,21 @@ Change the tunable parameters of a system to a new set of tunables. The new tunable parameters must be a subset of the current tunables as discovered by [`tunable_parameters`](@ref). The remaining parameters will be set as constants in the system. """ -function change_tunables(sys, new_tunables) +function subset_tunables(sys, new_tunables) + if !iscomplete(sys) + throw(ArgumentError("System must be `complete` before changing tunables.")) + end + if !is_split(sys) + throw(ArgumentError("Tunable parameters can only be changed for split systems.")) + end + cur_tunables = tunable_parameters(sys, parameters(sys)) diff_params = setdiff(cur_tunables, new_tunables) if !isempty(setdiff(new_tunables, cur_tunables)) - throw(ArgumentError("New tunables must be a subset of the current tunables. Found tunable parameters not in the system: $(setdiff(new_tunables, cur_tunables))")) + throw(ArgumentError("""New tunable parameters must be a subset of the current tunable parameters. Found tunable parameters not in the system: $(setdiff(new_tunables, cur_tunables)). + Note that array parameters can only be set as tunable or non-tunable, not partially tunable. They should be specified in the un-scalarized form. + """)) end cur_ps = get_ps(sys) const_ps = toconstant.(diff_params) diff --git a/test/parameter_dependencies.jl b/test/parameter_dependencies.jl index 7840e882a7..425ca7220e 100644 --- a/test/parameter_dependencies.jl +++ b/test/parameter_dependencies.jl @@ -184,11 +184,16 @@ end sys = mtkcompile(pendulum_sys) new_tunables = [L, b] - sys2 = ModelingToolkit.change_tunables(sys, new_tunables) + sys2 = ModelingToolkit.subset_tunables(sys, new_tunables) sys2_tunables = ModelingToolkit.tunable_parameters(sys2, ModelingToolkit.parameters(sys2)) @test length(sys2_tunables) == 2 @test isempty(setdiff(sys2_tunables, new_tunables)) - @test_throws ArgumentError ModelingToolkit.change_tunables(sys, [errp]) + @test_throws ArgumentError ModelingToolkit.subset_tunables(sys, [errp]) + @test_throws ArgumentError ModelingToolkit.subset_tunables(sys, [θ, L]) + sys3 = ModelingToolkit.subset_tunables(sys, []) + sys3_tunables = ModelingToolkit.tunable_parameters(sys3, ModelingToolkit.parameters(sys3)) + @test length(sys3_tunables) == 0 + end struct CallableFoo From 397bd3c308190242659408f3594a18ef560c91f3 Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 11 Aug 2025 18:48:46 +0530 Subject: [PATCH 06/11] chore: rm replacing for Initials --- src/parameters.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/parameters.jl b/src/parameters.jl index 3a9a04c590..e247907794 100644 --- a/src/parameters.jl +++ b/src/parameters.jl @@ -176,7 +176,6 @@ function subset_tunables(sys, new_tunables) const_ps = toconstant.(diff_params) new_ps = replace(cur_ps, (diff_params .=> const_ps)...) - new_ps = replace(new_ps, (Initial.(diff_params) .=> Initial.(const_ps))...) @set! sys.ps = new_ps complete(sys) end From 4796827a958ce6555fc03bfca1d26d7a1f84dc5d Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 11 Aug 2025 20:04:43 +0530 Subject: [PATCH 07/11] chore: replace -> for-loop --- src/parameters.jl | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/parameters.jl b/src/parameters.jl index e247907794..93c74e36a9 100644 --- a/src/parameters.jl +++ b/src/parameters.jl @@ -175,7 +175,14 @@ function subset_tunables(sys, new_tunables) cur_ps = get_ps(sys) const_ps = toconstant.(diff_params) - new_ps = replace(cur_ps, (diff_params .=> const_ps)...) - @set! sys.ps = new_ps + for (idx, p) in enumerate(cur_ps) + for (d, c) in zip(diff_params, const_ps) + if isequal(p, d) + setindex!(cur_ps, c, idx) + break + end + end + end + @set! sys.ps = cur_ps complete(sys) end From 0bbf1e1f2a1690be0c8643d024ceb0934b5725c0 Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 11 Aug 2025 20:14:23 +0530 Subject: [PATCH 08/11] docs: add docstring to docs --- docs/src/API/model_building.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/API/model_building.md b/docs/src/API/model_building.md index 28069b535e..f558ef2033 100644 --- a/docs/src/API/model_building.md +++ b/docs/src/API/model_building.md @@ -226,6 +226,7 @@ change_independent_variable add_accumulations noise_to_brownians convert_system_indepvar +ModelingToolkit.subset_tunables ``` ## Hybrid systems From c161b11f3bdf7e294a2bf38f19b6ed1244d0ee71 Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 11 Aug 2025 20:50:18 +0530 Subject: [PATCH 09/11] test: test incomplete and non-split systems --- test/parameter_dependencies.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/parameter_dependencies.jl b/test/parameter_dependencies.jl index 425ca7220e..7316a59bc4 100644 --- a/test/parameter_dependencies.jl +++ b/test/parameter_dependencies.jl @@ -194,6 +194,10 @@ end sys3_tunables = ModelingToolkit.tunable_parameters(sys3, ModelingToolkit.parameters(sys3)) @test length(sys3_tunables) == 0 + sys_incomplete = pendulum_sys + @test_throws ArgumentError ModelingToolkit.subset_tunables(sys_incomplete, new_tunables) + sys_nonsplit = mtkcompile(pendulum_sys; split = false) + @test_throws ArgumentError ModelingToolkit.subset_tunables(sys_nonsplit, new_tunables) end struct CallableFoo From 8c8dbf830e8e24f6a3c90d9a5ca7eb74d713d9fd Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 11 Aug 2025 21:38:12 +0530 Subject: [PATCH 10/11] chore: export subset_tunables --- docs/src/API/model_building.md | 2 +- src/ModelingToolkit.jl | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/src/API/model_building.md b/docs/src/API/model_building.md index f558ef2033..c9d7c2f249 100644 --- a/docs/src/API/model_building.md +++ b/docs/src/API/model_building.md @@ -226,7 +226,7 @@ change_independent_variable add_accumulations noise_to_brownians convert_system_indepvar -ModelingToolkit.subset_tunables +subset_tunables ``` ## Hybrid systems diff --git a/src/ModelingToolkit.jl b/src/ModelingToolkit.jl index 26efc0c7a9..d2dd7af7ef 100644 --- a/src/ModelingToolkit.jl +++ b/src/ModelingToolkit.jl @@ -265,7 +265,8 @@ export isinput, isoutput, getbounds, hasbounds, getguess, hasguess, isdisturbanc istunable, getdist, hasdist, tunable_parameters, isirreducible, getdescription, hasdescription, hasunit, getunit, hasconnect, getconnect, - hasmisc, getmisc, state_priority + hasmisc, getmisc, state_priority, + subset_tunables export liouville_transform, change_independent_variable, substitute_component, add_accumulations, noise_to_brownians, Girsanov_transform, change_of_variables export PDESystem @@ -345,6 +346,7 @@ export DynamicOptSolution @public collect_var_to_name!, collect_vars!, eqtype_supports_collect_vars, hasdefault @public getdefault, setdefault, iscomplete, isparameter, modified_unknowns! @public renamespace, namespace_equations +@public subset_tunables for prop in [SYS_PROPS; [:continuous_events, :discrete_events]] getter = Symbol(:get_, prop) From 014dd35da49c7190d8c13c446aabeb331986accb Mon Sep 17 00:00:00 2001 From: Aayush Sabharwal Date: Tue, 12 Aug 2025 11:13:43 +0530 Subject: [PATCH 11/11] Update src/ModelingToolkit.jl --- src/ModelingToolkit.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ModelingToolkit.jl b/src/ModelingToolkit.jl index d2dd7af7ef..bb2ba0285d 100644 --- a/src/ModelingToolkit.jl +++ b/src/ModelingToolkit.jl @@ -346,7 +346,6 @@ export DynamicOptSolution @public collect_var_to_name!, collect_vars!, eqtype_supports_collect_vars, hasdefault @public getdefault, setdefault, iscomplete, isparameter, modified_unknowns! @public renamespace, namespace_equations -@public subset_tunables for prop in [SYS_PROPS; [:continuous_events, :discrete_events]] getter = Symbol(:get_, prop)