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](https://developers.google.com/maps/documentation/route-optimization/cost-model.md.txt) 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`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.ShipmentModel.FIELDS.repeated.google.maps.routeoptimization.v1.TransitionAttributes.google.maps.routeoptimization.v1.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`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#transitionattributes).

> [!IMPORTANT]
> **Key Point:** With **transition attributes** you can implement many business constraints that concern sequences of locations. For example, you can make certain routes less attractive to the optimizer, forbid direct transitions from location A to location B, or ensure that a visit to location A is always followed by a visit to location B.

## 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`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.Shipment.VisitRequest.FIELDS.google.protobuf.Duration.google.maps.routeoptimization.v1.Shipment.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`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.Shipment.VisitRequest.FIELDS.repeated.string.google.maps.routeoptimization.v1.Shipment.VisitRequest.tags)
      in all visit requests that use this parking spot.

   2. [`Vehicle.start_tags`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.Vehicle.FIELDS.repeated.string.google.maps.routeoptimization.v1.Vehicle.start_tags)
      if the vehicle starts its route at this parking spot.

   3. [`Vehicle.end_tags`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.Vehicle.FIELDS.repeated.string.google.maps.routeoptimization.v1.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`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.ShipmentModel.FIELDS.repeated.google.maps.routeoptimization.v1.TransitionAttributes.google.maps.routeoptimization.v1.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`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.TransitionAttributes.FIELDS.string.google.maps.routeoptimization.v1.TransitionAttributes.excluded_src_tag)
      and
      [`TransitionAttributes.dst_tag`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.TransitionAttributes.FIELDS.string.google.maps.routeoptimization.v1.TransitionAttributes.dst_tag)
      to `PARKING_123`.

   2. Set [`TransitionAttributes.delay`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.TransitionAttributes.FIELDS.google.protobuf.Duration.google.maps.routeoptimization.v1.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`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.ShipmentModel.FIELDS.repeated.google.maps.routeoptimization.v1.TransitionAttributes.google.maps.routeoptimization.v1.ShipmentModel.transition_attributes):

   ```json
   {
     "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`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.Shipment.VisitRequest.FIELDS.repeated.string.google.maps.routeoptimization.v1.Shipment.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`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.Shipment.FIELDS.double.google.maps.routeoptimization.v1.Shipment.penalty_cost) to a small number.
3. For each vehicle, add `CLEANED` to
   [`Vehicle.start_tags`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.Vehicle.FIELDS.repeated.string.google.maps.routeoptimization.v1.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`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.Vehicle.FIELDS.repeated.string.google.maps.routeoptimization.v1.Vehicle.end_tags).

5. Add a new entry to [`ShipmentModel.transition_attributes`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.ShipmentModel.FIELDS.repeated.google.maps.routeoptimization.v1.TransitionAttributes.google.maps.routeoptimization.v1.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`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.TransitionAttributes.FIELDS.string.google.maps.routeoptimization.v1.TransitionAttributes.excluded_src_tag)
      to `CLEANED`.

   2. Set [`TransitionAttributes.dst_tag`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.TransitionAttributes.FIELDS.string.google.maps.routeoptimization.v1.TransitionAttributes.dst_tag)
      to `ROUTE_END`.

   3. Set [`TransitionAttributes.delay`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.TransitionAttributes.FIELDS.google.protobuf.Duration.google.maps.routeoptimization.v1.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:

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

> [!CAUTION]
> **Caution:** When you forbid too many transitions, you may completely block access to certain pickups or deliveries, and the optimizer may find only solutions where many or all shipments are skipped.

## 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`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.TransitionAttributes.FIELDS.google.protobuf.Duration.google.maps.routeoptimization.v1.TransitionAttributes.delay)
is best for implementing hard constraints or to express a trade-off in terms of
the time spent.
[`TransitionAttributes.cost`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.TransitionAttributes.FIELDS.double.google.maps.routeoptimization.v1.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`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#transitionattributes)
message must have one of
[`TransitionAttributes.src_tag`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.TransitionAttributes.FIELDS.string.google.maps.routeoptimization.v1.TransitionAttributes.src_tag)
and
[`TransitionAttributes.excluded_src_tag`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.TransitionAttributes.FIELDS.string.google.maps.routeoptimization.v1.TransitionAttributes.excluded_src_tag)
and one of
[`TransitionAttributes.dst_tag`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.TransitionAttributes.FIELDS.string.google.maps.routeoptimization.v1.TransitionAttributes.dst_tag)
and
[`TransitionAttributes.excluded_dst_tag`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.TransitionAttributes.FIELDS.string.google.maps.routeoptimization.v1.TransitionAttributes.excluded_dst_tag).

However, you can match all tags by setting
[`TransitionAttributes.excluded_src_tag`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.TransitionAttributes.FIELDS.string.google.maps.routeoptimization.v1.TransitionAttributes.excluded_src_tag)
or
[`TransitionAttributes.excluded_dst_tag`](https://developers.google.com/maps/documentation/route-optimization/reference/rpc/google.maps.routeoptimization.v1.md.txt#google.maps.routeoptimization.v1.TransitionAttributes.FIELDS.string.google.maps.routeoptimization.v1.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

- [Cost model parameters](https://developers.google.com/maps/documentation/route-optimization/cost-model.md.txt)