Google OR-Tools v9.12
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
scattered_vector.h
Go to the documentation of this file.
1// Copyright 2010-2025 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_LP_DATA_SCATTERED_VECTOR_H_
15#define OR_TOOLS_LP_DATA_SCATTERED_VECTOR_H_
16
17#include <cstddef>
18#include <vector>
19
20#include "absl/log/check.h"
22#include "ortools/util/bitset.h"
23
24namespace operations_research {
25namespace glop {
26
27// A class representing an entry of a scattered vector. The i-th nonzero
28// element of the vector is assumed to be located at indices[i] and its value is
29// coefficients[indices[i]], i.e., coefficients is a dense array.
30template <typename IndexType>
32 public:
33 using Index = IndexType;
34
35 Index index() const { return index_[i_.value()]; }
37 return coefficient_[index_[i_.value()].value()];
38 }
39
40 protected:
41 ScatteredVectorEntry(const Index* indices, const Fractional* coefficients,
42 EntryIndex i)
43 : i_(i), index_(indices), coefficient_(coefficients) {}
44
45 EntryIndex i_;
46 const Index* index_;
48};
49
50// A simple struct that contains a DenseVector and its non-zero indices.
51// TODO(user): This should be changed from struct to class.
52template <typename Index,
56
57 // This can be left empty in which case we just have the dense representation
58 // above. Otherwise, it should always be a superset of the actual non-zeros.
60 std::vector<Index> non_zeros;
61
62 // Temporary vector used in some sparse computation on the ScatteredVector.
63 // True indicates a possible non-zero value. Note that its state is not always
64 // consistent.
66
67 // In many cases there is a choice between treating the ScatteredVector as
68 // dense or as sparse. By default, dense algorithms are used when the
69 // proportion of non-zero entries is greater than
70 // kDefaultRatioForUsingDenseIteration.
71 //
72 // TODO(user): The constant should depend on what algorithm is used. Clearing
73 // a dense vector is a lot more efficient than doing more complex stuff. Clean
74 // this up by extracting all the currently used constants in one place with
75 // meaningful names.
76 constexpr static const double kDefaultRatioForUsingDenseIteration = 0.8;
77
78 Fractional operator[](Index index) const { return values[index]; }
79 Fractional& operator[](Index index) { return values[index]; }
80
81 // The iterator syntax for (auto entry : v) where v is a ScatteredVector only
82 // works when non_zeros is populated (i.e., when the vector is treated as
83 // sparse).
84 Iterator begin() const {
85 DCHECK(!non_zeros.empty() || IsAllZero(values));
86 return Iterator(this->non_zeros.data(), this->values.data(), EntryIndex(0));
87 }
88 Iterator end() const {
89 return Iterator(this->non_zeros.data(), this->values.data(),
90 EntryIndex(non_zeros.size()));
91 }
92
93 // Add the given value to the vector at position index. This interface
94 // encapsulates usage of the "is_non_zero" array, which should not be
95 // explicitly referenced outside of this struct.
96 void Add(Index index, Fractional value) {
97 values[index] += value;
98 if (!is_non_zero[index] && value != 0.0) {
99 is_non_zero.Set(index);
100 non_zeros.push_back(index);
101 non_zeros_are_sorted = false;
102 }
103 }
104
105 // Sorting the non-zeros is not always needed, but it allows us to have
106 // exactly the same behavior while using a sparse iteration or a dense one. So
107 // we always do it after a Solve().
110 std::sort(non_zeros.begin(), non_zeros.end());
112 }
113 }
114
115 // Returns true if it is more advantageous to use a dense iteration rather
116 // than using the non-zeros positions.
118 double ratio_for_using_dense_representation) const {
119 if (non_zeros.empty()) return true;
120 return static_cast<double>(non_zeros.size()) >
121 ratio_for_using_dense_representation *
122 static_cast<double>(values.size().value());
123 }
124
128
129 // Efficiently clears the is_non_zero vector.
132 is_non_zero.ClearAndResize(values.size());
133 } else {
134 is_non_zero.Resize(values.size());
135 for (const Index index : non_zeros) {
136 is_non_zero.ClearBucket(index);
137 }
138 DCHECK(is_non_zero.IsAllFalse());
139 }
140 }
141
142 // Update the is_non_zero vector to be consistent with the non_zeros vector.
145 for (const Index index : non_zeros) {
146 // is_non_zero[index] = true;
147 is_non_zero.Set(index);
148 }
149 }
150
151 // If the proportion of non-zero entries is too large, clears the vector of
152 // non-zeros.
153 void ClearNonZerosIfTooDense(double ratio_for_using_dense_representation) {
154 if (ShouldUseDenseIteration(ratio_for_using_dense_representation)) {
156 non_zeros.clear();
157 }
158 }
159
163
164 // Returns an overestimate of the number of non-zeros. This is actually
165 // exact for sparse vector, or the full size otherwise.
166 size_t NumNonZerosEstimate() const {
167 return non_zeros.empty() ? values.size().value() : non_zeros.size();
168 }
169};
170
171// Specializations used in the code.
173 public:
174 // Returns the row of the current entry.
175 RowIndex row() const { return index(); }
176
177 protected:
178 ScatteredColumnEntry(const RowIndex* indices, const Fractional* coefficients,
179 EntryIndex i)
180 : ScatteredVectorEntry<RowIndex>(indices, coefficients, i) {}
181};
182
183class ScatteredRowEntry : public ScatteredVectorEntry<ColIndex> {
184 public:
185 // Returns the column of the current entry.
186 ColIndex column() const { return index(); }
187
188 protected:
189 ScatteredRowEntry(const ColIndex* indices, const Fractional* coefficients,
190 EntryIndex i)
191 : ScatteredVectorEntry<ColIndex>(indices, coefficients, i) {}
192};
193
196
198 : public ScatteredVector<RowIndex, ScatteredColumnIterator> {};
199struct ScatteredRow : public ScatteredVector<ColIndex, ScatteredRowIterator> {};
200
202 return reinterpret_cast<const ScatteredRow&>(c);
203}
205 return reinterpret_cast<const ScatteredColumn&>(r);
206}
207
208} // namespace glop
209} // namespace operations_research
210
211#endif // OR_TOOLS_LP_DATA_SCATTERED_VECTOR_H_
RowIndex row() const
Returns the row of the current entry.
ScatteredColumnEntry(const RowIndex *indices, const Fractional *coefficients, EntryIndex i)
ColIndex column() const
Returns the column of the current entry.
ScatteredRowEntry(const ColIndex *indices, const Fractional *coefficients, EntryIndex i)
ScatteredVectorEntry(const Index *indices, const Fractional *coefficients, EntryIndex i)
bool IsAllZero(const Container &input)
Returns true if the given Fractional container is all zeros.
Definition lp_utils.h:229
VectorIterator< ScatteredColumnEntry > ScatteredColumnIterator
VectorIterator< ScatteredRowEntry > ScatteredRowIterator
const ScatteredRow & TransposedView(const ScatteredColumn &c)
In SWIG mode, we don't want anything besides these top-level includes.
Fractional operator[](Index index) const
void ClearNonZerosIfTooDense(double ratio_for_using_dense_representation)
void Add(Index index, Fractional value)
static constexpr const double kDefaultRatioForUsingDenseIteration
void ClearSparseMask()
Efficiently clears the is_non_zero vector.
StrictITIVector< Index, Fractional > values
void RepopulateSparseMask()
Update the is_non_zero vector to be consistent with the non_zeros vector.
bool ShouldUseDenseIteration(double ratio_for_using_dense_representation) const