【问题标题】:Optaplanner skipping Phases and returning empty solutionOptaplanner 跳过阶段并返回空解决方案
【发布时间】:2021-09-28 23:27:58
【问题描述】:

我正在为课程安排项目(教师、课程、时间)。我正在使用 optaplanner 作为 spring-boot 应用程序的一部分,测试代码正在编译并正确运行,但是结果包含空解决方案,在日志输出中我看到以下消息:

rted:花费时间 (11)、最佳分数 (0hard/0soft)、环境模式 (REPRODUCIBLE)、移动线程数 (NONE)、随机 (JDK 种子 0)。 2021-09-28 22:39:26.619 INFO 2579 --- [pool-1-thread-1] o.o.core.impl.solver.DefaultSolver:跳过所有阶段 (2):在 0 个计划实体中,没有一个是可移动的(非固定)。 2021-09-28 22:39:26.620 INFO 2579 --- [pool-1-thread-1] o.o.core.impl.solver.DefaultSolver :求解结束:花费时间 (16),最佳分数 (0hard/0soft),分数计算速度(62/秒),阶段总数(2),环境模式(REPRODUCIBLE),移动线程数(NONE)。

问题出在我写的测试计算器中记录对象但没有记录任何内容,这是计算器的代码:

public class ScheduleScoreCalculator implements EasyScoreCalculator<ScheduleTable, HardSoftScore>
{
@Override
public HardSoftScore calculateScore(ScheduleTable scheduleTable) {
    int hardScore = 0;
    int softScore = 0;

    List<ScheduledClass> scheduledClassList = scheduleTable.getScheduledClasses();
    System.out.println(scheduleTable);
    System.out.println("Hmmmmm ---"); // this is logged but the score is not changing
    for(ScheduledClass a: scheduledClassList) {
        for (ScheduledClass b : scheduledClassList) {
            if (a.getTeacher().getTeacherId() > 17000L) {
                hardScore+=18;
            }
            if (a.getTimeslot() != null && a.getTimeslot().equals(b.getTimeslot())
                    && a.getId() < b.getId()) {
                if (a.getTeacher() != null && a.getTeacher().equals(b.getTeacher())) {
                    hardScore--;
                }
                if (a.getTeacher().equals(b.getTeacher())) {
                    hardScore--;
                }
            } else {
                hardScore++;
                softScore+=2;
            }
        }
    }

    return HardSoftScore.of(hardScore, softScore);
}
}

那么请知道为什么 optaplanner 可能会跳过创建可能的解决方案?

【问题讨论】:

  • 答案就在日志中:“跳过所有阶段 (2):在 0 个计划实体中,没有一个是可移动的(非固定)。”你似乎没有计划实体,因此没有什么要计划的。我将留给您检查您的计划解决方案是否已正确注释,并且它确实包含一些实体。如果是这样并且您仍然看到此问题,请分享有关您的问题的更多信息,包括。您的域。
  • @LukášPetrovický 你的理论看起来很合理,我当然有带有 3 个规划变量的 @ PlanningEntity 注释类,我通过删除 @ PlanningEntity 来测试你的想法,但项目拒绝构建这样说:“也许你的 @ PlanningEntity 注释的类不在子包中......”所以它确实看到了带有注释的类。但是,可能结构有问题,所以我会修改它,如果它没有帮助我会更新问题详细信息,谢谢

标签: java spring-boot maven optaplanner


【解决方案1】:

问题比我想象的要简单,用“PlanningSolution”注释的解决方案类具有用“PlanningEntityCollectionProperty”注释的属性“scheduledClasses”我的错误是这个属性是用空列表(ArrayList)初始化的,解决方案是初始化一个解决方案班级!回想起来,我认为文档应该归咎于此,provided example 没有提到我们需要这个,所以它不应该是 null (否则会引发异常)并且它不应该是空 List .您需要使用类对其进行初始化,而不为可移动属性设置任何值(用“PlanningVariable”注释)。 感谢@Lukáš Petrovický,因为他的评论帮助我进行了正确的调查!

【讨论】:

  • 一个空的实体列表很遗憾是一个有效的例子。解决该问题会立即返回,而无需更改解决方案。在某些每天运行的自动化案例中,有时可能会发生没有实体可分配的情况。这就像在一个空列表上做Collections.reverse() - 这也不会很快失败。
  • @GeoffreyDeSmet 我查看了您的个人资料,感谢您提供这款很棒的软件!我理解你的观点,所以也许在(描述良好的)示例中添加小注释可能会帮助像我这样的新手避免这个问题。还有其他可能需要的东西,那就是 EasyScoreCalculator(我还没有测试约束提供者方法)应该在它自己的命名空间中,因为当它在求解器命名空间中时,项目拒绝构建,因为它看到 2 EasyScoreCalculator类,这可能是错误,我稍后会尝试对此进行更多调查,但如果不是,则值得一提
  • 感谢您的建议。我查看了快速入门文档,看看在某处添加“确保您的课程列表不为空”是否有意义。它确实已经说“带有所有课程的lessonList 字段”。但是,添加这句话需要权衡:快速入门文档也需要简洁——因此添加所有此类陷阱注释会适得其反。现在,出于这个原因,我将其省略,但如果更多人遇到这个问题,我们可以重新考虑。感谢您在任何情况下的报告:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 2020-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-06
相关资源
最近更新 更多