# \[ANN\] AccessibleOptimization: optimization with arbitrary objects instead of vectors

**URL:** <https://discourse.julialang.org/t/ann-accessibleoptimization-optimization-with-arbitrary-objects-instead-of-vectors/99695>\
**Category:** Package Announcements\
**Created:** [May 31, 2023, 10:16pm UTC](https://discourse.julialang.org/t/ann-accessibleoptimization-optimization-with-arbitrary-objects-instead-of-vectors/99695 "2023-05-31T22:16:14Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [May 31, 2023, 10:16pm UTC](https://discourse.julialang.org/t/ann-accessibleoptimization-optimization-with-arbitrary-objects-instead-of-vectors/99695/1 "2023-05-31T22:16:14Z")

</div>

> # `AccessibleOptimization`
> 
> 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.

# Motivation

Suppose you need to optimize parameters of a function that takes some Julia object as its input. Maybe it’s a model you want to fit to some data, maybe it’s just an optimization problem.

There are various optimization packages in Julia, surely they can help here. But they typically work with parameters as a vector, or at least a vector-like object, so arbitrary user/package-defined structs should be manually converted to/from vectors.

Several packages aim to help with this conversion. AFAIK, the most generic, composable and extensible approach is optics by `Accessors.jl`. Even with `Accessors`, there is a lot of boilerplate back/forth conversions, especially noticeable for small adhoc problems.

`AccessibleOptimization` is a thin wrapper around `Optimization.jl`, that uses `Accessors` + `AccessorsExtra` machinery to flexibly define target parameters for optimization, using arbitrary structs as function inputs.

# Usage

A simple example, using just (named)tuples:

```julia-auto
# define a model (sum-of-sqexps) and a loss function to optimize:
expsum(m::Tuple, x) = sum(c -> c.scale * exp(-(x - c.shift)^2), m)
loss(m, data) = sum(d -> abs2(d.y - expsum(m, d.x)), data)

data = ... # collection of points with x and y

using IntervalSets
using AccessibleOptimization # reexports everything from Optimization and AccessorsExtra

# define which parameters to optimize, and what are their bounds
vars = OptArgs(
    # component shifts - values from 0..10:
    @o(_[∗].shift) => 0..10.,
    # component scales - positive-only (log10 transformation), from 10^-1 to 10^1:
    @o(log10(_[∗].scale)) => -1..1,
)

# create and solve the optimization problem, interface very similar to Optimization.jl
mod0 = ((
	(scale=1, shift=1),
	(scale=1, shift=2),
	(scale=1, shift=3),
))
ops = OptProblemSpec(Base.Fix2(loss, data), mod0, vars)
sol = solve(ops, ECA(), maxiters=300)
sol.uobj # the optimal model
loss(sol.uobj, data)

```

See the [README](https://gitlab.com/aplavin/AccessibleOptimization.jl) for more details, and the [Pluto notebook](https://aplavin.github.io/AccessibleOptimization.jl/examples/notebook.html) for examples that include custom structs, more involved parameter transformations, and constraints.

# See also

- [Accessors](https://github.com/JuliaObjects/Accessors.jl) and [AccessorsExtra](https://gitlab.com/aplavin/AccessorsExtra.jl) packages for generically referring to parts and transformations of arbitrary objects (so-called “optics”)
- [PlutoTables](https://discourse.julialang.org/t/ann-plutotables-edit-any-julia-object-in-a-tabular-interface/99696) using a very similar approach to define tabular editing UI for Julia objects

`AccessibleOptimization.jl` has just been registered in `General`.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 1, 2023, 12:04pm UTC](https://discourse.julialang.org/t/ann-accessibleoptimization-optimization-with-arbitrary-objects-instead-of-vectors/99695/2 "2023-06-01T12:04:38Z")

</div>

This looks great. Could we just merge it into Optimization.jl / SciMLBase? We’ve been wanting to handle some canonicalization for awhile.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [June 2, 2023, 9:28am UTC](https://discourse.julialang.org/t/ann-accessibleoptimization-optimization-with-arbitrary-objects-instead-of-vectors/99695/3 "2023-06-02T09:28:47Z")

</div>

It could make sense, but I’m not sure what the interface should be, and could it be used for something else in addition to Optimization.  
The current state of AccessibleOptimization just grew from my annoyance of manually putting `Accessors.getall`/`setall` everywhere and keeping track of the parameter vector. Maybe, something better is possible, open to suggestions.

I don’t understand sciml internals and type hierarchy well… `AccessibleOptimization` defines its own types for “optimization problem” and “optprob solution” to convert object ↔ vector automatically when needed.  
Btw, no code there really depends on `Optimization`, only on `SciMLBase`. Optimization is loaded just to reexport it, because actually using AccessibleOptimization requires it anyway.

---

<div class="post-metadata">

**Author:** ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)\
**Post date:** [June 2, 2023, 10:00am UTC](https://discourse.julialang.org/t/ann-accessibleoptimization-optimization-with-arbitrary-objects-instead-of-vectors/99695/4 "2023-06-02T10:00:30Z")

</div>

Shameless plug: [GitHub - JuliaNonconvex/Nonconvex.jl: Toolbox for non-convex constrained optimization.](https://github.com/JuliaNonconvex/Nonconvex.jl) already supports arbitrary decision variables. It is even [documented](https://julianonconvex.github.io/Nonconvex.jl/stable/problem/model/#Variable-definition).

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [June 2, 2023, 10:06am UTC](https://discourse.julialang.org/t/ann-accessibleoptimization-optimization-with-arbitrary-objects-instead-of-vectors/99695/5 "2023-06-02T10:06:34Z")

</div>

I may’ve missed that package, but looking at the docs I don’t see if supports the same flexibility as `AccessibleOptimization`.  
Can you give a simple example comparable to that in the [README here](https://gitlab.com/aplavin/AccessibleOptimization.jl)? Where the model struct and the target function are defined first, without any regard to optimization and with no restrictions, and separately after that one specifies what parts of the model struct to vary in optimization.

---

<div class="post-metadata">

**Author:** ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)\
**Post date:** [June 2, 2023, 10:39am UTC](https://discourse.julialang.org/t/ann-accessibleoptimization-optimization-with-arbitrary-objects-instead-of-vectors/99695/6 "2023-06-02T10:39:01Z")

</div>

Not quite the same but similar enough.

```julia
struct ExpModel{A,B}
    scale::A
    shift::B
end
(m::ExpModel)(x) = m.scale * exp(-(x - m.shift)^2)

lb = [ExpModel(0.3, 0.0)]
ub = [ExpModel(10.0, 10.0)]
x0 = [ExpModel(5.0, 5.0)]

data = (x = rand(10), y = rand(10))

loss(m::Vector{<:ExpModel}, data) = sum(abs2.(data.y - m[1].(data.x)))

obj = Base.Fix2(loss, data)

using Nonconvex
Nonconvex.@load Metaheuristics

alg = MetaheuristicsAlg(ECA)

options = MetaheuristicsOptions(N = 1000)

model = Model(obj)

addvar!(model, lb, ub)

res = optimize(model, alg, x0; options)

```

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [June 2, 2023, 10:54am UTC](https://discourse.julialang.org/t/ann-accessibleoptimization-optimization-with-arbitrary-objects-instead-of-vectors/99695/7 "2023-06-02T10:54:46Z")

</div>

Yes, in the simple case it’s similar indeed.  
AccessibleOptimization also lets you choose what parameters to modify in optimization, and add variable transformation.  
No model modification needed, just change optimization variables definition:

```julia
# vary shifts and scales of all components
vars = OptArgs(
    @o(_[∗].shift) => 0..10.,
    @o(_[∗].scale) => 0..10,
)

# same, but log-transform scales:
vars = OptArgs(
    @o(_[∗].shift) => 0..10.,
    @o(log10(_[∗].scale)) => -1..1,
)

# keep the first component parameters fixed, only vary 2 and 3:
vars = OptArgs(
    @o(_[2:3][∗].shift) => 0..10.,
    @o(log10(_[2:3][∗].scale)) => -1..1,
)

# only vary scales, keep shifts fixed:
vars = OptArgs(
    @o(log10(_[∗].scale)) => -1..1,
)

```

and so on.

---

<div class="post-metadata">

**Author:** ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)\
**Post date:** [June 2, 2023, 12:51pm UTC](https://discourse.julialang.org/t/ann-accessibleoptimization-optimization-with-arbitrary-objects-instead-of-vectors/99695/8 "2023-06-02T12:51:54Z")

</div>

Can probably do that already by using a lower bound that’s equal to the upper bound. Internally, we can then eliminate such variables. But many solvers will already eliminate decision variables whose lower and upper bounds are the same. Also you can easily define custom ways to linearize structs and go back in Nonconvex.jl by overloading a method. But I will stop derailing this post now. Congratulations on your package!

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [June 2, 2023, 3:05pm UTC](https://discourse.julialang.org/t/ann-accessibleoptimization-optimization-with-arbitrary-objects-instead-of-vectors/99695/9 "2023-06-02T15:05:21Z")

</div>

That’s not derailing, always nice to see alternative approaches to fundamentally the same problem!

Maybe it’s “with a hammer, everything looks like a nail”, but I really like how `Accessors` deal with selecting and transforming values. `AccessibleOptimization` itself is a thin wrapper, real work is done downstream.

---

<div class="post-metadata">

**Author:** ![SteffenPL](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/steffenpl/32/206270_2.png) [@SteffenPL](https://discourse.julialang.org/u/SteffenPL)\
**Post date:** [June 7, 2023, 5:28am UTC](https://discourse.julialang.org/t/ann-accessibleoptimization-optimization-with-arbitrary-objects-instead-of-vectors/99695/10 "2023-06-07T05:28:54Z")

</div>

@aplavin Nice package!

It might still be nice to have a limited version of this in `Optimization.jl`, I’m working with a student who would maybe be interested in doing a small PR to `Optimization.jl` (maybe less powerful than your interface).

I wanted to check with you, not that we both do the same thing!

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [June 7, 2023, 1:07pm UTC](https://discourse.julialang.org/t/ann-accessibleoptimization-optimization-with-arbitrary-objects-instead-of-vectors/99695/11 "2023-06-07T13:07:53Z")

</div>

`AccessibleOptimization` in its current state already covers everything I wanted from it beforehand, so I don’t plan to add any other major features or integrations. This may change over time, of course.  
Please let me know if some related features are missing or interface could be better, there’s likely something I didn’t imagine (:

It would be nice to include arbitrary objects handling into `Optimization.jl` itself, but I don’t feel familiar with the codebase, and a separate package works just fine for me.

---

<div class="post-metadata">

**Author:** ![SteffenPL](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/steffenpl/32/206270_2.png) [@SteffenPL](https://discourse.julialang.org/u/SteffenPL)\
**Post date:** [June 7, 2023, 1:31pm UTC](https://discourse.julialang.org/t/ann-accessibleoptimization-optimization-with-arbitrary-objects-instead-of-vectors/99695/12 "2023-06-07T13:31:57Z")

</div>

Sounds good. So, it would be fine for you if we work on the integration (maybe borrowing a bit of your ideas)?

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [June 7, 2023, 2:24pm UTC](https://discourse.julialang.org/t/ann-accessibleoptimization-optimization-with-arbitrary-objects-instead-of-vectors/99695/13 "2023-06-07T14:24:15Z")

</div>

Sure! That’s the point of open sources and permissive licenses.

---

<div class="post-metadata">

**Author:** ![Vaibhavdixit02](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vaibhavdixit02/32/2916_2.png) [@Vaibhavdixit02](https://discourse.julialang.org/u/Vaibhavdixit02)\
**Post date:** [June 8, 2023, 5:26pm UTC](https://discourse.julialang.org/t/ann-accessibleoptimization-optimization-with-arbitrary-objects-instead-of-vectors/99695/14 "2023-06-08T17:26:39Z")

</div>

Look forward to seeing the PR! Feel free to ping me on slack if you run into any blockers.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [September 14, 2025, 3:53am UTC](https://discourse.julialang.org/t/ann-accessibleoptimization-optimization-with-arbitrary-objects-instead-of-vectors/99695/15 "2025-09-14T03:53:53Z")

</div>

Check out [AccessibleModels.jl: Automatic UI and Model Fitting for Arbitrary Objects](https://discourse.julialang.org/t/accessiblemodels-jl-automatic-ui-and-model-fitting-for-arbitrary-objects/132363) : it builds on the positive experience creating and using this package, improving further.

AccessibleModels.jl provides a uniform model definition syntax for a bunch of backends instead of Optimizationjl-only here. Backends include optimization, MCMC sampling, and even UI generation.

I consider AccessibleOptimization.jl effectively deprecated now: it still works fine, but AccessibleModels.jl has all its features & more, and I recommend using that package instead.
