30#ifndef OR_TOOLS_LP_DATA_SPARSE_VECTOR_H_
31#define OR_TOOLS_LP_DATA_SPARSE_VECTOR_H_
40#include "absl/strings/str_format.h"
51template <
typename IndexType>
52class SparseVectorEntry;
83template <
typename IndexType,
84 typename IteratorType = VectorIterator<SparseVectorEntry<IndexType>>>
93 using Entry =
typename Iterator::Entry;
103#if !defined(_MSC_VER)
108#if !defined(_MSC_VER)
136 void Reserve(EntryIndex new_capacity);
305 return ::util::IntegerRange<EntryIndex>(EntryIndex(0),
num_entries_);
339 DCHECK_GE(new_size, 0);
381 std::unique_ptr<char[]>
buffer_;
396 void AddMultipleToSparseVectorInternal(
412template <
typename IndexType>
415 using Index = IndexType;
447template <
typename IndexType,
typename IteratorType>
449 return Iterator(this->index_, this->coefficient_, EntryIndex(0));
452template <
typename IndexType,
typename IteratorType>
454 return Iterator(this->index_, this->coefficient_, num_entries_);
460template <
typename IndexType,
typename IteratorType>
465 coefficient_(nullptr),
466 may_contain_duplicates_(false) {}
468template <
typename IndexType,
typename IteratorType>
470 PopulateFromSparseVector(other);
473template <
typename IndexType,
typename IteratorType>
476 PopulateFromSparseVector(other);
480template <
typename IndexType,
typename IteratorType>
482 num_entries_ = EntryIndex(0);
483 may_contain_duplicates_ =
false;
486template <
typename IndexType,
typename IteratorType>
488 capacity_ = EntryIndex(0);
489 num_entries_ = EntryIndex(0);
491 coefficient_ =
nullptr;
493 may_contain_duplicates_ =
false;
496template <
typename IndexType,
typename IteratorType>
498 if (new_capacity <= capacity_)
return;
502 if (new_capacity.value() & 3) {
503 new_capacity += EntryIndex(4 - (new_capacity.value() & 3));
506 const size_t index_buffer_size = new_capacity.value() *
sizeof(
Index);
507 const size_t value_buffer_size = new_capacity.value() *
sizeof(
Fractional);
508 const size_t new_buffer_size = index_buffer_size + value_buffer_size;
509 std::unique_ptr<char[]> new_buffer(
new char[new_buffer_size]);
510 IndexType*
const new_index =
reinterpret_cast<Index*
>(new_buffer.get());
512 reinterpret_cast<Fractional*
>(new_index + new_capacity.value());
515 if (num_entries_ > 0) {
520 std::memmove(new_index, index_,
sizeof(IndexType) * num_entries_.value());
521 std::memmove(new_coefficient, coefficient_,
524 std::swap(buffer_, new_buffer);
526 coefficient_ = new_coefficient;
527 capacity_ = new_capacity;
530template <
typename IndexType,
typename IteratorType>
532 return num_entries_ == EntryIndex(0);
535template <
typename IndexType,
typename IteratorType>
537 std::swap(buffer_, other->buffer_);
538 std::swap(num_entries_, other->num_entries_);
539 std::swap(capacity_, other->capacity_);
540 std::swap(may_contain_duplicates_, other->may_contain_duplicates_);
541 std::swap(index_, other->index_);
542 std::swap(coefficient_, other->coefficient_);
545template <
typename IndexType,
typename IteratorType>
557 std::vector<std::pair<Index, Fractional>> entries;
558 entries.reserve(num_entries_.value());
559 for (EntryIndex i(0); i < num_entries_; ++i) {
560 entries.emplace_back(GetIndex(i), GetCoefficient(i));
563 entries.begin(), entries.end(),
564 [](
const std::pair<Index, Fractional>&
a,
565 const std::pair<Index, Fractional>&
b) { return a.first < b.first; });
567 EntryIndex new_size(0);
568 for (
int i = 0; i < num_entries_; ++i) {
569 const std::pair<Index, Fractional> entry = entries[i];
570 if (entry.second == 0.0)
continue;
571 if (i + 1 == num_entries_ || entry.first != entries[i + 1].first) {
572 MutableIndex(new_size) = entry.first;
573 MutableCoefficient(new_size) = entry.second;
577 ResizeDown(new_size);
578 may_contain_duplicates_ =
false;
581template <
typename IndexType,
typename IteratorType>
583 Index previous_index(-1);
584 for (
const EntryIndex i : AllEntryIndices()) {
587 previous_index =
index;
589 may_contain_duplicates_ =
false;
593template <
typename IndexType,
typename IteratorType>
595 const SparseVector& sparse_vector) {
601 Reserve(sparse_vector.capacity_);
605 if (sparse_vector.num_entries_ > 0) {
610 std::memmove(index_, sparse_vector.index_,
611 sizeof(
Index) * sparse_vector.num_entries_.value());
612 std::memmove(coefficient_, sparse_vector.coefficient_,
613 sizeof(
Fractional) * sparse_vector.num_entries_.value());
615 num_entries_ = sparse_vector.num_entries_;
616 may_contain_duplicates_ = sparse_vector.may_contain_duplicates_;
619template <
typename IndexType,
typename IteratorType>
621 const DenseVector& dense_vector) {
623 const Index num_indices(dense_vector.size());
625 if (dense_vector[
index] != 0.0) {
629 may_contain_duplicates_ =
false;
632template <
typename IndexType,
typename IteratorType>
634 const SparseVector& sparse_vector,
Index offset) {
635 for (
const EntryIndex i : sparse_vector.AllEntryIndices()) {
636 const Index new_index = offset + sparse_vector.GetIndex(i);
637 DCHECK_GE(new_index, 0);
638 AddEntry(new_index, sparse_vector.GetCoefficient(i));
640 may_contain_duplicates_ =
true;
643template <
typename IndexType,
typename IteratorType>
645 StrictITIVector<IndexType, bool>* boolean_vector)
const {
649 if (!may_contain_duplicates_ || num_entries_ <= 1)
return true;
652 const Index max_index =
653 *std::max_element(index_, index_ + num_entries_.value());
654 if (boolean_vector->size() <= max_index) {
655 boolean_vector->resize(max_index + 1,
false);
658 may_contain_duplicates_ =
false;
659 for (
const EntryIndex i : AllEntryIndices()) {
661 if ((*boolean_vector)[
index]) {
662 may_contain_duplicates_ =
true;
665 (*boolean_vector)[
index] =
true;
669 for (
const EntryIndex i : AllEntryIndices()) {
670 (*boolean_vector)[GetIndex(i)] =
false;
672 return !may_contain_duplicates_;
675template <
typename IndexType,
typename IteratorType>
679 if (!may_contain_duplicates_ || num_entries_ <= 1)
return true;
680 StrictITIVector<Index, bool> boolean_vector;
681 return CheckNoDuplicates(&boolean_vector);
686template <
typename IndexType,
typename IteratorType>
690 may_contain_duplicates_ =
true;
693template <
typename IndexType,
typename IteratorType>
695 DCHECK(CheckNoDuplicates());
697 const EntryIndex
end(num_entries());
698 while (i <
end && GetIndex(i) !=
index) {
701 if (i ==
end)
return;
702 const int num_moved_entries = (num_entries_ - i).
value() - 1;
703 std::memmove(index_ + i.value(), index_ + i.value() + 1,
704 sizeof(
Index) * num_moved_entries);
705 std::memmove(coefficient_ + i.value(), coefficient_ + i.value() + 1,
710template <
typename IndexType,
typename IteratorType>
713 DCHECK(CheckNoDuplicates());
714 EntryIndex new_index(0);
715 for (
const EntryIndex i : AllEntryIndices()) {
716 const Fractional magnitude = fabs(GetCoefficient(i));
717 if (magnitude > threshold) {
718 MutableIndex(new_index) = GetIndex(i);
719 MutableCoefficient(new_index) = GetCoefficient(i);
723 ResizeDown(new_index);
726template <
typename IndexType,
typename IteratorType>
728 Fractional threshold,
const DenseVector& weights) {
729 DCHECK(CheckNoDuplicates());
730 EntryIndex new_index(0);
731 for (
const EntryIndex i : AllEntryIndices()) {
732 if (fabs(GetCoefficient(i)) * weights[GetIndex(i)] > threshold) {
733 MutableIndex(new_index) = GetIndex(i);
734 MutableCoefficient(new_index) = GetCoefficient(i);
738 ResizeDown(new_index);
741template <
typename IndexType,
typename IteratorType>
744 DCHECK(CheckNoDuplicates());
745 for (
const EntryIndex i : AllEntryIndices()) {
746 if (GetIndex(i) ==
index) {
747 std::swap(MutableIndex(EntryIndex(0)), MutableIndex(i));
748 std::swap(MutableCoefficient(EntryIndex(0)), MutableCoefficient(i));
754template <
typename IndexType,
typename IteratorType>
757 DCHECK(CheckNoDuplicates());
758 const EntryIndex last_entry = num_entries() - 1;
759 for (
const EntryIndex i : AllEntryIndices()) {
760 if (GetIndex(i) ==
index) {
761 std::swap(MutableIndex(last_entry), MutableIndex(i));
762 std::swap(MutableCoefficient(last_entry), MutableCoefficient(i));
768template <
typename IndexType,
typename IteratorType>
771 for (
const EntryIndex i : AllEntryIndices()) {
772 MutableCoefficient(i) *= factor;
776template <
typename IndexType,
typename IteratorType>
779 for (
const EntryIndex i : AllEntryIndices()) {
780 MutableCoefficient(i) *= factors[GetIndex(i)];
784template <
typename IndexType,
typename IteratorType>
787 for (
const EntryIndex i : AllEntryIndices()) {
788 MutableCoefficient(i) /= factor;
792template <
typename IndexType,
typename IteratorType>
795 for (
const EntryIndex i : AllEntryIndices()) {
796 MutableCoefficient(i) /= factors[GetIndex(i)];
800template <
typename IndexType,
typename IteratorType>
805 for (
const EntryIndex i : AllEntryIndices()) {
806 (*dense_vector)[GetIndex(i)] = GetCoefficient(i);
810template <
typename IndexType,
typename IteratorType>
812 const IndexPermutation& index_perm,
Index num_indices,
813 DenseVector* dense_vector)
const {
815 dense_vector->AssignToZero(num_indices);
816 for (
const EntryIndex i : AllEntryIndices()) {
817 (*dense_vector)[index_perm[GetIndex(i)]] = GetCoefficient(i);
821template <
typename IndexType,
typename IteratorType>
823 Fractional multiplier, DenseVector* dense_vector)
const {
825 if (multiplier == 0.0)
return;
826 for (
const EntryIndex i : AllEntryIndices()) {
827 (*dense_vector)[GetIndex(i)] += multiplier * GetCoefficient(i);
831template <
typename IndexType,
typename IteratorType>
835 Fractional drop_tolerance, SparseVector* accumulator_vector)
const {
836 AddMultipleToSparseVectorInternal(
true, multiplier, removed_common_index,
837 drop_tolerance, accumulator_vector);
840template <
typename IndexType,
typename IteratorType>
845 AddMultipleToSparseVectorInternal(
false, multiplier, removed_common_index,
846 drop_tolerance, accumulator_vector);
849template <
typename IndexType,
typename IteratorType>
854 DCHECK(IsCleanedUp());
855 DCHECK(accumulator_vector->IsCleanedUp());
856 DCHECK(CheckNoDuplicates());
857 DCHECK(accumulator_vector->CheckNoDuplicates());
858 DCHECK_NE(0.0, LookUpCoefficient(common_index));
859 DCHECK_NE(0.0, accumulator_vector->LookUpCoefficient(common_index));
872 const EntryIndex size_a =
a.num_entries();
873 const EntryIndex size_b =
b.num_entries();
874 const int size_adjustment = delete_common_index ? -2 : 0;
875 const EntryIndex new_size_upper_bound = size_a + size_b + size_adjustment;
876 c.Reserve(new_size_upper_bound);
877 c.num_entries_ = new_size_upper_bound;
878 while ((ia < size_a) && (ib < size_b)) {
879 const Index index_a =
a.GetIndex(ia);
880 const Index index_b =
b.GetIndex(ib);
883 if (index_a == index_b) {
884 if (index_a != common_index) {
885 const Fractional a_coeff_mul = multiplier *
a.GetCoefficient(ia);
891 if (std::abs(sum) > drop_tolerance) {
892 c.MutableIndex(ic) = index_a;
893 c.MutableCoefficient(ic) = sum;
896 }
else if (!delete_common_index) {
897 c.MutableIndex(ic) =
b.GetIndex(ib);
898 c.MutableCoefficient(ic) =
b.GetCoefficient(ib);
903 }
else if (index_a < index_b) {
904 const Fractional new_value = multiplier *
a.GetCoefficient(ia);
905 if (std::abs(new_value) > drop_tolerance) {
906 c.MutableIndex(ic) = index_a;
907 c.MutableCoefficient(ic) = new_value;
912 c.MutableIndex(ic) =
b.GetIndex(ib);
913 c.MutableCoefficient(ic) =
b.GetCoefficient(ib);
918 while (ia < size_a) {
919 const Fractional new_value = multiplier *
a.GetCoefficient(ia);
920 if (std::abs(new_value) > drop_tolerance) {
921 c.MutableIndex(ic) =
a.GetIndex(ia);
922 c.MutableCoefficient(ic) = new_value;
927 while (ib < size_b) {
928 c.MutableIndex(ic) =
b.GetIndex(ib);
929 c.MutableCoefficient(ic) =
b.GetCoefficient(ib);
934 c.may_contain_duplicates_ =
false;
935 c.Swap(accumulator_vector);
936 DCHECK(accumulator_vector->IsCleanedUp());
939template <
typename IndexType,
typename IteratorType>
941 const IndexPermutation& index_perm) {
942 for (
const EntryIndex i : AllEntryIndices()) {
943 MutableIndex(i) = index_perm[GetIndex(i)];
947template <
typename IndexType,
typename IteratorType>
950 EntryIndex new_index(0);
951 for (
const EntryIndex i : AllEntryIndices()) {
953 if (index_perm[
index] >= 0) {
954 MutableIndex(new_index) = index_perm[
index];
955 MutableCoefficient(new_index) = GetCoefficient(i);
959 ResizeDown(new_index);
962template <
typename IndexType,
typename IteratorType>
964 const IndexPermutation& index_perm, SparseVector* output) {
967 const EntryIndex
end(num_entries_);
970 if (i >=
end)
return;
971 if (index_perm[GetIndex(i)] >= 0)
break;
974 output->AddEntry(GetIndex(i), GetCoefficient(i));
975 for (EntryIndex j(i + 1); j <
end; ++j) {
976 if (index_perm[GetIndex(j)] < 0) {
977 MutableIndex(i) = GetIndex(j);
978 MutableCoefficient(i) = GetCoefficient(j);
981 output->AddEntry(GetIndex(j), GetCoefficient(j));
989 output->may_contain_duplicates_ =
true;
992template <
typename IndexType,
typename IteratorType>
996 for (
const EntryIndex i : AllEntryIndices()) {
997 if (GetIndex(i) ==
index) {
1002 value = GetCoefficient(i);
1008template <
typename IndexType,
typename IteratorType>
1010 const SparseVector& other)
const {
1012 if (num_entries() != other.num_entries())
return false;
1013 for (
const EntryIndex i : AllEntryIndices()) {
1014 if (GetIndex(i) != other.GetIndex(i))
return false;
1015 if (GetCoefficient(i) != other.GetCoefficient(i))
return false;
1020template <
typename IndexType,
typename IteratorType>
1023 for (
const EntryIndex i : AllEntryIndices()) {
1024 if (i != 0) s +=
", ";
1025 absl::StrAppendFormat(&s,
"[%d]=%g", GetIndex(i).
value(),
Fractional coefficient() const
EntryIndex i_
The index of the sparse vector entry represented by this object.
const Fractional * coefficient_
SparseVectorEntry(const Index *indices, const Fractional *coefficients, EntryIndex i)
StrictITIVector< Index, Fractional > DenseVector
void Swap(SparseVector *other)
void RemoveNearZeroEntries(Fractional threshold)
Fractional * coefficient_
EntryIndex num_entries() const
Note this method can only be used when the vector has no duplicates.
void MoveEntryToFirstPosition(Index index)
Fractional GetFirstCoefficient() const
void ApplyPartialIndexPermutation(const IndexPermutation &index_perm)
::util::IntegerRange< EntryIndex > AllEntryIndices() const
void ApplyIndexPermutation(const IndexPermutation &index_perm)
Applies the index permutation to all entries: index = index_perm[index];.
void AddMultipleToSparseVectorAndDeleteCommonIndex(Fractional multiplier, Index removed_common_index, Fractional drop_tolerance, SparseVector *accumulator_vector) const
void ComponentWiseMultiply(const DenseVector &factors)
void PopulateFromSparseVector(const SparseVector &sparse_vector)
Index GetFirstIndex() const
void ClearAndRelease()
Clears the vector and releases the memory it uses.
SparseVector & operator=(const SparseVector &other)
void RemoveNearZeroEntriesWithWeights(Fractional threshold, const DenseVector &weights)
bool IsEmpty() const
Returns true if the vector is empty.
SparseVector(const SparseVector &other)
bool may_contain_duplicates_
void DeleteEntry(Index index)
typename Iterator::Entry Entry
void Clear()
Clears the vector, i.e. removes all entries.
std::string DebugString() const
void MoveEntryToLastPosition(Index index)
void AppendEntriesWithOffset(const SparseVector &sparse_vector, Index offset)
Fractional GetCoefficient(EntryIndex i) const
void ResizeDown(EntryIndex new_size)
Index * index_
Pointers to the first elements of the index and coefficient arrays.
void ComponentWiseDivide(const DenseVector &factors)
void SetCoefficient(Index index, Fractional value)
Defines the coefficient at index, i.e. vector[index] = value;.
Fractional & MutableCoefficient(EntryIndex i)
void AddMultipleToSparseVectorAndIgnoreCommonIndex(Fractional multiplier, Index removed_common_index, Fractional drop_tolerance, SparseVector *accumulator_vector) const
void PopulateFromDenseVector(const DenseVector &dense_vector)
void AddEntry(Index index, Fractional value)
void MoveTaggedEntriesTo(const IndexPermutation &index_perm, SparseVector *output)
void DivideByConstant(Fractional factor)
void Reserve(EntryIndex new_capacity)
Reserve the underlying storage for the given number of entries.
std::unique_ptr< char[]> buffer_
Index & MutableIndex(EntryIndex i)
Index GetLastIndex() const
Like GetFirst*, but for the last entry.
void MultiplyByConstant(Fractional factor)
void PermutedCopyToDenseVector(const IndexPermutation &index_perm, Index num_indices, DenseVector *dense_vector) const
bool CheckNoDuplicates() const
Permutation< Index > IndexPermutation
Fractional GetLastCoefficient() const
void AddMultipleToDenseVector(Fractional multiplier, DenseVector *dense_vector) const
bool IsEqualTo(const SparseVector &other) const
void CopyToDenseVector(Index num_indices, DenseVector *dense_vector) const
Index GetIndex(EntryIndex i) const
Fractional LookUpCoefficient(Index index) const
void AssignToZero(IntType size)
absl::Span< const double > coefficients
IntegerValue GetCoefficient(const IntegerVariable var, const LinearExpression &expr)
In SWIG mode, we don't want anything besides these top-level includes.
#define RETURN_IF_NULL(x)
#define RETURN_VALUE_IF_NULL(x, v)
std::optional< int64_t > end