介绍cplex 约束规划建模基础知识

约束规划 opl语言

本文主要基于ILOG的约束规划(Constraint Programming)模块求解调度问题,因此主要介绍调度相关的函数

依据运筹学建模,主要介绍变量和约束

参考文献:https://doi.org/10.1007/s10601-018-9281-x
这篇文献是IBM在Constraint期刊发表的CPO模块介绍,更加详细,本文只是对其进行了摘要和翻译,想要更全面的了解CP模块,可以查看此文献。

后续会对docplex的cp模块进行介绍,但基本内容都是关于区间变量和关系约束这两块。

Interval Variables

basic interval variables

区间变量表示调度中占据一段时间的活动或者任务,并且其在调度问题中的时间位置是不确定的,也就是不知道任务是在什么时候开始。
区间变量由开始时间和结束时间组成。并且区间变量是可选的,也就是我们设置的区间变量可能在解中出现,也可以不出现。
所以可以应用于以下场景:

  1. 可选任务:任务未必一定全部加工
  2. 备选资源,但这些资源并非全部使用,而是选择一部分
  3. 模式选择:任务有多种工作模式,但只能选一个
  4. 可选路径:任务的加工过程有多个,但只选择一条
  5. hierarchical description of a project as a work-breakdown structure with tasks decomposed
    into sub-tasks, part of the project being optional

例如区间变量a是一个决策变量,其值域可以为空集,也可以为[s,e],s表示开始时间,e表示结束时间,l=s-e,表示其长度

值得注意的是,区间变量有一个和长度length相联系的属性size,size是小于等于length的。

如果区间变量a为空集,其相当于不存在,即便应用在后面的noOverlap函数或者次序约束上,都相当于没有作用

# 区间变量a表示值域为默认的,也就是l不确定,但s和e必须为非负数,此时的size和length相等
dvar interval a;
# b则表示其区间长度在【0,10】的范围内
dvar interval b size 0..10;
# c表示区间变量为可选,并且长度为10,可以从-1000开始到1000
dvar interval c optional in -1000..1000 size 10;

比如有100个任务,每个工序都有一个加工时间time,那么这些工序应该设置为

dvar interval task[i in Tasks] optional in 0..100 size time[i];

Tasks表示所有的任务都只能在0到100内进行,time表示所有任务的加工时间,也就是size。

option表示任务是可选的,也就是可以任务不是必然存在。

Intensity,size and forbidden values

这部分主要是介绍随着时间的变化,可以对区间变量的length进行变化,例如变大或缩小,主要是通过设置函数,我没有用过,因此不再介绍。

logic constraint

这里表示的是逻辑约束,也就是if条件的问题,具体可以看下面两个

presenceOf()函数表示的是如果区间变量存在则返回1,否则返回0

# 表示如果a是数,则b一定是实数
presenceOf(a) => presenceOf(b)

# a,b同时为present或者同时为absent
presenceOf(a) == presenceOf(b)

Temporal constraints

这里主要说的是区间变量之间的关系,比如任务a和任务b之间的开始和结束时间的关系

  1. startOf(a) 任务a开始的时间
  2. endOf(b) 任务a结束的时间
  3. endBeforeEnd(a,b) 任务a结束的时间大于任务b结束的时间

可以开始开始,结束结束,开始结束,结束开始等关系

# a的完工时间必须在b开始之间的z个单位
endBeforeStart(a,b,z)
# 其中z可以为负值,表示推迟到b开始之后的z个单位,a才完工
# z也可以为固定的值或者决策变量

Constraints on groups of interval variables

单个区间变量和一组区间变量之间的关系

span constraint

跨越约束

span(a,{b1,b2...bn})

表示区间边变量a,如果存在,将分布在区间变量集合B={b1,b2…bn}中。也就是区间变量a和B集合第一个存在的元素一起开始,和最后一个存在的元素一起结束

举个例子:汽车产品加工中有许多工序,那这些工序有些是存在的,有些可能是冗余的,那汽车可以设置为一个区间变量,其基本属性是[start,end]时间,而组成汽车产品的工序也可以设置为区间变量。

我们如何确认汽车的基本属性呢?

使用span约束可以表达,汽车的完工时间应该在任务区间变量的范围内。也就是一个汽车的区间变量一定位于这一组工序的区间变量中,但是具体的位置不知道,只知道汽车区间变量可以出现在这组工序区间变量的任意位置。

span(汽车,一组工序),就能够表达

alternative constraint

候选变量,区间变量a是从集合B中任意选择一个

alternative(a,{b1,b2...bn},c)

如果a存在,则其将与B集合中选中的某个元素一起开始和结束,c则会和a一起开始和结束

Interval variables sequencing

大多数调度任务中都会存在一些分离资源(disjunctive resources),其在任何时间点只能完成一项任务,典型的例子如工人,机器等。因此设计了一个新的决策变量 sequence variable,其值是一系列区间变量的排列。用来表示这些区间变量之间的一些关系

Sequencing constraint

举个例子:一个产品有5个工序,工序加工的先后顺序就是这个约束的含义,形如p=[2,1,3,5,4],任务2和任务1的关系就是

before(p,2,1)在序列p中,任务2在任务1前

# 如果a存在,则其在序列p中的位置为第一个
first(p,a)
# 如果a存在,则其在序列p中的位置为最后一个
last(p,a)
# 如果a,b都存在,则在p中的位置表现为,a在b的前面
before(p,a,b)
# 如果a,b都存在,则在p中,a在b的前面,且直接相邻,中间没有其他区间变量
prev(p,a,b)

No-overlap constraint

排序约束并不决定区间变量的开始时间和结束时间,其只是确定相对位置,进行合理分配。无交叉约束表示的是,两个任务之间不存在交叉区域,比如一组区间变量a,其中任务2的开始和结束时间分别是3和5,则任务1的开始和结束时间就不能是3和5。

noOverlap(a)

Same-sequence and same-common-subsequence constraints

例如有两组排序p1和p2,已经获得了p1内部区间变量之间的关系,可以直接使用samesequence(p1,p2),将这种关系转给p2,具体以后补充。

总结

约束规划中的基础变量是区间变量,基础约束是次序约束和排序约束

只需要明白interval variable、sequence variable、temporal constraint、sequence constraint这四部分的内容,一般的调度问题都能构建出来。

你可能感兴趣的:(docplex)