OR-Tools  9.1
model_update_merge.cc
Go to the documentation of this file.
1// Copyright 2010-2021 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 <cstdint>
18#include <iterator>
19#include <utility>
20
23#include "ortools/math_opt/model.pb.h"
24#include "ortools/math_opt/model_update.pb.h"
25#include "ortools/math_opt/sparse_containers.pb.h"
26
27namespace operations_research {
28namespace math_opt {
29
30void MergeIntoUpdate(const ModelUpdateProto& from, ModelUpdateProto& into) {
31 internal::MergeIntoSortedIds(from.deleted_variable_ids(),
32 *into.mutable_deleted_variable_ids());
33 internal::MergeIntoSortedIds(from.deleted_linear_constraint_ids(),
34 *into.mutable_deleted_linear_constraint_ids());
35
37 from.variable_updates().lower_bounds(),
38 *into.mutable_variable_updates()->mutable_lower_bounds());
40 from.variable_updates().upper_bounds(),
41 *into.mutable_variable_updates()->mutable_upper_bounds());
43 from.variable_updates().integers(),
44 *into.mutable_variable_updates()->mutable_integers());
45
47 from.linear_constraint_updates().lower_bounds(),
48 *into.mutable_linear_constraint_updates()->mutable_lower_bounds());
50 from.linear_constraint_updates().upper_bounds(),
51 *into.mutable_linear_constraint_updates()->mutable_upper_bounds());
52
53 if (!from.new_variables().ids().empty() &&
54 !into.new_variables().ids().empty()) {
55 CHECK_GT(*from.new_variables().ids().begin(),
56 *into.new_variables().ids().rbegin());
57 }
58 into.mutable_new_variables()->MergeFrom(from.new_variables());
59
60 if (!from.new_linear_constraints().ids().empty() &&
61 !into.new_linear_constraints().ids().empty()) {
62 CHECK_GT(*from.new_linear_constraints().ids().begin(),
63 *into.new_linear_constraints().ids().rbegin());
64 }
65 into.mutable_new_linear_constraints()->MergeFrom(
66 from.new_linear_constraints());
67
68 if (from.objective_updates().has_direction_update()) {
69 into.mutable_objective_updates()->set_direction_update(
70 from.objective_updates().direction_update());
71 }
72 if (from.objective_updates().has_offset_update()) {
73 into.mutable_objective_updates()->set_offset_update(
74 from.objective_updates().offset_update());
75 }
77 from.objective_updates().linear_coefficients(),
78 *into.mutable_objective_updates()->mutable_linear_coefficients());
79
81 from.linear_constraint_matrix_updates(),
82 *into.mutable_linear_constraint_matrix_updates());
83}
84
85namespace internal {
86
87void MergeIntoSortedIds(const google::protobuf::RepeatedField<int64_t>& from,
88 google::protobuf::RepeatedField<int64_t>& into) {
89 google::protobuf::RepeatedField<int64_t> result;
90
91 // We don't reserve the sum of the sizes of both repeated fields since they
92 // can contain overlapping ids. But we know that we will have at least the max
93 // length of either repeated field.
94 result.Reserve(std::max(from.size(), into.size()));
95
96 int from_i = 0;
97 int into_i = 0;
98 while (from_i < from.size() && into_i < into.size()) {
99 if (from[from_i] < into[into_i]) {
100 result.Add(from[from_i]);
101 ++from_i;
102 } else if (from[from_i] > into[into_i]) {
103 result.Add(into[into_i]);
104 ++into_i;
105 } else { // from[from_i] == into[into_i]
106 result.Add(from[from_i]);
107 ++from_i;
108 ++into_i;
109 }
110 }
111
112 // At this point either from_i == from.size() or to_i == to.size() or
113 // both. And the one that is not empty, if it exists, has elements greater
114 // than all other elements already inserted.
115 result.Reserve(result.size() +
116 std::max(from.size() - from_i, into.size() - into_i));
117 for (; from_i < from.size(); ++from_i) {
118 result.Add(from[from_i]);
119 }
120 for (; into_i < into.size(); ++into_i) {
121 result.Add(into[into_i]);
122 }
123
124 into.Swap(&result);
125}
126
127void MergeIntoSparseDoubleMatrix(const SparseDoubleMatrixProto& from,
128 SparseDoubleMatrixProto& into) {
129 SparseDoubleMatrixProto result;
130 auto& result_row_ids = *result.mutable_row_ids();
131 auto& result_column_ids = *result.mutable_column_ids();
132 auto& result_coefficients = *result.mutable_coefficients();
133
134 // We don't reserve the sum of the sizes of both sparse matrices since they
135 // can contain overlapping tuples. But we know that we will have at least the
136 // max length of either matrix.
137 const int max_size = std::max(from.row_ids_size(), into.row_ids_size());
138 result_row_ids.Reserve(max_size);
139 result_column_ids.Reserve(max_size);
140 result_coefficients.Reserve(max_size);
141
142 int from_i = 0;
143 int into_i = 0;
144 while (from_i < from.row_ids_size() && into_i < into.row_ids_size()) {
145 // Matrices are in row-major order and std::pair comparison is
146 // lexicographical, thus matrices are sorted in the natural order of pairs
147 // of coordinates (row, col).
148 const auto from_coordinates =
149 std::make_pair(from.row_ids(from_i), from.column_ids(from_i));
150 const auto into_coordinates =
151 std::make_pair(into.row_ids(into_i), into.column_ids(into_i));
152 if (from_coordinates < into_coordinates) {
153 result_row_ids.Add(from_coordinates.first);
154 result_column_ids.Add(from_coordinates.second);
155 result_coefficients.Add(from.coefficients(from_i));
156 ++from_i;
157 } else if (from_coordinates > into_coordinates) {
158 result_row_ids.Add(into_coordinates.first);
159 result_column_ids.Add(into_coordinates.second);
160 result_coefficients.Add(into.coefficients(into_i));
161 ++into_i;
162 } else { // from_coordinates == into_coordinates
163 result_row_ids.Add(from_coordinates.first);
164 result_column_ids.Add(from_coordinates.second);
165 result_coefficients.Add(from.coefficients(from_i));
166 ++from_i;
167 ++into_i;
168 }
169 }
170
171 // At this point either from_i == from.row_ids_size() or
172 // to_i == to.row_ids_size() (or both). And the one that is not empty, if it
173 // exists, has elements greater than all other elements already inserted.
174 const int remaining_size =
175 std::max(from.row_ids_size() - from_i, into.row_ids_size() - into_i);
176 result_row_ids.Reserve(result_row_ids.size() + remaining_size);
177 result_column_ids.Reserve(result_column_ids.size() + remaining_size);
178 result_coefficients.Reserve(result_coefficients.size() + remaining_size);
179 for (; from_i < from.row_ids_size(); ++from_i) {
180 result_row_ids.Add(from.row_ids(from_i));
181 result_column_ids.Add(from.column_ids(from_i));
182 result_coefficients.Add(from.coefficients(from_i));
183 }
184 for (; into_i < into.row_ids_size(); ++into_i) {
185 result_row_ids.Add(into.row_ids(into_i));
186 result_column_ids.Add(into.column_ids(into_i));
187 result_coefficients.Add(into.coefficients(into_i));
188 }
189
190 into.Swap(&result);
191}
192
193} // namespace internal
194} // namespace math_opt
195} // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
#define CHECK_GT(val1, val2)
Definition: base/logging.h:703
void MergeIntoSparseVector(const SparseVector &from, SparseVector &into)
void MergeIntoSparseDoubleMatrix(const SparseDoubleMatrixProto &from, SparseDoubleMatrixProto &into)
void MergeIntoSortedIds(const google::protobuf::RepeatedField< int64_t > &from, google::protobuf::RepeatedField< int64_t > &into)
void MergeIntoUpdate(const ModelUpdateProto &from, ModelUpdateProto &into)
Collection of objects used to extend the Constraint Solver library.