当前位置: 首页 > 知识库问答 >
问题:

Optaplanner惩罚不适用于可为null的变量

梁新觉
2023-03-14

我使用的OptaPlanner有两个规划变量,其中一个定义为nullable=true。遵循会议示例(为简单起见),假设Room可以为空,但Time不能为空。

我在非空的time变量上定义了一个约束,但似乎只有当可空的room变量不为空时,惩罚才起作用,否则会失败。

下面是我的代码片段:

@PlanningEntity
public class Meeting {

   @PlanningVariable(valueRangeProviderRefs = "time")
   private LocalDateTime time;

   @PlanningVariable(valueRangeProviderRefs = "availableRooms", nullable = true)
   private Room room;

   private long personId;
   ...
}

在我的约束提供者类中,我定义了以下约束来确保一个人不能参加两个单独的会议:

protected Constraint samePersonAndTimeConflict(ConstraintFactory constraintFactory) {
        return constraintFactory
                // Select each pair of 2 different meetings ...
                .forEachUniquePair(Meeting.class,
                        // ... for the same person ...
                        equal(Meeting::getPersonId),
                        // ... in the same time ...
                        equal(Meeting::getDateTime))
                // ... and penalize each pair with a hard weight.
                .penalize(SAME_PERSON_AND_TIME_CONFLICT, HardSoftScore.ONE_HARD);
    } 

当创建两个具有非空值的对象时,如果假设同一个人同时参加两个单独的会议,则该约束将很好地工作,并以一个硬分数惩罚。然而,当处理可为null的房间变量确实为null的对象时,没有惩罚。结果是,我得到了一个解决方案,其中许多情况下,同一个人有相同的时间分配。

我还尝试了用其他方式处理约束,例如使用“forEachIncludingNullVars”和“forEach”,但我看到了相同的结果:

protected Constraint samePersonAndTimeConflict(ConstraintFactory constraintFactory) {
        return constraintFactory
                .forEachIncludingNullVars(Meeting.class)
                //.filter(meeting -> meeting.getDateTime() != null)
                .join(Meeting.class,
                        lessThan(Meeting::getId),
                        equal(Meeting::getTime),
                        equal(Meeting::getPersonId)) //,
                .penalize(SAME_PERSON_AND_TIME_CONFLICT, HardSoftScore.ONE_HARD);

我还尝试将分数类更改为HardMediumSoftScore,并通过一个中等惩罚。对于没有会议室的会议,仍然没有处罚。

OptaPlanner似乎根本没有发挥应有的作用。在这一点上,我不知道我还能尝试什么。请建议。

***编辑***

按照下面的建议,使用嵌套的constraintFactory和附加的foreachingcludingnullvars子句,我最终实现了我的约束,如下所示——现在它可以工作了:

protected Constraint samePersonAndTimeConflict(ConstraintFactory constraintFactory) {
        final Constraint constraint = constraintFactory.forEachIncludingNullVars(Meeting.class)
                .join(
                        constraintFactory.forEachIncludingNullVars(Meeting.class)
                                .filter(meeting -> meeting.getTime() != null),
                        lessThan(WorkDay::getId),
                        equal(WorkDay::getEmployeeId),
                        equal(WorkDay::getDate))
                .penalize("Same person and time conflict", HardMediumSoftScore.ONE_HARD);
        return constraint;
    }

共有1个答案

卢晟
2023-03-14

forEach()在这里不起作用,因为这只会给您提供没有任何变量为null的实体foreachingcludingnullvars()是一种方法。但是您还需要了解,join与forEach具有相同的行为-它不包括具有空变量的实体。

要考虑到这一点,您需要使用嵌套流连接,如下所示:

protected Constraint samePersonAndTimeConflict(ConstraintFactory constraintFactory) {
    return constraintFactory
            .forEachIncludingNullVars(Meeting.class)
            .join(
                constraintFactory.forEachIncludingNullVars(Meeting.class),
                    // add your joiners here
            ).penalize(SAME_PERSON_AND_TIME_CONFLICT, HardSoftScore.ONE_HARD);
}

这样,连接将创建所有实体的交叉乘积,而不管它们的任何变量是否为空。然后,它就变成了filter剔除您不希望看到空值的部分的问题。

 类似资料:
  • 问题内容: 在Eclipse下开发Java应用程序时,我收到有关“通过综合方法访问方法/值”的警告。解决方案只是将私有访问修饰符更改为默认级别。 这让我想知道:使用合成方法会受到什么惩罚?有一些?我认为编译器/ Eclipse会发出警告,但是它是否如此相关或可以安全地忽略? 我在这里没有看到这些信息,所以我问。 问题答案: Eclipse警告您,您可能会公开您认为是私有的信息。如下所示,恶意代码可

  • 管道分支惩罚是ALU和IF之间非零距离的结果。 这句话是什么意思?

  • 问题内容: 我看过布兰登·罗德斯(Brandon Rhodes)关于Cython的谈话-“ EXE的日子即将到来”。 布兰登在09:30提到对于一段特定的短代码,跳过解释可以使速度提高40%,而跳过分配和分配可以使速度提高574%(10:10)。 我的问题是-如何测量特定代码段?是否需要手动提取基础的c命令,然后以某种方式使运行时运行它们? 这是一个非常有趣的观察,但是如何重新创建实验? 问题答案

  • 考虑以下几点: 为什么第一个版本是编译错误,当我已经声明lambda是可变的,并通过值捕获(我认为是它的副本)? 使用clang(x86_64-apple-darwin14.3.0)和Visual C(vc120)进行测试,这是错误消息的来源。

  • 问题内容: from celery import Celery 这是我用来测试芹菜的代码。我希望每次使用addone()时,返回值都应该增加。但是为什么总是1? 结果 问题答案: 默认情况下,启动工作程序时,Celery以并发4启动它,这意味着它已启动4个进程来处理任务请求。(加上一个控制其他进程的进程。)我不知道该使用哪种算法将任务请求分配给为工作人员启动的进程,但是最终,如果执行足够,您将看到

  • 我想使用Boost.Range和带有init-capture的C 1y lambdas来计算两个向量的元素差异。减去一个向量的固定(即第一个)元素的更简单情况是有效的。但是,当我尝试通过在第二个范围上增加迭代器(并使lambda可变)来计算“矢量化差异”时,我得到一个编译器错误。示例代码(请注意,我没有使用通用的 lambda,因此 g 4.8 和 Clang SVN 都可以解析此代码): 活生生