Gurobi C++回调获取MILP节点数及LP松弛值问题咨询
在C++中通过Gurobi回调准确获取节点数与LP松弛目标值
一、解决节点数统计不准确的问题
自定义NodeCounter回调计数不准,大多是因为手动计数逻辑覆盖不全(比如漏掉剪枝节点、跳过的节点,或是重复计数)。直接用Gurobi内置的信息接口获取是最可靠的方式:
在回调类的callback方法中,当事件类型为CB_MIPNODE时,通过getIntInfo(GRB_INTINFO_NODECOUNT)即可拿到当前已处理的节点总数。如果只需要最终总节点数,也可以在求解结束后直接调用model.getIntInfo(GRB_INTINFO_NODECOUNT)获取,无需依赖回调计数。
示例回调类片段:
class NodeInfoCallback : public GRBCallback { protected: void callback() { try { if (where == GRB_CB_MIPNODE) { // 获取当前已处理节点数 long long nodeCount = getIntInfo(GRB_INTINFO_NODECOUNT); std::cout << "已处理节点数: " << nodeCount << std::endl; } else if (where == GRB_CB_MIPSOL) { // 找到可行解时同步节点数 long long nodeCount = getIntInfo(GRB_INTINFO_NODECOUNT); } } catch (GRBException e) { std::cout << "回调异常: " << e.getMessage() << std::endl; } catch (...) { std::cout << "未知回调异常" << std::endl; } } };
启用回调的代码:
NodeInfoCallback cb; model.setCallback(&cb); model.optimize(); // 求解结束后直接获取总节点数 long long totalNodes = model.getIntInfo(GRB_INTINFO_NODECOUNT); std::cout << "总节点数: " << totalNodes << std::endl;
二、通过回调获取LP松弛目标值(无需重复求解)
不需要调用Model.relax()重新求解,在MILP求解的回调中就能直接拿到根节点及各分支节点的LP松弛目标值:
- 根节点松弛值:第一个
CB_MIPNODE事件触发时,当节点松弛求解完成(状态为GRB_OPTIMAL),用getDoubleInfo(GRB_DBLINFO_MIPNODE_OBJ)获取。 - 分支节点松弛值:后续每个
CB_MIPNODE事件中,都可以用同样的接口获取对应节点的松弛目标。
修改回调类加入松弛值获取逻辑:
class MIPInfoCallback : public GRBCallback { private: double rootRelaxObj; bool rootCaptured = false; public: MIPInfoCallback() : rootRelaxObj(0.0) {} double getRootRelaxObj() const { return rootRelaxObj; } protected: void callback() { try { if (where == GRB_CB_MIPNODE) { int nodeStatus = getIntInfo(GRB_INTINFO_MIPNODE_STATUS); if (nodeStatus == GRB_OPTIMAL) { double currentRelaxObj = getDoubleInfo(GRB_DBLINFO_MIPNODE_OBJ); // 捕获根节点松弛值 if (!rootCaptured) { rootRelaxObj = currentRelaxObj; rootCaptured = true; std::cout << "根节点LP松弛目标值: " << rootRelaxObj << std::endl; } // 输出当前分支节点的松弛值 long long nodeCount = getIntInfo(GRB_INTINFO_NODECOUNT); std::cout << "节点 " << nodeCount << " 的LP松弛目标值: " << currentRelaxObj << std::endl; } } } catch (GRBException e) { std::cout << "回调异常: " << e.getMessage() << std::endl; } catch (...) { std::cout << "未知回调异常" << std::endl; } } };
使用方式:
MIPInfoCallback cb; model.setCallback(&cb); model.optimize(); // 求解结束后获取根节点松弛值 double rootObj = cb.getRootRelaxObj(); std::cout << "最终根节点LP松弛值: " << rootObj << std::endl;
注意事项
- 确保模型参数没有禁用MIP节点回调,比如
GRB_IntParam_MIPFocus等参数不会影响回调触发。 - 如果仅需根节点松弛值,也可以在求解前调用
model.relax().optimize(),但回调方式无需重复构建模型,效率更高。
内容的提问来源于stack exchange,提问作者Farah Mind
相关产品推荐
相关产品推荐

