OR-Tools  9.2
model_update_merge.h
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 
14 #ifndef OR_TOOLS_MATH_OPT_CORE_MODEL_UPDATE_MERGE_H_
15 #define OR_TOOLS_MATH_OPT_CORE_MODEL_UPDATE_MERGE_H_
16 
17 #include <algorithm>
18 #include <cstdint>
19 
20 #include "ortools/base/logging.h"
21 #include "ortools/math_opt/model_update.pb.h"
22 #include "ortools/math_opt/sparse_containers.pb.h"
23 
24 namespace operations_research {
25 namespace math_opt {
26 
27 // Merges the `from` update into the `into` one.
28 //
29 // The `from` update must represent an update that happens after the `into` one
30 // is applied. Thus when the two updates have overlaps, the `from` one overrides
31 // the value of the `into` one (i.e. the `from` update is expected to be more
32 // recent).
33 //
34 // This function also CHECKs that the ids of new variables and constraints in
35 // `from` are greater than the ones in `into` (as expected if `from` happens
36 // after `into`).
37 //
38 // Note that the complexity is O(size(from) + size(into)) thus if you need to
39 // merge a long list of updates this may be not efficient enough. In that case
40 // an n-way merge would be needed to be implemented here.
41 void MergeIntoUpdate(const ModelUpdateProto& from, ModelUpdateProto& into);
42 
43 namespace internal {
44 
45 // Merges the `from` list of sorted ids into the `into` one. Duplicates are
46 // removed.
47 void MergeIntoSortedIds(const google::protobuf::RepeatedField<int64_t>& from,
48  google::protobuf::RepeatedField<int64_t>& into);
49 
50 // Merges the `from` sparse vector into the `into` one. When the two vectors
51 // have overlaps, the value in `from` is used to overwrite the one in `into`.
52 //
53 // The SparseVector type is either SparseDoubleVectorProto or
54 // SparseBoolVectorProto.
55 template <typename SparseVector>
56 inline void MergeIntoSparseVector(const SparseVector& from, SparseVector& into);
57 
58 // Merges the `from` sparse matrix into the `into` one. When the two matrices
59 // have overlaps, the value in `from` is used to overwrite the one in `into`.
60 void MergeIntoSparseDoubleMatrix(const SparseDoubleMatrixProto& from,
61  SparseDoubleMatrixProto& into);
62 
63 } // namespace internal
64 
66 // Inline functions implementations.
68 
69 namespace internal {
70 
71 template <typename SparseVector>
72 void MergeIntoSparseVector(const SparseVector& from, SparseVector& into) {
73  CHECK_EQ(from.ids_size(), from.values_size());
74  CHECK_EQ(into.ids_size(), into.values_size());
75 
76  SparseVector result;
77  auto& result_ids = *result.mutable_ids();
78  auto& result_values = *result.mutable_values();
79 
80  // We don't reserve the sum of the sizes of both sparse vectors since they can
81  // contain overlapping ids. But we know that we will have at least the max
82  // length of either vector.
83  const int max_size = std::max(from.ids_size(), into.ids_size());
84  result_ids.Reserve(max_size);
85  result_values.Reserve(max_size);
86 
87  int from_i = 0;
88  int into_i = 0;
89  while (from_i < from.ids_size() && into_i < into.ids_size()) {
90  if (from.ids(from_i) < into.ids(into_i)) {
91  result_ids.Add(from.ids(from_i));
92  result_values.Add(from.values(from_i));
93  ++from_i;
94  } else if (from.ids(from_i) > into.ids(into_i)) {
95  result_ids.Add(into.ids(into_i));
96  result_values.Add(into.values(into_i));
97  ++into_i;
98  } else { // from.ids(from_i) == into.ids(into_i)
99  result_ids.Add(from.ids(from_i));
100  result_values.Add(from.values(from_i));
101  ++from_i;
102  ++into_i;
103  }
104  }
105 
106  // At this point either from_i == from.ids_size() or to_i == to.ids_size() (or
107  // both). And the one that is not empty, if it exists, has elements greater
108  // than all other elements already inserted.
109  const int remaining_size =
110  std::max(from.ids_size() - from_i, into.ids_size() - into_i);
111  result_ids.Reserve(result_ids.size() + remaining_size);
112  result_values.Reserve(result_values.size() + remaining_size);
113  for (; from_i < from.ids_size(); ++from_i) {
114  result_ids.Add(from.ids(from_i));
115  result_values.Add(from.values(from_i));
116  }
117  for (; into_i < into.ids_size(); ++into_i) {
118  result_ids.Add(into.ids(into_i));
119  result_values.Add(into.values(into_i));
120  }
121 
122  into.Swap(&result);
123 }
124 
125 } // namespace internal
126 } // namespace math_opt
127 } // namespace operations_research
128 
129 #endif // OR_TOOLS_MATH_OPT_CORE_MODEL_UPDATE_MERGE_H_
void MergeIntoSortedIds(const google::protobuf::RepeatedField< int64_t > &from, google::protobuf::RepeatedField< int64_t > &into)
void MergeIntoSparseVector(const SparseVector &from, SparseVector &into)
void MergeIntoUpdate(const ModelUpdateProto &from, ModelUpdateProto &into)
int64_t max
Definition: alldiff_cst.cc:140
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:702
Collection of objects used to extend the Constraint Solver library.
void MergeIntoSparseDoubleMatrix(const SparseDoubleMatrixProto &from, SparseDoubleMatrixProto &into)