-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8663f8c
commit 6178d16
Showing
4 changed files
with
165 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
--- | ||
categories: [optimization, mathematics] | ||
tags: [job shop schedule] | ||
--- | ||
|
||
# 作业车间调度问题求解框架 | ||
|
||
--- | ||
|
||
组合优化问题广泛出现于各行各业,例如生产制造排程,机场航班调度、项目管理计划等,求解这类问题有助于解决实际应用中的调度难题、提高生产效率;考虑到实际的业务逻辑因行业而异且可能相当复杂,本系列文章针对调度类问题的基本模型——作业车间调度(Job Shop Schedule),基于Python开发了一个通用的求解框架: | ||
|
||
- 参考文献实现了一些基本解法例如基于规则指派、局部搜索、群体方法等 | ||
|
||
- 便于快速实施和测试新算法(参考 [Python建模](2021-08-14-作业车间调度问题求解框架:Python建模.md)) | ||
|
||
|
||
## 项目仓库 | ||
|
||
https://github.com/dothinking/job_shop_schedule | ||
|
||
## 建模 | ||
|
||
- [问题描述](2021-08-08-作业车间调度问题求解框架:问题描述.md) | ||
|
||
- [Python建模](2021-08-14-作业车间调度问题求解框架:Python建模.md) | ||
|
||
- [基于matplotlib的动态甘特图](2021-08-15-基于matplotlib的动态甘特图.md) | ||
|
||
|
||
## 求解 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
--- | ||
categories: [optimization, python/vba/cpp] | ||
tags: [job shop schedule] | ||
--- | ||
|
||
# 作业车间调度问题求解框架:Python建模 | ||
|
||
--- | ||
|
||
基于前文对作业车间调度问题的定义和描述,本文进行Python建模,开发了一个通用的作业车间调度问题求解框架,把问题分解、抽象为可重用的部分,从而专注求解算法的开发、实施和验证。 | ||
|
||
> [dothinking/job_shop_schedule](https://github.com/dothinking/job_shop_schedule) | ||
|
||
## 框架结构 | ||
|
||
整个求解框架基于Python面向对象编程实现,主要结构参考下图。 | ||
|
||
 | ||
|
||
|
||
其中,所有对象按用途可以归为三类: | ||
|
||
|
||
### (a) 物理对象 | ||
|
||
- `Job` 作业实体 | ||
- `Machine` 机器实体 | ||
- `Operation` 工序实体,包含所属作业、分配的机器、加工时长等属性 | ||
|
||
|
||
### (b) 求解变量 | ||
|
||
`OperationStep`是工序实体`Operation` 的封装,同时加上待求解的参数 `start_time`。根据前文关于作业车间问题的两种不同的描述方式,相应有两种不同的求解思路: | ||
|
||
- 对于以`start_time`为变量描述的数学模型,直接求解`start_time`即可 | ||
- 对于以 **析取图** 描述的模型,需要先求解工序的顺序,然后递推出`start_time` | ||
|
||
因此,对于析取图描述的模型,还提供了以下中间属性: | ||
|
||
- 继承自 `JobStep` 的 `pre_job_op` 和 `next_job_op`,分别表示当前工序在所属作业实体上的顺序:前一道工序和下一道工序;并且,它们是已知的。 | ||
|
||
- 继承自 `MachineStep` 的 `pre_machine_op` 和 `next_machine_op`,分别表示当前工序在分配机器上的加工顺序:前一道工序和下一道工序;注意这个顺序即为需要求解的变量。 | ||
|
||
|
||
### (c) 求解流程 | ||
|
||
`JSProblem` 是所有工序实体 `Operation` 的封装: | ||
|
||
- 它的解为一个`JSSolution`实例 | ||
- 每当获得一个更好的解,**需要使用`update_solution()`方法显式更新** | ||
|
||
`JSSolution` 是所有变量 `OperationStep` 的封装: | ||
|
||
- 对于析取图求解模型,需要显式地调用 `evaluate()` 来基于求解的顺序计算最终变量 `start_time`;基于数学模型则无需这一步。 | ||
|
||
- `is_feasible()` 判断一个解是否满足所有约束 | ||
|
||
- 如果是一个可行解,`makespan`属性得到最大加工周期长度 | ||
|
||
|
||
`JSSolver` 是作业车间调度问题求解器的基类,便于继承此基类后实施新算法。 | ||
|
||
|
||
## 实施新算法 | ||
|
||
以上的设计可以避免重复工作,从而专注于算法本身的实现和测试。基于此框架,实施新算法的只需创建自定义求解器类,然后继承 `JSSolver` 并实现 `do_solver()` 方法。`do_solver()` 方法内部主要分为三大步骤: | ||
|
||
- 基于问题创建初始状态的解(注意并非可行的 **初始解**) | ||
|
||
```python | ||
solution = JSSolution(problem) | ||
``` | ||
|
||
- 实施算法,计算或者优化这个解 | ||
|
||
- 对于以`start_time`为变量描述的数学模型,直接求解每个工序的`start_time`即可 | ||
- **对于以析取图描述的模型,需要先求解工序的顺序,然后显式地调用 `solution.evaluate()` 递推出`start_time`** | ||
|
||
|
||
- 每次迭代得到更好的解后,显式更新问题的解 | ||
|
||
```python | ||
problem.update_solution(solution) | ||
``` | ||
|
||
关键代码参考: | ||
|
||
```python | ||
from model.solver import JSSolver | ||
from model.problem import JSProblem | ||
from model.solution import JSSolution | ||
|
||
class UserSolver(JSSolver): | ||
|
||
def do_solve(self, problem:JSProblem): | ||
'''User defined solving process.''' | ||
|
||
# (1) Initialize an empty solution from problem | ||
solution = JSSolution(problem) | ||
|
||
# (2) Solve or optimize the solution, | ||
# i.e. determine the start_time of OperationStep instances. | ||
# Note to evaluate solution explicitly if disjunctive graph model. | ||
... | ||
# solution.evaluate() | ||
|
||
# (3) Update the solution for problem iteratively | ||
problem.update_solution(solution) | ||
``` | ||
|
||
|
||
## 测试算法 | ||
|
||
框架已经内置了作业车间调度问题的标准考题数据,便于根据名称直接初始化问题。以下示例调用自定义求解器 `SampleSolver` 求解 `ft10` 问题。 | ||
|
||
- 更多基本问题数据 [参考](https://github.com/dothinking/job_shop_schedule/blob/master/benchmark/instances.json) | ||
|
||
- 求解过程以甘特图形式动态展示解的变化 | ||
|
||
|
||
```python | ||
from model.problem import JSProblem | ||
from solver.SampleSolver import SampleSolver | ||
|
||
# load benchmark problem | ||
problem = JSProblem(benchmark='ft10') | ||
|
||
# solve problem with user defined solver | ||
s = SampleSolver(name='sample') | ||
s.solve(problem=problem) | ||
``` | ||
|
||
基本介绍到此结束,接下来将陆续实施一些求解算法。 |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.