Decision Optimization

Decision Optimization

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


#Analytics
#DecisionOptimization
#DecisionOptimization
 View Only
Expand all | Collapse all

Inheriting Node Data

  • 1.  Inheriting Node Data

    Posted 09/03/14 02:29 AM

    Originally posted by: VKV7_Anulark_Naber


    I am now using the node data to store information on which variables that have been branched. Here are my questions:

    1. It seems that the node data needs to be manually copied from a parent to children - always. Do I understand it correctly, or is the node data automatically inherited or copied by any cplex callback?

    2. In case of manually copying, I have a problem because I also have a random part in the branchcallback that allows cplex to do its own branching and the other random part using my branching. For the cplex part, I have no control over the node data, and in this case, the node data would be lost. Is therer any way to go around this issue?

    Thanks in advance.


    #CPLEXOptimizers
    #DecisionOptimization


  • 2.  Re: Inheriting Node Data

    Posted 09/03/14 08:41 AM

    Originally posted by: anahana


    Hi, 

    Not sure if CPLEX automatically inherits node data, but I doubt it. Can you provide more information about your second point? I'm doing something similar and may be able to help.

     

    Regards,  


    #CPLEXOptimizers
    #DecisionOptimization


  • 3.  Re: Inheriting Node Data

    Posted 09/03/14 09:03 AM

    Originally posted by: VKV7_Anulark_Naber


    Because in the branchcallback, we have to copy the node data of the current node and add the information of the new branching variable to get a new node data to be attached to the new nodes. This is no problem. But when sometimes I let cplex branch, it won't do that job, so I will lose the node data of the parent. That is the problem.


    #CPLEXOptimizers
    #DecisionOptimization


  • 4.  Re: Inheriting Node Data

    Posted 09/03/14 10:47 AM

    Originally posted by: anahana


    May be this will help:

    When you want to have CPLEX branch by itself, use the getBranch function to identify which branch CPLEX is going to choose, then branch on it manually adding the node data you want. This way you are controlling all the branching decisions while choosing some to be the same as the ones CPLEX would have chosen.

    Regards, 


    #CPLEXOptimizers
    #DecisionOptimization


  • 5.  Re: Inheriting Node Data

    Posted 09/03/14 11:00 AM

    Originally posted by: VKV7_Anulark_Naber


    Oh, ok. That means I have to add manually to every node the node data. Thanks.


    #CPLEXOptimizers
    #DecisionOptimization


  • 6.  Re: Inheriting Node Data

    Posted 09/15/14 10:20 AM

    The makeBranch(IloNum, NodeData *) overload comes in handy here. It creates the n-th CPLEX branch but allows attaching node data to the newly created branch.


    #CPLEXOptimizers
    #DecisionOptimization


  • 7.  Re: Inheriting Node Data

    Posted 09/17/14 10:13 AM

    Originally posted by: VKV7_Anulark_Naber


    Now I implemented my NodeData like this:

    typedef std::map<int,int> FixVarMap;
    class FixVarInfo_t : public IloCplex::BranchCallbackI::NodeData {
      IloInt ParentId; //parent's nodeid
      FixVarInfo_t * ParentPtr; //pointer to the parent's nodedata
      FixVarMap FixPair;
     
    public:
      FixVarInfo_t () {};
      FixVarInfo_t (IloInt id, FixVarInfo_t *ptr) //store parent's id and ptr ot parent's nodedata
        : ParentId(id), ParentPtr(ptr)  {};
     
      void FixVarInfo_t::insertVals (const int key, const int val) {
        //To insert variables and fixed values to FixPair };
     
      int FixVarInfo_t::getValue (const int key, FixVarInfo_t *ptr1) { //key is variableId  //A recursive method
         int index = -1;
         FixVarMap::iterator it;
         it = ptr1->FixPair.find(key);
         if (it != ptr1->FixPair.end()) {
           index = it->second;
         }
        else {
            if (ptr1->ParentId > 0)
                 index = ptr1->getValue (key, ptr1->ParentPtr);
         }
         return index;
       };
    };
     

    Now there is a problem. Till a node in the second level (say node 3), the nodedata is changed.

     

    Here are some output from debugger of these codes in BranchCallback before branching:

    FixVarInfo_t *FixVarInfo = dynamic_cast <FixVarInfo_t *> (getNodeData()); //get nodedata of the current node

    FixVarInfo_t *FixVarInfo1 = new FixVarInfo_t (getNodeId()._id, FixVarInfo); //nodedata of a new node, here copy the nodedata of the current node as its parent

     

    ---At Node 0, before branching

    + FixVarInfo 0x0000000000000000 {ParentId=??? ParentPtr=??? FixPair={ size=??? } } FixVarInfo_t *
     
    + FixVarInfo1 0x0000000000334fc0 {ParentId=0 ParentPtr=0x0000000000000000 {ParentId=??? ParentPtr=??? FixPair={ size=??? } } ...} FixVarInfo_t *
     

    ---At Node 2, before branching

    + FixVarInfo 0x0000000000334fc0 {ParentId=0 ParentPtr=0x0000000000000000 {ParentId=??? ParentPtr=??? FixPair={ size=??? } } ...} FixVarInfo_t *
    + FixVarInfo1 0x0000000003257d40 {ParentId=2 ParentPtr=0x0000000000334fc0 {ParentId=0 ParentPtr=0x0000000000000000 {...} ...} ...} FixVarInfo_t *
     

    So far so good.

    ---At Node 3, before branching

    + FixVarInfo 0x0000000003257d40 {ParentId=2 ParentPtr=0x0000000000334fc0 {ParentId=3 ParentPtr=0x0000000003257d40 {...} ...} ...} FixVarInfo_t *
    + FixVarInfo1 0x0000000000334fc0 {ParentId=3 ParentPtr=0x0000000003257d40 {ParentId=2 ParentPtr=0x0000000000334fc0 {...} ...} ...} FixVarInfo_t *
     

    Now something went wrong. FixVarInfo is obtained from getNodeData() at Node 3, it is supposed to be the same as FixVarInfo1 at Node 2, but it is not. This creates an infinite loop in the recursive method getValue(). I cannot figure out what went wrong. I used the pointers to the nodedata of the parent, so I don't need to copy all fixed variables in order to save time and storage. Could somebody help please?

     


    #CPLEXOptimizers
    #DecisionOptimization


  • 8.  Re: Inheriting Node Data

    Posted 09/18/14 02:07 AM

    Using pointers to the node data of a different node is not a good idea, IMO: once CPLEX is finished with a node it will invoke operator delete on the node data of that node. So you are most likely accessing dangling pointers in your code.


    #CPLEXOptimizers
    #DecisionOptimization


  • 9.  Re: Inheriting Node Data

    Posted 09/18/14 03:09 AM

    Originally posted by: VKV7_Anulark_Naber


    What do you mean by "finish"? Do you mean when the node get fathomed either by pruning, feasible solution, or infeasibility, right? Or other meanings?

    But the pointer in the example was lost to the root node and this was still in the beginning of the branch and bound tree, so I presume that no node is fathomed at this point.

    The fixed/branched variables are needed to add local cuts, therefore, these nodes would still be active including their parents. If the problem is large, copying all fixed variables from parents would require a bigger storage. Is there any other suggestions?

    Thanks in advance.


    #CPLEXOptimizers
    #DecisionOptimization


  • 10.  Re: Inheriting Node Data

    Posted 09/22/14 02:21 AM

    What do you mean by "finish"? Do you mean when the node get fathomed either by pruning, feasible solution, or infeasibility, right? Or other meanings?

    All that, plus when the node is fully processed (for example because CPLEX did branch on it).

    But the pointer in the example was lost to the root node and this was still in the beginning of the branch and bound tree, so I presume that no node is fathomed at this point.

    If I understand correctly then in your example 2 is a child of 0 and 3 is a child of 2? So when 3 is processed then CPLEX has already branched on 0 and 2, hence these two nodes are finished and CPLEX should have invoked the destructor of the corresponding node data. Maybe just add some print-out to the node data destructor to see when the destructor is invoked.

    The fixed/branched variables are needed to add local cuts, therefore, these nodes would still be active including their parents. If the problem is large, copying all fixed variables from parents would require a bigger storage. Is there any other suggestions?

    You can work with a tree-like data structure as you had planned. You only need to make sure that NodeData is not a node in that tree. So build a tree of FixVarInfo but let NodeData only point into that tree. That way deletion of a NodeData will not affect the tree of FixVarInfo instances.


    #CPLEXOptimizers
    #DecisionOptimization


  • 11.  Re: Inheriting Node Data

    Posted 09/22/14 09:54 AM

    Originally posted by: VKV7_Anulark_Naber


    Now, I implemented the NodeData as you suggested:

    class myNodeData_t : public IloCplex::BranchCallbackI::NodeData {
    public:
      FixVarInfo_t *NodeDataPtr; //pointer to FixVarInfo
      myNodeData_t (FixVarInfo_t *p) : NodeDataPtr(p) {};
    };
    In the BranchCallback, there are these statements to get the NodeData and pointer to FixVarInfo:

    FixVarInfo_t *FixVarInfo;

    if (getNodeId()._id == 0) {
      FixVarInfo = new FixVarInfo_t (-1, NULL);
      FixVarInfo->NodeId = 0;
    }
    else { //retrive NodeData and pointer to FixVarInfo
      myNodeData_t *currentNodeData = dynamic_cast <myNodeData_t *> (getNodeData());
      FixVarInfo = currentNodeData->NodeDataPtr; 
    }
     
    FixVarInfo_t *FixVarInfo1 = new FixVarInfo_t (getNodeId()._id, FixVarInfo); //Child1's FixVarInfo
    FixVarInfo_t *FixVarInfo2 = new FixVarInfo_t (getNodeId()._id, FixVarInfo); //Child2's FixVarInfo
    myNodeData_t *NodeData1 = new myNodeData_t (FixVarInfo1); //Pointer to Child1's FixVarInfo
    myNodeData_t *NodeData2 = new myNodeData_t (FixVarInfo2); //Pointer to Child2's FixVarInfo
    ...

     

    FixVarInfo1->NodeId = makeBranch(cons1, vars1, vals1, dirs1, getObjValue(), NodeData1)._id;
    FixVarInfo2->NodeId = makeBranch(cons2, vars2, vals2, dirs2, getObjValue(), NodeData2)._id;
     

    Is this the correct way to do it?

     

     


    #CPLEXOptimizers
    #DecisionOptimization


  • 12.  Re: Inheriting Node Data

    Posted 09/22/14 10:17 AM

    Looks correct to me at first glance. You may want to add reference counting to the FixVarInfo pointers/instances so that things get cleaned up automatically when they are no longer referenced from node data objects.


    #CPLEXOptimizers
    #DecisionOptimization


  • 13.  Re: Inheriting Node Data

    Posted 09/22/14 10:21 AM

    Originally posted by: VKV7_Anulark_Naber


    Never done it before. Any example codes would be very helpful. Thanks.


    #CPLEXOptimizers
    #DecisionOptimization


  • 14.  Re: Inheriting Node Data

    Posted 09/23/14 02:30 AM

    C++-11 has std::shared_ptr for reference counting, the same class exists in boost, I think.

    Just searching the Internet for "c++" and "reference counting" or "smart pointer" should produce lots of examples.


    #CPLEXOptimizers
    #DecisionOptimization


  • 15.  Re: Inheriting Node Data

    Posted 09/23/14 04:48 AM

    Originally posted by: VKV7_Anulark_Naber


    Thank you.


    #CPLEXOptimizers
    #DecisionOptimization