VRP with Skills

It occurs very often that the jobs that your vehicles need to execute require specific skills - some special conditions of transportation that need to be met. It may happen when a customer requires some service like a plumber or electrician, or some delivery or pickup requires a vehicle equipped with a refrigerator compartment. In such cases, you will need to specify those requirements as skills for your vehicles to fit the customer job constraints.

Let’s consider a situation when we have 7 different jobs, and some of them require different skills:

  • job_1 - no skills required
  • job_2 - no skills required
  • job_3 - fridge
  • job_4 - plumber
  • job_5 - plumber
  • job_6 - electrician
  • job_7 - no skills required

Let's assume that for executing those jobs, we have two types of vehicles in our fleet - with the fridge and plumber skills and with enough capacity, but we do not have any vehicle with the electrician skills. The problem for such constraint will look as follows:

Problem

{
  "fleet": {
    "types": [
      {
        "id": "qwert1234",
        "profile": "car_1",
        "costs": { "fixed": 7.0, "distance": 0.005, "time": 0.02 },
        "shifts": [
          {
            "start": {
              "time": "2021-08-27T08:03:00Z",
              "location": { "lat": 52.530971, "lng": 13.384915 }
            },
            "end": {
              "time": "2021-08-27T16:03:00Z",
              "location": { "lat": 52.45717902261775, "lng": 13.45675245690121 }
            }
          }
        ],
        "capacity": [50],
        "skills": ["plumber"],
        "amount": 2
      },
      {
        "id": "abcde1234",
        "profile": "car_1",
        "costs": { "fixed": 7.0, "distance": 0.0, "time": 8.0 },
        "shifts": [
          {
            "start": {
              "time": "2021-08-27T08:03:00Z",
              "location": { "lat": 52.530971, "lng": 13.384915 }
            },
            "end": {
              "time": "2021-08-27T16:03:00Z",
              "location": { "lat": 52.45717902261775, "lng": 13.45675245690121 }
            }
          }
        ],
        "capacity": [50],
        "skills": ["fridge"],
        "amount": 2
      }
    ],
    "profiles": [{ "type": "car", "name": "car_1" }]
  },
  "plan": {
    "jobs": [
      {
        "id": "job_1",
        "tasks": {
          "pickups": [
            {
              "places": [
                {
                  "location": {
                    "lat": 52.57433728008193,
                    "lng": 13.414626318800853
                  },
                  "duration": 900
                }
              ],
              "demand": [2]
            }
          ]
        }
      },
      {
        "id": "job_2",
        "tasks": {
          "pickups": [
            {
              "places": [
                {
                  "location": {
                    "lat": 52.54252808824531,
                    "lng": 13.384239353645219
                  },
                  "duration": 720
                }
              ],
              "demand": [2]
            }
          ]
        }
      },
      {
        "id": "job_3",
        "skills": ["fridge"],
        "tasks": {
          "deliveries": [
            {
              "places": [
                {
                  "location": {
                    "lat": 52.558716170353655,
                    "lng": 13.31823634661218
                  },
                  "duration": 240
                }
              ],
              "demand": [2]
            }
          ]
        }
      },
      {
        "id": "job_4",
        "skills": ["plumber"],
        "tasks": {
          "deliveries": [
            {
              "places": [
                {
                  "location": {
                    "lat": 52.45348677617264,
                    "lng": 13.321459421457485
                  },
                  "duration": 60
                }
              ],
              "demand": [2]
            }
          ]
        }
      },
      {
        "id": "job_5",
        "skills": ["plumber"],
        "tasks": {
          "deliveries": [
            {
              "places": [
                {
                  "location": {
                    "lat": 52.53284583231377,
                    "lng": 13.432577803817928
                  },
                  "duration": 300
                }
              ],
              "demand": [2]
            }
          ]
        }
      },
      {
        "id": "job_6",
        "skills": ["elecrician"],
        "tasks": {
          "deliveries": [
            {
              "places": [
                {
                  "location": { "lat": 52.5528458, "lng": 13.4425778 },
                  "duration": 300
                }
              ],
              "demand": [2]
            }
          ]
        }
      },
      {
        "id": "job_7",
        "tasks": {
          "deliveries": [
            {
              "places": [
                {
                  "location": { "lat": 52.532845, "lng": 13.425778 },
                  "duration": 300
                }
              ],
              "demand": [2]
            }
          ]
        }
      }
    ]
  }
}

Solution

The solution for this problem will look as follows:

{
    "statistic": {
        "cost": 21677.89,
        "distance": 70151,
        "duration": 9621,
        "times": {
            "driving": 7101,
            "serving": 2520,
            "waiting": 0,
            "break": 0
        }
    },
    "tours": [
        {
            "vehicleId": "qwert1234_2",
            "typeId": "qwert1234",
            "stops": [
                {
                    "location": {
                        "lat": 52.530971,
                        "lng": 13.384915
                    },
                    "time": {
                        "arrival": "2021-08-27T08:03:00Z",
                        "departure": "2021-08-27T08:03:00Z"
                    },
                    "load": [
                        6
                    ],
                    "activities": [
                        {
                            "jobId": "departure",
                            "type": "departure"
                        }
                    ]
                },
                {
                    "location": {
                        "lat": 52.54252808824531,
                        "lng": 13.38423935364522
                    },
                    "time": {
                        "arrival": "2021-08-27T08:07:51Z",
                        "departure": "2021-08-27T08:19:51Z"
                    },
                    "load": [
                        8
                    ],
                    "activities": [
                        {
                            "jobId": "job_2",
                            "type": "pickup"
                        }
                    ]
                },
                {
                    "location": {
                        "lat": 52.57433728008193,
                        "lng": 13.414626318800853
                    },
                    "time": {
                        "arrival": "2021-08-27T08:33:37Z",
                        "departure": "2021-08-27T08:48:37Z"
                    },
                    "load": [
                        10
                    ],
                    "activities": [
                        {
                            "jobId": "job_1",
                            "type": "pickup"
                        }
                    ]
                },
                {
                    "location": {
                        "lat": 52.532845,
                        "lng": 13.425778
                    },
                    "time": {
                        "arrival": "2021-08-27T09:04:29Z",
                        "departure": "2021-08-27T09:09:29Z"
                    },
                    "load": [
                        8
                    ],
                    "activities": [
                        {
                            "jobId": "job_7",
                            "type": "delivery"
                        }
                    ]
                },
                {
                    "location": {
                        "lat": 52.53284583231377,
                        "lng": 13.432577803817928
                    },
                    "time": {
                        "arrival": "2021-08-27T09:12:02Z",
                        "departure": "2021-08-27T09:17:02Z"
                    },
                    "load": [
                        6
                    ],
                    "activities": [
                        {
                            "jobId": "job_5",
                            "type": "delivery"
                        }
                    ]
                },
                {
                    "location": {
                        "lat": 52.45348677617264,
                        "lng": 13.321459421457485
                    },
                    "time": {
                        "arrival": "2021-08-27T09:45:06Z",
                        "departure": "2021-08-27T09:46:06Z"
                    },
                    "load": [
                        4
                    ],
                    "activities": [
                        {
                            "jobId": "job_4",
                            "type": "delivery"
                        }
                    ]
                },
                {
                    "location": {
                        "lat": 52.45717902261775,
                        "lng": 13.45675245690121
                    },
                    "time": {
                        "arrival": "2021-08-27T09:58:56Z",
                        "departure": "2021-08-27T09:58:56Z"
                    },
                    "load": [
                        0
                    ],
                    "activities": [
                        {
                            "jobId": "arrival",
                            "type": "arrival"
                        }
                    ]
                }
            ],
            "statistic": {
                "cost": 350.89,
                "distance": 40954,
                "duration": 6956,
                "times": {
                    "driving": 4676,
                    "serving": 2280,
                    "waiting": 0,
                    "break": 0
                }
            }
        },
        {
            "vehicleId": "abcde1234_1",
            "typeId": "abcde1234",
            "stops": [
                {
                    "location": {
                        "lat": 52.530971,
                        "lng": 13.384915
                    },
                    "time": {
                        "arrival": "2021-08-27T08:03:00Z",
                        "departure": "2021-08-27T08:03:00Z"
                    },
                    "load": [
                        2
                    ],
                    "activities": [
                        {
                            "jobId": "departure",
                            "type": "departure"
                        }
                    ]
                },
                {
                    "location": {
                        "lat": 52.558716170353655,
                        "lng": 13.31823634661218
                    },
                    "time": {
                        "arrival": "2021-08-27T08:19:19Z",
                        "departure": "2021-08-27T08:23:19Z"
                    },
                    "load": [
                        0
                    ],
                    "activities": [
                        {
                            "jobId": "job_3",
                            "type": "delivery"
                        }
                    ]
                },
                {
                    "location": {
                        "lat": 52.45717902261775,
                        "lng": 13.45675245690121
                    },
                    "time": {
                        "arrival": "2021-08-27T08:47:25Z",
                        "departure": "2021-08-27T08:47:25Z"
                    },
                    "load": [
                        0
                    ],
                    "activities": [
                        {
                            "jobId": "arrival",
                            "type": "arrival"
                        }
                    ]
                }
            ],
            "statistic": {
                "cost": 21327.0,
                "distance": 29197,
                "duration": 2665,
                "times": {
                    "driving": 2425,
                    "serving": 240,
                    "waiting": 0,
                    "break": 0
                }
            }
        }
    ],
    "unassigned": [
        {
            "jobId": "job_6",
            "reasons": [
                {
                    "code": "SKILL_CONSTRAINT",
                    "description": "cannot serve required skill"
                }
            ]
        }
    ]
}

Solution Evaluation

As we can see from the solution, the jobs with the respective demand and skills were assigned to the respective vehicles, as expected. We can see the total statistics of the execution that includes cost, distance, and duration with exact timing for driving, serving, waiting and breaks. At the same time, we see that one job with the skill electrician didn't match any of the vehicle skills, thus it wasn't assigned to any vehicle.

Note that it is also possible to specify multiple skills for a single vehicle. In that case, a vehicle should have all those skills that a job requires to be able to serve it. A vehicle can also have additional skills that are not required by that particular job which won't affect optimization.

results matching ""

    No results matching ""