Multiple MIP starts with the same makespan
AnsweredHello,
I am investigating warm start approaches for resource-constrained project planning. (minimization problem)
I am working with different models for the RCPSP.
The model iam using in the following is the simple time discrete model by Pritzker.
First, I compute start times for the projects/jobs using various heuristics. From these start times, I then construct an initial solution for my model and assign the variables accordingly using .set(GRB.DoubleAttr.Start, 1.0); (or 0.0).
I have several heuristics, each of which is executed multiple times. As a result, I obtain several start time vectors which may have the same makespan but are not entirely identical otherwise. In such cases, I would like to construct a solution from each of these start time vectors and provide them to the solver.
Based on my current implementation, this should already be the case. As described in the Gurobi documentation here https://support.gurobi.com/hc/en-us/articles/360043834831-How-do-I-use-MIP-starts , I use:model.set(GRB.IntAttr.NumStart, startTimesList.size());
and then iterate over each start time vector, settingfor (int s = 0; s < model.get(GRB.IntAttr.NumStart); s++) { model.set(GRB.IntParam.StartNumber, s); …}
(model.update() is executed after each step).
When examining the log:User MIP start 0 produced solution with objective 45 (0.03s)Loaded user MIP start 0 with objective 45User MIP start 1 did not produce a new incumbent solutionUser MIP start 2 did not produce a new incumbent solution
After multiple test runs it becomes apparent that only the first start solution is accepted, while the others are consistently rejected.
According to a post from 12 days ago (https://support.gurobi.com/hc/en-us/articles/15185996954897-What-does-User-MIP-start-did-not-produce-a-new-incumbent-solution-mean), there are several reasons for this log output:
- A Gurobi heuristic during presolve found a solution that matches or surpasses the quality of the MIP start solution.
- For a partial MIP start, the limited exploration did not find a new incumbent solution.
- The provided MIP start is infeasible for the model. In this case, there might be an additional message similar to the following to provide some indication:
User MIP start violates constraint c1 by 2934.000000000
4. There are numerical issues, e.g., the MIP start is only almost feasible or feasible only within tolerances.
Since the first start solution is never rejected, and I have also output and manually checked the start times, the issue cannot be attributed to point 3 or point 4. Furthermore, I do not receive any additional messages.
Because I assign values to all variables, point 2 should also not be the cause.
Thus, the explanation must be point 1: A Gurobi heuristic during presolve found a solution that matches or surpasses the quality of the MIP start solution.
The log indicates that MIP starts are rejected before presolve statistics are printed, which makes me wonder whether they are discarded due to duplication of the objective value (same makespan).User MIP start 0 produced solution with objective 45 (0.03s)Loaded user MIP start 0 with objective 45User MIP start 1 did not produce a new incumbent solutionUser MIP start 2 did not produce a new incumbent solution
Presolve removed 599 rows and 3885 columnsPresolve time: 0.25sPresolved: 114 rows, 188 columns, 1116 nonzerosVariable types: 0 continuous, 188 integer (179 binary)Root barrier log…
so i was asking myself:
Is Gurobi discarding starts simply because their objective value matches an already accepted start, even though the variable assignments differ?
If so, why is it possible to pass multiple start solutions to the solver if only the first one with the minimal makespan is actually used?
Is the option of setting multiple start solutions intended exclusively for multi-objective optimization problems? Yet, in the following forum post (https://support.gurobi.com/hc/en-us/articles/360043834831-How-do-I-use-MIP-starts)from 9 months ago, the following was written:
Note that Gurobi does not currently support adding multiple MIP starts for multi-objective problems.
Therefore, I would like to ask: is it possible to set multiple MIP starts even if they all have the same makespan or not?
In this post(from 6 years ago https://support.gurobi.com/hc/en-us/community/posts/360043361351-Is-there-any-benefit-to-providing-multiple-MIP-starts?input_string=Multiple%20MIP%20starts%20with%20the%20same%20makespan) the following is stated:
"No, the point is that in some cases the user does not have a complete solution at hand, but is just speculating that a certain combination of variable assignments can be extended to a full solution. In such situations, it is often beneficial to provide multiple such assignments so that Gurobi can try to complete different start vectors in the hope that at least one of them yields a solution of good quality.
If you have full start vectors available that are feasible solutions, there is usually no need to provide multiple of them. Just providing the one that leads to the best objective value should be good enough."
sadly that doesnt answer my question what to do with multiple feasible solutions where i cant evaluate a single one as the “best”.
I hope I have not overlooked anything. I will attach the model file and the log file.
Furthermore, I have another question regarding binary variables, which are initialized as follows:startingTimeVars[i][t] = model.addVar(0.0, 1.0, 0.0, GRB.BINARY, "startingTime[" + i + "]_at_[" + t + "]");
(since double obj = 0)
Should these variables be explicitly set to 0 when constructing the start solution?
If I do not set them, especially in models with many binary variables where most of them are supposed to take the value 0, I always receive a warning. This leads me to explicitly set them to 0. However, these variables should by default already have the value 0. What is the best practice for handling such variables?
If you require additional information please let me know. - Tobias
here is the code setting the var start attributes:
if (!startTimesList.isEmpty()) {
Map<Integer, Integer> startTimes = null;
model.set(GRB.IntAttr.NumStart, startTimesList.size());
model.update();
// Iterate through the list of start times and set the start values for the variables
// This allows for multiple MIP starts, where each start time configuration can be tried
// by Gurobi to find a feasible solution faster.
// If there are multiple start times, Gurobi will try each one in sequence and choose the best one.
for (int s = 0; s < model.get(GRB.IntAttr.NumStart); s++) {
model.set(GRB.IntParam.StartNumber, s);
model.update();
System.out.println("Setting MIP start for index: " + s);
startTimes = startTimesList.get(s);
for (int i = 0; i < data.numberJob; i++) {
for (int j = earliestStartTime[i]; j < latestStartTime[i]; j++) {
GRBVar var = model.getVarByName("startingTime[" + i + "]_at_[" + j + "]");
if (var != null) {
if (startTimes.get(i).equals(j)) {
System.out.println("Setting variable for job " + i + " at time " + j + " to 1.0");
var.set(GRB.DoubleAttr.Start, 1.0);
} else {
var.set(GRB.DoubleAttr.Start, 0.0);
}
} else {
System.err.println("Variable for job " + i + " at time " + j + " not found.");
}
}
}
model.update(); // Update the model after setting starts
}
}
model.update(); // Ensure the model is updated after modifying variableshere is the complete log:
Gurobi 12.0.2 (linux64) logging started Di 19 Aug 2025 14:41:29 CEST
Set parameter LogFile to value "linear_model.log"
Gurobi Optimizer version 12.0.2 build v12.0.2rc0 (linux64 - "Ubuntu 22.04.5 LTS")
CPU model: Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz, instruction set [SSE2|AVX|AVX2]
Thread count: 4 physical cores, 8 logical processors, using up to 4 threads
Non-default parameters:
TimeLimit 30
MIPGap 0
Method 2
Threads 4
Academic license 2623289 - for non-commercial use only - registered to ue___@student.kit.edu
Optimize a model with 713 rows, 4073 columns and 36458 nonzeros
Model fingerprint: 0xe86735b8
Variable types: 0 continuous, 4073 integer (4073 binary)
Coefficient statistics:
Matrix range [1e+00, 2e+02]
Objective range [4e+01, 2e+02]
Bounds range [1e+00, 1e+00]
RHS range [1e+00, 1e+01]
User MIP start 0 produced solution with objective 45 (0.03s)
Loaded user MIP start 0 with objective 45
User MIP start 1 did not produce a new incumbent solution
User MIP start 2 did not produce a new incumbent solution
Presolve removed 599 rows and 3885 columns
Presolve time: 0.25s
Presolved: 114 rows, 188 columns, 1116 nonzeros
Variable types: 0 continuous, 188 integer (179 binary)
Root barrier log...
Ordering time: 0.00s
Barrier statistics:
AA' NZ : 7.630e+02
Factor NZ : 1.445e+03
Factor Ops : 2.411e+04 (less than 1 second per iteration)
Threads : 1
Objective Residual
Iter Primal Dual Primal Dual Compl Time
0 4.53178656e+01 2.86970903e+01 3.51e+01 2.64e-02 5.67e-01 0s
1 4.40414661e+01 2.76108408e+01 9.16e+00 5.00e-16 1.39e-01 0s
2 4.33577840e+01 3.77461795e+01 3.00e-01 3.89e-16 1.55e-02 0s
3 4.30490728e+01 4.25045113e+01 4.97e-03 1.67e-16 1.32e-03 0s
4 4.30004425e+01 4.29955815e+01 1.44e-05 5.64e-17 1.17e-05 0s
5 4.30000004e+01 4.29999956e+01 8.34e-09 3.33e-16 1.16e-08 0s
6 4.30000000e+01 4.30000000e+01 8.35e-12 1.93e-16 1.16e-11 0s
Barrier solved model in 6 iterations and 0.31 seconds (0.26 work units)
Optimal objective 4.30000000e+01
Root relaxation: objective 4.300000e+01, 132 iterations, 0.00 seconds (0.00 work units)
Nodes | Current Node | Objective Bounds | Work
Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
H 0 0 43.0000000 43.00000 0.00% - 0s
0 0 43.00000 0 5 43.00000 43.00000 0.00% - 0s
Explored 1 nodes (209 simplex iterations) in 0.31 seconds (0.26 work units)
Thread count was 4 (of 8 available processors)
Solution count 2: 43 45
Optimal solution found (tolerance 0.00e+00)
Best objective 4.300000000000e+01, best bound 4.300000000000e+01, gap 0.0000%
Warning: to let Gurobi read it back, use rlp format-
Hi Tobias,
Gurobi only uses the MIP start with the best objective value. If multiple MIP starts have the same objective value, all but the first one will be discarded.
This is the case because Gurobi uses MIP starts as a pruning technique, not a guide to computing the next candidate solutions. (This is in contrast to what happens with warm starts for LPs.) The pruning is done as part of the branch-and-bound algorithm. Because the MIP start tells Gurobi that the optimal objective value is at least as small (in case of a minimization objective) as the objective O of the best MIP start, it can prune any branches where the optimal objective of the relaxed subproblem is larger than O.
The variable values of the MIP starts are only essential to computing the start objective and confirming that it corresponds to a feasible solution that satisfies variable types. Otherwise, the values can be discarded, so Gurobi does not benefit from having multiple solution assignments for the same objective value.
It is still possible to provide multiple MIP starts, so users don't have to check themselves to see which are feasible and lead to the best objective. Gurobi will take care of that algorithmic and computational effort. This is particularly relevant when the provided MIP starts are just guesses or partial solutions.
I hope that helps answer your question.
Best,
Martin
----
Dr. Martin Bromberger - MIP Development Scholar
Gurobi GmbH
Sandstraße 104
40789 Monheim am Rhein
Email: martin.bromberger@gurobi.com (he, him, his)
-------------------------------------------------------------------------------
Sitz der Gesellschaft: Düsseldorf
Registergericht: Düsseldorf, HRB 99473
Geschäftsführer: Craig Albrecht und Duke Perrucci0 -
Hey Martin,
thanks for the fast reply. You did in fact answer my question :). Thank you very much.
best regards,
Tobias0
Please sign in to leave a comment.
Comments
2 comments