OR-Tools  9.3
scattered_vector.h
Go to the documentation of this file.
1// Copyright 2010-2021 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 <cmath>
18#include <limits>
19
23#include "ortools/util/bitset.h"
24
25namespace operations_research {
26namespace glop {
27
28// A class representing an entry of a scattered vector. The i-th nonzero
29// element of the vector is assumed to be located at indices[i] and its value is
30// coefficients[indices[i]], i.e., coefficients is a dense array.
31template <typename IndexType>
33 public:
34 using Index = IndexType;
35
36 Index index() const { return index_[i_.value()]; }
38 return coefficient_[index_[i_.value()].value()];
39 }
40
41 protected:
43 EntryIndex i)
44 : i_(i), index_(indices), coefficient_(coefficients) {}
45
46 EntryIndex i_;
47 const Index* index_;
49};
50
51// A simple struct that contains a DenseVector and its non-zero indices.
52// TODO(user): This should be changed from struct to class.
53template <typename Index,
57
58 // This can be left empty in which case we just have the dense representation
59 // above. Otherwise, it should always be a superset of the actual non-zeros.
61 std::vector<Index> non_zeros;
62
63 // Temporary vector used in some sparse computation on the ScatteredVector.
64 // True indicates a possible non-zero value. Note that its state is not always
65 // consistent.
67
68 // In many cases there is a choice between treating the ScatteredVector as
69 // dense or as sparse. By default, dense algorithms are used when the
70 // proportion of non-zero entries is greater than
71 // kDefaultRatioForUsingDenseIteration.
72 //
73 // TODO(user): The constant should depend on what algorithm is used. Clearing
74 // a dense vector is a lot more efficient than doing more complex stuff. Clean
75 // this up by extracting all the currently used constants in one place with
76 // meaningful names.
77 constexpr static const double kDefaultRatioForUsingDenseIteration = 0.8;
78
81
82 // The iterator syntax for (auto entry : v) where v is a ScatteredVector only
83 // works when non_zeros is populated (i.e., when the vector is treated as
84 // sparse).
85 Iterator begin() const {
86 DCHECK(!non_zeros.empty() || IsAllZero(values));
87 return Iterator(this->non_zeros.data(), this->values.data(), EntryIndex(0));
88 }
89 Iterator end() const {
90 return Iterator(this->non_zeros.data(), this->values.data(),
91 EntryIndex(non_zeros.size()));
92 }
93
94 // Add the given value to the vector at position index. This interface
95 // encapsulates usage of the "is_non_zero" array, which should not be
96 // explicitly referenced outside of this struct.
98 values[index] += value;
99 if (!is_non_zero[index] && value != 0.0) {
100 is_non_zero[index] = true;
101 non_zeros.push_back(index);
102 non_zeros_are_sorted = false;
103 }
104 }
105
106 // Sorting the non-zeros is not always needed, but it allows us to have
107 // exactly the same behavior while using a sparse iteration or a dense one. So
108 // we always do it after a Solve().
111 std::sort(non_zeros.begin(), non_zeros.end());
113 }
114 }
115
116 // Returns true if it is more advantageous to use a dense iteration rather
117 // than using the non-zeros positions.
119 double ratio_for_using_dense_representation) const {
120 if (non_zeros.empty()) return true;
121 return static_cast<double>(non_zeros.size()) >
122 ratio_for_using_dense_representation *
123 static_cast<double>(values.size().value());
124 }
125
128 }
129
130 // Efficiently clears the is_non_zero vector.
133 is_non_zero.assign(values.size(), false);
134 } else {
135 is_non_zero.resize(values.size(), false);
136 for (const Index index : non_zeros) {
137 is_non_zero[index] = false;
138 }
140 }
141 }
142
143 // Update the is_non_zero vector to be consistent with the non_zeros vector.
146 for (const Index index : non_zeros) is_non_zero[index] = true;
147 }
148
149 // If the proportion of non-zero entries is too large, clears the vector of
150 // non-zeros.
151 void ClearNonZerosIfTooDense(double ratio_for_using_dense_representation) {
152 if (ShouldUseDenseIteration(ratio_for_using_dense_representation)) {
154 non_zeros.clear();
155 }
156 }
157
160 }
161
162 // Returns an over-estimate of the number of non-zeros. This is actually
163 // exact for sparse vector, or the full size otherwise.
164 size_t NumNonZerosEstimate() const {
165 return non_zeros.empty() ? values.size().value() : non_zeros.size();
166 }
167};
168
169// Specializations used in the code.
171 public:
172 // Returns the row of the current entry.
173 RowIndex row() const { return index(); }
174
175 protected:
176 ScatteredColumnEntry(const RowIndex* indices, const Fractional* coefficients,
177 EntryIndex i)
178 : ScatteredVectorEntry<RowIndex>(indices, coefficients, i) {}
179};
180
181class ScatteredRowEntry : public ScatteredVectorEntry<ColIndex> {
182 public:
183 // Returns the column of the current entry.
184 ColIndex column() const { return index(); }
185
186 protected:
187 ScatteredRowEntry(const ColIndex* indices, const Fractional* coefficients,
188 EntryIndex i)
189 : ScatteredVectorEntry<ColIndex>(indices, coefficients, i) {}
190};
191
194
196 : public ScatteredVector<RowIndex, ScatteredColumnIterator> {};
197struct ScatteredRow : public ScatteredVector<ColIndex, ScatteredRowIterator> {};
198
200 return reinterpret_cast<const ScatteredRow&>(c);
201}
203 return reinterpret_cast<const ScatteredColumn&>(r);
204}
205
206} // namespace glop
207} // namespace operations_research
208
209#endif // OR_TOOLS_LP_DATA_SCATTERED_VECTOR_H_
#define DCHECK(condition)
Definition: base/logging.h:890
RowIndex row() const
ScatteredColumnEntry(const RowIndex *indices, const Fractional *coefficients, EntryIndex i)
ColIndex column() const
ScatteredRowEntry(const ColIndex *indices, const Fractional *coefficients, EntryIndex i)
ScatteredVectorEntry(const Index *indices, const Fractional *coefficients, EntryIndex i)
EntryIndex i_
Index index() const
IndexType Index
Fractional coefficient() const
const Fractional * coefficient_
const Index * index_
void assign(IntType size, const T &v)
Definition: lp_types.h:278
int64_t value
absl::Span< const double > coefficients
int index
bool IsAllZero(const Container &input)
bool IsAllFalse(const BoolVector &v)
const ScatteredRow & TransposedView(const ScatteredColumn &c)
Collection of objects used to extend the Constraint Solver library.
static constexpr const double kDefaultRatioForUsingDenseIteration
bool ShouldUseDenseIteration(double ratio_for_using_dense_representation) const
void Add(Index index, Fractional value)
void ClearNonZerosIfTooDense(double ratio_for_using_dense_representation)
StrictITIVector< Index, bool > is_non_zero
StrictITIVector< Index, Fractional > values
Fractional operator[](Index index) const