1

我目前正在尝试使用 OptaPlanner,因为它似乎是我遇到的问题的完美解决方案。

基本上,项目作业调度示例就是我想要的,但是因为我只知道我的 Java 基础知识,所以这开始起来很复杂。所以我试图从一个非常有限的例子开始,然后从那里开始:

我有一个持续时间和一个定义的前任的任务。计划实体是每个任务开始的时间。

我有一个硬分,惩罚在其前任的 starttime+duration 之前开始的任务。我也有一个软分数,它试图减少差距,使整个过程尽可能短。

public HardSoftScore calculateScore(Schedule schedule) {
    int hardScore = 0;
    int softScore = 0;

    for (Task task : schedule.getTaskList()) {
        int endTime = task.getAllocation().getStartTime() + task.getDuration();
        softScore = -endTime;

        for (Task task2 : schedule.getTaskList()) {
            if(task.getId()!=task2.getId()){
                if( task2.getPredecessorId()==task.getId()) {
                    if (endTime > task2.getAllocation().getStartTime()) {
                        hardScore += task2.getAllocation().getStartTime() - endTime;
                    }
                }
            }
        }
    }

    return HardSoftScore.valueOf(hardScore, softScore);

}

这是求解器配置:

<?xml version="1.0" encoding="UTF-8"?>
<solver>
    <!--<environmentMode>FAST_ASSERT</environmentMode>-->

    <!-- Domain model configuration -->
    <solutionClass>com.foo.scheduler.domain.Schedule</solutionClass>
    <planningEntityClass>com.foo.scheduler.domain.Task</planningEntityClass>

    <!-- Score configuration -->
    <scoreDirectorFactory>
        <scoreDefinitionType>HARD_SOFT</scoreDefinitionType>
        <simpleScoreCalculatorClass>com.foo.scheduler.solver.score.SchedulingSimpleScoreCalculator</simpleScoreCalculatorClass>
    </scoreDirectorFactory>

    <!-- Optimization algorithms configuration -->
    <termination>
        <maximumSecondsSpend>100</maximumSecondsSpend>
    </termination>
    <constructionHeuristic>
        <constructionHeuristicType>FIRST_FIT</constructionHeuristicType>
    </constructionHeuristic>
    <localSearch>
        <acceptor>
            <entityTabuSize>7</entityTabuSize>
        </acceptor>
        <forager>
            <acceptedCountLimit>1000</acceptedCountLimit>
        </forager>
    </localSearch>
</solver>

问题是,只要我只有硬分,这效果很好。但它当然有差距。一旦我添加了软分数,一切都会在大约 10 步后卡住。为什么?

[...]
2014-05-03 20:01:31,966 [main] DEBUG     Step index (10), time spend (495), score (-35hard/-66soft),     best score (-34hard/-68soft), accepted/selected move count (1000/19884) for picked step (com.foo.scheduler.domain.Task@35480096 => com.foo.scheduler.domain.Allocation@f9a4520).
2014-05-03 20:03:11,471 [main] DEBUG     Step index (11), time spend (100000), score (-35hard/-65soft),     best score (-34hard/-68soft), accepted/selected move count (0/105934687) for picked step (com.foo.scheduler.domain.Task@7050c91f => com.foo.scheduler.domain.Allocation@47c44bd4).
4

1 回答 1

1

在步骤 11中选择的移动计数105934687清楚地表明没有移动被接受。不过,我看不出软分数是如何触发的。只有一种解释:

  • EntityTabuAcceptor不接受任何招式,因为它们都是禁忌,也就是说每一个招式的计划实体都在禁忌列表中。如果您的数据集非常小(14或计划实体较少),这是可能的。打开 TRACE 日志记录,日志将确认这一点。

这些解决方法中的每一个都应该解决这个问题:

  • 使用延迟验收

    <acceptor>
      <lateAcceptanceSize>400</lateAcceptanceSize>
    </acceptor>
    <forager>
      <acceptedCountLimit>1</acceptedCountLimit>
    </forager>
    
  • 使用<entityTabuRatio>代替<entityTabuSize>

  • <entityTabuSize>基于数据集大小的SolverFactory.getSolverConfig(). 不建议!

为什么少于 14 个规划实体?

因为默认情况下你会得到 a<changeMoveSelector>和 a <swapMoveSelector><swapMoveSelector>交换 2 个实体,如果它赢得一步,则两者都成为禁忌。禁忌列表大小是步数,因此如果 7 个交换动作连续赢得步数,则禁忌列表中可以有 14 个实体。

于 2014-05-05T06:55:59.717 回答