Open langestefan opened 1 month ago
Thanks, this is really good input and something I been thinking about myself!
As a clarification, remake
is a bit of black-magic and is mostly for model-selection with the aim of having to not rebuilt the problem (should ideally very seldom have to be used), which I should make clearer in the docs.
As of your thoughts:
ComponentArray
as it will also make it possible to add support for SciML (e.g. UDE models with both neural networks and mechanistic terms) in a manageable way. Therefore, it would also definitely make sense to have get_u0
etc..., return ComponentArray
as the default.ComponentArray
is the standard parameter struct
then order should not really matter that much right? Because in a ComponentArray
it is easy to change the value of certain parameters, just x.name = val
. Moreover, the ODE interacting functions (get_ps
etc...), they will with ComponentArray
have to return the parameters in a certain order, so I think there is a point in enforcing that ordering matters.get_xmin
that in a similar fashion to get_x
can return parameters on linear and transformed scales, and by also having a function that can transform between linear and parameter scale? What do you think?
Also, @TorkelE you might be interested in this if you have time.
Thanks for your reply, it makes more sense now.
But, now if
ComponentArray
is the standard parameterstruct
then order should not really matter that much right? Because in aComponentArray
it is easy to change the value of certain parameters, justx.name = val
. Moreover, the ODE interacting functions (get_ps
etc...), they will withComponentArray
have to return the parameters in a certain order, so I think there is a point in enforcing that ordering matters.
Yes completely agree. But functions like nllh
, FIM
will still fail if your ComponentArray
doesn't have the right order. But what's more inconvenient (as a user) is that the scale is part of the variable name. Ideally, I would just like every parameter to be a tuple(name, value, scale). That way I don't have to inspect names to keep track of parameter scales and it should be very clear to PEtab what values I am providing it.
3. I get your point on parameter scale (and how it impacts the naming). But I think the current approach should be the least confusing, because now the scale is very transparent (and I hope it is clear which scale to provide custom value on). From above, I think maybe a lot of your problems could be resolved by having a `get_xmin` that in a similar fashion to `get_x` can return parameters on linear and transformed scales, and by also having a function that can transform between linear and parameter scale?
Yes for sure that would help a lot.
But functions like
nllh
,FIM
will still fail if yourComponentArray
doesn't have the right order.
I think the best solution here would just to add an order check in these function. And if the order is wrong, the error message can refer to an ordering function.
Ideally, I would just like every parameter to be a tuple(name, value, scale).
I think this is a valid point, but I also see this getting very complicated for the future when for example adding neural network support in PEtab (which definitely will happen within this year). Maybe what is needed is a set
function, like set_x(x, :name, val)
where you as the user can set values on the linear scale (and the function takes care of fixing everything to the correct scale)?
I think the best solution here would just to add an order check in these function. And if the order is wrong, the error message can refer to an ordering function.
Would it not be an option to handle that internally? The component array already has the axis names and the values. So technically it should be able to automatically infer the right order without the user having to specify it?
If I compare it to using plain MTK, I specify:
@parameters A B C D
params = [A, B, C, D]
values = [1, 2, 3, 4]
parammap = Dict(params .=> values)
And ODEProblem
constructor accepts parammap as an argument. Whatever MTK does with the order internally I dont care about.
Would it not be an option to handle that internally?
Fair point, and PEtabODEProblem
can internally build an index for efficient mapping (which is only rebuilt if the input changes). So this is doable. And for parameter estimation the input is behind the scenes Vector
anyhow so this will not affect performance.
Then the only thing left is the get_ps
functions. If the goal is not to have them depend on order, I guess it should make more sense for them to return a map as is currently done.
Lastly, do you think a set_val
or similar function would be useful for setting value without worrying about parameter scale?
To make the package even better I want to make the suggestion to standardize the way you retrieve parameters and supply them to constructors. This standardization should be independent of the scale of the parameters, be it problem or inference space.
To illustrate why this is useful, I am currently trying to achieve the following.
I have an optimisation result and the original problem:
Now I want to achieve the following:
problem.nllh
,problem.FIM
etc.How to achieve this?
I go to the API and see what's available. I can get
result.xmin
and pass it directly toproblem.nllh
and it works, great. Butxmin
is the in the inference scale, I want to save the parameters in linear scale. Well there is no method to do that, but I can do:xmin_lin = PEtab.get_ps(result, problem)
. But this method is missing the noise parameters? I want to save those too.I can get the noise parameters from xmin however, and combine them with the linear parameters:
But this is really ugly. If I want to
remake
the problem, I have to supply:But where to get this dict? Also why is it a dict, why can't I pass my ComponentArray? Yeah okay, you can hardcode it, but for larger models this is not doable.
Lastly, I can use the very convenient
get_x
to get my parameters on linear scale and in the right order. But to get my inference result in this format, I need toremake
it first withxmin
. But if I do that, the result fromremake
is missing all of the parameters.So this fails with
KeyError: key :log10_C_e not found
I think instead of passing results, dicts, componentarrays and parameter vectors around I think it would improve usability a lot if we had one single definition of a parameter object. So that each method takes the exact same object, knows at what scale (or is specified by the user) it is so that if it needs to put it in inference scale it can do that internally. It should not have to rely on the order of the parameter, or whether it's called
log10_C_e
instead ofC_e
.