cp-sat求解器介绍及使用案例

简介: cp-sat求解器介绍及使用案例更多文章欢迎关注我的微信公众号:Python学习杂记

ortools是Google开发的一套优化工具,其中ortools中自带的cp-sat是一个用于求解约束规划问题的求解器。本文介绍一下cp-sat的求解原理和基础应用。

cp-sat求解器介绍

cp-sat的原理是基于有限域上的布尔可满足性问题(SAT)和伪布尔优化(PBO)。它将约束规划问题转化为一个整数线性规划(ILP)问题,并使用启发式搜索和冲突分析等技术来寻找最优解或证明无解。

  • 它可以处理整数变量、布尔变量、线性约束、全局约束、指示器约束等。
  • 它可以处理多目标优化问题,并支持词典序或分层方法。
  • 它可以利用多核处理器并行计算,并提供超时和中断功能。
  • 它可以输出详细的求解过程信息,包括冲突数、支配数、重启数等。

cp-sat的求解过程

预处理

将约束规划问题转化为一个整数线性规划(ILP)问题,并进行一些简化和优化,如删除冗余变量和约束、合并等价变量和约束、检测对称性和支配性等。

搜索

使用启发式搜索策略在可行解空间中寻找最优解或证明无解。搜索过程中会使用冲突分析、重启、剪枝等技术来加速求解过程。

输出

输出最优解或无解的结果,并给出一些求解过程的信息,如冲突数、支配数、重启数等。

cp-sat的搜索策略

cp-sat的搜索策略是基于有限域上的布尔可满足性问题(SAT)和伪布尔优化(PBO)。它将整数变量和布尔变量都编码为二进制位向量,并使用布尔逻辑运算来表示约束条件。它使用了一种叫做CDCL(conflict-driven clause learning)的算法来进行搜索。

CDCL算法步骤

  • 选择一个未赋值的变量,并给它一个随机或启发式的值,这叫做猜测(guess)。
  • 根据已赋值的变量和约束条件,推导出其他变量的值,这叫做传播(propagate)。
  • 如果没有发生冲突,即所有约束都被满足,那么继续选择下一个未赋值的变量并重复上述步骤;如果发生了冲突,即有某个约束被违反了,那么回溯到上一个猜测点,并改变该猜测点的值,这叫做回溯(backtrack)。
  • 在回溯过程中,还会根据冲突原因学习出新的约束条件,并加入到原始问题中,这叫做学习(learn)。学习出来的新约束可以帮助剪枝去掉一些不可行或次优的分支,从而缩小搜索空间。

cp-sat使用技术

  • 使用多线程并行计算,同时进行多个搜索过程,并共享学习出来的新约束。
  • 使用分层方法来处理多目标优化问题,即按照目标函数的优先级依次求解,每次求解时将上一个目标函数的最优值作为约束条件。
  • 使用词典序方法来处理多目标优化问题,即将多个目标函数组合成一个单一的目标函数,按照词典序比较不同解的优劣。
  • 使用线性化技术来处理非线性约束,即将非线性约束转化为一系列的线性约束和变量。

cp-sat可解决的问题

cp-sat可以用来解决各种约束规划问题,如排程、布局、分配、选址等。以下是一些常见的案例:

  • 排程问题:给定一组任务和一组资源,如工人、机器、车辆等,每个任务有一定的持续时间和优先级,每个资源有一定的可用时间和容量,求解如何安排任务到资源上,使得满足所有约束条件,并最大化或最小化某个目标函数,如完成时间、成本、利润等。
  • 装载问题:给定一组物品和一个容器,如箱子、背包、棋盘等,每个物品有一定的形状和大小,每个容器有一定的尺寸和限制,求解如何放置物品到容器中,使得满足所有约束条件,并最大化或最小化某个目标函数,如占用空间、重量、价值等。
  • 分配问题:给定一组代表人或物的节点和一组代表关系或需求的边,每个节点有一定的属性和限制,每条边有一定的权重和方向,求解如何分配节点到不同的集合或角色中,使得满足所有约束条件,并最大化或最小化某个目标函数,如总权重、平衡度、公平度等。
  • 选址问题:给定一个地图上的一组候选位置和一组需求点,每个候选位置有一定的成本和收益,每个需求点有一定的数量和距离限制,求解如何选择若干候选位置作为服务点或设施点,并分配需求点到服务点或设施点上,使得满足所有约束条件,并最大化或最小化某个目标函数,如总收益、总成本、总距离等。

cp-sat案例

案例1:简单线性规划问题

有两种产品A和B,每种产品需要不同数量的原料X和Y。每单位A需要3单位X和2单位Y,每单位B需要4单位X和3单位Y。每天最多可以生产1000单位X和800单位Y。每单位A的利润是25元,每单位B的利润是30元。问如何安排生产计划,使得总利润最大?

from ortools.sat.python import cp_model
# 创建模型
model = cp_model.CpModel()
# 定义变量
x = model.NewIntVar(0, 1000, 'x') # 生产A的数量
y = model.NewIntVar(0, 1000, 'y') # 生产B的数量
# 定义目标函数
profit = model.NewIntVar(0, 1000000, 'profit') # 总利润
model.Add(profit == 25 * x + 30 * y) # 利润等于单价乘以数量
model.Maximize(profit) # 最大化利润
# 定义约束条件
model.Add(3 * x + 4 * y <= 1000) # 原料X的限制
model.Add(2 * x + 3 * y <= 800) # 原料Y的限制
# 创建求解器并求解模型
solver = cp_model.CpSolver()
status = solver.Solve(model)
# 打印结果
if status == cp_model.OPTIMAL:
    print('最优解:')
    print('生产A:', solver.Value(x))
    print('生产B:', solver.Value(y))
    print('总利润:', solver.Value(profit))
else:
    print('没有找到最优解')

案例2:分配问题

这个案例是使用CP-SAT求解器来解决一个分配问题。分配问题是指将一组任务分配给一组工人,使得每个任务只能由一个工人完成,每个工人只能完成一个任务,且总成本最小。

from ortools.sat.python import cp_model
# 创建模型
model = cp_model.CpModel()
# 定义数据
num_workers = 4 # 工人数量
num_tasks = 4 # 任务数量
costs = [ # 每个工人完成每个任务的成本矩阵
    [90, 76, 75, 70],
    [35, 85, 55, 65],
    [125, 95, 90, 105],
    [45, 110, 95, 115],
]
# 定义变量
x = [] # x[i][j]表示第i个工人是否被分配到第j个任务,取值为0或1
for i in range(num_workers):
    t = []
    for j in range(num_tasks):
        t.append(model.NewBoolVar('x[%i,%i]' % (i,j)))
    x.append(t)
# 定义约束条件
# 每个工人只能被分配到一个任务
for i in range(num_workers):
    model.Add(sum(x[i][j] for j in range(num_tasks)) == 1)
# 每个任务只能被分配给一个工人
for j in range(num_tasks):
    model.Add(sum(x[i][j] for i in range(num_workers)) == 1)
# 定义目标函数:最小化总成本
objective_terms = []
for i in range(num_workers):
    for j in range(num_tasks):
        objective_terms.append(costs[i][j] * x[i][j])
model.Minimize(sum(objective_terms))
# 创建求解器并求解模型
solver = cp_model.CpSolver()
status = solver.Solve(model)
if status == cp_model.OPTIMAL:
    print('Total cost: %i' % solver.ObjectiveValue())
    print()
    for i in range(num_workers):
        for j in range(num_tasks):
            if solver.Value(x[i][j]) == True:
                print('Worker %i assigned to task %i. Cost: %i' %
                      (i,j,costs[i][j]))

目录
相关文章
|
算法
OR-tools求解器使用介绍(二)
OR-tools求解器使用介绍(二)
1727 0
|
人工智能 算法 决策智能
OR-tools求解器使用介绍(一)
OR-tools求解器使用介绍(一)
1874 0
|
算法 Java 决策智能
运筹优化工具库介绍(一)
运筹优化问题有时候极其复杂,我们可以使用运筹优化工具库帮助数学建模,解决复杂的最优化问题,本文介绍几个常见的运筹优化工具库。
2747 0
|
C语言 Perl 存储
优化求解器之MPS文件的格式简介
在使用MindOpt优化求解器解决实际问题时,其中重要的一环在于如何建立优化模型,以及存储优化模型以便于作为求解器的输入文件。存储优化模型的文件,其关键在于定义一种清晰的格式,用来说明优化模型的数学结构和相关的数据。接下来我们将发布一系列文章,对常见的MPS/LP等格式的模型文件和命名规范进行简要的介绍。
优化求解器之MPS文件的格式简介
|
人工智能 达摩院 开发工具
MindOpt不联网License,可直接在阿里云线上购买了
在很多场景里,由于智能决策运行环境不允许联网、网络不稳定、或者需要毫秒级计算决策方案需要节省联网耗时等场景,多用户反馈需要【不联网】的License。
MindOpt不联网License,可直接在阿里云线上购买了
|
算法 调度
基于or-tools解决物流调度问题(一)
基于or-tools解决物流调度问题(一)
642 3
|
决策智能
Or-tools调用求解器介绍(三)
Or-tools调用求解器介绍(三)
1070 0
|
达摩院 BI 索引
切割问题【数学规划的应用(含代码)】阿里达摩院MindOpt
本文主要讲述了使用MindOpt工具对切割问题进行优化的过程与实践。切割问题是指从一维原材料(如木材、钢材等)中切割出特定长度的零件以满足不同需求,同时尽可能减少浪费的成本。文章通过实例详细介绍了如何使用MindOpt云上建模求解平台及其配套的MindOpt APL建模语言来解决此类问题,包括数学建模、代码实现、求解过程及结果分析等内容。此外,还讨论了一维切割问题的应用场景,并对其进行了扩展,探讨了更复杂的二维和三维切割问题。通过本文的学习,读者能够掌握利用MindOpt工具解决实际切割问题的方法和技术。
|
达摩院 供应链 安全
光储荷经济性调度问题【数学规划的应用(含代码)】阿里达摩院MindOpt
本文介绍使用MindOpt工具优化光储荷经济性调度的数学规划问题。光储荷经济性调度技术旨在最大化能源利用率和经济效益,应用场景包括分布式光伏微网、家庭能源管理系统、商业及工业用电、电力市场参与者等。文章详细阐述了如何通过数学规划方法解决虚拟电厂中的不确定性与多目标优化难题,并借助MindOpt云建模平台、MindOpt APL建模语言及MindOpt优化求解器实现问题建模与求解。最终案例展示了如何通过合理充放电策略减少37%的电费支出,实现经济与环保双重效益。读者可通过提供的链接获取完整源代码。
|
达摩院 供应链 JavaScript
网络流问题--仓储物流调度【数学规划的应用(含代码)】阿里达摩院MindOpt
本文通过使用MindOpt工具优化仓储物流调度问题,旨在提高物流效率并降低成本。首先,通过考虑供需匹配、运输时间与距离、车辆容量、仓库储存能力等因素构建案例场景。接着,利用数学规划方法,包括线性规划和网络流问题,来建立模型。在网络流问题中,通过定义节点(资源)和边(资源间的关系),确保流量守恒和容量限制条件下找到最优解。文中还详细介绍了MindOpt Studio云建模平台和MindOpt APL建模语言的应用,并通过实例展示了如何声明集合、参数、变量、目标函数及约束条件,并最终解析了求解结果。通过这些步骤,实现了在满足各仓库需求的同时最小化运输成本的目标。