如何根据OptaPlanner中添加的第一个元素设置参数



每个作业都有自己的位置(城市(。每个员工只能在一个地点工作。如果员工在一个地点工作,他就不能接受另一个地点的订单。我该怎么做?给定:

@Data
@PlanningEntity
public class Job {
@PlanningId
private Long id;
private String location;
@PlanningVariable(valueRangeProviderRefs = "employeeRange")
private Employee employee;
}
@Data
@PlanningEntity
public class Employee {
@PlanningId
private Long id;
@InverseRelationShadowVariable(sourceVariableName = "employee")
private List<Job> jobs = new ArrayList<>();
}
@Data
@PlanningSolution
public class Solution {
@PlanningEntityCollectionProperty
@ValueRangeProvider(id = "employeeRange")
private List<Emoloyee> employees;
@PlanningEntityCollectionProperty
private List<Job> jobs;
@PlanningScore
private HardMediumSoftScore score;
public Solution(List<Emoloyee> employees, List<Job> jobs) {
this.employees = employees;
this.jobs = jobs;
}
}

以下是考虑位置的约束条件:

private Constraint locationIsConsidered(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(Job.class)
.filter(job -> !job.getEmployee().getLocation()
.equals(job.getLocation()))
.penalize("Location conflict", HardMediumSoftScore.ONE_HARD);
}

另一个约束(不考虑位置(:但不起作用

private Constraint directionIsNotConsidered(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(Job.class)
.groupBy(Job::getInspector)
.filter(employee -> employee.getJobs().stream()
.anyMatch(job -> !Objects.equals(job.getLocation(),
employee.getJobs().get(0).getLocation()))
).penalize("Location Conflict", HardMediumSoftScore.ONE_HARD);
}

提前感谢!

恐怕您在这里试图解决的实际上是两个不同的规划问题。将员工分配到各个位置,然后将工作分配给这些位置的员工。后者的结果取决于前者的结果;如果前者的结果发生变化,则需要对后者的整个结果进行显著的重新计算。

试图在一个解决方案中同时解决这两个问题必然会引发问题。一旦你将一名员工分配到一个地点,并将一些工作分配给该员工,那么将该员工重新分配到另一个地点就可以保证打破严格的限制(现在所有的工作都指向来自不同城市的员工(,尝试从不同城市分配工作的举措也是如此——因此,任何举措都不会真正让你取得任何进展,除非你写了一个自定义的调动,在地点调动时重新分配所有员工的工作,再加上一大堆调动过滤器,消除无用的调动。尽管此问题不会阻止解算器工作,但解算器的效率不会太高。

更好的办法是实施多阶段规划。首先解决将员工分配到城市的问题。如果这是一个足够简单的问题,请使用暴力;如果很难,请使用OptaPlanner。一旦你有了分配,就可以使用OptaPlanner为这些员工分配工作,他们的城市现在是不可变的。这会带来效率低下的问题,但实施和理解起来相对简单。

我想我已经找到了解决方案。

private Constraint directionIsNotConsidered(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(Job.class)
.groupBy(Job::getInspector)
.filter(employee -> employee.getJobs().stream()
.anyMatch(job -> !Objects.equals(job.getLocation(),
employee.getJobs().get(0).getLocation()))
).penalize("Location Conflict", HardMediumSoftScore.ONE_HARD);
}

最新更新