optaplanner阴影变量
文章目录
简介
阴影变量是一种规划变量,其正确值可以从真实规划变量的状态推断出来。尽管根据定义,这种变量违反了归一化原则,但在某些情况下使用阴影变量非常实用,特别是为了更自然地表达约束条件。例如,在带有时间窗口的车辆路径问题中,车辆到达客户的时间可以基于该车辆先前访问的客户(以及两个位置之间已知的行驶时间)进行计算。
当车辆的客户发生变化时,每个客户的到达时间会自动调整。有关更多信息,请参见车辆路径领域模型。
从评分计算的角度来看,阴影变量与其他任何规划变量一样。从优化的角度来看,OptaPlanner实际上只优化真实变量(并且大部分忽略阴影变量):它仅确保当真实变量发生变化时,任何相关的阴影变量也会相应地发生变化。
任何至少有一个阴影变量的类都是一个规划实体类(即使它没有真实的规划变量)。该类必须在求解器配置中定义,并带有@PlanningEntity
注解。
一个真实规划实体类至少有一个真实规划变量,但也可以有阴影变量。一个阴影规划实体类没有真实的规划变量,至少有一个阴影规划变量。
有几种内置的阴影变量:
双向变量(反向关系阴影变量)
如果两个变量总是相互指向对方的实例(除非一侧指向null并且另一侧不存在),则这两个变量是双向变量。例如,如果A引用B,则B引用A。
对于非链式规划变量,双向关系必须是多对一的关系。要映射两个规划变量之间的双向关系,请在源端(真实端)上使用@PlanningVariable
注解普通规划变量:
@PlanningEntity
public class CloudProcess {
@PlanningVariable(...)
public CloudComputer getComputer() {
return computer;
}
public void setComputer(CloudComputer computer) {
...}
}
然后,在另一侧(阴影侧)使用@InverseRelationShadowVariable
注解,并将其放在集合(通常是Set或List)属性上:
@PlanningEntity
public class CloudComputer {
@InverseRelationShadowVariable(sourceVariableName = "computer")
public List<CloudProcess> getProcessList() {
return processList;
}
}
请将此类注册为规划实体,否则OptaPlanner将无法检测到它,并且阴影变量不会更新。sourceVariableName
属性是getter方法返回类型上真实规划变量的名称(即另一侧的真实规划变量的名称)。
阴影属性(通常是集合,如List、Set或SortedSet)永远不能为null。如果没有真实变量引用该阴影实体,则它是一个空集合。此外,它必须是可变的集合,因为一旦OptaPlanner开始初始化或更改真实规划变量,它将相应地添加和删除这些阴影变量的集合中的元素。
对于链式规划变量,双向关系始终是一对一的关系。在这种情况下,真实端看起来像这样:
@PlanningEntity
public class Customer ... {
@PlanningVariable(graphType = PlanningVariableGraphType.CHAINED, ...)
public Standstill getPreviousStandstill() {
return previousStandstill;
}
public void setPreviousStandstill(Standstill previousStandstill) {
...}
}
阴影端看起来像这样:
@PlanningEntity
public class Standstill {
@InverseRelationShadowVariable(sourceVariableName = "previousStandstill")
public Customer getNextCustomer() {
return nextCustomer;
}
public void setNextCustomer(Customer nextCustomer) {