Model business logic with transition attributes

This guide shows possible uses of transition attributes. It will teach you how to model real-world scenarios on two examples: incorporating time to park the vehicle into the optimized routes, and ensuring that each route ends with a visit to a specific location.

Before you begin

You use transition attributes to add model-specific costs and delays to certain transitions in the optimized routes. These costs and delays are added on top of the transition durations and costs computed from the map data based on the parameters of the vehicle used.

A transition is the segment of the route that connects one location to the next.

A location refers to any of the following points in a vehicle's route:

  • The starting point of the route.
  • A stop where a pickup or a delivery is made.
  • The ending point of the route.

You define all transition attributes for the model by adding them to the list ShipmentModel.transition_attributes. Each element of the list defines one set of transition attributes, and it is matched with transitions in the routes using tags on the start location and the end location of the transition. To learn more about transition attributes, see the reference documentation for TransitionAttributes.

Model real-world scenarios

This section shows two small examples of how to implement real-world business constraints using transition attributes.

Reserve time for parking

In this scenario, the driver needs to park the vehicle before they can visit location A. Location B is nearby, and the driver can use the same parking spot for both visits. If the driver visits B right after A, they save time because they don't need to leave the parking spot and park the vehicle again. In the Route Optimization API, you can use transition attributes to add extra time to park the vehicle only when the driver moves from one parking spot to other.

When you model the parking time separately from visit durations, you make routes where visits that use the same parking are grouped take less time. You make the model more precise, and you also make the optimizer prefer routes where the visits are grouped.

Use the following steps to do this in a Route Optimization API request:

  1. Use VisitRequest.duration only for the time needed to perform the visit. For example, to hand over the package and collect a signature from the customer.

  2. For each distinct parking spot used in the model, use a new tag that is not used for anything else in the model, for example PARKING_123.

  3. Add this tag to the following:

    1. VisitRequest.tags in all visit requests that use this parking spot.

    2. Vehicle.start_tags if the vehicle starts its route at this parking spot.

    3. Vehicle.end_tags if the vehicle starts ends its route at this parking spot.

  4. For each new parking tag, add an entry to ShipmentModel.transition_attributes that adds a delay for parking when coming from a different parking spot by doing the following:

    1. Set TransitionAttributes.excluded_src_tag and TransitionAttributes.dst_tag to PARKING_123.

    2. Set TransitionAttributes.delay to the time needed to park the vehicle.

    For example, when the tag of a location is PARKING_123 and it takes 150 seconds to park the vehicle, you add the following entry to ShipmentModel.transition_attributes:

    {
      "excluded_src_tag": "PARKING_123",
      "dst_tag": "PARKING_123",
      "delay": "150s"
    }
    

Mandatory cleaning at the end of the route

In this scenario, the vehicle needs to be cleaned at the end of the route, with the following additional constraints:

  • The cleaning is done at a specialized cleaning facility before returning to the vehicle depot. The optimized route uses the best cleaning facility based on its location and the locations of the pickups and deliveries made by the vehicle.
  • After the cleaning, the vehicle must not perform any additional pickups or deliveries.
  • The time to drive there and clean the vehicle counts against the working hours of the driver, and it must fit into the maximal duration of the route.

You model this requirement by allowing only routes that are either empty or whose last visit is to a cleaning facility. In the Route Optimization API, you do this by prohibiting transitions to the ending waypoint of the route from any location except from the cleaning facility or from the starting point of the route:

  1. Pick two new tags that are not used anywhere in the model, for example CLEANED and ROUTE_END. The former is for locations where the vehicle is or becomes clean, and the latter is for end of the route.
  2. For each vehicle, add a new delivery-only shipment that represents the visit to a cleaning facility with the following attributes:
    1. Each cleaning facility location should be represented as a delivery visit request of this shipment.
    2. Add CLEANED to VisitRequest.tags of each visit request of the cleaning facility shipment. It signals that a vehicle leaving this location is clean. Other visit requests in the model shouldn't use this tag so that the vehicle is considered "not clean" when leaving them.
    3. Allow the optimizer to skip this shipment when the vehicle is otherwise unused by setting its penalty_cost to a small number.
  3. For each vehicle, add CLEANED to Vehicle.start_tags. This is used to mark the vehicle as clean before it performs any pickups or deliveries, assuming that it has been cleaned at the end of the previous working day, and allow it to go from the starting waypoint directly to its end waypoint. Even if such routes don't happen in practice, allowing this scenario helps the optimizer search for optimized routes more efficiently.

  4. For each vehicle, add ROUTE_END to Vehicle.end_tags.

  5. Add a new entry to ShipmentModel.transition_attributes that prohibits vehicles from arriving at the vehicle end waypoint when they are not clean, with the following properties:

    1. Set TransitionAttributes.excluded_src_tag to CLEANED.

    2. Set TransitionAttributes.dst_tag to ROUTE_END.

    3. Set TransitionAttributes.delay to a large value. When you make the delay longer than the maximal route duration, you effectively prohibit the optimizer from using this transition in a route.

    For example, when the time scale of the model is one working day, you can use a delay of 24 hours (86400 seconds) to prohibit the transition to the end of the route from anywhere except a cleaning facility and the start of the route:

    {
      "excluded_src_tag": "CLEANED",
      "dst_tag": "ROUTE_END",
      "delay": "86400s"
    }
    

How to choose between delays and costs

The choice between delays and costs depends on the nature of the implemented business logic and constraints. Setting TransitionAttributes.delay is best for implementing hard constraints or to express a trade-off in terms of the time spent. TransitionAttributes.cost fits better when implementing soft preferences or trade-offs expressed as an additional cost. You may combine delays and costs arbitrarily when both time spent and cost are concerned.

The vehicle cleaning example uses a very long delay, because cleaning the vehicle at the end of the route is a hard requirement and the long delay prevents the optimizer from ignoring the requirement. If you set only a cost, the optimizer could choose to skip the cleaning, if it finds a way to make up for the cost elsewhere, for example by delivering more shipments in the time "saved" by not cleaning the vehicle.

The parking example uses a short delay that corresponds to the additional time needed to park the vehicle. You could also use costs in combination with delays, if the driver stops at a paid parking lot.

How to add a transition attribute that matches all visit requests

The examples above use transition attributes that match locations that have a given tag, or locations that don't have the tag. But what if you need to add transition attributes that apply to all transitions?

You can't just omit the tags, because each TransitionAttributes message must have one of TransitionAttributes.src_tag and TransitionAttributes.excluded_src_tag and one of TransitionAttributes.dst_tag and TransitionAttributes.excluded_dst_tag.

However, you can match all tags by setting TransitionAttributes.excluded_src_tag or TransitionAttributes.excluded_dst_tag to a tag that is not used anywhere in the model. This will match all locations that don't have this tag, but since you intentionally chose a tag that is not used by any location, these transition attributes will match all locations.

Further reading