# Gurobi MIP start, calling GRBread to provide starting vector using a \*.mst/ \*.sol file

**URL:** https://discourse.julialang.org/t/gurobi-mip-start-calling-grbread-to-provide-starting-vector-using-a-mst-sol-file/10610
**Category:** Optimization (Mathematical)
**Created:** [April 29, 2018, 8:24pm UTC](https://discourse.julialang.org/t/gurobi-mip-start-calling-grbread-to-provide-starting-vector-using-a-mst-sol-file/10610 "2018-04-29T20:24:16Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![Anton\_Hinneck](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/anton_hinneck/32/22716_2.png) [@Anton\_Hinneck](https://discourse.julialang.org/u/Anton_Hinneck)
#### Post date: [April 29, 2018, 8:24pm UTC](https://discourse.julialang.org/t/gurobi-mip-start-calling-grbread-to-provide-starting-vector-using-a-mst-sol-file/10610/1 "2018-04-29T20:24:16Z")

</div>

Hi,

i am currently developing a mixed integer model and need to pass an initial solution from a previous run to Gurobi. I probably could do it using JuMP’s `setvalue()` function. It would be much more handy however, to just generate an \*.mst file from a solved model to then pass it to the solver before the next run.

I was already successful in generating an \*.mst file by using `MyJuMPModel.internalModel.inner`. This is how I generated the file:

```julia
grb_mod = MyJuMPModel.internalModel.inner
write_model(grb_mod, "out.mst")

```

I read on [Gurobi’s website](http://www.gurobi.com/documentation/7.5/refman/c_grbread.html) that the function `GRBread()` can be used to provide the solver with a starting vector, by passing an \*.mst file. Unfortunately, this function is currently not exposed in the `Gurobi` package. Thus, I was trying to expose this function with limited success. Limited success meaning that I do not get error messages but Gurobi does not seem to use the starting vector.

In the `Gurobi` package I added the following function to `grb_model.jl`:

```julia
function grb_read(model::Model, filename::String)
    @assert isascii(filename) # TODO: support non-ascii file names
    @assert model.ptr_model != C_NULL
        ret = @grb_ccall(read, Cint,
        (Ptr{Void}, Ptr{UInt8}),
        model.ptr_model, filename)
    if ret != 0
        throw(GurobiError(model.env, ret))
    end
    nothing
end

```

Also, I added this function in the export section of the `Gurobi.jl` file.  
This function is based on a call of `GRBread()` in one of Gurobi’s '.cpp files.

```julia
GRBModel::read(const string& filename)
{
  if (Cmodel == NULL) throw
    GRBException("Model not loaded", GRB_ERROR_INTERNAL);
  int error = GRBread(Cmodel, filename.c_str());
  if (error) throw GRBException(string(GRBgeterrormsg(Cenv)), error);
}

```

Some advice or thoughts on this would be great.

Is it possible to use \*.mst files for this purpose?  
Since, I was not getting any errors, but the `internalModel` does not seem to change, I figured that something must be wrong with the pointer to the model in the function. I do not have any experience with ccalls in Julia.

Anton

* * *

I provided a detailed solution in an answer below.

---

<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: [April 29, 2018, 9:46pm UTC](https://discourse.julialang.org/t/gurobi-mip-start-calling-grbread-to-provide-starting-vector-using-a-mst-sol-file/10610/2 "2018-04-29T21:46:52Z")

</div>

Do you have a [MWE](https://stackoverflow.com/help/mcve) that demonstrates that Gurobi doesn’t use the MIP start?

You many need to update the model after adding the MIP start.  
[https://github.com/JuliaOpt/Gurobi.jl/blob/8dd94aebf2b22004cef3b6f3ad7ea00d00b66a1d/src/grb\_model.jl#L89-L96](https://github.com/JuliaOpt/Gurobi.jl/blob/8dd94aebf2b22004cef3b6f3ad7ea00d00b66a1d/src/grb_model.jl#L89-L96)

If you are calling `solve` from JuMP afterwards, you probably need to remove any existing solution to prevent JuMP from calling setwarmstart:  
[https://github.com/JuliaOpt/JuMP.jl/blob/v0.18.1/src/solvers.jl#L399](https://github.com/JuliaOpt/JuMP.jl/blob/v0.18.1/src/solvers.jl#L399)

Hope that is enough to point you in the right direction.

---

<div class="post-metadata">

### Author: ![Anton\_Hinneck](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/anton_hinneck/32/22716_2.png) [@Anton\_Hinneck](https://discourse.julialang.org/u/Anton_Hinneck)
#### Post date: [April 30, 2018, 12:41pm UTC](https://discourse.julialang.org/t/gurobi-mip-start-calling-grbread-to-provide-starting-vector-using-a-mst-sol-file/10610/3 "2018-04-30T12:41:22Z")

</div>

Thanks a lot! Using `update_model!()` did the trick 🙂 I am not so certain though that the mip start is used. Here is a MWE.

```julia
using Gurobi
using JuMP

dir = "C:/Users/..."
cd(dir)

simple_model = Model(solver=GurobiSolver())

@variable(simple_model, product_1 >= 0, Int)
@variable(simple_model, product_2 >= 0, Int)
@variable(simple_model, product_3 >= 0, Int)
@variable(simple_model, z >= 0)

@objective(simple_model, Max, z)

@constraint(simple_model, 2 * product_1 + 5 * product_2 + 4 * product_3 == z)
@constraint(simple_model, 0.5 * product_1 + 2 * product_2 + 1 * product_3 <= 6)

JuMP.build(simple_model)

```

After accessing the “Start”-Array in the `Gurobi.Model` I just get the default values:

```julia
start_1 = Gurobi.get_dblattrarray(simple_model.internalModel.inner, "Start", 1, 4)
println(start_1)

```

> [1.0e101, 1.0e101, 1.0e101, 1.0e101]

Using the solution file _(simple\_out.sol)_ from a previous run, by employing the function I added to ` grb_model.jl`, I then get the right start vector:

```julia
inject_mip_start = true
if inject_mip_start
        grb_read(simple_model.internalModel.inner, "simple_out.sol")
        update_model!(simple_model.internalModel.inner)
end

start_2 = Gurobi.get_dblattrarray(simple_model.internalModel.inner, "Start", 1, 4)
println(start_2)

```

> [12.0, 0.0, 0.0, 24.0]

If I do not use `update_model!()`, the start values are not updated in the model. Now, I would like to test, whether this solution is used during optimization. I used `optimize(simple_model.internalModel.inner)` as well as `solve(simple_model)` right after building the model using JuMP and after injecting the mip start. Unfortunately, I get the same solver output. It does not seem that this initial solution is taken advantage of.

Are you aware of anything that might cause this, or a way of verifying that the mip start is used? Btw, do you know where JuMP.solve() and JuMP.build() are defined? I could not find these functions in the JuMP-repo on Github. Thanks a lot, sorry for all these questions 🤐

* * *

In order for this example to work, the the function `grb_read()` (as provided in the initial post) must be added to the local `grb_model.jl` file in the local Gurobi package. Also, `grb_read` must be added to the export section in the `Gurobi.jl` file.

A solution file must be produced before it can be injected. For this it is possible to use:  
`write_model(simple_model.internalModel.inner, "simple_out.sol")`  
… after initially solving the model with `inject_mip_start = false`.

* * *

OK, last update, the solution as presented works 🙂 It is crucial to call Gurobi.optimize() instead of JuMP.solve(). Thanks again, this was definitely pointing me in the right direction 🙂 I verified it, by applying it to a much bigger model. The issue was, that my simple\_model was too less of a challenge, as an optimal solution could instantly be obtained.

Would it be possible that I create a PR so `grb_read()` could be merged into the Gurobi package?

---

<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: [April 30, 2018, 10:50pm UTC](https://discourse.julialang.org/t/gurobi-mip-start-calling-grbread-to-provide-starting-vector-using-a-mst-sol-file/10610/4 "2018-04-30T22:50:10Z")

</div>

The following works for me.

```julia
using Gurobi
using JuMP

simple_model = Model(solver=GurobiSolver(Presolve=0))

@variable(simple_model, product_1 >= 0, Int)
@variable(simple_model, product_2 >= 0, Int)
@variable(simple_model, product_3 >= 0, Int)
@variable(simple_model, z >= 0)

@objective(simple_model, Max, z)

@constraint(simple_model, 2 * product_1 + 5 * product_2 + 4 * product_3 == z)
@constraint(simple_model, 0.5 * product_1 + 2 * product_2 + 1 * product_3 <= 6)

JuMP.build(simple_model)

start_1 = Gurobi.get_dblattrarray(simple_model.internalModel.inner, "Start", 1, 4)

solve(simple_model)
write_model(simple_model.internalModel.inner, "simple_out.sol")

simple_model.colVal .= NaN

grb_read(simple_model.internalModel.inner, "simple_out.sol")
Gurobi.update_model!(simple_model.internalModel.inner)

solve(simple_model)

```

Here is the Gurobi log.

```julia
Academic license - for non-commercial use only
Optimize a model with 2 rows, 4 columns and 7 nonzeros
Variable types: 1 continuous, 3 integer (0 binary)
Coefficient statistics:
  Matrix range [5e-01, 5e+00]
  Objective range [1e+00, 1e+00]
  Bounds range [0e+00, 0e+00]
  RHS range [6e+00, 6e+00]
Found heuristic solution: objective -0
Variable types: 0 continuous, 4 integer (0 binary)

Root relaxation: objective 2.400000e+01, 3 iterations, 0.00 seconds

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

* 0 0 0 24.0000000 24.00000 0.00% - 0s

Explored 0 nodes (3 simplex iterations) in 0.00 seconds
Thread count was 8 (of 8 available processors)

Solution count 2: 24 -0

Optimal solution found (tolerance 1.00e-04)
Best objective 2.400000000000e+01, best bound 2.400000000000e+01, gap 0.0000%
Optimize a model with 2 rows, 4 columns and 7 nonzeros
Variable types: 1 continuous, 3 integer (0 binary)
Coefficient statistics:
  Matrix range [5e-01, 5e+00]
  Objective range [1e+00, 1e+00]
  Bounds range [0e+00, 0e+00]
  RHS range [6e+00, 6e+00]

Loaded MIP start with objective 24
MIP start did not produce a new incumbent solution

Variable types: 0 continuous, 4 integer (0 binary)

Root relaxation: cutoff, 2 iterations, 0.00 seconds

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

     0 0 cutoff 0 24.00000 24.00000 0.00% - 0s

Explored 0 nodes (2 simplex iterations) in 0.00 seconds
Thread count was 8 (of 8 available processors)

Solution count 1: 24

Optimal solution found (tolerance 1.00e-04)
Best objective 2.400000000000e+01, best bound 2.400000000000e+01, gap 0.0000%

```

> I could not find these functions in the JuMP-repo on Github

JuMP is going through a re-write, so you will need to look at the [release-0.18 branch](https://github.com/JuliaOpt/JuMP.jl/tree/release-0.18)

> Would it be possible that I create a PR so grb\_read() could be merged into the Gurobi package?

Yes please.

---

<div class="post-metadata">

### Author: ![g001234](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/g001234/32/2956_2.png) [@g001234](https://discourse.julialang.org/u/g001234)
#### Post date: [October 13, 2022, 1:24am UTC](https://discourse.julialang.org/t/gurobi-mip-start-calling-grbread-to-provide-starting-vector-using-a-mst-sol-file/10610/5 "2022-10-13T01:24:37Z")

</div>

I was wondering if there is a way to achieve this with a more recent version of JuMP? When I run `grb_read(m.internalModel.inner, "output.sol")`, I got the error `type Model has no field internalModel`.

I’m using JuMP v1.0.0 and Julia 1.6.

---

<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: [October 13, 2022, 2:09am UTC](https://discourse.julialang.org/t/gurobi-mip-start-calling-grbread-to-provide-starting-vector-using-a-mst-sol-file/10610/6 "2022-10-13T02:09:31Z")

</div>

We have greatly improved and simplified things since the post in 2018. The equivalent is now:

```julia
using JuMP, Gurobi
model = direct_model(Gurobi.Optimizer())
set_optimizer_attribute(model, "Presolve", 0)
@variable(model, product_1 >= 0, Int)
@variable(model, product_2 >= 0, Int)
@variable(model, product_3 >= 0, Int)
@variable(model, z >= 0)
@objective(model, Max, z)
@constraint(model, 2 * product_1 + 5 * product_2 + 4 * product_3 == z)
@constraint(model, 0.5 * product_1 + 2 * product_2 + 1 * product_3 <= 6)
optimize!(model)
grb = backend(model)
GRBwrite(grb, "simple_out.sol")
set_start_value.(all_variables(model), nothing)
GRBread(grb, "simple_out.sol")
optimize!(model)

```

---

<div class="post-metadata">

### Author: ![g001234](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/g001234/32/2956_2.png) [@g001234](https://discourse.julialang.org/u/g001234)
#### Post date: [October 13, 2022, 2:36am UTC](https://discourse.julialang.org/t/gurobi-mip-start-calling-grbread-to-provide-starting-vector-using-a-mst-sol-file/10610/7 "2022-10-13T02:36:06Z")

</div>

Thank you very much, Oscar!
