Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
routing_utils.cc
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <algorithm>
17#include <functional>
18#include <queue>
19#include <tuple>
20#include <utility>
21#include <vector>
22
23#include "absl/log/check.h"
25
26namespace operations_research {
27
29 std::function<int64_t(int, int)> load_demand_of_item_for_bin,
30 std::vector<LoadLimit> load_limit_per_bin) {
31 DCHECK_EQ(num_bins_, load_limit_per_bin.size());
32 for (const LoadLimit& limit : load_limit_per_bin) {
33 const int64_t violation = std::max<int64_t>(0, CapOpp(limit.soft_max_load));
34 total_cost_ =
35 CapAdd(total_cost_, CapProd(violation, limit.cost_above_soft_max_load));
36 }
37 load_demands_per_dimension_.push_back(std::move(load_demand_of_item_for_bin));
38 for (int b = 0; b < num_bins_; ++b) {
39 load_per_bin_[b].push_back(0);
40 load_limits_per_bin_[b].push_back(load_limit_per_bin[b]);
41 }
42}
43
44bool BinCapacities::CheckAdditionFeasibility(int item, int bin) const {
45 return CheckAdditionsFeasibility({item}, bin);
46}
47
48bool BinCapacities::CheckAdditionsFeasibility(const std::vector<int>& items,
49 int bin) const {
50 for (size_t dim = 0; dim < load_demands_per_dimension_.size(); ++dim) {
51 const LoadLimit& limit = load_limits_per_bin_[bin][dim];
52 int64_t new_load = load_per_bin_[bin][dim];
53 for (const int item : items) {
54 new_load = CapAdd(new_load, load_demands_per_dimension_[dim](item, bin));
55 }
56 // TODO(user): try to reorder on failure, so that tight dimensions are
57 // checked first.
58 if (new_load > limit.max_load) return false;
59 }
60 return true;
61}
62
63bool BinCapacities::AddItemToBin(int item, int bin) {
64 bool feasible = true;
65 for (size_t dim = 0; dim < load_demands_per_dimension_.size(); ++dim) {
66 int64_t& load = load_per_bin_[bin][dim];
67 const LoadLimit& limit = load_limits_per_bin_[bin][dim];
68 const int64_t prev_violation =
69 std::max<int64_t>(0, CapSub(load, limit.soft_max_load));
70 load = CapAdd(load, load_demands_per_dimension_[dim](item, bin));
71 const int64_t curr_violation =
72 std::max<int64_t>(0, CapSub(load, limit.soft_max_load));
73 total_cost_ =
74 CapAdd(total_cost_, CapProd(CapSub(curr_violation, prev_violation),
76 feasible &= load <= limit.max_load;
77 }
78 return feasible;
79}
80
81bool BinCapacities::RemoveItemFromBin(int item, int bin) {
82 bool feasible = true;
83 for (size_t dim = 0; dim < load_demands_per_dimension_.size(); ++dim) {
84 int64_t& load = load_per_bin_[bin][dim];
85 const LoadLimit& limit = load_limits_per_bin_[bin][dim];
86 const int64_t prev_violation =
87 std::max<int64_t>(0, CapSub(load, limit.soft_max_load));
88 load = CapSub(load, load_demands_per_dimension_[dim](item, bin));
89 const int64_t curr_violation =
90 std::max<int64_t>(0, CapSub(load, limit.soft_max_load));
91 total_cost_ =
92 CapAdd(total_cost_, CapProd(CapSub(curr_violation, prev_violation),
94 feasible &= load <= limit.max_load;
95 }
96 return feasible;
97}
98
100 for (size_t dim = 0; dim < load_demands_per_dimension_.size(); ++dim) {
101 int64_t& load = load_per_bin_[bin][dim];
102 const LoadLimit& limit = load_limits_per_bin_[bin][dim];
103 const int64_t prev_violation =
104 std::max<int64_t>(0, CapSub(load, limit.soft_max_load));
105 load = 0;
106 const int64_t curr_violation =
107 std::max<int64_t>(0, CapOpp(limit.soft_max_load));
108 total_cost_ =
109 CapAdd(total_cost_, CapProd(CapSub(curr_violation, prev_violation),
111 }
112}
113
115 for (int bin = 0; bin < num_bins_; ++bin) {
116 ClearItemsOfBin(bin);
117 }
118}
119
121 int num_arcs, int64_t start,
122 const std::function<int64_t(int64_t)>& next_accessor,
123 const std::function<bool(int64_t)>& is_end,
124 const std::function<int64_t(int64_t, int64_t, int64_t)>&
125 arc_cost_for_route_start,
126 std::vector<std::pair<int64_t, int>>* most_expensive_arc_starts_and_ranks,
127 std::pair<int, int>* first_expensive_arc_indices) {
128 if (is_end(next_accessor(start))) {
129 // Empty route.
130 *first_expensive_arc_indices = {-1, -1};
131 return false;
132 }
133
134 // NOTE: The negative ranks are so that for a given cost, lower ranks are
135 // given higher priority.
136 using ArcCostNegativeRankStart = std::tuple<int64_t, int, int64_t>;
137 std::priority_queue<ArcCostNegativeRankStart,
138 std::vector<ArcCostNegativeRankStart>,
139 std::greater<ArcCostNegativeRankStart>>
140 arc_info_pq;
141
142 int64_t before_node = start;
143 int rank = 0;
144 while (!is_end(before_node)) {
145 const int64_t after_node = next_accessor(before_node);
146 const int64_t arc_cost =
147 arc_cost_for_route_start(before_node, after_node, start);
148 arc_info_pq.emplace(arc_cost, -rank, before_node);
149
150 before_node = after_node;
151 rank++;
152
153 if (rank > num_arcs) {
154 arc_info_pq.pop();
155 }
156 }
157
158 DCHECK_GE(rank, 2);
159 DCHECK_EQ(arc_info_pq.size(), std::min(rank, num_arcs));
160
161 most_expensive_arc_starts_and_ranks->resize(arc_info_pq.size());
162 int arc_index = arc_info_pq.size() - 1;
163 while (!arc_info_pq.empty()) {
164 const ArcCostNegativeRankStart& arc_info = arc_info_pq.top();
165 (*most_expensive_arc_starts_and_ranks)[arc_index] = {
166 std::get<2>(arc_info), -std::get<1>(arc_info)};
167 arc_index--;
168 arc_info_pq.pop();
169 }
170
171 *first_expensive_arc_indices = {0, 1};
172 return true;
173}
174
175} // namespace operations_research
void ClearItems()
Removes all items from all bins.
bool RemoveItemFromBin(int item, int bin)
Removes item from bin, return whether the bin is feasible.
void AddDimension(std::function< int64_t(int, int)> load_demand_of_item_for_bin, std::vector< LoadLimit > load_limit_per_bin)
void ClearItemsOfBin(int bin)
Removes all items from given bin, resets the total cost.
bool CheckAdditionsFeasibility(const std::vector< int > &items, int bin) const
bool CheckAdditionFeasibility(int item, int bin) const
Checks whether adding item(s) is feasible w.r.t. dimensions.
bool AddItemToBin(int item, int bin)
int64_t b
Definition table.cc:45
In SWIG mode, we don't want anything besides these top-level includes.
int64_t CapAdd(int64_t x, int64_t y)
int64_t CapSub(int64_t x, int64_t y)
int64_t CapProd(int64_t x, int64_t y)
bool FindMostExpensiveArcsOnRoute(int num_arcs, int64_t start, const std::function< int64_t(int64_t)> &next_accessor, const std::function< bool(int64_t)> &is_end, const std::function< int64_t(int64_t, int64_t, int64_t)> &arc_cost_for_route_start, std::vector< std::pair< int64_t, int > > *most_expensive_arc_starts_and_ranks, std::pair< int, int > *first_expensive_arc_indices)
int64_t CapOpp(int64_t v)
Note(user): -kint64min != kint64max, but kint64max == ~kint64min.
int64_t start