Passing struct as argument to optimizer

Is it possible to pass a struct of parameters as an argument to an optimizer? The example below estimates an OLS model in which the intercept and slope are passed a vector p.

function ssr(y,x,p)
    return sum((y .- (p[1] .+ p[2] .* x)).^2)
end

x1 = cumsum(ones(10))
y1 = 2 .+ 3 .* x1 .+ rand(10)

Optim.minimizer(optimize(p->ssr(y1,x1,p), ones(2)))

Is it possible to instead pass the intercept and slope as a struct?

struct ols_struct
   intercept::Float64
   slope::Float64
end
p = ols_struct(1,1)

Most optimizers expect a vector of unknowns, but you can just wrap an anonymous function around your struct p -> ols_struct(p[1], p[2]).

Most optimizers require flat arrays, but there are some options to pass more structured data instead:

function nice_ssr(y, x, p)
     sum(@. (y - (p.intercept + p.slope * x))^2)
end

ComponentArrays.jl which allows to treat (nested) named tuples as flat vectors

using ComponentArrays

p0 = ComponentArray(intercept = 1.0, slope = 1.0)
optimize(p -> nice_ssr(y1, x1, p), p0)

or if you prefer using structs, Functors.jl which help in converting between (nested) structs and flat vectors:

using Functors

 @functor ols_struct
_, rebuild = Functors.functor(ols_struct(1.0, 1.0))
optimize(x -> nice_ssr(y1, x1, rebuild(x)), ones(2))