JSprit: неподписанные задания, пока есть транспортные средства

Я использую JSprit для решения проблемы нескольких коммивояжеров с временными окнами: у меня есть продавец, который должен посетить n клиентов в течение недели как можно быстрее с временными ограничениями. Я настроил автомобиль на каждый день и услугу для каждого клиента.

Это на самом деле работает, но я не могу найти способ справиться с заданиями, запланированными на определенное время. Например, у продавца есть 15 клиентов, но в понедельник в 15:00 у него назначена встреча. Я хотел бы, чтобы маршрут был оптимизирован с учетом этого ограничения.

Я пытался указать работу с временным окном, соответствующим встрече, но работа обычно не назначается, а машины все еще есть! Я пытался применить необходимые навыки на работе и на транспортном средстве, прикрепленном к нужному дню, и тот же результат.

Итак, вот мои проблемы: - Я не могу установить работу как обязательную (не может быть не назначенной) и в определенное время. - Я не понимаю, почему есть незанятые рабочие места, а есть неиспользуемые автомобили.

РЕДАКТИРОВАТЬ: я изменяю свой код, чтобы добавить приоритет и увеличить временные окна в качестве совета. Не повезло, задание 1 все еще не назначено.

public class test {


private ArrayList<Service> serviceList; // list of services
private ArrayList<Location> locationList; // list of location
private Location dep;   // departure & arrival for each day
private String parameters;
// distances between locations
private double times[][]; 



public test()
{
    this.serviceList = new ArrayList<>();
    this.locationList = new ArrayList<>();
    this.parameters = "";

}

public void test(int nb)
{
   this.times = new double[nb+1][nb+1];

   // collect data from json for the list of geocoded services

     try (InputStream in = new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8));
     JsonReader read = javax.json.Json.createReader(in)) {

        JsonObject obj = read.readObject();
        JsonArray results = obj.getJsonArray("clients");

        // departure
        dep = Location.Builder.newInstance().setId("0").setIndex(0).setCoordinate(Coordinate.newInstance(48.88626, 2.22135)).build();
        // parameters for OSRM request
        parameters = "&loc=48.88626, 2.22135";

        locationList.add(dep);

        // get locations from json
       for(int i=0; i<nb;i++)
       {
           JsonObject result = results.getValuesAs(JsonObject.class).get(i);
           Location l = Location.Builder.newInstance().setId(Integer.toString(i+1)).setIndex(i+1).setCoordinate(Coordinate.newInstance(Double.valueOf(result.getString("latitude")), Double.valueOf(result.getString("longitude")))).build();
           locationList.add(l);
           // parameters for OSRM request
           parameters += "&loc="+result.getString("latitude")+","+result.getString("longitude");
       }

    // Vehicles     
    VehicleTypeImpl.Builder vehicleTypeBuilder = VehicleTypeImpl.Builder.newInstance("vehicleType");
    VehicleType vehicleType = vehicleTypeBuilder.setCostPerTransportTime(1).setCostPerWaitingTime(1).setCostPerServiceTime(1).setCostPerDistance(0).build();

    // vehicule for each day
    VehicleImpl vehicleMon = VehicleImpl.Builder.newInstance("vehicleMon").setType(vehicleType).setStartLocation(dep).setEarliestStart(32400).setLatestArrival(64800).build();
    VehicleImpl vehicleTue = VehicleImpl.Builder.newInstance("vehicleTue").setType(vehicleType).setStartLocation(dep).setEarliestStart(118800).setLatestArrival(151200).build();
    VehicleImpl vehicleWed = VehicleImpl.Builder.newInstance("vehicleWed").setType(vehicleType).setStartLocation(dep).setEarliestStart(205200).setLatestArrival(237600).build();
    VehicleImpl vehicleThu = VehicleImpl.Builder.newInstance("vehicleThu").setType(vehicleType).setStartLocation(dep).setEarliestStart(291600).setLatestArrival(324000).build();
    VehicleImpl vehicleFry = VehicleImpl.Builder.newInstance("vehicleFry").setType(vehicleType).setStartLocation(dep).setEarliestStart(378000).setLatestArrival(410400).build();
    VehicleImpl vehicleSat = VehicleImpl.Builder.newInstance("vehicleSat").setType(vehicleType).setStartLocation(dep).setEarliestStart(464400).setLatestArrival(496800).build();
    VehicleImpl vehicleSun = VehicleImpl.Builder.newInstance("vehicleSun").setType(vehicleType).setStartLocation(dep).setEarliestStart(550800).setLatestArrival(583200).build();


    // the job with a specific time window which represent a scheduled appointment 
    Service serviceTW = Service.Builder.newInstance(Integer.toString(1))
                .setName("1")
                .addTimeWindow(124200, 131400) // 2 hours window
                .setPriority(1) // high priority 
                .setServiceTime(3600).setLocation(locationList.get(1)).build(); 

        serviceList.add(serviceTW);

    // jobs
    for(int i=1; i<nb; i++) // we skip the first one which is above
    {
        Service service = Service.Builder.newInstance(Integer.toString(i+1))
                .setName(Integer.toString(i+1))
                .setPriority(3) // low priority
                .addTimeWindow(32400, 583200) // time window for all week
                .setServiceTime(3600).setLocation(locationList.get(i+1)).build();
        serviceList.add(service);
    }

    // matrix time
        // retrieve traveling time from OSRM
    getOSRM_times();

    VehicleRoutingTransportCostsMatrix.Builder costMatrixBuilder = VehicleRoutingTransportCostsMatrix.Builder.newInstance(true);

    for(int i=0; i<nb ;i++)
    {
        for(int j=0; j<nb+1;j++)
        {
            costMatrixBuilder.addTransportTime(Integer.toString(i), Integer.toString(j), times[i][j]/10);
        }

    }
    // adding vehicles
    VehicleRoutingTransportCosts costMatrix = costMatrixBuilder.build();
    VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance();
    vrpBuilder
            .addVehicle(vehicleMon)
            .addVehicle(vehicleTue)
            .addVehicle(vehicleWed)
            .addVehicle(vehicleThu)
            .addVehicle(vehicleFry)
            .addVehicle(vehicleSat)
            .addVehicle(vehicleSun)
            .addAllJobs(serviceList).setFleetSize(FleetSize.FINITE).setRoutingCost(costMatrix);


// Problem/Solution
VehicleRoutingProblem problem = vrpBuilder.build();
VehicleRoutingAlgorithm algorithm = Jsprit.createAlgorithm(problem);
Collection<VehicleRoutingProblemSolution> solutions = algorithm.searchSolutions();
VehicleRoutingProblemSolution bestSolution = Solutions.bestOf(solutions);

File dir = new File("output");
    // if the directory does not exist, create it
    if (!dir.exists()){
        System.out.println("creating directory ./output");
        boolean result = dir.mkdir();  
        if(result) System.out.println("./output created");  
    }


    // RESULTS
        //xml
    new VrpXMLWriter(problem, solutions).write("output/problem-with-solution.xml");
        // console
   SolutionPrinter.print(problem, bestSolution, Print.VERBOSE);
        // image
   new Plotter(problem,bestSolution).setLabel(Plotter.Label.ID).plot("output/solution.png", "solution");

   }catch (IOException ex) {Logger.getLogger(Json.class.getName()).log(Level.SEVERE, null, ex);}

}

Я заметил, что если я изменю день моей постоянной работы, назначенный на этот день автомобиль всегда будет заполнен, а работа не назначена.


person why    schedule 26.05.2016    source источник
comment
Я предлагаю вам взглянуть на новейший выпуск, который включает приоритет задания. Тем не менее, я считаю, что вы ошибаетесь в своем утверждении о наличии транспортных средств. У вас есть только одно транспортное средство, которое доступно в каждый отдельный день и без приоритетов, у jsprit нет причин отдавать предпочтение вашей фиксированной встрече по сравнению с другими заданиями, которые вы выделили с несколькими временными окнами.   -  person roganjosh    schedule 30.05.2016
comment
Соглашусь с вами, когда моя работа не занята, автомобиль в это время весь день занят другими работами. Тем не менее, видя это, почему jsprit не назначил другой автомобиль для этих работ и не использовал VehicleTue для фиксированной работы 1 ?   -  person why    schedule 31.05.2016


Ответы (1)


На самом деле, я думаю, вы слишком усложнили определение временных окон обслуживания, что может вызвать проблему. Jsprit не может назначить услугу, когда нет доступных транспортных средств. Итак, я бы продолжал ежедневно определять ваши транспортные средства, как и вы, но я бы создавал каждое задание с помощью .addTimeWindow(32400, 583200). Каждый из них можно обслуживать только один раз и только тогда, когда транспортное средство доступно, поэтому оно служит цели, которую вы ищете, без огромных накладных расходов на жонглирование временными окнами.

Если фиксированное обязательство важнее, чем то, что можно было бы выполнить в любой момент в течение недели, самое время протестировать новую функцию приоритеты работы :)

person roganjosh    schedule 30.05.2016