Why the results of my model remain the same even if the objective value changes?

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_PRODUCTs_ALL), u_k in keys(UNITS), t in TIME], Int, lower_bound = 0)

        @objective(
            premex,
            Min,
            sum(
                sum(
                    (
                        (
                            sum(
                                PRODAMOUNT[op_k, u_k, t] 
                                for (op_k, op) in _ORDER_PRODUCTs_ALL
                            )
                             == 0 ? 0 : u["cap"]
                        ) - 
                        sum(
                            PRODAMOUNT[op_k, u_k, t] * _PRODUCTs_ALL[op["product"]]["bagSize"] 
                            for (op_k, op) in _ORDER_PRODUCTs_ALL
                        )
                    ) * u["util_cost1"]
                for (u_k, u) in UNITS
                )  
                +
                sum(
                    sum(
                        PRODAMOUNT[op_k, u_k, t] 
                        == 0 ? 0 :
                        (t > _ORDERs_ALL[op["order"]]["details"]["deadline"] ? (t - _ORDERs_ALL[op["order"]]["details"]["deadline"]) * 1000000 : 0)
                    for (op_k, op) in _ORDER_PRODUCTs_ALL
                    )
                for (u_k, u) in UNITS
                )
            for t in TIME
            )
        )

as you can see outer loop is TIME, the first part of it is:

                sum(
                    (
                        (
                            sum(
                                PRODAMOUNT[op_k, u_k, t] 
                                for (op_k, op) in _ORDER_PRODUCTs_ALL
                            )
                             == 0 ? 0 : u["cap"]
                        ) - 
                        sum(
                            PRODAMOUNT[op_k, u_k, t] * _PRODUCTs_ALL[op["product"]]["bagSize"] 
                            for (op_k, op) in _ORDER_PRODUCTs_ALL
                        )
                    ) * u["util_cost1"]
                for (u_k, u) in UNITS
                )  

This should force the minimum waste of machines’ capacity. After running with only this part the model is giving objective_value(premex) = 1.172286e6

The next part:

                sum(
                    sum(
                        PRODAMOUNT[op_k, u_k, t] 
                        == 0 ? 0 :
                        (t > _ORDERs_ALL[op["order"]]["details"]["deadline"] ? (t - _ORDERs_ALL[op["order"]]["details"]["deadline"]) * 1000000 : 0)
                    for (op_k, op) in _ORDER_PRODUCTs_ALL
                    )
                for (u_k, u) in UNITS
                )

Should force orders that have a deadline to move up (to be finished first). This I didn’t compose perfectly but it should work. And the objective_value(premex) = 6.4791172286e10 in this case.

As you can see the objective_value changes significantly, but the results remain the same.

I clearly said that if PRODAMOUNT[op_k, u_k, t] == 0 then the system will have no issues, but if not then the penalty should apply (if any). I think this is not enough for the system to recognize what to do to make no penalties.

In other words, how to force model to finish orders that have deadlines first?

This is the same issue as Condition in @objective - #5 by odow.

You cannot put conditions like this in the objective, because they get evaluated with JuMP VariableRef rather than the value of the variable.

You need to use a mixed-integer reformulation.

# Instead of
model = Model()
@variable(model, x[1:2], Bin)
@show sum(x) == 0  # false! because x[1] + x[2] != 0
@objective(model, Min, sum(x) == 0 ? 0 : 1)
@show objective_value(model) # 1.0 <-- a constant!

# Use
model = Model()
@variable(model, x[1:2] >= 0, Int)
@variable(model, y, Bin)
M = 10_000  # A number bigger than optimal `sum(x)`.
@constraint(model, sum(x) - M * y <= 0)
@objective(model, Min, 1 * y)

MIP-modelling is an art, and there are a lot of tradeoffs and tractability issues you need to consider. e.g., how big is M? You’re going to run into issues if you model is large.

3 Likes

So you are suggesting another variable and constant big enough to become bigger than the sum of the original one?

@odow do you have any more complex examples of how to model objective function so I can check them. Maybe I will have more ideas, thanks a lot for your help with this.

And can I do it this way then?

            @variable(premex, PRODAMOUNT[op_k in keys(_ORDER_PRODUCTs_ALL), u_k in keys(UNITS), t in TIME], Int, lower_bound = 0)
            @variable(premex, UTILIZATION[u_k in keys(UNITS), t in TIME], Int, lower_bound = 0)
            @variable(premex, DEADLINE[t in TIME], Int, lower_bound = 0)

    @timeit to "Objective" begin
        @objective(
            premex,
            Min,
            sum(
                sum(
                    UTILIZATION[u_k, t]
                    for (u_k, u) in UNITS
                ) +
                DEADLINE[t]
            for t in TIME
            )
        )
    end

    @timeit to "UTILIZATION" begin
        @constraint(
            premex,
            [u_k in keys(UNITS), t in TIME],
            UTILIZATION[u_k, t] == 
            sum(
                (
                    (
                        sum(
                            PRODAMOUNT[op_k, u_k, t] 
                            for (op_k, op) in _ORDER_PRODUCTs_ALL
                        )
                        == 0 ? 0 : UNITS[u_k]["cap"]
                    ) - 
                    sum(
                        PRODAMOUNT[op_k, u_k, t] * _PRODUCTs_ALL[op["product"]]["bagSize"] 
                        for (op_k, op) in _ORDER_PRODUCTs_ALL
                    )
                ) * UNITS[u_k]["util_cost1"]
            )          
        )    
    end

    @timeit to "DEADLINE" begin
        @constraint(
            premex,
            [t in TIME],
            DEADLINE[t in TIME] == 
            sum(
                sum(
                    PRODAMOUNT[op_k, u_k, t] 
                    == 0 ? 0 :
                    (t - _ORDERs_ALL[op["order"]]["details"]["deadline"]) * 1000000 
                for (op_k, op) in _ORDER_PRODUCTs_ALL
                    if t > _ORDERs_ALL[op["order"]]["details"]["deadline"]
                )
            for (u_k, u) in UNITS
            )    
        )    
    end

Or maybe this way:

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

            @variable(premex, UTILIZATION_CAP[u_k in keys(UNITS), t in TIME], Int, lower_bound = 0)

        @objective(
            premex,
            Min,
            sum(
                UTILIZATION_CAP[u_k, t]
                for (u_k, u) in UNITS, t in TIME
            )
        )

        @constraint(
            premex,
            [op_k in keys(_ORDER_PRODUCTs_ALL), u_k in keys(UNITS), t in TIME],
            PRODAMOUNT[op_k, u_k, t] => 
            {
                UTILIZATION_CAP[u_k, t] == UNITS[u_k]["cap"] -
                sum(
                    PRODAMOUNT[op_k, u_k, t] * _PRODUCTs_ALL[op["product"]]["bagSize"] 
                    for (op_k, op) in _ORDER_PRODUCTs_ALL
                )
            }
        )    

The cookbook has lots of examples: 9 Mixed integer optimization — MOSEK Modeling Cookbook 3.3.0

Instead of posting these code snippets, please post reproducible examples.

model = Model()
@variable(model, x[1:2] >= 0, Int)
@variable(model, y, Bin)
@constraint(model, y => {sum(x) <= 0})
@objective(model, Min, 1 * y)
2 Likes