# Getting info from CPLEX output

**URL:** <https://discourse.julialang.org/t/getting-info-from-cplex-output/42582>\
**Category:** Optimization (Mathematical)\
**Tags:** jump\
**Created:** [July 5, 2020, 11:51pm UTC](https://discourse.julialang.org/t/getting-info-from-cplex-output/42582 "2020-07-05T23:51:01Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Codzilla](https://avatars.discourse-cdn.com/v4/letter/c/7cd45c/32.png) [@Codzilla](https://discourse.julialang.org/u/Codzilla)\
**Post date:** [July 5, 2020, 11:51pm UTC](https://discourse.julialang.org/t/getting-info-from-cplex-output/42582/1 "2020-07-05T23:51:01Z")

</div>

I’m using JuMP to solve a large number of instancies with CPLEX and I would like to use the information output by CPLEX such as the number of Flow cuts applied or time spent during branch & bound. Is there any elegant way to get these informations in variables?

As of now, my solution is to redirect my stdout to a file so that CPLEX prints everything there and do a grep (+ cast to Float) on the resulting file. It’s a quick and dirty solution but I didn’t find anything else either in the CPLEX documentation or in the JuMP one.

Is there a better solution?

---

<div class="post-metadata">

**Author:** ![joaquimg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/joaquimg/32/223_2.png) [@joaquimg](https://discourse.julialang.org/u/joaquimg)\
**Post date:** [July 6, 2020, 12:03am UTC](https://discourse.julialang.org/t/getting-info-from-cplex-output/42582/2 "2020-07-06T00:03:23Z")

</div>

JuMP is a great way to interact with solvers, such as CPLEX. Loosely speaking, JuMP will “convert” CPLEX’s C API calls into JuMP calls, which can be solver independent (the same function for many solvers) or solver dependent (each solver will have particular functions).  
I am not aware of the functionality you are asking for, however, if you find some info about how to do that in CPLEX’s manual we can help you with a (hopefully) nice way to that with JuMP + Julia.

---

<div class="post-metadata">

**Author:** ![Codzilla](https://avatars.discourse-cdn.com/v4/letter/c/7cd45c/32.png) [@Codzilla](https://discourse.julialang.org/u/Codzilla)\
**Post date:** [July 6, 2020, 12:44am UTC](https://discourse.julialang.org/t/getting-info-from-cplex-output/42582/3 "2020-07-06T00:44:39Z")

</div>

It might be clearer with an example. After running the optimize!() function, CPLEX prints out information such as

> julia\> optimize!(model)  
> CPXPARAM\_TimeLimit 3600  
> CPXPARAM\_Threads 1  
> Warning: Non-integral bounds for integer variables rounded.  
> 1 of 1 MIP starts provided solutions.  
> MIP start ‘m1’ defined initial solution with objective 1003023.1305.  
> Warning: Non-integral bounds for integer variables rounded.  
> Tried aggregator 1 time.  
> MIP Presolve eliminated 20 rows and 0 columns.  
> MIP Presolve modified 10 coefficients.  
> Reduced MIP has 1448 rows, 9520 columns, and 45848 nonzeros.  
> Reduced MIP has 428 binaries, 0 generals, 0 SOSs, and 0 indicators.  
> Presolve time = 0.00 sec. (27.40 ticks)  
> Tried aggregator 1 time.  
> Reduced MIP has 1448 rows, 9520 columns, and 45848 nonzeros.  
> Reduced MIP has 428 binaries, 0 generals, 0 SOSs, and 0 indicators.  
> Presolve time = 0.02 sec. (25.30 ticks)  
> Probing time = 0.00 sec. (6.45 ticks)  
> Clique table members: 20.  
> MIP emphasis: balance optimality and feasibility.  
> MIP search method: dynamic search.  
> Parallel mode: none, using 1 thread.  
> Root relaxation solution time = 0.00 sec. (19.96 ticks)
> 
> ```
> Nodes Cuts/
> 
> ```
> 
> Node Left Objective IInf Best Integer Best Bound ItCnt Gap
> 
> - 
> 
> ```
> 0+ 0 1003023.1305 -9110496.3688 --- 
> 0 0 937733.4054 78 1003023.1305 937733.4054 672 6.51%
> 0 0 960438.9696 95 1003023.1305 Cuts: 285 770 4.25%
> 0 0 967788.9910 92 1003023.1305 Cuts: 193 842 3.51%
> 0 0 972277.3234 113 1003023.1305 Cuts: 134 940 3.07%
> 0 0 975773.3675 98 1003023.1305 Cuts: 130 1039 2.72%
> 0 0 978571.6876 101 1003023.1305 Cuts: 124 1122 2.44%
> 0 0 980584.2773 126 1003023.1305 Cuts: 108 1221 2.24%
> 0 0 983789.9356 72 1003023.1305 Cuts: 116 1347 1.92%
> 0 0 985012.8528 92 1003023.1305 Cuts: 65 1418 1.80%
> 0 0 985850.9575 96 1003023.1305 Cuts: 69 1494 1.71%
> 0 0 986708.7299 96 1003023.1305 Cuts: 67 1575 1.63%
> 
> ```
> 
> - 
> 
> ```
> 0+ 0 992729.7930 986708.7299 0.61%
> 0 0 986922.4191 74 992729.7930 Cuts: 61 1643 0.58%
> 0 0 987047.8536 86 992729.7930 Cuts: 67 1706 0.57%
> 0 0 987160.9933 62 992729.7930 Cuts: 46 1771 0.56%
> 0 0 987241.1345 101 992729.7930 Cuts: 34 1837 0.55%
> 0 0 987461.5478 88 992729.7930 Cuts: 59 1890 0.53%
> 0 0 987706.3188 100 992729.7930 Cuts: 72 1989 0.51%
> 0 0 987831.4118 83 992729.7930 Cuts: 56 2066 0.49%
> 0 0 987919.9779 98 992729.7930 Cuts: 47 2125 0.48%
> 0 2 987919.9779 98 992729.7930 987920.8848 2125 0.48%
> 
> ```
> 
> Elapsed time = 1.77 sec. (2902.57 ticks, tree = 0.01 MB, solutions = 2)  
> 30 22 988495.5139 68 992729.7930 988068.2933 2716 0.47%  
> 89 57 990548.1597 51 992729.7930 988253.6533 3398 0.45%  
> 120 70 989589.1727 66 992729.7930 988534.2782 3918 0.42%  
> 178 91 989630.9612 58 992729.7930 988878.3892 4525 0.39%  
> 228 108 992527.9493 50 992729.7930 989338.6592 5330 0.34%  
> 283 124 990903.1868 43 992729.7930 989599.2238 6041 0.32%  
> 360 152 992513.4992 33 992729.7930 989942.6504 6892 0.28%  
> 422 148 cutoff 992729.7930 990394.5056 7779 0.24%  
> 493 155 992336.9089 25 992729.7930 990788.1302 8577 0.20%
> 
> Cover cuts applied: 2  
> Implied bound cuts applied: 7  
> Flow cuts applied: 107  
> Mixed integer rounding cuts applied: 41  
> Flow path cuts applied: 39
> 
> Root node processing (before b&c):  
> Real time = 1.77 sec. (2896.93 ticks)  
> Sequential b&c:  
> Real time = 1.67 sec. (3203.84 ticks)  
> ------------  
> Total (root+branch&cut) = 3.44 sec. (6100.77 ticks)

I would like to access this information.  
There’s no function directly in the CPLEX API for C that does this as far as I’m aware, so it’s probably not just me missing a JuMP function or a missing bridge.

It’s probably local variables that are destroyed when CPLEX is done running. As these are not Julia variables in the first place, I have little hope that it’s possible to retrieve these information in a neat way but I might be wrong.

---

<div class="post-metadata">

**Author:** ![mtanneau](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mtanneau/32/17787_2.png) [@mtanneau](https://discourse.julialang.org/u/mtanneau)\
**Post date:** [July 6, 2020, 2:04am UTC](https://discourse.julialang.org/t/getting-info-from-cplex-output/42582/4 "2020-07-06T02:04:46Z")

</div>

As I heard it in a CPLEX workshop: “If it’s not in the C API, then it doesn’t exist.”

If it’s in the C API (either as a specific function or by querying the right attribute), then it should be in the Julia wrapper as well.

---

<div class="post-metadata">

**Author:** ![mike\_k](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mike_k/32/211864_2.png) [@mike\_k](https://discourse.julialang.org/u/mike_k)\
**Post date:** [July 6, 2020, 11:02am UTC](https://discourse.julialang.org/t/getting-info-from-cplex-output/42582/5 "2020-07-06T11:02:38Z")

</div>

In the C API you can retrieve the number of applied cuts with [CPXgetnumcuts](https://perso.ensta-paris.fr/~diam/ro/online/cplex/cplex1271/refcallablelibrary/mipapi/getnumcuts.html)( CPXCENVptr env, CPXCLPptr lp, int cuttype, int \* num\_p ). However, it is not well documented in JuMP.jl and CPLEX.jl how to obtain the pointers to “env” and “lp”. You can try to find some function which is supported by JuMP and CPLEX [here](https://perso.ensta-paris.fr/~diam/ro/online/cplex/cplex1271/refcallablelibrary/groups/homepageaccessmipresults.html) (e.g., CPXgetmiprelgap should be supported) and look up how it is done in the source code of the packages.  
If you come up with an solution please share it.

---

<div class="post-metadata">

**Author:** ![mtanneau](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mtanneau/32/17787_2.png) [@mtanneau](https://discourse.julialang.org/u/mtanneau)\
**Post date:** [July 6, 2020, 3:53pm UTC](https://discourse.julialang.org/t/getting-info-from-cplex-output/42582/6 "2020-07-06T15:53:17Z")

</div>

To reach the `env` and `lp` pointers, the simplest is to use direct mode, then make your way through the various layers until you reach the CPLEX objects (technically, pointers to the CPLEX objects)

```julia
jump_model = JuMP.direct_model(CPLEX.Optimizer()) # JuMP
moi_model = backend(jump_model) # MOI
cplex_model = moi_model.inner # CPLEX.jl
env, lp = cplex_model.env, cplex_model.lp # CPLEX (C api)

```

In most cases, you should be able to query the information you want from `cplex_model` directly, since most (if not all) C api functions are wrapped in Julia.

Finally, to query the number of cuts, call `CPXgetnumcuts` (as wrapped in [CPLEX.jl](https://github.com/jump-dev/CPLEX.jl/blob/44c8ca62b4e0e63e85a66e029e332d9dafeebd32/src/cpx_solve.jl#L320-L328)) as @mike_k pointed out.

The strategy is similar if you want to access a different attribute.

---

<div class="post-metadata">

**Author:** ![mike\_k](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mike_k/32/211864_2.png) [@mike\_k](https://discourse.julialang.org/u/mike_k)\
**Post date:** [July 21, 2020, 9:39am UTC](https://discourse.julialang.org/t/getting-info-from-cplex-output/42582/7 "2020-07-21T09:39:15Z")

</div>

I wrote a simple function which does the job using [CPXgetnumcuts](https://www.ibm.com/support/knowledgecenter/SSSA5P_12.9.0/ilog.odms.cplex.help/refcallablelibrary/mipapi/getnumcuts.html) and the full defines of [CPLEX.jl](https://github.com/jump-dev/CPLEX.jl/blob/44c8ca62b4e0e63e85a66e029e332d9dafeebd32/src/full_defines_1290.jl) for CPLEX version 12.9, and `direct_model` in JuMP.

```julia
function cpx_get_num_cuts( model::Model, cuttype::Int32 )
    num_cuts::Int32 = -1
    moi_model = backend( model ) # MOI
    cplex_model = moi_model.inner # CPLEX.jl
    num_cuts = CPLEX.get_num_cuts( cplex_model, cuttype )
    return num_cuts::Int32
end

```

After solving simply call, e.g.,

```julia
foo = cpx_get_num_cuts( model, CPLEX.CPX_CUT_FRAC )

```

to obtain the number of added Gomory fractional cuts.
