# How to make if in the objective function

**URL:** <https://discourse.julialang.org/t/how-to-make-if-in-the-objective-function/46859>\
**Category:** Optimization (Mathematical)\
**Created:** [September 18, 2020, 5:13pm UTC](https://discourse.julialang.org/t/how-to-make-if-in-the-objective-function/46859 "2020-09-18T17:13:26Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![sogrbilja](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sogrbilja/32/17521_2.png) [@sogrbilja](https://discourse.julialang.org/u/sogrbilja)\
**Post date:** [September 18, 2020, 5:13pm UTC](https://discourse.julialang.org/t/how-to-make-if-in-the-objective-function/46859/1 "2020-09-18T17:13:26Z")

</div>

Here is the function

```julia
        @objective(
            prmx,
            Min,
            sum(
                sum(
                    UNITS[u_k]["cap"] - sum(
                        PRODAMOUNT[op_k, u_k, t] * _PRODUCTs_ALL[op["product"]]["bagSize"] 
                        for (op_k, op) in _ORDER_PRODUCTs_ALL
                    )
                for u_k in keys(UNITS)
                )
            for t in TIME
            )
        )

```

How to change UNITS[u\_k][“cap”] to be zero if sum(PRODAMOUNT…) is zero in given objective function?

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [September 18, 2020, 5:23pm UTC](https://discourse.julialang.org/t/how-to-make-if-in-the-objective-function/46859/2 "2020-09-18T17:23:50Z")

</div>

I would suggest defining the function in general in a less “compact” way, which will make transparent that kind of condition:

```julia
function f(parameters?)

  sum1 = sum( PRODAMOUNT[op_k, u_k, t] * _PRODUCTs_ALL[op["product"]]["bagSize"] 
                        for (op_k, op) in _ORDER_PRODUCTs_ALL )
  if sum1 == 0
      ...
  end
  sum2 = sum(UNITS[u_k]["cap"] - sum1...)
  sum3 = ...

end

@objective(prmx,Min,f)

```

Also, by doing so, I at least would find much easier to take care of types of parameters, avoiding global variables, etc.

---

<div class="post-metadata">

**Author:** ![sogrbilja](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sogrbilja/32/17521_2.png) [@sogrbilja](https://discourse.julialang.org/u/sogrbilja)\
**Post date:** [September 18, 2020, 5:25pm UTC](https://discourse.julialang.org/t/how-to-make-if-in-the-objective-function/46859/3 "2020-09-18T17:25:26Z")

</div>

> [@lmiq](#):
>
> ```julia
> function f(parameters?)
> 
> sum1 = sum( PRODAMOUNT[op_k, u_k, t] * _PRODUCTs_ALL[op["product"]]["bagSize"] 
> for (op_k, op) in _ORDER_PRODUCTs_ALL )
> if sum1 == 0
> ...
> end
> sum2 = sum(UNITS[u_k]["cap"] - sum1...)
> sum3 = ...
> 
> end
> 
> ```

thanks, let me try that…

---

<div class="post-metadata">

**Author:** ![sogrbilja](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sogrbilja/32/17521_2.png) [@sogrbilja](https://discourse.julialang.org/u/sogrbilja)\
**Post date:** [September 18, 2020, 5:36pm UTC](https://discourse.julialang.org/t/how-to-make-if-in-the-objective-function/46859/4 "2020-09-18T17:36:47Z")

</div>

I’ve created function this way:

```julia
        function goal()
            total = 0
            for t in TIME
                for (u_k, u) in UNITS
                    sum1 = sum(PRODAMOUNT[op_k, u_k, t] * _PRODUCTs_ALL[op["product"]]["bagSize"] 
                                        for (op_k, op) in _ORDER_PRODUCTs_ALL)
                    if sum1 > 0
                        total += u["cap"] - sum1
                    end
                end
            end
            return total
        end
      
      
        @objective(
            prmx,
            Min,
            goal
        )

```

but I am getting error:

> ERROR: LoadError: The objective function `goal` is not supported by JuMP.

---

<div class="post-metadata">

**Author:** ![sogrbilja](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sogrbilja/32/17521_2.png) [@sogrbilja](https://discourse.julialang.org/u/sogrbilja)\
**Post date:** [September 18, 2020, 5:57pm UTC](https://discourse.julialang.org/t/how-to-make-if-in-the-objective-function/46859/5 "2020-09-18T17:57:48Z")

</div>

And if I write it like this:

```julia
        function goal(u_k, t)
            sum1 = sum(PRODAMOUNT[op_k, u_k, t] * _PRODUCTs_ALL[op["product"]]["bagSize"] 
                                for (op_k, op) in _ORDER_PRODUCTs_ALL)
            if sum1 > 0
                sum1 = UNITS[u_k]["cap"] - sum1
            end
    
            return sum1
        end
      
      
        @objective(
            prmx,
            Min,
            sum(
                sum( 
                    goal(u_k, t)
                for u_k in keys(UNITS)
                )
            for t in TIME
            )
        )

```

I am then getting this error:

> ERROR: LoadError: MethodError: no method matching isless(::Int64, ::GenericAffExpr{Float64,VariableRef})

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [September 18, 2020, 6:25pm UTC](https://discourse.julialang.org/t/how-to-make-if-in-the-objective-function/46859/6 "2020-09-18T18:25:45Z")

</div>

I would be nice if you provided a minimal code to be tested. It is not clear to me what is the flexibility of the `@objective ` macro of JuMP in accepting functions coded differently. The examples in the manual are quite restrictive.

---

<div class="post-metadata">

**Author:** ![sogrbilja](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sogrbilja/32/17521_2.png) [@sogrbilja](https://discourse.julialang.org/u/sogrbilja)\
**Post date:** [September 18, 2020, 6:59pm UTC](https://discourse.julialang.org/t/how-to-make-if-in-the-objective-function/46859/7 "2020-09-18T18:59:56Z")

</div>

> [@lmiq](#):
>
> The examples in the manual are quite restrictive.

I started coding in julia / jump just two weeks ago and I am not familiar with its syntax yet. Can you please share with me those examples in the manual?

I can share with you the complete code if you want, just tell me where I should send it to you?

I’ve managed this, but still, it is not working properly:

```julia
        function goal(u_k, t)
            sum1 = sum(PRODAMOUNT[op_k, u_k, t] * _PRODUCTs_ALL[op["product"]]["bagSize"] 
                                for (op_k, op) in _ORDER_PRODUCTs_ALL)
                                    
            if sum1 == 0
            else
                sum1 = (UNITS[u_k]["cap"] - sum1) * UNITS[u_k]["util_cost1"]
            end
    
            return sum1
        end
      
        @objective(
            prmx,
            Min,
            sum(
                sum( 
                    goal(u_k, t)
                for u_k in keys(UNITS)
                )
            for t in TIME
            )
        )

```

Now the objective value of the solved model is 1172286, but when I output the results it says: 92282

So something is going on in behind that I can’t see…

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [September 18, 2020, 7:37pm UTC](https://discourse.julialang.org/t/how-to-make-if-in-the-objective-function/46859/8 "2020-09-18T19:37:32Z")

</div>

I am not familiar with JuMP either. I have used `Optim` instead, and I prefer its syntax in general:

> **[Optim.jl](https://julianlsolvers.github.io/Optim.jl/stable/#user/minimization/)**
>
> Pure Julia implementations of optimization algorithms.

---

<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 18, 2020, 7:57pm UTC](https://discourse.julialang.org/t/how-to-make-if-in-the-objective-function/46859/9 "2020-09-18T19:57:46Z")

</div>

Please refrain from posting the same question multiple times:

> [@Why the results of my model remain the same even if the objective value changes?](https://discourse.julialang.org/t/why-the-results-of-my-model-remain-the-same-even-if-the-objective-value-changes/46817):
>
> I am struggling with modeling so much, for me what is logical is not so in the model. The next thing is how to force the system to change results by changing the objective value, so let me explain. I see we can only have one objective value and that is OK. So my guessing is that the system will try to Min (or Max) the value of the objective function by changing the variable(s), is that correct? In my objective function I have 2 parts: @variable(premex, PRODAMOUNT[op\_k in keys(\_ORDER\_P…

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [September 18, 2020, 10:14pm UTC](https://discourse.julialang.org/t/how-to-make-if-in-the-objective-function/46859/10 "2020-09-18T22:14:40Z")

</div>

I understand that you have some parameter that define your objective function. Using Optim you would do something like (which I think it is quite natural):

```julia
using Optim
pars = [1, 2, 3]
f(x) = pars[1]*x[1]^2 + pars[2]*x[2]^2 + (x[3]-pars[3])^2
x0 = rand(3) 
r = optimize(f,x0)

```

Result:

```julia
julia> r = optimize(f,x0)
 * Status: success

 * Candidate solution
    Final objective value: 4.408826e-09

 * Found with
    Algorithm: Nelder-Mead

 * Convergence measures
    √(Σ(yᵢ-ȳ)²)/n ≤ 1.0e-08

 * Work counters
    Seconds run: 0 (vs limit Inf)
    Iterations: 63
    f(x) calls: 124

julia> r.minimizer
3-element Array{Float64,1}:
 -3.578322069066043e-7
 -2.8679363307059896e-5
  3.0000525707764787

```

This is using the NelderMead algorithm, which does not use derivatives. You can choose a different algorithm, and use automatic derivatives, with, for example:

```julia
julia> r = optimize(f,x0,LBFGS(),autodiff=:forward)
 * Status: success

 * Candidate solution
    Final objective value: 7.896313e-33

 * Found with
    Algorithm: L-BFGS

 * Convergence measures
    |x - x'| = 3.53e-01 ≰ 0.0e+00
    |x - x'|/|x'| = 1.18e-01 ≰ 0.0e+00
    |f(x) - f(x')| = 3.32e-01 ≰ 0.0e+00
    |f(x) - f(x')|/|f(x')| = 4.21e+31 ≰ 0.0e+00
    |g(x)| = 2.22e-16 ≤ 1.0e-08

 * Work counters
    Seconds run: 0 (vs limit Inf)
    Iterations: 2
    f(x) calls: 5
    ∇f(x) calls: 5

```

Result:

```julia
julia> r.minimizer
3-element Array{Float64,1}:
 -4.163336342344337e-17
  5.551115123125783e-17
  3.0

```

Here you can define the function naturally using loops, conditionals, etc:

```julia
julia> function f(x)
         f = 0.
         for i in 1:length(x)
            f = f + (x[i]-pars[i])^2
         end
         return f
       end
f (generic function with 1 method)

julia> r = optimize(f,x0,LBFGS(),autodiff=:forward)

julia> r.minimizer
3-element Array{Float64,1}:
 1.0
 2.0
 3.0

```

---

<div class="post-metadata">

**Author:** ![tomerarnon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomerarnon/32/3170_2.png) [@tomerarnon](https://discourse.julialang.org/u/tomerarnon)\
**Post date:** [September 18, 2020, 10:54pm UTC](https://discourse.julialang.org/t/how-to-make-if-in-the-objective-function/46859/11 "2020-09-18T22:54:33Z")

</div>

First let me say this is a lot more readable, and therefore much more accessible to folks eager to help!  
However, as @odow mentioned in the other thread, assuming `_PRODUCTs_ALL` or `PRODAMOUNT` contain variables, this is not possible. The result of `sum1` is an expression containing variables, and this expression is _not a number_, so when you compare it to 0, the answer is _always false_. This is clearly not the behavior you want. Unfortunately, what you want to have happen is entirely impossible. You need to introduce a binary variable as discussed in that thread that will determine which branch to take based on the value of the expression. This is sometimes called a Big-M formulation, and @odow gave an example of the approach [here](https://discourse.julialang.org/t/why-the-results-of-my-model-remain-the-same-even-if-the-objective-value-changes/46817/2)

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [September 19, 2020, 12:46am UTC](https://discourse.julialang.org/t/how-to-make-if-in-the-objective-function/46859/12 "2020-09-19T00:46:41Z")

</div>

I was playing with JuMP now, and this is how you can define a function with multiple variables and conditionals, etc. I’m not sure if this is part of your problem though. Anyway, I only found how to do this in other discourse threads:

```julia
julia> using JuMP

julia> model = Model()
A JuMP Model
Feasibility problem with:
Variables: 0
Model mode: AUTOMATIC
CachingOptimizer state: NO_OPTIMIZER
Solver name: No optimizer attached.

julia> @variable(model,x[1:3])
3-element Array{VariableRef,1}:
 x[1]
 x[2]
 x[3]

julia> function f(x)
         f = 0.
         for i in 1:length(x)
            if i == 1 
              f = f + (x[i]-pars[i])^2
            else
              f = f + (x[i]+pars[i])^2
            end
         end
         return f
       end
f (generic function with 1 method)

julia> pars = [1, 2, 3]
3-element Array{Int64,1}:
 1
 2
 3

julia> @objective(model, Min, f(x)) # note the f(x) ( not simply f )
x[1]² + x[2]² + x[3]² - 2 x[1] + 4 x[2] + 6 x[3] + 14

```

---

<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 19, 2020, 2:05am UTC](https://discourse.julialang.org/t/how-to-make-if-in-the-objective-function/46859/13 "2020-09-19T02:05:12Z")

</div>

There is a distinction between conditionals on parameters of the model (i.e., conditionals at the model creation time) and conditionals on variable values (i.e., conditionals at the model evaluation/solving time).

The approach you describe works for conditionals on model parameters (creation time). In your example, you build a non-linear objective function (i.e., variables multiply each other) and the assemblage of the objective function uses `if` statements. Nice, but this is literally just building a (possibly complicated) polynomial **before** running the model, and passing the polynomial object to JuMP. How the polynomial was built, if conditionals were used or not, is irrelevant to JuMP. JuMP just received an object describing a polynomial and will pass it to the underlying solver. As for any other method call, the called method (i.e., `@objective` in this case) has no idea how the values passed as arguments to it were produced. The fact `@objective` is a macro may lead to confusion, as a macro could have a peek at how the values were produced, but this is not the case here.

The problem is that @sogrbilja wants the JuMP model to behave differently depending on which values the `x` variables assume during the model solving process by `JuMP`/‘underlying solver’. This behaviour cannot be straightforwardly described by a simple polynomial object, the conditional must be inside the polynomial, inside the formula, but the polynomial/formula object does not support this construction. This is the reason your suggestion

```julia
  sum1 = sum( PRODAMOUNT[op_k, u_k, t] * _PRODUCTs_ALL[op["product"]]["bagSize"] 
                        for (op_k, op) in _ORDER_PRODUCTs_ALL )
  if sum1 == 0

```

will not work: `sum1 == 0` always evaluates to `false`. `sum1` is a “polynomial” object with variables `x` which are of unknown value before solving the model, `sum1` is never just the number zero. For @sogrbilja to obtain what he wants, the conditional must be inserted inside the “polynomial” object, for the solver to deal with it during the solving process. There is a trick for doing something like this, and it was mentioned by @odow and reiterated by @tomerarnon:

This is sometimes called a Big-M formulation, and @odow gave an example of the approach [here](https://discourse.julialang.org/t/why-the-results-of-my-model-remain-the-same-even-if-the-objective-value-changes/46817/2)

Big-M formulations have weak bounds and may be hard to prove optimality with them, but they are the only alternative I am aware if you want to model the problem as a MILP (Mixed-Integer Linear Program).

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [September 19, 2020, 9:34am UTC](https://discourse.julialang.org/t/how-to-make-if-in-the-objective-function/46859/14 "2020-09-19T09:34:27Z")

</div>

Nice. To me it nor clear what he wants, really. For a general, possibly dynamic objective function, I would use a derivative free solver (NelderMead, for example). Still my impression is that there is some confusion on what the function to be minimized is, or how build the model.

Not sure if he still needs help, but if so I’ll begin suggesting him to explain clearly his problem: which are the variables? Which are the parameters? What is the expected outcome? Etc.

---

<div class="post-metadata">

**Author:** ![sogrbilja](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sogrbilja/32/17521_2.png) [@sogrbilja](https://discourse.julialang.org/u/sogrbilja)\
**Post date:** [September 19, 2020, 10:53am UTC](https://discourse.julialang.org/t/how-to-make-if-in-the-objective-function/46859/15 "2020-09-19T10:53:22Z")

</div>

Thank you all for giving me directions, the latest modification I’ve made is this:

```julia

            @variable(prmx, PRODAMOUNT[op_k in keys(_ORDER_PRODUCTs_ALL), u_k in keys(UNITS), t in TIME], Int, lower_bound = 0)
            @variable(prmx, UNIT_NOT_IN_USE[u_k in keys(UNITS), t in TIME], Bin)

    @constraint(
        prmx,
        [u_k in keys(UNITS), t in TIME],
        sum(PRODAMOUNT[op_k, u_k, t] * _PRODUCTs_ALL[op["product"]]["bagSize"]
            for (op_k, op) in _ORDER_PRODUCTs_ALL) - UNITS[u_k]["cap"] * (1 - UNIT_NOT_IN_USE[u_k, t]) <= 0
    )   

        @objective(
            prmx,
            Max,
            sum(
                sum( 
                     UNIT_NOT_IN_USE[u_k, t]
                for u_k in keys(UNITS)
                )
            for t in TIME
            )
        )

```

This way I will try to maximize units that are not in use thus also maximizing the overall utilization of units as well.

Hope this time I did it right 😃
