使用HardActivityConstraint在Jsprit中强加顺序

时间:2015-03-06 08:19:43

标签: java jsprit

在重新解决先前解决的问题(当然还有一些新数据)的情况下,通常不可能在给出车辆的第一次分配后重新分配。驱动程序已经开始了,任何新的解决方案都必须考虑到:

  • 工作必须保持不变(不能分配给其他车辆)
  • 作为第一个分配给他的活动必须在未来的解决方案中保持如此

为了简单起见,我使用单一车辆方案,并且只尝试强加第二个子弹(即确保某个活动将成为解决方案中的第一个)。

这是我定义约束的方式:

new HardActivityConstraint()
{
    @Override
    public ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct,
                                       double prevActDepTime)
    {
        String locationId = newAct.getLocation().getId();

        //  we want to make sure that any solution will have "C1" as its first activity
        boolean activityShouldBeFirst = locationId.equals("C1");

        boolean attemptingToInsertFirst = (prevAct instanceof Start);

        if (activityShouldBeFirst && !attemptingToInsertFirst)
            return ConstraintsStatus.NOT_FULFILLED_BREAK;

        if (!activityShouldBeFirst && attemptingToInsertFirst)
            return ConstraintsStatus.NOT_FULFILLED;

        return ConstraintsStatus.FULFILLED;
    }
}

这就是我构建算法的方法:

VehicleRoutingAlgorithmBuilder vraBuilder;
vraBuilder = new VehicleRoutingAlgorithmBuilder(vrpProblem, "schrimpf.xml"); 
vraBuilder.addCoreConstraints();
vraBuilder.addDefaultCostCalculators();

StateManager stateManager = new StateManager(vrpProblem);
ConstraintManager constraintManager = new ConstraintManager(vrpProblem, stateManager);
constraintManager.addConstraint(new HardActivityConstraint() { ... }, Priority.HIGH);
vraBuilder.setStateAndConstraintManager(stateManager, constraintManager);

VehicleRoutingAlgorithm algorithm = vraBuilder.build();

结果并不好。我只获得分配了一份工作的解决方案(具有所需活动的工作)。在调试中,很明显作业插入迭代考虑了许多可行的选项,这些选项似乎完全解决了问题,但在底线,算法返回的最佳解决方案不包括其他作业。

更新:更令人惊讶的是,当我在超过5辆车的场景中使用约束时,它运行正常(最差的结果是1辆车)。

如果需要,我很乐意附上更多信息。

由于 扎克

1 个答案:

答案 0 :(得分:0)

首先,您可以使用初始路线确保某些工作从一开始就需要分配给特定车辆(参见example)。

其次,要确保在开始和初始作业(位置)之间不插入任何活动(例如示例中的“C1”),您需要按照定义HardActConstraint的方式禁止它,只需修改它以便newAct永远不能介于prevAct = Start和nextAct = act(C1)。

第三,关于您的更新,请记住算法的本质是破坏解决方案的一部分(删除多个作业)并再次重新创建解决方案(插入未分配的作业)。目前,schrimpf算法相对于作业总数破坏了许多工作,即随机破坏的noJobs = 0.5 * totalNoJobs和径向破坏的0.3 * totalNoJobs。如果您的问题非常小,则要删除的作业份额可能不够。这将在下一版本中发生变化,您可以使用开箱即用的算法,该算法定义了需要删除的绝对最小作业。暂时修改algorithmConfig.xml中的共享。