我是 OptaPlanner 的新用户。
我需要在员工之间划分工作列表,但一名员工执行的工作数量不应少于或多于指定值。 例如,一名员工每天不能执行少于 10 项和超过 30 项工作。
源代码
@Data
@NoArgsConstructor
@PlanningEntity
public class Job {
@PlanningId
private Long id;
@PlanningVariable(valueRangeProviderRefs = "employeeRange")
private Employee employee;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@PlanningEntity
public class Inspector {
@PlanningId
private Long id;
@InverseRelationShadowVariable(sourceVariableName = "employee")
private List<Job> jobs;
}
@Data
@NoArgsConstructor
@PlanningSolution
public class Plan {
@ProblemFactCollectionProperty
@ValueRangeProvider(id = "employeeRange")
private List<Employee> employees;
@PlanningEntityCollectionProperty
private List<Job> jobs;
@PlanningScore
private HardSoftScore score;
}
还有一个问题:
如何将多个约束合并为一个。 例如,一名员工每天可以执行 10 到 30 项工作。一次出差持续2天,因此在此期间他总共可以完成20到60份工作。
我阅读了文档,但我不确定 count() countDistinct() min() max()
是否适合此目的
最佳答案
在您的域中,我没有看到任何用于确定作业日期的字段,因此我假设所有作业共享相同的日期。使用Constraint Streams ,您可以对最小和最大工作限制进行建模,如下所示:
public class MyConstraintProvider implements ConstraintProvider {
@Override
public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
return new Constraint[] {
minimumJobsPerDay(constraintFactory),
maximumJobsPerDay(constraintFactory)
};
}
Constraint minimumJobsPerDay(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(Inspector.class)
.filter(inspector -> inspector.getJobs().size() < 10)
.penalize("Employee performing less than minimum jobs per day",
HardSoftScore.ONE_HARD,
inspector -> 10 - inspector.getJobs().size());
}
Constraint maximumJobsPerDay(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(Inspector.class)
.filter(inspector -> inspector.getJobs().size() > 30)
.penalize("Employee performing more than maximum jobs per day",
HardSoftScore.ONE_HARD,
inspector -> inspector.getJobs().size() - 30);
}
}
对于你的第二个问题,Compose Constraint Collector对于组合约束非常有用(尽管您的示例不需要)。对于您的示例(带有附加问题事实类 BusinessTrip
):
@Data
@AllArgsConstructor
public class BusinessTrip {
private Employee employee;
private LocalDate start;
private LocalDate end;
}
并更改工作,使其具有日期:
@Data
@NoArgsConstructor
@PlanningEntity
public class Job {
@PlanningId
private Long id;
private LocalDate date;
@PlanningVariable(valueRangeProviderRefs = "employeeRange")
private Employee employee;
}
约束可以像这样建模:
Constraint jobsDuringBusinessTrip(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(BusinessTrip.class)
.join(Employee.class, Joiners.equal(BusinessTrip::getEmployee, employee -> employee))
.join(Job.class, Joiners.overlapping(
(trip, employee) -> trip.getStart().atStartOfDay(),
(trip, employee) -> trip.getEnd().atStartOfDay(),
job -> job.getDate().atStartOfDay(),
job -> job.getDate().plusDays(1).atStartOfDay()),
Joiners.equal((trip, employee) -> employee, Job::getEmployee))
.groupBy((trip,employee,job) -> trip,
(trip,employee,job) -> employee,
ConstraintCollectors.countTri())
.filter((trip, employee, jobCount) -> jobCount < 20 || jobCount > 60)
.penalize("Over or under job count during business trip",
HardSoftScore.ONE_HARD);
}
关于java - 如何在 OptaPlanner 中为每组的最小和最大计数添加 HardConstraint?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72858723/