AccessibleOptimization.jl

Combining Accessors.jl + Optimization.jl to enable function optimization with arbitrary structs. Vary struct parameters, combinations and transformations of them. Uniform and composable, zero overhead.

Defining features of AccessibleOptimization:

  • No need to deal with raw vectors of optimized parameters: their values are automatically put into model structs
  • Can use arbitrary structs as model definitions, no requirements or limitations on their content, types, or methods
  • Can flexibly specify the list of parameters to optimize, as well as their bounds and constrains - independently of the model struct/object creation
  • Everything is type-stable and performant

Usage

Suppose you want to fit a model to data. Here, our model is a sum of squared exponentials.

First, define your model and a way to evaluate it. Regular Julia code, no special types or functions. This is not Accessors/Optimization specific at all, you may have model definitions already!

struct ExpModel{A,B}
    scale::A
    shift::B
end

struct SumModel{T <: Tuple}
    comps::T
end

(m::ExpModel)(x) = m.scale * exp(-(x - m.shift)^2)
(m::SumModel)(x) = sum(c -> c(x), m.comps)

loss(m, data) = @p data |> sum(abs2(_.y - m(_.x)))

Then, load AccessibleOptimization, define optimization parameters, and perform optimization:

using AccessibleOptimization

# which parameters to optimize, what are their bouds?
vars = OptArgs(
	@optic(_.comps[].shift) => 0..10.,  # shifts of both components: values from 0..10
	@optic(log10(_.comps[].scale)) => -1..1,  # component scales: positive-only (using log10 transformation), from 10^-1 to 10^1
)
# create and solve the optimization problem, interface very similar to Optimization.jl
ops = OptProblemSpec(Base.Fix2(loss, data), mod0, vars)
sol = solve(ops, ECA(), maxiters=300)
sol.uobj::SumModel  # the optimal model

See also a walkthrough, with more examples and details.

Related packages

AccessibleOptimization gains its composability and generality powers (and half its name!) from Accessors and AccessorsExtra packages.

The optimization part is directly delegated to Optimization. Other backends are possible, but best to add them as methods to Optimization proper and use from AccessibleOptimization.

These packages have generally similar goals, but neither provides all features AccessibleOptimization or Accessors do: