xref: /aosp_15_r20/external/googleapis/google/cloud/optimization/v1/fleet_routing.proto (revision d5c09012810ac0c9f33fe448fb6da8260d444cc9)
1// Copyright 2023 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15syntax = "proto3";
16
17package google.cloud.optimization.v1;
18
19import "google/api/annotations.proto";
20import "google/api/client.proto";
21import "google/api/field_behavior.proto";
22import "google/cloud/optimization/v1/async_model.proto";
23import "google/longrunning/operations.proto";
24import "google/protobuf/duration.proto";
25import "google/protobuf/timestamp.proto";
26import "google/type/latlng.proto";
27
28option go_package = "cloud.google.com/go/optimization/apiv1/optimizationpb;optimizationpb";
29option java_multiple_files = true;
30option java_outer_classname = "FleetRoutingProto";
31option java_package = "com.google.cloud.optimization.v1";
32
33// A service for optimizing vehicle tours.
34//
35// Validity of certain types of fields:
36//
37//   * `google.protobuf.Timestamp`
38//     * Times are in Unix time: seconds since 1970-01-01T00:00:00+00:00.
39//     * seconds must be in [0, 253402300799],
40//       i.e. in [1970-01-01T00:00:00+00:00, 9999-12-31T23:59:59+00:00].
41//     * nanos must be unset or set to 0.
42//   * `google.protobuf.Duration`
43//     * seconds must be in [0, 253402300799],
44//       i.e. in [1970-01-01T00:00:00+00:00, 9999-12-31T23:59:59+00:00].
45//     * nanos must be unset or set to 0.
46//   * `google.type.LatLng`
47//     * latitude must be in [-90.0, 90.0].
48//     * longitude must be in [-180.0, 180.0].
49//     * at least one of latitude and longitude must be non-zero.
50service FleetRouting {
51  option (google.api.default_host) = "cloudoptimization.googleapis.com";
52  option (google.api.oauth_scopes) =
53      "https://www.googleapis.com/auth/cloud-platform";
54
55  // Sends an `OptimizeToursRequest` containing a `ShipmentModel` and returns an
56  // `OptimizeToursResponse` containing `ShipmentRoute`s, which are a set of
57  // routes to be performed by vehicles minimizing the overall cost.
58  //
59  // A `ShipmentModel` model consists mainly of `Shipment`s that need to be
60  // carried out and `Vehicle`s that can be used to transport the `Shipment`s.
61  // The `ShipmentRoute`s assign `Shipment`s to `Vehicle`s. More specifically,
62  // they assign a series of `Visit`s to each vehicle, where a `Visit`
63  // corresponds to a `VisitRequest`, which is a pickup or delivery for a
64  // `Shipment`.
65  //
66  // The goal is to provide an assignment of `ShipmentRoute`s to `Vehicle`s that
67  // minimizes the total cost where cost has many components defined in the
68  // `ShipmentModel`.
69  rpc OptimizeTours(OptimizeToursRequest) returns (OptimizeToursResponse) {
70    option (google.api.http) = {
71      post: "/v1/{parent=projects/*/locations/*}:optimizeTours"
72      body: "*"
73      additional_bindings {
74        post: "/v1/{parent=projects/*}:optimizeTours"
75        body: "*"
76      }
77    };
78  }
79
80  // Optimizes vehicle tours for one or more `OptimizeToursRequest`
81  // messages as a batch.
82  //
83  // This method is a Long Running Operation (LRO). The inputs for optimization
84  // (`OptimizeToursRequest` messages) and outputs (`OptimizeToursResponse`
85  // messages) are read/written from/to Cloud Storage in user-specified
86  // format. Like the `OptimizeTours` method, each `OptimizeToursRequest`
87  // contains a `ShipmentModel` and returns an `OptimizeToursResponse`
88  // containing `ShipmentRoute`s, which are a set of routes to be performed by
89  // vehicles minimizing the overall cost.
90  rpc BatchOptimizeTours(BatchOptimizeToursRequest)
91      returns (google.longrunning.Operation) {
92    option (google.api.http) = {
93      post: "/v1/{parent=projects/*/locations/*}:batchOptimizeTours"
94      body: "*"
95      additional_bindings {
96        post: "/v1/{parent=projects/*}:batchOptimizeTours"
97        body: "*"
98      }
99    };
100    option (google.longrunning.operation_info) = {
101      response_type: "BatchOptimizeToursResponse"
102      metadata_type: "AsyncModelMetadata"
103    };
104  }
105}
106
107// Request to be given to a tour optimization solver which defines the
108// shipment model to solve as well as optimization parameters.
109message OptimizeToursRequest {
110  // Defines how the solver should handle the request. In all modes but
111  // `VALIDATE_ONLY`, if the request is invalid, you will receive an
112  // `INVALID_REQUEST` error. See
113  // [max_validation_errors][google.cloud.optimization.v1.OptimizeToursRequest.max_validation_errors]
114  // to cap the number of errors returned.
115  enum SolvingMode {
116    // Solve the model.
117    DEFAULT_SOLVE = 0;
118
119    // Only validates the model without solving it: populates as many
120    // [OptimizeToursResponse.validation_errors][google.cloud.optimization.v1.OptimizeToursResponse.validation_errors]
121    // as possible.
122    VALIDATE_ONLY = 1;
123
124    // Only populates
125    // [OptimizeToursResponse.validation_errors][google.cloud.optimization.v1.OptimizeToursResponse.validation_errors]
126    // or
127    // [OptimizeToursResponse.skipped_shipments][google.cloud.optimization.v1.OptimizeToursResponse.skipped_shipments],
128    // and doesn't actually solve the rest of the request (`status` and `routes`
129    // are unset in the response).
130    // If infeasibilities in `injected_solution_constraint` routes are detected
131    // they are populated in the
132    // [OptimizeToursResponse.validation_errors][google.cloud.optimization.v1.OptimizeToursResponse.validation_errors]
133    // field and
134    // [OptimizeToursResponse.skipped_shipments][google.cloud.optimization.v1.OptimizeToursResponse.skipped_shipments]
135    // is left empty.
136    //
137    // *IMPORTANT*: not all infeasible shipments are returned here, but only the
138    // ones that are detected as infeasible during preprocessing.
139    DETECT_SOME_INFEASIBLE_SHIPMENTS = 2;
140  }
141
142  // Mode defining the behavior of the search, trading off latency versus
143  // solution quality. In all modes, the global request deadline is enforced.
144  enum SearchMode {
145    // Unspecified search mode, equivalent to `RETURN_FAST`.
146    SEARCH_MODE_UNSPECIFIED = 0;
147
148    // Stop the search after finding the first good solution.
149    RETURN_FAST = 1;
150
151    // Spend all the available time to search for better solutions.
152    CONSUME_ALL_AVAILABLE_TIME = 2;
153  }
154
155  // Required. Target project and location to make a call.
156  //
157  // Format: `projects/{project-id}/locations/{location-id}`.
158  //
159  // If no location is specified, a region will be chosen automatically.
160  string parent = 1 [(google.api.field_behavior) = REQUIRED];
161
162  // If this timeout is set, the server returns a response before the timeout
163  // period has elapsed or the server deadline for synchronous requests is
164  // reached, whichever is sooner.
165  //
166  // For asynchronous requests, the server will generate a solution (if
167  // possible) before the timeout has elapsed.
168  google.protobuf.Duration timeout = 2;
169
170  // Shipment model to solve.
171  ShipmentModel model = 3;
172
173  // By default, the solving mode is `DEFAULT_SOLVE` (0).
174  SolvingMode solving_mode = 4;
175
176  // Search mode used to solve the request.
177  SearchMode search_mode = 6;
178
179  // Guide the optimization algorithm in finding a first solution that is
180  // similar to a previous solution.
181  //
182  // The model is constrained when the first solution is built.
183  // Any shipments not performed on a route are implicitly skipped in the first
184  // solution, but they may be performed in successive solutions.
185  //
186  // The solution must satisfy some basic validity assumptions:
187  //
188  //   * for all routes, `vehicle_index` must be in range and not be duplicated.
189  //   * for all visits, `shipment_index` and `visit_request_index` must be
190  //     in range.
191  //   * a shipment may only be referenced on one route.
192  //   * the pickup of a pickup-delivery shipment must be performed before
193  //     the delivery.
194  //   * no more than one pickup alternative or delivery alternative of
195  //     a shipment may be performed.
196  //   * for all routes, times are increasing (i.e., `vehicle_start_time
197  //     <= visits[0].start_time <= visits[1].start_time ...
198  //     <= vehicle_end_time`).
199  //   * a shipment may only be performed on a vehicle that is allowed. A
200  //     vehicle is allowed if
201  //     [Shipment.allowed_vehicle_indices][google.cloud.optimization.v1.Shipment.allowed_vehicle_indices]
202  //     is empty or its `vehicle_index` is included in
203  //     [Shipment.allowed_vehicle_indices][google.cloud.optimization.v1.Shipment.allowed_vehicle_indices].
204  //
205  // If the injected solution is not feasible, a validation error is not
206  // necessarily returned and an error indicating infeasibility may be returned
207  // instead.
208  repeated ShipmentRoute injected_first_solution_routes = 7;
209
210  // Constrain the optimization algorithm to find a final solution that is
211  // similar to a previous solution. For example, this may be used to freeze
212  // portions of routes which have already been completed or which are to be
213  // completed but must not be modified.
214  //
215  // If the injected solution is not feasible, a validation error is not
216  // necessarily returned and an error indicating infeasibility may be returned
217  // instead.
218  InjectedSolutionConstraint injected_solution_constraint = 8;
219
220  // If non-empty, the given routes will be refreshed, without modifying their
221  // underlying sequence of visits or travel times: only other details will be
222  // updated. This does not solve the model.
223  //
224  // As of 2020/11, this only populates the polylines of non-empty routes and
225  // requires that `populate_polylines` is true.
226  //
227  // The `route_polyline` fields of the passed-in routes may be inconsistent
228  // with route `transitions`.
229  //
230  // This field must not be used together with `injected_first_solution_routes`
231  // or `injected_solution_constraint`.
232  //
233  // `Shipment.ignore` and `Vehicle.ignore` have no effect on the behavior.
234  // Polylines are still populated between all visits in all non-empty routes
235  // regardless of whether the related shipments or vehicles are ignored.
236  repeated ShipmentRoute refresh_details_routes = 9;
237
238  // If true:
239  //
240  //   * uses
241  //   [ShipmentRoute.vehicle_label][google.cloud.optimization.v1.ShipmentRoute.vehicle_label]
242  //   instead of `vehicle_index` to
243  //     match routes in an injected solution with vehicles in the request;
244  //     reuses the mapping of original
245  //     [ShipmentRoute.vehicle_index][google.cloud.optimization.v1.ShipmentRoute.vehicle_index]
246  //     to new
247  //     [ShipmentRoute.vehicle_index][google.cloud.optimization.v1.ShipmentRoute.vehicle_index]
248  //     to update
249  //     [ConstraintRelaxation.vehicle_indices][google.cloud.optimization.v1.InjectedSolutionConstraint.ConstraintRelaxation.vehicle_indices]
250  //     if non-empty, but the mapping must be unambiguous (i.e., multiple
251  //     `ShipmentRoute`s must not share the same original `vehicle_index`).
252  //   * uses
253  //   [ShipmentRoute.Visit.shipment_label][google.cloud.optimization.v1.ShipmentRoute.Visit.shipment_label]
254  //   instead of `shipment_index`
255  //     to match visits in an injected solution with shipments in the request;
256  //   * uses
257  //   [SkippedShipment.label][google.cloud.optimization.v1.SkippedShipment.label]
258  //   instead of
259  //   [SkippedShipment.index][google.cloud.optimization.v1.SkippedShipment.index]
260  //   to
261  //     match skipped shipments in the injected solution with request
262  //     shipments.
263  //
264  // This interpretation applies to the `injected_first_solution_routes`,
265  // `injected_solution_constraint`, and `refresh_details_routes` fields.
266  // It can be used when shipment or vehicle indices in the request have
267  // changed since the solution was created, perhaps because shipments or
268  // vehicles have been removed from or added to the request.
269  //
270  // If true, labels in the following categories must appear at most once in
271  // their category:
272  //
273  //   * [Vehicle.label][google.cloud.optimization.v1.Vehicle.label] in the
274  //   request;
275  //   * [Shipment.label][google.cloud.optimization.v1.Shipment.label] in the
276  //   request;
277  //   * [ShipmentRoute.vehicle_label][google.cloud.optimization.v1.ShipmentRoute.vehicle_label] in the injected solution;
278  //   * [SkippedShipment.label][google.cloud.optimization.v1.SkippedShipment.label] and [ShipmentRoute.Visit.shipment_label][google.cloud.optimization.v1.ShipmentRoute.Visit.shipment_label] in
279  //     the injected solution (except pickup/delivery visit pairs, whose
280  //     `shipment_label` must appear twice).
281  //
282  // If a `vehicle_label` in the injected solution does not correspond to a
283  // request vehicle, the corresponding route is removed from the solution
284  // along with its visits. If a `shipment_label` in the injected solution does
285  // not correspond to a request shipment, the corresponding visit is removed
286  // from the solution. If a
287  // [SkippedShipment.label][google.cloud.optimization.v1.SkippedShipment.label]
288  // in the injected solution does not correspond to a request shipment, the
289  // `SkippedShipment` is removed from the solution.
290  //
291  // Removing route visits or entire routes from an injected solution may
292  // have an effect on the implied constraints, which may lead to change in
293  // solution, validation errors, or infeasibility.
294  //
295  // NOTE: The caller must ensure that each
296  // [Vehicle.label][google.cloud.optimization.v1.Vehicle.label] (resp.
297  // [Shipment.label][google.cloud.optimization.v1.Shipment.label]) uniquely
298  // identifies a vehicle (resp. shipment) entity used across the two relevant
299  // requests: the past request that produced the `OptimizeToursResponse` used
300  // in the injected solution and the current request that includes the injected
301  // solution. The uniqueness checks described above are not enough to guarantee
302  // this requirement.
303  bool interpret_injected_solutions_using_labels = 10;
304
305  // Consider traffic estimation in calculating `ShipmentRoute` fields
306  // [Transition.travel_duration][google.cloud.optimization.v1.ShipmentRoute.Transition.travel_duration],
307  // [Visit.start_time][google.cloud.optimization.v1.ShipmentRoute.Visit.start_time],
308  // and `vehicle_end_time`; in setting the
309  // [ShipmentRoute.has_traffic_infeasibilities][google.cloud.optimization.v1.ShipmentRoute.has_traffic_infeasibilities]
310  // field, and in calculating the
311  // [OptimizeToursResponse.total_cost][google.cloud.optimization.v1.OptimizeToursResponse.total_cost]
312  // field.
313  bool consider_road_traffic = 11;
314
315  // If true, polylines will be populated in response `ShipmentRoute`s.
316  bool populate_polylines = 12;
317
318  // If true, polylines will be populated in response
319  // [ShipmentRoute.transitions][google.cloud.optimization.v1.ShipmentRoute.transitions].
320  // Note that in this case, the polylines will also be populated in the
321  // deprecated `travel_steps`.
322  bool populate_transition_polylines = 13;
323
324  // If this is set, then the request can have a deadline
325  // (see https://grpc.io/blog/deadlines) of up to 60 minutes.
326  // Otherwise, the maximum deadline is only 30 minutes.
327  // Note that long-lived requests have a significantly larger (but still small)
328  // risk of interruption.
329  bool allow_large_deadline_despite_interruption_risk = 14;
330
331  // If true, travel distances will be computed using geodesic distances instead
332  // of Google Maps distances, and travel times will be computed using geodesic
333  // distances with a speed defined by `geodesic_meters_per_second`.
334  bool use_geodesic_distances = 15;
335
336  // When `use_geodesic_distances` is true, this field must be set and defines
337  // the speed applied to compute travel times. Its value must be at least 1.0
338  // meters/seconds.
339  optional double geodesic_meters_per_second = 16;
340
341  // Truncates the number of validation errors returned. These errors are
342  // typically attached to an INVALID_ARGUMENT error payload as a BadRequest
343  // error detail (https://cloud.google.com/apis/design/errors#error_details),
344  // unless solving_mode=VALIDATE_ONLY: see the
345  // [OptimizeToursResponse.validation_errors][google.cloud.optimization.v1.OptimizeToursResponse.validation_errors]
346  // field.
347  // This defaults to 100 and is capped at 10,000.
348  optional int32 max_validation_errors = 5;
349
350  // Label that may be used to identify this request, reported back in the
351  // [OptimizeToursResponse.request_label][google.cloud.optimization.v1.OptimizeToursResponse.request_label].
352  string label = 17;
353
354  // Deprecated: Use
355  // [OptimizeToursRequest.populate_transition_polylines][google.cloud.optimization.v1.OptimizeToursRequest.populate_transition_polylines]
356  // instead. If true, polylines will be populated in response
357  // [ShipmentRoute.transitions][google.cloud.optimization.v1.ShipmentRoute.transitions].
358  // Note that in this case, the polylines will also be populated in the
359  // deprecated `travel_steps`.
360  bool populate_travel_step_polylines = 20 [deprecated = true];
361}
362
363// Response after solving a tour optimization problem containing the routes
364// followed by each vehicle, the shipments which have been skipped and the
365// overall cost of the solution.
366message OptimizeToursResponse {
367  // Overall metrics, aggregated over all routes.
368  message Metrics {
369    // Aggregated over the routes. Each metric is the sum (or max, for loads)
370    // over all
371    // [ShipmentRoute.metrics][google.cloud.optimization.v1.ShipmentRoute.metrics]
372    // fields of the same name.
373    AggregatedMetrics aggregated_route_metrics = 1;
374
375    // Number of mandatory shipments skipped.
376    int32 skipped_mandatory_shipment_count = 2;
377
378    // Number of vehicles used. Note: if a vehicle route is empty and
379    // [Vehicle.used_if_route_is_empty][google.cloud.optimization.v1.Vehicle.used_if_route_is_empty]
380    // is true, the vehicle is considered used.
381    int32 used_vehicle_count = 3;
382
383    // The earliest start time for a used vehicle, computed as the minimum over
384    // all used vehicles of
385    // [ShipmentRoute.vehicle_start_time][google.cloud.optimization.v1.ShipmentRoute.vehicle_start_time].
386    google.protobuf.Timestamp earliest_vehicle_start_time = 4;
387
388    // The latest end time for a used vehicle, computed as the maximum over all
389    // used vehicles of
390    // [ShipmentRoute.vehicle_end_time][google.cloud.optimization.v1.ShipmentRoute.vehicle_end_time].
391    google.protobuf.Timestamp latest_vehicle_end_time = 5;
392
393    // Cost of the solution, broken down by cost-related request fields.
394    // The keys are proto paths, relative to the input OptimizeToursRequest,
395    // e.g. "model.shipments.pickups.cost", and the values are the total cost
396    // generated by the corresponding cost field, aggregated over the whole
397    // solution. In other words, costs["model.shipments.pickups.cost"] is the
398    // sum of all pickup costs over the solution. All costs defined in the model
399    // are reported in detail here with the exception of costs related to
400    // TransitionAttributes that are only reported in an aggregated way as of
401    // 2022/01.
402    map<string, double> costs = 10;
403
404    // Total cost of the solution. The sum of all values in the costs map.
405    double total_cost = 6;
406  }
407
408  // Routes computed for each vehicle; the i-th route corresponds to the i-th
409  // vehicle in the model.
410  repeated ShipmentRoute routes = 1;
411
412  // Copy of the
413  // [OptimizeToursRequest.label][google.cloud.optimization.v1.OptimizeToursRequest.label],
414  // if a label was specified in the request.
415  string request_label = 3;
416
417  // The list of all shipments skipped.
418  repeated SkippedShipment skipped_shipments = 4;
419
420  // List of all the validation errors that we were able to detect
421  // independently. See the "MULTIPLE ERRORS" explanation for the
422  // [OptimizeToursValidationError][google.cloud.optimization.v1.OptimizeToursValidationError]
423  // message.
424  repeated OptimizeToursValidationError validation_errors = 5;
425
426  // Duration, distance and usage metrics for this solution.
427  Metrics metrics = 6;
428
429  // Deprecated: Use
430  // [Metrics.total_cost][google.cloud.optimization.v1.OptimizeToursResponse.Metrics.total_cost]
431  // instead. Total cost of the solution. This takes into account all costs:
432  // costs per per hour and travel hour, fixed vehicle costs, unperformed
433  // shipment penalty costs, global duration cost, etc.
434  double total_cost = 2 [deprecated = true];
435}
436
437// Request to batch optimize tours as an asynchronous operation.
438// Each input file should contain one `OptimizeToursRequest`, and each output
439// file will contain one `OptimizeToursResponse`. The request contains
440// information to read/write and parse the files. All the input and output files
441// should be under the same project.
442message BatchOptimizeToursRequest {
443  // Information for solving one optimization model asynchronously.
444  message AsyncModelConfig {
445    // User defined model name, can be used as alias by users to keep track of
446    // models.
447    string display_name = 1;
448
449    // Required. Information about the input model.
450    InputConfig input_config = 2 [(google.api.field_behavior) = REQUIRED];
451
452    // Required. The desired output location information.
453    OutputConfig output_config = 3 [(google.api.field_behavior) = REQUIRED];
454
455    // If this is set, the model will be solved in the checkpoint mode. In this
456    // mode, the input model can have a deadline longer than 30 mins without the
457    // risk of interruption. The model will be solved in multiple short-running
458    // stages. Each stage generates an intermediate checkpoint
459    // and stores it in the user's Cloud Storage buckets. The checkpoint
460    // mode should be preferred over
461    // allow_large_deadline_despite_interruption_risk since it prevents the risk
462    // of interruption.
463    bool enable_checkpoints = 4;
464  }
465
466  // Required. Target project and location to make a call.
467  //
468  // Format: `projects/{project-id}/locations/{location-id}`.
469  //
470  // If no location is specified, a region will be chosen automatically.
471  string parent = 1 [(google.api.field_behavior) = REQUIRED];
472
473  // Required. Input/Output information each purchase model, such as file paths
474  // and data formats.
475  repeated AsyncModelConfig model_configs = 2
476      [(google.api.field_behavior) = REQUIRED];
477}
478
479// Response to a `BatchOptimizeToursRequest`. This is returned in
480// the LRO Operation after the operation is complete.
481message BatchOptimizeToursResponse {}
482
483// A shipment model contains a set of shipments which must be performed by a
484// set of vehicles, while minimizing the overall cost, which is the sum of:
485//
486// * the cost of routing the vehicles (sum of cost per total time, cost per
487//   travel time, and fixed cost over all vehicles).
488// * the unperformed shipment penalties.
489// * the cost of the global duration of the shipments
490message ShipmentModel {
491  // Specifies a duration and distance matrix from visit and vehicle start
492  // locations to visit and vehicle end locations.
493  message DurationDistanceMatrix {
494    // Specifies a row of the duration and distance matrix.
495    message Row {
496      // Duration values for a given row. It must have as many elements as
497      // [ShipmentModel.duration_distance_matrix_dst_tags][google.cloud.optimization.v1.ShipmentModel.duration_distance_matrix_dst_tags].
498      repeated google.protobuf.Duration durations = 1;
499
500      // Distance values for a given row. If no costs or constraints refer to
501      // distances in the model, this can be left empty; otherwise it must have
502      // as many elements as `durations`.
503      repeated double meters = 2;
504    }
505
506    // Specifies the rows of the duration and distance matrix. It must have as
507    // many elements as
508    // [ShipmentModel.duration_distance_matrix_src_tags][google.cloud.optimization.v1.ShipmentModel.duration_distance_matrix_src_tags].
509    repeated Row rows = 1;
510
511    // Tag defining to which vehicles this duration and distance matrix applies.
512    // If empty, this applies to all vehicles, and there can only be a single
513    // matrix.
514    //
515    // Each vehicle start must match exactly one matrix, i.e. exactly one of
516    // their `start_tags` field must match the `vehicle_start_tag` of a matrix
517    // (and of that matrix only).
518    //
519    // All matrices must have a different `vehicle_start_tag`.
520    string vehicle_start_tag = 2;
521  }
522
523  // A precedence rule between two events (each event is the pickup or the
524  // delivery of a shipment): the "second" event has to start at least
525  // `offset_duration` after "first" has started.
526  //
527  // Several precedences can refer to the same (or related) events, e.g.,
528  // "pickup of B happens after delivery of A" and "pickup of C happens after
529  // pickup of B".
530  //
531  // Furthermore, precedences only apply when both shipments are performed and
532  // are otherwise ignored.
533  message PrecedenceRule {
534    // Shipment index of the "first" event. This field must be specified.
535    optional int32 first_index = 1;
536
537    // Indicates if the "first" event is a delivery.
538    bool first_is_delivery = 3;
539
540    // Shipment index of the "second" event. This field must be specified.
541    optional int32 second_index = 2;
542
543    // Indicates if the "second" event is a delivery.
544    bool second_is_delivery = 4;
545
546    // The offset between the "first" and "second" event. It can be negative.
547    google.protobuf.Duration offset_duration = 5;
548  }
549
550  // Deprecated: Use top level
551  // [BreakRule][google.cloud.optimization.v1.ShipmentModel.BreakRule] instead.
552  // Rules to generate time breaks for a vehicle (e.g. lunch
553  // breaks). A break is a contiguous period of time during which the vehicle
554  // remains idle at its current position and cannot perform any visit. A break
555  // may occur:
556  //
557  // * during the travel between two visits (which includes the time right
558  //   before or right after a visit, but not in the middle of a visit), in
559  //   which case it extends the corresponding transit time between the visits
560  // * before the vehicle start (the vehicle may not start in the middle of
561  //   a break), in which case it does not affect the vehicle start time.
562  // * after the vehicle end (ditto, with the vehicle end time).
563  message BreakRule {
564    option deprecated = true;
565
566    // The sequence of breaks (i.e. their number and order) that apply to each
567    // vehicle must be known beforehand. The repeated `BreakRequest`s define
568    // that sequence, in the order in which they must occur. Their time windows
569    // (`earliest_start_time` / `latest_start_time`) may overlap, but they must
570    // be compatible with the order (this is checked).
571    message BreakRequest {
572      // Required. Lower bound (inclusive) on the start of the break.
573      google.protobuf.Timestamp earliest_start_time = 1
574          [(google.api.field_behavior) = REQUIRED];
575
576      // Required. Upper bound (inclusive) on the start of the break.
577      google.protobuf.Timestamp latest_start_time = 2
578          [(google.api.field_behavior) = REQUIRED];
579
580      // Required. Minimum duration of the break. Must be positive.
581      google.protobuf.Duration min_duration = 3
582          [(google.api.field_behavior) = REQUIRED];
583    }
584
585    // One may further constrain the frequency and duration of the breaks
586    // specified above, by enforcing a minimum break frequency, such as
587    // "There must be a break of at least 1 hour every 12 hours". Assuming that
588    // this can be interpreted as "Within any sliding time window of 12h, there
589    // must be at least one break of at least one hour", that example would
590    // translate to the following `FrequencyConstraint`:
591    // ```
592    // {
593    //    min_break_duration { seconds: 3600 }         # 1 hour.
594    //    max_inter_break_duration { seconds: 39600 }  # 11 hours (12 - 1 = 11).
595    // }
596    // ```
597    //
598    // The timing and duration of the breaks in the solution will respect all
599    // such constraints, in addition to the time windows and minimum durations
600    // already specified in the `BreakRequest`.
601    //
602    // A `FrequencyConstraint` may in practice apply to non-consecutive breaks.
603    // For example, the following schedule honors the "1h every 12h" example:
604    // ```
605    //   04:00 vehicle start
606    //    .. performing travel and visits ..
607    //   09:00 1 hour break
608    //   10:00 end of the break
609    //    .. performing travel and visits ..
610    //   12:00 20-min lunch break
611    //   12:20 end of the break
612    //    .. performing travel and visits ..
613    //   21:00 1 hour break
614    //   22:00 end of the break
615    //    .. performing travel and visits ..
616    //   23:59 vehicle end
617    // ```
618    message FrequencyConstraint {
619      // Required. Minimum break duration for this constraint. Nonnegative.
620      // See description of `FrequencyConstraint`.
621      google.protobuf.Duration min_break_duration = 1
622          [(google.api.field_behavior) = REQUIRED];
623
624      // Required. Maximum allowed span of any interval of time in the route
625      // that does not include at least partially a break of `duration >=
626      // min_break_duration`. Must be positive.
627      google.protobuf.Duration max_inter_break_duration = 2
628          [(google.api.field_behavior) = REQUIRED];
629    }
630
631    // Sequence of breaks. See the `BreakRequest` message.
632    repeated BreakRequest break_requests = 1;
633
634    // Several `FrequencyConstraint` may apply. They must all be satisfied by
635    // the `BreakRequest`s of this `BreakRule`. See `FrequencyConstraint`.
636    repeated FrequencyConstraint frequency_constraints = 2;
637  }
638
639  // Set of shipments which must be performed in the model.
640  repeated Shipment shipments = 1;
641
642  // Set of vehicles which can be used to perform visits.
643  repeated Vehicle vehicles = 2;
644
645  // Constrains the maximum number of active vehicles. A vehicle is active if
646  // its route performs at least one shipment. This can be used to limit the
647  // number of routes in the case where there are fewer drivers than
648  // vehicles and that the fleet of vehicles is heterogeneous. The optimization
649  // will then select the best subset of vehicles to use.
650  // Must be strictly positive.
651  optional int32 max_active_vehicles = 4;
652
653  // Global start and end time of the model: no times outside of this range
654  // can be considered valid.
655  //
656  // The model's time span must be less than a year, i.e. the `global_end_time`
657  // and the `global_start_time` must be within 31536000 seconds of each other.
658  //
659  // When using `cost_per_*hour` fields, you might want to set this window to a
660  // smaller interval to increase performance (eg. if you model a single day,
661  // you should set the global time limits to that day).
662  // If unset, 00:00:00 UTC, January 1, 1970 (i.e. seconds: 0, nanos: 0) is used
663  // as default.
664  google.protobuf.Timestamp global_start_time = 5;
665
666  // If unset, 00:00:00 UTC, January 1, 1971 (i.e. seconds: 31536000, nanos: 0)
667  // is used as default.
668  google.protobuf.Timestamp global_end_time = 6;
669
670  // The "global duration" of the overall plan is the difference between the
671  // earliest effective start time and the latest effective end time of
672  // all vehicles. Users can assign a cost per hour to that quantity to try
673  // and optimize for earliest job completion, for example. This cost must be in
674  // the same unit as
675  // [Shipment.penalty_cost][google.cloud.optimization.v1.Shipment.penalty_cost].
676  double global_duration_cost_per_hour = 7;
677
678  // Specifies duration and distance matrices used in the model. If this field
679  // is empty, Google Maps or geodesic distances will be used instead, depending
680  // on the value of the `use_geodesic_distances` field. If it is not empty,
681  // `use_geodesic_distances` cannot be true and neither
682  // `duration_distance_matrix_src_tags` nor `duration_distance_matrix_dst_tags`
683  // can be empty.
684  //
685  // Usage examples:
686  //
687  // * There are two locations: locA and locB.
688  // * 1 vehicle starting its route at locA and ending it at locA.
689  // * 1 pickup visit request at locB.
690  //
691  // ```
692  // model {
693  //   vehicles { start_tags: "locA"  end_tags: "locA" }
694  //   shipments { pickups { tags: "locB" } }
695  //   duration_distance_matrix_src_tags: "locA"
696  //   duration_distance_matrix_src_tags: "locB"
697  //   duration_distance_matrix_dst_tags: "locA"
698  //   duration_distance_matrix_dst_tags: "locB"
699  //   duration_distance_matrices {
700  //     rows {  # from: locA
701  //       durations { seconds: 0 }   meters: 0    # to: locA
702  //       durations { seconds: 100 } meters: 1000 # to: locB
703  //     }
704  //     rows {  # from: locB
705  //       durations { seconds: 102 } meters: 990 # to: locA
706  //       durations { seconds: 0 }   meters: 0   # to: locB
707  //     }
708  //   }
709  // }
710  // ```
711  //
712  //
713  // * There are three locations: locA, locB and locC.
714  // * 1 vehicle starting its route at locA and ending it at locB, using
715  //   matrix "fast".
716  // * 1 vehicle starting its route at locB and ending it at locB, using
717  //   matrix "slow".
718  // * 1 vehicle starting its route at locB and ending it at locB, using
719  //   matrix "fast".
720  // * 1 pickup visit request at locC.
721  //
722  // ```
723  // model {
724  //   vehicles { start_tags: "locA" end_tags: "locB" start_tags: "fast" }
725  //   vehicles { start_tags: "locB" end_tags: "locB" start_tags: "slow" }
726  //   vehicles { start_tags: "locB" end_tags: "locB" start_tags: "fast" }
727  //   shipments { pickups { tags: "locC" } }
728  //   duration_distance_matrix_src_tags: "locA"
729  //   duration_distance_matrix_src_tags: "locB"
730  //   duration_distance_matrix_src_tags: "locC"
731  //   duration_distance_matrix_dst_tags: "locB"
732  //   duration_distance_matrix_dst_tags: "locC"
733  //   duration_distance_matrices {
734  //     vehicle_start_tag: "fast"
735  //     rows {  # from: locA
736  //       durations { seconds: 1000 } meters: 2000 # to: locB
737  //       durations { seconds: 600 }  meters: 1000 # to: locC
738  //     }
739  //     rows {  # from: locB
740  //       durations { seconds: 0 }   meters: 0    # to: locB
741  //       durations { seconds: 700 } meters: 1200 # to: locC
742  //     }
743  //     rows {  # from: locC
744  //       durations { seconds: 702 } meters: 1190 # to: locB
745  //       durations { seconds: 0 }   meters: 0    # to: locC
746  //     }
747  //   }
748  //   duration_distance_matrices {
749  //     vehicle_start_tag: "slow"
750  //     rows {  # from: locA
751  //       durations { seconds: 1800 } meters: 2001 # to: locB
752  //       durations { seconds: 900 }  meters: 1002 # to: locC
753  //     }
754  //     rows {  # from: locB
755  //       durations { seconds: 0 }    meters: 0    # to: locB
756  //       durations { seconds: 1000 } meters: 1202 # to: locC
757  //     }
758  //     rows {  # from: locC
759  //       durations { seconds: 1001 } meters: 1195 # to: locB
760  //       durations { seconds: 0 }    meters: 0    # to: locC
761  //     }
762  //   }
763  // }
764  // ```
765  repeated DurationDistanceMatrix duration_distance_matrices = 8;
766
767  // Tags defining the sources of the duration and distance matrices;
768  // `duration_distance_matrices(i).rows(j)` defines durations and distances
769  // from visits with tag `duration_distance_matrix_src_tags(j)` to other visits
770  // in matrix i.
771  //
772  // Tags correspond to
773  // [VisitRequest.tags][google.cloud.optimization.v1.Shipment.VisitRequest.tags]
774  // or [Vehicle.start_tags][google.cloud.optimization.v1.Vehicle.start_tags].
775  // A given `VisitRequest` or `Vehicle` must match exactly one tag in this
776  // field. Note that a `Vehicle`'s source, destination and matrix tags may be
777  // the same; similarly a `VisitRequest`'s source and destination tags may be
778  // the same. All tags must be different and cannot be empty strings. If this
779  // field is not empty, then `duration_distance_matrices` must not be empty.
780  repeated string duration_distance_matrix_src_tags = 9;
781
782  // Tags defining the destinations of the duration and distance matrices;
783  // `duration_distance_matrices(i).rows(j).durations(k)` (resp.
784  // `duration_distance_matrices(i).rows(j).meters(k))` defines the duration
785  // (resp. the distance) of the travel from visits with tag
786  // `duration_distance_matrix_src_tags(j)` to visits with tag
787  // `duration_distance_matrix_dst_tags(k)` in matrix i.
788  //
789  // Tags correspond to
790  // [VisitRequest.tags][google.cloud.optimization.v1.Shipment.VisitRequest.tags]
791  // or [Vehicle.start_tags][google.cloud.optimization.v1.Vehicle.start_tags].
792  // A given `VisitRequest` or `Vehicle` must match exactly one tag in this
793  // field. Note that a `Vehicle`'s source, destination and matrix tags may be
794  // the same; similarly a `VisitRequest`'s source and destination tags may be
795  // the same. All tags must be different and cannot be empty strings. If this
796  // field is not empty, then `duration_distance_matrices` must not be empty.
797  repeated string duration_distance_matrix_dst_tags = 10;
798
799  // Transition attributes added to the model.
800  repeated TransitionAttributes transition_attributes = 11;
801
802  // Sets of incompatible shipment_types (see `ShipmentTypeIncompatibility`).
803  repeated ShipmentTypeIncompatibility shipment_type_incompatibilities = 12;
804
805  // Sets of `shipment_type` requirements (see `ShipmentTypeRequirement`).
806  repeated ShipmentTypeRequirement shipment_type_requirements = 13;
807
808  // Set of precedence rules which must be enforced in the model.
809  repeated PrecedenceRule precedence_rules = 14;
810
811  // Deprecated: No longer used.
812  // Set of break rules used in the model.
813  // Each vehicle specifies the `BreakRule` that applies to it via the
814  // [Vehicle.break_rule_indices][google.cloud.optimization.v1.Vehicle.break_rule_indices]
815  // field (which must be a singleton).
816  repeated BreakRule break_rules = 15 [deprecated = true];
817}
818
819// The shipment of a single item, from one of its pickups to one of its
820// deliveries. For the shipment to be considered as performed, a unique vehicle
821// must visit one of its pickup locations (and decrease its spare capacities
822// accordingly), then visit one of its delivery locations later on (and
823// therefore re-increase its spare capacities accordingly).
824message Shipment {
825  // Request for a visit which can be done by a vehicle: it has a geo-location
826  // (or two, see below), opening and closing times represented by time windows,
827  // and a service duration time (time spent by the vehicle once it has arrived
828  // to pickup or drop off goods).
829  message VisitRequest {
830    // The geo-location where the vehicle arrives when performing this
831    // `VisitRequest`. If the shipment model has duration distance matrices,
832    // `arrival_location` must not be specified.
833    google.type.LatLng arrival_location = 1;
834
835    // The waypoint where the vehicle arrives when performing this
836    // `VisitRequest`. If the shipment model has duration distance matrices,
837    // `arrival_waypoint` must not be specified.
838    Waypoint arrival_waypoint = 2;
839
840    // The geo-location where the vehicle departs after completing this
841    // `VisitRequest`. Can be omitted if it is the same as `arrival_location`.
842    // If the shipment model has duration distance matrices,
843    // `departure_location` must not be specified.
844    google.type.LatLng departure_location = 3;
845
846    // The waypoint where the vehicle departs after completing this
847    // `VisitRequest`. Can be omitted if it is the same as `arrival_waypoint`.
848    // If the shipment model has duration distance matrices,
849    // `departure_waypoint` must not be specified.
850    Waypoint departure_waypoint = 4;
851
852    // Specifies tags attached to the visit request.
853    // Empty or duplicate strings are not allowed.
854    repeated string tags = 5;
855
856    // Time windows which constrain the arrival time at a visit.
857    // Note that a vehicle may depart outside of the arrival time window, i.e.
858    // arrival time + duration do not need to be inside a time window. This can
859    // result in waiting time if the vehicle arrives before
860    // [TimeWindow.start_time][google.cloud.optimization.v1.TimeWindow.start_time].
861    //
862    // The absence of `TimeWindow` means that the vehicle can perform this visit
863    // at any time.
864    //
865    // Time windows must be disjoint, i.e. no time window must overlap with or
866    // be adjacent to another, and they must be in increasing order.
867    //
868    // `cost_per_hour_after_soft_end_time` and `soft_end_time` can only
869    // be set if there is a single time window.
870    repeated TimeWindow time_windows = 6;
871
872    // Duration of the visit, i.e. time spent by the vehicle between arrival
873    // and departure (to be added to the possible waiting time; see
874    // `time_windows`).
875    google.protobuf.Duration duration = 7;
876
877    // Cost to service this visit request on a vehicle route. This can be used
878    // to pay different costs for each alternative pickup or delivery of a
879    // shipment. This cost must be in the same unit as `Shipment.penalty_cost`
880    // and must not be negative.
881    double cost = 8;
882
883    // Load demands of this visit request. This is just like
884    // [Shipment.load_demands][google.cloud.optimization.v1.Shipment.load_demands]
885    // field, except that it only applies to this
886    // [VisitRequest][google.cloud.optimization.v1.Shipment.VisitRequest]
887    // instead of the whole [Shipment][google.cloud.optimization.v1.Shipment].
888    // The demands listed here are added to the demands listed in
889    // [Shipment.load_demands][google.cloud.optimization.v1.Shipment.load_demands].
890    map<string, Load> load_demands = 12;
891
892    // Specifies the types of the visit. This may be used to allocate additional
893    // time required for a vehicle to complete this visit (see
894    // [Vehicle.extra_visit_duration_for_visit_type][google.cloud.optimization.v1.Vehicle.extra_visit_duration_for_visit_type]).
895    //
896    // A type can only appear once.
897    repeated string visit_types = 10;
898
899    // Specifies a label for this `VisitRequest`. This label is reported in the
900    // response as `visit_label` in the corresponding
901    // [ShipmentRoute.Visit][google.cloud.optimization.v1.ShipmentRoute.Visit].
902    string label = 11;
903
904    // Deprecated: Use
905    // [VisitRequest.load_demands][google.cloud.optimization.v1.Shipment.VisitRequest.load_demands]
906    // instead.
907    repeated CapacityQuantity demands = 9 [deprecated = true];
908  }
909
910  // When performing a visit, a predefined amount may be added to the vehicle
911  // load if it's a pickup, or subtracted if it's a delivery. This message
912  // defines such amount. See
913  // [load_demands][google.cloud.optimization.v1.Shipment.load_demands].
914  message Load {
915    // The amount by which the load of the vehicle performing the corresponding
916    // visit will vary. Since it is an integer, users are advised to choose an
917    // appropriate unit to avoid loss of precision. Must be ≥ 0.
918    int64 amount = 2;
919  }
920
921  // Set of pickup alternatives associated to the shipment. If not specified,
922  // the vehicle only needs to visit a location corresponding to the deliveries.
923  repeated VisitRequest pickups = 1;
924
925  // Set of delivery alternatives associated to the shipment. If not specified,
926  // the vehicle only needs to visit a location corresponding to the pickups.
927  repeated VisitRequest deliveries = 2;
928
929  // Load demands of the shipment (for example weight, volume, number of
930  // pallets etc). The keys in the map should be identifiers describing the type
931  // of the corresponding load, ideally also including the units.
932  // For example: "weight_kg", "volume_gallons", "pallet_count", etc.
933  // If a given key does not appear in the map, the corresponding load is
934  // considered as null.
935  map<string, Load> load_demands = 14;
936
937  // If the shipment is not completed, this penalty is added to the overall
938  // cost of the routes. A shipment is considered completed if one of its pickup
939  // and delivery alternatives is visited. The cost may be expressed in the
940  // same unit used for all other cost-related fields in the model and must be
941  // positive.
942  //
943  // *IMPORTANT*: If this penalty is not specified, it is considered infinite,
944  // i.e. the shipment must be completed.
945  optional double penalty_cost = 4;
946
947  // The set of vehicles that may perform this shipment. If empty, all vehicles
948  // may perform it. Vehicles are given by their index in the `ShipmentModel`'s
949  // `vehicles` list.
950  repeated int32 allowed_vehicle_indices = 5;
951
952  // Specifies the cost that is incurred when this shipment is delivered by each
953  // vehicle. If specified, it must have EITHER:
954  //
955  //   * the same number of elements as `costs_per_vehicle_indices`.
956  //     `costs_per_vehicle[i]` corresponds to vehicle
957  //     `costs_per_vehicle_indices[i]` of the model.
958  //   * the same number of elements as there are vehicles in the model. The
959  //     i-th element corresponds to vehicle #i of the model.
960  //
961  // These costs must be in the same unit as `penalty_cost` and must not be
962  // negative. Leave this field empty, if there are no such costs.
963  repeated double costs_per_vehicle = 6;
964
965  // Indices of the vehicles to which `costs_per_vehicle` applies. If non-empty,
966  // it must have the same number of elements as `costs_per_vehicle`. A vehicle
967  // index may not be specified more than once. If a vehicle is excluded from
968  // `costs_per_vehicle_indices`, its cost is zero.
969  repeated int32 costs_per_vehicle_indices = 7;
970
971  // Specifies the maximum relative detour time compared to the shortest path
972  // from pickup to delivery. If specified, it must be nonnegative, and the
973  // shipment must contain at least a pickup and a delivery.
974  //
975  // For example, let t be the shortest time taken to go from the selected
976  // pickup alternative directly to the selected delivery alternative. Then
977  // setting `pickup_to_delivery_relative_detour_limit` enforces:
978  //
979  // ```
980  // start_time(delivery) - start_time(pickup) <=
981  // std::ceil(t * (1.0 + pickup_to_delivery_relative_detour_limit))
982  // ```
983  //
984  // If both relative and absolute limits are specified on the same shipment,
985  // the more constraining limit is used for each possible pickup/delivery pair.
986  // As of 2017/10, detours are only supported when travel durations do not
987  // depend on vehicles.
988  optional double pickup_to_delivery_relative_detour_limit = 8;
989
990  // Specifies the maximum absolute detour time compared to the shortest path
991  // from pickup to delivery. If specified, it must be nonnegative, and the
992  // shipment must contain at least a pickup and a delivery.
993  //
994  // For example, let t be the shortest time taken to go from the selected
995  // pickup alternative directly to the selected delivery alternative. Then
996  // setting `pickup_to_delivery_absolute_detour_limit` enforces:
997  //
998  // ```
999  // start_time(delivery) - start_time(pickup) <=
1000  // t + pickup_to_delivery_absolute_detour_limit
1001  // ```
1002  //
1003  // If both relative and absolute limits are specified on the same shipment,
1004  // the more constraining limit is used for each possible pickup/delivery pair.
1005  // As of 2017/10, detours are only supported when travel durations do not
1006  // depend on vehicles.
1007  google.protobuf.Duration pickup_to_delivery_absolute_detour_limit = 9;
1008
1009  // Specifies the maximum duration from start of pickup to start of delivery of
1010  // a shipment. If specified, it must be nonnegative, and the shipment must
1011  // contain at least a pickup and a delivery. This does not depend on which
1012  // alternatives are selected for pickup and delivery, nor on vehicle speed.
1013  // This can be specified alongside maximum detour constraints: the solution
1014  // will respect both specifications.
1015  google.protobuf.Duration pickup_to_delivery_time_limit = 10;
1016
1017  // Non-empty string specifying a "type" for this shipment.
1018  // This feature can be used to define incompatibilities or requirements
1019  // between `shipment_types` (see `shipment_type_incompatibilities` and
1020  // `shipment_type_requirements` in `ShipmentModel`).
1021  //
1022  // Differs from `visit_types` which is specified for a single visit: All
1023  // pickup/deliveries belonging to the same shipment share the same
1024  // `shipment_type`.
1025  string shipment_type = 11;
1026
1027  // Specifies a label for this shipment. This label is reported in the response
1028  // in the `shipment_label` of the corresponding
1029  // [ShipmentRoute.Visit][google.cloud.optimization.v1.ShipmentRoute.Visit].
1030  string label = 12;
1031
1032  // If true, skip this shipment, but don't apply a `penalty_cost`.
1033  //
1034  // Ignoring a shipment results in a validation error when there are any
1035  // `shipment_type_requirements` in the model.
1036  //
1037  // Ignoring a shipment that is performed in `injected_first_solution_routes`
1038  // or `injected_solution_constraint` is permitted; the solver removes the
1039  // related pickup/delivery visits from the performing route.
1040  // `precedence_rules` that reference ignored shipments will also be ignored.
1041  bool ignore = 13;
1042
1043  // Deprecated: Use
1044  // [Shipment.load_demands][google.cloud.optimization.v1.Shipment.load_demands]
1045  // instead.
1046  repeated CapacityQuantity demands = 3 [deprecated = true];
1047}
1048
1049// Specifies incompatibilties between shipments depending on their
1050// shipment_type. The appearance of incompatible shipments on the same route is
1051// restricted based on the incompatibility mode.
1052message ShipmentTypeIncompatibility {
1053  // Modes defining how the appearance of incompatible shipments are restricted
1054  // on the same route.
1055  enum IncompatibilityMode {
1056    // Unspecified incompatibility mode. This value should never be used.
1057    INCOMPATIBILITY_MODE_UNSPECIFIED = 0;
1058
1059    // In this mode, two shipments with incompatible types can never share the
1060    // same vehicle.
1061    NOT_PERFORMED_BY_SAME_VEHICLE = 1;
1062
1063    // For two shipments with incompatible types with the
1064    // `NOT_IN_SAME_VEHICLE_SIMULTANEOUSLY` incompatibility mode:
1065    //
1066    // * If both are pickups only (no deliveries) or deliveries only (no
1067    //   pickups), they cannot share the same vehicle at all.
1068    // * If one of the shipments has a delivery and the other a pickup, the two
1069    //   shipments can share the same vehicle iff the former shipment is
1070    //   delivered before the latter is picked up.
1071    NOT_IN_SAME_VEHICLE_SIMULTANEOUSLY = 2;
1072  }
1073
1074  // List of incompatible types. Two shipments having different `shipment_types`
1075  // among those listed are "incompatible".
1076  repeated string types = 1;
1077
1078  // Mode applied to the incompatibility.
1079  IncompatibilityMode incompatibility_mode = 2;
1080}
1081
1082// Specifies requirements between shipments based on their shipment_type.
1083// The specifics of the requirement are defined by the requirement mode.
1084message ShipmentTypeRequirement {
1085  // Modes defining the appearance of dependent shipments on a route.
1086  enum RequirementMode {
1087    // Unspecified requirement mode. This value should never be used.
1088    REQUIREMENT_MODE_UNSPECIFIED = 0;
1089
1090    // In this mode, all "dependent" shipments must share the same vehicle as at
1091    // least one of their "required" shipments.
1092    PERFORMED_BY_SAME_VEHICLE = 1;
1093
1094    // With the `IN_SAME_VEHICLE_AT_PICKUP_TIME` mode, all "dependent"
1095    // shipments need to have at least one "required" shipment on their vehicle
1096    // at the time of their pickup.
1097    //
1098    // A "dependent" shipment pickup must therefore have either:
1099    //
1100    // * A delivery-only "required" shipment delivered on the route after, or
1101    // * A "required" shipment picked up on the route before it, and if the
1102    //   "required" shipment has a delivery, this delivery must be performed
1103    //   after the "dependent" shipment's pickup.
1104    IN_SAME_VEHICLE_AT_PICKUP_TIME = 2;
1105
1106    // Same as before, except the "dependent" shipments need to have a
1107    // "required" shipment on their vehicle at the time of their *delivery*.
1108    IN_SAME_VEHICLE_AT_DELIVERY_TIME = 3;
1109  }
1110
1111  // List of alternative shipment types required by the
1112  // `dependent_shipment_types`.
1113  repeated string required_shipment_type_alternatives = 1;
1114
1115  // All shipments with a type in the `dependent_shipment_types` field require
1116  // at least one shipment of type `required_shipment_type_alternatives` to be
1117  // visited on the same route.
1118  //
1119  // NOTE: Chains of requirements such that a `shipment_type` depends on itself
1120  // are not allowed.
1121  repeated string dependent_shipment_types = 2;
1122
1123  // Mode applied to the requirement.
1124  RequirementMode requirement_mode = 3;
1125}
1126
1127// Encapsulates a set of optional conditions to satisfy when calculating
1128// vehicle routes. This is similar to `RouteModifiers` in the Google Maps
1129// Platform API; see:
1130// https://developers.google.com/maps/documentation/routes/reference/rest/v2/RouteModifiers.
1131message RouteModifiers {
1132  // Specifies whether to avoid toll roads where reasonable. Preference will be
1133  // given to routes not containing toll roads. Applies only to motorized travel
1134  // modes.
1135  bool avoid_tolls = 2;
1136
1137  // Specifies whether to avoid highways where reasonable. Preference will be
1138  // given to routes not containing highways. Applies only to motorized travel
1139  // modes.
1140  bool avoid_highways = 3;
1141
1142  // Specifies whether to avoid ferries where reasonable. Preference will be
1143  // given to routes not containing travel by ferries. Applies only to motorized
1144  // travel modes.
1145  bool avoid_ferries = 4;
1146
1147  // Optional. Specifies whether to avoid navigating indoors where reasonable.
1148  // Preference will be given to routes not containing indoor navigation.
1149  // Applies only to the `WALKING` travel mode.
1150  bool avoid_indoor = 5 [(google.api.field_behavior) = OPTIONAL];
1151}
1152
1153// Models a vehicle in a shipment problem. Solving a shipment problem will
1154// build a route starting from `start_location` and ending at `end_location`
1155// for this vehicle. A route is a sequence of visits (see `ShipmentRoute`).
1156message Vehicle {
1157  // Travel modes which can be used by vehicles.
1158  //
1159  // These should be a subset of the Google Maps Platform Routes Preferred API
1160  // travel modes, see:
1161  // https://developers.google.com/maps/documentation/routes_preferred/reference/rest/Shared.Types/RouteTravelMode.
1162  enum TravelMode {
1163    // Unspecified travel mode, equivalent to `DRIVING`.
1164    TRAVEL_MODE_UNSPECIFIED = 0;
1165
1166    // Travel mode corresponding to driving directions (car, ...).
1167    DRIVING = 1;
1168
1169    // Travel mode corresponding to walking directions.
1170    WALKING = 2;
1171  }
1172
1173  // Policy on how a vehicle can be unloaded. Applies only to shipments having
1174  // both a pickup and a delivery.
1175  //
1176  // Other shipments are free to occur anywhere on the route independent of
1177  // `unloading_policy`.
1178  enum UnloadingPolicy {
1179    // Unspecified unloading policy; deliveries must just occur after their
1180    // corresponding pickups.
1181    UNLOADING_POLICY_UNSPECIFIED = 0;
1182
1183    // Deliveries must occur in reverse order of pickups
1184    LAST_IN_FIRST_OUT = 1;
1185
1186    // Deliveries must occur in the same order as pickups
1187    FIRST_IN_FIRST_OUT = 2;
1188  }
1189
1190  // Defines a load limit applying to a vehicle, e.g. "this truck may only
1191  // carry up to 3500 kg". See
1192  // [load_limits][google.cloud.optimization.v1.Vehicle.load_limits].
1193  message LoadLimit {
1194    // Interval of acceptable load amounts.
1195    message Interval {
1196      // A minimum acceptable load. Must be ≥ 0.
1197      // If they're both specified,
1198      // [min][google.cloud.optimization.v1.Vehicle.LoadLimit.Interval.min] must
1199      // be ≤
1200      // [max][google.cloud.optimization.v1.Vehicle.LoadLimit.Interval.max].
1201      int64 min = 1;
1202
1203      // A maximum acceptable load. Must be ≥ 0. If unspecified, the maximum
1204      // load is unrestricted by this message.
1205      // If they're both specified,
1206      // [min][google.cloud.optimization.v1.Vehicle.LoadLimit.Interval.min] must
1207      // be ≤
1208      // [max][google.cloud.optimization.v1.Vehicle.LoadLimit.Interval.max].
1209      optional int64 max = 2;
1210    }
1211
1212    // The maximum acceptable amount of load.
1213    optional int64 max_load = 1;
1214
1215    // A soft limit of the load. See
1216    // [cost_per_unit_above_soft_max][google.cloud.optimization.v1.Vehicle.LoadLimit.cost_per_unit_above_soft_max].
1217    int64 soft_max_load = 2;
1218
1219    // If the load ever exceeds
1220    // [soft_max_load][google.cloud.optimization.v1.Vehicle.LoadLimit.soft_max_load]
1221    // along this vehicle's route, the following cost penalty applies (only once
1222    // per vehicle): (load -
1223    // [soft_max_load][google.cloud.optimization.v1.Vehicle.LoadLimit.soft_max_load])
1224    // * [cost_per_unit_above_soft_max][google.cloud.optimization.v1.Vehicle.LoadLimit.cost_per_unit_above_soft_max]. All costs
1225    // add up and must be in the same unit as
1226    // [Shipment.penalty_cost][google.cloud.optimization.v1.Shipment.penalty_cost].
1227    double cost_per_unit_above_soft_max = 3;
1228
1229    // The acceptable load interval of the vehicle at the start of the route.
1230    Interval start_load_interval = 4;
1231
1232    // The acceptable load interval of the vehicle at the end of the route.
1233    Interval end_load_interval = 5;
1234  }
1235
1236  // A limit defining a maximum duration of the route of a vehicle. It can be
1237  // either hard or soft.
1238  //
1239  // When a soft limit field is defined, both the soft max threshold and its
1240  // associated cost must be defined together.
1241  message DurationLimit {
1242    // A hard limit constraining the duration to be at most max_duration.
1243    google.protobuf.Duration max_duration = 1;
1244
1245    // A soft limit not enforcing a maximum duration limit, but when violated
1246    // makes the route incur a cost. This cost adds up to other costs defined in
1247    // the model, with the same unit.
1248    //
1249    // If defined, `soft_max_duration` must be nonnegative. If max_duration is
1250    // also defined, `soft_max_duration` must be less than max_duration.
1251    google.protobuf.Duration soft_max_duration = 2;
1252
1253    // Cost per hour incurred if the `soft_max_duration` threshold is violated.
1254    // The additional cost is 0 if the duration is under the threshold,
1255    // otherwise the cost depends on the duration as follows:
1256    // ```
1257    //   cost_per_hour_after_soft_max * (duration - soft_max_duration)
1258    // ```
1259    // The cost must be nonnegative.
1260    optional double cost_per_hour_after_soft_max = 3;
1261
1262    // A soft limit not enforcing a maximum duration limit, but when violated
1263    // makes the route incur a cost, quadratic in the duration. This cost adds
1264    // up to other costs defined in the model, with the same unit.
1265    //
1266    // If defined, `quadratic_soft_max_duration` must be nonnegative. If
1267    // `max_duration` is also defined, `quadratic_soft_max_duration` must be
1268    // less than `max_duration`, and the difference must be no larger than one
1269    // day:
1270    //
1271    //    `max_duration - quadratic_soft_max_duration <= 86400 seconds`
1272    google.protobuf.Duration quadratic_soft_max_duration = 4;
1273
1274    // Cost per square hour incurred if the
1275    // `quadratic_soft_max_duration` threshold is violated.
1276    //
1277    // The additional cost is 0 if the duration is under the threshold,
1278    // otherwise the cost depends on the duration as follows:
1279    //
1280    // ```
1281    //   cost_per_square_hour_after_quadratic_soft_max *
1282    //   (duration - quadratic_soft_max_duration)^2
1283    // ```
1284    //
1285    // The cost must be nonnegative.
1286    optional double cost_per_square_hour_after_quadratic_soft_max = 5;
1287  }
1288
1289  // The travel mode which affects the roads usable by the vehicle and its
1290  // speed. See also `travel_duration_multiple`.
1291  TravelMode travel_mode = 1;
1292
1293  // Optional. A set of conditions to satisfy that affect the way routes are
1294  // calculated for the given vehicle.
1295  RouteModifiers route_modifiers = 2 [(google.api.field_behavior) = OPTIONAL];
1296
1297  // Geographic location where the vehicle starts before picking up any
1298  // shipments. If not specified, the vehicle starts at its first pickup.
1299  // If the shipment model has duration and distance matrices, `start_location`
1300  // must not be specified.
1301  google.type.LatLng start_location = 3;
1302
1303  // Waypoint representing a geographic location where the vehicle starts before
1304  // picking up any shipments. If neither `start_waypoint` nor `start_location`
1305  // is specified, the vehicle starts at its first pickup.
1306  // If the shipment model has duration and distance matrices, `start_waypoint`
1307  // must not be specified.
1308  Waypoint start_waypoint = 4;
1309
1310  // Geographic location where the vehicle ends after it has completed its last
1311  // `VisitRequest`. If not specified the vehicle's `ShipmentRoute` ends
1312  // immediately when it completes its last `VisitRequest`.
1313  // If the shipment model has duration and distance matrices, `end_location`
1314  // must not be specified.
1315  google.type.LatLng end_location = 5;
1316
1317  // Waypoint representing a geographic location where the vehicle ends after
1318  // it has completed its last `VisitRequest`. If neither `end_waypoint` nor
1319  // `end_location` is specified, the vehicle's `ShipmentRoute` ends immediately
1320  // when it completes its last `VisitRequest`.
1321  // If the shipment model has duration and distance matrices, `end_waypoint`
1322  // must not be specified.
1323  Waypoint end_waypoint = 6;
1324
1325  // Specifies tags attached to the start of the vehicle's route.
1326  //
1327  // Empty or duplicate strings are not allowed.
1328  repeated string start_tags = 7;
1329
1330  // Specifies tags attached to the end of the vehicle's route.
1331  //
1332  // Empty or duplicate strings are not allowed.
1333  repeated string end_tags = 8;
1334
1335  // Time windows during which the vehicle may depart its start location.
1336  // They must be within the global time limits (see
1337  // [ShipmentModel.global_*][google.cloud.optimization.v1.ShipmentModel.global_start_time]
1338  // fields). If unspecified, there is no limitation besides those global time
1339  // limits.
1340  //
1341  // Time windows belonging to the same repeated field must be disjoint, i.e. no
1342  // time window can overlap with or be adjacent to another, and they must be in
1343  // chronological order.
1344  //
1345  // `cost_per_hour_after_soft_end_time` and `soft_end_time` can only be set if
1346  // there is a single time window.
1347  repeated TimeWindow start_time_windows = 9;
1348
1349  // Time windows during which the vehicle may arrive at its end location.
1350  // They must be within the global time limits (see
1351  // [ShipmentModel.global_*][google.cloud.optimization.v1.ShipmentModel.global_start_time]
1352  // fields). If unspecified, there is no limitation besides those global time
1353  // limits.
1354  //
1355  // Time windows belonging to the same repeated field must be disjoint, i.e. no
1356  // time window can overlap with or be adjacent to another, and they must be in
1357  // chronological order.
1358  //
1359  // `cost_per_hour_after_soft_end_time` and `soft_end_time` can only be set if
1360  // there is a single time window.
1361  repeated TimeWindow end_time_windows = 10;
1362
1363  // Specifies a multiplicative factor that can be used to increase or decrease
1364  // travel times of this vehicle. For example, setting this to 2.0 means
1365  // that this vehicle is slower and has travel times that are twice what they
1366  // are for standard vehicles. This multiple does not affect visit durations.
1367  // It does affect cost if `cost_per_hour` or `cost_per_traveled_hour` are
1368  // specified. This must be in the range [0.001, 1000.0]. If unset, the vehicle
1369  // is standard, and this multiple is considered 1.0.
1370  //
1371  // WARNING: Travel times will be rounded to the nearest second after this
1372  // multiple is applied but before performing any numerical operations, thus,
1373  // a small multiple may result in a loss of precision.
1374  //
1375  // See also `extra_visit_duration_for_visit_type` below.
1376  optional double travel_duration_multiple = 11;
1377
1378  // Unloading policy enforced on the vehicle.
1379  UnloadingPolicy unloading_policy = 12;
1380
1381  // Capacities of the vehicle (weight, volume, # of pallets for example).
1382  // The keys in the map are the identifiers of the type of load, consistent
1383  // with the keys of the
1384  // [Shipment.load_demands][google.cloud.optimization.v1.Shipment.load_demands]
1385  // field. If a given key is absent from this map, the corresponding capacity
1386  // is considered to be limitless.
1387  map<string, LoadLimit> load_limits = 30;
1388
1389  // Vehicle costs: all costs add up and must be in the same unit as
1390  // [Shipment.penalty_cost][google.cloud.optimization.v1.Shipment.penalty_cost].
1391  //
1392  // Cost per hour of the vehicle route. This cost is applied to the total time
1393  // taken by the route, and includes travel time, waiting time, and visit time.
1394  // Using `cost_per_hour` instead of just `cost_per_traveled_hour` may result
1395  // in additional latency.
1396  double cost_per_hour = 16;
1397
1398  // Cost per traveled hour of the vehicle route. This cost is applied only to
1399  // travel time taken by the route (i.e., that reported in
1400  // [ShipmentRoute.transitions][google.cloud.optimization.v1.ShipmentRoute.transitions]),
1401  // and excludes waiting time and visit time.
1402  double cost_per_traveled_hour = 17;
1403
1404  // Cost per kilometer of the vehicle route. This cost is applied to the
1405  // distance reported in the
1406  // [ShipmentRoute.transitions][google.cloud.optimization.v1.ShipmentRoute.transitions]
1407  // and does not apply to any distance implicitly traveled from the
1408  // `arrival_location` to the `departure_location` of a single `VisitRequest`.
1409  double cost_per_kilometer = 18;
1410
1411  // Fixed cost applied if this vehicle is used to handle a shipment.
1412  double fixed_cost = 19;
1413
1414  // This field only applies to vehicles when their route does not serve any
1415  // shipments. It indicates if the vehicle should be considered as used or not
1416  // in this case.
1417  //
1418  // If true, the vehicle goes from its start to its end location even if it
1419  // doesn't serve any shipments, and time and distance costs resulting from its
1420  // start --> end travel are taken into account.
1421  //
1422  // Otherwise, it doesn't travel from its start to its end location, and no
1423  // `break_rule` or delay (from `TransitionAttributes`) are scheduled for this
1424  // vehicle. In this case, the vehicle's `ShipmentRoute` doesn't contain any
1425  // information except for the vehicle index and label.
1426  bool used_if_route_is_empty = 20;
1427
1428  // Limit applied to the total duration of the vehicle's route. In a given
1429  // `OptimizeToursResponse`, the route duration of a vehicle is the
1430  // difference between its `vehicle_end_time` and `vehicle_start_time`.
1431  DurationLimit route_duration_limit = 21;
1432
1433  // Limit applied to the travel duration of the vehicle's route. In a given
1434  // `OptimizeToursResponse`, the route travel duration is the sum of all its
1435  // [transitions.travel_duration][google.cloud.optimization.v1.ShipmentRoute.Transition.travel_duration].
1436  DurationLimit travel_duration_limit = 22;
1437
1438  // Limit applied to the total distance of the vehicle's route. In a given
1439  // `OptimizeToursResponse`, the route distance is the sum of all its
1440  // [transitions.travel_distance_meters][google.cloud.optimization.v1.ShipmentRoute.Transition.travel_distance_meters].
1441  DistanceLimit route_distance_limit = 23;
1442
1443  // Specifies a map from visit_types strings to durations. The duration is time
1444  // in addition to
1445  // [VisitRequest.duration][google.cloud.optimization.v1.Shipment.VisitRequest.duration]
1446  // to be taken at visits with the specified `visit_types`. This extra visit
1447  // duration adds cost if `cost_per_hour` is specified. Keys (i.e.
1448  // `visit_types`) cannot be empty strings.
1449  //
1450  // If a visit request has multiple types, a duration will be added for each
1451  // type in the map.
1452  map<string, google.protobuf.Duration> extra_visit_duration_for_visit_type =
1453      24;
1454
1455  // Describes the break schedule to be enforced on this vehicle.
1456  // If empty, no breaks will be scheduled for this vehicle.
1457  BreakRule break_rule = 25;
1458
1459  // Specifies a label for this vehicle. This label is reported in the response
1460  // as the `vehicle_label` of the corresponding
1461  // [ShipmentRoute][google.cloud.optimization.v1.ShipmentRoute].
1462  string label = 27;
1463
1464  // If true, `used_if_route_is_empty` must be false, and this vehicle will
1465  // remain unused.
1466  //
1467  // If a shipment is performed by an ignored vehicle in
1468  // `injected_first_solution_routes`, it is skipped in the first solution but
1469  // is free to be performed in the response.
1470  //
1471  // If a shipment is performed by an ignored vehicle in
1472  // `injected_solution_constraint` and any related pickup/delivery is
1473  // constrained to remain on the vehicle (i.e., not relaxed to level
1474  // `RELAX_ALL_AFTER_THRESHOLD`), it is skipped in the response.
1475  // If a shipment has a non-empty `allowed_vehicle_indices` field and all of
1476  // the allowed vehicles are ignored, it is skipped in the response.
1477  bool ignore = 28;
1478
1479  // Deprecated: No longer used.
1480  // Indices in the `break_rule` field in the source
1481  // [ShipmentModel][google.cloud.optimization.v1.ShipmentModel]. They
1482  // correspond to break rules enforced on the vehicle.
1483  //
1484  // As of 2018/03, at most one rule index per vehicle can be specified.
1485  repeated int32 break_rule_indices = 29 [deprecated = true];
1486
1487  // Deprecated: Use
1488  // [Vehicle.load_limits][google.cloud.optimization.v1.Vehicle.load_limits]
1489  // instead.
1490  repeated CapacityQuantity capacities = 13 [deprecated = true];
1491
1492  // Deprecated: Use
1493  // [Vehicle.LoadLimit.start_load_interval][google.cloud.optimization.v1.Vehicle.LoadLimit.start_load_interval]
1494  // instead.
1495  repeated CapacityQuantityInterval start_load_intervals = 14
1496      [deprecated = true];
1497
1498  // Deprecated: Use
1499  // [Vehicle.LoadLimit.end_load_interval][google.cloud.optimization.v1.Vehicle.LoadLimit.end_load_interval]
1500  // instead.
1501  repeated CapacityQuantityInterval end_load_intervals = 15 [deprecated = true];
1502}
1503
1504// Time windows constrain the time of an event, such as the arrival time at a
1505// visit, or the start and end time of a vehicle.
1506//
1507// Hard time window bounds, `start_time` and `end_time`, enforce the earliest
1508// and latest time of the event, such that `start_time <= event_time <=
1509// end_time`. The soft time window lower bound, `soft_start_time`, expresses a
1510// preference for the event to happen at or after `soft_start_time` by incurring
1511// a cost proportional to how long before soft_start_time the event occurs. The
1512// soft time window upper bound, `soft_end_time`, expresses a preference for the
1513// event to happen at or before `soft_end_time` by incurring a cost proportional
1514// to how long after `soft_end_time` the event occurs. `start_time`, `end_time`,
1515// `soft_start_time` and `soft_end_time` should be within the global time limits
1516// (see
1517// [ShipmentModel.global_start_time][google.cloud.optimization.v1.ShipmentModel.global_start_time]
1518// and
1519// [ShipmentModel.global_end_time][google.cloud.optimization.v1.ShipmentModel.global_end_time])
1520// and should respect:
1521// ```
1522//   0 <= `start_time` <= `soft_start_time` <= `end_time` and
1523//   0 <= `start_time` <= `soft_end_time` <= `end_time`.
1524// ```
1525message TimeWindow {
1526  // The hard time window start time. If unspecified it will be set to
1527  // `ShipmentModel.global_start_time`.
1528  google.protobuf.Timestamp start_time = 1;
1529
1530  // The hard time window end time. If unspecified it will be set to
1531  // `ShipmentModel.global_end_time`.
1532  google.protobuf.Timestamp end_time = 2;
1533
1534  // The soft start time of the time window.
1535  google.protobuf.Timestamp soft_start_time = 3;
1536
1537  // The soft end time of the time window.
1538  google.protobuf.Timestamp soft_end_time = 4;
1539
1540  // A cost per hour added to other costs in the model if the event occurs
1541  // before soft_start_time, computed as:
1542  //
1543  // ```
1544  //    max(0, soft_start_time - t.seconds)
1545  //                           * cost_per_hour_before_soft_start_time / 3600,
1546  // t being the time of the event.
1547  // ```
1548  //
1549  // This cost must be positive, and the field can only be set if
1550  // soft_start_time has been set.
1551  optional double cost_per_hour_before_soft_start_time = 5;
1552
1553  // A cost per hour added to other costs in the model if the event occurs after
1554  // `soft_end_time`, computed as:
1555  //
1556  // ```
1557  //    max(0, t.seconds - soft_end_time.seconds)
1558  //                     * cost_per_hour_after_soft_end_time / 3600,
1559  // t being the time of the event.
1560  // ```
1561  //
1562  // This cost must be positive, and the field can only be set if
1563  // `soft_end_time` has been set.
1564  optional double cost_per_hour_after_soft_end_time = 6;
1565}
1566
1567// Deprecated: Use
1568// [Vehicle.LoadLimit.Interval][google.cloud.optimization.v1.Vehicle.LoadLimit.Interval]
1569// instead.
1570message CapacityQuantity {
1571  option deprecated = true;
1572
1573  string type = 1;
1574
1575  int64 value = 2;
1576}
1577
1578// Deprecated: Use
1579// [Vehicle.LoadLimit.Interval][google.cloud.optimization.v1.Vehicle.LoadLimit.Interval]
1580// instead.
1581message CapacityQuantityInterval {
1582  option deprecated = true;
1583
1584  string type = 1;
1585
1586  optional int64 min_value = 2;
1587
1588  optional int64 max_value = 3;
1589}
1590
1591// A limit defining a maximum distance which can be traveled. It can be either
1592// hard or soft.
1593//
1594// If a soft limit is defined, both `soft_max_meters` and
1595// `cost_per_kilometer_above_soft_max` must be defined and be nonnegative.
1596message DistanceLimit {
1597  // A hard limit constraining the distance to be at most max_meters. The limit
1598  // must be nonnegative.
1599  optional int64 max_meters = 1;
1600
1601  // A soft limit not enforcing a maximum distance limit, but when violated
1602  // results in a cost which adds up to other costs defined in the model,
1603  // with the same unit.
1604  //
1605  // If defined soft_max_meters must be less than max_meters and must be
1606  // nonnegative.
1607  optional int64 soft_max_meters = 2;
1608
1609  // Cost per kilometer incurred, increasing up to `soft_max_meters`, with
1610  // formula:
1611  // ```
1612  //   min(distance_meters, soft_max_meters) / 1000.0 *
1613  //   cost_per_kilometer_below_soft_max.
1614  // ```
1615  // This cost is not supported in `route_distance_limit`.
1616  optional double cost_per_kilometer_below_soft_max = 4;
1617
1618  // Cost per kilometer incurred if distance is above `soft_max_meters` limit.
1619  // The additional cost is 0 if the distance is under the limit, otherwise the
1620  // formula used to compute the cost is the following:
1621  // ```
1622  //   (distance_meters - soft_max_meters) / 1000.0 *
1623  //   cost_per_kilometer_above_soft_max.
1624  // ```
1625  // The cost must be nonnegative.
1626  optional double cost_per_kilometer_above_soft_max = 3;
1627}
1628
1629// Specifies attributes of transitions between two consecutive visits on a
1630// route. Several `TransitionAttributes` may apply to the same transition: in
1631// that case, all extra costs add up and the strictest constraint or limit
1632// applies (following natural "AND" semantics).
1633message TransitionAttributes {
1634  // Tags defining the set of (src->dst) transitions these attributes apply to.
1635  //
1636  // A source visit or vehicle start matches iff its
1637  // [VisitRequest.tags][google.cloud.optimization.v1.Shipment.VisitRequest.tags]
1638  // or [Vehicle.start_tags][google.cloud.optimization.v1.Vehicle.start_tags]
1639  // either contains `src_tag` or does not contain `excluded_src_tag` (depending
1640  // on which of these two fields is non-empty).
1641  string src_tag = 1;
1642
1643  // See `src_tag`. Exactly one of `src_tag` and `excluded_src_tag` must be
1644  // non-empty.
1645  string excluded_src_tag = 2;
1646
1647  // A destination visit or vehicle end matches iff its
1648  // [VisitRequest.tags][google.cloud.optimization.v1.Shipment.VisitRequest.tags]
1649  // or [Vehicle.end_tags][google.cloud.optimization.v1.Vehicle.end_tags] either
1650  // contains `dst_tag` or does not contain `excluded_dst_tag` (depending on
1651  // which of these two fields is non-empty).
1652  string dst_tag = 3;
1653
1654  // See `dst_tag`. Exactly one of `dst_tag` and `excluded_dst_tag` must be
1655  // non-empty.
1656  string excluded_dst_tag = 4;
1657
1658  // Specifies a cost for performing this transition. This is in the same unit
1659  // as all other costs in the model and must not be negative. It is applied on
1660  // top of all other existing costs.
1661  double cost = 5;
1662
1663  // Specifies a cost per kilometer applied to the distance traveled while
1664  // performing this transition. It adds up to any
1665  // [Vehicle.cost_per_kilometer][google.cloud.optimization.v1.Vehicle.cost_per_kilometer]
1666  // specified on vehicles.
1667  double cost_per_kilometer = 6;
1668
1669  // Specifies a limit on the distance traveled while performing this
1670  // transition.
1671  //
1672  // As of 2021/06, only soft limits are supported.
1673  DistanceLimit distance_limit = 7;
1674
1675  // Specifies a delay incurred when performing this transition.
1676  //
1677  // This delay always occurs *after* finishing the source visit and *before*
1678  // starting the destination visit.
1679  google.protobuf.Duration delay = 8;
1680}
1681
1682// Encapsulates a waypoint. Waypoints mark arrival and departure locations of
1683// VisitRequests, and start and end locations of Vehicles.
1684message Waypoint {
1685  // Different ways to represent a location.
1686  oneof location_type {
1687    // A point specified using geographic coordinates, including an optional
1688    // heading.
1689    Location location = 1;
1690
1691    // The POI Place ID associated with the waypoint.
1692    string place_id = 2;
1693  }
1694
1695  // Indicates that the location of this waypoint is meant to have a preference
1696  // for the vehicle to stop at a particular side of road. When you set this
1697  // value, the route will pass through the location so that the vehicle can
1698  // stop at the side of road that the location is biased towards from the
1699  // center of the road. This option works only for the 'DRIVING' travel mode,
1700  // and when the 'location_type' is set to 'location'.
1701  bool side_of_road = 3;
1702}
1703
1704// Encapsulates a location (a geographic point, and an optional heading).
1705message Location {
1706  // The waypoint's geographic coordinates.
1707  google.type.LatLng lat_lng = 1;
1708
1709  // The compass heading associated with the direction of the flow of traffic.
1710  // This value is used to specify the side of the road to use for pickup and
1711  // drop-off. Heading values can be from 0 to 360, where 0 specifies a heading
1712  // of due North, 90 specifies a heading of due East, etc.
1713  optional int32 heading = 2;
1714}
1715
1716// Rules to generate time breaks for a vehicle (e.g. lunch breaks). A break
1717// is a contiguous period of time during which the vehicle remains idle at its
1718// current position and cannot perform any visit. A break may occur:
1719//
1720// * during the travel between two visits (which includes the time right
1721//   before or right after a visit, but not in the middle of a visit), in
1722//   which case it extends the corresponding transit time between the visits,
1723// * or before the vehicle start (the vehicle may not start in the middle of
1724//   a break), in which case it does not affect the vehicle start time.
1725// * or after the vehicle end (ditto, with the vehicle end time).
1726message BreakRule {
1727  // The sequence of breaks (i.e. their number and order) that apply to each
1728  // vehicle must be known beforehand. The repeated `BreakRequest`s define
1729  // that sequence, in the order in which they must occur. Their time windows
1730  // (`earliest_start_time` / `latest_start_time`) may overlap, but they must
1731  // be compatible with the order (this is checked).
1732  message BreakRequest {
1733    // Required. Lower bound (inclusive) on the start of the break.
1734    google.protobuf.Timestamp earliest_start_time = 1
1735        [(google.api.field_behavior) = REQUIRED];
1736
1737    // Required. Upper bound (inclusive) on the start of the break.
1738    google.protobuf.Timestamp latest_start_time = 2
1739        [(google.api.field_behavior) = REQUIRED];
1740
1741    // Required. Minimum duration of the break. Must be positive.
1742    google.protobuf.Duration min_duration = 3
1743        [(google.api.field_behavior) = REQUIRED];
1744  }
1745
1746  // One may further constrain the frequency and duration of the breaks
1747  // specified above, by enforcing a minimum break frequency, such as
1748  // "There must be a break of at least 1 hour every 12 hours". Assuming that
1749  // this can be interpreted as "Within any sliding time window of 12h, there
1750  // must be at least one break of at least one hour", that example would
1751  // translate to the following `FrequencyConstraint`:
1752  // ```
1753  // {
1754  //    min_break_duration { seconds: 3600 }         # 1 hour.
1755  //    max_inter_break_duration { seconds: 39600 }  # 11 hours (12 - 1 = 11).
1756  // }
1757  // ```
1758  //
1759  // The timing and duration of the breaks in the solution will respect all
1760  // such constraints, in addition to the time windows and minimum durations
1761  // already specified in the `BreakRequest`.
1762  //
1763  // A `FrequencyConstraint` may in practice apply to non-consecutive breaks.
1764  // For example, the following schedule honors the "1h every 12h" example:
1765  // ```
1766  //   04:00 vehicle start
1767  //    .. performing travel and visits ..
1768  //   09:00 1 hour break
1769  //   10:00 end of the break
1770  //    .. performing travel and visits ..
1771  //   12:00 20-min lunch break
1772  //   12:20 end of the break
1773  //    .. performing travel and visits ..
1774  //   21:00 1 hour break
1775  //   22:00 end of the break
1776  //    .. performing travel and visits ..
1777  //   23:59 vehicle end
1778  // ```
1779  message FrequencyConstraint {
1780    // Required. Minimum break duration for this constraint. Nonnegative.
1781    // See description of `FrequencyConstraint`.
1782    google.protobuf.Duration min_break_duration = 1
1783        [(google.api.field_behavior) = REQUIRED];
1784
1785    // Required. Maximum allowed span of any interval of time in the route that
1786    // does not include at least partially a break of `duration >=
1787    // min_break_duration`. Must be positive.
1788    google.protobuf.Duration max_inter_break_duration = 2
1789        [(google.api.field_behavior) = REQUIRED];
1790  }
1791
1792  // Sequence of breaks. See the `BreakRequest` message.
1793  repeated BreakRequest break_requests = 1;
1794
1795  // Several `FrequencyConstraint` may apply. They must all be satisfied by
1796  // the `BreakRequest`s of this `BreakRule`. See `FrequencyConstraint`.
1797  repeated FrequencyConstraint frequency_constraints = 2;
1798}
1799
1800// A vehicle's route can be decomposed, along the time axis, like this (we
1801// assume there are n visits):
1802// ```
1803//   |            |            |          |       |  T[2], |        |      |
1804//   | Transition |  Visit #0  |          |       |  V[2], |        |      |
1805//   |     #0     |    aka     |   T[1]   |  V[1] |  ...   | V[n-1] | T[n] |
1806//   |  aka T[0]  |    V[0]    |          |       | V[n-2],|        |      |
1807//   |            |            |          |       | T[n-1] |        |      |
1808//   ^            ^            ^          ^       ^        ^        ^      ^
1809// vehicle    V[0].start   V[0].end     V[1].   V[1].    V[n].    V[n]. vehicle
1810//  start     (arrival)   (departure)   start   end      start    end     end
1811// ```
1812// Note that we make a difference between:
1813//
1814// * "punctual events", such as the vehicle start and end and each visit's start
1815//   and end (aka arrival and departure). They happen at a given second.
1816// * "time intervals", such as the visits themselves, and the transition between
1817//   visits. Though time intervals can sometimes have zero duration, i.e. start
1818//   and end at the same second, they often have a positive duration.
1819//
1820// Invariants:
1821//
1822// * If there are n visits, there are n+1 transitions.
1823// * A visit is always surrounded by a transition before it (same index) and a
1824//   transition after it (index + 1).
1825// * The vehicle start is always followed by transition #0.
1826// * The vehicle end is always preceded by transition #n.
1827//
1828// Zooming in, here is what happens during a `Transition` and a `Visit`:
1829// ```
1830// ---+-------------------------------------+-----------------------------+-->
1831//    |           TRANSITION[i]             |           VISIT[i]          |
1832//    |                                     |                             |
1833//    |  * TRAVEL: the vehicle moves from   |      PERFORM the visit:     |
1834//    |    VISIT[i-1].departure_location to |                             |
1835//    |    VISIT[i].arrival_location, which |  * Spend some time:         |
1836//    |    takes a given travel duration    |    the "visit duration".    |
1837//    |    and distance                     |                             |
1838//    |                                     |  * Load or unload           |
1839//    |  * BREAKS: the driver may have      |    some quantities from the |
1840//    |    breaks (e.g. lunch break).       |    vehicle: the "demand".   |
1841//    |                                     |                             |
1842//    |  * WAIT: the driver/vehicle does    |                             |
1843//    |    nothing. This can happen for     |                             |
1844//    |    many reasons, for example when   |                             |
1845//    |    the vehicle reaches the next     |                             |
1846//    |    event's destination before the   |                             |
1847//    |    start of its time window         |                             |
1848//    |                                     |                             |
1849//    |  * DELAY: *right before* the next   |                             |
1850//    |    arrival. E.g. the vehicle and/or |                             |
1851//    |    driver spends time unloading.    |                             |
1852//    |                                     |                             |
1853// ---+-------------------------------------+-----------------------------+-->
1854//    ^                                     ^                             ^
1855// V[i-1].end                           V[i].start                    V[i].end
1856// ```
1857// Lastly, here is how the TRAVEL, BREAKS, DELAY and WAIT can be arranged
1858// during a transition.
1859//
1860// * They don't overlap.
1861// * The DELAY is unique and *must* be a contiguous period of time right
1862//   before the next visit (or vehicle end). Thus, it suffice to know the
1863//   delay duration to know its start and end time.
1864// * The BREAKS are contiguous, non-overlapping periods of time. The
1865//   response specifies the start time and duration of each break.
1866// * TRAVEL and WAIT are "preemptable": they can be interrupted several times
1867//   during this transition. Clients can assume that travel happens "as soon as
1868//   possible" and that "wait" fills the remaining time.
1869//
1870// A (complex) example:
1871// ```
1872//                                TRANSITION[i]
1873// --++-----+-----------------------------------------------------------++-->
1874//   ||     |       |           |       |           |         |         ||
1875//   ||  T  |   B   |     T     |       |     B     |         |    D    ||
1876//   ||  r  |   r   |     r     |   W   |     r     |    W    |    e    ||
1877//   ||  a  |   e   |     a     |   a   |     e     |    a    |    l    ||
1878//   ||  v  |   a   |     v     |   i   |     a     |    i    |    a    ||
1879//   ||  e  |   k   |     e     |   t   |     k     |    t    |    y    ||
1880//   ||  l  |       |     l     |       |           |         |         ||
1881//   ||     |       |           |       |           |         |         ||
1882// --++-----------------------------------------------------------------++-->
1883// ```
1884message ShipmentRoute {
1885  // Deprecated: Use
1886  // [ShipmentRoute.Transition.delay_duration][google.cloud.optimization.v1.ShipmentRoute.Transition.delay_duration]
1887  // instead. Time interval spent on the route resulting from a
1888  // [TransitionAttributes.delay][google.cloud.optimization.v1.TransitionAttributes.delay].
1889  message Delay {
1890    option deprecated = true;
1891
1892    // Start of the delay.
1893    google.protobuf.Timestamp start_time = 1;
1894
1895    // Duration of the delay.
1896    google.protobuf.Duration duration = 2;
1897  }
1898
1899  // A visit performed during a route. This visit corresponds to a pickup or a
1900  // delivery of a `Shipment`.
1901  message Visit {
1902    // Index of the `shipments` field in the source
1903    // [ShipmentModel][google.cloud.optimization.v1.ShipmentModel].
1904    int32 shipment_index = 1;
1905
1906    // If true the visit corresponds to a pickup of a `Shipment`. Otherwise, it
1907    // corresponds to a delivery.
1908    bool is_pickup = 2;
1909
1910    // Index of `VisitRequest` in either the pickup or delivery field of the
1911    // `Shipment` (see `is_pickup`).
1912    int32 visit_request_index = 3;
1913
1914    // Time at which the visit starts. Note that the vehicle may arrive earlier
1915    // than this at the visit location. Times are consistent with the
1916    // `ShipmentModel`.
1917    google.protobuf.Timestamp start_time = 4;
1918
1919    // Total visit load demand as the sum of the shipment and the visit request
1920    // `load_demands`. The values are negative if the visit is a delivery.
1921    // Demands are reported for the same types as the
1922    // [Transition.loads][google.cloud.optimization.v1.ShipmentRoute.Transition]
1923    // (see this field).
1924    map<string, Shipment.Load> load_demands = 11;
1925
1926    // Extra detour time due to the shipments visited on the route before the
1927    // visit and to the potential waiting time induced by time windows.
1928    // If the visit is a delivery, the detour is computed from the corresponding
1929    // pickup visit and is equal to:
1930    // ```
1931    // start_time(delivery) - start_time(pickup)
1932    // - (duration(pickup) + travel duration from the pickup location
1933    // to the delivery location).
1934    // ```
1935    // Otherwise, it is computed from the vehicle `start_location` and is equal
1936    // to:
1937    // ```
1938    // start_time - vehicle_start_time - travel duration from
1939    // the vehicle's `start_location` to the visit.
1940    // ```
1941    google.protobuf.Duration detour = 6;
1942
1943    // Copy of the corresponding `Shipment.label`, if specified in the
1944    // `Shipment`.
1945    string shipment_label = 7;
1946
1947    // Copy of the corresponding
1948    // [VisitRequest.label][google.cloud.optimization.v1.Shipment.VisitRequest.label],
1949    // if specified in the `VisitRequest`.
1950    string visit_label = 8;
1951
1952    // Deprecated: Use
1953    // [Transition.vehicle_loads][google.cloud.optimization.v1.ShipmentRoute.Transition.vehicle_loads]
1954    // instead. Vehicle loads upon arrival at the visit location, for each type
1955    // specified in
1956    // [Vehicle.capacities][google.cloud.optimization.v1.Vehicle.capacities],
1957    // `start_load_intervals`, `end_load_intervals` or `demands`.
1958    //
1959    // Exception: we omit loads for quantity types unconstrained by intervals
1960    // and that don't have any non-zero demand on the route.
1961    repeated CapacityQuantity arrival_loads = 9 [deprecated = true];
1962
1963    // Deprecated: Use
1964    // [ShipmentRoute.Transition.delay_duration][google.cloud.optimization.v1.ShipmentRoute.Transition.delay_duration]
1965    // instead. Delay occurring before the visit starts.
1966    Delay delay_before_start = 10 [deprecated = true];
1967
1968    // Deprecated: Use
1969    // [Visit.load_demands][google.cloud.optimization.v1.ShipmentRoute.Visit.load_demands]
1970    // instead.
1971    repeated CapacityQuantity demands = 5 [deprecated = true];
1972  }
1973
1974  // Transition between two events on the route. See the description of
1975  // [ShipmentRoute][google.cloud.optimization.v1.ShipmentRoute].
1976  //
1977  // If the vehicle does not have a `start_location` and/or `end_location`, the
1978  // corresponding travel metrics are 0.
1979  message Transition {
1980    // Travel duration during this transition.
1981    google.protobuf.Duration travel_duration = 1;
1982
1983    // Distance traveled during the transition.
1984    double travel_distance_meters = 2;
1985
1986    // When traffic is requested via
1987    // [OptimizeToursRequest.consider_road_traffic]
1988    // [google.cloud.optimization.v1.OptimizeToursRequest.consider_road_traffic],
1989    // and the traffic info couldn't be retrieved for a `Transition`, this
1990    // boolean is set to true. This may be temporary (rare hiccup in the
1991    // realtime traffic servers) or permanent (no data for this location).
1992    bool traffic_info_unavailable = 3;
1993
1994    // Sum of the delay durations applied to this transition. If any, the delay
1995    // starts exactly `delay_duration` seconds before the next event (visit or
1996    // vehicle end). See
1997    // [TransitionAttributes.delay][google.cloud.optimization.v1.TransitionAttributes.delay].
1998    google.protobuf.Duration delay_duration = 4;
1999
2000    // Sum of the duration of the breaks occurring during this transition, if
2001    // any. Details about each break's start time and duration are stored in
2002    // [ShipmentRoute.breaks][google.cloud.optimization.v1.ShipmentRoute.breaks].
2003    google.protobuf.Duration break_duration = 5;
2004
2005    // Time spent waiting during this transition. Wait duration corresponds to
2006    // idle time and does not include break time. Also note that this wait time
2007    // may be split into several non-contiguous intervals.
2008    google.protobuf.Duration wait_duration = 6;
2009
2010    // Total duration of the transition, provided for convenience. It is equal
2011    // to:
2012    //
2013    // * next visit `start_time` (or `vehicle_end_time` if this is the last
2014    // transition) - this transition's `start_time`;
2015    // * if `ShipmentRoute.has_traffic_infeasibilities` is false, the following
2016    // additionally holds: `total_duration = travel_duration + delay_duration
2017    // + break_duration + wait_duration`.
2018    google.protobuf.Duration total_duration = 7;
2019
2020    // Start time of this transition.
2021    google.protobuf.Timestamp start_time = 8;
2022
2023    // The encoded polyline representation of the route followed during the
2024    // transition.
2025    // This field is only populated if [populate_transition_polylines]
2026    // [google.cloud.optimization.v1.OptimizeToursRequest.populate_transition_polylines]
2027    // is set to true.
2028    EncodedPolyline route_polyline = 9;
2029
2030    // Vehicle loads during this transition, for each type that either appears
2031    // in this vehicle's
2032    // [Vehicle.load_limits][google.cloud.optimization.v1.Vehicle.load_limits],
2033    // or that have non-zero
2034    // [Shipment.load_demands][google.cloud.optimization.v1.Shipment.load_demands]
2035    // on some shipment performed on this route.
2036    //
2037    // The loads during the first transition are the starting loads of the
2038    // vehicle route. Then, after each visit, the visit's `load_demands` are
2039    // either added or subtracted to get the next transition's loads, depending
2040    // on whether the visit was a pickup or a delivery.
2041    map<string, VehicleLoad> vehicle_loads = 11;
2042
2043    // Deprecated: Use
2044    // [Transition.vehicle_loads][google.cloud.optimization.v1.ShipmentRoute.Transition.vehicle_loads]
2045    // instead.
2046    repeated CapacityQuantity loads = 10 [deprecated = true];
2047  }
2048
2049  // Reports the actual load of the vehicle at some point along the route,
2050  // for a given type (see
2051  // [Transition.vehicle_loads][google.cloud.optimization.v1.ShipmentRoute.Transition.vehicle_loads]).
2052  message VehicleLoad {
2053    // The amount of load on the vehicle, for the given type. The unit of load
2054    // is usually indicated by the type. See
2055    // [Transition.vehicle_loads][google.cloud.optimization.v1.ShipmentRoute.Transition.vehicle_loads].
2056    int64 amount = 1;
2057  }
2058
2059  // The encoded representation of a polyline. More information on polyline
2060  // encoding can be found here:
2061  // https://developers.google.com/maps/documentation/utilities/polylinealgorithm
2062  // https://developers.google.com/maps/documentation/javascript/reference/geometry#encoding.
2063  message EncodedPolyline {
2064    // String representing encoded points of the polyline.
2065    string points = 1;
2066  }
2067
2068  // Data representing the execution of a break.
2069  message Break {
2070    // Start time of a break.
2071    google.protobuf.Timestamp start_time = 1;
2072
2073    // Duration of a break.
2074    google.protobuf.Duration duration = 2;
2075  }
2076
2077  // Deprecated: Use
2078  // [ShipmentRoute.Transition][google.cloud.optimization.v1.ShipmentRoute.Transition]
2079  // instead. Travel between each visit along the route: from the vehicle's
2080  // `start_location` to the first visit's `arrival_location`, then from the
2081  // first visit's `departure_location` to the second visit's
2082  // `arrival_location`, and so on until the vehicle's `end_location`. This
2083  // accounts only for the actual travel between visits, not counting the
2084  // waiting time, the time spent performing a visit, nor the distance covered
2085  // during a visit.
2086  //
2087  // Invariant: `travel_steps_size() == visits_size() + 1`.
2088  //
2089  // If the vehicle does not have a start_ and/or end_location, the
2090  // corresponding travel metrics are 0 and/or empty.
2091  message TravelStep {
2092    option deprecated = true;
2093
2094    // Duration of the travel step.
2095    google.protobuf.Duration duration = 1;
2096
2097    // Distance traveled during the step.
2098    double distance_meters = 2;
2099
2100    // When traffic is requested via
2101    // [OptimizeToursRequest.consider_road_traffic][google.cloud.optimization.v1.OptimizeToursRequest.consider_road_traffic],
2102    // and the traffic info couldn't be retrieved for a TravelStep, this boolean
2103    // is set to true. This may be temporary (rare hiccup in the realtime
2104    // traffic servers) or permanent (no data for this location).
2105    bool traffic_info_unavailable = 3;
2106
2107    // The encoded polyline representation of the route followed during the
2108    // step.
2109    //
2110    // This field is only populated if
2111    // [OptimizeToursRequest.populate_travel_step_polylines][google.cloud.optimization.v1.OptimizeToursRequest.populate_travel_step_polylines]
2112    // is set to true.
2113    EncodedPolyline route_polyline = 4;
2114  }
2115
2116  // Vehicle performing the route, identified by its index in the source
2117  // `ShipmentModel`.
2118  int32 vehicle_index = 1;
2119
2120  // Label of the vehicle performing this route, equal to
2121  // `ShipmentModel.vehicles(vehicle_index).label`, if specified.
2122  string vehicle_label = 2;
2123
2124  // Time at which the vehicle starts its route.
2125  google.protobuf.Timestamp vehicle_start_time = 5;
2126
2127  // Time at which the vehicle finishes its route.
2128  google.protobuf.Timestamp vehicle_end_time = 6;
2129
2130  // Ordered sequence of visits representing a route.
2131  // visits[i] is the i-th visit in the route.
2132  // If this field is empty, the vehicle is considered as unused.
2133  repeated Visit visits = 7;
2134
2135  // Ordered list of transitions for the route.
2136  repeated Transition transitions = 8;
2137
2138  // When
2139  // [OptimizeToursRequest.consider_road_traffic][google.cloud.optimization.v1.OptimizeToursRequest.consider_road_traffic],
2140  // is set to true, this field indicates that inconsistencies in route timings
2141  // are predicted using traffic-based travel duration estimates. There may be
2142  // insufficient time to complete traffic-adjusted travel, delays, and breaks
2143  // between visits, before the first visit, or after the last visit, while
2144  // still satisfying the visit and vehicle time windows. For example,
2145  //
2146  // ```
2147  //   start_time(previous_visit) + duration(previous_visit) +
2148  //   travel_duration(previous_visit, next_visit) > start_time(next_visit)
2149  // ```
2150  //
2151  // Arrival at next_visit will likely happen later than its current
2152  // time window due the increased estimate of travel time
2153  // `travel_duration(previous_visit, next_visit)` due to traffic. Also, a break
2154  // may be forced to overlap with a visit due to an increase in travel time
2155  // estimates and visit or break time window restrictions.
2156  bool has_traffic_infeasibilities = 9;
2157
2158  // The encoded polyline representation of the route.
2159  // This field is only populated if
2160  // [OptimizeToursRequest.populate_polylines][google.cloud.optimization.v1.OptimizeToursRequest.populate_polylines]
2161  // is set to true.
2162  EncodedPolyline route_polyline = 10;
2163
2164  // Breaks scheduled for the vehicle performing this route.
2165  // The `breaks` sequence represents time intervals, each starting at the
2166  // corresponding `start_time` and lasting `duration` seconds.
2167  repeated Break breaks = 11;
2168
2169  // Duration, distance and load metrics for this route. The fields of
2170  // [AggregatedMetrics][google.cloud.optimization.v1.AggregatedMetrics] are
2171  // summed over all
2172  // [ShipmentRoute.transitions][google.cloud.optimization.v1.ShipmentRoute.transitions]
2173  // or
2174  // [ShipmentRoute.visits][google.cloud.optimization.v1.ShipmentRoute.visits],
2175  // depending on the context.
2176  AggregatedMetrics metrics = 12;
2177
2178  // Cost of the route, broken down by cost-related request fields.
2179  // The keys are proto paths, relative to the input OptimizeToursRequest, e.g.
2180  // "model.shipments.pickups.cost", and the values are the total cost
2181  // generated by the corresponding cost field, aggregated over the whole route.
2182  // In other words, costs["model.shipments.pickups.cost"] is the sum of all
2183  // pickup costs over the route. All costs defined in the model are reported in
2184  // detail here with the exception of costs related to TransitionAttributes
2185  // that are only reported in an aggregated way as of 2022/01.
2186  map<string, double> route_costs = 17;
2187
2188  // Total cost of the route. The sum of all costs in the cost map.
2189  double route_total_cost = 18;
2190
2191  // Deprecated: Use
2192  // [Transition.vehicle_loads][google.cloud.optimization.v1.ShipmentRoute.Transition.vehicle_loads]
2193  // instead. Vehicle loads upon arrival at its end location, for each type
2194  // specified in
2195  // [Vehicle.capacities][google.cloud.optimization.v1.Vehicle.capacities],
2196  // `start_load_intervals`, `end_load_intervals` or demands. Exception: we omit
2197  // loads for quantity types unconstrained by intervals and that don't have any
2198  // non-zero demand on the route.
2199  repeated CapacityQuantity end_loads = 13 [deprecated = true];
2200
2201  // Deprecated: Use
2202  // [ShipmentRoute.transitions][google.cloud.optimization.v1.ShipmentRoute.transitions]
2203  // instead. Ordered list of travel steps for the route.
2204  repeated TravelStep travel_steps = 14 [deprecated = true];
2205
2206  // Deprecated: No longer used.
2207  // This field will only be populated at the
2208  // [ShipmentRoute.Visit][google.cloud.optimization.v1.ShipmentRoute.Visit]
2209  // level.
2210  //
2211  // This field is the extra detour time due to the shipments visited on the
2212  // route.
2213  //
2214  // It is equal to `vehicle_end_time` - `vehicle_start_time` - travel duration
2215  // from the vehicle's start_location to its `end_location`.
2216  google.protobuf.Duration vehicle_detour = 15 [deprecated = true];
2217
2218  // Deprecated: Delay occurring before the vehicle end. See
2219  // [TransitionAttributes.delay][google.cloud.optimization.v1.TransitionAttributes.delay].
2220  Delay delay_before_vehicle_end = 16 [deprecated = true];
2221}
2222
2223// Specifies details of unperformed shipments in a solution. For trivial cases
2224// and/or if we are able to identify the cause for skipping, we report the
2225// reason here.
2226message SkippedShipment {
2227  // If we can explain why the shipment was skipped, reasons will be listed
2228  // here. If the reason is not the same for all vehicles, `reason` will have
2229  // more than 1 element. A skipped shipment cannot have duplicate reasons,
2230  // i.e. where all fields are the same except for `example_vehicle_index`.
2231  // Example:
2232  // ```
2233  // reasons {
2234  //   code: DEMAND_EXCEEDS_VEHICLE_CAPACITY
2235  //   example_vehicle_index: 1
2236  //   example_exceeded_capacity_type: "Apples"
2237  // }
2238  // reasons {
2239  //   code: DEMAND_EXCEEDS_VEHICLE_CAPACITY
2240  //   example_vehicle_index: 3
2241  //   example_exceeded_capacity_type: "Pears"
2242  // }
2243  // reasons {
2244  //   code: CANNOT_BE_PERFORMED_WITHIN_VEHICLE_DISTANCE_LIMIT
2245  //   example_vehicle_index: 1
2246  // }
2247  // ```
2248  // The skipped shipment is incompatible with all vehicles. The reasons may
2249  // be different for all vehicles but at least one vehicle's "Apples"
2250  // capacity would be exceeded (including vehicle 1), at least one vehicle's
2251  // "Pears" capacity would be exceeded (including vehicle 3) and at least one
2252  // vehicle's distance limit would be exceeded (including vehicle 1).
2253  message Reason {
2254    // Code identifying the reason type. The order here is meaningless. In
2255    // particular, it gives no indication of whether a given reason will
2256    // appear before another in the solution, if both apply.
2257    enum Code {
2258      // This should never be used. If we are unable to understand why a
2259      // shipment was skipped, we simply return an empty set of reasons.
2260      CODE_UNSPECIFIED = 0;
2261
2262      // There is no vehicle in the model making all shipments infeasible.
2263      NO_VEHICLE = 1;
2264
2265      // The demand of the shipment exceeds a vehicle's capacity for some
2266      // capacity types, one of which is `example_exceeded_capacity_type`.
2267      DEMAND_EXCEEDS_VEHICLE_CAPACITY = 2;
2268
2269      // The minimum distance necessary to perform this shipment, i.e. from
2270      // the vehicle's `start_location` to the shipment's pickup and/or delivery
2271      // locations and to the vehicle's end location exceeds the vehicle's
2272      // `route_distance_limit`.
2273      //
2274      // Note that for this computation we use the geodesic distances.
2275      CANNOT_BE_PERFORMED_WITHIN_VEHICLE_DISTANCE_LIMIT = 3;
2276
2277      // The minimum time necessary to perform this shipment, including travel
2278      // time, wait time and service time exceeds the vehicle's
2279      // `route_duration_limit`.
2280      //
2281      // Note: travel time is computed in the best-case scenario, namely as
2282      // geodesic distance x 36 m/s (roughly 130 km/hour).
2283      CANNOT_BE_PERFORMED_WITHIN_VEHICLE_DURATION_LIMIT = 4;
2284
2285      // Same as above but we only compare minimum travel time and the
2286      // vehicle's `travel_duration_limit`.
2287      CANNOT_BE_PERFORMED_WITHIN_VEHICLE_TRAVEL_DURATION_LIMIT = 5;
2288
2289      // The vehicle cannot perform this shipment in the best-case scenario
2290      // (see `CANNOT_BE_PERFORMED_WITHIN_VEHICLE_DURATION_LIMIT` for time
2291      // computation) if it starts at its earliest start time: the total time
2292      // would make the vehicle end after its latest end time.
2293      CANNOT_BE_PERFORMED_WITHIN_VEHICLE_TIME_WINDOWS = 6;
2294
2295      // The `allowed_vehicle_indices` field of the shipment is not empty and
2296      // this vehicle does not belong to it.
2297      VEHICLE_NOT_ALLOWED = 7;
2298    }
2299
2300    // Refer to the comments of Code.
2301    Code code = 1;
2302
2303    // If the reason is related to a shipment-vehicle incompatibility, this
2304    // field provides the index of one relevant vehicle.
2305    optional int32 example_vehicle_index = 2;
2306
2307    // If the reason code is `DEMAND_EXCEEDS_VEHICLE_CAPACITY`, documents one
2308    // capacity type that is exceeded.
2309    string example_exceeded_capacity_type = 3;
2310  }
2311
2312  // The index corresponds to the index of the shipment in the source
2313  // `ShipmentModel`.
2314  int32 index = 1;
2315
2316  // Copy of the corresponding
2317  // [Shipment.label][google.cloud.optimization.v1.Shipment.label], if specified
2318  // in the `Shipment`.
2319  string label = 2;
2320
2321  // A list of reasons that explain why the shipment was skipped. See comment
2322  // above `Reason`.
2323  repeated Reason reasons = 3;
2324}
2325
2326// Aggregated metrics for
2327// [ShipmentRoute][google.cloud.optimization.v1.ShipmentRoute] (resp. for
2328// [OptimizeToursResponse][google.cloud.optimization.v1.OptimizeToursResponse]
2329// over all [Transition][google.cloud.optimization.v1.ShipmentRoute.Transition]
2330// and/or [Visit][google.cloud.optimization.v1.ShipmentRoute.Visit] (resp. over
2331// all [ShipmentRoute][google.cloud.optimization.v1.ShipmentRoute]) elements.
2332message AggregatedMetrics {
2333  // Number of shipments performed. Note that a pickup and delivery pair only
2334  // counts once.
2335  int32 performed_shipment_count = 1;
2336
2337  // Total travel duration for a route or a solution.
2338  google.protobuf.Duration travel_duration = 2;
2339
2340  // Total wait duration for a route or a solution.
2341  google.protobuf.Duration wait_duration = 3;
2342
2343  // Total delay duration for a route or a solution.
2344  google.protobuf.Duration delay_duration = 4;
2345
2346  // Total break duration for a route or a solution.
2347  google.protobuf.Duration break_duration = 5;
2348
2349  // Total visit duration for a route or a solution.
2350  google.protobuf.Duration visit_duration = 6;
2351
2352  // The total duration should be equal to the sum of all durations above.
2353  // For routes, it also corresponds to:
2354  // [ShipmentRoute.vehicle_end_time][google.cloud.optimization.v1.ShipmentRoute.vehicle_end_time]
2355  // `-`
2356  // [ShipmentRoute.vehicle_start_time][google.cloud.optimization.v1.ShipmentRoute.vehicle_start_time]
2357  google.protobuf.Duration total_duration = 7;
2358
2359  // Total travel distance for a route or a solution.
2360  double travel_distance_meters = 8;
2361
2362  // Maximum load achieved over the entire route (resp. solution), for each of
2363  // the quantities on this route (resp. solution), computed as the maximum over
2364  // all
2365  // [Transition.vehicle_loads][google.cloud.optimization.v1.ShipmentRoute.Transition.vehicle_loads]
2366  // (resp.
2367  // [ShipmentRoute.metrics.max_loads][google.cloud.optimization.v1.AggregatedMetrics.max_loads].
2368  map<string, ShipmentRoute.VehicleLoad> max_loads = 9;
2369
2370  // Deprecated: Use
2371  // [ShipmentRoute.route_costs][google.cloud.optimization.v1.ShipmentRoute.route_costs]
2372  // and
2373  // [OptimizeToursResponse.Metrics.costs][google.cloud.optimization.v1.OptimizeToursResponse.Metrics.costs]
2374  // instead.
2375  map<string, double> costs = 10 [deprecated = true];
2376
2377  // Deprecated: Use
2378  // [ShipmentRoute.route_total_cost][google.cloud.optimization.v1.ShipmentRoute.route_total_cost]
2379  // and
2380  // [OptimizeToursResponse.Metrics.total_cost][google.cloud.optimization.v1.OptimizeToursResponse.Metrics.total_cost]
2381  // instead.
2382  double total_cost = 11 [deprecated = true];
2383}
2384
2385// Solution injected in the request including information about which visits
2386// must be constrained and how they must be constrained.
2387message InjectedSolutionConstraint {
2388  // For a group of vehicles, specifies at what threshold(s) constraints on
2389  // visits will be relaxed and to which level. Shipments listed in
2390  // the `skipped_shipment` field are constrained to be skipped; i.e., they
2391  // cannot be performed.
2392  message ConstraintRelaxation {
2393    // If `relaxations` is empty, the start time and sequence of all visits
2394    // on `routes` are fully constrained and no new visits may be inserted or
2395    // added to those routes. Also, a vehicle's start and end time in
2396    // `routes` is fully constrained, unless the vehicle is empty (i.e., has no
2397    // visits and has `used_if_route_is_empty` set to false in the model).
2398    //
2399    // `relaxations(i).level` specifies the constraint relaxation level applied
2400    // to a visit #j that satisfies:
2401    //
2402    //   * `route.visits(j).start_time >= relaxations(i).threshold_time` AND
2403    //   * `j + 1 >= relaxations(i).threshold_visit_count`
2404    //
2405    // Similarly, the vehicle start is relaxed to `relaxations(i).level` if it
2406    // satisfies:
2407    //
2408    //   * `vehicle_start_time >= relaxations(i).threshold_time` AND
2409    //   * `relaxations(i).threshold_visit_count == 0`
2410    // and the vehicle end is relaxed to `relaxations(i).level` if it satisfies:
2411    //   * `vehicle_end_time >= relaxations(i).threshold_time` AND
2412    //   * `route.visits_size() + 1 >= relaxations(i).threshold_visit_count`
2413    //
2414    // To apply a relaxation level if a visit meets the `threshold_visit_count`
2415    // OR the `threshold_time` add two `relaxations` with the same `level`:
2416    // one with only `threshold_visit_count` set and the other with only
2417    // `threshold_time` set. If a visit satisfies the conditions of multiple
2418    // `relaxations`, the most relaxed level applies. As a result, from the
2419    // vehicle start through the route visits in order to the vehicle end, the
2420    // relaxation level becomes more relaxed: i.e., the relaxation level is
2421    // non-decreasing as the route progresses.
2422    //
2423    // The timing and sequence of route visits that do not satisfy the
2424    // threshold conditions of any `relaxations` are fully constrained
2425    // and no visits may be inserted into these sequences. Also, if a
2426    // vehicle start or end does not satisfy the conditions of any
2427    // relaxation the time is fixed, unless the vehicle is empty.
2428    message Relaxation {
2429      // Expresses the different constraint relaxation levels, which are
2430      // applied for a visit and those that follow when it satisfies the
2431      // threshold conditions.
2432      //
2433      // The enumeration below is in order of increasing relaxation.
2434      enum Level {
2435        // Implicit default relaxation level: no constraints are relaxed,
2436        // i.e., all visits are fully constrained.
2437        //
2438        // This value must not be explicitly used in `level`.
2439        LEVEL_UNSPECIFIED = 0;
2440
2441        // Visit start times and vehicle start/end times will be relaxed, but
2442        // each visit remains bound to the same vehicle and the visit sequence
2443        // must be observed: no visit can be inserted between them or before
2444        // them.
2445        RELAX_VISIT_TIMES_AFTER_THRESHOLD = 1;
2446
2447        // Same as `RELAX_VISIT_TIMES_AFTER_THRESHOLD`, but the visit sequence
2448        // is also relaxed: visits can only be performed by this vehicle, but
2449        // can potentially become unperformed.
2450        RELAX_VISIT_TIMES_AND_SEQUENCE_AFTER_THRESHOLD = 2;
2451
2452        // Same as `RELAX_VISIT_TIMES_AND_SEQUENCE_AFTER_THRESHOLD`, but the
2453        // vehicle is also relaxed: visits are completely free at or after the
2454        // threshold time and can potentially become unperformed.
2455        RELAX_ALL_AFTER_THRESHOLD = 3;
2456      }
2457
2458      // The constraint relaxation level that applies when the conditions
2459      // at or after `threshold_time` AND at least `threshold_visit_count` are
2460      // satisfied.
2461      Level level = 1;
2462
2463      // The time at or after which the relaxation `level` may be applied.
2464      google.protobuf.Timestamp threshold_time = 2;
2465
2466      // The number of visits at or after which the relaxation `level` may be
2467      // applied. If `threshold_visit_count` is 0 (or unset), the `level` may be
2468      // applied directly at the vehicle start.
2469      //
2470      // If it is `route.visits_size() + 1`, the `level` may only be applied to
2471      // the vehicle end. If it is more than `route.visits_size() + 1`,
2472      // `level` is not applied at all for that route.
2473      int32 threshold_visit_count = 3;
2474    }
2475
2476    // All the visit constraint relaxations that will apply to visits on
2477    // routes with vehicles in `vehicle_indices`.
2478    repeated Relaxation relaxations = 1;
2479
2480    // Specifies the vehicle indices to which the visit constraint
2481    // `relaxations` apply. If empty, this is considered the default and the
2482    // `relaxations` apply to all vehicles that are not specified in other
2483    // `constraint_relaxations`. There can be at most one default, i.e., at
2484    // most one constraint relaxation field is allowed empty
2485    // `vehicle_indices`. A vehicle index can only be listed once, even within
2486    // several `constraint_relaxations`.
2487    //
2488    // A vehicle index is mapped the same as
2489    // [ShipmentRoute.vehicle_index][google.cloud.optimization.v1.ShipmentRoute.vehicle_index],
2490    // if `interpret_injected_solutions_using_labels` is true (see `fields`
2491    // comment).
2492    repeated int32 vehicle_indices = 2;
2493  }
2494
2495  // Routes of the solution to inject. Some routes may be omitted from the
2496  // original solution. The routes and skipped shipments must satisfy the basic
2497  // validity assumptions listed for `injected_first_solution_routes`.
2498  repeated ShipmentRoute routes = 1;
2499
2500  // Skipped shipments of the solution to inject. Some may be omitted from the
2501  // original solution. See the `routes` field.
2502  repeated SkippedShipment skipped_shipments = 2;
2503
2504  // For zero or more groups of vehicles, specifies when and how much to relax
2505  // constraints. If this field is empty, all non-empty vehicle routes are
2506  // fully constrained.
2507  repeated ConstraintRelaxation constraint_relaxations = 3;
2508}
2509
2510// Describes an error encountered when validating an `OptimizeToursRequest`.
2511message OptimizeToursValidationError {
2512  // Specifies a context for the validation error. A `FieldReference` always
2513  // refers to a given field in this file and follows the same hierarchical
2514  // structure. For example, we may specify element #2 of `start_time_windows`
2515  // of vehicle #5 using:
2516  // ```
2517  // name: "vehicles" index: 5 sub_field { name: "end_time_windows" index: 2 }
2518  // ```
2519  // We however omit top-level entities such as `OptimizeToursRequest` or
2520  // `ShipmentModel` to avoid crowding the message.
2521  message FieldReference {
2522    // Name of the field, e.g., "vehicles".
2523    string name = 1;
2524
2525    oneof index_or_key {
2526      // Index of the field if repeated.
2527      int32 index = 2;
2528
2529      // Key if the field is a map.
2530      string key = 4;
2531    }
2532
2533    // Recursively nested sub-field, if needed.
2534    FieldReference sub_field = 3;
2535  }
2536
2537  // A validation error is defined by the pair (`code`, `display_name`) which
2538  // are always present.
2539  //
2540  // Other fields (below) provide more context about the error.
2541  //
2542  // *MULTIPLE ERRORS*:
2543  // When there are multiple errors, the validation process tries to output
2544  // several of them. Much like a compiler, this is an imperfect process. Some
2545  // validation errors will be "fatal", meaning that they stop the entire
2546  // validation process. This is the case for `display_name="UNSPECIFIED"`
2547  // errors, among others. Some may cause the validation process to skip other
2548  // errors.
2549  //
2550  // *STABILITY*:
2551  // `code` and `display_name` should be very stable. But new codes and
2552  // display names may appear over time, which may cause a given (invalid)
2553  // request to yield a different (`code`, `display_name`) pair because the new
2554  // error hid the old one (see "MULTIPLE ERRORS").
2555  //
2556  // *REFERENCE*: A list of all (code, name) pairs:
2557  //
2558  // * UNSPECIFIED = 0;
2559  // * VALIDATION_TIMEOUT_ERROR = 10; Validation couldn't be completed within
2560  // the deadline.
2561  //
2562  // * REQUEST_OPTIONS_ERROR = 12;
2563  //     * REQUEST_OPTIONS_INVALID_SOLVING_MODE = 1201;
2564  //     * REQUEST_OPTIONS_INVALID_MAX_VALIDATION_ERRORS = 1203;
2565  //     * REQUEST_OPTIONS_INVALID_GEODESIC_METERS_PER_SECOND = 1204;
2566  //     * REQUEST_OPTIONS_GEODESIC_METERS_PER_SECOND_TOO_SMALL = 1205;
2567  //     * REQUEST_OPTIONS_MISSING_GEODESIC_METERS_PER_SECOND = 1206;
2568  //     * REQUEST_OPTIONS_POPULATE_PATHFINDER_TRIPS_AND_GEODESIC_DISTANCE
2569  //       = 1207;
2570  //     * REQUEST_OPTIONS_COST_MODEL_OPTIONS_AND_GEODESIC_DISTANCE = 1208;
2571  //     * REQUEST_OPTIONS_TRAVEL_MODE_INCOMPATIBLE_WITH_TRAFFIC = 1211;
2572  //     * REQUEST_OPTIONS_MULTIPLE_TRAFFIC_FLAVORS = 1212;
2573  //     * REQUEST_OPTIONS_INVALID_TRAFFIC_FLAVOR = 1213;
2574  //     * REQUEST_OPTIONS_TRAFFIC_ENABLED_WITHOUT_GLOBAL_START_TIME = 1214;
2575  //     * REQUEST_OPTIONS_TRAFFIC_ENABLED_WITH_PRECEDENCES = 1215;
2576  //     * REQUEST_OPTIONS_TRAFFIC_PREFILL_MODE_INVALID = 1216;
2577  //     * REQUEST_OPTIONS_TRAFFIC_PREFILL_ENABLED_WITHOUT_TRAFFIC = 1217;
2578  // * INJECTED_SOLUTION_ERROR = 20;
2579  //     * INJECTED_SOLUTION_MISSING_LABEL = 2000;
2580  //     * INJECTED_SOLUTION_DUPLICATE_LABEL = 2001;
2581  //     * INJECTED_SOLUTION_AMBIGUOUS_INDEX = 2002;
2582  //     * INJECTED_SOLUTION_INFEASIBLE_AFTER_GETTING_TRAVEL_TIMES = 2003;
2583  //     * INJECTED_SOLUTION_TRANSITION_INCONSISTENT_WITH_ACTUAL_TRAVEL = 2004;
2584  //     * INJECTED_SOLUTION_CONCURRENT_SOLUTION_TYPES = 2005;
2585  //     * INJECTED_SOLUTION_MORE_THAN_ONE_PER_TYPE = 2006;
2586  //     * INJECTED_SOLUTION_REFRESH_WITHOUT_POPULATE = 2008;
2587  //     * INJECTED_SOLUTION_CONSTRAINED_ROUTE_PORTION_INFEASIBLE = 2010;
2588  // * SHIPMENT_MODEL_ERROR = 22;
2589  //     * SHIPMENT_MODEL_TOO_LARGE = 2200;
2590  //     * SHIPMENT_MODEL_TOO_MANY_CAPACITY_TYPES = 2201;
2591  //     * SHIPMENT_MODEL_GLOBAL_START_TIME_NEGATIVE_OR_NAN = 2202;
2592  //     * SHIPMENT_MODEL_GLOBAL_END_TIME_TOO_LARGE_OR_NAN = 2203;
2593  //     * SHIPMENT_MODEL_GLOBAL_START_TIME_AFTER_GLOBAL_END_TIME = 2204;
2594  //     * SHIPMENT_MODEL_GLOBAL_DURATION_TOO_LONG = 2205;
2595  //     * SHIPMENT_MODEL_MAX_ACTIVE_VEHICLES_NOT_POSITIVE = 2206;
2596  //     * SHIPMENT_MODEL_DURATION_MATRIX_TOO_LARGE = 2207;
2597  // * INDEX_ERROR = 24;
2598  // * TAG_ERROR = 26;
2599  // * TIME_WINDOW_ERROR = 28;
2600  //     * TIME_WINDOW_INVALID_START_TIME = 2800;
2601  //     * TIME_WINDOW_INVALID_END_TIME = 2801;
2602  //     * TIME_WINDOW_INVALID_SOFT_START_TIME = 2802;
2603  //     * TIME_WINDOW_INVALID_SOFT_END_TIME = 2803;
2604  //     * TIME_WINDOW_OUTSIDE_GLOBAL_TIME_WINDOW = 2804;
2605  //     * TIME_WINDOW_START_TIME_AFTER_END_TIME = 2805;
2606  //     * TIME_WINDOW_INVALID_COST_PER_HOUR_BEFORE_SOFT_START_TIME = 2806;
2607  //     * TIME_WINDOW_INVALID_COST_PER_HOUR_AFTER_SOFT_END_TIME = 2807;
2608  //     * TIME_WINDOW_COST_BEFORE_SOFT_START_TIME_WITHOUT_SOFT_START_TIME
2609  //       = 2808;
2610  //     * TIME_WINDOW_COST_AFTER_SOFT_END_TIME_WITHOUT_SOFT_END_TIME = 2809;
2611  //     * TIME_WINDOW_SOFT_START_TIME_WITHOUT_COST_BEFORE_SOFT_START_TIME
2612  //       = 2810;
2613  //     * TIME_WINDOW_SOFT_END_TIME_WITHOUT_COST_AFTER_SOFT_END_TIME = 2811;
2614  //     * TIME_WINDOW_OVERLAPPING_ADJACENT_OR_EARLIER_THAN_PREVIOUS = 2812;
2615  //     * TIME_WINDOW_START_TIME_AFTER_SOFT_START_TIME = 2813;
2616  //     * TIME_WINDOW_SOFT_START_TIME_AFTER_END_TIME = 2814;
2617  //     * TIME_WINDOW_START_TIME_AFTER_SOFT_END_TIME = 2815;
2618  //     * TIME_WINDOW_SOFT_END_TIME_AFTER_END_TIME = 2816;
2619  //     * TIME_WINDOW_COST_BEFORE_SOFT_START_TIME_SET_AND_MULTIPLE_WINDOWS
2620  //       = 2817;
2621  //     * TIME_WINDOW_COST_AFTER_SOFT_END_TIME_SET_AND_MULTIPLE_WINDOWS = 2818;
2622  //     * TRANSITION_ATTRIBUTES_ERROR = 30;
2623  //     * TRANSITION_ATTRIBUTES_INVALID_COST = 3000;
2624  //     * TRANSITION_ATTRIBUTES_INVALID_COST_PER_KILOMETER = 3001;
2625  //     * TRANSITION_ATTRIBUTES_DUPLICATE_TAG_PAIR = 3002;
2626  //     * TRANSITION_ATTRIBUTES_DISTANCE_LIMIT_MAX_METERS_UNSUPPORTED = 3003;
2627  //     * TRANSITION_ATTRIBUTES_UNSPECIFIED_SOURCE_TAGS = 3004;
2628  //     * TRANSITION_ATTRIBUTES_CONFLICTING_SOURCE_TAGS_FIELDS = 3005;
2629  //     * TRANSITION_ATTRIBUTES_UNSPECIFIED_DESTINATION_TAGS = 3006;
2630  //     * TRANSITION_ATTRIBUTES_CONFLICTING_DESTINATION_TAGS_FIELDS = 3007;
2631  //     * TRANSITION_ATTRIBUTES_DELAY_DURATION_NEGATIVE_OR_NAN = 3008;
2632  //     * TRANSITION_ATTRIBUTES_DELAY_DURATION_EXCEEDS_GLOBAL_DURATION = 3009;
2633  // * AMOUNT_ERROR = 31;
2634  //     * AMOUNT_NEGATIVE_VALUE = 3100;
2635  // * LOAD_LIMIT_ERROR = 33;
2636  //     * LOAD_LIMIT_INVALID_COST_ABOVE_SOFT_MAX = 3303;
2637  //     * LOAD_LIMIT_SOFT_MAX_WITHOUT_COST_ABOVE_SOFT_MAX = 3304;
2638  //     * LOAD_LIMIT_COST_ABOVE_SOFT_MAX_WITHOUT_SOFT_MAX = 3305;
2639  //     * LOAD_LIMIT_NEGATIVE_SOFT_MAX = 3306;
2640  //     * LOAD_LIMIT_MIXED_DEMAND_TYPE = 3307;
2641  //     * LOAD_LIMIT_MAX_LOAD_NEGATIVE_VALUE = 3308;
2642  //     * LOAD_LIMIT_SOFT_MAX_ABOVE_MAX = 3309;
2643  // * INTERVAL_ERROR = 34;
2644  //     * INTERVAL_MIN_EXCEEDS_MAX = 3401;
2645  //     * INTERVAL_NEGATIVE_MIN = 3402;
2646  //     * INTERVAL_NEGATIVE_MAX = 3403;
2647  //     * INTERVAL_MIN_EXCEEDS_CAPACITY = 3404;
2648  //     * INTERVAL_MAX_EXCEEDS_CAPACITY = 3405;
2649  // * DISTANCE_LIMIT_ERROR = 36;
2650  //     * DISTANCE_LIMIT_INVALID_COST_AFTER_SOFT_MAX = 3601;
2651  //     * DISTANCE_LIMIT_SOFT_MAX_WITHOUT_COST_AFTER_SOFT_MAX = 3602;
2652  //     * DISTANCE_LIMIT_COST_AFTER_SOFT_MAX_WITHOUT_SOFT_MAX = 3603;
2653  //     * DISTANCE_LIMIT_NEGATIVE_MAX = 3604;
2654  //     * DISTANCE_LIMIT_NEGATIVE_SOFT_MAX = 3605;
2655  //     * DISTANCE_LIMIT_SOFT_MAX_LARGER_THAN_MAX = 3606;
2656  // * DURATION_LIMIT_ERROR = 38;
2657  //     * DURATION_LIMIT_MAX_DURATION_NEGATIVE_OR_NAN = 3800;
2658  //     * DURATION_LIMIT_SOFT_MAX_DURATION_NEGATIVE_OR_NAN = 3801;
2659  //     * DURATION_LIMIT_INVALID_COST_PER_HOUR_AFTER_SOFT_MAX = 3802;
2660  //     * DURATION_LIMIT_SOFT_MAX_WITHOUT_COST_AFTER_SOFT_MAX = 3803;
2661  //     * DURATION_LIMIT_COST_AFTER_SOFT_MAX_WITHOUT_SOFT_MAX = 3804;
2662  //     * DURATION_LIMIT_QUADRATIC_SOFT_MAX_DURATION_NEGATIVE_OR_NAN = 3805;
2663  //     * DURATION_LIMIT_INVALID_COST_AFTER_QUADRATIC_SOFT_MAX = 3806;
2664  //     * DURATION_LIMIT_QUADRATIC_SOFT_MAX_WITHOUT_COST_PER_SQUARE_HOUR
2665  //       = 3807;
2666  //     * DURATION_LIMIT_COST_PER_SQUARE_HOUR_WITHOUT_QUADRATIC_SOFT_MAX
2667  //       = 3808;
2668  //     * DURATION_LIMIT_QUADRATIC_SOFT_MAX_WITHOUT_MAX = 3809;
2669  //     * DURATION_LIMIT_SOFT_MAX_LARGER_THAN_MAX = 3810;
2670  //     * DURATION_LIMIT_QUADRATIC_SOFT_MAX_LARGER_THAN_MAX = 3811;
2671  //     * DURATION_LIMIT_DIFF_BETWEEN_MAX_AND_QUADRATIC_SOFT_MAX_TOO_LARGE
2672  //       = 3812;
2673  //     * DURATION_LIMIT_MAX_DURATION_EXCEEDS_GLOBAL_DURATION = 3813;
2674  //     * DURATION_LIMIT_SOFT_MAX_DURATION_EXCEEDS_GLOBAL_DURATION = 3814;
2675  //     * DURATION_LIMIT_QUADRATIC_SOFT_MAX_DURATION_EXCEEDS_GLOBAL_DURATION
2676  //       = 3815;
2677  // * SHIPMENT_ERROR = 40;
2678  //     * SHIPMENT_PD_LIMIT_WITHOUT_PICKUP_AND_DELIVERY = 4014;
2679  //     * SHIPMENT_PD_ABSOLUTE_DETOUR_LIMIT_DURATION_NEGATIVE_OR_NAN = 4000;
2680  //     * SHIPMENT_PD_ABSOLUTE_DETOUR_LIMIT_DURATION_EXCEEDS_GLOBAL_DURATION
2681  //       = 4001;
2682  //     * SHIPMENT_PD_RELATIVE_DETOUR_LIMIT_INVALID = 4015;
2683  //     * SHIPMENT_PD_DETOUR_LIMIT_AND_EXTRA_VISIT_DURATION = 4016;
2684  //     * SHIPMENT_PD_TIME_LIMIT_DURATION_NEGATIVE_OR_NAN = 4002;
2685  //     * SHIPMENT_PD_TIME_LIMIT_DURATION_EXCEEDS_GLOBAL_DURATION = 4003;
2686  //     * SHIPMENT_EMPTY_SHIPMENT_TYPE = 4004;
2687  //     * SHIPMENT_NO_PICKUP_NO_DELIVERY = 4005;
2688  //     * SHIPMENT_INVALID_PENALTY_COST = 4006;
2689  //     * SHIPMENT_ALLOWED_VEHICLE_INDEX_OUT_OF_BOUNDS = 4007;
2690  //     * SHIPMENT_DUPLICATE_ALLOWED_VEHICLE_INDEX = 4008;
2691  //     * SHIPMENT_INCONSISTENT_COST_FOR_VEHICLE_SIZE_WITHOUT_INDEX = 4009;
2692  //     * SHIPMENT_INCONSISTENT_COST_FOR_VEHICLE_SIZE_WITH_INDEX = 4010;
2693  //     * SHIPMENT_INVALID_COST_FOR_VEHICLE = 4011;
2694  //     * SHIPMENT_COST_FOR_VEHICLE_INDEX_OUT_OF_BOUNDS = 4012;
2695  //     * SHIPMENT_DUPLICATE_COST_FOR_VEHICLE_INDEX = 4013;
2696  // * VEHICLE_ERROR = 42;
2697  //     * VEHICLE_EMPTY_REQUIRED_OPERATOR_TYPE = 4200;
2698  //     * VEHICLE_DUPLICATE_REQUIRED_OPERATOR_TYPE = 4201;
2699  //     * VEHICLE_NO_OPERATOR_WITH_REQUIRED_OPERATOR_TYPE = 4202;
2700  //     * VEHICLE_EMPTY_START_TAG = 4203;
2701  //     * VEHICLE_DUPLICATE_START_TAG = 4204;
2702  //     * VEHICLE_EMPTY_END_TAG = 4205;
2703  //     * VEHICLE_DUPLICATE_END_TAG = 4206;
2704  //     * VEHICLE_EXTRA_VISIT_DURATION_NEGATIVE_OR_NAN = 4207;
2705  //     * VEHICLE_EXTRA_VISIT_DURATION_EXCEEDS_GLOBAL_DURATION = 4208;
2706  //     * VEHICLE_EXTRA_VISIT_DURATION_EMPTY_KEY = 4209;
2707  //     * VEHICLE_FIRST_SHIPMENT_INDEX_OUT_OF_BOUNDS = 4210;
2708  //     * VEHICLE_FIRST_SHIPMENT_IGNORED = 4211;
2709  //     * VEHICLE_FIRST_SHIPMENT_NOT_BOUND = 4212;
2710  //     * VEHICLE_LAST_SHIPMENT_INDEX_OUT_OF_BOUNDS = 4213;
2711  //     * VEHICLE_LAST_SHIPMENT_IGNORED = 4214;
2712  //     * VEHICLE_LAST_SHIPMENT_NOT_BOUND = 4215;
2713  //     * VEHICLE_IGNORED_WITH_USED_IF_ROUTE_IS_EMPTY = 4216;
2714  //     * VEHICLE_INVALID_COST_PER_KILOMETER = 4217;
2715  //     * VEHICLE_INVALID_COST_PER_HOUR = 4218;
2716  //     * VEHICLE_INVALID_COST_PER_TRAVELED_HOUR = 4219;
2717  //     * VEHICLE_INVALID_FIXED_COST = 4220;
2718  //     * VEHICLE_INVALID_TRAVEL_DURATION_MULTIPLE = 4221;
2719  //     * VEHICLE_TRAVEL_DURATION_MULTIPLE_WITH_SHIPMENT_PD_DETOUR_LIMITS
2720  //       = 4223;
2721  //     * VEHICLE_MATRIX_INDEX_WITH_SHIPMENT_PD_DETOUR_LIMITS = 4224;
2722  //     * VEHICLE_MINIMUM_DURATION_LONGER_THAN_DURATION_LIMIT = 4222;
2723  // * VISIT_REQUEST_ERROR = 44;
2724  //     * VISIT_REQUEST_EMPTY_TAG = 4400;
2725  //     * VISIT_REQUEST_DUPLICATE_TAG = 4401;
2726  //     * VISIT_REQUEST_DURATION_NEGATIVE_OR_NAN = 4404;
2727  //     * VISIT_REQUEST_DURATION_EXCEEDS_GLOBAL_DURATION = 4405;
2728  // * PRECEDENCE_ERROR = 46;
2729  //     * PRECEDENCE_RULE_MISSING_FIRST_INDEX = 4600;
2730  //     * PRECEDENCE_RULE_MISSING_SECOND_INDEX = 4601;
2731  //     * PRECEDENCE_RULE_FIRST_INDEX_OUT_OF_BOUNDS = 4602;
2732  //     * PRECEDENCE_RULE_SECOND_INDEX_OUT_OF_BOUNDS = 4603;
2733  //     * PRECEDENCE_RULE_DUPLICATE_INDEX = 4604;
2734  //     * PRECEDENCE_RULE_INEXISTENT_FIRST_VISIT_REQUEST = 4605;
2735  //     * PRECEDENCE_RULE_INEXISTENT_SECOND_VISIT_REQUEST = 4606;
2736  // * BREAK_ERROR = 48;
2737  //     * BREAK_RULE_EMPTY = 4800;
2738  //     * BREAK_REQUEST_UNSPECIFIED_DURATION = 4801;
2739  //     * BREAK_REQUEST_UNSPECIFIED_EARLIEST_START_TIME = 4802;
2740  //     * BREAK_REQUEST_UNSPECIFIED_LATEST_START_TIME = 4803;
2741  //     * BREAK_REQUEST_DURATION_NEGATIVE_OR_NAN = 4804; = 4804;
2742  //     * BREAK_REQUEST_LATEST_START_TIME_BEFORE_EARLIEST_START_TIME = 4805;
2743  //     * BREAK_REQUEST_EARLIEST_START_TIME_BEFORE_GLOBAL_START_TIME = 4806;
2744  //     * BREAK_REQUEST_LATEST_END_TIME_AFTER_GLOBAL_END_TIME = 4807;
2745  //     * BREAK_REQUEST_NON_SCHEDULABLE = 4808;
2746  //     * BREAK_FREQUENCY_MAX_INTER_BREAK_DURATION_NEGATIVE_OR_NAN = 4809;
2747  //     * BREAK_FREQUENCY_MIN_BREAK_DURATION_NEGATIVE_OR_NAN = 4810;
2748  //     * BREAK_FREQUENCY_MIN_BREAK_DURATION_EXCEEDS_GLOBAL_DURATION = 4811;
2749  //     * BREAK_FREQUENCY_MAX_INTER_BREAK_DURATION_EXCEEDS_GLOBAL_DURATION
2750  //       = 4812;
2751  //     * BREAK_REQUEST_DURATION_EXCEEDS_GLOBAL_DURATION = 4813;
2752  //     * BREAK_FREQUENCY_MISSING_MAX_INTER_BREAK_DURATION = 4814;
2753  //     * BREAK_FREQUENCY_MISSING_MIN_BREAK_DURATION = 4815;
2754  // * SHIPMENT_TYPE_INCOMPATIBILITY_ERROR = 50;
2755  //     * SHIPMENT_TYPE_INCOMPATIBILITY_EMPTY_TYPE = 5001;
2756  //     * SHIPMENT_TYPE_INCOMPATIBILITY_LESS_THAN_TWO_TYPES = 5002;
2757  //     * SHIPMENT_TYPE_INCOMPATIBILITY_DUPLICATE_TYPE = 5003;
2758  //     * SHIPMENT_TYPE_INCOMPATIBILITY_INVALID_INCOMPATIBILITY_MODE = 5004;
2759  //     * SHIPMENT_TYPE_INCOMPATIBILITY_TOO_MANY_INCOMPATIBILITIES = 5005;
2760  // * SHIPMENT_TYPE_REQUIREMENT_ERROR = 52;
2761  //     * SHIPMENT_TYPE_REQUIREMENT_NO_REQUIRED_TYPE = 52001;
2762  //     * SHIPMENT_TYPE_REQUIREMENT_NO_DEPENDENT_TYPE = 52002;
2763  //     * SHIPMENT_TYPE_REQUIREMENT_INVALID_REQUIREMENT_MODE = 52003;
2764  //     * SHIPMENT_TYPE_REQUIREMENT_TOO_MANY_REQUIREMENTS = 52004;
2765  //     * SHIPMENT_TYPE_REQUIREMENT_EMPTY_REQUIRED_TYPE = 52005;
2766  //     * SHIPMENT_TYPE_REQUIREMENT_DUPLICATE_REQUIRED_TYPE = 52006;
2767  //     * SHIPMENT_TYPE_REQUIREMENT_NO_REQUIRED_TYPE_FOUND = 52007;
2768  //     * SHIPMENT_TYPE_REQUIREMENT_EMPTY_DEPENDENT_TYPE = 52008;
2769  //     * SHIPMENT_TYPE_REQUIREMENT_DUPLICATE_DEPENDENT_TYPE = 52009;
2770  //     * SHIPMENT_TYPE_REQUIREMENT_SELF_DEPENDENT_TYPE = 52010;
2771  //     * SHIPMENT_TYPE_REQUIREMENT_GRAPH_HAS_CYCLES = 52011;
2772  // * VEHICLE_OPERATOR_ERROR = 54;
2773  //     * VEHICLE_OPERATOR_EMPTY_TYPE = 5400;
2774  //     * VEHICLE_OPERATOR_MULTIPLE_START_TIME_WINDOWS = 5401;
2775  //     * VEHICLE_OPERATOR_SOFT_START_TIME_WINDOW = 5402;
2776  //     * VEHICLE_OPERATOR_MULTIPLE_END_TIME_WINDOWS = 5403;
2777  //     * VEHICLE_OPERATOR_SOFT_END_TIME_WINDOW = 5404;
2778  // * DURATION_SECONDS_MATRIX_ERROR = 56;
2779  //     * DURATION_SECONDS_MATRIX_DURATION_NEGATIVE_OR_NAN = 5600;
2780  //     * DURATION_SECONDS_MATRIX_DURATION_EXCEEDS_GLOBAL_DURATION = 5601;
2781  int32 code = 1;
2782
2783  // The error display name.
2784  string display_name = 2;
2785
2786  // An error context may involve 0, 1 (most of the time) or more fields. For
2787  // example, referring to vehicle #4 and shipment #2's first pickup can be
2788  // done as follows:
2789  // ```
2790  // fields { name: "vehicles" index: 4}
2791  // fields { name: "shipments" index: 2 sub_field {name: "pickups" index: 0} }
2792  // ```
2793  // Note, however, that the cardinality of `fields` should not change for a
2794  // given error code.
2795  repeated FieldReference fields = 3;
2796
2797  // Human-readable string describing the error. There is a 1:1 mapping
2798  // between `code` and `error_message` (when code != "UNSPECIFIED").
2799  //
2800  // *STABILITY*: Not stable: the error message associated to a given `code` may
2801  // change (hopefully to clarify it) over time. Please rely on the
2802  // `display_name` and `code` instead.
2803  string error_message = 4;
2804
2805  // May contain the value(s) of the field(s). This is not always available. You
2806  // should absolutely not rely on it and use it only for manual model
2807  // debugging.
2808  string offending_values = 5;
2809}
2810