# Get branch-and-bound node depth with JuMP

**URL:** https://discourse.julialang.org/t/get-branch-and-bound-node-depth-with-jump/71128
**Category:** Optimization (Mathematical)
**Tags:** question, package, jump, optimization
**Created:** [November 8, 2021, 6:50am UTC](https://discourse.julialang.org/t/get-branch-and-bound-node-depth-with-jump/71128 "2021-11-08T06:50:29Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![Matheus\_Diogenes\_And](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matheus_diogenes_and/32/27925_2.png) [@Matheus\_Diogenes\_And](https://discourse.julialang.org/u/Matheus_Diogenes_And)
#### Post date: [November 8, 2021, 6:50am UTC](https://discourse.julialang.org/t/get-branch-and-bound-node-depth-with-jump/71128/1 "2021-11-08T06:50:29Z")

</div>

Greetings.

I am facing a problem with JuMP 0.21.4 and Julia 1.6.2. I am working with an Integer Programming model using CPLEX 12.10 and I using callbacks to add some cuts, however, I need these cuts to be added only when the callback is at the root, i.e, I need to add these cuts only when the node depth is 0. Hence, I would like to know if anyone has done something similar. I have used such functionality before when working with another programming language ([IBM Documentation](https://www.ibm.com/docs/en/icos/12.10.0?topic=methods-getcurrentnodedepth-method)).

Thank you for your time.

ps: Note that I am not talking about the callback node status ([Callbacks · JuMP](https://jump.dev/JuMP.jl/stable/reference/callbacks/#Callback-node-status)).

---

<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: [November 8, 2021, 6:54am UTC](https://discourse.julialang.org/t/get-branch-and-bound-node-depth-with-jump/71128/2 "2021-11-08T06:54:45Z")

</div>

You will need to use a solver-dependent callback: [https://github.com/jump-dev/CPLEX.jl#callbacks](https://github.com/jump-dev/CPLEX.jl#callbacks)

---

<div class="post-metadata">

### Author: ![Matheus\_Diogenes\_And](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matheus_diogenes_and/32/27925_2.png) [@Matheus\_Diogenes\_And](https://discourse.julialang.org/u/Matheus_Diogenes_And)
#### Post date: [November 8, 2021, 7:55am UTC](https://discourse.julialang.org/t/get-branch-and-bound-node-depth-with-jump/71128/3 "2021-11-08T07:55:54Z")

</div>

Very thank you, that is exactly what I was looking for.

---

<div class="post-metadata">

### Author: ![Matheus\_Diogenes\_And](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matheus_diogenes_and/32/27925_2.png) [@Matheus\_Diogenes\_And](https://discourse.julialang.org/u/Matheus_Diogenes_And)
#### Post date: [November 12, 2021, 4:35am UTC](https://discourse.julialang.org/t/get-branch-and-bound-node-depth-with-jump/71128/4 "2021-11-12T04:35:50Z")

</div>

Hi, I am sorry for reopening this thread. But I am still struggling to get the branch-and-bound depth through a solver-dependent callback. Follows an MWE based on the example provided at [here](https://github.com/jump-dev/CPLEX.jl#callbacks).

```julia
using JuMP, CPLEX, Test

model = direct_model(CPLEX.Optimizer())
set_silent(model)
MOI.set(model, MOI.NumberOfThreads(), 1)

@variable(model, 0 <= x <= 2.5, Int)
@variable(model, 0 <= y <= 2.5, Int)
@objective(model, Max, y)

function my_callback_function(cb_data::CPLEX.CallbackContext, context_id::Clong)
  # preliminary checkings
  context_id != CPX_CALLBACKCONTEXT_CANDIDATE && return
  ispoint_p = Ref{Cint}()
  (CPXcallbackcandidateispoint(cb_data, ispoint_p) != 0 || ispoint_p[]) == 0 && return
  # getting depth
  depth = Ref{Clong}()
# CPXcallbackgetinfoint(cb_data, CPX_CALLBACK_INFO_NODE_DEPTH, depth)
# CPXcallbackgetinfolong(cb_data, CPX_CALLBACK_INFO_NODE_DEPTH, depth)
  CPXcallbackgetinfodbl(cb_data, CPX_CALLBACK_INFO_NODE_DEPTH, depth)
  depth > 0 && return
end
MOI.set(model, CPLEX.CallbackFunction(), my_callback_function)
optimize!(model)

```

When executing the above code, the following output is given:

```julia
ERROR: LoadError: MethodError: Cannot `convert` an object of type Int64 to an object of type CPXCALLBACKINFO

```

As you can see, I already tried replacing the call CPXcallbackgetinfodbl with CPXcallbackgetinfoint and CPXcallbackgetinfolong. But both changes lead to the same error. I suppose that I am using the wrong function or the wrong flag, i.e. I should use something other than CPX\_CALLBACK\_INFO\_NODE\_DEPTH. I would like to know if anyone has any documentation about this.

Thank you and best regards.

---

<div class="post-metadata">

### Author: ![jd-foster](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jd-foster/32/35824_2.png) [@jd-foster](https://discourse.julialang.org/u/jd-foster)
#### Post date: [November 12, 2021, 4:48am UTC](https://discourse.julialang.org/t/get-branch-and-bound-node-depth-with-jump/71128/5 "2021-11-12T04:48:31Z")

</div>

> [@Matheus\_Diogenes\_And](#):
>
> `CPX_CALLBACK_INFO_NODE_DEPTH`

This is a declared `const` of type `Int64`:

> <https://github.com/jump-dev/CPLEX.jl/blob/75431de991736702ae076d19d3fc96d5c9c61cc0/src/gen1210/libcpx_common.jl#L371-L371>

`CPXcallbackgetinfodbl` expects it’s second argument as a `CPXCALLBACKINFO` CEnum type:

> <https://github.com/jump-dev/CPLEX.jl/blob/75431de991736702ae076d19d3fc96d5c9c61cc0/src/gen1210/libcpx_api.jl#L85-L87>

so one of these:

> <https://github.com/jump-dev/CPLEX.jl/blob/75431de991736702ae076d19d3fc96d5c9c61cc0/src/gen1210/libcpx_common.jl#L1335-L1349>

You probably want `CPXCALLBACKINFO_NODEDEPTH` not `CPX_CALLBACK_INFO_NODE_DEPTH`. Not a hard mistake to make!

---

<div class="post-metadata">

### Author: ![Matheus\_Diogenes\_And](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matheus_diogenes_and/32/27925_2.png) [@Matheus\_Diogenes\_And](https://discourse.julialang.org/u/Matheus_Diogenes_And)
#### Post date: [November 12, 2021, 6:42am UTC](https://discourse.julialang.org/t/get-branch-and-bound-node-depth-with-jump/71128/6 "2021-11-12T06:42:56Z")

</div>

Very thank you for your answer. The code is now executing, however, I think the results are not right. I used the commands as you suggested resulting in the function below:

```julia
function my_callback_function(cb_data::CPLEX.CallbackContext, context_id::Clong) # preliminary checkings
  context_id != CPX_CALLBACKCONTEXT_CANDIDATE && return
  ispoint_p = Ref{Cint}()
  (CPXcallbackcandidateispoint(cb_data, ispoint_p) != 0 || ispoint_p[] == 0) && return # getting depth
  depth = Ref{Clong}()
  CPXcallbackgetinfolong(cb_data, CPXCALLBACKINFO_NODEDEPTH, depth)
  println(depth[])
end

```

And I getting really strange results, specifically very big numbers, such as 52465968, 140258102699840,…  
I think that the conditions ` (CPXcallbackcandidateispoint(cb_data, ispoint_p) != 0 || ispoint_p[] == 0)` are not enough. Which is strange, since according to the [documentation](https://www.ibm.com/docs/en/icos/20.1.0?topic=manual-cpxcallbackinfo) this is a valid condition. If anyone has ever faced such a thing I would like to hear something.

Thank you.

UPDATE 1: Fixing code typing error.

---

<div class="post-metadata">

### Author: ![jd-foster](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jd-foster/32/35824_2.png) [@jd-foster](https://discourse.julialang.org/u/jd-foster)
#### Post date: [November 12, 2021, 12:16pm UTC](https://discourse.julialang.org/t/get-branch-and-bound-node-depth-with-jump/71128/7 "2021-11-12T12:16:59Z")

</div>

> [@Matheus\_Diogenes\_And](#):
>
> `(CPXcallbackcandidateispoint(cb_data, ispoint_p) != 0 || ispoint_p[]) == 0`

Quick thought: are you sure the last bracket is where you want it? If this is a Bool comparison, I would use `false` over `0`, or do you want `ispoint_p[] == 0)`?

---

<div class="post-metadata">

### Author: ![Matheus\_Diogenes\_And](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matheus_diogenes_and/32/27925_2.png) [@Matheus\_Diogenes\_And](https://discourse.julialang.org/u/Matheus_Diogenes_And)
#### Post date: [November 12, 2021, 4:33pm UTC](https://discourse.julialang.org/t/get-branch-and-bound-node-depth-with-jump/71128/8 "2021-11-12T16:33:29Z")

</div>

Now it is, it was a typing error, even with the bracket at the right place, the error still persists.

---

<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: [November 13, 2021, 9:50pm UTC](https://discourse.julialang.org/t/get-branch-and-bound-node-depth-with-jump/71128/9 "2021-11-13T21:50:00Z")

</div>

On some platforms `Clong != CPXLONG`. Try:

```nohighlight
function my_callback_function(cb_data::CPLEX.CallbackContext, context_id::Clong)
    if context_id != CPX_CALLBACKCONTEXT_CANDIDATE
        return
    end
    ispoint_p = Ref{Cint}()
    ret = CPXcallbackcandidateispoint(cb_data, ispoint_p)
    if ret != 0 || ispoint_p[] == 0
        return
    end
    depth = Ref{CPXLONG}()
    ret = CPXcallbackgetinfolong(cb_data, CPXCALLBACKINFO_NODEDEPTH, depth)
    @assert ret == 0
    println(depth[])
end

```

---

<div class="post-metadata">

### Author: ![Matheus\_Diogenes\_And](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matheus_diogenes_and/32/27925_2.png) [@Matheus\_Diogenes\_And](https://discourse.julialang.org/u/Matheus_Diogenes_And)
#### Post date: [November 15, 2021, 4:12am UTC](https://discourse.julialang.org/t/get-branch-and-bound-node-depth-with-jump/71128/10 "2021-11-15T04:12:58Z")

</div>

Thanks for the answer, but the problem still persists. Follows the complete code so you can check the behavior on your own machine.

```julia
using JuMP, CPLEX, Test

model = direct_model(CPLEX.Optimizer())
set_silent(model)
MOI.set(model, MOI.NumberOfThreads(), 1)

@variable(model, 0 <= x <= 2.5, Int)
@variable(model, 0 <= y <= 2.5, Int)
@objective(model, Max, y)

function my_callback_function(cb_data::CPLEX.CallbackContext, context_id::Clong)
#function my_callback_function(cb_data::CPLEX.CallbackContext, context_id::CPXLONG)
  # preliminary checkings
  context_id != CPX_CALLBACKCONTEXT_CANDIDATE && return
# ispoint_p = Ref{Cint}()
  ispoint_p = Ref{CPXINT}()
  (CPXcallbackcandidateispoint(cb_data, ispoint_p) != 0 || ispoint_p[] == 0) && return
  # getting depth
# depth = Ref{Clong}()
  depth = Ref{CPXLONG}()
  CPXcallbackgetinfolong(cb_data, CPXCALLBACKINFO_NODEDEPTH, depth)
  println(depth[])
end
MOI.set(model, CPLEX.CallbackFunction(), my_callback_function)
optimize!(model)

```

Thanks for the consideration.

---

<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: [November 15, 2021, 6:09am UTC](https://discourse.julialang.org/t/get-branch-and-bound-node-depth-with-jump/71128/11 "2021-11-15T06:09:12Z")

</div>

> CPXcallbackgetinfolong(cb\_data, CPXCALLBACKINFO\_NODEDEPTH, depth)

You need to check the return code to see if the call succeeded. I’m guessing it didn’t. Probably because there was no node and the problem was solved at the root node via heuristics?

More generally, you need to read the CPLEX documentation in more detail: [IBM Documentation](https://www.ibm.com/docs/en/icos/20.1.0?topic=manual-cpxcallbackinfo)

You say you only want to add cuts at the root, but `CPX_CALLBACKCONTEXT_CANDIDATE` indicates that you have a valid integer solution. Perhaps you want `CPXCALLBACKINFO_NODECOUNT` or `CPXCALLBACKINFO_NODEUID`? instead?

---

<div class="post-metadata">

### Author: ![Matheus\_Diogenes\_And](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matheus_diogenes_and/32/27925_2.png) [@Matheus\_Diogenes\_And](https://discourse.julialang.org/u/Matheus_Diogenes_And)
#### Post date: [November 15, 2021, 9:49am UTC](https://discourse.julialang.org/t/get-branch-and-bound-node-depth-with-jump/71128/12 "2021-11-15T09:49:59Z")

</div>

Thank you, now it seems to be working.

```julia
using JuMP, CPLEX

model = direct_model(CPLEX.Optimizer())
set_silent(model)
MOI.set(model, MOI.NumberOfThreads(), 1)

@variable(model, 0 <= x <= 2.5, Int)
@variable(model, 0 <= y <= 2.5, Int)
@objective(model, Max, y)

function my_callback_function(cb_data::CPLEX.CallbackContext, context_id::Clong)
  ispoint_p = Ref{CPXINT}()
  (CPXcallbackcandidateispoint(cb_data, ispoint_p) != 0 || ispoint_p[] == 0) && return
  n = Ref{CPXLONG}()
  CPXcallbackgetinfolong(cb_data, CPXCALLBACKINFO_NODECOUNT, n)
  println(n[])
end
MOI.set(model, CPLEX.CallbackFunction(), my_callback_function)
optimize!(model)

```

I just question myself why the above program is printing 0 twice.

---

<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: [November 15, 2021, 7:09pm UTC](https://discourse.julialang.org/t/get-branch-and-bound-node-depth-with-jump/71128/13 "2021-11-15T19:09:36Z")

</div>

> [@Matheus\_Diogenes\_And](#):
>
> I just question myself why the above program is printing 0 twice.

Because your callback gets called multiple times at the root node.

Additionally, you are still not checking the return code of `CPXcallbackgetinfolong` for success.
