OR-Tools  9.6
scattered_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_LP_DATA_SCATTERED_VECTOR_H_
15 #define OR_TOOLS_LP_DATA_SCATTERED_VECTOR_H_
16 
17 #include <cmath>
18 #include <limits>
19 
21 #include "ortools/base/logging.h"
23 #include "ortools/util/bitset.h"
24 
25 namespace operations_research {
26 namespace 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.
31 template <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.
53 template <typename Index,
54  typename Iterator = VectorIterator<ScatteredVectorEntry<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.
60  bool non_zeros_are_sorted = false;
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().
110  if (!non_zeros_are_sorted) {
111  std::sort(non_zeros.begin(), non_zeros.end());
112  non_zeros_are_sorted = true;
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 
126  bool ShouldUseDenseIteration() const {
128  }
129 
130  // Efficiently clears the is_non_zero vector.
132  if (ShouldUseDenseIteration()) {
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  }
139  DCHECK(IsAllFalse(is_non_zero));
140  }
141  }
142 
143  // Update the is_non_zero vector to be consistent with the non_zeros vector.
145  ClearSparseMask();
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)) {
153  ClearSparseMask();
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.
170 class ScatteredColumnEntry : public ScatteredVectorEntry<RowIndex> {
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 
181 class 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> {};
197 struct ScatteredRow : public ScatteredVector<ColIndex, ScatteredRowIterator> {};
198 
199 inline const ScatteredRow& TransposedView(const ScatteredColumn& c) {
200  return reinterpret_cast<const ScatteredRow&>(c);
201 }
202 inline const ScatteredColumn& TransposedView(const ScatteredRow& r) {
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_
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:312
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.
bool ShouldUseDenseIteration(double ratio_for_using_dense_representation) const
constexpr static const double kDefaultRatioForUsingDenseIteration
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