30 #ifndef OR_TOOLS_LP_DATA_SPARSE_VECTOR_H_
31 #define OR_TOOLS_LP_DATA_SPARSE_VECTOR_H_
39 #include "absl/strings/str_format.h"
50 template <
typename IndexType>
51 class SparseVectorEntry;
82 template <
typename IndexType,
83 typename IteratorType = VectorIterator<SparseVectorEntry<IndexType>>>
92 using Entry =
typename Iterator::Entry;
102 #if !defined(_MSC_VER)
107 #if !defined(_MSC_VER)
304 return ::util::IntegerRange<EntryIndex>(EntryIndex(0),
num_entries_);
338 DCHECK_GE(new_size, 0);
395 void AddMultipleToSparseVectorInternal(
411 template <
typename IndexType>
446 template <
typename IndexType,
typename IteratorType>
448 return Iterator(this->index_, this->coefficient_, EntryIndex(0));
451 template <
typename IndexType,
typename IteratorType>
453 return Iterator(this->index_, this->coefficient_, num_entries_);
459 template <
typename IndexType,
typename IteratorType>
464 coefficient_(nullptr),
465 may_contain_duplicates_(false) {}
467 template <
typename IndexType,
typename IteratorType>
469 PopulateFromSparseVector(other);
472 template <
typename IndexType,
typename IteratorType>
475 PopulateFromSparseVector(other);
479 template <
typename IndexType,
typename IteratorType>
481 num_entries_ = EntryIndex(0);
482 may_contain_duplicates_ =
false;
485 template <
typename IndexType,
typename IteratorType>
487 capacity_ = EntryIndex(0);
488 num_entries_ = EntryIndex(0);
490 coefficient_ =
nullptr;
492 may_contain_duplicates_ =
false;
495 template <
typename IndexType,
typename IteratorType>
497 if (new_capacity <= capacity_)
return;
501 if (new_capacity.value() & 3) {
502 new_capacity += EntryIndex(4 - (new_capacity.value() & 3));
505 const size_t index_buffer_size = new_capacity.value() *
sizeof(
Index);
506 const size_t value_buffer_size = new_capacity.value() *
sizeof(
Fractional);
507 const size_t new_buffer_size = index_buffer_size + value_buffer_size;
508 std::unique_ptr<char[]> new_buffer(
new char[new_buffer_size]);
509 IndexType*
const new_index =
reinterpret_cast<Index*
>(new_buffer.get());
511 reinterpret_cast<Fractional*
>(new_index + new_capacity.value());
514 if (num_entries_ > 0) {
519 std::memmove(new_index, index_,
sizeof(IndexType) * num_entries_.value());
520 std::memmove(new_coefficient, coefficient_,
525 coefficient_ = new_coefficient;
526 capacity_ = new_capacity;
529 template <
typename IndexType,
typename IteratorType>
531 return num_entries_ == EntryIndex(0);
534 template <
typename IndexType,
typename IteratorType>
544 template <
typename IndexType,
typename IteratorType>
556 std::vector<std::pair<Index, Fractional>> entries;
557 entries.reserve(num_entries_.value());
558 for (EntryIndex i(0); i < num_entries_; ++i) {
562 entries.begin(), entries.end(),
563 [](
const std::pair<Index, Fractional>&
a,
564 const std::pair<Index, Fractional>&
b) { return a.first < b.first; });
566 EntryIndex new_size(0);
567 for (
int i = 0; i < num_entries_; ++i) {
568 const std::pair<Index, Fractional> entry = entries[i];
569 if (entry.second == 0.0)
continue;
570 if (i + 1 == num_entries_ || entry.first != entries[i + 1].first) {
571 MutableIndex(new_size) = entry.first;
572 MutableCoefficient(new_size) = entry.second;
576 ResizeDown(new_size);
577 may_contain_duplicates_ =
false;
580 template <
typename IndexType,
typename IteratorType>
582 Index previous_index(-1);
583 for (
const EntryIndex i : AllEntryIndices()) {
586 previous_index =
index;
588 may_contain_duplicates_ =
false;
592 template <
typename IndexType,
typename IteratorType>
609 std::memmove(index_, sparse_vector.
index_,
618 template <
typename IndexType,
typename IteratorType>
622 const Index num_indices(dense_vector.
size());
624 if (dense_vector[
index] != 0.0) {
628 may_contain_duplicates_ =
false;
631 template <
typename IndexType,
typename IteratorType>
636 DCHECK_GE(new_index, 0);
639 may_contain_duplicates_ =
true;
642 template <
typename IndexType,
typename IteratorType>
648 if (!may_contain_duplicates_ || num_entries_ <= 1)
return true;
651 const Index max_index =
652 *std::max_element(index_, index_ + num_entries_.value());
653 if (boolean_vector->
size() <= max_index) {
654 boolean_vector->
resize(max_index + 1,
false);
657 may_contain_duplicates_ =
false;
658 for (
const EntryIndex i : AllEntryIndices()) {
660 if ((*boolean_vector)[
index]) {
661 may_contain_duplicates_ =
true;
664 (*boolean_vector)[
index] =
true;
668 for (
const EntryIndex i : AllEntryIndices()) {
669 (*boolean_vector)[GetIndex(i)] =
false;
671 return !may_contain_duplicates_;
674 template <
typename IndexType,
typename IteratorType>
678 if (!may_contain_duplicates_ || num_entries_ <= 1)
return true;
680 return CheckNoDuplicates(&boolean_vector);
685 template <
typename IndexType,
typename IteratorType>
689 may_contain_duplicates_ =
true;
692 template <
typename IndexType,
typename IteratorType>
694 DCHECK(CheckNoDuplicates());
697 while (i <
end && GetIndex(i) !=
index) {
700 if (i ==
end)
return;
701 const int num_moved_entries = (num_entries_ - i).
value() - 1;
702 std::memmove(index_ + i.value(), index_ + i.value() + 1,
703 sizeof(
Index) * num_moved_entries);
704 std::memmove(coefficient_ + i.value(), coefficient_ + i.value() + 1,
709 template <
typename IndexType,
typename IteratorType>
712 DCHECK(CheckNoDuplicates());
713 EntryIndex new_index(0);
714 for (
const EntryIndex i : AllEntryIndices()) {
716 if (magnitude > threshold) {
717 MutableIndex(new_index) = GetIndex(i);
722 ResizeDown(new_index);
725 template <
typename IndexType,
typename IteratorType>
728 DCHECK(CheckNoDuplicates());
729 EntryIndex new_index(0);
730 for (
const EntryIndex i : AllEntryIndices()) {
732 MutableIndex(new_index) = GetIndex(i);
737 ResizeDown(new_index);
740 template <
typename IndexType,
typename IteratorType>
743 DCHECK(CheckNoDuplicates());
744 for (
const EntryIndex i : AllEntryIndices()) {
745 if (GetIndex(i) ==
index) {
746 std::swap(MutableIndex(EntryIndex(0)), MutableIndex(i));
747 std::swap(MutableCoefficient(EntryIndex(0)), MutableCoefficient(i));
753 template <
typename IndexType,
typename IteratorType>
756 DCHECK(CheckNoDuplicates());
758 for (
const EntryIndex i : AllEntryIndices()) {
759 if (GetIndex(i) ==
index) {
760 std::swap(MutableIndex(last_entry), MutableIndex(i));
761 std::swap(MutableCoefficient(last_entry), MutableCoefficient(i));
767 template <
typename IndexType,
typename IteratorType>
770 for (
const EntryIndex i : AllEntryIndices()) {
771 MutableCoefficient(i) *= factor;
775 template <
typename IndexType,
typename IteratorType>
778 for (
const EntryIndex i : AllEntryIndices()) {
779 MutableCoefficient(i) *= factors[GetIndex(i)];
783 template <
typename IndexType,
typename IteratorType>
786 for (
const EntryIndex i : AllEntryIndices()) {
787 MutableCoefficient(i) /= factor;
791 template <
typename IndexType,
typename IteratorType>
794 for (
const EntryIndex i : AllEntryIndices()) {
795 MutableCoefficient(i) /= factors[GetIndex(i)];
799 template <
typename IndexType,
typename IteratorType>
804 for (
const EntryIndex i : AllEntryIndices()) {
809 template <
typename IndexType,
typename IteratorType>
815 for (
const EntryIndex i : AllEntryIndices()) {
820 template <
typename IndexType,
typename IteratorType>
824 if (multiplier == 0.0)
return;
825 for (
const EntryIndex i : AllEntryIndices()) {
830 template <
typename IndexType,
typename IteratorType>
835 AddMultipleToSparseVectorInternal(
true, multiplier, removed_common_index,
836 drop_tolerance, accumulator_vector);
839 template <
typename IndexType,
typename IteratorType>
844 AddMultipleToSparseVectorInternal(
false, multiplier, removed_common_index,
845 drop_tolerance, accumulator_vector);
848 template <
typename IndexType,
typename IteratorType>
853 DCHECK(IsCleanedUp());
855 DCHECK(CheckNoDuplicates());
857 DCHECK_NE(0.0, LookUpCoefficient(common_index));
871 const EntryIndex size_a =
a.num_entries();
872 const EntryIndex size_b =
b.num_entries();
873 const int size_adjustment = delete_common_index ? -2 : 0;
874 const EntryIndex new_size_upper_bound = size_a + size_b + size_adjustment;
875 c.
Reserve(new_size_upper_bound);
877 while ((ia < size_a) && (ib < size_b)) {
878 const Index index_a =
a.GetIndex(ia);
879 const Index index_b =
b.GetIndex(ib);
882 if (index_a == index_b) {
883 if (index_a != common_index) {
884 const Fractional a_coeff_mul = multiplier *
a.GetCoefficient(ia);
890 if (std::abs(sum) > drop_tolerance) {
895 }
else if (!delete_common_index) {
902 }
else if (index_a < index_b) {
914 while (ia < size_a) {
920 while (ib < size_b) {
928 c.
Swap(accumulator_vector);
931 template <
typename IndexType,
typename IteratorType>
934 for (
const EntryIndex i : AllEntryIndices()) {
935 MutableIndex(i) = index_perm[GetIndex(i)];
939 template <
typename IndexType,
typename IteratorType>
942 EntryIndex new_index(0);
943 for (
const EntryIndex i : AllEntryIndices()) {
945 if (index_perm[
index] >= 0) {
946 MutableIndex(new_index) = index_perm[
index];
951 ResizeDown(new_index);
954 template <
typename IndexType,
typename IteratorType>
959 const EntryIndex
end(num_entries_);
962 if (i >=
end)
return;
963 if (index_perm[GetIndex(i)] >= 0)
break;
967 for (EntryIndex j(i + 1); j <
end; ++j) {
968 if (index_perm[GetIndex(j)] < 0) {
969 MutableIndex(i) = GetIndex(j);
984 template <
typename IndexType,
typename IteratorType>
988 for (
const EntryIndex i : AllEntryIndices()) {
989 if (GetIndex(i) ==
index) {
1000 template <
typename IndexType,
typename IteratorType>
1005 for (
const EntryIndex i : AllEntryIndices()) {
1006 if (GetIndex(i) != other.
GetIndex(i))
return false;
1012 template <
typename IndexType,
typename IteratorType>
1015 for (
const EntryIndex i : AllEntryIndices()) {
1016 if (i != 0) s +=
", ";
1017 absl::StrAppendFormat(&s,
"[%d]=%g", GetIndex(i).
value(),
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)
Fractional & MutableCoefficient(EntryIndex i)
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)
::util::IntegerRange< EntryIndex > AllEntryIndices() const
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
bool may_contain_duplicates_
Fractional * coefficient_
std::string DebugString() const
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
void ApplyPartialIndexPermutation(const IndexPermutation &index_perm)
SparseVector & operator=(SparseVector &&other)=default
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
Index & MutableIndex(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)
std::optional< int64_t > end