Google OR-Tools v9.11
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-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_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
23namespace operations_research {
24namespace glop {
25
26// A class representing an entry of a scattered vector. The i-th nonzero
27// element of the vector is assumed to be located at indices[i] and its value is
28// coefficients[indices[i]], i.e., coefficients is a dense array.
29template <typename IndexType>
31 public:
32 using Index = IndexType;
33
34 Index index() const { return index_[i_.value()]; }
36 return coefficient_[index_[i_.value()].value()];
37 }
38
39 protected:
41 EntryIndex i)
42 : i_(i), index_(indices), coefficient_(coefficients) {}
43
44 EntryIndex i_;
45 const Index* index_;
47};
48
49// A simple struct that contains a DenseVector and its non-zero indices.
50// TODO(user): This should be changed from struct to class.
51template <typename Index,
55
56 // This can be left empty in which case we just have the dense representation
57 // above. Otherwise, it should always be a superset of the actual non-zeros.
59 std::vector<Index> non_zeros;
60
61 // Temporary vector used in some sparse computation on the ScatteredVector.
62 // True indicates a possible non-zero value. Note that its state is not always
63 // consistent.
65
66 // In many cases there is a choice between treating the ScatteredVector as
67 // dense or as sparse. By default, dense algorithms are used when the
68 // proportion of non-zero entries is greater than
69 // kDefaultRatioForUsingDenseIteration.
70 //
71 // TODO(user): The constant should depend on what algorithm is used. Clearing
72 // a dense vector is a lot more efficient than doing more complex stuff. Clean
73 // this up by extracting all the currently used constants in one place with
74 // meaningful names.
75 constexpr static const double kDefaultRatioForUsingDenseIteration = 0.8;
76
79
80 // The iterator syntax for (auto entry : v) where v is a ScatteredVector only
81 // works when non_zeros is populated (i.e., when the vector is treated as
82 // sparse).
83 Iterator begin() const {
84 DCHECK(!non_zeros.empty() || IsAllZero(values));
85 return Iterator(this->non_zeros.data(), this->values.data(), EntryIndex(0));
86 }
87 Iterator end() const {
88 return Iterator(this->non_zeros.data(), this->values.data(),
89 EntryIndex(non_zeros.size()));
90 }
91
92 // Add the given value to the vector at position index. This interface
93 // encapsulates usage of the "is_non_zero" array, which should not be
94 // explicitly referenced outside of this struct.
96 values[index] += value;
97 if (!is_non_zero[index] && value != 0.0) {
98 is_non_zero[index] = true;
99 non_zeros.push_back(index);
100 non_zeros_are_sorted = false;
101 }
102 }
103
104 // Sorting the non-zeros is not always needed, but it allows us to have
105 // exactly the same behavior while using a sparse iteration or a dense one. So
106 // we always do it after a Solve().
109 std::sort(non_zeros.begin(), non_zeros.end());
111 }
112 }
113
114 // Returns true if it is more advantageous to use a dense iteration rather
115 // than using the non-zeros positions.
117 double ratio_for_using_dense_representation) const {
118 if (non_zeros.empty()) return true;
119 return static_cast<double>(non_zeros.size()) >
120 ratio_for_using_dense_representation *
121 static_cast<double>(values.size().value());
122 }
123
127
128 // Efficiently clears the is_non_zero vector.
131 is_non_zero.assign(values.size(), false);
132 } else {
133 is_non_zero.resize(values.size(), false);
134 for (const Index index : non_zeros) {
135 is_non_zero[index] = false;
136 }
137 DCHECK(IsAllFalse(is_non_zero));
138 }
139 }
140
141 // Update the is_non_zero vector to be consistent with the non_zeros vector.
144 for (const Index index : non_zeros) is_non_zero[index] = true;
145 }
146
147 // If the proportion of non-zero entries is too large, clears the vector of
148 // non-zeros.
149 void ClearNonZerosIfTooDense(double ratio_for_using_dense_representation) {
150 if (ShouldUseDenseIteration(ratio_for_using_dense_representation)) {
152 non_zeros.clear();
153 }
154 }
155
159
160 // Returns an overestimate of the number of non-zeros. This is actually
161 // exact for sparse vector, or the full size otherwise.
162 size_t NumNonZerosEstimate() const {
163 return non_zeros.empty() ? values.size().value() : non_zeros.size();
164 }
165};
166
167// Specializations used in the code.
169 public:
170 // Returns the row of the current entry.
171 RowIndex row() const { return index(); }
172
173 protected:
174 ScatteredColumnEntry(const RowIndex* indices, const Fractional* coefficients,
175 EntryIndex i)
176 : ScatteredVectorEntry<RowIndex>(indices, coefficients, i) {}
177};
178
179class ScatteredRowEntry : public ScatteredVectorEntry<ColIndex> {
180 public:
181 // Returns the column of the current entry.
182 ColIndex column() const { return index(); }
183
184 protected:
185 ScatteredRowEntry(const ColIndex* indices, const Fractional* coefficients,
186 EntryIndex i)
187 : ScatteredVectorEntry<ColIndex>(indices, coefficients, i) {}
188};
189
192
194 : public ScatteredVector<RowIndex, ScatteredColumnIterator> {};
195struct ScatteredRow : public ScatteredVector<ColIndex, ScatteredRowIterator> {};
196
198 return reinterpret_cast<const ScatteredRow&>(c);
199}
201 return reinterpret_cast<const ScatteredColumn&>(r);
202}
203
204} // namespace glop
205} // namespace operations_research
206
207#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)
void assign(IntType size, const T &v)
Definition lp_types.h:319
int64_t value
absl::Span< const double > coefficients
int index
bool IsAllZero(const Container &input)
Returns true if the given Fractional container is all zeros.
Definition lp_utils.h:229
bool IsAllFalse(const BoolVector &v)
Returns true if the given vector of bool is all false.
Definition lp_utils.h:238
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
StrictITIVector< Index, bool > is_non_zero