/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* */ /* This file is part of the HiGHS linear optimization suite */ /* */ /* Written and engineered 2008-2022 at the University of Edinburgh */ /* */ /* Available as open-source under the MIT License */ /* */ /* Authors: Julian Hall, Ivet Galabova, Leona Gottwald and Michael */ /* Feldmeier */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "mip/HighsDynamicRowMatrix.h" #include #include #include #include HighsDynamicRowMatrix::HighsDynamicRowMatrix(HighsInt ncols) { AheadPos_.resize(ncols, -1); AheadNeg_.resize(ncols, -1); Asize_.resize(ncols); } /// adds a row to the matrix with the given values and returns its index HighsInt HighsDynamicRowMatrix::addRow(HighsInt* Rindex, double* Rvalue, HighsInt Rlen, bool linkCols) { HighsInt rowindex; HighsInt start; HighsInt end; // insert the row in an existing empty space or append the values to the end // if no space that is large enough exists std::set>::iterator it; if (freespaces_.empty() || (it = freespaces_.lower_bound(std::make_pair( Rlen, HighsInt{-1}))) == freespaces_.end()) { start = ARindex_.size(); end = start + Rlen; ARindex_.resize(end); ARvalue_.resize(end); ARrowindex_.resize(end); AprevPos_.resize(end, -1); AnextPos_.resize(end, -1); AprevNeg_.resize(end, -1); AnextNeg_.resize(end, -1); } else { std::pair freeslot = *it; freespaces_.erase(it); start = freeslot.second; end = start + Rlen; // if the space was not completely occupied, we register the remainder of // it again in the priority queue if (freeslot.first > Rlen) { freespaces_.emplace(freeslot.first - Rlen, end); } } // register the range of values for this row with a reused or a new index if (deletedrows_.empty()) { rowindex = ARrange_.size(); ARrange_.emplace_back(start, end); colsLinked.push_back(linkCols); } else { rowindex = deletedrows_.back(); deletedrows_.pop_back(); ARrange_[rowindex].first = start; ARrange_[rowindex].second = end; colsLinked[rowindex] = linkCols; } // now add the nonzeros in the order sorted by the index value for (HighsInt i = start; i != end; ++i) { ARindex_[i] = Rindex[i - start]; ARvalue_[i] = Rvalue[i - start]; ARrowindex_[i] = rowindex; } // link the row values to the columns if (!linkCols) return rowindex; for (HighsInt i = start; i != end; ++i) { HighsInt col = ARindex_[i]; ++Asize_[col]; if (ARvalue_[i] > 0) { AprevPos_[i] = -1; HighsInt head = AheadPos_[col]; AheadPos_[col] = i; AnextPos_[i] = head; if (head != -1) AprevPos_[head] = i; } else { AprevNeg_[i] = -1; HighsInt head = AheadNeg_[col]; AheadNeg_[col] = i; AnextNeg_[i] = head; if (head != -1) AprevNeg_[head] = i; } } return rowindex; } void HighsDynamicRowMatrix::unlinkColumns(HighsInt rowindex) { if (!colsLinked[rowindex]) return; colsLinked[rowindex] = false; HighsInt start = ARrange_[rowindex].first; HighsInt end = ARrange_[rowindex].second; for (HighsInt i = start; i != end; ++i) { HighsInt col = ARindex_[i]; --Asize_[col]; if (ARvalue_[i] > 0) { HighsInt prev = AprevPos_[i]; HighsInt next = AnextPos_[i]; if (next != -1) { assert(AprevPos_[next] == i); AprevPos_[next] = prev; } if (prev != -1) { assert(AnextPos_[prev] == i); AnextPos_[prev] = next; } else { assert(AheadPos_[col] == i); AheadPos_[col] = next; } } else { HighsInt prev = AprevNeg_[i]; HighsInt next = AnextNeg_[i]; if (next != -1) { assert(AprevNeg_[next] == i); AprevNeg_[next] = prev; } if (prev != -1) { assert(AnextNeg_[prev] == i); AnextNeg_[prev] = next; } else { assert(AheadNeg_[col] == i); AheadNeg_[col] = next; } } } } /// removes the row with the given index from the matrix, afterwards the index /// can be reused for new rows void HighsDynamicRowMatrix::removeRow(HighsInt rowindex) { HighsInt start = ARrange_[rowindex].first; HighsInt end = ARrange_[rowindex].second; if (colsLinked[rowindex]) { for (HighsInt i = start; i != end; ++i) { HighsInt col = ARindex_[i]; --Asize_[col]; if (ARvalue_[i] > 0) { HighsInt prev = AprevPos_[i]; HighsInt next = AnextPos_[i]; if (next != -1) { assert(AprevPos_[next] == i); AprevPos_[next] = prev; } if (prev != -1) { assert(AnextPos_[prev] == i); AnextPos_[prev] = next; } else { assert(AheadPos_[col] == i); AheadPos_[col] = next; } } else { HighsInt prev = AprevNeg_[i]; HighsInt next = AnextNeg_[i]; if (next != -1) { assert(AprevNeg_[next] == i); AprevNeg_[next] = prev; } if (prev != -1) { assert(AnextNeg_[prev] == i); AnextNeg_[prev] = next; } else { assert(AheadNeg_[col] == i); AheadNeg_[col] = next; } } } } // register the space of the deleted row and the index so that it can be // reused deletedrows_.push_back(rowindex); freespaces_.emplace(end - start, start); // set the range to -1,-1 to indicate a deleted row ARrange_[rowindex].first = -1; ARrange_[rowindex].second = -1; }