手动安装Gurobi并配置gurobipy到Python环境(Windows/Conda)
手动安装Gurobi并配置gurobipy到Python环境(Windows/Conda)
1. 问题背景
Gurobi商用时需要gurobipy与本地Gurobi安装包版本匹配,并且正确读取许可证文件。很多同学卡在"安装包已经有了,pip也装了,import就是报错"这一步。
本文记录完整的排查和配置流程,环境:Windows 11 + Anaconda Python 3.12 + Gurobi 13.0。
2. 确认Gurobi安装包状态
Gurobi的Windows安装包默认路径在 C:\gurobi<版本号>\win64\。
# PowerShell 或 Git Bash 下执行
ls C:\gurobi1300\win64\bin\
# 关键文件检查清单:
# ✅ gurobi_cl.exe — 命令行求解器
# ✅ gurobi.lic — 许可证文件
# ✅ grbgetkey.exe — 许可证获取工具
# ✅ gurobi130.dll — 动态链接库(后续Python调用依赖)
许可证文件(gurobi.lic)内容长这样:
TYPE=NODE
VERSION=13
HOSTNAME=你的机器名
HOSTID=你的MAC地址
EXPIRATION=2027-11-29
KEY=XXXXXX
如果你是学术用户,从学校或Gurobi官网申请license后,用grbgetkey.exe下载。如果是企业用户,直接拿到gurobi.lic放到bin/下即可。
3. Python环境匹配是核心坑
3.1 先搞清楚你用哪个Python
# 查看当前Python路径和版本
python --version # 例如 Python 3.12.7
python -c "import sys; print(sys.executable)"
# 输出: D:\anaconda3\python.exe
gurobipy的wheel包是与 Python主版本号严格绑定的:
cp311→ Python 3.11cp312→ Python 3.12
如果你用错pip(比如系统Python装到了Conda Python的环境里),会报ModuleNotFoundError: No module named 'gurobipy'。
3.2 用正确的pip安装
# 关键:用 python -m pip,确保pip和Python是同一个环境
python -m pip install gurobipy
pip会自动根据当前Python版本拉取匹配的wheel:
Downloading .../gurobipy-13.0.1-cp312-cp312-win_amd64.whl (11.2 MB)
↑ ↑
版本号 cp312 = Python 3.12, win_amd64 = Windows 64位
3.3 常见报错与排查
| 报错 | 原因 | 解决 |
|---|---|---|
ModuleNotFoundError: No module named 'gurobipy' | pip装到了另一个Python环境 | python -m pip install gurobipy |
ImportError: DLL load failed | gurobi130.dll不在PATH中 | 把C:\gurobi1300\win64\bin加到系统PATH |
No Gurobi license found | 许可证文件找不到 | 检查gurobi.lic是否在bin/下,或设环境变量GRB_LICENSE_FILE |
4. 验证安装
写一个完整的测试脚本,一次性验证:导入 → 许可证 → 建模 → 求解 → 获取结果。
import gurobipy as gp
def test_gurobi():
"""最小模型验证Gurobi全链路是否正常。"""
print("gurobipy version:", gp.__version__)
# 创建模型
m = gp.Model("test")
# 添加变量:x是binary决策变量,y是连续变量
x = m.addVar(vtype=gp.GRB.BINARY, name="x")
y = m.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="y")
# 添加约束:x + y <= 10
m.addConstr(x + y <= 10, "c0")
# 设置目标:最大化 y
m.setObjective(y, gp.GRB.MAXIMIZE)
# 求解(OutputFlag=1显示日志,=0静默)
m.setParam("OutputFlag", 1)
m.optimize()
# 检查结果
if m.Status == gp.GRB.OPTIMAL:
print(f"Status: OPTIMAL")
print(f"x = {x.X}") # 预期 0.0
print(f"y = {y.X}") # 预期 10.0
print(f"Obj = {m.ObjVal}") # 预期 10.0
return True
else:
print(f"FAILED. Status: {m.Status}")
return False
if __name__ == "__main__":
success = test_gurobi()
print("\n✅ 环境正常" if success else "\n❌ 环境异常,排查上述报错")
预期输出(截取关键行):
gurobipy version: 13.0.1
Restricted license - for non-production use only - expires 2027-11-29
Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (win64 - Windows 11+.0)
Thread count: 14 physical cores, 20 logical processors, using up to 20 threads
Optimal solution found (tolerance 1.00e-04)
x = 0.0
y = 10.0
Obj = 10.0
✅ 环境正常
如果能跑到这一步,说明 Python绑定、DLL链接、许可证校验、求解器内核 全部正常。
5. 环境变量配置(可选但推荐)
如果不想每次打开终端都检查DLL路径,建议把Gurobi路径加入系统环境变量。
# 管理员PowerShell下执行
[Environment]::SetEnvironmentVariable(
"GRB_LICENSE_FILE",
"C:\gurobi1300\win64\bin\gurobi.lic",
"User"
)
或在 系统属性 → 环境变量 → Path 中添加:C:\gurobi1300\win64\bin。
6. 许可证文件管理与替换
许可证是 Gurobi 使用中更换频率最高的部分——学术许可证每年续期、换电脑后 HOSTID 变化、商业许可证升级等场景都需要替换。本节覆盖完整的替换流程。
6.1 什么时候需要替换许可证
| 场景 | 现象 | 需要做什么 |
|---|---|---|
| 许可证过期 | 报错 License expired | 续期并下载新 .lic |
| 换了电脑/重装系统 | 报错 Host ID mismatch | 重新申请绑定新机器的 .lic |
| MAC 地址变更 | 同上(HOSTID 绑定 MAC) | 同上 |
| 升级 Gurobi 大版本 | 报错 License version mismatch | 申请匹配新版本的 .lic |
| 从 WLS 切换到本地许可证 | 规模受限(变量数上限 2000) | 获取本地 .lic 文件 |
6.2 学术许可证申请(免费)
Gurobi 对学术用户提供免费许可证,但需要 .edu 邮箱注册。
步骤 1:注册 Gurobi 账号
访问 https://www.gurobi.com/academia/academic-program-and-registrations/ ,用学校邮箱注册。
步骤 2:生成许可证密钥
登录后进入 https://portal.gurobi.com/iam/licenses/ ,点击 “Generate License”。
选择许可证类型:
- Named-User Academic — 绑定单台机器(最常用)
- Floating Academic — 浮动许可证(需学校服务器,一般不需要)
点击后会得到一个形如 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 的密钥。
步骤 3:下载许可证文件
方法 A:用 grbgetkey(推荐)
# 在 PowerShell 中执行,替换为你的密钥
C:\gurobi1300\win64\bin\grbgetkey.exe xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
执行过程:
info : grbgetkey version 13.0.1
info : Contacting Gurobi license server...
info : License 1234567 for user yourname@university.edu
info : License type: NAMED-COMPUTER
info : Host ID detected: aabbccddeeff
Where should we store the license file?
Press enter to accept the default path (C:\gurobi1300\win64\bin\gurobi.lic)
>
按 Enter 即可,默认存到 bin\ 下。
方法 B:手动下载
在 Gurobi Portal 页面直接点击 “Download License File”,下载 gurobi.lic 文件,然后手动复制到 C:\gurobi1300\win64\bin\。
6.3 替换许可证文件(核心操作)
替换本质上就是覆盖旧的 gurobi.lic 文件。
# Step 1: 备份旧许可证(可选但推荐)
copy C:\gurobi1300\win64\bin\gurobi.lic C:\gurobi1300\win64\bin\gurobi.lic.bak
# Step 2: 用 grbgetkey 下载新许可证(会自动覆盖)
C:\gurobi1300\win64\bin\grbgetkey.exe 你的新密钥
# 或者:手动复制下载的 gurobi.lic 到 bin 目录
copy Downloads\gurobi.lic C:\gurobi1300\win64\bin\gurobi.lic
Step 3: 验证新许可证
# 用命令行工具检查
C:\gurobi1300\win64\bin\gurobi_cl.exe --license
预期输出:
Gurobi license valid
License type : NAMED-COMPUTER
Expiration date : 2027-11-29
...
再用 Python 验证:
import gurobipy as gp
m = gp.Model("test")
m.setParam("OutputFlag", 0)
x = m.addVar()
m.setObjective(x)
m.optimize()
print(f"License OK, Gurobi {gp.gurobi.version()}")
6.4 许可证文件存放位置优先级
Gurobi 按以下顺序查找许可证文件:
| 优先级 | 查找位置 | 说明 |
|---|---|---|
| 1 | 环境变量 GRB_LICENSE_FILE 指定的路径 | 绝对路径,最高优先 |
| 2 | %HOME%\gurobi.lic | 用户主目录下 |
| 3 | C:\gurobi<ver>\win64\bin\gurobi.lic | 安装目录下(默认) |
| 4 | %GRB_LICENSE_FILE% 目录下的 gurobi.lic | 如果环境变量指向目录而非文件 |
常见坑:如果 GRB_LICENSE_FILE 环境变量指向旧路径,即使你替换了 bin\ 下的 .lic,Gurobi 仍然读旧的。替换后一定要检查:
# 检查环境变量指向哪里
echo %GRB_LICENSE_FILE%
如果有值但路径不对,更新它:
[Environment]::SetEnvironmentVariable(
"GRB_LICENSE_FILE",
"C:\gurobi1300\win64\bin\gurobi.lic",
"User"
)
6.5 许可证类型与规模限制
| 许可证类型 | 来源 | 变量数限制 | 说明 |
|---|---|---|---|
| WLS(Web License Service) | pip install gurobipy 自带 | 2000 变量, 2000 约束 | 在线验证,有规模限制 |
| Named-User Academic | Gurobi Portal 申请 | 无限制 | 本地文件,免费 |
| Named-User Commercial | 购买 | 无限制 | 本地文件,付费 |
| Floating | 服务器部署 | 无限制 | 需 Token Server |
关键区别:pip install gurobipy 不带本地许可证时会自动使用 WLS,这就是为什么 C++ 能跑大规模但 Python 不行的原因。解决方法就是配置本地 .lic 文件(按上面步骤操作)。
7. gurobipy API 速查:从建模到求解的完整流程
7.1 建模五步法
所有 Gurobi 模型都遵循同一个流程:
创建模型 → 添加变量 → 添加约束 → 设置目标 → 求解
import gurobipy as gp
from gurobipy import GRB
# Step 1: 创建模型
m = gp.Model("my_model")
# Step 2: 添加变量
x = m.addVar(lb=0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="x")
y = m.addVar(lb=0, vtype=GRB.INTEGER, name="y")
z = m.addVar(vtype=GRB.BINARY, name="z")
# Step 3: 添加约束
m.addConstr(2*x + y <= 10, "c0")
m.addConstr(x + 3*y >= 4, "c1")
m.addConstr(z == 1, "c2") # 固定 z=1
# Step 4: 设置目标
m.setObjective(x + y, GRB.MAXIMIZE)
# Step 5: 求解
m.optimize()
7.2 变量类型速查
| 类型 | vtype 参数 | 域 | 典型用途 |
|---|---|---|---|
| 连续变量 | GRB.CONTINUOUS(默认) | [lb, ub] | 速度、角度、质量 |
| 整数变量 | GRB.INTEGER | [lb, ub] ∩ ℤ | 数量、人数 |
| 二值变量 | GRB.BINARY | {0, 1} | 选择/不选择、开关 |
| 半连续变量 | GRB.SEMICONT | {0} ∪ [lb, ub] | 产量为 0 或 ≥ 最低批量 |
| 半整数变量 | GRB.SEMIINT | {0} ∪ [lb, ub] ∩ ℤ | 订货量为 0 或 ≥ 最低整数 |
批量添加变量(推荐,性能更好):
# 方法 1:addVars — 创建一组索引变量
x = m.addVars(5, lb=0, vtype=GRB.CONTINUOUS, name="x")
# 访问:x[0], x[1], ..., x[4]
# 方法 2:用列表推导 + tuplelist 索引
pairs = [(i, j) for i in range(3) for j in range(3) if i != j]
x = m.addVars(pairs, vtype=GRB.BINARY, name="x")
# 访问:x[0,1], x[0,2], x[1,0], ...
# 方法 3:字典推导(完全自定义)
indices = {"alpha": 0, "beta": 1, "gamma": 2}
y = m.addVars(indices, lb=0, ub=10, name="y")
# 访问:y["alpha"], y["beta"], y["gamma"]
7.3 约束写法大全
线性约束:
# 单个约束
m.addConstr(2*x + 3*y <= 100, "capacity")
# 批量约束(用 addConstrs + 生成器表达式)
m.addConstrs((x[i] + x[j] <= 1 for i in range(5) for j in range(i+1, 5)),
name="conflict")
# 范围约束(lhs ≤ expr ≤ rhs)
m.addRangeConstr(x + y, 5, 15, "range_c") # 5 ≤ x+y ≤ 15
# 等式约束
m.addConstr(x + y == 10, "eq_c")
指示约束(Indicator Constraint):
二值变量控制约束是否生效——替代 Big-M 的优雅写法:
# 如果 z=1,则 x + y ≤ 10 必须满足
# 如果 z=0,则该约束被忽略
m.addConstr((z == 1) >> (x + y <= 10), "indicator_c")
SOS 约束(Special Ordered Set):
# SOS-1: 一组变量中最多 1 个非零
vars_sos = m.addVars(5, lb=0, name="sos_var")
m.addSOS(GRB.SOS_TYPE1, [vars_sos[i] for i in range(5)])
# SOS-2: 一组变量中最多 2 个相邻变量非零(分段线性近似用)
m.addSOS(GRB.SOS_TYPE2, [vars_sos[i] for i in range(5)])
通用约束(General Constraint):
# 逻辑与:z = and(x, y)
z_and = m.addVar(vtype=GRB.BINARY)
m.addConstr(z_and == gp.and_(x, y))
# 逻辑或:z = or(x, y)
z_or = m.addVar(vtype=GRB.BINARY)
m.addConstr(z_or == gp.or_(x, y))
# 最大值:z = max(x, y)
z_max = m.addVar()
m.addGenConstrMax(z_max, [x, y], name="max_c")
# 最小值:z = min(x, y)
z_min = m.addVar()
m.addGenConstrMin(z_min, [x, y], name="min_c")
# 绝对值:z = |x|
z_abs = m.addVar()
m.addGenConstrAbs(z_abs, x, name="abs_c")
# 非线性函数近似:y = f(x),用分段线性表示
import math
pts = [(i, math.sin(i)) for i in [0, 1, 2, 3]]
m.addGenConstrPWL(x, y, [p[0] for p in pts], [p[1] for p in pts])
7.4 目标函数
线性目标:
m.setObjective(3*x + 2*y, GRB.MAXIMIZE)
m.setObjective(gp.quicksum(w[i]*x[i] for i in range(N)), GRB.MINIMIZE)
二次目标(QP/QCQP):
# min x^2 + y^2
m.setObjective(x*x + y*y, GRB.MINIMIZE)
多目标优化:
# 先最大化目标 1,再最小化目标 2(分层优化)
m.setObjectiveN(x, index=0, priority=2, weight=1.0, name="obj1")
m.setObjectiveN(y, index=1, priority=1, weight=1.0, name="obj2")
# priority 越大越先优化
7.5 求解与结果获取
基本求解:
m.optimize()
求解状态判断:
if m.Status == GRB.OPTIMAL:
print("找到最优解")
elif m.Status == GRB.INFEASIBLE:
print("无可行解")
m.computeIIS() # 计算不可行子系统,找出冲突约束
m.write("model.ilp")
elif m.Status == GRB.TIME_LIMIT:
print("达到时间限制")
if m.SolCount > 0:
print(f"当前最优解: {m.ObjVal}") # 仍有可行解
elif m.Status == GRB.UNBOUNDED:
print("模型无界")
获取变量值:
# 单个变量
val_x = x.X # 变量值
val_rc = x.RC # Reduced cost
val_lb = x.lb # 下界
val_ub = x.ub # 上界
# 批量获取
x_vals = m.getAttr("X", [x[i] for i in range(5)])
# 或
x_vals = {i: x[i].X for i in range(5)}
# 模型级信息
obj_val = m.ObjVal # 目标函数值
gap = m.MIPGap # MIP gap
runtime = m.Runtime # 求解时间(秒)
node_count = m.NodeCount # 分支定界节点数
获取对偶信息(仅 LP):
# 约束的对偶值(影子价格)
constr = m.getConstrByName("c0")
pi = constr.Pi # 对偶变量值
# 对偶值的经济含义:约束 RHS 增加 1 单位,目标函数变化 Pi 单位
7.6 常用参数设置
# 时间限制(秒)
m.setParam("TimeLimit", 3600)
# MIP Gap 容差(默认 1e-4)
m.setParam("MIPGap", 1e-6)
# 线性规划算法
m.setParam("Method", 2) # 0=primal simplex, 1=dual simplex, 2=barrier, 3=concurrent
# 线程数
m.setParam("Threads", 8)
# 输出控制
m.setParam("OutputFlag", 0) # 0=静默, 1=显示求解日志
m.setParam("LogFile", "solve.log")
# 求解精度
m.setParam("FeasibilityTol", 1e-6)
m.setParam("OptimalityTol", 1e-6)
m.setParam("IntFeasTol", 1e-5)
# 启发式搜索强度(MIP)
m.setParam("Heuristics", 0.5) # 0~1,越大花越多时间在启发式
# 内存限制(GB)
m.setParam("MemLimit", 16)
参数也可以全局设置(影响所有后续创建的模型):
gp.setParam("OutputFlag", 0) # 全局静默
7.7 模型 I/O
# 保存模型
m.write("model.lp") # LP 格式(可读)
m.write("model.mps") # MPS 格式(标准,跨求解器通用)
m.write("model.mst") # MIP start 文件
m.write("model.sol") # 解文件
m.write("model.bas") # 基变量文件(LP)
# 读取模型
m = gp.read("model.mps")
m.optimize()
# 读取初始解(加速 MIP 求解)
m.read("initial_solution.mst")
7.8 完整示例:生产调度
一个综合示例,覆盖建模 → 求解 → 输出 → 保存全流程:
import gurobipy as gp
from gurobipy import GRB
def production_scheduling():
"""
工厂生产调度问题:
- 3 种产品,2 条产线
- 每条产线有产能上限(小时)
- 求最大利润的生产方案
"""
products = ["A", "B", "C"]
lines = ["L1", "L2"]
# 利润(元/件)
profit = {"A": 100, "B": 150, "C": 200}
# 各产品在各产线的工时(小时/件)
time_req = {
("A", "L1"): 2.0, ("A", "L2"): 2.5,
("B", "L1"): 1.5, ("B", "L2"): 1.0,
("C", "L1"): 3.0, ("C", "L2"): 2.0,
}
# 产线可用工时
capacity = {"L1": 120, "L2": 100}
# 产品最大需求
demand = {"A": 50, "B": 80, "C": 40}
m = gp.Model("production")
m.setParam("OutputFlag", 0)
# x[p, l] = 产品 p 在产线 l 上的产量
x = m.addVars(products, lines, lb=0, vtype=GRB.INTEGER, name="x")
# 是否生产产品 p(二值变量,用于指示约束)
z = m.addVars(products, vtype=GRB.BINARY, name="z")
# 约束 1:产线产能
for l in lines:
m.addConstr(
gp.quicksum(time_req[p, l] * x[p, l] for p in products) <= capacity[l],
name=f"cap_{l}"
)
# 约束 2:总产量 ≤ 需求
for p in products:
m.addConstr(
gp.quicksum(x[p, l] for l in lines) <= demand[p],
name=f"demand_{p}"
)
# 约束 3:如果 z[p]=0,则产品 p 产量为 0(指示约束)
for p in products:
m.addConstr(
gp.quicksum(x[p, l] for l in lines) <= demand[p] * z[p],
name=f"link_{p}"
)
# 目标:最大化利润
m.setObjective(
gp.quicksum(profit[p] * x[p, l] for p in products for l in lines),
GRB.MAXIMIZE
)
# 求解
m.optimize()
# 输出结果
if m.Status == GRB.OPTIMAL:
print(f"最优利润: {m.ObjVal:.0f} 元")
print(f"求解时间: {m.Runtime:.3f} 秒\n")
print("生产方案:")
for p in products:
total = sum(int(x[p, l].X) for l in lines)
if total > 0:
detail = ", ".join(f"{l}={int(x[p,l].X)}" for l in lines)
print(f" 产品 {p}: 共 {total} 件 ({detail})")
else:
print(f" 产品 {p}: 不生产")
print(f"\n产线利用率:")
for l in lines:
used = sum(time_req[p, l] * x[p, l].X for p in products)
print(f" {l}: {used:.1f}/{capacity[l]} 小时 ({used/capacity[l]*100:.1f}%)")
# 保存模型和解
m.write("production.lp")
m.write("production.sol")
else:
print(f"求解失败,状态码: {m.Status}")
if __name__ == "__main__":
production_scheduling()
预期输出:
最优利润: 26000 元
求解时间: 0.005 秒
生产方案:
产品 A: 共 50 件 (L1=50, L2=0)
产品 B: 共 80 件 (L1=0, L2=80)
产品 C: 共 40 件 (L1=0, L2=40)
产线利用率:
L1: 100.0/120 小时 (83.3%)
L2: 100.0/100 小时 (100.0%)
8. 进阶:在MILP模型中使用gurobipy
以下是一个实用的论文实验模板——敏捷卫星观测调度MILP(对应球面Dubins论文Section 6.2):
import numpy as np
import gurobipy as gp
def build_transition_cost_matrix(
Q_list: list[np.ndarray], # N个姿态的Sabban帧 ∈ SO(3)
dubins_solver, # 你的球面Dubins闭式求解器
omega_max: float, # 卫星最大角速度 [rad/s]
) -> np.ndarray:
"""
用球面Dubins求解器预计算精确转移时间矩阵 T_ij。
T_ij 的每一行对应目标 i, 列对应目标 j.
"""
N = len(Q_list)
T = np.zeros((N, N))
for i in range(N):
for j in range(N):
if i != j:
result = dubins_solver.solve(Q_list[i], Q_list[j])
T[i, j] = result.optimal_solution.total_angle / omega_max
return T
def schedule_milp(
N: int,
T: np.ndarray,
durations: list[float],
time_windows: list[tuple[float, float]],
weights: list[float],
) -> dict:
"""
敏捷卫星多目标观测调度MILP (最大化观测总价值).
Parameters
----------
N : 目标数量
T : (N,N) 转移时间矩阵
durations : 每个目标的成像时长
time_windows : 每个目标的观测时间窗 [(e_i, l_i), ...]
weights : 每个目标的优先级权重
Returns
-------
dict with keys: status, selected, sequence, start_times, total_value
"""
m = gp.Model("agile_satellite_scheduling")
m.setParam("OutputFlag", 0) # 静默模式
# --- 决策变量 ---
x = {} # x[i,j] = 1 表示目标i观察后立即转向目标j
y = {} # y[i] = 1 表示目标i被选中观察
t = {} # t[i] = 目标i的观测开始时刻
M = 600.0 # big-M (LEO单次过顶约10分钟)
for i in range(N):
y[i] = m.addVar(vtype=gp.GRB.BINARY, name=f"y_{i}")
t[i] = m.addVar(lb=0, name=f"t_{i}")
for j in range(N):
if i != j:
x[i, j] = m.addVar(vtype=gp.GRB.BINARY, name=f"x_{i}_{j}")
# --- 流守恒约束 ---
for i in range(N):
m.addConstr(
gp.quicksum(x[i, j] for j in range(N) if j != i) == y[i],
name=f"flow_out_{i}"
)
m.addConstr(
gp.quicksum(x[j, i] for j in range(N) if j != i) == y[i],
name=f"flow_in_{i}"
)
# --- 序列时间约束 ---
for i in range(N):
for j in range(N):
if i != j:
m.addConstr(
t[j] >= t[i] + durations[i] + T[i, j] - M * (1 - x[i, j]),
name=f"seq_{i}_{j}"
)
# --- 时间窗约束 ---
for i in range(N):
e_i, l_i = time_windows[i]
m.addConstr(t[i] >= e_i, name=f"tw_lb_{i}")
m.addConstr(t[i] <= l_i - durations[i], name=f"tw_ub_{i}")
# --- 目标:最大化总价值 ---
m.setObjective(
gp.quicksum(weights[i] * y[i] for i in range(N)),
gp.GRB.MAXIMIZE
)
m.optimize()
# --- 结果解析 ---
if m.Status != gp.GRB.OPTIMAL:
return {"status": "INFEASIBLE", "selected": [], "total_value": 0.0}
selected = [i for i in range(N) if y[i].X > 0.5]
return {
"status": "OPTIMAL",
"selected": selected,
"start_times": {i: t[i].X for i in selected},
"total_value": m.ObjVal,
"solve_time": m.Runtime,
}
9. 快速故障排查清单
| 症状 | 排查命令 | 解决 |
|---|---|---|
gurobipy 导入失败 | python -c "import gurobipy" | 检查python -m pip list | grep gurobi |
| DLL载入失败 | python -c "import ctypes; ctypes.CDLL('gurobi130.dll')" | 将C:\gurobi1300\win64\bin加入PATH |
| 许可证无效 | python -c "import gurobipy as gp; gp.Model()" | 检查gurobi.lic路径和过期时间 |
| 版本不匹配 | python -m pip show gurobipy | pip install 时确认 cp312 与 Python 3.12 匹配 |
核心原则就一句话:python -m pip install gurobipy 保证装到当前环境,gurobi.lic 在 bin/ 下,万事大吉。 其余报错 90% 是 pip 装错了 Python 环境导致的。
更多推荐



所有评论(0)