Timefold AI过约束规划:解除不满足硬约束的分配条目异常
问题分析与解决方案
核心原因
你遇到的问题是因为Timefold求解器会优先满足硬约束(优先级最高),当开启allowsUnassigned=true后,求解器发现不分配任何课程可以完全避免硬约束违规(得到0hard),而分配九年级的数学课就会触发硬惩罚。但你没有配置约束来鼓励分配那些不违反硬约束的课程,所以求解器选择了全不分配的方案,哪怕这会导致medium分数受损。
另外还有一个潜在问题:你的硬约束使用了HardSoftScore.ONE_HARD,但规划分数类型是HardMediumSoftScore,类型不匹配可能导致分数计算异常,需要修正。
具体修复步骤
1. 统一分数类型
将硬约束中的分数常量改为对应HardMediumSoftScore的类型:
Constraint ninthGradeStudentsDislikesMaths(ConstraintFactory constraintFactory) { return constraintFactory.forEach(Lesson.class) .filter(lesson -> lesson.getStudentGroup().equals("9th grade") && lesson.getSubject().equals("Math")) // 替换为HardMediumSoftScore的常量 .penalize(HardMediumSoftScore.ONE_HARD) .asConstraint("9th grade students does not like Maths"); }
2. 添加约束鼓励分配合法课程
需要添加一个medium级别的约束,引导求解器优先分配那些不违反硬约束的课程,可以选择以下两种方案之一:
方案A:惩罚未分配的合法课程
Constraint penalizeUnassignedValidLessons(ConstraintFactory constraintFactory) { return constraintFactory.forEach(Lesson.class) // 筛选出可分配的合法课程(不触发硬约束) .filter(lesson -> !(lesson.getStudentGroup().equals("9th grade") && lesson.getSubject().equals("Math"))) // 检查是否未分配 .filter(lesson -> lesson.getTimeslot() == null || lesson.getRoom() == null) .penalize(HardMediumSoftScore.ONE_MEDIUM) .asConstraint("Penalize unassigned valid lessons"); }
方案B:奖励已分配的合法课程
Constraint rewardAssignedValidLessons(ConstraintFactory constraintFactory) { return constraintFactory.forEach(Lesson.class) .filter(lesson -> !(lesson.getStudentGroup().equals("9th grade") && lesson.getSubject().equals("Math"))) .filter(lesson -> lesson.getTimeslot() != null && lesson.getRoom() != null) .reward(HardMediumSoftScore.ONE_MEDIUM) .asConstraint("Reward assigned valid lessons"); }
将上述约束添加到defineConstraints方法的返回数组中。
3. 检查原有约束
确保原有约束中没有硬约束强制所有课程必须分配(比如类似mustAssignAllLessons的硬约束),如果有,需要将其分数级别改为medium或soft,否则求解器会被迫分配所有课程,包括违反硬约束的九年级数学课。
预期效果
修复后,求解器会优先避免分配九年级的数学课(避免硬惩罚),同时尽可能分配其他所有课程(满足medium约束),最终得到类似0hard/0medium/-Xsoft的分数(X为未分配的九年级数学课数量对应的惩罚,若配置了相关soft约束),且所有合法课程都会被正确分配。
内容的提问来源于stack exchange,提问作者Sadisha
相关产品推荐
相关产品推荐

