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