OR-Tools  9.3
sparse_submatrix.cc
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
15
16#include <algorithm>
17#include <cstdint>
18#include <optional>
19#include <utility>
20#include <vector>
21
22#include "absl/container/flat_hash_map.h"
23#include "absl/types/span.h"
27#include "ortools/math_opt/sparse_containers.pb.h"
28
30namespace {
31
32// A semi-open range [start, end). If end is nullopt, all indices >= start are
33// included.
34struct IndexRange {
35 int64_t start;
36 std::optional<int64_t> end;
37
38 // Returns true if the input value is in the [start, end) range.
39 bool Contains(const int64_t id) const {
40 return id >= start && (!end.has_value() || id < *end);
41 }
42};
43
44} // namespace
45
47 const SparseDoubleMatrixProto& matrix, const int64_t start_row_id,
48 const std::optional<int64_t> end_row_id, const int64_t start_col_id,
49 const std::optional<int64_t> end_col_id) {
50 const int matrix_size = matrix.row_ids_size();
51 CHECK_EQ(matrix_size, matrix.column_ids_size());
52 CHECK_EQ(matrix_size, matrix.coefficients_size());
53 const IndexRange row_range = {.start = start_row_id, .end = end_row_id};
54 const IndexRange col_range = {.start = start_col_id, .end = end_col_id};
55
56 SparseSubmatrixRowsView filtered_rows;
57
58 // row_start, next_row_start and row_end are indices into the matrix data.
59 for (int row_start = 0, next_row_start; row_start < matrix_size;
60 // next_row_start is set from row_end once found at the start of the loop
61 // below.
62 row_start = next_row_start) {
63 // Find the end of the current row such that all index in [start, end) are
64 // for the same row.
65 const int64_t row_id = matrix.row_ids(row_start);
66 int row_end = row_start + 1;
67 while (row_end < matrix_size && matrix.row_ids(row_end) == row_id) {
68 ++row_end;
69 }
70
71 // Prepare the next iteration.
72 next_row_start = row_end;
73
74 // Ignore rows not in the expected range.
75 if (!row_range.Contains(row_id)) {
76 continue;
77 }
78
79 // Finds the first column or the row in the col_range.
80 int row_cols_start = row_start;
81 while (row_cols_start < row_end &&
82 !col_range.Contains(matrix.column_ids(row_cols_start))) {
83 ++row_cols_start;
84 }
85
86 // Finds the first column greater of equal to row_cols_start that is not in
87 // the col_range.
88 int row_cols_end = row_cols_start;
89 while (row_cols_end < row_end &&
90 col_range.Contains(matrix.column_ids(row_cols_end))) {
91 ++row_cols_end;
92 }
93 const int row_cols_len = row_cols_end - row_cols_start;
94
95 if (row_cols_len != 0) {
96 filtered_rows.emplace_back(
97 row_id, MakeView(absl::MakeConstSpan(matrix.column_ids())
98 .subspan(row_cols_start, row_cols_len),
99 absl::MakeConstSpan(matrix.coefficients())
100 .subspan(row_cols_start, row_cols_len)));
101 }
102 }
103
104 return filtered_rows;
105}
106
107std::vector<std::pair<int64_t, SparseVector<double>>> TransposeSparseSubmatrix(
108 const SparseSubmatrixRowsView& submatrix_by_rows) {
109 // Extract the columns by iterating on the filtered views of the rows (the
110 // matrix is row major).
111 absl::flat_hash_map<int64_t, SparseVector<double>> filtered_columns;
112 for (const auto& [row_id, column_values] : submatrix_by_rows) {
113 for (const auto [column_id, value] : column_values) {
114 SparseVector<double>& row_values = filtered_columns[column_id];
115 row_values.ids.push_back(row_id);
116 row_values.values.push_back(value);
117 }
118 }
119
120 // The output should be sorted by column id.
121 std::vector<std::pair<int64_t, SparseVector<double>>> sorted_filtered_columns(
122 std::make_move_iterator(filtered_columns.begin()),
123 std::make_move_iterator(filtered_columns.end()));
124 std::sort(sorted_filtered_columns.begin(), sorted_filtered_columns.end(),
125 [](const std::pair<int64_t, SparseVector<double>>& lhs,
126 const std::pair<int64_t, SparseVector<double>>& rhs) {
127 return lhs.first < rhs.first;
128 });
129
130 return sorted_filtered_columns;
131}
132
133} // namespace operations_research::math_opt
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:703
int64_t value
std::vector< std::pair< int64_t, SparseVector< double > > > TransposeSparseSubmatrix(const SparseSubmatrixRowsView &submatrix_by_rows)
std::vector< std::pair< int64_t, SparseVectorView< double > > > SparseSubmatrixRowsView
SparseSubmatrixRowsView SparseSubmatrixByRows(const SparseDoubleMatrixProto &matrix, const int64_t start_row_id, const std::optional< int64_t > end_row_id, const int64_t start_col_id, const std::optional< int64_t > end_col_id)
SparseVectorView< T > MakeView(absl::Span< const int64_t > ids, const Collection &values)
std::optional< int64_t > end
int64_t start