首页 > 解决方案 > 如何在 C++/CPLEX 中集成回调的输出

问题描述

我在我的代码中使用了宏回调,我想将输出集成在一起。在每个节点上,我需要 Pseudocosts、slacks、variableBranch 等的值。但我不知道如何将我检索到的这些数据与不同的回调集成。我不会一起运行所有回调。每次我使用不同的回调运行代码时,NodeID 或 Node 的值都不相等。例如,在 pic1 中,我运行 BranchCallback 来检索 Pseudocosts,在 pic3 中,我使用 UserCutCallback 来检索每个节点的变量值。从 pic1 中可以看出,最后一个节点是 126,但在 pic3 中,最后一个节点是 164。我想在 excel 中为每个节点创建数据结构,但我不知道我必须考虑哪些节点数?126 还是 164?例如在 pic1 中,我可以说关于 node10 的所有信息(伪成本的值)都属于 pic3 中的 node10 吗?在 pic3 中,关于 node10 的所有信息(slacks 的值)都属于 pic1 中的 node10?

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;
}
}
}

在此处输入图像描述 在此处输入图像描述

标签: visual-c++cplex

解决方案


你同时问很多事情。我将回答与主题相关的问题。对于其他一切,请创建一个新问题并显示您的代码、您的实际输出并解释它与预期输出的不同之处。

IloCplex 类有一个函数out()。该函数返回对 CPLEX 将其所有输出发送到的流的引用。您可以将该引用传递给您的回调,然后从您的回调中写入该流。

例如:

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

接着

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

创建和注册回调。

更新编辑问题后,您的问题似乎不是从回调中打印输出,而是其他内容。

首先请注意,如果您使用用户剪切回调执行一次运行,而使用分支回调执行另一次运行,则预计会获得不同的搜索路径。无法将节点编号或节点 ID 从一次运行关联到另一次运行。您想要获得的统计数据必须通过一次运行获得。

此外,为了识别节点,您不应使用节点号或处理的节点数(日志最左侧列中的数字)。相反,您应该使用节点的 ID。这就是C++ API 中的序列号。这是唯一可以用来识别节点的东西。这些 id 应该与日志最右侧显示的节点 id 匹配,以防动态搜索被禁用(如果您使用控制回调,则会自动发生)。这些节点 ID 可从所有回调中获得,您可以使用它们收集从同一节点的不同回调中收集的信息。

更新2:实际上,我错了。返回的数字和日志一栏getNodeId()显示的数字不一样,请看我对这个问题的回答。没有办法将这两个数字联系起来。对困惑感到抱歉。我想你在另一个论坛上也问过类似的问题,我声称这两个数字是相同的。那也是错误的。再次抱歉。NodeID

因此,基本上,将回调中的事物与日志中的事物相关联的唯一选择是执行单线程运行,然后查看事物的打印顺序。

但是,为了跟踪树(以及伪成本等),您不需要日志。只需使用序列号,您就可以从回调中完成所有操作。最困难的部分是跟踪可以像这样完成的父/子关系(并不是说这不是线程安全的):

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());
   }
}

推荐阅读