Связанные вакансии в JSprit, один перед другим случаем: IllegalArgumentException

Этот вопрос связан с этой темой: Связанные вакансии в JSprit

Я пытаюсь использовать ограничение "один перед другим", но сталкиваюсь с java.lang.IllegalArgumentException: arg не должен быть нулевым . Похоже, что Cap2 емкости имеет значение null при расчете максимальной емкости. Я действительно не понимаю, почему.

:(

У вас есть идея по этому поводу?

Кстати, у меня версия 1.6.2. ТС за помощь.

        String before = "2";
        String after = "11";

        final StateManager stateManager = new StateManager(problem);
        stateManager.addStateUpdater(new JobsInRouteMemorizer(stateManager));



        ConstraintManager constraintManager = new ConstraintManager(problem, stateManager);
        constraintManager.addConstraint(new OneJobBeforeAnother(stateManager, before, after));

        final RewardAndPenaltiesThroughSoftConstraints contrib = new RewardAndPenaltiesThroughSoftConstraints(problem, before, after);
        SolutionCostCalculator costCalculator = new SolutionCostCalculator() {

            @Override
            public double getCosts(VehicleRoutingProblemSolution solution) {
                double costs = 0.;
                List<VehicleRoute> routes = (List<VehicleRoute>) solution.getRoutes();
                for(VehicleRoute route : routes){
                    costs+=route.getVehicle().getType().getVehicleCostParams().fix;
                    costs+=stateManager.getRouteState(route, InternalStates.COSTS, Double.class);
                    costs+=contrib.getCosts(route);
                }
                return costs;
            }

        };
        VehicleRoutingAlgorithmBuilder vraBuilder = new VehicleRoutingAlgorithmBuilder(problem,
                "algorithmConfig.xml");
        vraBuilder.addCoreConstraints();
        vraBuilder.setStateAndConstraintManager(stateManager, constraintManager);
        vraBuilder.addDefaultCostCalculators();
        vraBuilder.setObjectiveFunction(costCalculator);
        algorithm = vraBuilder.build();



public class JobsInRouteMemorizer implements StateUpdater, ActivityVisitor {
private StateManager stateManager;
private VehicleRoute route;



public JobsInRouteMemorizer(StateManager stateManager) {
    super();
    this.stateManager = stateManager;
}

@Override
public void begin(VehicleRoute route) {
    this.route=route;
}

@Override
public void visit(TourActivity activity) {
    if(activity instanceof JobActivity){
        String jobId = ((JobActivity) activity).getJob().getId();
        StateId stateId = stateManager.createStateId(jobId);
        System.out.println(stateId.getIndex());
        System.out.println(stateId.toString());
        stateManager.putProblemState(stateId, VehicleRoute.class, this.route);
    }

}

@Override
public void finish() {}

}

person Cédric Alexis    schedule 29.03.2016    source источник
comment
Привет @Cédric Alexis, твоя проблема решена? Я мог столкнуться с той же проблемой. Спасибо.   -  person He Huang    schedule 28.07.2016


Ответы (1)


Краткий ответ: вы не можете создавать экземпляры StateId на лету. Все экземпляры StateId должны быть сгенерированы до запуска алгоритма. Посмотрите более подробный ответ, почему делать это по-прежнему не очень хорошая идея, и вам следует подумать о редизайне.

Анализ: я столкнулся с той же проблемой и проследил ее до того, как создаются экземпляры StateId в StateManager:

public StateId createStateId(String name) {
    if (createdStateIds.containsKey(name)) return createdStateIds.get(name);
    if (stateIndexCounter >= activityStates[0].length) {
        activityStates = new Object[vrp.getNuActivities() + 1][stateIndexCounter + 1];
        vehicleDependentActivityStates = new Object[nuActivities][nuVehicleTypeKeys][stateIndexCounter + 1];
        routeStatesArr = new Object[vrp.getNuActivities()+1][stateIndexCounter+1];
        vehicleDependentRouteStatesArr = new Object[nuActivities][nuVehicleTypeKeys][stateIndexCounter+1];
        problemStates = new Object[stateIndexCounter+1];
    }
    StateId id = StateFactory.createId(name, stateIndexCounter);
    incStateIndexCounter();
    createdStateIds.put(name, id);
    return id;
}

Каждый раз, когда вы создаете новый StateId и для состояний больше нет места, старые массивы состояний перезаписываются более длинной версией, чтобы освободить место для вашего нового состояния (в начале есть место для 30 StateId, некоторые уже используются самим JSprit). ). Как видите, старые элементы не копируются, поэтому здесь происходит состояние гонки между UpdateLoads, которое устанавливает состояние, используемое как cap2, вашим кодом, который генерирует новый StateId и перезаписывает текущее состояние, и UpdateMaxCapacityUtilisationAtActivitiesByLookingForwardInRoute, который читается государство (которого больше не существует).

Учитывая, что этот код расширяет массивы только на единицу, очень неэффективно иметь много StateId, так как для каждого нового StateId все массивы должны создаваться заново. Чтобы смягчить это, я использовал только один StateId в своем коде и сохранил в нем Map<String, VehicleRoute>:

Map<String, VehicleRoute> routeMapping = Optional.ofNullable(stateManager.getProblemState(stateId, Map.class)).orElse(new ConcurrentHashMap<>())

Таким образом, у вас не закончатся экземпляры StateId, и вы сможете хранить связи между неограниченным количеством заданий.

person sgift    schedule 23.08.2016