Reconstruct() in Parameters.jl with parameters interdependency

Hi all,

I find Parameters.jl and its function reconstruct() a very convenient way to handle models that need to be computed under many set of parameters. The feature that one can define a default value for a parameter that is a function of other parameters is really useful. However, consider the following:

using Parameters

@with_kw struct Para
    a::Float64
    b = a + 1
end
p = Para(a=1)

Which returns a struct with a = 1 and b = 2. Now if one uses reconstruct:

p2 = reconstruct(p,a=5)

I would like p2 to return a struct with a = 5 and b = 6, however it returns a struct with a = 5 and b = 2 (b is not updated to the new value of a). In my opinion, for most applications it would make much more sense that reconstruct makes b still consistent with the parameter a. Does anyone know any other option to achieve the desired result (in as simple and parsimonious way)?

1 Like

In this case if b is always a function of a I would just define it as a function

using Parameters

@with_kw struct Para
    a::Float64
end
b(p) = p.a + 1

p = Para(a=1)
julia> p = Para(a=1);
julia> b(p)
2.0
julia> p2 = reconstruct(p, a=5);
julia> b(p2)
6.0

Although I’ll grant that this might not be practical if b is more expensive to compute.

2 Likes

Another way would be to use getproperty. (Which arguably should be used for computed fields.)

1 Like

For extensive sets of parameters with precomputed quantities, I usually try to organize my code like this:

struct Parameters{...}
    ...
end

struct PrecomputedModel{TP <: Parameters, ...}
    parameters::TP
    ...
end

function PrecomputedModel(parameters::Parameters)
     ... # do the precalculations
end

Then the two sets of quantities are organized separately, which I find leads to cleaner code.

2 Likes

Just from today, maybe of relevance

https://discourse.julialang.org/t/ann-lazilyinitializedfields-jl-handling-lazily-initialized-fields-in-a-consistent-way

2 Likes