# Optimization using JuMP

**URL:** https://discourse.julialang.org/t/optimization-using-jump/89720
**Category:** Optimization (Mathematical)
**Tags:** jump
**Created:** [November 3, 2022, 3:06pm UTC](https://discourse.julialang.org/t/optimization-using-jump/89720 "2022-11-03T15:06:56Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![JUL1A](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jul1a/32/47432_2.png) [@JUL1A](https://discourse.julialang.org/u/JUL1A)
#### Post date: [November 3, 2022, 3:06pm UTC](https://discourse.julialang.org/t/optimization-using-jump/89720/1 "2022-11-03T15:06:56Z")

</div>

I’m trying to code an optimization problem in Julia using `JuMP`. The objective function has two matrix multiplications.  
**First** , multiply the vector of `w` with size (10) by the matrix of `arr_C` with size (20, 10). So the `w` should be transposed to size (1, 10) to perform matrix multiplication.  
**Second** , multiply the vector of `w_each_sim` with size (20) by the result of the first multiplication, which is also a vector of size (20). So the multiplication should be like (1x20) x (20x1) to achieve a scalar. Please read until the last line of the question because I applied updates in various ways.  
My first try is as follows:

```julia-auto
julia> using JuMP, Ipopt

julia> a = rand(20, 10);

julia> b = rand(20); b = b./sum(b)

julia> function port_opt(
            n_assets::Int8,
            arr_C::Matrix{Float64},
            w_each_sim::Vector{Float64})
        """
        Calculate weight of each asset through optimization

        Parameters
        ----------
            n_assets::Int8 - number of assets
            arr_C::Matrix{Float64} - array of C
            w_each_sim::Vector{Float64} - weights of each similar TW

        Returns
        -------
            w_opt::Vector{Float64} - weights of each asset
        """

        model = Model(Ipopt.Optimizer)
        @variable(model, 0<= w[1:n_assets] <=1)
        @NLconstraint(model, sum([w[i] for i in 1:n_assets]) == 1)
        @NLobjective(model, Max, w_each_sim * log10.([w[i]*arr_C[i] for i in 1:n_assets]))
        optimize!(model)

        @show value.(w)
        return value.(w)
    end

julia> port_opt(Int8(10), a, b)
ERROR: UndefVarError: i not defined
Stacktrace:
 [1] macro expansion
   @ C:\Users\JL\.julia\packages\JuMP\Z1pVn\src\macros.jl:1834 [inlined]
 [2] port_opt(n_assets::Int8, arr_C::Matrix{Float64}, w_each_sim::Vector{Float64})
   @ Main e:\MyWork\paperbase.jl:237
 [3] top-level scope
   @ REPL[4]:1

```

The problem is with the `@NLconstraint` line.  
How can I make this code work and get the optimization done?

## Aditional tests

I rectified the objective function as follows:

```julia-auto
function Obj(w, arr_C, w_each_sim)

    first_expr = w'*arr_C'
    second_expr = map(first_expr) do x
        log10(x)
    end

    return w_each_sim * second_expr
end

function port_opt(
        n_assets::Int8,
        arr_C::Matrix{Float64},
        w_each_sim::Vector{Float64})
    

    ....
    ....
    @NLconstraint(model, sum(w[i] for i in 1:n_assets) == 1)
    @NLobjective(model, Max, Obj(w, arr_C, w_each_sim))
    optimize!(model)

    @show value.(w)
    return value.(w)
end

a, b = rand(20, 10), rand(20); b = b./sum(b);
port_opt(Int8(10), a, b)

# Threw this:
ERROR: Unexpected array VariableRef[w[1], w[2], w[3], w[4], w[5], w[6], w[7], w[8], w[9], w[10]] in nonlinear expression. Nonlinear expressions may contain only scalar expressions.

```

Then I tried this:

```julia-auto
function Obj(w, arr_C::Matrix{T}, w_each_sim::Vector{T}) where {T<:Real}

    first_expr = zeros(T, length(w_each_sim))
    for i∈size(w_each_sim, 1), j∈eachindex(w_each_sim)
        first_expr[i] += w[j]*arr_C[i, j]
    end

    second_expr = map(first_expr) do x
        log(x)
    end

    res = 0
    for idx∈eachindex(w_each_sim)
        res += w_each_sim[idx]*second_expr[idx]
    end

    return res
end

function port_opt(
        n_assets::Int8,
        arr_C::Matrix{Float64},
        w_each_sim::Vector{Float64})

    model = Model()
    @variable(model, 0<= w[1:n_assets] <=1)
    @NLconstraint(model, +(w...) == 1)
    register(model, :Obj, Int64(n_assets), Obj, autodiff=true)
    @NLobjective(model, Max, Obj(w, arr_C, w_each_sim))
    optimize!(model)

    @show value.(w)
    return value.(w)
end

a, b = rand(20, 10), rand(20); b = b./sum(b);
port_opt(Int8(10), a, b)

# threw this
ERROR: Unable to register the function :Obj because it does not support differentiation via ForwardDiff.

Common reasons for this include:

 * the function assumes `Float64` will be passed as input, it must work for any
   generic `Real` type.
 * the function allocates temporary storage using `zeros(3)` or similar. This
   defaults to `Float64`, so use `zeros(T, 3)` instead.

```

And finally, I tried this:

```julia-auto
function Obj(the_x...)
    w, arr_C, W_each_sim = the_x
    first_expr = zeros(length(w_each_sim))
    for i∈size(w_each_sim, 1), j∈eachindex(w_each_sim)
        first_expr[i] += w[j]*arr_C[i, j]
    end

    second_expr = map(first_expr) do x
        log(x)
    end

    res = 0
    for idx∈eachindex(w_each_sim)
        res += w_each_sim[idx]*second_expr[idx]
    end

    return res
end

function port_opt(
        n_assets::Int8,
        arr_C::Matrix{Float64},
        w_each_sim::Vector{Float64})

    model = Model()
    @variable(model, 0<= w[1:n_assets] <=1)
    register(model, :Obj, Int64(n_assets), Obj, autodiff=true)
    the_x = [w, arr_C, w_each_sim]
    @NLobjective(model, Max, Obj(the_x...))
    optimize!(model)

    @show value.(w)
    return value.(w)
end
a, b = rand(20, 10), rand(20); b = b./sum(b);
port_opt(Int8(10), a, b)

# Threw this
ERROR: Unexpected array VariableRef[w[1], w[2], w[3], w[4], w[5], w[6], w[7], w[8], w[9], w[10]] in nonlinear expression. Nonlinear expressions may contain only scalar expressions.
Stacktrace:

```

---

<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 3, 2022, 7:02pm UTC](https://discourse.julialang.org/t/optimization-using-jump/89720/2 "2022-11-03T19:02:59Z")

</div>

> [@JUL1A](#):
>
> `@NLobjective(model, Max, w_each_sim * log10.([w[i]*arr_C[i] for i in 1:n_assets]))`

You need

```julia
@NLobjective(model, Max, sum(w_each_sim[i] * log10(w[i]*arr_C[i]) for i in 1:n_assets))

```

There are a number of limitations in the nonlinear interface to JuMP: [Nonlinear Modeling (Legacy) · JuMP](https://jump.dev/JuMP.jl/stable/manual/nlp/#Syntax-notes)

But I’ll see if we can improve the error message.

---

<div class="post-metadata">

### Author: ![JUL1A](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jul1a/32/47432_2.png) [@JUL1A](https://discourse.julialang.org/u/JUL1A)
#### Post date: [November 3, 2022, 8:20pm UTC](https://discourse.julialang.org/t/optimization-using-jump/89720/3 "2022-11-03T20:20:37Z")

</div>

> [@odow](#):
>
> You need
> 
> `@NLobjective(model, Max, sum(w_each_sim[i] * log10(w[i]*arr_C[i]) for i in 1:n_assets))`

Unfortunately, this isn’t true; because neither `w[i]*arr_C[i]` nor `w_each_sim[i] * ...` aren’t matrix multiplication!  
`w` is a vector with a length of 10, and `arr_C` is a Matrix with the shape of (20, 10). So, in this case, `((w[i]*arr_C[i]) for i in 1:n_assets)` isn’t a matrix multiplication! If you would like to know about the objective function, this function is all you need:

```julia
function Obj(w, arr_C::Matrix{T}, w_each_sim::Vector{T}) where {T<:Real}

    first_expr = zeros(T, length(w_each_sim))
    for i∈size(w_each_sim, 1), j∈eachindex(w_each_sim)
        first_expr[i] += w[j]*arr_C[i, j]
    end

    second_expr = map(first_expr) do x
        log(x)
    end

    res = 0
    for idx∈eachindex(w_each_sim)
        res += w_each_sim[idx]*second_expr[idx]
    end

    return res
end

```

`w` is the vector of weights, and `arr_C` is the matrix of relative prices, like \frac{Price\_{day \:i}}{Price\_{day\:i-1}}. `w_each_sim` stands for the weight of each similar Time Window that is a vector with length 20.

---

<div class="post-metadata">

### Author: ![JUL1A](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jul1a/32/47432_2.png) [@JUL1A](https://discourse.julialang.org/u/JUL1A)
#### Post date: [November 3, 2022, 8:40pm UTC](https://discourse.julialang.org/t/optimization-using-jump/89720/4 "2022-11-03T20:40:44Z")

</div>

> [@odow](#):
>
> There are a number of limitations in the nonlinear interface to JuMP: [Nonlinear Modeling · JuMP](https://jump.dev/JuMP.jl/stable/manual/nlp/#Syntax-notes)

Thank you for mentioning this. I tried another way using the `@expression` macro like this:

```julia
using JuMP, Ipopt

function port_opt(
        n_assets::Int8,
        arr_C::Matrix{Float64},
        w_each_sim::Vector{Float64})

    model = Model(Ipopt.Optimizer)
    @variable(model, 0<= w[1:n_assets] <=1)
    @constraint(model, sum(w[i] for i in 1:n_assets) == 1)
    
    @expression(model, cw, w'*arr_C')
    @expression(model, log_cw, [log(item) for item in cw])
    @expression(model, obj_expr, w_each_sim'*log_cw)

    @NLobjective(model, Max, obj_expr)
    optimize!(model)

    @show value.(w)
    return value.(w)
end

```

It threw:

```julia
ERROR: log is not defined for type GenericAffExpr. Are you trying to build a nonlinear problem? Make sure you use @NLconstraint/@NLobjective.

```

Which is an ambiguous error since I already used `@NLobjective` in the objective definition. Also, I don’t know how I should perform the logarithm.

---

<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 3, 2022, 8:49pm UTC](https://discourse.julialang.org/t/optimization-using-jump/89720/5 "2022-11-03T20:49:04Z")

</div>

> Unfortunately, this isn’t true

That’ll teach me for replying without reading the question properly or testing the example. I assumed too much 😆

How about this:

```julia
using JuMP, Ipopt
a = rand(20, 10)
b = rand(20); b = b./sum(b)

"""
Calculate weight of each asset through optimization

Parameters
----------
    n_assets::Int8 - number of assets
    arr_C::Matrix{Float64} - array of C
    w_each_sim::Vector{Float64} - weights of each similar TW

Returns
-------
    w_opt::Vector{Float64} - weights of each asset
"""
function port_opt(
    n_assets::Int8,
    arr_C::Matrix{Float64},
    w_each_sim::Vector{Float64},
)
    model = Model(Ipopt.Optimizer)
    @variable(model, 0<= w[1:n_assets] <=1)
    @NLconstraint(model, sum(w[i] for i in 1:n_assets) == 1)
    @NLobjective(
        model,
        Max, 
        sum(
            w_each_sim[i] * log10(sum(w[j] * arr_C[i, j] for j in 1:size(arr_C, 2)))
            for i in 1:length(w_each_sim)
        )
    )
    optimize!(model)
    return value.(w)
end

port_opt(Int8(10), a, b)

```

---

<div class="post-metadata">

### Author: ![JUL1A](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jul1a/32/47432_2.png) [@JUL1A](https://discourse.julialang.org/u/JUL1A)
#### Post date: [November 3, 2022, 8:52pm UTC](https://discourse.julialang.org/t/optimization-using-jump/89720/6 "2022-11-03T20:52:06Z")

</div>

> [@odow](#):
>
> That’ll teach me for replying without reading the question properly or testing the example.

Your response is heartwarming to me, no matter the result. So, thank you! 🧡

---

<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 3, 2022, 8:52pm UTC](https://discourse.julialang.org/t/optimization-using-jump/89720/7 "2022-11-03T20:52:38Z")

</div>

> [@JUL1A](#):
>
> Which is an ambiguous error

It’s thrown by `@expression(model, log_cw, [log(item) for item in cw])`. We’re experimenting with something that would fix this: [https://github.com/jump-dev/JuMP.jl/pull/3106](https://github.com/jump-dev/JuMP.jl/pull/3106)

---

<div class="post-metadata">

### Author: ![JUL1A](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jul1a/32/47432_2.png) [@JUL1A](https://discourse.julialang.org/u/JUL1A)
#### Post date: [November 3, 2022, 9:00pm UTC](https://discourse.julialang.org/t/optimization-using-jump/89720/8 "2022-11-03T21:00:24Z")

</div>

> [@odow](#):
>
> ```julia
> function port_opt(
> n_assets::Int8,
> arr_C::Matrix{Float64},
> w_each_sim::Vector{Float64},
> )
> model = Model(Ipopt.Optimizer)
> @variable(model, 0<= w[1:n_assets] <=1)
> @NLconstraint(model, sum(w[i] for i in 1:n_assets) == 1)
> @NLobjective(
> model,
> Max, 
> sum(
> w_each_sim[i] * log10(sum(w[j] * arr_C[i, j] for j in 1:size(arr_C, 2)))
> for i in 1:length(w_each_sim)
> )
> )
> optimize!(model)
> return value.(w)
> end
> 
> port_opt(Int8(10), a, b)
> 
> ```

This seems to be exactly like the function which I referred to:

> [@JUL1A](#):
>
> If you would like to know about the objective function, this function is all you need:

I’ll investigate it concisely and reach you with the result. But it seems correct to me until now. Thanks. But, I didn’t learn what the problem was and why I should define the objective function expression like that to work. I mean, what is the problem with this syntax:

```julia
function Obj(w, arr_C::Matrix{T}, w_each_sim::Vector{T}) where {T<:Real}

    first_expr = zeros(T, length(w_each_sim))
    for i∈size(w_each_sim, 1), j∈eachindex(w_each_sim)
        first_expr[i] += w[j]*arr_C[i, j]
    end

    second_expr = map(first_expr) do x
        log(x)
    end

    res = 0
    for idx∈eachindex(w_each_sim)
        res += w_each_sim[idx]*second_expr[idx]
    end

    return res
end

```

This function inherently is the same as `sum( w_each_sim[i] * log10(sum(w[j] * arr_C[i, j] for j in 1:size(arr_C, 2))) for i in 1:length(w_each_sim))`. But I didn’t understand why mine didn’t work. I’m asking this because I want to learn how to define optimization problems in JuMP and what the point is here.

---

<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 3, 2022, 9:05pm UTC](https://discourse.julialang.org/t/optimization-using-jump/89720/9 "2022-11-03T21:05:06Z")

</div>

> But I didn’t understand why mine didn’t work.

The nonlinear interface to JuMP has a number of syntax limitations. You must write out all expressions, and you cannot use things like `map`, broadcasting, or linear algebra. See [Nonlinear Modeling (Legacy) · JuMP](https://jump.dev/JuMP.jl/stable/manual/nlp/#Syntax-notes)

You can use user-defined functions, but they have a limited scope, and must comply with the syntax: [Nonlinear Modeling (Legacy) · JuMP](https://jump.dev/JuMP.jl/stable/manual/nlp/#User-defined-Functions)

---

<div class="post-metadata">

### Author: ![JUL1A](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jul1a/32/47432_2.png) [@JUL1A](https://discourse.julialang.org/u/JUL1A)
#### Post date: [November 3, 2022, 9:06pm UTC](https://discourse.julialang.org/t/optimization-using-jump/89720/10 "2022-11-03T21:06:44Z")

</div>

Thank you so much🧡  
I’ll read the official doc of your great package to fill my understanding gaps.

---

<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 3, 2022, 9:07pm UTC](https://discourse.julialang.org/t/optimization-using-jump/89720/11 "2022-11-03T21:07:54Z")

</div>

> I’ll read the official doc of your great package to fill my understanding gaps.

Let me know if any bits are not clear after reading the docs. We try hard to make them useful, but we’re always open to suggestions for improvements.

---

<div class="post-metadata">

### Author: ![JUL1A](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jul1a/32/47432_2.png) [@JUL1A](https://discourse.julialang.org/u/JUL1A)
#### Post date: [November 3, 2022, 9:10pm UTC](https://discourse.julialang.org/t/optimization-using-jump/89720/12 "2022-11-03T21:10:28Z")

</div>

Your attitude toward users is the cherry on the top of your efforts. Sure I will! Thank you for helping and putting in the time and energy.  
Sorry, where should I mention my questions? Do you suggest any special framework?

---

<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 3, 2022, 9:18pm UTC](https://discourse.julialang.org/t/optimization-using-jump/89720/13 "2022-11-03T21:18:12Z")

</div>

> Sorry, where should I mention my questions?

If they are documentation suggestions and you have a GitHub account, post a comment here: [Suggestions for documentation improvements · Issue #2348 · jump-dev/JuMP.jl · GitHub](https://github.com/jump-dev/JuMP.jl/issues/2348)

Otherwise, open a new post on this forum.
