Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow altering a symbolic parameter default value after creation. #2650

Closed
Datseris opened this issue Apr 16, 2024 · 9 comments
Closed

Allow altering a symbolic parameter default value after creation. #2650

Datseris opened this issue Apr 16, 2024 · 9 comments

Comments

@Datseris
Copy link

As far as I can tell, this isn't possible right now:

@parameters p = 0.5
p.val.metadata[Symbolics.VariableDefaultValue] = 0.6
ERROR: MethodError: no method matching setindex!(::Base.ImmutableDict{DataType, Any}, ::Float64, ::Type{Symbolics.VariableDefaultValue})    

because the metadata are immutable:

julia> p.val.metadata
Base.ImmutableDict{DataType, Any} with 3 entries:
  MTKVariableTypeCtx   => PARAMETER
  VariableSource       => (:parameters, :p)
  VariableDefaultValue => 0.5

Context where this is useful:

I have a parameter at global scope. I have two functions, each representing two different physical processes A, B. They both utilize the same parameter, which itself is also utilized in other unrelated processes C. However, in my A, B the parameter should have a different starting value (while of course in all cases A, B, C the parameter covers the same physical range). I cannot use the same parameter everywhere and have its default value be context-specific. But I would like to!

@hersle
Copy link
Contributor

hersle commented Jul 16, 2024

You can do it like this:

using ModelingToolkit
using ModelingToolkit: t_nounits as t, D_nounits as D

@parameters p
@variables x(t)
@named A = ODESystem([D(x) ~ p], t; defaults = [p => 1.0])
@named B = ODESystem([D(x) ~ p], t; defaults = [p => 2.0])

@ChrisRackauckas
Copy link
Member

yes the system level overload the way to do this.

@Datseris
Copy link
Author

Datseris commented Jul 16, 2024

This is not good enough of a solution for me because I want to do this alteration before I construct the model, not after. The function in which I want to do the alteration of the parameter value does not have access to the full model, or the model equations so that I can just pass them to an ODESystem. Neither have been built yet. And it won't be possible to refactor my code so that this happens, because it doesn't make conceptual sense in the way I build my simulations.

Being able to alter a parameter or variable value after it has been created seems like a legitimate request. Likely this needs to be transferred to the Symbolics.jl repo because this should be possible and useful even before using MTK.

@ChrisRackauckas
Copy link
Member

It seems like you want SymbolicUtils.setmetadata? It seems to not be documented, but I think it's a legitimate request to add it to the public API.

@Datseris
Copy link
Author

Hm, it is almost what I want but not quite. Perhaps what I want is not possible, because I want an in-place modification. At the moment:

julia> @parameters p_T = 0.15
1-element Vector{Num}:
 p_T

julia> SymbolicUtils.setmetadata(p_T, Symbolics.VariableDefaultValue, 1.5)  
p_T

julia> p_T.val.metadata
Base.ImmutableDict{DataType, Any} with 3 entries:
  MTKVariableTypeCtx   => PARAMETER
  VariableSource       => (:parameters, :p_T)
  VariableDefaultValue => 0.15

so p_T has not been overwritten in place. In my simulation setup p_T is passed in as a parameter (currently from global scope), and I want to modify this parameter so that it has a different starting value.

Is this impossible? As long as the metadata are an immutable dict it likely will be, and I assume there is a reason for that immutability.

@Datseris
Copy link
Author

Okay, thankfully in my simulation setup I can do

global p_T = SymbolicUtils.setmetadata(p_T, Symbolics.VariableDefaultValue, 1.5)

and this will overwrite the global scope variable defined with @parameters. So that's good enough for me now!

@hersle
Copy link
Contributor

hersle commented Jul 16, 2024

Is it possible for MTK/SymbolicUtils to expose a mutating setter? Then you would not have to mess with global.

@SebastianM-C
Copy link
Contributor

The fundamental aspect here is that the metadata is immutable, and that is unlikely to change any time soon (as @Datseris pointed out). To have a mutating setter, you'd need the metadata to be mutable in the first place.

@ChrisRackauckas
Copy link
Member

I would presume that the proposed hash consing of @bowenszhu might actually make this easier, because then all information on the consed variable is stored in one place, so it can be globally updated just by updating that linked dictionary. In the current form the equations have different variable objects that happen to hash the same, but with the consing/DAG representation it should recognize semantically they are all the same. That change I think is required to make such a feature possible.

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

No branches or pull requests

4 participants