You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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松弛目标值:

  1. 根节点松弛值:第一个CB_MIPNODE事件触发时,当节点松弛求解完成(状态为GRB_OPTIMAL),用getDoubleInfo(GRB_DBLINFO_MIPNODE_OBJ)获取。
  2. 分支节点松弛值:后续每个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 07:05:28