# JuMP: User defined functions with vector inputs and outputs

**URL:** https://discourse.julialang.org/t/jump-user-defined-functions-with-vector-inputs-and-outputs/106025
**Category:** Optimization (Mathematical)
**Tags:** jump
**Created:** [November 10, 2023, 5:39am UTC](https://discourse.julialang.org/t/jump-user-defined-functions-with-vector-inputs-and-outputs/106025 "2023-11-10T05:39:27Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![A\_C](https://avatars.discourse-cdn.com/v4/letter/a/da6949/32.png) [@A\_C](https://discourse.julialang.org/u/A_C)
#### Post date: [November 10, 2023, 5:39am UTC](https://discourse.julialang.org/t/jump-user-defined-functions-with-vector-inputs-and-outputs/106025/1 "2023-11-10T05:39:27Z")

</div>

In the JuMP documentation it is mentioned that functions with vector inputs and outputs require a [workaround](https://jump.dev/JuMP.jl/stable/manual/nonlinear/#jump_user_defined_operators). However the following example works:

> **MWE**
>
> ```julia
> using JuMP
> import Ipopt
> 
> mwe = Model(Ipopt.Optimizer)
> 
> @variable(mwe, x[1:5])
> @variable(mwe, y[1:5])
> 
> xref = ones(5)*10
> yref = ones(5)*20
> 
> function obj(x, y, xref, yref)
> sum = zero(eltype(x))
> for i=1:length(xref)
> sum = sum + (x[i] - xref[i])^2 + (y[i] - yref[i])^2
> end
> 
> return [sum, sum]
> end
> 
> @objective(mwe, Min, obj(x[1:5], y[1:5], xref, yref)[1])
> 
> optimize!(mwe)
> 
> println("Value of x and y : ", [value.(x) value.(y)])
> 
> ```

It is not clear from the docs if user defined functions with vector inputs and outputs are supported?

I could even write an RK4 scheme for direct optimal control nicely:

> **RK4.jl**
>
> ```julia
> using JuMP
> import Ipopt
> using GLMakie
> 
> dubins = Model(Ipopt.Optimizer)
> 
> vm = 1.0 # Max forward speed
> um = 1.0 # Max turning speed
> ns = 3 # Number of states
> nu = 1 # Number of inputs
> n = 200 # Time steps
> 
> # System dynamics
> function f(x, u)
> return [vm*cos(x[3]), vm*sin(x[3]), u]
> end
> 
> # Objective Function
> function obj_f(x, u, Δt)
> return Δt
> end
> 
> # Decision variables
> @variables(dubins, begin
> 0 <= Δt <= 0.05 # Time step
> # State variables
> x[1:3,1:n] # Velocity
> # Control variables
> -um ≤ u[1:1,1:n] ≤ um # Thrust
> end)
> 
> # Objective
> @objective(dubins, Min, obj_f(x[1:3,1:n], u[1,1:n], Δt))
> #Initial conditions
> @constraint(dubins, x[1:3, 1] .== [0, 0, -π/2] )
> # Final conditions
> @constraint(dubins, x[1:3, n] == [5.0, 5.0, π/2 + π/4])
> 
> # Dynamic constraints: RK4
> for j in 1:n-1
> k1 = f(x[1:3,j], u[j])
> k2 = f(x[1:3,j] + Δt*k1/2, u[j])
> k3 = f(x[1:3,j] + Δt*k2/2, u[j])
> k4 = f(x[1:3,j] + Δt*k3, u[j])
> @constraint(dubins, x[1:3, j+1] == x[1:3,j] + Δt*(k1 + 2*k2 + 2*k3 + k4)/6)
> end
> 
> # Solve for the control and state
> println("Solving...")
> optimize!(dubins)
> solution_summary(dubins)
> 
> # Display results
> println("Min time: ", objective_value(dubins)*n)
> 
> fig = Figure()
> ax = Axis(fig[1,1], autolimitaspect = 1)
> lines!(ax, value.(x[1,1:n]), value.(x[2, 1:n]))
> fig
> 
> ```

---

<div class="post-metadata">

### Author: ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)
#### Post date: [November 10, 2023, 8:26pm UTC](https://discourse.julialang.org/t/jump-user-defined-functions-with-vector-inputs-and-outputs/106025/2 "2023-11-10T20:26:24Z")

</div>

The restriction to user-defined functions with vector outputs applies only to functions that you registered with `@operator`.

In your examples, you are using the function-tracing feature, which builds a `NonlinearExpr` object, and so everything works.

I agree that this isn’t clear in the documentation, so I need to improve it.

---

<div class="post-metadata">

### Author: ![A\_C](https://avatars.discourse-cdn.com/v4/letter/a/da6949/32.png) [@A\_C](https://discourse.julialang.org/u/A_C)
#### Post date: [November 11, 2023, 1:55am UTC](https://discourse.julialang.org/t/jump-user-defined-functions-with-vector-inputs-and-outputs/106025/3 "2023-11-11T01:55:07Z")

</div>

Thanks a lot for the clarification. What are the limitations of the function-tracing approach? And when is it necessary to use `@operator` for function registration?

If it may be of help for documentation: most of the examples in the Nonlinear section add constraint equations one at a time. Hence, it creates an impression that the vectors are not supported. Maybe it would be helpful to add an example which uses function-tracing?

---

<div class="post-metadata">

### Author: ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)
#### Post date: [November 11, 2023, 2:28am UTC](https://discourse.julialang.org/t/jump-user-defined-functions-with-vector-inputs-and-outputs/106025/4 "2023-11-11T02:28:22Z")

</div>

> [@A\_C](#):
>
> What are the limitations of the function-tracing approach?

It needs to use only operators for which operator overloading has been implemented. Your `obj` example uses only `+`, `-` and `^`.

It won’t work for something like `LinearAlgebra.det(x' * x)` or `call_to_c_library(x)`.

In general, using function tracing is preferred to registering an operator, except for when the function produces a very large expression.

> If it may be of help for documentation: most of the examples in the Nonlinear section add constraint equations one at a time. Hence, it creates an impression that the vectors are not supported. Maybe it would be helpful to add an example which uses function-tracing?

Yip. And in addition, I think I need to add a section explaining what functions tracing is, and what the benefits and limitations are 😄.

My initial hope was that things like `obj(...)` would just work (it does), and people wouldn’t get confused, but I guess they do!

---

<div class="post-metadata">

### Author: ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)
#### Post date: [November 12, 2023, 4:18am UTC](https://discourse.julialang.org/t/jump-user-defined-functions-with-vector-inputs-and-outputs/106025/5 "2023-11-12T04:18:05Z")

</div>

I’ve opened a PR to improve the documentation: [[docs] add section on function tracing by odow · Pull Request #3570 · jump-dev/JuMP.jl · GitHub](https://github.com/jump-dev/JuMP.jl/pull/3570). Let me know if you have any comments.

---

<div class="post-metadata">

### Author: ![A\_C](https://avatars.discourse-cdn.com/v4/letter/a/da6949/32.png) [@A\_C](https://discourse.julialang.org/u/A_C)
#### Post date: [November 13, 2023, 4:10am UTC](https://discourse.julialang.org/t/jump-user-defined-functions-with-vector-inputs-and-outputs/106025/6 "2023-11-13T04:10:13Z")

</div>

Thanks a lot. I will try out some examples from optimal control with this approach and report if I face any issues.
