Jsprit:无法添加多个相关作业

Jsprit : Can't add multiple related jobs

我正在使用 JSPRIT 来解决路由和旅行者问题。它实际上适用于简单的约束(时间、容量等)。但是我试图实现 "Related jobs" 约束。对于简单的案例,我成功了,比如第 7 个工作在列表中的第 1 个工作之前提供。

我想对一些服务进行分组优化。例如,我想强制 7 号在 1 号之前服务,21 号在 13 号之前服务。也许还有更多。

当我尝试这个时,结果顺序只排在第 7 个之前,但第 21 个不在第 13 个之前,有时甚至不在同一条路线上。

这比 Related jobs in JSprit 更复杂。

谁能举个例子?有人试过吗?

public final static int PERSON_DIMENSION_INDEX = 0;
public final static boolean VEHICLE_RETURNS_AT_DEPOT = false;
public final static Location TEST_VEHICLE_LOCATION = Location.newInstance(48.856614, 2.352222);
public final static int TEST_VEHICLE_LOCATION_INDEX = 0;
public final static int MAX_INCREMENT = 25;

public final static boolean USE_DISTANCE_MATRIX = true;
public final static boolean ADD_TIME_CONSTRAINTS = false;
public final static boolean USE_ONE_BEFORE_ANOTHER_CONSTRAINT = true;
private static final boolean PLOT_RESULT = false;

public static void main(String[] args) {
    /*
     * Date today : 8 o'clock
     */

    // .getDirections(contextTest, "27 rue jacques louvel tessier", "10 rue
    // de geispitzen");
    Calendar c = new GregorianCalendar();
    c.set(Calendar.HOUR_OF_DAY, 8); // anything 0 - 23
    c.set(Calendar.MINUTE, 0);
    c.set(Calendar.SECOND, 0);
    Date d1 = c.getTime(); // the midnight, that's the first second of the
                            // day.
    System.out.println("Date today 8h clock");
    System.out.println(d1.toString());
    System.out.println(d1.getTime() / 1000);
    final long TODAY_START_TIME = d1.getTime() / 1000;
    /*
     * Here, get the vehicles types.
     */
    List<TypeVehicle> vehicleTypes = getVehiclesTypesFromDatabase();

    /*
     * Built de jsprit vehicle types.
     */
    Map<String, VehicleTypeImpl> jSpritvVehicleTypes = new HashMap<String, VehicleTypeImpl>();

    for (TypeVehicle vehicleType : vehicleTypes) {
        String vehicleTypeId = String.valueOf(vehicleType.getId());
        int vehicleCapacity = vehicleType.getAvailableSeats();
        VehicleTypeImpl jSpritvVehicleType = VehicleTypeImpl.Builder.newInstance(vehicleTypeId)
                .addCapacityDimension(PERSON_DIMENSION_INDEX, vehicleCapacity).build();

        jSpritvVehicleTypes.put(vehicleTypeId, jSpritvVehicleType);
    }

    /*
     * Here, get the vehicles.
     */
    List<Vehicle> vehicles = getVehiclesFromDatabase();
    /*
     * Here, build the vehicles.
     */
    Map<String, VehicleImpl> jSpritVehicles = new HashMap<String, VehicleImpl>();
    for (Vehicle Vehicle : vehicles) {
        String vehicleId = String.valueOf(Vehicle.getId());
        List<Habilitation> habilitations = Vehicle.getHabilitations();
        String thisVehicleTypeId = String.valueOf(Vehicle.getType());
        VehicleTypeImpl vehicleType = jSpritvVehicleTypes.get(thisVehicleTypeId);
        Skills skills = null;
        for (Habilitation habilitation : habilitations) {
            skills = new Skills.Builder().addSkill(habilitation.getLabel()).build();
        }

        VehicleImpl vehicleImpl = VehicleImpl.Builder.newInstance(vehicleId).setType(vehicleType).addSkills(skills)
                .setStartLocation(TEST_VEHICLE_LOCATION).setEarliestStart(TODAY_START_TIME).build();
        jSpritVehicles.put(vehicleId, vehicleImpl);
    }

    /*
     * Here, get the spots to serve (pickups and deliveries)
     */

    List<Place> places = getSpots(); // This will change a lot.
    List<Service> services = new ArrayList<Service>();

    int increment = 0;
    String[] origins = new String[MAX_INCREMENT];
    String[] destinations = new String[MAX_INCREMENT];

    origins[0] = TEST_VEHICLE_LOCATION.getCoordinate().getX() + "," + TEST_VEHICLE_LOCATION.getCoordinate().getY();
    destinations[0] = TEST_VEHICLE_LOCATION.getCoordinate().getX() + ","
            + TEST_VEHICLE_LOCATION.getCoordinate().getY();
    increment++;

    for (Place place : places) {

        if (increment < MAX_INCREMENT) {
            String id = String.valueOf(increment);
            int dimensionValue = place.getAccessibility();
            double lat = place.getLat();
            double lng = place.getLng();
            Location location = Location.newInstance(lat, lng);
            Service.Builder builder = Service.Builder.newInstance(id)
                    .addSizeDimension(PERSON_DIMENSION_INDEX, dimensionValue).setLocation(location);
            /*
             * TIME CONSTRAINTS
             */
            if (ADD_TIME_CONSTRAINTS) {
                int random = randomNumber(0, 43200); // 12 hours of possible
                                                        // work. 8am / 8pm
                System.out.println("Time windows : " + new Date((TODAY_START_TIME + random) * 1000).toString()
                        + " / " + new Date((TODAY_START_TIME + random + 1800) * 1000).toString());
                builder.addTimeWindow(TODAY_START_TIME + random, TODAY_START_TIME + random + 1800);
            }
            Service service = builder.build();
            services.add(service);
            origins[increment] = lat + "," + lng;
            destinations[increment] = lat + "," + lng;
            increment++;
        }

    }
    /*
     * Here, get the constraints (ex : one before another)
     */

    /*
     * Here, get the time limits
     */

    VehicleRoutingTransportCostsMatrix costsMatrix;
    if (USE_DISTANCE_MATRIX) {
        /*
         * Distances matrix
         */
        VehicleRoutingTransportCostsMatrix.Builder vrtcMatrix = VehicleRoutingTransportCostsMatrix.Builder
                .newInstance(true);
        GeoApiContext context = null;
        costsMatrix = generateCostMatrix(origins, destinations, vrtcMatrix, context);
    }

    /*
     * Init jsprit
     */
    VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance();
    vrpBuilder.addAllVehicles(jSpritVehicles.values()).addAllJobs(services);
    vrpBuilder.setFleetSize(FleetSize.INFINITE);

    if (USE_DISTANCE_MATRIX) {
        System.out.println("Using DISTANCE MATRIX...");
        vrpBuilder = vrpBuilder.setRoutingCost(costsMatrix);
    } else {
        System.out.println("NOT Using DISTANCE MATRIX...");
    }
    VehicleRoutingProblem problem = vrpBuilder.build();
    /*
     * get the algorithm out-of-the-box.
     */
    VehicleRoutingAlgorithm algorithm;
    if (USE_ONE_BEFORE_ANOTHER_CONSTRAINT) {
        /**
         * Adding constraints...
         */



        String before = "11";
        String after = "9";



        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.setObjectiveFunction(costCalculator);
        algorithm = vraBuilder.build();

    } else {

        algorithm = Jsprit.createAlgorithm(problem);

    }

    /*
     * and search a solution which returns a collection of solutions (here
     * only one solution is constructed)
     */
    Collection<VehicleRoutingProblemSolution> solutions = algorithm.searchSolutions();

    /*
     * use the static helper-method in the utility class Solutions to get
     * the best solution (in terms of least costs)
     */
    for (VehicleRoutingProblemSolution vehicleRoutingProblemSolution : solutions) {
        System.out.println("Solution #"
                + ((List<VehicleRoutingProblemSolution>) solutions).indexOf(vehicleRoutingProblemSolution));
        System.out.println(vehicleRoutingProblemSolution.getCost());
    }
    VehicleRoutingProblemSolution bestSolution = Solutions.bestOf(solutions);
    SolutionPrinter.print(problem, bestSolution, Print.VERBOSE);
    new GraphStreamViewer(problem, bestSolution).labelWith(Label.ID).setRenderDelay(100).display();
    if(PLOT_RESULT){
        new GraphStreamViewer(problem, bestSolution).labelWith(Label.ID).setRenderDelay(100).display();
    }


}

我终于知道了。我只是忘了将生成的成本添加到成本计算器中。见下文:

    final List<RewardAndPenaltiesThroughSoftConstraints> contribs = new ArrayList<RewardAndPenaltiesThroughSoftConstraints>();
        for (Integer id : forcedOrdersList.keySet()) {
            List<String> order= forcedOrdersList.get(id);
            String before = order.get(0);
            String after = order.get(1);
            constraintManager.addConstraint(new OneJobBeforeAnother(stateManager, before, after));
            contribs.add(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);
                    for (RewardAndPenaltiesThroughSoftConstraints contrib : contribs) {
                        costs+=contrib.getCosts(route);
                    }
                }
                return costs;
            }

        };