OR-Tools  9.1
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
21#include "ortools/math_opt/model_update.pb.h"
22#include "ortools/math_opt/sparse_containers.pb.h"
23
24namespace operations_research {
25namespace 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.
41void MergeIntoUpdate(const ModelUpdateProto& from, ModelUpdateProto& into);
42
43namespace internal {
44
45// Merges the `from` list of sorted ids into the `into` one. Duplicates are
46// removed.
47void 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.
55template <typename SparseVector>
56inline 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`.
60void MergeIntoSparseDoubleMatrix(const SparseDoubleMatrixProto& from,
61 SparseDoubleMatrixProto& into);
62
63} // namespace internal
64
66// Inline functions implementations.
68
69namespace internal {
70
71template <typename SparseVector>
72void 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_
int64_t max
Definition: alldiff_cst.cc:140
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:698
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.