What is the meaning of multiple objective functions?

I have multiple objective functions in my code, created by a loop around the @objective macro. Here’s the code:

using JuMP
using MosekTools
K = 3
N = 2
penalties = [1.0, 3.9, 8.7]
function fac1(r::Number, i::Number, l::Number)
    fac1 = 1.0
    for m in 0:r-1
        fac1 *= (i-m)*(l-m)
    end
    return fac1
end


function fac2(r::Number, i::Number, l::Number, tau::Float64)
   return tau ^ (i + l - 2r + 1)/(i + l - 2r + 1)
end

function Q_r(i::Number, l::Number, r::Number, tau::Float64)
    if i >= r && l >= r
        return 2 * fac1(r, i, l) * fac2(r, i, l, tau)
    else
        return 0.0
    end
end


function Q(i::Number, l::Number, tau::Number)
    elem = 0
    for r in 0:N
        elem += penalties[r + 1] * Q_r(i, l, r, tau)
    end
    return elem
end

# discrete segment starting times
mat = Array{Float64, 3}(undef, K, N+1, N+1)
function Q_mat()
    for k in 0:K-1
        for i in 1:N+1
            for j in 1:N+1
                mat[k+1, i, j] = Q(i, j, convert(Float64, k))
            end
        end
        return mat
    end
end

function A_tau(r::Number, n::Number, tau::Float64)
    fac = 1
    for m in 1:r
        fac *= (n - (m - 1))
    end
    if n >= r
        return fac * tau ^ (n - r)
    else
        return 0.0
    end
end

function A_tau_mat(tau::Float64)
    mat = Array{Float64, 2}(undef, N+1, N+1)
    for i in 1:N+1
        for j in 1:N+1
            mat[i, j] = A_tau(i, j, tau)
        end
    end
    return mat
end

function A_0(r::Number, n::Number)
    if r == n
        fac = 1
        for m in 1:r
            fac *= r - (m - 1)
        end
        return fac
    else
        return 0.0
    end
end

m = Model(optimizer_with_attributes(Mosek.Optimizer, "QUIET" => false, "INTPNT_CO_TOL_DFEAS" => 1e-7))


@variable(m, A[i=1:K+1,j=1:K,k=1:N+1,l=1:N+1])
@variable(m, p[i=1:K+1,j=1:N+1])

# constraint difference might be a small fractional difference.
# assuming that time difference is 1 second starting from 0.
for i in 1:K
    @constraint(m, -A_tau_mat(convert(Float64, i-1)) * p[i] .+ A_tau_mat(convert(Float64, i-1)) * p[i+1] .== [0.0, 0.0, 0.0])
end

for i in 1:K+1
    @constraint(m, A_tau_mat(convert(Float64, i-1)) * p[i] .== [1.0 12.0 13.0])
end
@constraint(m, A_tau_mat(convert(Float64, K+1)) * p[K+1] .== [0.0 0.0 0.0])

for i in 1:K+1
    @objective(m, Min, p[i]' * Q_mat()[i] * p[i])
end

optimize!(m)
println("p value is ", value.(p))

The code runs successfully. What does it mean to have multiple objective functions? If there are multiple objective functions, then which one is being minimized? Are they being minimized jointly?

There is only one objective function, @objective replaces the last objective function set so only the last @objective call is taken into account.

2 Likes

Is @constraint replaced in the for loop too? If that’s the case, then how to programmatically specify K number of constraints as is the case in the above code?

No, each @constraint macro creates a new constraint. There can by arbitrarily many constraints but only one objective.

2 Likes

I agree with blegat, the each new objective replaces the previous objective. Eventually, you run the optimization code with the last objective defined. That is, however, an issue when using BilevelJuMP to define a bilevel optimization problem with multiple lower-level (second-level) programs. There are no examples as to how that can be done without the new lower-level program objective replacing the previous one. See here:

https://github.com/joaquimg/BilevelJuMP.jl/issues/1