IllegalStateException得分求解器配置更改后的损坏

时间:2015-11-03 09:44:14

标签: optaplanner

我在求解器配置中的本地搜索部分如下所示:

<acceptor>
    <lateAcceptanceSize>400</lateAcceptanceSize>
    <entityTabuSize>9</entityTabuSize>
</acceptor>
<forager>
    <acceptedCountLimit>2000</acceptedCountLimit>
</forager>

并且一切正常但是当我将其更改为(我认为可能导致优化的因素):

<acceptor>
<lateAcceptanceSize>600</lateAcceptanceSize>
</acceptor>
<forager>
<acceptedCountLimit>4</acceptedCountLimit>
</forager>

解算器开始工作后我得到了异常

Score corruption: the solution's score (-20hard/-8medium/-4soft) is not the uncorruptedScore (-20hard/-8medium/-8soft)

什么可能导致这个问题? (它只是来自FULL_ASSERT模式的信息)

编辑:

可以将某些东西连接到规则:

// Boundary lessons have to be schedulead at the beginning/end in a day
rule "boundaryLesson"
    when
        $oddzial : Oddzial()
        $boundaryLesson : Lesson(scheduled == true, containsOddzial($oddzial), base.lessonLimits.isBoundaryLesson == true, $base : base)
        exists Lesson(scheduled == true, containsOddzial($oddzial), dayLessonNumber.day == $base.day, base.lessonNumberFrom < $base.lessonNumberFrom)
        and exists Lesson(scheduled == true, containsOddzial($oddzial), dayLessonNumber.day == $base.day, base.lessonNumberTo > $base.lessonNumberTo)
    then
        scoreHolder.addHardConstraintMatch(kcontext, -1);
end

因为,有时我也会得到以下错误:

Score corruption: the workingScore (0hard/-2medium/0soft) is not the uncorruptedScore (-1hard/-2medium/0soft) after completedAction (8848-537:Tuesday-3 {com.pbz.plek.model.simple.DayLessonNr@5924af87 -> com.pbz.plek.model.simple.DayLessonNr@5924af87}):
  The corrupted scoreDirector has no ConstraintMatch(s) which are in excess.
  The corrupted scoreDirector has 1 ConstraintMatch(s) which are missing:
    com.praca.mgr.cp.algorytm.solver/boundaryLesson/level0/[8854-537:Tuesday-2, com.krakfin.pbz.plek.model.simple.Oddzial@c9d4]=-1
  Check your score constraints.

我知道增量分数计算是如何工作的,但我看不出这条规则会出现什么问题

2 个答案:

答案 0 :(得分:1)

在这两种情况下,你都会有潜在的分数损坏,但只有第二种情况才会出现。为了提高生产可靠性,你肯定想要修复它。

请参阅有关“增量分数计算”的文档,以了解损坏分数。通常原因:

  • 影子变量损坏。使用OptaPlanner 6.3.0.Final或更高版本,它将显示为“VariableListener损坏”而不是“分数损坏”并提供更多信息。
  • 错误的自定义移动由于移动错误而移动。通常情况下,这将显示为“撤消移动损坏”而不是“分数损坏”。
  • 错误的自定义Move在第二次完成相同解决方案状态时的行为不同。这将在processWorkingSolutionDuringStep()期间检测到。

如果您使用Drools计算:

  • 导致“分数损坏”的错误分数规则。从OptaPlanner 6.1开始,这是不太可能的,因为编写糟糕的评分规则要困难得多。尝试评论得分规则,找出应该责怪哪一个。
  • Drools中的一个错误。不太可能,但可能。创建一个专门的复制器并提交jira。

如果您使用增量分数计算:

  • 糟糕的Java增量分数计算器。使用<assertScoreDirectorFactor>也可以使用简单的分数计算器。祝你好运。

答案 1 :(得分:0)

总结一下:

  • 我正在使用OptaPlanner 6.3.0.Final和FullAssert环境模式
  • 我删除了自定义移动以排除该部分中的错误可能性
  • 有两个plannig变量:Sala(Room)和DzienNrLekcji(对象包括日期和课程编号)
  • 没有任何影子变量
  • 每个分数都存在损坏分数的问题所以我离开了 只有硬约束规则部分,看起来像这样:

    // ############################################# ###############################     //硬约束     // ################################################# ############################

    // two Lessons at the same time should be in another rooms.
    rule "salaOccupancy"
        when
                $leftLesson : Lesson($id : base.numericId, scheduled == true, $sala : sala)
                not Lesson(scheduled == true, timeCollision($leftLesson), sala == $sala, base.numericId < $id)
                $rightLesson : Lesson(scheduled == true, timeCollision($leftLesson), sala == $sala, base.numericId > $id)
        then
            scoreHolder.addHardConstraintMatch(kcontext, -10);
    end
    
    // each oddzial and nauczyciel can't have two lessons at the same time
    rule "przydzialCollision"
        when
               $przydzialConflict : PrzydzialConflict($leftPrzydzial : leftPrzydzial, $rightPrzydzial : rightPrzydzial)
               $leftLesson : Lesson(scheduled == true, base.przydzial == $leftPrzydzial)
               $rightLesson : Lesson(scheduled == true, base.przydzial == $rightPrzydzial, timeCollision($leftLesson), this != $leftLesson)
            then
                scoreHolder.addHardConstraintMatch(kcontext, -2 * $przydzialConflict.getConflictCount());
    end
    
    // sala's capacity shouldn't be exceeded
    rule "salaCapacity"
        when
            $sala : Sala($capacity : ograniczenia.maxLiczbaUczniow.max)
            $lesson : Lesson(scheduled == true, sala == $sala)
            $limit : LessonStudentLimit(lesson == $lesson, numberOfStudents > $capacity)
        then
            scoreHolder.addHardConstraintMatch(kcontext, -2);
    end
    
    // cannot put lesson into not available time period in Sala or Przydzial
    rule "availability"
        when
            Lesson( scheduled == true , dostepnaSala == false )
            or Lesson( scheduled == true , dostepnyPrzydzial == false)
        then
            scoreHolder.addHardConstraintMatch(kcontext, -2);
    end
    
    // Oddzials cannot have gaps between classes during a day
    rule "gaps"
        when
            $oddzial : Oddzial()
            $dzien : DzienTygodnia()
            $lessonList : ArrayList(LessonBlockCounter.calculateOddzialGaps($lessonList,TimetableSolution.maxLessonNr)>0) from collect (
                Lesson(scheduled == true, containsOddzial($oddzial), dzienNrLekcji.dzien == $dzien)
            )
        then
            scoreHolder.addHardConstraintMatch(kcontext, -5*LessonBlockCounter.calculateOddzialGaps($lessonList,TimetableSolution.maxLessonNr));
    end
    
    // If Przydzial has blocks distribution defined, only one lesson per day is allowed
    rule "blocks"
        when
            $przydzial : Przydzial( ograniczenia.ograniczeniaBlokiLekcyjnePrzydzialu.czyTylkoJednaLekcjaNaDzien.isAktywne() == true )
            $dzien : DzienTygodnia()
            $lessonCount : Number( intValue > 1 ) from accumulate (
                $lesson : Lesson(scheduled == true, base.przydzial == $przydzial,dzienNrLekcji.dzien == $dzien),
                count($lesson)
            )
        then
            scoreHolder.addHardConstraintMatch(kcontext, -2);
    end
    
    // Boundary lessons have to be schedulead at the beginning/end in a day
    rule "boundaryLesson"
        when
            $oddzial : Oddzial()
            $boundaryLesson : Lesson(scheduled == true, containsOddzial($oddzial), base.ograniczeniaLekcja.czyLekcjaGraniczna.aktywne == true, $base : base)
            exists Lesson(scheduled == true, containsOddzial($oddzial), dzienNrLekcji.dzien == $base.dzien, base.lekcjaNrOd < $base.lekcjaNrOd)
            and exists Lesson(scheduled == true, containsOddzial($oddzial), dzienNrLekcji.dzien == $base.dzien, base.lekcjaNrDo > $base.lekcjaNrDo)
        then
            scoreHolder.addHardConstraintMatch(kcontext, -1);
    end
    
    // Linked lessons have to take place at the same time
    rule "linkedLesson"
        when
            $linkedLesson : Lesson(scheduled == true, base.ograniczeniaLekcja.lekcjePolaczone.empty == false, $dzienNrLekcji : dzienNrLekcji)
            Lesson(scheduled == true, base.ograniczeniaLekcja.lekcjePolaczone contains $linkedLesson.base, dzienNrLekcji != $dzienNrLekcji)
        then
            scoreHolder.addHardConstraintMatch(kcontext, -5);
    end
    
    // Linked lessons have to take place at the same time
    rule "scheduledLinkedLesson"
        when
            $linkedLesson : Lesson(scheduled == false, base.ograniczeniaLekcja.lekcjePolaczone.empty == false)
        then
            scoreHolder.addHardConstraintMatch(kcontext, -10*$linkedLesson.getBase().getCzasTrwania());
    end
    
    
    // Lessons have to be placed in the school time boundaries
    rule "schoolTime"
        when
            $lesson : Lesson(scheduled == true, base.czasTrwania > 1 , base.lekcjaNrOd > TimetableSolution.maxLessonNr - base.czasTrwania)
        then
            scoreHolder.addHardConstraintMatch(kcontext, -5);
    end
    
    // Lessons have to be scheduled in one of the preferred sala
    rule "assignedSalaPrzydzialu"
        when
            $lesson : Lesson( scheduled == true,
            sala not memberOf base.przydzial.ograniczenia.perferowaneSale.preferowaneSale.saleList )
        then
           scoreHolder.addHardConstraintMatch(kcontext, -1);
    end
    
    // ############################################################################
    // Medium constraints
    // ############################################################################
    
    //lesson have to have sala and day assigned, not assigned lessons are acceptable in overconstrained problem
    rule "scheduledLesson"
        when
            $lesson : Lesson( scheduled == false )
        then
            scoreHolder.addMediumConstraintMatch(kcontext, -$lesson.getBase().getCzasTrwania());
    end
    

运行算法后,我得到了异常:

2015-11-04 10:39:21,493 [http-8080-3] INFO  org.optaplanner.core.impl.solver.DefaultSolver - Solving started: time spent (426), best score (uninitialized/-160hard/-165medium/0soft), environment mode (FULL_ASSERT), random (JDK with seed 0).
2015-11-04 10:39:23,969 [http-8080-3] INFO  org.optaplanner.core.impl.constructionheuristic.DefaultConstructionHeuristicPhase - Construction Heuristic phase (0) ended: step total (165), time spent (2903), best score (-160hard/-165medium/0soft).
2015-11-04 10:39:24,615 [http-8080-3] ERROR org.apache.struts2.dispatcher.Dispatcher - Exception occurred during processing request: Score corruption: the solution's score (-123hard/-161medium/0soft) is not the uncorruptedScore (-126hard/-160medium/0soft).
java.lang.IllegalStateException: Score corruption: the solution's score (-123hard/-161medium/0soft) is not the uncorruptedScore (-126hard/-160medium/0soft).
    at org.optaplanner.core.impl.score.director.AbstractScoreDirectorFactory.assertScoreFromScratch(AbstractScoreDirectorFactory.java:100)
    at org.optaplanner.core.impl.solver.scope.DefaultSolverScope.assertScoreFromScratch(DefaultSolverScope.java:127)
    at org.optaplanner.core.impl.solver.recaller.BestSolutionRecaller.processWorkingSolutionDuringStep(BestSolutionRecaller.java:107)
    ...

在研究问题后,我非常确定它与增量分数计算和drl文件有关。我认为该问题会导致“间隙”规则,因为“calulateOddzialGaps”方法会检查收集的$ lessonList的日期和课程编号,但在评论此规则问题后仍然存在。任何其他规则都不会在java方法中的WHEN部分使用课程(planningEntity)。有什么不对?我没有任何其他想法......