我从BranchCallback获得了NodeID(getNodeID)和Parent,并从NodeCallback获得了可变分支。当我绘制树搜索算法时,某些节点在这些节点之前没有任何变量分支,并且当我看到VS C ++的控制台时,没有那些NodeId的记录。但是我确定BranchCallback中有很多信息,例如那些节点的目标值。为什么?
答案 0 :(得分:1)
请注意(如我在另一篇文章中所述),控制台日志中显示的NodeID与您在回调中获得的NodeID不同。因此,这两件事是无法关联的。
然后,对于您要询问的其他内容,您不清楚如何获取任何数据。特别是,如果您在分支回调中收集节点,然后仅稍后在节点回调中计算我们的分支变量,则此方法可能不适用于已修剪的节点。为什么不从分支回调中也获得分支变量呢? 这是一个简单的示例,该怎么做:
#include <map>
#include <limits>
#include <iostream>
#include <ilcplex/ilocplex.h>
#include <ilconcert/ilothread.h>
using std::cout;
using std::endl;
/** The info we collect for a node. */
struct Info {
IloCplex::MIPCallbackI::NodeId id; /**< The node's id. */
IloCplex::MIPCallbackI::NodeId parent; /**< ID of the parent (root is 0). */
IloNumVar branchVar; /**< The variable on which CPLEX branched
* to create this node. */
IloNum branchVal; /**< The value CPLEX used for branching. */
IloCplex::BranchDirection branchDir; /**< The direction into which CPLEX branched. */
};
// Overload operator< so that we can use NodeIds as keys in maps.
bool operator<(IloCplex::MIPCallbackI::NodeId const &n1,
IloCplex::MIPCallbackI::NodeId const &n2)
{
return n1._id < n2._id;
}
// Map node ids to Info objects so that you can easily get from the info
// for a child to the info of its parent.
IloFastMutex lck;
typedef std::map<IloCplex::MIPCallbackI::NodeId,Info> MapType;
MapType nodeMap;
// A simple branch callback that tracks CPLEX branching decisions.
ILOBRANCHCALLBACK0(BranchCallback) {
IloInt const n = getNbranches();
IloCplex::MIPCallbackI::NodeId me = getNodeId();
IloNumVarArray x(getEnv());
IloNumArray bounds(getEnv());
IloCplex::BranchDirectionArray dirs(getEnv());
for (IloInt b = 0; b < n; ++b) {
// Get what CPLEX plans to do and perform the exact same branch.
// Then record all the information abouth the newly created branch.
getBranch(x, bounds, dirs, b);
Info info;
info.id = makeBranch(b);
info.parent = me;
if ( x.getSize() == 1 ) {
info.branchVar = x[0];
info.branchVal = bounds[0];
info.branchDir = dirs[0];
}
else {
// CPLEX branches on more than one variable. We don't record that.
info.branchVar = 0;
info.branchVal = std::numeric_limits<double>::quiet_NaN();
info.branchDir = IloCplex::BranchGlobal;
}
lck.lock();
nodeMap.insert(MapType::value_type(info.id, info));
lck.unlock();
}
dirs.end();
bounds.end();
x.end();
}
int
main(int argc, char **argv) {
for (int a = 1; a < argc; ++a) {
IloEnv env;
IloModel model(env);
IloCplex cplex(model);
cplex.importModel(model, argv[a]);
cplex.use(BranchCallback(env));
nodeMap.clear();
cplex.setParam(IloCplex::Threads, cplex.getNumCores());
//cplex.setParam(IloCplex::Threads, 1);
//cplex.setParam(IloCplex::NodeLim, 10);
cplex.solve();
// Print information about all the nodes.
for (MapType::const_iterator it = nodeMap.begin(); it != nodeMap.end(); ++it) {
Info const &i = it->second;
cout << "Node " << i.id << " created from " << i.parent
<< " by branching "
<< (i.branchDir == IloCplex::BranchUp ? "up" : "down")
<< " on " << (i.branchVar.getImpl() ? i.branchVar.getName() : "more than one variable")
<< " with value " << i.branchVal
<< endl;
}
env.end();
}
return 0;
}
如果您还想跟踪选择节点的顺序,请添加一个字段
IloInt order;
转到Info
类,并使用像这样的节点回调:
// A simple node callback that tracks the order in which nodes are selected.
ILONODECALLBACK0(NodeCallback) {
// The order that CPLEX plans to execute next is at index 0.
IloCplex::MIPCallbackI::NodeId next = getNodeId(0);
lck.lock();
static IloInt order = 0;
nodeMap[next].order = order++;
lck.unlock();
}
(除了简单的计数器,您还可以使用时间戳或其他方式)。