Files
ortools-clone/ortools/lp_data/sparse_column.h
Laurent Perron c64f28f3bc fix includes
2024-01-12 16:30:47 +01:00

205 lines
6.8 KiB
C++

// Copyright 2010-2024 Google LLC
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef OR_TOOLS_LP_DATA_SPARSE_COLUMN_H_
#define OR_TOOLS_LP_DATA_SPARSE_COLUMN_H_
#include <vector>
#include "ortools/lp_data/lp_types.h"
#include "ortools/lp_data/permutation.h"
#include "ortools/lp_data/sparse_vector.h"
namespace operations_research {
namespace glop {
// TODO(user): Consider using kInvalidRow for this?
const RowIndex kNonPivotal(-1);
// Specialization of SparseVectorEntry and SparseColumnIterator for the
// SparseColumn class. In addition to index(), it also provides row() for better
// readability on the client side.
class SparseColumnEntry : public SparseVectorEntry<RowIndex> {
public:
// Returns the row of the current entry.
RowIndex row() const { return index(); }
protected:
SparseColumnEntry(const RowIndex* indices, const Fractional* coefficients,
EntryIndex i)
: SparseVectorEntry<RowIndex>(indices, coefficients, i) {}
};
using SparseColumnIterator = VectorIterator<SparseColumnEntry>;
class ColumnView;
// A SparseColumn is a SparseVector<RowIndex>, with a few methods renamed
// to help readability on the client side.
class SparseColumn : public SparseVector<RowIndex, SparseColumnIterator> {
friend class ColumnView;
public:
SparseColumn() : SparseVector<RowIndex, SparseColumnIterator>() {}
// Use a separate API to get the row and coefficient of entry #i.
RowIndex EntryRow(EntryIndex i) const { return GetIndex(i); }
Fractional EntryCoefficient(EntryIndex i) const { return GetCoefficient(i); }
RowIndex GetFirstRow() const { return GetFirstIndex(); }
RowIndex GetLastRow() const { return GetLastIndex(); }
void ApplyRowPermutation(const RowPermutation& p) {
ApplyIndexPermutation(p);
}
void ApplyPartialRowPermutation(const RowPermutation& p) {
ApplyPartialIndexPermutation(p);
}
};
// Class to iterate on the entries of a given column with the same interface
// as for SparseColumn.
class ColumnView {
public:
// Clients should pass Entry by value rather than by reference.
// This is because SparseColumnEntry is small (2 pointers and an index) and
// previous profiling of this type of use showed no performance penalty
// (see cl/51057736).
// Example: for(const Entry e : column_view)
typedef SparseColumnEntry Entry;
typedef VectorIterator<Entry> Iterator;
ColumnView(EntryIndex num_entries, const RowIndex* rows,
const Fractional* const coefficients)
: num_entries_(num_entries), rows_(rows), coefficients_(coefficients) {}
explicit ColumnView(const SparseColumn& column)
: num_entries_(column.num_entries()),
rows_(column.index_),
coefficients_(column.coefficient_) {}
EntryIndex num_entries() const { return num_entries_; }
Fractional EntryCoefficient(EntryIndex i) const {
return coefficients_[i.value()];
}
Fractional GetFirstCoefficient() const {
return EntryCoefficient(EntryIndex(0));
}
RowIndex EntryRow(EntryIndex i) const { return rows_[i.value()]; }
RowIndex GetFirstRow() const { return EntryRow(EntryIndex(0)); }
Iterator begin() const {
return Iterator(this->rows_, this->coefficients_, EntryIndex(0));
}
Iterator end() const {
return Iterator(this->rows_, this->coefficients_, num_entries_);
}
Fractional LookUpCoefficient(RowIndex index) const {
Fractional value(0.0);
for (const auto e : *this) {
if (e.row() == index) {
// Keep in mind the vector may contains several entries with the same
// index. In such a case the last one is returned.
// TODO(user): investigate whether an optimized version of
// LookUpCoefficient for "clean" columns yields speed-ups.
value = e.coefficient();
}
}
return value;
}
bool IsEmpty() const { return num_entries_ == EntryIndex(0); }
private:
const EntryIndex num_entries_;
const RowIndex* const rows_;
const Fractional* const coefficients_;
};
// --------------------------------------------------------
// RandomAccessSparseColumn
// --------------------------------------------------------
// A RandomAccessSparseColumn is a mix between a DenseColumn and a SparseColumn.
// It makes it possible to populate a dense column from a sparse column in
// O(num_entries) instead of O(num_rows), and to access an entry in O(1).
// As the constructor runs in O(num_rows), a RandomAccessSparseColumn should be
// used several times to amortize the creation cost.
class RandomAccessSparseColumn {
public:
// Creates a RandomAccessSparseColumn.
// Runs in O(num_rows).
explicit RandomAccessSparseColumn(RowIndex num_rows);
// This type is neither copyable nor movable.
RandomAccessSparseColumn(const RandomAccessSparseColumn&) = delete;
RandomAccessSparseColumn& operator=(const RandomAccessSparseColumn&) = delete;
virtual ~RandomAccessSparseColumn();
// Clears the column.
// Runs in O(num_entries).
void Clear();
void Resize(RowIndex num_rows);
// Sets value at row.
// Runs in O(1).
void SetCoefficient(RowIndex row, Fractional value) {
column_[row] = value;
MarkRowAsChanged(row);
}
// Adds value to the current value at row.
// Runs in O(1).
void AddToCoefficient(RowIndex row, Fractional value) {
column_[row] += value;
MarkRowAsChanged(row);
}
// Populates from a sparse column.
// Runs in O(num_entries).
void PopulateFromSparseColumn(const SparseColumn& sparse_column);
// Populates a sparse column from the lazy dense column.
// Runs in O(num_entries).
void PopulateSparseColumn(SparseColumn* sparse_column) const;
// Returns the number of rows.
// Runs in O(1).
RowIndex GetNumberOfRows() const { return RowIndex(column_.size()); }
// Returns the value in position row.
// Runs in O(1).
Fractional GetCoefficient(RowIndex row) const { return column_[row]; }
private:
// Keeps a trace of which rows have been changed.
void MarkRowAsChanged(RowIndex row) {
if (!changed_[row]) {
changed_[row] = true;
row_change_.push_back(row);
}
}
// The dense version of the column.
DenseColumn column_;
// Dense Boolean vector used to mark changes.
DenseBooleanColumn changed_;
// Stack to store changes.
std::vector<RowIndex> row_change_;
};
} // namespace glop
} // namespace operations_research
#endif // OR_TOOLS_LP_DATA_SPARSE_COLUMN_H_