15 #ifndef OR_TOOLS_MATH_OPT_STORAGE_SPARSE_MATRIX_H_
16 #define OR_TOOLS_MATH_OPT_STORAGE_SPARSE_MATRIX_H_
24 #include "absl/algorithm/container.h"
25 #include "absl/container/flat_hash_map.h"
26 #include "absl/container/flat_hash_set.h"
27 #include "absl/meta/type_traits.h"
28 #include "absl/types/span.h"
31 #include "ortools/math_opt/sparse_containers.pb.h"
70 inline bool set(VariableId first, VariableId second,
double value);
73 inline double get(VariableId first, VariableId second)
const;
76 void Delete(VariableId variable);
82 std::vector<VariableId>
Variables()
const;
95 std::vector<std::pair<VariableId, double>>
Terms(VariableId variable)
const;
102 std::vector<std::tuple<VariableId, VariableId, double>>
Terms()
const;
118 const absl::flat_hash_map<std::pair<VariableId, VariableId>,
double>&
values()
123 SparseDoubleMatrixProto
Proto()
const;
125 SparseDoubleMatrixProto
Update(
126 const absl::flat_hash_set<VariableId>& deleted_variables,
127 absl::Span<const VariableId> new_variables,
128 const absl::flat_hash_set<std::pair<VariableId, VariableId>>& dirty)
132 inline std::pair<VariableId, VariableId> make_key(VariableId first,
133 VariableId second)
const;
134 void CompactIfNeeded();
137 absl::flat_hash_map<std::pair<VariableId, VariableId>,
double> values_;
138 absl::flat_hash_map<VariableId, std::vector<VariableId>> related_variables_;
141 int64_t nonzeros_ = 0;
174 template <
typename RowId,
typename ColumnId>
195 std::vector<ColumnId>
row(RowId row_id)
const;
199 std::vector<RowId>
column(ColumnId column_id)
const;
206 std::vector<std::pair<ColumnId, double>>
RowTerms(RowId row_id)
const;
213 std::vector<std::pair<RowId, double>>
ColumnTerms(ColumnId col_id)
const;
220 std::vector<std::tuple<RowId, ColumnId, double>>
Terms()
const;
232 SparseDoubleMatrixProto
Proto()
const;
235 const absl::flat_hash_set<RowId>& deleted_rows,
236 absl::Span<const RowId> new_rows,
237 const absl::flat_hash_set<ColumnId>& deleted_columns,
238 absl::Span<const ColumnId> new_columns,
239 const absl::flat_hash_set<std::pair<RowId, ColumnId>>& dirty)
const;
242 void CompactIfNeeded();
245 absl::flat_hash_map<std::pair<RowId, ColumnId>,
double> values_;
246 absl::flat_hash_map<RowId, std::vector<ColumnId>> rows_;
247 absl::flat_hash_map<ColumnId, std::vector<RowId>> columns_;
250 int64_t nonzeros_ = 0;
260 template <
typename RowId,
typename ColumnId>
262 std::vector<std::tuple<RowId, ColumnId, double>> entries);
274 template <
typename RowId,
typename ColumnId>
276 std::vector<std::tuple<RowId, ColumnId, double>> entries) {
277 absl::c_sort(entries);
278 const int num_entries =
static_cast<int>(entries.size());
279 SparseDoubleMatrixProto result;
282 result.mutable_coefficients()->Reserve(
num_entries);
283 for (
const auto [lin_con,
var,
coef] : entries) {
284 result.add_row_ids(lin_con.value());
285 result.add_column_ids(
var.value());
286 result.add_coefficients(
coef);
297 std::pair<VariableId, VariableId> SparseSymmetricMatrix::make_key(
298 const VariableId first,
const VariableId second)
const {
303 const double value) {
304 const std::pair<VariableId, VariableId> key = make_key(first, second);
305 auto map_iter = values_.find(key);
307 if (map_iter == values_.end()) {
311 related_variables_[first].push_back(second);
312 if (first != second) {
313 related_variables_[second].push_back(first);
315 values_[key] =
value;
319 if (map_iter->second ==
value) {
322 const double old_value = map_iter->second;
323 map_iter->second =
value;
327 }
else if (old_value == 0.0) {
335 const VariableId second)
const {
343 template <
typename RowId,
typename ColumnId>
345 const double value) {
346 const std::pair<RowId, ColumnId> key = {
row,
column};
347 const auto it = values_.find(key);
348 if (it == values_.end()) {
354 values_[key] =
value;
358 if (it->second ==
value) {
361 const double old_value = it->second;
366 }
else if (old_value == 0.0) {
373 template <
typename RowId,
typename ColumnId>
375 const ColumnId
column)
const {
376 const auto it = values_.find({
row,
column});
377 if (it != values_.end()) {
382 template <
typename RowId,
typename ColumnId>
384 const ColumnId
column)
const {
385 const auto it = values_.find({
row,
column});
386 return it != values_.end() && it->second != 0.0;
389 template <
typename RowId,
typename ColumnId>
391 const auto row_it = rows_.find(
row);
392 if (row_it == rows_.end()) {
395 for (
const ColumnId
col : row_it->second) {
396 auto val_it = values_.find({row_it->first,
col});
397 if (val_it != values_.end() && val_it->second != 0.0) {
398 val_it->second = 0.0;
405 template <
typename RowId,
typename ColumnId>
407 const auto col_it = columns_.find(
column);
408 if (col_it == columns_.end()) {
411 for (
const RowId
row : col_it->second) {
412 auto val_it = values_.find({
row, col_it->first});
413 if (val_it != values_.end() && val_it->second != 0.0) {
414 val_it->second = 0.0;
421 template <
typename RowId,
typename ColumnId>
423 const RowId row_id)
const {
424 std::vector<ColumnId> result;
425 const auto it = rows_.find(row_id);
426 if (it != rows_.end()) {
427 for (
const ColumnId
col : it->second) {
428 if (contains(row_id,
col)) {
429 result.push_back(
col);
436 template <
typename RowId,
typename ColumnId>
438 const ColumnId column_id)
const {
439 std::vector<RowId> result;
440 const auto it = columns_.find(column_id);
441 if (it != columns_.end()) {
442 for (
const RowId row_id : it->second) {
443 if (contains(row_id, column_id)) {
444 result.push_back(row_id);
451 template <
typename RowId,
typename ColumnId>
452 std::vector<std::pair<ColumnId, double>>
454 std::vector<std::pair<ColumnId, double>> result;
455 const auto it = rows_.find(row_id);
456 if (it != rows_.end()) {
457 for (
const ColumnId
col : it->second) {
458 const double val = get(row_id,
col);
460 result.push_back({
col, val});
467 template <
typename RowId,
typename ColumnId>
468 std::vector<std::pair<RowId, double>>
470 std::vector<std::pair<RowId, double>> result;
471 const auto it = columns_.find(col_id);
472 if (it != columns_.end()) {
473 for (
const RowId row_id : it->second) {
474 const double val = get(row_id, col_id);
476 result.push_back({row_id, val});
483 template <
typename RowId,
typename ColumnId>
484 std::vector<std::tuple<RowId, ColumnId, double>>
486 std::vector<std::tuple<RowId, ColumnId, double>> result;
487 result.reserve(nonzeros_);
488 for (
const auto& [k, v] : values_) {
490 result.push_back({k.first, k.second, v});
496 template <
typename RowId,
typename ColumnId>
503 template <
typename RowId,
typename ColumnId>
508 template <
typename RowId,
typename ColumnId>
510 SparseDoubleMatrixProto result;
511 std::vector<std::tuple<RowId, ColumnId, double>> terms = Terms();
513 for (
const auto [r, c, v] : terms) {
514 result.add_row_ids(r.value());
515 result.add_column_ids(c.value());
516 result.add_coefficients(v);
521 template <
typename RowId,
typename ColumnId>
523 const absl::flat_hash_set<RowId>& deleted_rows,
524 const absl::Span<const RowId> new_rows,
525 const absl::flat_hash_set<ColumnId>& deleted_columns,
526 const absl::Span<const ColumnId> new_columns,
527 const absl::flat_hash_set<std::pair<RowId, ColumnId>>& dirty)
const {
529 std::vector<std::tuple<LinearConstraintId, VariableId, double>>
536 if (deleted_rows.contains(
row) || deleted_columns.contains(
column)) {
542 for (
const ColumnId new_col : new_columns) {
544 for (
const auto [
row,
coef] : ColumnTerms(new_col)) {
545 matrix_updates.push_back({
row, new_col,
coef});
548 for (
const RowId new_row : new_rows) {
550 for (
const auto [
col,
coef] : RowTerms(new_row)) {
553 if (new_columns.empty() ||
col < new_columns[0]) {
554 matrix_updates.push_back({new_row,
col,
coef});
561 template <
typename RowId,
typename ColumnId>
563 const int64_t zeros = values_.size() - nonzeros_;
564 if (values_.empty() ||
570 for (
auto row_it = rows_.begin(); row_it != rows_.end();) {
571 const RowId
row = row_it->first;
572 std::vector<ColumnId>& row_entries = row_it->second;
574 for (int64_t read = 0; read < row_entries.size(); ++read) {
575 const ColumnId
col = row_entries[read];
576 const auto val_it = values_.find({
row,
col});
577 if (val_it != values_.end() && val_it->second != 0.0) {
578 row_entries[write] =
col;
583 rows_.erase(row_it++);
585 row_entries.resize(write);
592 for (
auto col_it = columns_.begin(); col_it != columns_.end();) {
593 const ColumnId
col = col_it->first;
594 std::vector<RowId>& col_entries = col_it->second;
596 for (int64_t read = 0; read < col_entries.size(); ++read) {
597 const RowId
row = col_entries[read];
598 const auto val_it = values_.find({
row,
col});
599 if (val_it != values_.end()) {
600 if (val_it->second != 0.0) {
601 col_entries[write] =
row;
604 values_.erase(val_it);
609 columns_.erase(col_it++);
611 col_entries.resize(write);
void DeleteRow(RowId row)
std::vector< std::pair< ColumnId, double > > RowTerms(RowId row_id) const
void DeleteColumn(ColumnId column)
bool set(RowId row, ColumnId column, double value)
std::vector< RowId > column(ColumnId column_id) const
std::vector< std::tuple< RowId, ColumnId, double > > Terms() const
std::vector< std::pair< RowId, double > > ColumnTerms(ColumnId col_id) const
SparseDoubleMatrixProto Proto() const
bool contains(RowId row, ColumnId column) const
std::vector< ColumnId > row(RowId row_id) const
SparseDoubleMatrixProto Update(const absl::flat_hash_set< RowId > &deleted_rows, absl::Span< const RowId > new_rows, const absl::flat_hash_set< ColumnId > &deleted_columns, absl::Span< const ColumnId > new_columns, const absl::flat_hash_set< std::pair< RowId, ColumnId >> &dirty) const
int64_t impl_detail_matrix_storage_size() const
double get(RowId row, ColumnId column) const
double get(VariableId first, VariableId second) const
void Delete(VariableId variable)
const absl::flat_hash_map< std::pair< VariableId, VariableId >, double > & values() 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
SparseDoubleMatrixProto Proto() const
bool set(VariableId first, VariableId second, double value)
int64_t impl_detail_matrix_storage_size() const
std::vector< std::tuple< VariableId, VariableId, double > > Terms() const
const Collection::value_type::second_type & FindWithDefault(const Collection &collection, const typename Collection::value_type::first_type &key, const typename Collection::value_type::second_type &value)
SparseDoubleMatrixProto EntriesToMatrixProto(std::vector< std::tuple< RowId, ColumnId, double >> entries)
constexpr double kZerosCleanup