OR-Tools  9.6
sparse_matrix.cc
Go to the documentation of this file.
1 // Copyright 2010-2022 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 <cstdint>
17 #include <tuple>
18 #include <utility>
19 #include <vector>
20 
21 #include "absl/algorithm/container.h"
22 #include "absl/container/flat_hash_map.h"
23 #include "absl/container/flat_hash_set.h"
24 #include "absl/meta/type_traits.h"
25 #include "absl/types/span.h"
27 #include "ortools/math_opt/sparse_containers.pb.h"
29 
31 
32 void SparseSymmetricMatrix::Delete(const VariableId variable) {
33  auto related_vars = related_variables_.find(variable);
34  if (related_vars == related_variables_.end()) {
35  return;
36  }
37  for (const VariableId related : related_vars->second) {
38  auto mat_value = values_.find(make_key(variable, related));
39  if (mat_value != values_.end() && mat_value->second != 0.0) {
40  nonzeros_--;
41  mat_value->second = 0.0;
42  }
43  }
44  CompactIfNeeded();
45 }
46 
48  const VariableId variable) const {
49  std::vector<VariableId> result;
50  if (!related_variables_.contains(variable)) {
51  return result;
52  }
53  for (const VariableId second : related_variables_.at(variable)) {
54  if (get(variable, second) != 0) {
55  result.push_back(second);
56  }
57  }
58  return result;
59 }
60 
61 std::vector<VariableId> SparseSymmetricMatrix::Variables() const {
62  std::vector<VariableId> result;
63  // Note: we could make this more efficient in the presence of deletions by
64  // storing the actual number of neighbors in the value of related_variables_.
65  for (const auto& [var, related] : related_variables_) {
66  for (const VariableId other : related) {
67  if (get(var, other) != 0.0) {
68  result.push_back(var);
69  break;
70  }
71  }
72  }
73  return result;
74 }
75 
76 std::vector<std::pair<VariableId, double>> SparseSymmetricMatrix::Terms(
77  const VariableId variable) const {
78  std::vector<std::pair<VariableId, double>> result;
79  if (!related_variables_.contains(variable)) {
80  return result;
81  }
82  for (const VariableId second : related_variables_.at(variable)) {
83  double val = get(variable, second);
84  if (val != 0) {
85  result.push_back({second, val});
86  }
87  }
88  return result;
89 }
90 
91 std::vector<std::tuple<VariableId, VariableId, double>>
93  std::vector<std::tuple<VariableId, VariableId, double>> result;
94  result.reserve(nonzeros_);
95  for (const auto& [var_pair, value] : values_) {
96  if (value != 0.0) {
97  result.push_back({var_pair.first, var_pair.second, value});
98  }
99  }
100  return result;
101 }
102 
103 void SparseSymmetricMatrix::CompactIfNeeded() {
104  const int64_t zeros = values_.size() - nonzeros_;
105  if (values_.empty() ||
106  static_cast<double>(zeros) / values_.size() <= internal::kZerosCleanup) {
107  return;
108  }
109  for (auto related_var_it = related_variables_.begin();
110  related_var_it != related_variables_.end();) {
111  const VariableId v = related_var_it->first;
112  std::vector<VariableId>& related = related_var_it->second;
113  int64_t write = 0;
114  for (int64_t read = 0; read < related.size(); ++read) {
115  auto val = values_.find(make_key(v, related[read]));
116  if (val != values_.end()) {
117  if (val->second != 0) {
118  related[write] = related[read];
119  ++write;
120  } else {
121  values_.erase(val);
122  }
123  }
124  }
125  if (write == 0) {
126  related_variables_.erase(related_var_it++);
127  } else {
128  related.resize(write);
129  ++related_var_it;
130  }
131  }
132 }
133 
135  related_variables_.clear();
136  values_.clear();
137  nonzeros_ = 0;
138 }
139 
140 SparseDoubleMatrixProto SparseSymmetricMatrix::Proto() const {
141  SparseDoubleMatrixProto result;
142 
143  std::vector<VariableId> vars_in_order;
144  for (const auto& [v, _] : related_variables_) {
145  vars_in_order.push_back(v);
146  }
147  absl::c_sort(vars_in_order);
148 
149  for (const VariableId v : vars_in_order) {
150  // TODO(b/233630053): reuse the allocation once an iterator API is
151  // supported.
152  std::vector<std::pair<VariableId, double>> related = Terms(v);
153  absl::c_sort(related);
154  for (const auto [other, coef] : related) {
155  if (v <= other) {
156  result.add_row_ids(v.value());
157  result.add_column_ids(other.value());
158  result.add_coefficients(coef);
159  }
160  }
161  }
162  return result;
163 }
164 
165 SparseDoubleMatrixProto SparseSymmetricMatrix::Update(
166  const absl::flat_hash_set<VariableId>& deleted_variables,
167  const absl::Span<const VariableId> new_variables,
168  const absl::flat_hash_set<std::pair<VariableId, VariableId>>& dirty) const {
169  std::vector<std::tuple<VariableId, VariableId, double>> updates;
170  for (const std::pair<VariableId, VariableId> pair : dirty) {
171  // If either variable has been deleted, don't add it.
172  if (deleted_variables.contains(pair.first) ||
173  deleted_variables.contains(pair.second)) {
174  continue;
175  }
176  updates.push_back({pair.first, pair.second, get(pair.first, pair.second)});
177  }
178 
179  for (const VariableId v : new_variables) {
180  if (related_variables_.contains(v)) {
181  // TODO(b/233630053): do not allocate here.
182  for (const auto [other, coef] : Terms(v)) {
183  if (v <= other) {
184  updates.push_back({v, other, coef});
185  } else if (new_variables.empty() || other < new_variables[0]) {
186  updates.push_back({other, v, coef});
187  }
188  }
189  }
190  }
191  return internal::EntriesToMatrixProto(std::move(updates));
192 }
193 
194 } // namespace operations_research::math_opt
double get(VariableId first, VariableId second) const
std::vector< VariableId > RelatedVariables(VariableId variable) const
std::vector< VariableId > Variables() const
SparseDoubleMatrixProto Update(const absl::flat_hash_set< VariableId > &deleted_variables, absl::Span< const VariableId > new_variables, const absl::flat_hash_set< std::pair< VariableId, VariableId >> &dirty) const
std::vector< std::tuple< VariableId, VariableId, double > > Terms() const
int64_t value
IntVar * var
Definition: expr_array.cc:1874
int64_t coef
Definition: expr_array.cc:1875
SparseDoubleMatrixProto EntriesToMatrixProto(std::vector< std::tuple< RowId, ColumnId, double >> entries)