30#ifndef OR_TOOLS_LP_DATA_SPARSE_VECTOR_H_
31#define OR_TOOLS_LP_DATA_SPARSE_VECTOR_H_
38#include "absl/strings/str_format.h"
49template <
typename IndexType>
50class SparseVectorEntry;
81template <
typename IndexType,
82 typename IteratorType = VectorIterator<SparseVectorEntry<IndexType>>>
91 using Entry =
typename Iterator::Entry;
101#if !defined(_MSC_VER)
106#if !defined(_MSC_VER)
303 return ::util::IntegerRange<EntryIndex>(EntryIndex(0),
num_entries_);
394 void AddMultipleToSparseVectorInternal(
410template <
typename IndexType>
445template <
typename IndexType,
typename IteratorType>
447 return Iterator(this->index_, this->coefficient_, EntryIndex(0));
450template <
typename IndexType,
typename IteratorType>
452 return Iterator(this->index_, this->coefficient_, num_entries_);
458template <
typename IndexType,
typename IteratorType>
463 coefficient_(nullptr),
464 may_contain_duplicates_(false) {}
466template <
typename IndexType,
typename IteratorType>
468 PopulateFromSparseVector(other);
471template <
typename IndexType,
typename IteratorType>
474 PopulateFromSparseVector(other);
478template <
typename IndexType,
typename IteratorType>
480 num_entries_ = EntryIndex(0);
481 may_contain_duplicates_ =
false;
484template <
typename IndexType,
typename IteratorType>
486 capacity_ = EntryIndex(0);
487 num_entries_ = EntryIndex(0);
489 coefficient_ =
nullptr;
491 may_contain_duplicates_ =
false;
494template <
typename IndexType,
typename IteratorType>
496 if (new_capacity <= capacity_)
return;
500 if (new_capacity.value() & 3) {
501 new_capacity += EntryIndex(4 - (new_capacity.value() & 3));
504 const size_t index_buffer_size = new_capacity.value() *
sizeof(
Index);
505 const size_t value_buffer_size = new_capacity.value() *
sizeof(
Fractional);
506 const size_t new_buffer_size = index_buffer_size + value_buffer_size;
507 std::unique_ptr<char[]> new_buffer(
new char[new_buffer_size]);
508 IndexType*
const new_index =
reinterpret_cast<Index*
>(new_buffer.get());
510 reinterpret_cast<Fractional*
>(new_index + new_capacity.value());
513 if (num_entries_ > 0) {
518 std::memmove(new_index, index_,
sizeof(IndexType) * num_entries_.value());
519 std::memmove(new_coefficient, coefficient_,
524 coefficient_ = new_coefficient;
525 capacity_ = new_capacity;
528template <
typename IndexType,
typename IteratorType>
530 return num_entries_ == EntryIndex(0);
533template <
typename IndexType,
typename IteratorType>
543template <
typename IndexType,
typename IteratorType>
555 std::vector<std::pair<Index, Fractional>> entries;
556 entries.reserve(num_entries_.value());
557 for (EntryIndex i(0); i < num_entries_; ++i) {
561 entries.begin(), entries.end(),
562 [](
const std::pair<Index, Fractional>&
a,
563 const std::pair<Index, Fractional>&
b) { return a.first < b.first; });
565 EntryIndex new_size(0);
566 for (
int i = 0; i < num_entries_; ++i) {
567 const std::pair<Index, Fractional> entry = entries[i];
568 if (entry.second == 0.0)
continue;
569 if (i + 1 == num_entries_ || entry.first != entries[i + 1].first) {
570 MutableIndex(new_size) = entry.first;
571 MutableCoefficient(new_size) = entry.second;
575 ResizeDown(new_size);
576 may_contain_duplicates_ =
false;
579template <
typename IndexType,
typename IteratorType>
581 Index previous_index(-1);
582 for (
const EntryIndex i : AllEntryIndices()) {
585 previous_index =
index;
587 may_contain_duplicates_ =
false;
591template <
typename IndexType,
typename IteratorType>
608 std::memmove(index_, sparse_vector.
index_,
617template <
typename IndexType,
typename IteratorType>
621 const Index num_indices(dense_vector.
size());
623 if (dense_vector[
index] != 0.0) {
627 may_contain_duplicates_ =
false;
630template <
typename IndexType,
typename IteratorType>
638 may_contain_duplicates_ =
true;
641template <
typename IndexType,
typename IteratorType>
647 if (!may_contain_duplicates_ || num_entries_ <= 1)
return true;
650 const Index max_index =
651 *std::max_element(index_, index_ + num_entries_.value());
652 if (boolean_vector->
size() <= max_index) {
653 boolean_vector->
resize(max_index + 1,
false);
656 may_contain_duplicates_ =
false;
657 for (
const EntryIndex i : AllEntryIndices()) {
659 if ((*boolean_vector)[
index]) {
660 may_contain_duplicates_ =
true;
663 (*boolean_vector)[
index] =
true;
667 for (
const EntryIndex i : AllEntryIndices()) {
668 (*boolean_vector)[GetIndex(i)] =
false;
670 return !may_contain_duplicates_;
673template <
typename IndexType,
typename IteratorType>
677 if (!may_contain_duplicates_ || num_entries_ <= 1)
return true;
679 return CheckNoDuplicates(&boolean_vector);
684template <
typename IndexType,
typename IteratorType>
688 may_contain_duplicates_ =
true;
691template <
typename IndexType,
typename IteratorType>
693 DCHECK(CheckNoDuplicates());
696 while (i < end && GetIndex(i) !=
index) {
699 if (i == end)
return;
700 const int num_moved_entries = (num_entries_ - i).
value() - 1;
701 std::memmove(index_ + i.value(), index_ + i.value() + 1,
702 sizeof(
Index) * num_moved_entries);
703 std::memmove(coefficient_ + i.value(), coefficient_ + i.value() + 1,
708template <
typename IndexType,
typename IteratorType>
711 DCHECK(CheckNoDuplicates());
712 EntryIndex new_index(0);
713 for (
const EntryIndex i : AllEntryIndices()) {
715 if (magnitude > threshold) {
716 MutableIndex(new_index) = GetIndex(i);
721 ResizeDown(new_index);
724template <
typename IndexType,
typename IteratorType>
727 DCHECK(CheckNoDuplicates());
728 EntryIndex new_index(0);
729 for (
const EntryIndex i : AllEntryIndices()) {
731 MutableIndex(new_index) = GetIndex(i);
736 ResizeDown(new_index);
739template <
typename IndexType,
typename IteratorType>
742 DCHECK(CheckNoDuplicates());
743 for (
const EntryIndex i : AllEntryIndices()) {
744 if (GetIndex(i) ==
index) {
745 std::swap(MutableIndex(EntryIndex(0)), MutableIndex(i));
746 std::swap(MutableCoefficient(EntryIndex(0)), MutableCoefficient(i));
752template <
typename IndexType,
typename IteratorType>
755 DCHECK(CheckNoDuplicates());
757 for (
const EntryIndex i : AllEntryIndices()) {
758 if (GetIndex(i) ==
index) {
759 std::swap(MutableIndex(last_entry), MutableIndex(i));
760 std::swap(MutableCoefficient(last_entry), MutableCoefficient(i));
766template <
typename IndexType,
typename IteratorType>
769 for (
const EntryIndex i : AllEntryIndices()) {
770 MutableCoefficient(i) *= factor;
774template <
typename IndexType,
typename IteratorType>
777 for (
const EntryIndex i : AllEntryIndices()) {
778 MutableCoefficient(i) *= factors[GetIndex(i)];
782template <
typename IndexType,
typename IteratorType>
785 for (
const EntryIndex i : AllEntryIndices()) {
786 MutableCoefficient(i) /= factor;
790template <
typename IndexType,
typename IteratorType>
793 for (
const EntryIndex i : AllEntryIndices()) {
794 MutableCoefficient(i) /= factors[GetIndex(i)];
798template <
typename IndexType,
typename IteratorType>
803 for (
const EntryIndex i : AllEntryIndices()) {
808template <
typename IndexType,
typename IteratorType>
814 for (
const EntryIndex i : AllEntryIndices()) {
819template <
typename IndexType,
typename IteratorType>
823 if (multiplier == 0.0)
return;
824 for (
const EntryIndex i : AllEntryIndices()) {
829template <
typename IndexType,
typename IteratorType>
834 AddMultipleToSparseVectorInternal(
true, multiplier, removed_common_index,
835 drop_tolerance, accumulator_vector);
838template <
typename IndexType,
typename IteratorType>
843 AddMultipleToSparseVectorInternal(
false, multiplier, removed_common_index,
844 drop_tolerance, accumulator_vector);
847template <
typename IndexType,
typename IteratorType>
854 DCHECK(CheckNoDuplicates());
856 DCHECK_NE(0.0, LookUpCoefficient(common_index));
870 const EntryIndex size_a =
a.num_entries();
871 const EntryIndex size_b =
b.num_entries();
872 const int size_adjustment = delete_common_index ? -2 : 0;
873 const EntryIndex new_size_upper_bound = size_a + size_b + size_adjustment;
874 c.
Reserve(new_size_upper_bound);
876 while ((ia < size_a) && (ib < size_b)) {
877 const Index index_a =
a.GetIndex(ia);
878 const Index index_b =
b.GetIndex(ib);
881 if (index_a == index_b) {
882 if (index_a != common_index) {
883 const Fractional a_coeff_mul = multiplier *
a.GetCoefficient(ia);
889 if (std::abs(sum) > drop_tolerance) {
894 }
else if (!delete_common_index) {
901 }
else if (index_a < index_b) {
913 while (ia < size_a) {
919 while (ib < size_b) {
927 c.
Swap(accumulator_vector);
930template <
typename IndexType,
typename IteratorType>
933 for (
const EntryIndex i : AllEntryIndices()) {
934 MutableIndex(i) = index_perm[GetIndex(i)];
938template <
typename IndexType,
typename IteratorType>
941 EntryIndex new_index(0);
942 for (
const EntryIndex i : AllEntryIndices()) {
944 if (index_perm[
index] >= 0) {
945 MutableIndex(new_index) = index_perm[
index];
950 ResizeDown(new_index);
953template <
typename IndexType,
typename IteratorType>
958 const EntryIndex end(num_entries_);
961 if (i >= end)
return;
962 if (index_perm[GetIndex(i)] >= 0)
break;
966 for (EntryIndex j(i + 1); j < end; ++j) {
967 if (index_perm[GetIndex(j)] < 0) {
968 MutableIndex(i) = GetIndex(j);
983template <
typename IndexType,
typename IteratorType>
987 for (
const EntryIndex i : AllEntryIndices()) {
988 if (GetIndex(i) ==
index) {
999template <
typename IndexType,
typename IteratorType>
1004 for (
const EntryIndex i : AllEntryIndices()) {
1005 if (GetIndex(i) != other.
GetIndex(i))
return false;
1011template <
typename IndexType,
typename IteratorType>
1014 for (
const EntryIndex i : AllEntryIndices()) {
1015 if (i != 0) s +=
", ";
1016 absl::StrAppendFormat(&s,
"[%d]=%g", GetIndex(i).
value(),
#define DCHECK_LE(val1, val2)
#define DCHECK_NE(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK(condition)
Fractional coefficient() const
const Fractional * coefficient_
SparseVectorEntry(const Index *indices, const Fractional *coefficients, EntryIndex i)
void ComponentWiseMultiply(const DenseVector &factors)
std::unique_ptr< char[]> buffer_
void PopulateFromDenseVector(const DenseVector &dense_vector)
void MoveTaggedEntriesTo(const IndexPermutation &index_perm, SparseVector *output)
void Swap(SparseVector *other)
void ApplyIndexPermutation(const IndexPermutation &index_perm)
Index GetIndex(EntryIndex i) const
bool CheckNoDuplicates() const
void CopyToDenseVector(Index num_indices, DenseVector *dense_vector) const
Fractional LookUpCoefficient(Index index) const
SparseVector & operator=(const SparseVector &other)
void AddMultipleToDenseVector(Fractional multiplier, DenseVector *dense_vector) const
void ResizeDown(EntryIndex new_size)
void RemoveNearZeroEntriesWithWeights(Fractional threshold, const DenseVector &weights)
void PermutedCopyToDenseVector(const IndexPermutation &index_perm, Index num_indices, DenseVector *dense_vector) const
void AddMultipleToSparseVectorAndDeleteCommonIndex(Fractional multiplier, Index removed_common_index, Fractional drop_tolerance, SparseVector *accumulator_vector) const
SparseVector & operator=(SparseVector &&other)=default
bool may_contain_duplicates_
Fractional * coefficient_
std::string DebugString() const
Index & MutableIndex(EntryIndex i)
void DivideByConstant(Fractional factor)
Index GetLastIndex() const
Index GetFirstIndex() const
void MultiplyByConstant(Fractional factor)
SparseVector(SparseVector &&other)=default
void ComponentWiseDivide(const DenseVector &factors)
typename Iterator::Entry Entry
::util::IntegerRange< EntryIndex > AllEntryIndices() const
void ApplyPartialIndexPermutation(const IndexPermutation &index_perm)
Permutation< Index > IndexPermutation
void AddMultipleToSparseVectorAndIgnoreCommonIndex(Fractional multiplier, Index removed_common_index, Fractional drop_tolerance, SparseVector *accumulator_vector) const
void RemoveNearZeroEntries(Fractional threshold)
void MoveEntryToFirstPosition(Index index)
bool CheckNoDuplicates(StrictITIVector< Index, bool > *boolean_vector) const
void MoveEntryToLastPosition(Index index)
void AddEntry(Index index, Fractional value)
Fractional GetLastCoefficient() const
bool IsEqualTo(const SparseVector &other) const
Fractional GetFirstCoefficient() const
void Reserve(EntryIndex new_capacity)
void DeleteEntry(Index index)
void AppendEntriesWithOffset(const SparseVector &sparse_vector, Index offset)
Fractional GetCoefficient(EntryIndex i) const
void SetCoefficient(Index index, Fractional value)
void PopulateFromSparseVector(const SparseVector &sparse_vector)
StrictITIVector< Index, Fractional > DenseVector
SparseVector(const SparseVector &other)
EntryIndex num_entries() const
Fractional & MutableCoefficient(EntryIndex i)
void AssignToZero(IntType size)
void resize(IntType size)
absl::Span< const double > coefficients
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
IntegerValue GetCoefficient(const IntegerVariable var, const LinearExpression &expr)
Collection of objects used to extend the Constraint Solver library.
#define RETURN_IF_NULL(x)
#define RETURN_VALUE_IF_NULL(x, v)