Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
sparse_matrix.cc
Go to the documentation of this file.
1// Copyright 2010-2025 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"
29
31
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
61std::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
76std::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
91std::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
103void 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
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
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
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< VariableId > RelatedVariables(VariableId variable) const
std::vector< std::tuple< VariableId, VariableId, double > > Terms() const
double get(VariableId first, VariableId second) const
SparseDoubleMatrixProto EntriesToMatrixProto(std::vector< std::tuple< RowId, ColumnId, double > > entries)
ElementId< ElementType::kVariable > VariableId
Definition elements.h:80