gurobi 一般使用 python 調用,官方的培訓會議及資料大部分也都基于 python。
由于最近上手了 c++,因此想試試 c++ 怎么調用 gurobi。但我發現,c++ 調用第三方庫比 python 或 java 要復雜不少。python 中直接 import 第三方庫,java 加載第三方庫的 jar 之后也能直接使用。但是對于 c++ 調用第三方庫,要有以下幾個步驟:
- 告訴 c++ 第三方庫與頭文件的地址
- 必須讓 c++ 去鏈接第三方庫(link library)
python 或 java 只需第一步或者更簡單,而 c++ 多了第二步。對于 c++,編譯和鏈接過程分為兩個獨立階段:編譯(compilation)和鏈接(linking),調用第三方庫時,僅僅通過 #include 包含頭文件是不夠的,必須在鏈接階段提供庫文件(.a、.dylib 等),以便將代碼與庫的實現連接起來。
- 頭文件(.h):
- 僅包含聲明(接口),如函數原型、類定義。
- 示例:gurobi_c++.h 定義了 GRBEnv 類的構造函數,但不實現。
- 庫文件(.a、.dylib 等):
- 包含實現(二進制代碼)。
- 示例:libgurobi_c++.a 包含 GRBEnv 的具體邏輯。
#include 只告訴編譯器“這些函數存在”,但鏈接器根據庫文件需要知道“這些函數在哪里”。
Mac 上用 c++ 還有更麻煩些,不能用 VS studio,只能用 CMake 了。但是 CMake 在 mac 上很多時候不能通過 findpackage 找到庫的地址,只能指定添加庫的地址。
下面是我在一個子文件夾的 cmakelist.txt 文件里的內容。
- 記得要在主文件夾下的 cmakelist.txt 中通過 addsubdirectory() 將當前子文件夾添加到主文件夾里
set(RUN_NAME LP) # 設置運行程序的名字# 創建可執行程序,需要運行的 cpp 文件放在這里
add_executable(${RUN_NAME}# gurobi_test.cppgurobi_examples/mip1_c++.cpp
)# 設置 Gurobi 路徑(根據你的安裝調整)
set(GUROBI_HOME "/Library/gurobi1201/macos_universal2") # gurobi 的安裝地址
set(GUROBI_INCLUDE_DIR "${GUROBI_HOME}/include") # 頭文件路徑
set(GUROBI_LIB_DIR "${GUROBI_HOME}/lib") # 庫文件路徑# 將路徑添加到搜索地址
include_directories(${GUROBI_LIB_DIR})
include_directories(${GUROBI_INCLUDE_DIR})# 鏈接 Gurobi 庫,這個靜態庫與動態庫都需要
target_link_libraries(${RUN_NAME}"${GUROBI_LIB_DIR}/libgurobi_c++.a" # .a 是靜態庫"${GUROBI_LIB_DIR}/libgurobi120.dylib" # .dylib 是動態庫
)
一個 gurobi 的 cpp 例子:
#include <iostream>
#include "gurobi_c++.h"int main() {try {// 創建 Gurobi 環境GRBEnv env = GRBEnv();env.set(GRB_IntParam_OutputFlag, 1); // 啟用輸出// 創建模型GRBModel model = GRBModel(env);model.set(GRB_StringAttr_ModelName, "Production_Optimization");// 添加決策變量GRBVar xA = model.addVar(0.0, GRB_INFINITY, 0.0, GRB_CONTINUOUS, "x_A"); // 產品 AGRBVar xB = model.addVar(0.0, GRB_INFINITY, 0.0, GRB_CONTINUOUS, "x_B"); // 產品 B// 設置目標函數:maximize 30x_A + 40x_BGRBLinExpr objective = 30.0 * xA + 40.0 * xB;model.setObjective(objective, GRB_MAXIMIZE);// 添加約束// 約束 1: x_A + 2x_B <= 100GRBLinExpr constr1 = xA + 2.0 * xB;model.addConstr(constr1 <= 100, "Resource1");// 約束 2: 3x_A + x_B <= 150GRBLinExpr constr2 = 3.0 * xA + xB;model.addConstr(constr2 <= 150, "Resource2");// 優化模型model.optimize();// 檢查優化狀態int status = model.get(GRB_IntAttr_Status);if (status == GRB_OPTIMAL) {std::cout << "Optimal solution found:\n";std::cout << "x_A = " << xA.get(GRB_DoubleAttr_X) << "\n";std::cout << "x_B = " << xB.get(GRB_DoubleAttr_X) << "\n";std::cout << "Objective value = " << model.get(GRB_DoubleAttr_ObjVal) << "\n";} else {std::cout << "No optimal solution found. Status = " << status << "\n";}} catch (GRBException e) {std::cout << "Gurobi error code = " << e.getErrorCode() << "\n";std::cout << e.getMessage() << "\n";} catch (...) {std::cout << "Unknown error during optimization\n";}return 0;
}
}
運行結果:
Optimal objective 2.400000000e+03
Optimal solution found:
x_A = 40
x_B = 30
Objective value = 2400