Google OR-Tools v9.11
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-2024 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
32void 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
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
140SparseDoubleMatrixProto 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
165SparseDoubleMatrixProto 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
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
void Clear()
Removes all terms from the matrix.
double get(VariableId first, VariableId second) const
Zero is returned if the value is not present.
void Delete(VariableId variable)
Zeros out all coefficients for this variable.
int64_t value
IntVar * var
int64_t coef
SparseDoubleMatrixProto EntriesToMatrixProto(std::vector< std::tuple< RowId, ColumnId, double > > entries)
entries must have unique (row, column) values but can be in any order.
An object oriented wrapper for quadratic constraints in ModelStorage.
Definition gurobi_isv.cc:28