Skip to main content

Callback Setsolution from a MIP solution node

Ongoing

Comments

22 comments

  • Pirmin
    Gurobi-versary
    First Question
    First Comment

    I am facing the same issue.

    Is there any solution for that?

    1
  • Jose Vindel
    Gurobi-versary
    Thought Leader
    Investigator

    Hello, I am facing the same question, the only thing I could find cb.GetNodeRel() can be used to retrieve the variables of the relaxation but I am unsure if it actually works for you, would be helpful if someone could share how can this be solved

    0
  • Eli Towle
    Gurobi Staff Gurobi Staff

    In the next major or minor Gurobi release, you will be able to set solutions from the \( \texttt{MIPSOL} \) callback. In the meantime, a workaround is to store the solution, then pass it to Gurobi in the next \( \texttt{MIPNODE} \) callback.

    1
  • Jose Vindel
    Gurobi-versary
    Thought Leader
    Investigator

    How can you have two callbacks in one function? to my understanding once you set the first \( \texttt{if} \) block, that's the only one it gets to run:

    def mycallback(model, where):
    if where == GRB.Callback.MIPSOL:
    v = model.cbGetSolution(model._vars)
    vs = model._vars
    vi = v/(v+3)
    elif where == GRB.Callback.MIPNODE:
    model.cbLazy(lhs,sense,rhs)
    model.cbSetSolution(vs,vi)

    model.optimize(mycallback)
    0
  • Philip Taffet
    Gurobi-versary
    Conversationalist
    Curious

    Your callback can definitely handle multiple `where` values with if statements.

    0
  • Eli Towle
    Gurobi Staff Gurobi Staff

    You can generate and store the solution when \( \texttt{mycallback} \) is called with \( \texttt{where=MIPSOL} \), then set the solution the next time \( \texttt{mycallback} \) is called with \( \texttt{where=MIPNODE} \). So the solution is generated and set in two different calls to \( \texttt{mycallback} \). E.g.:

    def mycallback(model, where):
    if where == GRB.Callback.MIPSOL:
    vals = model.cbGetSolution(model._vars)
    model._vals = [v / (v + 3) for v in vals]
    elif where == GRB.Callback.MIPNODE and model._vals is not None:
    model.cbSetSolution(model._vars, model._vals)
    model._vals = None


    model._vars = model.getVars()
    model._vals = None
    model.optimize(mycallback)
    1
  • Jose Vindel
    Gurobi-versary
    Thought Leader
    Investigator

    Thanks a lot! I am trying to implement this in the model I am working on, when I tried to use \( \texttt{where=MIPNODE} \) nothing seemed to happen, then I checked for the condition to see if it's being read, if the statement is true then the block inside that \(\texttt{elif}\) will be executed

    print(str(where==GRB.Callback.MIPNODE))

    However, the result I get back is 

    False

    So,  

    model.cbSetSolution(vars, solution)

    won't get executed, my question is, what could make the \(\texttt{GRB.Callback.MIPNODE}\) false? 

    0
  • Eli Towle
    Gurobi Staff Gurobi Staff

    Note that \( \texttt{where} \) is equal to \( \texttt{GRB.Callback.MIPSOL} \) when the solution is set, then \( \texttt{mycallback} \) will be called later (separately) with a \( \texttt{where} \) value of \( \texttt{GRB.Callback.MIPNODE} \). \( \texttt{where==GRB.Callback.MIPNODE} \) is \( \texttt{false} \) whenever \( \texttt{mycallback} \) is called with a non-\( \texttt{MIPNODE} \) value of \( \texttt{where} \) (see the Callback Codes section of the documentation). 

    Is \( \texttt{mycallback} \) never called with \( \texttt{where==GRB.Callback.MIPNODE} \)? It would be helpful to see the log output from Gurobi and your code for a minimal working callback function.

    0
  • Jose Vindel
    Gurobi-versary
    Thought Leader
    Investigator

    Hello, 

    Thanks, I could see what I was doing wrong. Now my code enters \( \texttt{where=MIPNODE} \) and I can make use of \(\texttt{cb.SetSolution}\). However, I also want to use \(\texttt{Model.UseSolution()}\), and when printing to check what value I am about to pass I get 1e+100. What does this value mean and what kind of heuristic does gurobi implement at this point?

    0
  • Eli Towle
    Gurobi Staff Gurobi Staff

    The return value of Model.cbUseSolution() is \( \texttt{GRB.INFINITY} \) (1e+100) if Gurobi isn't able to compute an improved solution using the variable values specified in Model.cbSetSolution(). Are you sure your solution is feasible and better than the current incumbent objective value?

    Gurobi solves an optimization problem to try to "fill in" any missing variable values. The solution you give to Gurobi generally comes from your own heuristic algorithm.

    0
  • Maliheh Aramon
    Gurobi Staff Gurobi Staff

    Hi Everyone

    Gurobi 9.5 was recently released. Included in this release is the ability to set a new solution from the MIP and the MIPSOL callbacks. Therefore, there is no need to store a solution internally and wait for the next MIPNODE callback anymore.

    Unfortunately, this new feature is missing in the Gurobi 9.5 documentation. It will be added in the next technical release. 

    We hope this new feature works well for you. Please let us know if you find any issues using this.

    Best regards,

    Maliheh

    0
  • Antonio Coppola
    First Comment

    Dear all,

    when useSolution() tries to produce an heuristic solution, does it check if it is feasible also w.r.t branching constraints added during the branch-and-cut algorithm?

    I am asking because I am sure to have a feasible solution which improves over the incumbent, which gets surely accepted by useSolution (i.e., that does not return INFINITY) only as long as I am in the root node, while during the branching it may or may not be accepted.
    If this is the case, how can I know which are the branching constraints added in the MIPNODE in which I'm feeding the solution? With this information I can modify accordingly my heuristic solution and use it.

    Thanks!

    0
  • Sophie Demassey
    Gurobi-versary
    First Comment
    First Question

    Hi,

    Same issue here.

    To solve a MINLP, I run Gurobi's B&C on a MILP relaxation and, at each MIPSOL, I either cutoff the integer node with a combinatorial cut or provides the actual MINLP solution if exists. With the oldest releases, I used the trick to store the solution and wait for the next MIPNODE event to post it. Now, I updated my code as solutions can now be set at MIPSOL. However, cbSetSolution/cbUseSolution keep rejecting the solutions I provide, and which are feasible (I checked them by cloning the model including all the lazy constraints and fixing the variables).

    Systematically, the callback is called twice at these MIPSOL nodes but with a different solution (the fractional part now satisfies the newly added lazy cut, but it is still not feasible for my problem).

    I also tried to enforce just partial solutions (only the integer part, or the fractional, or just one variable)... but cbUseSolution keeps returning 1e+101 anyway. I really do not see what I am doing wrong. As a feature request: could it be possible to get more information from cbUseSolution() when it rejects a solution ?

     

    1
  • Sophie Demassey
    Gurobi-versary
    First Comment
    First Question

    Hi, here is an update:

    I confirm that, in my code, setSolution/useSolution never works at where=MIPSOL (i.e. useSolution returns 1e+101) but it always does (i.e. useSolution returns the actual cost) when I store the solution and set/use it at the next where=MIPNODE.

    Now I have another problem in 1 of my test (among a dozen): useSolution "accepts" a solution at where=MIPNODE (i.e. it returns its actual cost) but the incumbent is not updated accordingly.  Do you know what could happen and how to know in the callback when a solution is actually "used" ?   Another question relative to this one: why MIPSOL_OBJBST returns the value of the current MIP solution and not the value of the incumbent at this point (given that the MIP solution can be cutoff in the callback) ? And could we have access to this (previous) incumbent value at where=MIPSOL ?

    Thank you.

    2
  • Eli Towle
    Gurobi Staff Gurobi Staff

    when useSolution() tries to produce an heuristic solution, does it check if it is feasible also w.r.t branching constraints added during the branch-and-cut algorithm?

    I am asking because I am sure to have a feasible solution which improves over the incumbent, which gets surely accepted by useSolution (i.e., that does not return INFINITY) only as long as I am in the root node, while during the branching it may or may not be accepted.
    If this is the case, how can I know which are the branching constraints added in the MIPNODE in which I'm feeding the solution? With this information I can modify accordingly my heuristic solution and use it.

    If the solution is feasible to the constraints of the original problem, it should be accepted. Are you using Gurobi 10.0.1? If so, are you able to construct a minimal working example that reproduces this behavior?

    I also tried to enforce just partial solutions (only the integer part, or the fractional, or just one variable)... but cbUseSolution keeps returning 1e+101 anyway. I really do not see what I am doing wrong. As a feature request: could it be possible to get more information from cbUseSolution() when it rejects a solution ?

    Do you mean that Model.cbUseSolution() always returns a value of 1e+101 when called in the \(\texttt{GRB.Callback.MIP}\) or \(\texttt{GRB.Callback.MIPSOL}\) callbacks? If so, this is expected. From the Model.cbUseSolution() documentation:

    Return value:

    The objective value for the solution obtained from your solution values. It equals GRB.INFINITY if no improved solution is found or the method has been called from a callback other than GRB.Callback.MIPNODE.

    When Model.cbUseSolution() is called from the \(\texttt{GRB.Callback.MIP}\) or \(\texttt{GRB.Callback.MIPSOL}\) callbacks, Gurobi stores the solution until it can be processed. Does the log indicate that the solution is later accepted?

    Another question relative to this one: why MIPSOL_OBJBST returns the value of the current MIP solution and not the value of the incumbent at this point (given that the MIP solution can be cutoff in the callback) ?

    This is a bug. A fix will be available in Gurobi 10.0.2. Thanks for letting us know!

    1
  • Antonio Coppola
    First Comment

    If the solution is feasible to the constraints of the original problem, it should be accepted. Are you using Gurobi 10.0.1? If so, are you able to construct a minimal working example that reproduces this behavior? 

    Sure, in the following you can find the log of my working example. As can be seen, I provide gurobi with an initial solution of value 18084.6. "Staggering vehicle" is the move of my local search, that tries to reduce the total value of the solution by rescheduling the departure time of one vehicle of my fleet at the time. Current total delay is the value of the heuristic solution. As long as I am in the root node the heuristic solutions that I find are accepted (unless gurobi finds a better heuristic solution in a shorter amount of time). The solution that I provide with value 5327.73 is not accepted by useSolution(), and this happens after gurobi started branching. What I do is then calling model.terminate() and restart the search using the solution with value 5327.73 as warm start, which is in this case accepted. Maybe it is worth to mention that I always provide values for integer and fractional variables:

    Academic license - for non-commercial use only - expires 2023-11-05
    Creating conflict variables
    Creating continuous variables
    Adding conflict constraints
    Writing the continuity constraints
    Writing the objective function
    saved unaccepted heuristic solution
    Set parameter TimeLimit to value 1.7832646110057831e+03
    Set parameter MIPGap to value 0
    Set parameter NodefileStart to value 0.5
    Set parameter MIPFocus to value 2
    Set parameter NumericFocus to value 2
    Set parameter FeasibilityTol to value 1e-08
    Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)

    CPU model: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz, instruction set [SSE2|AVX|AVX2|AVX512]
    Thread count: 4 physical cores, 8 logical processors, using up to 8 threads

    Optimize a model with 82376 rows, 106249 columns and 279747 nonzeros
    Model fingerprint: 0x47941e89
    Model has 113776 general constraints
    Variable types: 24637 continuous, 81612 integer (81612 binary)
    Coefficient statistics:
      Matrix range     [5e-01, 1e+00]
      Objective range  [1e+00, 1e+00]
      Bounds range     [1e+00, 7e+03]
      RHS range        [1e+00, 7e+03]
      PWLCon x range   [1e+00, 7e+00]
      PWLCon y range   [0e+00, 4e+01]
      GenCon rhs range [1e-03, 1e-03]
      GenCon coe range [1e+00, 1e+00]

    User MIP start produced solution with objective 18084.6 (0.50s)
    Loaded user MIP start with objective 18084.6

    Presolve removed 181263 rows and 229143 columns (presolve time = 6s) ...
    Presolve removed 262189 rows and 263764 columns (presolve time = 34s) ...
    Presolve removed 45152 rows and 79076 columns
    Presolve time: 33.65s
    Presolved: 37224 rows, 27173 columns, 144564 nonzeros
    Presolved model has 2319 SOS constraint(s)
    Found heuristic solution: objective 13947.533433
    Variable types: 12904 continuous, 14269 integer (14268 binary)
    Root relaxation presolve removed 207 rows and 238 columns
    Root relaxation presolved: 37017 rows, 26935 columns, 144045 nonzeros

    Deterministic concurrent LP optimizer: primal and dual simplex
    Showing first log only...

    Root simplex log...

    Iteration    Objective       Primal Inf.    Dual Inf.      Time
           0    3.1365904e+03   8.387912e+03   4.341447e+09     35s
       14061    4.0869493e+03   1.333196e+01   5.275585e+07     35s
       16826    1.3307845e+03   0.000000e+00   1.927024e+03     35s
       18385    7.5599080e+02   0.000000e+00   0.000000e+00     36s
    Concurrent spin time: 1.47s

    Solved with primal simplex
       18385    7.5599080e+02   0.000000e+00   0.000000e+00     37s

    Root relaxation: objective 7.559908e+02, 18385 iterations, 2.75 seconds (0.95 work units)

        Nodes    |    Current Node    |     Objective Bounds      |     Work
     Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time

         0     0  755.99080    0  705 13947.5334  755.99080  94.6%     -   39s
         0     0  755.99080    0  708 13947.5334  755.99080  94.6%     -   39s
         0     0  755.99080    0  708 13947.5334  755.99080  94.6%     -   39s
    H    0     0                    12827.749905  755.99080  94.1%     -   40s
     - staggering vehicle 178 by 5.32336 - current total delay: 12800.5 -> OldDelay - NewDelay = 27.259
     - staggering vehicle 193 by 26.8083 - current total delay: 12787.7 -> OldDelay - NewDelay = 12.7964
     - staggering vehicle 1257 by 9.1239 - current total delay: 12775.9 -> OldDelay - NewDelay = 11.7862
    setting heuristic solution in callback
    H    0     0                    9992.8697310  785.61880  92.1%     -   42s
         0     0  793.51342    0 1051 9992.86973  793.51342  92.1%     -   43s
         0     0  793.51342    0 1051 9992.86973  793.51342  92.1%     -   43s
     - staggering vehicle 38 by 17.3183 - current total delay: 9961 -> OldDelay - NewDelay = 31.8746
     - staggering vehicle 211 by 19.374 - current total delay: 9944.04 -> OldDelay - NewDelay = 16.9569
     - staggering vehicle 95 by 4.96945 - current total delay: 9931.15 -> OldDelay - NewDelay = 12.8843
     - staggering vehicle 46 by 19.1771 - current total delay: 9911.21 -> OldDelay - NewDelay = 19.9416
     - staggering vehicle 212 by 38.2075 - current total delay: 9875.98 -> OldDelay - NewDelay = 35.2322
     - staggering vehicle 724 by 12.7865 - current total delay: 9857.36 -> OldDelay - NewDelay = 18.6155
    setting heuristic solution in callback
         0     0  810.03454    0 1028 9992.86973  810.03454  91.9%     -   44s
    H    0     0                    9857.3647500  811.12093  91.8%     -   45s
         0     0  811.12093    0 1026 9857.36475  811.12093  91.8%     -   45s
         0     0  854.25190    0 1020 9857.36475  854.25190  91.3%     -   45s
         0     0  869.63497    0 1133 9857.36475  869.63497  91.2%     -   49s
         0     0  870.64213    0 1122 9857.36475  870.64213  91.2%     -   49s
         0     0  870.64213    0 1122 9857.36475  870.64213  91.2%     -   49s
    H    0     0                    8540.3112840  872.89051  89.8%     -   50s
         0     0  872.89051    0 1144 8540.31128  872.89051  89.8%     -   50s
         0     0  872.89051    0 1145 8540.31128  872.89051  89.8%     -   50s
     - staggering vehicle 781 by 68.6936 - destaggering vehicle 722 by 22.3973 - current total delay: 8485.77 -> OldDelay - NewDelay = 54.5431
     - staggering vehicle 1235 by 34.4721 - current total delay: 8473.08 -> OldDelay - NewDelay = 12.6875
     - staggering vehicle 38 by 17.3183 - current total delay: 8441.21 -> OldDelay - NewDelay = 31.8746
     - staggering vehicle 95 by 4.96945 - current total delay: 8428.32 -> OldDelay - NewDelay = 12.8843
     - staggering vehicle 1304 by 13.6961 - current total delay: 8418.14 -> OldDelay - NewDelay = 10.1808
     - staggering vehicle 1258 by 1.56485 - current total delay: 8415.8 -> OldDelay - NewDelay = 2.33793
     - staggering vehicle 931 by 2.68681 - current total delay: 8409.71 -> OldDelay - NewDelay = 6.09559
     - staggering vehicle 1069 by 4.76216 - current total delay: 8313.88 -> OldDelay - NewDelay = 95.8227
     - staggering vehicle 498 by 14.6169 - current total delay: 8310.3 -> OldDelay - NewDelay = 3.58557
    setting heuristic solution in callback
         0     0  872.92139    0 1146 8540.31128  872.92139  89.8%     -   52s
    H    0     0                    8310.2992920  872.92139  89.5%     -   52s
         0     0  872.92139    0 1144 8310.29929  872.92139  89.5%     -   52s
         0     0  907.59290    0  652 8310.29929  907.59290  89.1%     -   60s
    H    0     0                    6624.8816040  907.59290  86.3%     -   60s
    H    0     0                    6468.2387820  907.59290  86.0%     -   61s
    H    0     0                    5498.4590460  907.59290  83.5%     -   68s
     - staggering vehicle 904 by 17.6209 - current total delay: 5481.47 -> OldDelay - NewDelay = 16.9901
     - staggering vehicle 814 by 29.8285 - current total delay: 5459.35 -> OldDelay - NewDelay = 22.1203
    setting heuristic solution in callback
         3     4  953.57219    2  120 5498.45905  953.57219  82.7% 14708   75s
    H  514   154                    5366.8360710  974.57161  81.8%  97.7   80s
     - staggering vehicle 904 by 17.6209 - current total delay: 5349.85 -> OldDelay - NewDelay = 16.9901
     - staggering vehicle 814 by 29.8285 - current total delay: 5327.73 -> OldDelay - NewDelay = 22.1203
    setting heuristic solution in callback
    Heuristic solution has not been accepted - terminating MIP model
    saved unaccepted heuristic solution

    Cutting planes:
      Learned: 13
      Lift-and-project: 68
      Cover: 581
      Implied bound: 201
      Projected implied bound: 1
      Clique: 545
      MIR: 286
      StrongCG: 8
      Flow cover: 1491
      Zero half: 13
      Network: 1
      RLT: 172
      Relax-and-lift: 126

    Explored 515 nodes (119243 simplex iterations) in 86.43 seconds (42.35 work units)
    Thread count was 8 (of 8 available processors)

    Solution count 10: 5366.84 5498.46 6468.24 ... 13947.5

    Solve interrupted
    Best objective 5.366836070999e+03, best bound 1.003840565559e+03, gap 81.2955%

    User-callback calls 6672, time in user-callback 8.19 sec
    Set parameter TimeLimit to value 1.6964470658302307e+03
    Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)

    CPU model: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz, instruction set [SSE2|AVX|AVX2|AVX512]
    Thread count: 4 physical cores, 8 logical processors, using up to 8 threads

    Optimize a model with 82376 rows, 106249 columns and 279747 nonzeros
    Model fingerprint: 0xe041006f
    Model has 113776 general constraints
    Variable types: 24637 continuous, 81612 integer (81612 binary)
    Coefficient statistics:
      Matrix range     [5e-01, 1e+00]
      Objective range  [1e+00, 1e+00]
      Bounds range     [1e+00, 7e+03]
      RHS range        [1e+00, 7e+03]
      PWLCon x range   [1e+00, 7e+00]
      PWLCon y range   [0e+00, 4e+01]
      GenCon rhs range [1e-03, 1e-03]
      GenCon coe range [1e+00, 1e+00]

    User MIP start produced solution with objective 5327.73 (0.32s)
    Loaded user MIP start with objective 5327.73
    MIP start from previous solve did not produce a new incumbent solution
    [...]

    Thank you for your help!

     

     

     

     
     
    1
  • Eli Towle
    Gurobi Staff Gurobi Staff

    That looks pretty suspicious. I am assuming you are calling Model.cbUseSolution() in the \(\texttt{MIPNODE}\) callback and declaring the heuristic solution to be rejected if Model.cbUseSolution() returns \(\texttt{GRB.INFINITY}\). Are you able to share a minimal working code example?

    0
  • Antonio Coppola
    First Comment

    I am assuming you are calling Model.cbUseSolution() in the \(\texttt{MIPNODE}\) callback and declaring the heuristic solution to be rejected if Model.cbUseSolution() returns \(\texttt{MIPNODE}\). 

    This is correct.

    Are you able to share a minimal working code example?

    This behaviour arises only when the size of the instances I am trying to solve is large, so it is not really possible to provide a minimal working example. I can however share my callback function:

    • I retrieve \(\texttt{model._cbReleaseTimes}\) in \(\texttt{MIPSOL}\) using \(\texttt{model.cbGetSolution()}\);
    • I use these values to produce the heuristic solution in the subsequent \(\texttt{MIPNODE}\) with \(\texttt{getHeuristicSolution()}\);
    • In \(\texttt{setHeuristicSolution()}\), I set the values for my binary and continuous variables using \(\texttt{model.cbSetSolution()}\) (in the following the respective functions). Thereafter, I call \(\texttt{model.cbUseSolution()}\). If the return value of the latter is \(\texttt{1e+100}\), then I save the heuristic solution in an external file, terminate gurobi, and restart the model using the saved solution as warm start.
    def callback(instance: Instance, statusQuo: CompleteSolution) -> Callable:
    def callLocalSearch(model, where) -> None:
    if where == grb.GRB.Callback.MIPSOL:
                model._cbReleaseTimes = [model.cbGetSolution(model._departure[vehicle][path[0]])
    for vehicle, path in enumerate(instance.arcBasedShortestPaths)]
    if where == grb.GRB.Callback.MIPNODE:
    heuristicSolution = getHeuristicSolution(model, instance)
    setHeuristicSolution(model, heuristicSolution, instance)
    return callLocalSearch

     

    def setHeuristicSolution(model: Model, heuristicSolution: HeuristicSolution, instance: Instance) -> None:
    print("setting heuristic solution in callback")
    setHeuristicBinaryVariables(model, heuristicSolution)
    setHeuristicContinuousVariables(model, heuristicSolution)
    returnValUseSolution = model.cbUseSolution()
    if returnValUseSolution == 1e+100:
    print("Heuristic solution has not been accepted - terminating MIP model")
    suspendProcedure(heuristicSolution, model, instance)
    return

    def setHeuristicBinaryVariables(model, heuristicSolution):
    for arc in model._gamma:
    for firstVehicle, secondVehicle in itertools.combinations(model._gamma[arc], 2):
    model.cbSetSolution(model._alpha[arc][firstVehicle][secondVehicle],
    heuristicSolution.binaries.alpha[arc][firstVehicle][secondVehicle])
    model.cbSetSolution(model._beta[arc][firstVehicle][secondVehicle],
    heuristicSolution.binaries.beta[arc][firstVehicle][secondVehicle])
    model.cbSetSolution(model._gamma[arc][firstVehicle][secondVehicle],
    heuristicSolution.binaries.gamma[arc][firstVehicle][secondVehicle])
    model.cbSetSolution(model._alpha[arc][secondVehicle][firstVehicle],
    heuristicSolution.binaries.alpha[arc][secondVehicle][firstVehicle])
    model.cbSetSolution(model._beta[arc][secondVehicle][firstVehicle],
    heuristicSolution.binaries.beta[arc][secondVehicle][firstVehicle])
    model.cbSetSolution(model._gamma[arc][secondVehicle][firstVehicle],
    heuristicSolution.binaries.gamma[arc][secondVehicle][firstVehicle])
    def setHeuristicContinuousVariables(model, heuristicSolution):
    for vehicle in model._departure:
    for position, arc in enumerate(model._departure[vehicle]):
    model.cbSetSolution(model._departure[vehicle][arc],
    heuristicSolution.congestedSchedule[vehicle][position])
    model.cbSetSolution(model._delay[vehicle][arc], heuristicSolution.delaysOnArcs[vehicle][position])

    Thank you for your help.

     

    0
  • Eli Towle
    Gurobi Staff Gurobi Staff

    We are very interested in investigating this issue further, though this requires being able to reproduce the issue. I will open a support request for you to discuss how we can replicate the error.

    1
  • Maximilian Kolter
    Gurobi-versary
    First Comment
    First Question

    Is there any update regarding the issue?

    I experience the same problem. I find an improved solution in the callback, but Gurobi rejects it. However, if I use the same solution to warm start, the MIP it works fine.

    0
  • Eli Towle
    Gurobi Staff Gurobi Staff

    Our development team is aware of the issue described by Antonio. I unfortunately can't make any guarantees at this time about if/when a fix will become available.

    For that particular issue, a workaround is to set the Disconnected parameter to 0. Could you check if setting the Disconnected parameter to 0 resolves the issue? If not, please post the Gurobi log and a minimal version of your callback code.

    0
  • Pirmin
    Gurobi-versary
    First Question
    First Comment

    I was wondering if this issue has been solved or if there are other problems known to using MIP solutions in callbacks.

    I am trying to insert a partial MIP solution in a callback, which works as a starting solution. However, it is not accepted and returns 1e+101 when calling useSolution.

    In the following log, The Iteration shows that I am entering the callback, and then if I find my feasible solution, I try to insert it.

    Set parameter Username
    Academic license - for non-commercial use only - expires 2024-08-01
    Warning: parameter changes on this environment will not affect existing models.
    Set parameter Threads to value 1
    Set parameter Disconnected to value 0
    Set parameter MIPGap to value 0.02
    Set parameter LazyConstraints to value 1
    Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (win64)

    CPU model: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz, instruction set [SSE2|AVX|AVX2]
    Thread count: 4 physical cores, 8 logical processors, using up to 8 threads

    Optimize a model with 1573498 rows, 589114 columns and 3924084 nonzeros
    Model fingerprint: 0x8e831791
    Variable types: 13024 continuous, 576090 integer (90 binary)
    Coefficient statistics:
      Matrix range     [1e+00, 1e+08]
      Objective range  [5e-02, 6e+07]
      Bounds range     [1e+00, 1e+00]
      RHS range        [9e+01, 1e+02]
    Presolve removed 1468318 rows and 486305 columns (presolve time = 5s) ...
    Presolve removed 1468318 rows and 486305 columns
    Presolve time: 6.39s
    Presolved: 105180 rows, 102809 columns, 402180 nonzeros
    Variable types: 5610 continuous, 97199 integer (89 binary)
    Iteration: 1
    Found Insert!
    Insert!
    Return of useSolution: 1e+101
    Insert stop!
    Iteration stop: 1
    Iteration: 2
    Iteration stop: 2
    Found heuristic solution: objective 7.336881e+10
    Root relaxation presolved: 105000 rows, 102629 columns, 401460 nonzeros

    Deterministic concurrent LP optimizer: primal and dual simplex
    Showing first log only...


    Root simplex log...

    Iteration    Objective       Primal Inf.    Dual Inf.      Time
           0    6.8028811e+10   2.003508e+04   2.188655e+11     12s
    Concurrent spin time: 0.00s

    Solved with dual simplex

    Root simplex log...

    Iteration    Objective       Primal Inf.    Dual Inf.      Time
       29109    1.0025516e+10   0.000000e+00   0.000000e+00     14s

    Root relaxation: objective 1.002552e+10, 29109 iterations, 3.08 seconds (1.53 work units)
    Iteration: 3
    Found Insert!
    Insert!
    Return of useSolution: 1e+101
    Insert stop!
    Iteration stop: 3

        Nodes    |    Current Node    |     Objective Bounds      |     Work
     Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time

         0     0 1.0026e+10    0    - 7.3369e+10 1.0026e+10  86.3%     -   14s
    Iteration: 4
    Found Insert!
    Insert!
    Return of useSolution: 1e+101
    Insert stop!
    Iteration stop: 4
         0     0 1.0041e+10    0    - 7.3369e+10 1.0041e+10  86.3%     -   21s
    Iteration: 5
    Found Insert!
    Insert!
    Return of useSolution: 1e+101
    Insert stop!
    Iteration stop: 5
    *    0     0               0    1.004100e+10 1.0041e+10  0.00%     -   21s

    Cutting planes:
      Lazy constraints: 1243

    Explored 1 nodes (36403 simplex iterations) in 21.63 seconds (13.49 work units)
    Thread count was 8 (of 8 available processors)

    Solution count 2: 1.0041e+10 7.33688e+10

    Optimal solution found (tolerance 2.00e-02)
    Best objective 1.004099869152e+10, best bound 1.004099869152e+10, gap 0.0000%

    User-callback calls 2760, time in user-callback 2.18 sec
    Time measured: 21.891 seconds.
    0

Please sign in to leave a comment.