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 
22 #include "ortools/base/logging.h"
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 
27 namespace operations_research {
28 namespace math_opt {
29 
30 void 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 
85 namespace internal {
86 
87 void 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 
127 void 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
void MergeIntoSortedIds(const google::protobuf::RepeatedField< int64_t > &from, google::protobuf::RepeatedField< int64_t > &into)
#define CHECK_GT(val1, val2)
Definition: base/logging.h:703
void MergeIntoSparseVector(const SparseVector &from, SparseVector &into)
void MergeIntoUpdate(const ModelUpdateProto &from, ModelUpdateProto &into)
int64_t max
Definition: alldiff_cst.cc:140
Collection of objects used to extend the Constraint Solver library.
void MergeIntoSparseDoubleMatrix(const SparseDoubleMatrixProto &from, SparseDoubleMatrixProto &into)