具有链式规划变量的 PartitionedSearch 的最佳实践?

Best practices for PartitionedSearch with chained planning variables?

我一直在试验 TWVSP 的修改版本,使用链式规划变量和锚点。与 Standstill 的 TWVSP 示例类似的方法。

看起来像这样:

Vehicle1 (AnchorShadowVarialbe) - Trip1_1 - Trip1_2 - ... - Trip1_k1
...
VehicleM (Anchor) - TripM_1 - TripM_2 - ... - TripM_kM

行程已分配给车辆。每个行程都有一个 start/end 时间戳。一辆车不能服务 2 次重叠的行程。

为了加快求解器的速度,我开始将搜索 space 拆分为具有 SolutionPartitioner 实施的分区,因为可以根据行程将它们分组到集群中。目标是为集群获取出行车辆分配,但我只有一个车队。

第一个问题,我不能使用相同的车辆对象,因为求解器会失败并显示 IllegalStateException - 没关系,我为每个分区克隆车辆列表并分配给这些车辆的行程克隆对象。

然后,我捕捉到 phaseEnded 事件,其中 phaseScopePartitionedSearchPhaseScope 的一个实例(即分区搜索结束事件)并将行程重新分配给原始车辆对象(确保指针指向每个方向上的相同对象(类似于 previousStandstill,nextVisit 形成示例),以及手动修复链条,因此集群链仅锚定到原始车辆,并且它们链接在一起:

vehicleX - (partition0.trip(0)) - ... - (partition(i-1).trip(last)) - (partition(i).trip(0)) - ... 

然后我更新解决方案范围内的解决方案:

partitionPhaseScope.getSolverScope().setBestSolution(mergedSolution);

我想按照文档中的建议在分区后进行本地搜索,但出现错误:

Caused by: java.lang.IllegalStateException: The move thread with moveThreadIndex (65) has thrown an exception. Relayed here in the parent thread.
    at org.optaplanner.core.impl.heuristic.thread.OrderByMoveIndexBlockingQueue.take(OrderByMoveIndexBlockingQueue.java:147)
    at org.optaplanner.core.impl.localsearch.decider.MultiThreadedLocalSearchDecider.forageResult(MultiThreadedLocalSearchDecider.java:188)
    at org.optaplanner.core.impl.localsearch.decider.MultiThreadedLocalSearchDecider.decideNextStep(MultiThreadedLocalSearchDecider.java:159)
    at org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase.solve(DefaultLocalSearchPhase.java:71)
    at org.optaplanner.core.impl.solver.AbstractSolver.runPhases(AbstractSolver.java:99)
    at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:189)
    at com.mynamespace.planner.v4.rest.ScheduleResource.startSolving(ScheduleResource.java:221)
    at com.mynamespace.planner.v4.rest.ScheduleResource.solve(ScheduleResource.java:112)
    at com.mynamespace.planner.v4.rest.ScheduleResource_ClientProxy.solve(ScheduleResource_ClientProxy.zig:156)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:167)
    at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
    at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:638)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:504)
    at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget(ResourceMethodInvoker.java:454)
    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:456)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:417)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:391)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:68)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:488)
    ... 49 more
Caused by: java.lang.NullPointerException
    at org.drools.core.common.NamedEntryPoint.update(NamedEntryPoint.java:353)
    at org.drools.core.common.NamedEntryPoint.update(NamedEntryPoint.java:338)
    at org.drools.core.impl.StatefulKnowledgeSessionImpl.update(StatefulKnowledgeSessionImpl.java:1587)
    at org.drools.core.impl.StatefulKnowledgeSessionImpl.update(StatefulKnowledgeSessionImpl.java:1559)
    at org.optaplanner.core.impl.score.stream.drools.DroolsConstraintSession.update(DroolsConstraintSession.java:47)
    at org.optaplanner.core.impl.score.director.stream.ConstraintStreamScoreDirector.afterVariableChanged(ConstraintStreamScoreDirector.java:141)
    at org.optaplanner.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.retract(SingletonInverseVariableListener.java:96)
    at org.optaplanner.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.beforeVariableChanged(SingletonInverseVariableListener.java:46)
    at org.optaplanner.core.impl.domain.variable.listener.support.VariableListenerSupport.beforeVariableChanged(VariableListenerSupport.java:174)
    at org.optaplanner.core.impl.score.director.AbstractScoreDirector.beforeVariableChanged(AbstractScoreDirector.java:433)
    at org.optaplanner.core.impl.score.director.AbstractScoreDirector.changeVariableFacade(AbstractScoreDirector.java:446)
    at org.optaplanner.core.impl.heuristic.selector.move.generic.chained.ChainedChangeMove.doMoveOnGenuineVariables(ChainedChangeMove.java:74)
    at org.optaplanner.core.impl.heuristic.move.AbstractMove.doMove(AbstractMove.java:36)
    at org.optaplanner.core.impl.heuristic.move.AbstractMove.doMove(AbstractMove.java:31)
    at org.optaplanner.core.impl.score.director.AbstractScoreDirector.doAndProcessMove(AbstractScoreDirector.java:178)
    at org.optaplanner.core.impl.heuristic.thread.MoveThreadRunner.run(MoveThreadRunner.java:146)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)

知道缺少什么吗? 是否有关于如何使用链式规划变量进行 PartitionedSearch 的文档?

谢谢。

FactHandle 可能为 null,所以至少应该改进错误消息:https://issues.redhat.com/browse/PLANNER-2222

至于实际的错误,您的 Partitioned 可能会创建一个分区,该分区在 @ProblemFactCollectionProperty@PlanningEntityCollectionProperty 中没有这个事实,但在链接实体的尾随链中确实有它 (=考虑“更新”它的到达时间等可变侦听器。