# Passing an array of variables to a user-defined non-linear function

**URL:** <https://discourse.julialang.org/t/passing-an-array-of-variables-to-a-user-defined-non-linear-function/4132>\
**Category:** Optimization (Mathematical)\
**Tags:** question, jump\
**Created:** [June 7, 2017, 9:55am UTC](https://discourse.julialang.org/t/passing-an-array-of-variables-to-a-user-defined-non-linear-function/4132 "2017-06-07T09:55:29Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![axsk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/axsk/32/1952_2.png) [@axsk](https://discourse.julialang.org/u/axsk)\
**Post date:** [June 7, 2017, 9:55am UTC](https://discourse.julialang.org/t/passing-an-array-of-variables-to-a-user-defined-non-linear-function/4132/1 "2017-06-07T09:55:29Z")

</div>

I am trying to optimize a multivariate function with JuMP, but can’t find a way to pass the arguments.

The current code is:

```julia
using JuMP                                                                                                                                                                                                                                                                                                                 
n=100                                                                                                                                                              
m=Model()                                                                                                                                                                                 
@variable(m, 0 <= x[1:n] <= 1)                                                         
f(x) = rand() # doenst matter here                                                                                                                                                        
df(x) = rand(n) # "                                                                                                                                                                                                                                                                                                                                                            
JuMP.register(m, :obj, n, (x...)->f(x), (g,x...)->(g[:] = df(x)))
# and now the line in question:                                                                                                                                                                                                                                                                                                                                                                                                                                                                
@NLobjective(m, Max, obj(x))                                                                                                                                                                                                                                                                                                                                  
solve(m)

```

No matter how I try denoting the NLobjective, I get the error

```julia
ERROR: Incorrect number of arguments for "obj" in nonlinear expression.
 in error(::String) at ./error.jl:21

```

I also tried obj(x…) but this lead to the same result.

How would I specify this the correct way?

---

<div class="post-metadata">

**Author:** ![y4lu](https://avatars.discourse-cdn.com/v4/letter/y/47e85d/32.png) [@y4lu](https://discourse.julialang.org/u/y4lu)\
**Post date:** [June 7, 2017, 10:20am UTC](https://discourse.julialang.org/t/passing-an-array-of-variables-to-a-user-defined-non-linear-function/4132/2 "2017-06-07T10:20:46Z")

</div>

I tried methods(obj) and got nothing, is it (obj) a part of the JuMP module?  
You also have :obj, which kind of reads as a column header(?)

I wouldn’t have thought … is valid code

* * *

```julia
using JuMP

function f(x...)
  rand(length(x))
  end;

m = model()
param = 100;
@variable(m, 0 <= pvars[1:param] <= 1)
JuMP.register(m, :f, param, f, f)
@NLobjective(m, Max, f(x...))
solve(m)

```

---

<div class="post-metadata">

**Author:** ![axsk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/axsk/32/1952_2.png) [@axsk](https://discourse.julialang.org/u/axsk)\
**Post date:** [June 7, 2017, 10:35am UTC](https://discourse.julialang.org/t/passing-an-array-of-variables-to-a-user-defined-non-linear-function/4132/3 "2017-06-07T10:35:27Z")

</div>

I define obj as a JuMP-specific user-defined function via the register call (c.f. [jump docs](http://jump.readthedocs.io/en/stable/nlp.html#user-defined-functions))

Concerning the splatting operator `...` you might want to look up the [julia docs](https://docs.julialang.org/en/stable/manual/functions/#varargs-functions).

Anyone else got some ideas?

---

<div class="post-metadata">

**Author:** ![y4lu](https://avatars.discourse-cdn.com/v4/letter/y/47e85d/32.png) [@y4lu](https://discourse.julialang.org/u/y4lu)\
**Post date:** [June 7, 2017, 10:54am UTC](https://discourse.julialang.org/t/passing-an-array-of-variables-to-a-user-defined-non-linear-function/4132/4 "2017-06-07T10:54:45Z")

</div>

Do you need to define the obj function ?

- Edit: You’ve registered the :obj symbol and passed an anonymous definition but there is no function named obj outside the jump model, where you’re calling obj(x)

- II: from the jump docs

 ![](https://global.discourse-cdn.com/julialang/original/3X/7/2/728b7f2accb0bdee01edd9cbc932c2d75ce32d45.png)

---

<div class="post-metadata">

**Author:** ![miles.lubin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/miles.lubin/32/279_2.png) [@miles.lubin](https://discourse.julialang.org/u/miles.lubin)\
**Post date:** [June 7, 2017, 12:00pm UTC](https://discourse.julialang.org/t/passing-an-array-of-variables-to-a-user-defined-non-linear-function/4132/5 "2017-06-07T12:00:10Z")

</div>

This syntax is not supported: [Nonlinear Modeling — JuMP -- Julia for Mathematical Optimization 0.17 documentation](http://www.juliaopt.org/JuMP.jl/0.17/nlp.html#syntax-notes)

> All expressions must be simple scalar operations. You cannot use dot, matrix-vector products, vector slices, etc.

If all you’re doing is minimizing an unconstrained function, JuMP does very little for you. I’d recommend using Optim or calling Ipopt directly.

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [June 7, 2017, 12:20pm UTC](https://discourse.julialang.org/t/passing-an-array-of-variables-to-a-user-defined-non-linear-function/4132/6 "2017-06-07T12:20:39Z")

</div>

Perhaps what you are looking for can be achieved with `@eval`. For example, taking `n = 3`, the code looks like:

```julia
m = Model(solver=IpoptSolver(print_level=0))
n=3
@variable(m, 0 <= x[1:n] <= 1)
f(x...) = rand()
df(g,x...) = g[:] = rand(n)
JuMP.register(m, :obj, n, f, df)

```

The problematic `@NLobjective` could be specialized for `n=3` as:

```julia
@NLobjective(m, Max, obj(x[1],x[2],x[3]))

```

and this would work. To make it work for other `n` defined at _runtime_, we could build-up this expression and `@eval` it, as follows:

```julia
@eval @NLobjective(m, Max, $(Expr(:call, :obj, [Expr(:ref,:x,i) for i=1:n]...)))

```

This works, but I’m not really sure, it’s the way to solve the underlying optimization problem.

---

<div class="post-metadata">

**Author:** ![miles.lubin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/miles.lubin/32/279_2.png) [@miles.lubin](https://discourse.julialang.org/u/miles.lubin)\
**Post date:** [June 7, 2017, 12:27pm UTC](https://discourse.julialang.org/t/passing-an-array-of-variables-to-a-user-defined-non-linear-function/4132/7 "2017-06-07T12:27:09Z")

</div>

That’s also valid, but I would only recommend it to people who understand what’s going on there.

---

<div class="post-metadata">

**Author:** ![axsk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/axsk/32/1952_2.png) [@axsk](https://discourse.julialang.org/u/axsk)\
**Post date:** [June 7, 2017, 1:49pm UTC](https://discourse.julialang.org/t/passing-an-array-of-variables-to-a-user-defined-non-linear-function/4132/8 "2017-06-07T13:49:03Z")

</div>

@Dan: Thank you for the metaway 🙂  
Beeing a macro though, i hoped that `@NLobjective` was able to do that transformation itself, do you think this might be worth a ticket?

> If all you’re doing is minimizing an unconstrained function, JuMP does very little for you. I’d recommend using Optim or calling Ipopt directly.

I also have linear constraints so `Ipopt` would be the way to go.  
I already implemented the optimization using `NLopt` but was hoping to find a more optimizer-agnostic formulation using `JuMP` (although it by now only uses `Ipopt ` for these problems).

I suppose `MathProgBase` is the other way to go then?

Do I need to define all the methods for AbstractNonlinearModel as in the [docs](http://mathprogbasejl.readthedocs.io/en/latest/nlp.html)?

How does `JuMP` handle nonlinear problems using `Ipopt` without the supply of the second derivatives (in the `Ipopt` docs these are necessary)?

---

<div class="post-metadata">

**Author:** ![axsk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/axsk/32/1952_2.png) [@axsk](https://discourse.julialang.org/u/axsk)\
**Post date:** [June 7, 2017, 2:09pm UTC](https://discourse.julialang.org/t/passing-an-array-of-variables-to-a-user-defined-non-linear-function/4132/9 "2017-06-07T14:09:33Z")

</div>

Further reading helped 🙂

Ipopt also includes a L-BGFS hessian approximation. This is enabled automatically using MathProgBase if the :Hess feature is not enabled.

So far for the theory, lets see if I can get it running!

---

<div class="post-metadata">

**Author:** ![axsk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/axsk/32/1952_2.png) [@axsk](https://discourse.julialang.org/u/axsk)\
**Post date:** [June 7, 2017, 3:07pm UTC](https://discourse.julialang.org/t/passing-an-array-of-variables-to-a-user-defined-non-linear-function/4132/10 "2017-06-07T15:07:02Z")

</div>

Good news: The MathProbBase approach works 😄

Bad news: When trying your JuMP eval suggestion I get the error

```julia
ERROR: LoadError: UndefVarError: m not defined

```

Interpolating it with $m leads to the next error

```julia
ERROR: LoadError: UndefVarError: x not defined

```

where I don’t know how to continue, since my ‘meta’ is rather rusty 😉

Guess I’ll stick to the `MathProgBase` solution for now.

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [June 7, 2017, 3:58pm UTC](https://discourse.julialang.org/t/passing-an-array-of-variables-to-a-user-defined-non-linear-function/4132/11 "2017-06-07T15:58:45Z")

</div>

Glad to hear `MathProgBase` is working. It is a cleaner way to go (and probably more robust to changes). As for `@eval`, it works in the _global_ scope, and thus would not find `m` and `x` if they are defined locally in a function. It is mainly a work-around, and also points the way to and the fact, that meta-programs i.e. code generation can sometimes solve thorny problems, especially syntactic problems.

---

<div class="post-metadata">

**Author:** ![miles.lubin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/miles.lubin/32/279_2.png) [@miles.lubin](https://discourse.julialang.org/u/miles.lubin)\
**Post date:** [June 23, 2017, 4:15pm UTC](https://discourse.julialang.org/t/passing-an-array-of-variables-to-a-user-defined-non-linear-function/4132/12 "2017-06-23T16:15:03Z")

</div>

A nicer workaround for this has been proposed at [Julia+JuMP: variable number of arguments to function - Stack Overflow](https://stackoverflow.com/questions/44710900/juliajump-variable-number-of-arguments-to-function/44711305#44711305). It uses the raw expression input format instead of macros.
