• Gurobi Staff

Please have a look at the Knowledge Base article How do I divide by a variable in Gurobi?

If this is not what you are asking for, please clarify.

Edit: It looks like you are asking about performance degradation. Is this correct? In this case: Did you set tight variable bounds for variables D_edgeand mass_edge? Could you please share a log snippet and possibly a model file. Note that uploading files in the Community Forum is not possible but we discuss an alternative in Posting to the Community Forum.

Best regards,
Jaromił

Thanks for your response.

This is constraint in my code:

for edge in df_edges.index:       model.addConstr((D_edge[edge] * D_edge[edge]) >= (4 * 10e6 * mass_edge[edge] * Bp[edge]) /        (3600 * 3.14 * ro * V_max))

in this constraint the D_edge and mass_edge are continuous variables and Bp is binary variable.

When I run my model with this constraint and with a different objective function that doesn't involve the variable D_edge, the model performs well. However, when I include D_edge in my objective function, it significantly increases the time required for solving, often prompting me to interrupt the process.

I tried your suggestion, but I think it does not work. Can you tell me what is the problem when I put D_edge variable in objective function? Or could you please guide me how I can manage this constraint? Thanks a lot

this constraint is related to the determination of pipe sizes in district heating network. D_edge is diameter of each pipe, mass_edge is mass rate in each pipe and Bp is binary variable for selection the pipe. these are more line of my codes including objective function.

Cost_cap_pi = 0.0#M=1000000Cost_pi = {}for edge in df_edges.index:    # Create a Gurobi variable for each edge    Cost_pi[edge] = model.addVar(vtype=GRB.CONTINUOUS, lb=0, name=f"Cost_pi_{edge}")    # Piping cost calculation    Cost_pi_unit = 5.36 * D_edge[edge] + 139.15 * (Bp[edge]) # CHF/m    model.addConstr(Cost_pi[edge] == Cost_pi_unit * df_edges.at[edge, 'length'])    Cost_cap_pi += Cost_pi[edge]Cost_pi_tot = 2 * Cost_cap_pimodel.setObjective(Cost_pi_tot , GRB.MINIMIZE)
• Gurobi Staff

I tried your suggestion, but I think it does not work. Can you tell me what is the problem when I put D_edge variable in objective function? Or could you please guide me how I can manage this constraint?

In general, there is nothing wrong in using D_edge in your objective. However, with the new constraint your model is now nonconvex which makes the model by itself a lot harder. Additionally, from what you are saying it looks like that if you add D_edge to the objective that this steers the optimal solution point into an area of nonconvexity. There are no good general workarounds for this.

Could you please share a log output of your model? If possible, you could also share your model. You can generate an MPS or an LP file via the write() method. Note that uploading files in the Community Forum is not possible but we discuss an alternative in Posting to the Community Forum.

Best regards,
Jaromił

Thank you.

Here is file link of my code.

for example if i set the objective function without the D_edge variable it works well( such as this file), but if i add the main objective function such as :

# ----------------- Set Objective Function -------------------- #### Capital Cost of piping Cost_cap_pi = 0.0Cost_pi = {}for edge in df_edges.index:    Cost_pi[edge] = model.addVar(vtype=GRB.CONTINUOUS, lb=0, name=f"Cost_pi_{edge}")    # Piping cost calculation    Cost_cap_pi += Cost_pi[edge]Cost_pi_tot = 2 * Cost_cap_pimodel.setObjective(Cost_pi_tot , GRB.MINIMIZE)

it takes a lot of time and didn't give me a solution.
thank you.

• Gurobi Staff

Thank you. Could you please also share the model where Gurobi does not converge well?

• Gurobi Staff

Note that it would be best to again share just the MPS or LP file and not the Python code. If you share the Python code, then you also have to share all files it depends on which might be a lot (and possibly confidential).

• Gurobi Staff

The main difference between the two models is that some continuous variables have now more freedom. In the following I am referring to constraints which you get when you generate the human-readable LP file out of the MPS file. You can do that via, e.g.,

./gurobi_cl resultfile=my_model.lp timelimit=1 my_model.mps

For example

R844: - 56.57181062942548 B2351(5) + C2652(1) = 0

vs

R844: - 303.2249049737206 C2342(2) - 7871.967449084555 B2351(5) + C2652(1) = 0

In the first constraint C2652(1) can attain only 2 values 0 or 56.57181062942548. In the second case C2652(1) can attain many (continuous) values making the proof of global optimality way harder.

In general, the second model will always be way harder to solve than the first one due to the above.

Anyway, you could try the following reformulation:

Use the constraints

R688: - 85.6668337605393 C2(2) - 2223.981327943851 B11(6) + C2496(1) = 0qc250: C12(2) + [ - 0.151888879626705 C1(5) * B11(6) ] = 0qc251: - C12(2) + [ C2(2) ^2 ] >= 0

to first get

R688: - 85.6668337605393 C2(2) - 2223.981327943851 B11(6) + C2496(1) = 0qc251: [ - 0.151888879626705 C1(5) * B11(6) + C2(2) ^2 ] >= 0

and then solve for C2(2) to get

R688:  - 2223.981327943851/85.6668337605393 B11(6) + 1/85.6668337605393 C2496(1) = C2(2)qc251: [ - 0.151888879626705 C1(5) * B11(6) + C2(2) ^2 ] >= 0

Then substitute C2(2) into the square term

qc251: [ - 0.151888879626705 C1(5) * B11(6) + (- 2223.981327943851/85.6668337605393 B11(6) + 1/85.6668337605393 C2496(1)) ^2 ] >= 0

which gives

qc251:  (2223.981327943851/85.6668337605393)^2 B11(6) +  [ - 0.151888879626705 C1(5) * B11(6) - 2 * 2223.981327943851/85.6668337605393 * 1/85.6668337605393 C2496(1) * B11(6) +  (1/85.6668337605393 C2496(1)) ^2 ] >= 0

I used that B11(6)^2 = B11(6) because B11(6) is a binary variable.
You could do this reformulation at the model construction level. There is no guarantee that this helps performance but I think it might be worth a try.

Best regards,
Jaromił

I think it is better I use the root 2 in objective function for that. Can i implement it by

• Gurobi Staff

You could but this would then be a piecewise-linear approximation, see General Functions Constraints docs. Thus, I would stick to the quadratic formulation.

It would also be best if you bound every continuous variable. From looking at your model, I think you could bound every variable between [0,1e+06].

I tried it but it doesn't work (it's same as before). i have a constraint such as:

model.addConstr(aux1[edge] == fix * mass_edge[edge] * Bp[edge])model.addConstr(D_edge[edge] * D_edge[edge] >= (aux1[edge]))

when i delete one of the D_edge[edge] in second line, it works well. i can put the one variable instead D_edge[edge] * D_edge[edge] . but I have a D_edge in objective function, so i need put square root for that. What do you think?

• Gurobi Staff

You could try the square root approach. It might work, but please keep in mind that Gurobi currently works with a piecewise-linear approximation of the $$\sqrt{}$$ function and not with the true $$\sqrt{}$$ function. This might lead to numerical inaccuracies in the final solution.

You also have to make sure that the argument variables are $$\geq 0$$ when working with the $$\sqrt{}$$ function.

Regarding variable bounds: You might want to try and use some problem knowledge you have to bound at least some of the variables without turning the model infeasible.

Yes, but it is very weird because when i want to limit some variables it takes more time. in this special problem when i set this heuristics solver parameter model.setParam(GRB.Param.Heuristics, 0.1) it works. But i have not understood yet what was the problem with my code. I'm scared that it will not be general.

• Gurobi Staff

If finding a good feasible solution point is the bottleneck for your model then setting the Heuristics parameter definitely makes sense.

But i have not understood yet what was the problem with my code. I'm scared that it will not be general.

This is something you could find out through try-and-error and by utilizing as much problem knowledge as possible.

Yes, i guess it too. Thanks a lot.