Decision Optimization

Decision Optimization

Delivers prescriptive analytics capabilities and decision intelligence to improve decision-making.


#Analytics
#DecisionOptimization
#DecisionOptimization
 View Only
  • 1.  Get the depth of the current node C++

    Posted 08/13/14 08:17 AM

    Originally posted by: Frops


    Hi,

    I am using a user cut callback that adds some cuts to the model I want to solve. This works fine but I would like to add these cuts only to a certain level of depth of the nodes on the search tree. 
     
    I do not know how to retrieve the depth of the current node in the user cut callback.
     
    I have found this thread: https://www.ibm.com/developerworks/community/forums/html/topic?id=77777777-0000-0000-0000-000014535268&ps=25 where a similar question is answered using a Branch Callback. 

    I work with templates to build the Callbacks, not with classes. Is it possible to do the same using templates in Callbacks?

    I have tried to use a variable to control the depth of the node. The variable was updated in the branch callback and it was used in the usercut callback. But the variable was really not updated in the usercut callback after branch callbacks.

    My question is: Is there a way to know the depth of the current node in the usercut callback building callbacks with templates?

    Also, I have seen the function getDepth() in the NodeCallbackI. I understand that this might help.

    This function needs as input a node identifier, but I do not have any idea how I could obtain the node identifier of the current node.

    My second question is: Is there any way to get the node identifier inside the NodeCallback?

     

    Thanks in advances,

    Mireia


    #CPLEXOptimizers
    #DecisionOptimization


  • 2.  Re: Get the depth of the current node C++

    Posted 08/14/14 01:12 AM

    What do you mean when you are saying you use templates? Do you mean C++ templates? I don't see how you could build a callback without using a class. Maybe you are using a template class (or class template)? Could you show a small example? In any case, I don't see how using templates would interfere with the definition of callbacks.

    When the node callback is invoked, the next node to be processed is the node at index 0. So what you could do in the node callback is the following (untested):

    struct Depth : public IloCplex::MIPCallbackI::NodeData {
       IloInt const depth;
       Depth(IloInt d) : depth(d) {}
    };

    void main() {
       IloInt64 nextNode = 0;
       Depth *depth = new Depth(getDepth(nextNode));
       NodeData *old = setNodeData(nextNode, depth); // Replace node data in nextNode
       if ( old )  delete old;                       // Delete old node data (if there was any)
    }

    This sets the node user data for each node before it is being processed. Then, in any other callback you can do:

    void main() {
       Depth const* const d = (Depth *)getNodeData();
       IloInt depth = d ? d->depth : 0;
    }

    You have to explicitly test the case 'd == NULL' since the node callback is not invoked before processing the root node. Thus d==NULL for the root node, which by definition has depth 0.


    #CPLEXOptimizers
    #DecisionOptimization


  • 3.  Re: Get the depth of the current node C++

    Posted 08/14/14 03:41 AM

    Originally posted by: Frops


    Dear Daniel,

    Thank you for your answer. 

    I am so sorry, I made a mistake. I do not use templates for building Callbacks, I use MACROS. 

    For instance, 

    ILONODECALLBACK1(nodecallback, ofstream&, fitxer){

    nodep2=nodep2+1:

    fitxer << nodep2<<endl;

    }

    This callback does not do anything meaningful, just to show an example.

    There are a lot of macros defined depending on the type of callback: ILOUSERCUTCALLBACKk etc...

    Here is the link to the manual with all the macros  http://pic.dhe.ibm.com/infocenter/cosinfoc/v12r2/index.jsp?topic=%2Filog.odms.ide.help%2Fhtml%2Frefcppopl%2Fhtml%2Fmacros%2FILOUSERCUTCALLBACK0.html

     

    I did not understand that when the node callback is invoked, the next node to be processed is the node at index 0.

    So for instance, if in the macro I use the command getDepth on node 0, I should get the depth of the next node to be processed.

    For instance, my code should be like this:

    IloInt nodep; // global variable that keeps track of the depth of the current node

    ILONODECALLBACK1(nodecallback, ofstream&, fitxer){

    IloInt64 nextNode = 0;

    nodep=getDepth(nextNode);

    }

    Then if in another callback, in my case the usercutcallback, I use the global variable nodep, it will contain the depth of the current node.

     

    I am sorry I am not very good at C++. It is difficult for me to understand the callbacks defined that way.I will try to understand your proposal. Because, maybe I am missing something.

     

    Thanks a lot,


    #CPLEXOptimizers
    #DecisionOptimization


  • 4.  Re: Get the depth of the current node C++

    Posted 08/14/14 05:27 AM

    What you say about that global nodep variable is correct as along as you don't use multiple threads. In case of multiple threads callbacks may execute in parallel and multiple threads may process different nodes simultaneously, thus nodep would be correct for at most one thread.

    If you use a control callback (node callback, cut callback, branch callback, ...) then CPLEX automatically switches to single-threaded mode. So unless you explicitly set IloCplex::Threads to something >1, you should be good. If you use more than one thread just use the node callback code I outlined in my previous reply.

    To understand the macros a little better, it might help to look at the code to which they expand. Consider for example

    ILONODECALLBACK1(nodecallback, ofstream&, fitxer){
       IloInt64 nextNode = 0;
       nodep=getDepth(nextNode);
    }

    This expands to something like this (code from the macro in bold face. macro arguments underlined):

    class nodecallbackI : public IloCplex::NodeCallbackI {
       ofstream &fitxer;
    public:
       ... // some general stuff
       nodecallbackI(IloEnv env, ofstream &x1) : IloCplex::NodeCallbackI(env), fitxer(x1) {}
       void main();
    };
    IloCplex::Callback nodecallback(IloEnv env, ofstream &x1) { return IloCplex::Callback(new (env) nodecallbackI(env, x1)) }
    void nodecallbackI::main()
    {
       IloInt64 nextNode = 0;
       nodep = getDepth(nextNode);
    }

    So the macro does three things:

    1. It defines a class nodecallbackI (note the 'I' it appends to the name you provide to the macro). From the arguments passed to the macro it defines a constructor for this class.
    2. It defines a function nodecallback() that takes the same arguments as the class's constructor and returns a callback instance that uses the nodecallbackI class.
    3. It starts the definition of the callback's main() function so that any code you write after the macro will be the function body of the callback's main function.

    Instead of using the macro you could easily write all this yourself. The macro is just for your convenience. It is still good to understand what the macro does in detail :-)


    #CPLEXOptimizers
    #DecisionOptimization


  • 5.  Re: Get the depth of the current node C++

    Posted 08/14/14 06:04 AM

    Originally posted by: Frops


    Dear Daniel,

    Thank you very much. 

    Yes, I am using only one thread at the moment. But I understand that this will not work in case of multithread. 

    Thank you for your clarifying explanations regarding the macro and the use of classes. It has helped me a lot. I agree with you that macros are for conveinience, but it is good to understand the detail :)

    You have been an invaluable help to me. Thanks again,

    Mireia


    #CPLEXOptimizers
    #DecisionOptimization


  • 6.  Re: Get the depth of the current node C++

    Posted 08/31/17 03:25 AM

    Originally posted by: arccos0


    It's a pretty helpful answer. Thank you.

    A small question: 

    Does the sentence ``When the node callback is invoked, the next node to be processed is the node at index 0.'' mean the default node that the Cplex will choose is the one at index 0? 


    #CPLEXOptimizers
    #DecisionOptimization


  • 7.  Re: Get the depth of the current node C++

    Posted 08/31/17 04:04 AM

    Yes. If you do not select another node then the node that CPLEX will choose is the one at index 0.


    #CPLEXOptimizers
    #DecisionOptimization