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