# Ipopt and external function

**URL:** https://discourse.julialang.org/t/ipopt-and-external-function/47496
**Category:** Optimization (Mathematical)
**Tags:** jump
**Created:** [September 29, 2020, 4:46pm UTC](https://discourse.julialang.org/t/ipopt-and-external-function/47496 "2020-09-29T16:46:10Z")
**Posts on this page:** 12
**Page:** 1

<div class="post-metadata">

### Author: ![danicaratelli](https://avatars.discourse-cdn.com/v4/letter/d/90db22/32.png) [@danicaratelli](https://discourse.julialang.org/u/danicaratelli)
#### Post date: [September 29, 2020, 4:46pm UTC](https://discourse.julialang.org/t/ipopt-and-external-function/47496/1 "2020-09-29T16:46:10Z")

</div>

I am trying to solve a non-linear function using JuMP. From what I saw, I have to use Ipopt and, as [Nonlinear Modeling · JuMP](https://jump.dev/JuMP.jl/v0.20.0/nlp/) says, I cannot directly include the function in the NLobjective. To get around this I define a new variable `aux` and equate it to my external function as suggested (see below) but this does not seem to work. Any ideas what is wrong? Open to other solutions too.

```julia
model = Model(Ipopt.Optimizer)
function fopt(x,y) 
  return (1 - x)^2 + 100 * (y - x^2)^2;
end
@variable(model, x, start = 0.0)
@variable(model, y, start = 0.0)
@variable(model, aux)
@constraint(model, aux == fopt)
@NLobjective(model, Min, aux)

```

I know I could just put the output of `fopt` in the NLobjective, but I would like to know whether there is a way to do this using this approach. At some point, I will have a much more complicated function that I want to minimize.

Thank you!

---

<div class="post-metadata">

### Author: ![lungd](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lungd/32/10913_2.png) [@lungd](https://discourse.julialang.org/u/lungd)
#### Post date: [September 29, 2020, 7:00pm UTC](https://discourse.julialang.org/t/ipopt-and-external-function/47496/2 "2020-09-29T19:00:17Z")

</div>

I think you want to register the function as in: [https://jump.dev/JuMP.jl/latest/nlp/#User-defined-Functions-1](https://jump.dev/JuMP.jl/latest/nlp/#User-defined-Functions-1)

I got a solution of (x=1.0000000000034162, y=1.0000000000069469) with the following code:

```julia
using JuMP
using Ipopt

model = Model(Ipopt.Optimizer)
function fopt(x,y) 
  return (1 - x)^2 + 100 * (y - x^2)^2;
end
@variable(model, x, start = 0.0)
@variable(model, y, start = 0.0)

register(model, :fopt, 2, fopt, autodiff=true)

@NLobjective(model, Min, fopt(x,y))
JuMP.optimize!(model)

```

---

<div class="post-metadata">

### Author: ![danicaratelli](https://avatars.discourse-cdn.com/v4/letter/d/90db22/32.png) [@danicaratelli](https://discourse.julialang.org/u/danicaratelli)
#### Post date: [September 29, 2020, 8:13pm UTC](https://discourse.julialang.org/t/ipopt-and-external-function/47496/3 "2020-09-29T20:13:05Z")

</div>

Thank you! This works great!

Is this how one would solve these sorts of equations in Julia?

In particular, I usually have a very complicated `f()` (calling many other functions, etc) that I want to minimize but also constraining the space in which the inputs of `f` can be.

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [September 29, 2020, 8:27pm UTC](https://discourse.julialang.org/t/ipopt-and-external-function/47496/4 "2020-09-29T20:27:39Z")

</div>

Do you want a best solution (i.e., global optima) or a good-enough solution (local optima)?

---

<div class="post-metadata">

### Author: ![danicaratelli](https://avatars.discourse-cdn.com/v4/letter/d/90db22/32.png) [@danicaratelli](https://discourse.julialang.org/u/danicaratelli)
#### Post date: [September 29, 2020, 8:32pm UTC](https://discourse.julialang.org/t/ipopt-and-external-function/47496/5 "2020-09-29T20:32:29Z")

</div>

> [@Henrique\_Becker](#):
>
> local

Global (within the support).

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [September 29, 2020, 8:40pm UTC](https://discourse.julialang.org/t/ipopt-and-external-function/47496/6 "2020-09-29T20:40:12Z")

</div>

Well, seems like Ipopt works for global optimization:

> [Global convergence of the method is ensured by a line search procedure, based on a filter method.](https://coin-or.github.io/Ipopt/FAQ.html)

I have searched for global solutions for non-linear function only a single time, and I remember that if you want to be able to use a function that may do anything, then you do not have many options. If you just need something that is non-linear but very restricted like two variables multiplying each other, then many commercials solvers have support to that kinda of non-linearity (i.e., quadratic function).

---

<div class="post-metadata">

### Author: ![lungd](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lungd/32/10913_2.png) [@lungd](https://discourse.julialang.org/u/lungd)
#### Post date: [September 29, 2020, 9:08pm UTC](https://discourse.julialang.org/t/ipopt-and-external-function/47496/7 "2020-09-29T21:08:28Z")

</div>

> [@danicaratelli](#):
>
> but also constraining the space in which the inputs of `f` can be.

You could achieve that by adding bounds to the variables `@variable(model, 2 <= x <= 10, start = 0.0)`

---

<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: [September 30, 2020, 1:41am UTC](https://discourse.julialang.org/t/ipopt-and-external-function/47496/8 "2020-09-30T01:41:18Z")

</div>

> seems like Ipopt works for global optimization

This is only correct if the problem is convex.

---

<div class="post-metadata">

### Author: ![briochemc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/briochemc/32/4209_2.png) [@briochemc](https://discourse.julialang.org/u/briochemc)
#### Post date: [September 30, 2020, 4:17am UTC](https://discourse.julialang.org/t/ipopt-and-external-function/47496/9 "2020-09-30T04:17:49Z")

</div>

> [@Henrique\_Becker](#):
>
> Well, seems like Ipopt works for global optimization:
> 
> > [Global convergence of the method is ensured by a line search procedure, based on a filter method.](https://coin-or.github.io/Ipopt/FAQ.html)

I don’t think “global” in this quote means what you think. I just think means that it will converge, to a local optimum, wherever you start from. Actually, the `Ipopt` docs say

> `Ipopt` implements an interior point line search filter method that aims to find a _ **local** _ solution of [(NLP)](https://coin-or.github.io/Ipopt/index.html#NLP).

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [September 30, 2020, 1:41pm UTC](https://discourse.julialang.org/t/ipopt-and-external-function/47496/10 "2020-09-30T13:41:18Z")

</div>

It seems I was wrong. It is really unfortunate that their FAQ use the term _global_ to mean _local_, the two adjectives have a well-defined and opposite meanings in optimization. The entire FAQ page gives no hint it only solves convex problems optimally and that nonconvex problems are limited to local optima.

---

<div class="post-metadata">

### Author: ![danicaratelli](https://avatars.discourse-cdn.com/v4/letter/d/90db22/32.png) [@danicaratelli](https://discourse.julialang.org/u/danicaratelli)
#### Post date: [September 30, 2020, 1:49pm UTC](https://discourse.julialang.org/t/ipopt-and-external-function/47496/11 "2020-09-30T13:49:06Z")

</div>

Yes, I can confirm that it is indeed a **local** solution method. Just a simple example:

```julia
function f(x)
    return abs(5*x^2-(2*x-3)^3);
end
obj(x) = f(pars,x);
model = Model(with_optimizer(Ipopt.Optimizer, max_iter=100, print_level=0));
#adding variables
@variable(model, 0 <= x <= 10);
#register function
register(model, :obj, 1, obj, autodiff=true);
@NLobjective(model, Min, obj(x));
@time xsol_jump = JuMP.optimize!(model);
println("\nValue of x* is = ",string(value(x)))
println("Value of f(x*) is = ",string(f(value(x))))
println("...but Value of f(3.453) is = ",string(f(3.453)))

```

---

<div class="post-metadata">

### Author: ![ccoffrin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ccoffrin/32/400_2.png) [@ccoffrin](https://discourse.julialang.org/u/ccoffrin)
#### Post date: [September 30, 2020, 6:40pm UTC](https://discourse.julialang.org/t/ipopt-and-external-function/47496/12 "2020-09-30T18:40:17Z")

</div>

> [@Henrique\_Becker](#):
>
> seems like Ipopt works for global optimization

Another remark about this point. JuMP’s solver status values provide an indication about properties of the solution that is returned. In the case of Ipopt, the termination status is `LOCALLY_SOLVED`, which indicates that it only ensures local optimality condition. Solvers that provide global optimality conditions would return the status `OPTIMAL`.
