当前位置: 首页 > news >正文

使用 Google OR-Tools 轻松解决复杂优化问题(如排程优化)

之前有一篇Pyomo、PuLP 和 OR-Tools 解决约束优化问题效率对比,对比了几个同样的优化的python库。本篇文章Solve Complex Optimization Problems (like Schedule Optimization) with easy to use Google OR Tools适合对优化问题感兴趣的读者,特别是初学者。文章的亮点在于介绍了Google OR-Tools作为一个强大的开源工具,能够高效解决复杂的优化问题,如调度和路线规划。它通过简洁的Python代码示例,使读者能够快速上手。


文章目录

  • 1 什么是 Google OR-Tools?
    • 1.1 OR-Tools 可以解决的示例问题:
    • 1.2 什么是优化问题?
    • 1.2 OR-Tools 解决的问题类型
  • 2 实践:在 Python 中解决线性优化问题
    • 步骤 1:安装 OR-Tools
    • 步骤 2:Python 代码
    • 步骤 3:运行
  • 3 为什么在数据科学中使用 OR-Tools?
    • 3.1 主要收获
    • 3.2 完整代码示例:使用 OR-Tools 解决护士排班问题
      • 3.2.1 步骤 1:导入所需库
      • 3.2.2 步骤 2:定义问题数据
      • 3.2.3 步骤 3:创建模型和变量
      • 3.2.4 步骤 4:添加约束
      • 3.2.5 步骤 5:创建解决方案打印回调
      • 3.2.6 步骤 6:求解并打印解决方案
      • 3.2.7 示例输出


有些问题并非关乎预测未来,而是要在数量惊人的选项中找到最佳决策。这正是优化的用武之地。如果你在 Python 中进行开发,Google OR-Tools 是你可以使用的最强大的开源工具包之一。

从优化送货卡车路线到安排生产线上的机器,OR-Tools 将最先进的算法带到你的指尖。我们将探讨:

  • OR-Tools 是什么以及它为何有用
  • 它能解决的常见优化问题类型
  • 一个关于线性规划的 Python 实践示例

1 什么是 Google OR-Tools?

OR-Tools 是由 Google 开发的一套开源组合优化套件。它有助于解决那些可能解的数量极其庞大——远超暴力搜索范围的问题。OR-Tools 转而使用高级求解器,高效地寻找最优接近最优的解。

1.1 OR-Tools 可以解决的示例问题:

  • 车辆路径规划:为车队规划最优配送路线,同时遵守重量限制和配送时间窗。
  • 排程:根据优先级和时间限制将任务分配给资源。
  • 箱子装载:将不同尺寸的物品高效地装入容量有限的容器中。
  • 图优化:最短路径、最大流和分配问题。

1.2 什么是优化问题?

优化问题总是包含:

  1. 目标函数 — 需要优化的量(最小化成本、最大化利润等)。
  2. 约束条件 — 对可能解的限制。
  3. 可行解 — 满足所有约束条件的解。

示例:
一家航运公司必须将包裹分配给卡车并规划其路线,以最小化总成本。

  • 目标:最小化成本(燃料、时间等)。
  • 约束:卡车容量、交货期限。
  • 可行解:满足所有约束,但不一定是成本最低的。
  • 最优解:在所有可行解中成本最低的解。

1.2 OR-Tools 解决的问题类型

2 实践:在 Python 中解决线性优化问题

让我们通过一个使用 OR-Tools 的简单线性规划示例

问题:
最大化:
3x+y3x + y3x+y
受限于:
0≤x≤10 \le x \le 10x1
0≤y≤200 \le y \le 200y20
x+y≤2xx + y \le 2xx+y2x

步骤 1:安装 OR-Tools

pip install ortools

步骤 2:Python 代码

from ortools.init.python import init
from ortools.linear_solver import pywraplpdef main():print("Google OR-Tools version:", init.OrToolsVersion.version_string())solver = pywraplp.Solver.CreateSolver("GLOP")if not solver:print("Solver not created.")returnx = solver.NumVar(0, 1, "x")y = solver.NumVar(0, 2, "y")print("Number of variables =", solver.NumVariables())infinity = solver.infinity()constraint = solver.Constraint(-infinity, 2, "ct")constraint.SetCoefficient(x, 1)constraint.SetCoefficient(y, 1)print("Number of constraints =", solver.NumConstraints())objective = solver.Objective()objective.SetCoefficient(x, 3)objective.SetCoefficient(y, 1)objective.SetMaximization()result_status = solver.Solve()if result_status != pywraplp.Solver.OPTIMAL:print("No optimal solution found.")returnprint("Solution:")print("Objective value =", objective.Value())print("x =", x.solution_value())print("y =", y.solution_value())print(f"Solved in {solver.wall_time()} ms")
if __name__ == "__main__":main()

步骤 3:运行

python program.py

输出:

Solution:
Objective value = 4.0
x = 1.0
y = 1.0

3 为什么在数据科学中使用 OR-Tools?

  • 速度:针对巨大搜索空间的高效算法。
  • 灵活性:支持线性规划、整数规划、约束编程等。
  • 实战就绪:在 Google 规模的路由和排程问题中得到应用。

3.1 主要收获

  • 优化 ≠ 预测 — 它是在给定约束条件下做出最佳决策。
  • Google OR-Tools 可以解决各种优化问题 — 从排程到路径规划再到装箱。
  • 从线性规划开始,然后探索更高级的求解器,如约束编程混合整数规划

3.2 完整代码示例:使用 OR-Tools 解决护士排班问题

排程问题无处不在——从将送货卡车分配到路线,到管理工厂中的机器作业。在这个例子中,我们将探讨一个受现实世界启发的医院护士排班问题

场景:
医院主管需要在3 天内安排4 名护士,并遵循以下规则:

  1. 每天三班(每班 8 小时)。
  2. 每班一名护士,并且每名护士每天工作不超过一班。
  3. 在三天内,每名护士至少工作两班

3.2.1 步骤 1:导入所需库

我们将使用 OR-Tools 的 cp_model 模块中的约束编程 (CP)

from ortools.sat.python import cp_model

3.2.2 步骤 2:定义问题数据

num_nurses = 4
num_shifts = 3
num_days = 3
all_nurses = range(num_nurses)
all_shifts = range(num_shifts)
all_days = range(num_days)

3.2.3 步骤 3:创建模型和变量

我们将创建布尔变量,其中:

如果护士 [n] 在第 [d] 天工作班次 [s],则 shifts[(n,d,s)]=1shifts[(n, d, s)] = 1shifts[(n,d,s)]=1

model = cp_model.CpModel()shifts = {}
for
````pythonn in all_nurses:for d in all_days:for s in all_shifts:shifts[(n, d, s)] = model.NewBoolVar(f"shift_n{n}_d{d}_s{s}")

3.2.4 步骤 4:添加约束

1. 每班次恰好有一名护士

for d in all_days:for s in all_shifts:model.AddExactlyOne(shifts[(n, d, s)] for n in all_nurses)

2. 每名护士每天工作不超过一班

for n in all_nurses:for d in all_days:model.AddAtMostOne(shifts[(n, d, s)] for s in all_shifts)

3. 每名护士总共至少工作两班

我们根据总需求计算每名护士的最小和最大班次:

min_shifts_per_nurse = (num_shifts * num_days) // num_nurses
max_shifts_per_nurse = (min_shifts_per_nurseif (num_shifts * num_days) % num_nurses == 0else min_shifts_per_nurse + 1
)for n in all_nurses:shifts_worked = [shifts[(n, d, s)] for d in all_days for s in all_shifts]model.Add(sum(shifts_worked) >= min_shifts_per_nurse)model.Add(sum(shifts_worked) <= max_shifts_per_nurse)

3.2.5 步骤 5:创建解决方案打印回调

这让我们能够检查多个有效的排班表:

class NursesPartialSolutionPrinter(cp_model.CpSolverSolutionCallback):def __init__(self, shifts, num_nurses, num_days, num_shifts, limit):cp_model.CpSolverSolutionCallback.__init__(self)self._shifts = shiftsself._num_nurses = num_nursesself._num_days = num_daysself._num_shifts = num_shiftsself._solution_count = 0self._solution_limit = limitdef on_solution_callback(self):self._solution_count += 1print(f"Solution {self._solution_count}")for d in range(self._num_days):print(f"Day {d}")for n in range(self._num_nurses):working = Falsefor s in range(self._num_shifts):if self.Value(self._shifts[(n, d, s)]):working = Trueprint(f"  Nurse {n} works shift {s}")if not working:print(f"  Nurse {n} does not work")print()if self._solution_count >= self._solution_limit:self.StopSearch()

3.2.6 步骤 6:求解并打印解决方案

solver = cp_model.CpSolver()
solver.parameters.enumerate_all_solutions = True
solution_printer = NursesPartialSolutionPrinter(shifts, num_nurses, num_days, num_shifts, limit=5)
solver.Solve(model, solution_printer)

3.2.7 示例输出

Solution 1
Day 0Nurse 0 does not workNurse 1 works shift 0Nurse 2 works shift 1Nurse 3 works shift 2
Day 1Nurse 0 works shift 2Nurse 1 does not workNurse 2 works shift 1Nurse 3 works shift 0
Day 2Nurse 0 works shift 2Nurse 1 works shift 1Nurse 2 works shift 0Nurse 3 does not work

这个例子展示了 OR-Tools 中的约束编程如何用几行代码建模和解决复杂的排程问题。与传统的暴力方法不同,OR-Tools 在遵守所有约束的同时高效地搜索可行解——这使其非常适合实际世界的排程、时间表和资源分配问题。

http://www.dtcms.com/a/362116.html

相关文章:

  • HarvardX TinyML小笔记2(番外3:数据工程)
  • Node.js版本管理工具 || 全配置安装
  • Claude AI 因编写勒索软件和开展勒索活动而被滥用
  • Agent落地元年:谁在成为最坚实的土壤?
  • 【前端】跨域
  • 懒加载详细讲解
  • 在Linux系统上第一次创建java项目并运行
  • `[特殊字符]LeetCode每日一题 1792. 最大平均通过率(打卡第一天)`
  • 在 React Native 层禁止 iOS 左滑返回(手势返回/手势退出)
  • Unity 串口通讯2 硬件SDK 开发[数据监听,按键监听]
  • 人工智能——课程考核
  • Python OpenCV图像处理与深度学习:Python OpenCV图像几何变换入门
  • 线程池发生了异常该怎么处理?
  • Groovy 的核心语法
  • 计算机视觉与深度学习 | 传统图像处理技术的未来发展前景分析
  • 算法练习——169.多数元素
  • 焦耳热技术助力顶刊研究:薄层质子交换膜实现高效水电解制氢
  • 深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)第八章知识点问答(18题)
  • 在工业质检中,机器视觉与人工检测的决策依据
  • Java类加载机制
  • 亚马逊云代理商:如何选择适合的AWS EC2实例类型?
  • ARM-SPI屏幕案例
  • 1. 叙述与命题
  • 【开题答辩全过程】以 基于JSP的养生网站设计与实现为例,包含答辩的问题和答案
  • 在JAVA中Mybatis的使用
  • GitHub每日最火火火项目(9.1)
  • TDengine 日期时间函数 DAYOFWEEK 使用手册
  • shell编程基础入门-3
  • 人工势场法(APF)路径规划 MATLAB
  • 战略进阶——解读92页培训_战略+概述与基本框架麦肯锡【附全文阅读】