Best practices for dealing with functions taking multiple vector variables

Sometimes I want to use a function like f(x,y,z,w), where x,y,z,w are themselves vectors of potentially different lengths. But sometimes when I call solvers (e.g. NLSolve, Optim, Implicit Differentiation, JuMP) or other functions from packages, they want me to pass in a function with just one argument or perhaps 2 arguments, but I think not, say, 4 arguments.

What is the recommended way to deal with this? I could join x,y,z,w into one big vector using vcat and then pass it into the solvers as a single argument, but then it might be annoying to have to keep track of which part parts of the concatenated vector correspond to which of the four initial vectors.

I know this is a broad question, but does anyone have suggestions on this? Thanks

Usually, I do the following:

optimize(x -> f(x, y, z, w), args...)

where x is a vector of parameters to be optimized. There might be more performant ways of passing additional arguments.

If x,y, z and w are parameters that you are optimizing, I think they need to be put into a single vector.

2 Likes

If all are variables of your problem, you may have to put them in a single vector. You could do that and create something like:

vars = (
    x = @view(vec[1:10]),
    y = @view(vec[11:30]),
    etc.
)

Where vec is the complete vector. Then you can access each set with vars.x, vars.y, etc.

Be careful to put all that inside a function, such that y, z, w are not globals.

2 Likes

I think that is good advice. If I remember correctly, another possibility is to return a new function that captures the other arguments, but there is a bug causing performance issues. I think it might be Fix type instability of closures capturing types (2) by simeonschaub · Pull Request #40985 · JuliaLang/julia · GitHub

But in principle, I think you could also do the following once the bug is fixed:

gen(x, y, z, w) = x -> f(x, y, z, w)
f = gen(x, y z, w)
optimize(f, args...)

Is that true, or am I misunderstanding?

I think it should be

Still, this to be inside a function, otherwise f is a non constant global.

1 Like

ArrayPartition from RecursiveArrayTools is a nice way to handle this. It behaves like the concatenated array but allows access to the original arrays by property name.