using Parameters: @with_kw
@with_kw struct Param
mean = 0.
variance = 1.
end
struct Solver
params::Dict{Symbol,Param}
function Solver(params...)
new(Dict(params...))
end
end
Based on this interface, the user can construct solvers like the following:
The idea is that for each variable of the problem one can specify a set of parameters that will trigger a different method. The code is working fine, but I guess there is a cleaner way of achieving the same result without this ugly Param type in front of the parameters?
You could use NamedTuples.jl to get something closer to your “cleaner” option. When named tuples come to Julia 0.7, the syntax will be even nicer.
You could also use a TOML string/file for this type of thing. That’s more like your GetPot option. (It’s also coming to more use in Julia as part of Pkg3.)
Haha! But no, I have no answers only a few comments:
The deeper you nest your options, the more organized they are but also the more painful to deal with.
With scripting languages there is rarely a need to use separate configuration files: just use a script instead, saves you the hassle to deal with another package and the user the hassle of learning/context-switching to another mini-language.
Have a look at how DiffEq handles options, mostly through kwargs I think.
Keyword args to the solver. Keyword arguments currently have an overhead, but that should get fixed soon enough so I wouldn’t worry about it. The cost isn’t too high though, so if it’s just in the setup phase you won’t even notice it. If you do it via splatting positional args and then assuming the args are in order, you can at least make it like
I thought of using positional arguments and assume order, but the interface looks more obscure. I like explicit pairs var1=>param1, var2=>…, but I may change this point of view in the future.
@tshort, I am back to this issue after a while. I am giving NamedTuple a try, but couldn’t make the outer constructor below work:
using Parameters: @with_kw
@with_kw struct Param
mean = 0.
variance = 1.
end
struct Solver
params::Dict{Symbol,Param}
# inner ctor to be called from outside
Solver(params::Dict{Symbol,Param}) = new(params)
end
# outer ctor with named tuples
function Solver(params...)
dict = Dict{Symbol,Param}()
for (varname, varparams) in params
push!(dict, varname => Param(varparams...)) # doesn't work
end
Kriging(dict)
end
Could you please give a hand? The goal is to have the Solver working with named tuples as you described:
The problem is that I have many variables in the problem. So if I say mean=1, what variable it refers to? That is why keyword arguments don’t solve the problem. I need to have pairs variable_name => (mean=1) to disambiguate instead of assuming that the user will remember the order of the variables when he defined the EstimationProblem.
You could just use a dictionary instead of a named tuple. If you really want to use named tuples you could convert the named tuple to a dictionary inside the Solver function:
julia> a = @NT(mean = 0.0, variance = 0.0)
(mean = 0.0, variance = 0.0)
julia> d = Dict(k=>v for (k,v) in zip(fieldnames(typeof(a)), a))
Dict{Symbol,Float64} with 2 entries:
:mean => 0.0
:variance => 0.0
julia> Param(d...)
Or @kwdef could, in addition, generate a constructor for a named tuple.
That is exactly my question, how to write an outer constructor that converts named tuples to dictionaries. I have tried it in my previous comment, but failed. I will try with your code snippet now.
@kristoffer.carlsson this is my second attempt, now with your code snippet, it didn’t work unfortunately:
using Parameters: @with_kw
using NamedTuples
@with_kw struct Param
mean = 0.
variance = 1.
end
struct Solver
params::Dict{Symbol,Param}
# inner ctor to be called from outside
Solver(params::Dict{Symbol,Param}) = new(params)
end
# outer ctor with named tuples
function Solver(params...)
# build Dict for inner ctor
dict = Dict{Symbol,Param}()
for (varname, varparams) in params
# varparams is a NamedTuple
d = Dict(k => v for (k,v) in zip(fieldnames(typeof(varparams)), varparams))
push!(dict, varname => Param(d...))
end
Solver(dict) # call inner ctor
end
The conversion from NamedTuple to Dict works, but what I really need is to pass the NamedTuple entries as keyword arguments to the Param type, which takes care of all the checks like valid parameter names, types, etc.
Each pair in this list would be converted to a pair of Symbol and Param, where Param is defined above. The Param type has keyword constructors from the Parameters.jl package. This way I am enforcing meaningful parameters for each variable even though the user types arbitrary NamedTuples like @NT(not_valid=2.).
My issue is in defining the outer constructor that does this conversion Dict{Symbol,NamedTuple} to Dict{Symbol,Param}. This outer constructor is vararg.
Please let me know if is still not clear, all the code from my previous comment is correct, except for the outer constructor, which doesn’t compile.
The reason I am doing this now is because I hope that in Julia v0.7, the @NT will go away and then the syntax will be super clean: