OR-Tools  9.6
glpk_sparse_vector.h
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 
14 #ifndef OR_TOOLS_MATH_OPT_SOLVERS_GLPK_GLPK_SPARSE_VECTOR_H_
15 #define OR_TOOLS_MATH_OPT_SOLVERS_GLPK_GLPK_SPARSE_VECTOR_H_
16 
17 #include <functional>
18 #include <limits>
19 #include <optional>
20 #include <vector>
21 
22 #include "ortools/base/logging.h"
23 
25 
26 // Sparse vector in GLPK format.
27 //
28 // GLPK represents a sparse vector of size n with two arrays of size n+1, one
29 // for indices and one for values. The first element of each of these arrays is
30 // ignored (GLPK uses one-based indices). On top of that, the array of indices
31 // contains one-based indices (typically rows or columns indices). The entries
32 // are not necessarily sorted.
33 //
34 // For example to store a sparse vector where we have:
35 //
36 // idx | value
37 // ----+------
38 // 1 | 2.5
39 // 2 |
40 // 3 | -1.0
41 // 4 |
42 // 5 | 0.5
43 //
44 // GLPK would use two arrays:
45 //
46 // const int indices[] = { /*ignored*/-1, 3, 1, 5 };
47 // const double values[] = { /*ignored*/NAN, -1.0, 2.5, 0.5 };
48 //
49 // This class also keeps an additional vector which size is the capacity of the
50 // sparse vector (i.e. the corresponding size of a dense vector). It associates
51 // to each index an optional position of the corresponding entry in the indices
52 // and values arrays. This is used to make Set() and Get() O(1) and this makes
53 // Clear() O(size()) since indices associated to entries need to be cleared.
54 //
55 // This additional vector along with the ones used for indices and values are
56 // all pre-allocated to fit the capacity. Hence an instance of this class
57 // allocates:
58 //
59 // capacity * (2 * sizeof(int) + sizeof(double))
60 //
61 // It is thus recommended to reuse the same instance multiple times instead of
62 // reallocating one for it to be efficient.
64  public:
65  // Builds a sparse vector with the provided capacity (i.e. the size of the
66  // vector it was dense).
67  //
68  // This operation has O(capacity) complexity (see the class documentation for
69  // allocated memory).
70  explicit GlpkSparseVector(const int capacity);
71 
72  // Returns the capacity (the size of the vector if it was dense).
73  int capacity() const { return capacity_; }
74 
75  // Returns the number of entries in the sparse vector.
76  int size() const { return size_; }
77 
78  // Returns the indices array of the GLPK sparse vector.
79  //
80  // Only values in [1, size()] are meaningful.
81  const int* indices() const { return indices_.data(); }
82 
83  // Returns the values array of the GLPK sparse vector.
84  //
85  // Only values in [1, size()] are meaningful.
86  const double* values() const { return values_.data(); }
87 
88  // Clears the sparse vector, removing all entries.
89  //
90  // This operation has O(size()) complexity.
91  void Clear();
92 
93  // Returns the value at the given index if there is a corresponding entry or
94  // nullopt.
95  //
96  // It CHECKs that the index is in [1, capacity]. The operation has O(1)
97  // complexity.
98  inline std::optional<double> Get(int index) const;
99 
100  // Changes the value of the given index, adding a new entry if necessary.
101  //
102  // Note that entries are only removed by Clear() or Load(). Setting a value to
103  // 0.0 does not remove the corresponding entry.
104  //
105  // It CHECKs that the index is in [1, capacity]. The operation has O(1)
106  // complexity.
107  inline void Set(int index, double value);
108 
109  // Replaces the content of the sparse vector by calling a GLPK API.
110  //
111  // Since GLPK functions have other parameters, here we expect the caller to
112  // provide a wrapping lambda expression that passes the indices and values
113  // buffers to the GLPK function and returns the number of written elements.
114  //
115  // It CHECKs that the returned number of elements is not greater than the
116  // capacity, that the indices are in [1, capacity] range and that there is no
117  // duplicated indices.
118  //
119  // Example:
120  //
121  // GlpkSparseVector row_values(num_cols);
122  // row_values.Set([&](int* const indices, double* const values) {
123  // return glp_get_mat_row(problem, row_index, indices, values);
124  // });
125  //
126  void Load(std::function<int(int* indices, double* values)> getter);
127 
128  private:
129  // Guard value used in index_to_entry_ to identify indices not in the sparse
130  // vector.
131  static constexpr int kNotPresent = std::numeric_limits<int>::max();
132 
133  // Capacity.
134  int capacity_;
135 
136  // Number of entries.
137  int size_ = 0;
138 
139  // For each dense index in [1, capacity], keeps the index of the corresponding
140  // entry in indices_ and values_. If the index i has a value in the sparse
141  // vector then indices_[index_to_entry_[i]] == i and
142  // values_[index_to_entry_[i]] is the corresponding value. If the index i does
143  // not have a value then index_to_entry_[i] == kNotPresent.
144  //
145  // Note that as for indices_ and values_, index_to_entry_[0] is unused.
146  std::vector<int> index_to_entry_;
147 
148  // The GLPK one-based vector of entries' indices. Only values in [1, size_]
149  // are meaningful.
150  std::vector<int> indices_;
151 
152  // The GLPK one-based vector of entries' values. Only values in [1, size_] are
153  // meaningful.
154  std::vector<double> values_;
155 };
156 
158 // Inline implementations
160 
161 std::optional<double> GlpkSparseVector::Get(const int index) const {
162  CHECK_GE(index, 1);
163  CHECK_LE(index, capacity_);
164 
165  const int entry = index_to_entry_[index];
166  if (entry == kNotPresent) {
167  return std::nullopt;
168  }
169 
170  DCHECK_GE(entry, 1);
171  DCHECK_LE(entry, capacity_);
172  DCHECK_EQ(indices_[entry], index);
173 
174  return values_[entry];
175 }
176 
177 void GlpkSparseVector::Set(const int index, const double value) {
178  CHECK_GE(index, 1);
179  CHECK_LE(index, capacity_);
180 
181  const int entry = index_to_entry_[index];
182  if (entry == kNotPresent) {
183  DCHECK_LT(size_, capacity_);
184  ++size_;
185  index_to_entry_[index] = size_;
186  indices_[size_] = index;
187  values_[size_] = value;
188 
189  return;
190  }
191 
192  DCHECK_GE(entry, 1);
193  DCHECK_LE(entry, capacity_);
194  DCHECK_EQ(indices_[entry], index);
195 
196  values_[entry] = value;
197 }
198 
199 } // namespace operations_research::math_opt
200 
201 #endif // OR_TOOLS_MATH_OPT_SOLVERS_GLPK_GLPK_SPARSE_VECTOR_H_
int64_t max
Definition: alldiff_cst.cc:140
void Load(std::function< int(int *indices, double *values)> getter)
std::optional< double > Get(int index) const
int64_t value
int index