# Optimizable parameters

TLDR: I want to use `Parameters.jl` and convert a fraction of its fields to a vector and back. I can convert to the vector, but I don’t know how to convert back - please help

Here is my MWE `Para` type

``````using Parameters
@with_kw struct Para{T}
a::T = 1.0
b::T = 2.0
c::T = 3.0
end
``````

with three parameters (`a`, `b`, and `c`). Some examples of concrete `Para`s:

``````julia> p1 = Para()
Para{Float64}
a: Float64 1.0
b: Float64 2.0
c: Float64 3.0

julia> p2 = Para(a = 4.0, c = 5.0)
Para{Float64}
a: Float64 4.0
b: Float64 2.0
c: Float64 5.0
``````

Note that the `Para` constructor nicely works by supplying it assignments (like `a = 4.0` - Thanks to `Parameters.jl`! ).

I want to optimize only `a` and `b`. For that, I want to create a vector of the values in `a` and `b` for a given `Para`. So I create a tuple of the symbol names

``````optimizable_Para = (:a, :b)
``````

which lists the “optimizable” parameters. To create the vector of the optimizable parameters, I have the function

``````function convert_Para_to_Vector(p::Para)
[getfield(p, s) for s in optimizable_Para]
end
``````

Some examples of conversion from `Para` to `Vector`:

``````julia> x1 = convert_Para_to_Vector(p1)
2-element Array{Float64,1}:
1.0
2.0

julia> x2 = convert_Para_to_Vector(p2)
2-element Array{Float64,1}:
4.0
2.0
``````

Now I want to do the opposite, i.e., create a `Para` from a `Vector` (and assign the default values to the parameters not listed in `optimizable_Para`, the non-optimizable parameters).
Thus I am looking for a function `convert_Vector_to_Para` that achieves

``````function convert_Vector_to_Para(x)
Para(a = x[1], b = x[2])
end
``````

But, instead of explicitly writing the assignments (`a = x[1], b = x[2]`), I would like to use the symbols in `oPara`. So that if I change `oPara` in the future, I don’t have to rewrite `convert_Vector_to_Para`. I have not been able to figure how to do that so far… Please help?

My guess is I need a macro, but the closest I have been is via a function which does not work:

``````function convert_Vector_to_Para(x)
eval(Expr(:call, :Para, [Expr(:(=), oPara[i], x[i]) for i in 1:length(optimizable_Para)]...))
end
``````
``````function Para(obj::AbstractVector,
overwrite::AbstractVector{<:Symbol})
fn = fieldnames(Para)
default = Para()
T = eltype(obj)
return Para(NamedTuple{fn}(
name in overwrite ?
obj[idx] :
T(getfield(default, name)) for
(idx, name) in enumerate(fn))...)
end
``````
1 Like

Flatten.jl was made entirely to do this! Even for nested structs.

Like:

``````using Flatten
import Flatten: flattenable

@flattenable @with_kw struct Para{T}
a::T = 1.0 | true
b::T = 2.0 | true
c::T = 3.0 | false
end

julia> para = Para()
Para{Float64}
a: Float64 1.0
b: Float64 2.0
c: Float64 3.0

julia> fieldnameflatten(para)
(:a, :b)

julia> data = flatten(Vector,para)
2-element Array{Float64,1}:
1.0
2.0

julia> data[2] = 5.0
5.0

julia> Flatten.reconstruct(para, data)
Para{Float64}
a: Float64 1.0
b: Float64 5.0
c: Float64 3.0

``````

It becomes increasingly useful the larger and more complicated the struct, and it generates pretty fast code.

To use the fieldnames in the array, make an AxisArray

``````data = flatten(Vector,para)
names = fieldnameflatten(Vector, para)
a = AxisArray(data, Axis{:parameters}(names))

julia> a[:b]
2.0
``````
4 Likes

Make it a subtype of FieldVector from StaticArrays.jl

1 Like

That’s the simplest way, but he needs to exclude fields from the vector and rebuild ignoring those excluded fields

1 Like

Thank you very much, this is even better than what I was looking for! I’ll try it right away!

@Raf It seems Flatten.jl (and Tags.jl) are not in the reigistry. Is that normal?

That’s in the process of happening right now! except some people thought Tags.jl wasn’t a clear enough name (after I already renamed it from MetaFields.jl), I’m considering FieldTags.jl or FieldMetadata.jl, if you have any opinions now is the time!

So for now use `add "https://github.com/rafaqz/Tags.jl"` and `add "https://github.com/rafaqz/Flatten.jl"` but also expect some changes in the coming month.

Any feedback or feature requests you have would be really useful too, I’m not sure how people will actually use these packages.

1 Like

I’m considering FieldTags.jl or FieldMetadata.jl, if you have any opinions now is the time!

My uneducated vote would go to `FieldMetadata.jl`. It is longer but I think it is more descriptive. I’ll got there to ask things about it