Search code examples
visual-c++cplex

How to integrate the outputs from Callbacks in C++/CPLEX


I used macro Callbacks in my code and I want to integrate outputs with together. At each node I need the value of Pseudocosts, slacks, variableBranch and etc. But I don’t know how to integrate these data that I retrieve with different Callbacks. I don’t run all Callbacks with together. Each time I run the code with different Callbacks the values of NodeID or Node aren’t equal. For example in pic1 I run BranchCallback to retrieve Pseudocosts and in pic3 I used UserCutCallback to retrieve the values of variables at each nodes. As can be seen in pic1 the last node is 126 but in pic3 the last node is 164. I want to create data structure in excel with each nodes but I don’t know which number of nodes I have to consider?126 or 164? For example in pic1, can I say all information(values of pseudocosts ) about node10 is belong to node10 in pic3? And in pic3, all information(values of slacks ) about node10 is belong to node10 in pic1?

ILOUSERCUTCALLBACK1(Myvalue, IloArray<IloNumVarArray>, vars) {
for (int i = 0; i < nbworkers; ++i) {
for (int j = 0; j < nbmachines; j++) {
cout << "getvalue(" << vars[i][j] << ") = "
<< getValue(vars[i][j]) << endl;
}
}
}

enter image description here enter image description here


Solution

  • You ask many things at the same time. I am going to answer the question that is related to the subject. For everything else please create a new question and show your code, your actual output and explain how that differs from the expected output.

    The IloCplex class has a function out(). That function returns a reference to the stream to which CPLEX sends all its output. You can pass that reference to your callbacks and then write to that stream from your callbacks.

    For example:

    ILOUSERCUTCALLBACK1(MyCallback, std::ostream &, output) {
      output << "Message from callback" << std::endl;
    }
    

    and then

    cplex.use(MyCallback(cplex.getEnv(), cplex.out()));
    

    to create and register the callback.

    UPDATE After you edited your question, it seems your problem is not to print output from a callback but something else.

    First of all note that it is expected to get different search paths if you do one run with a user cut callback and another run with a branch callback. There is no way to relate the node numbers or node ids from one run to the other. The statistics you want to obtain must be acquired with one single run.

    Moreover, in order to identify a node you should not use the node number or the number of nodes processed (the number in the left-most column in the log). Instead you should use the ID of a node. This is what is known as sequence number in the C++ API. This is the only thing you can use to identify a node. These ids should match with the node ids shown at the very right of the log in case dynamic search is disabled (which happens automatically if you use control callbacks). These node IDs are available from all callbacks and you can use them collect information collected from different callbacks for the same node.

    Update 2: Actually, I was wrong. The number returned by getNodeId() and the number shown in the NodeID column of the log are different, see my answer to this question. There is no way to relate these two numbers. Sorry for the confusion. I think you asked a similar question in another forum as well and I claimed the two numbers to be the same. That was wrong as well. Sorry again.

    So basically your only option to relate things in a callback to things in a log is to perform a single-threaded run and then look at the order in which things are printed.

    However, in order to trace the tree (along with pseudo costs etc.) you don't need the log. You can do everything from a callback by just using sequence numbers. The most difficult part is tracking the parent/child relationship which can be done like this (not that this is not thread safe):

    struct Parent {
       typedef IloCplex::MIPCallbackI::NodeId NodeId;
       struct Less {
          bool operator()(NodeId const &n1, NodeId const &n2) const {
             return n1._id < n2._id;
          }
       };
       typedef std::map<NodeId,NodeId,Less> MapType;
       MapType parents;
       void set(NodeId child, NodeId parent) { parents[child] = parent; }
       IloCplex::MIPCallbackI::NodeId get(NodeId child) const {
          MapType::const_iterator it = parents.find(child);
          return (it == parents.end()) ? NodeId() : it->second;
       }
    };
    
    Parent parent;
    
    ILOBRANCHCALLBACK0(BranchCallback) {
       std::cout << "CALLBACK[B]: " << getNodeId()
                 << " (" << parent.get(getNodeId()) << ")" << std::endl;
       int const n = getNbranches();
       for (int i = 0; i < n; ++i) {
          NodeId id = makeBranch(i);
          parent.set(id, getNodeId());
       }
    }