# Optimisation design advice - metaprogramming/closures

**URL:** <https://discourse.julialang.org/t/optimisation-design-advice-metaprogramming-closures/35264>\
**Category:** General Usage\
**Tags:** question, metaprogramming, optimization\
**Created:** [February 27, 2020, 11:26pm UTC](https://discourse.julialang.org/t/optimisation-design-advice-metaprogramming-closures/35264 "2020-02-27T23:26:43Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![anon32405968](https://avatars.discourse-cdn.com/v4/letter/a/57b2e6/32.png) [@anon32405968](https://discourse.julialang.org/u/anon32405968)\
**Post date:** [February 27, 2020, 11:26pm UTC](https://discourse.julialang.org/t/optimisation-design-advice-metaprogramming-closures/35264/1 "2020-02-27T23:26:43Z")

</div>

Hello. We are trying to optimise parameters for functions that look something like:

```julia
function cost_func(time::Vector{Float64}, params::Vector{Float64})
    cₐ, a, cᵦ, β = params
    return (some complicated combination of time and parameters)
end

```

The number of parameters varies for different models but we always extract them explicitly from the array for stylistic reasons and to avoid typos in the model definition.

**What is the best way to ‘freeze’ one or more of the parameters to a specific value(s) so that the optimisation is only performed on the ‘unfrozen’ parameters?**

Note that the freezing must be able to take place within another function so we must avoid world age issues. Also, we must be optimisation algorithm/library generic so we can’t just set lower and upper limits to just below and above the desired value for the fixed parameters (as some algo/libraries don’t feature bounds).

At the moment we have a rather complex solution defining our models as expressions and using functionwrappers to avoid world age issues. I suspect that we can do something far more straightforward with closures but I haven’t found a way to do it yet.

Many thanks for any advice or thoughts.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 28, 2020, 8:03am UTC](https://discourse.julialang.org/t/optimisation-design-advice-metaprogramming-closures/35264/2 "2020-02-28T08:03:33Z")

</div>

Closures? But it seems you already know about them, so I am not sure what the question is.

---

<div class="post-metadata">

**Author:** ![Karajan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/karajan/32/8545_2.png) [@Karajan](https://discourse.julialang.org/u/Karajan)\
**Post date:** [February 28, 2020, 9:14am UTC](https://discourse.julialang.org/t/optimisation-design-advice-metaprogramming-closures/35264/3 "2020-02-28T09:14:15Z")

</div>

If I understand the questions correctly, the usual way to do something like this with closures is

```julia
f(a, b, c) = a + b + c

optimize((b, c) -> f(5, b, c))

```

or similar. This way you only have to provide two parameters and `a` is set as `5`.

---

<div class="post-metadata">

**Author:** ![anon32405968](https://avatars.discourse-cdn.com/v4/letter/a/57b2e6/32.png) [@anon32405968](https://discourse.julialang.org/u/anon32405968)\
**Post date:** [February 28, 2020, 10:26am UTC](https://discourse.julialang.org/t/optimisation-design-advice-metaprogramming-closures/35264/4 "2020-02-28T10:26:41Z")

</div>

Hello @Tamas_Papp and @Karajan , thanks both for your responses.

Yes I agree that would be a nice way to do it, but how is it possible when the arguments takes the form of a vector of floats? Is there a zero-overhead way to add some abstraction on top of that? And also, it needs to be done in a generic, programatic way (the programmer doesn’t know which parameters the user will want to freeze).

_(edit: in case it’s worth mentioning, a model in our software is actually a struct with four different possible functions that can be fitted/predicted against depending the available data, all use the same parameters. The struct can also contain additional info such as params as a tuple of symbols)_

---

<div class="post-metadata">

**Author:** ![Karajan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/karajan/32/8545_2.png) [@Karajan](https://discourse.julialang.org/u/Karajan)\
**Post date:** [February 28, 2020, 10:47am UTC](https://discourse.julialang.org/t/optimisation-design-advice-metaprogramming-closures/35264/5 "2020-02-28T10:47:26Z")

</div>

I’m not sure I understand correctly what the specific setting is for you but I’ll try.

You can do the following:

```julia
# I'm using a buffer array here so I don't have to allocate a new
# array when going from length 3 to 4.
function wrapper(optim_array, buffer_array, index, value)
    found = 0
    for i in 1:length(buffer_array)
        if i == index
            buffer_array[i] = value
            found = 1
        else
            buffer_array[i] = optim_array[i - found]
        end
    end
    @show buffer_array
    cost_function(buffer_array)
end

buffer_array = zeros(4)
optimize(x -> wrapper(x, buffer_array, 3, 5), ...)

```

It hasn’t zero overhead but pretty close to it.

```julia
cost_function(x) = sum(x)

@btime wrapper($(ones(3)), $(zeros(4)), 3, 5)
  11.918 ns (0 allocations: 0 bytes)
8.0

```

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 28, 2020, 10:47am UTC](https://discourse.julialang.org/t/optimisation-design-advice-metaprogramming-closures/35264/6 "2020-02-28T10:47:38Z")

</div>

> [@anon32405968](#):
>
> how is it possible when the arguments takes the form of a vector of floats? Is there a zero-overhead way to add some abstraction on top of that?

There are various simple ways to do this using higher-order functions, but please keep in mind that asking for a fully optimized, zero-overhead, and convenient solution without providing an MWE is somewhat unrealistic.

> [@Please read: make it easier to help you](https://discourse.julialang.org/t/psa-make-it-easier-to-help-you/14757):
>
> Welcome to the Julia Discourse! We are enthusiastic about helping Julia programmers, both beginner and experienced. This public service announcement (PSA) outlines best practices when asking for help. Following these points makes it easier for us to help you and more likely you’ll get a prompt, useful answer. Keywords are highlighted to make it easier to refer to specific points. Choose a descriptive title that captures the key part of your question, eg “plots with multiple axes” instead of …

---

<div class="post-metadata">

**Author:** ![anon32405968](https://avatars.discourse-cdn.com/v4/letter/a/57b2e6/32.png) [@anon32405968](https://discourse.julialang.org/u/anon32405968)\
**Post date:** [March 18, 2020, 11:57am UTC](https://discourse.julialang.org/t/optimisation-design-advice-metaprogramming-closures/35264/7 "2020-03-18T11:57:38Z")

</div>

@Karajan many thanks for your suggested solution. Although I didn’t end up using it, the idea of a wrapper function was exactly what I needed so I am very grateful. In case it is of use to anyone at all I present a minimum working example of the way I eventually designed the software. Note that in benchmarks there is no significant overhead.

The main components:

```julia
struct ModelStruct
    name::String
    free_params::Tuple
    fixed_params::NamedTuple
    G::Function
end

function ModelStruct(;name::String="Custom model", free::Tuple=(), fixed::NamedTuple=NamedTuple{}(), G)
   ModelStruct(name, free, fixed, G)
end

function freeze_params(orig::ModelStruct, tofix::NamedTuple)
    newfree = Tuple([i for i in orig.free_params if !(i in keys(tofix))])
    newfixed = merge(orig.fixed_params, tofix)
    ModelStruct(orig.name, newfree, newfixed, orig.G)
end

function moduluswitharrayinput(t_or_ω::Vector{Float64}, numparams::Vector{Float64}, modulusfunc::Function, freeparams::Tuple, fixedargs::NamedTuple)
    freeargs = NamedTuple{freeparams}(numparams)
    args = merge(freeargs, fixedargs)
    modulusfunc.(t_or_ω; args...)
end

```

And how this looks in use:

```julia
function test_function1(t; η, kᵦ, kᵧ)
    kᵧ + kᵦ*exp(-t*kᵦ/η)
end

tester = ModelStruct(name="Test model", free = (:η, :kᵦ, :kᵧ), G = test_function1)
freeze_params(tester, (η = 1.0,))

```

So the `ModelStruct` keeps track of which parameters are free and which are fixed. The optimiser only ‘sees’ a wrapper function `moduluswitharrayinput` which combines the fixed parameters with the ones it is trying to optimise for and sends these combined to the actual objective function.
