31 #include <unordered_map> 39 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
44 this->i_.push_back(v1);
45 this->j_.push_back(v2);
47 this->max_i_ = std::max(this->max_i_.value_or(BaseVertexID{}), this->i_.back());
48 this->max_j_ = std::max(this->max_j_.value_or(BaseVertexID{}), this->j_.back());
51 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
56 const Neighbours& rows,
57 const Neighbours& cols)
59 if (cols.size() != rows.size()) {
60 throw std::invalid_argument {
61 "Coordinate format column index table size does not match " 62 "row index table size" 66 this->i_.insert(this->i_.end(), rows .begin(), rows .end());
67 this->j_.insert(this->j_.end(), cols .begin(), cols .end());
69 this->max_i_ = std::max(this->max_i_.value_or(BaseVertexID{}), maxRowIdx);
70 this->max_j_ = std::max(this->max_j_.value_or(BaseVertexID{}), maxColIdx);
73 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
85 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
90 return this->i_.empty();
93 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
98 return this->i_.size() == this->j_.size();
101 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
102 std::optional<typename Opm::utility::CSRGraphFromCoordinates<VertexID, TrackCompressedIdx, PermitSelfConnections>::BaseVertexID>
109 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
110 std::optional<typename Opm::utility::CSRGraphFromCoordinates<VertexID, TrackCompressedIdx, PermitSelfConnections>::BaseVertexID>
117 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
122 return this->i_.size();
125 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
133 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
141 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
149 auto it = vertex_merges.find(v);
150 if (it != vertex_merges.end()) {
158 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
159 std::unordered_map<VertexID, VertexID>
165 VertexID max_original_vertex_id = std::max(max_i_.value_or(BaseVertexID{}), max_j_.value_or(BaseVertexID{}));
170 std::ranges::transform(i_, i_.begin(),
171 [
this, &vertex_merges](VertexID v) {
return findMergedVertexID(v, vertex_merges); });
173 std::ranges::transform(j_, j_.begin(),
174 [
this, &vertex_merges](VertexID v) {
return findMergedVertexID(v, vertex_merges); });
177 if constexpr (!PermitSelfConnections) {
178 auto write_pos = 0*i_.size();
179 for (
auto read_pos = 0*i_.size(); read_pos < i_.size(); ++read_pos) {
180 if (i_[read_pos] != j_[read_pos]) {
181 if (write_pos != read_pos) {
182 i_[write_pos] = i_[read_pos];
183 j_[write_pos] = j_[read_pos];
188 i_.resize(write_pos);
189 j_.resize(write_pos);
193 std::set<VertexID> sorted_unique_vertices;
194 sorted_unique_vertices.insert(i_.begin(), i_.end());
195 sorted_unique_vertices.insert(j_.begin(), j_.end());
198 std::unordered_map<VertexID, VertexID> vertex_map;
199 vertex_map.reserve(sorted_unique_vertices.size());
201 for (
auto& v : sorted_unique_vertices) {
202 vertex_map.emplace(v, new_id++);
206 this->max_i_ = this->max_j_ = new_id - 1;
209 auto remap = [&vertex_map](
auto v) {
211 return vertex_map.at(v);
214 std::ranges::transform(i_, i_.begin(), remap);
215 std::ranges::transform(j_, j_.begin(), remap);
218 std::unordered_map<VertexID, VertexID> final_mapping;
219 final_mapping.reserve(max_original_vertex_id + 1);
221 for (VertexID vertex = 0; vertex <= max_original_vertex_id; ++vertex) {
222 auto merged_id = findMergedVertexID(vertex, vertex_merges);
223 final_mapping.emplace(vertex, vertex_map.at(merged_id));
225 return final_mapping;
234 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
238 const Offset maxNumVertices,
239 const bool expandExistingIdxMap)
241 const auto maxRow = conns.maxRow();
243 if (maxRow.has_value() &&
244 (
static_cast<Offset
>(*maxRow) >= maxNumVertices))
246 throw std::invalid_argument {
247 "Number of vertices in input graph (" +
248 std::to_string(*maxRow) +
") " 249 "exceeds maximum graph size implied by explicit size of " 250 "adjacency matrix (" + std::to_string(maxNumVertices) +
')' 254 this->assemble(conns.rowIndices(), conns.columnIndices(),
255 maxRow.value_or(BaseVertexID{0}),
256 conns.maxCol().value_or(BaseVertexID{0}),
257 expandExistingIdxMap);
259 this->compress(maxNumVertices);
262 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
267 return this->startPointers().empty()
268 ? 0 : this->startPointers().size() - 1;
271 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
272 typename Opm::utility::CSRGraphFromCoordinates<VertexID, TrackCompressedIdx, PermitSelfConnections>::BaseVertexID
276 return this->numRows_ - 1;
279 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
280 typename Opm::utility::CSRGraphFromCoordinates<VertexID, TrackCompressedIdx, PermitSelfConnections>::BaseVertexID
284 return this->numCols_ - 1;
287 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
295 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
303 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
308 auto rowIdx = Neighbours{};
310 if (this->ia_.empty()) {
314 rowIdx.reserve(this->ia_.back());
316 auto row = BaseVertexID{};
318 const auto m = this->ia_.size() - 1;
319 for (
auto i = 0*m; i < m; ++i, ++row) {
320 const auto n = this->ia_[i + 1] - this->ia_[i + 0];
322 rowIdx.insert(rowIdx.end(), n, row);
328 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
336 if constexpr (TrackCompressedIdx) {
337 this->compressedIdx_.clear();
344 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
348 const Neighbours& cols,
349 const BaseVertexID maxRowIdx,
350 const BaseVertexID maxColIdx,
351 [[maybe_unused]]
const bool expandExistingIdxMap)
353 [[maybe_unused]]
auto compressedIdx = this->compressedIdx_;
354 [[maybe_unused]]
const auto numOrigNNZ = this->ja_.size();
356 auto i = this->coordinateFormatRowIndices();
357 i.insert(i.end(), rows.begin(), rows.end());
360 j.insert(j.end(), cols.begin(), cols.end());
363 const auto thisNumRows = std::max(this->numRows_, maxRowIdx + 1);
364 const auto thisNumCols = std::max(this->numCols_, maxColIdx + 1);
366 this->preparePushbackRowGrouping(thisNumRows, i);
368 this->groupAndTrackColumnIndicesByRow(i, j);
370 if constexpr (TrackCompressedIdx) {
371 if (expandExistingIdxMap) {
372 this->remapCompressedIndex(std::move(compressedIdx), numOrigNNZ);
376 this->numRows_ = thisNumRows;
377 this->numCols_ = thisNumCols;
380 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
385 if (this->numRows() > maxNumVertices) {
386 throw std::invalid_argument {
387 "Number of vertices in input graph (" +
388 std::to_string(this->numRows()) +
") " 389 "exceeds maximum graph size implied by explicit size of " 390 "adjacency matrix (" + std::to_string(maxNumVertices) +
')' 394 this->sortColumnIndicesPerRow();
397 this->condenseDuplicates();
399 const auto nRows = this->startPointers().size() - 1;
400 if (nRows < maxNumVertices) {
401 this->ia_.insert(this->ia_.end(),
402 maxNumVertices - nRows,
403 this->startPointers().back());
407 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
421 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
428 const auto colIdx = this->ja_;
429 auto end = colIdx.begin();
433 [[maybe_unused]]
auto compressedIdx = this->compressedIdx_;
434 if constexpr (TrackCompressedIdx) {
435 this->compressedIdx_.clear();
438 const auto numRows = this->ia_.size() - 1;
439 for (
auto row = 0*numRows; row < numRows; ++row) {
442 std::advance(end, this->ia_[row + 1] - this->ia_[row + 0]);
444 const auto q = this->ja_.size();
446 this->condenseAndTrackUniqueColumnsForSingleRow(begin, end);
448 this->ia_[row + 0] = q;
451 if constexpr (TrackCompressedIdx) {
452 this->remapCompressedIndex(std::move(compressedIdx));
456 this->ia_.back() = this->ja_.size();
459 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
463 const Neighbours& rowIdx)
465 assert (numRows >= 0);
467 this->ia_.assign(numRows + 1, 0);
471 for (
const auto& row : rowIdx) {
472 this->ia_[row + 1] += 1;
486 for (
typename Start::size_type i = 1, n = numRows; i <= n; ++i) {
487 this->ia_[0] += this->ia_[i];
488 this->ia_[i] = this->ia_[0] - this->ia_[i];
491 assert (this->ia_[0] == rowIdx.size());
494 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
498 const Neighbours& colIdx)
500 assert (this->ia_[0] == rowIdx.size());
502 const auto nnz = rowIdx.size();
504 this->ja_.resize(nnz);
506 if constexpr (TrackCompressedIdx) {
507 this->compressedIdx_.
clear();
508 this->compressedIdx_.reserve(nnz);
528 for (
auto nz = 0*nnz; nz < nnz; ++nz) {
529 const auto k = this->ia_[rowIdx[nz] + 1] ++;
531 this->ja_[k] = colIdx[nz];
533 if constexpr (TrackCompressedIdx) {
534 this->compressedIdx_.push_back(k);
541 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
546 [[maybe_unused]]
auto compressedIdx = this->compressedIdx_;
549 const auto rowIdx = this->coordinateFormatRowIndices();
550 const auto colIdx = this->ja_;
552 this->preparePushbackRowGrouping(this->numCols_, colIdx);
556 this->groupAndTrackColumnIndicesByRow(colIdx, rowIdx);
559 if constexpr (TrackCompressedIdx) {
560 this->remapCompressedIndex(std::move(compressedIdx));
563 std::swap(this->numRows_, this->numCols_);
566 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
570 typename Neighbours::const_iterator end)
580 while (begin != end) {
583 if constexpr (TrackCompressedIdx) {
584 this->compressedIdx_.push_back(this->ja_.size());
587 this->ja_.push_back(*begin);
590 std::find_if(begin, end, [last = this->ja_.back()]
591 (
const auto j) {
return j != last; });
593 if constexpr (TrackCompressedIdx) {
595 const auto ndup = std::distance(begin, next_unique);
601 this->compressedIdx_.insert(this->compressedIdx_.end(),
603 this->compressedIdx_.back());
611 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
615 [[maybe_unused]] std::optional<typename Start::size_type> numOrig)
617 if constexpr (TrackCompressedIdx) {
618 std::ranges::transform(compressedIdx, compressedIdx.begin(),
619 [
this](
const auto& i)
620 {
return this->compressedIdx_[i]; });
622 if (numOrig.has_value() && (*numOrig < this->compressedIdx_.size())) {
626 .insert(compressedIdx.end(),
627 this->compressedIdx_.begin() + *numOrig,
628 this->compressedIdx_.end());
631 this->compressedIdx_.swap(compressedIdx);
641 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
644 this->uncompressed_.clear();
648 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
653 if ((v1 < 0) || (v2 < 0)) {
654 throw std::invalid_argument {
655 "Vertex IDs must be non-negative. Got (v1,v2) = (" 656 + std::to_string(v1) +
", " + std::to_string(v2)
661 if constexpr (! PermitSelfConnections) {
668 this->uncompressed_.add(v1, v2);
671 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
676 if (vertices.empty()) {
680 for (
const auto& v : vertices) {
681 if (parent_.find(v) == parent_.end()) {
682 parent_.emplace(v, v);
687 if (vertices.size() > 1) {
688 for (std::size_t i = 1; i < vertices.size(); ++i) {
689 unionSets(vertices[0], vertices[i]);
694 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
700 auto it = parent_.find(v);
701 if (it == parent_.end()) {
702 parent_.emplace(v, v);
707 if (it->second != v) {
708 it->second = find(it->second);
713 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
719 VertexID rootA = find(a);
720 VertexID rootB = find(b);
723 if (rootA == rootB) {
730 parent_.at(rootB) = rootA;
732 parent_.at(rootA) = rootB;
736 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
742 if (parent_.empty()) {
743 return this->uncompressed_.maxRow().value_or(0) + 1;
747 std::unordered_map<VertexID, VertexID> vertex_merges;
748 for (
auto& [vertex, parent] : parent_) {
750 VertexID root = find(vertex);
753 if (vertex != root) {
754 vertex_merges.emplace(vertex, root);
758 if (!vertex_merges.empty()) {
759 vertex_mapping_ = this->uncompressed_.applyVertexMerges(vertex_merges);
762 return this->uncompressed_.maxRow().value_or(0) + 1;
765 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
771 if (!parent_.empty() && vertex_mapping_.empty()) {
775 if (! this->uncompressed_.isValid()) {
776 throw std::logic_error {
777 "Cannot compress invalid connection list" 781 this->csr_.merge(this->uncompressed_, maxNumVertices, expandExistingIdxMap);
783 this->uncompressed_.clear();
786 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
791 if (vertex_mapping_.empty()) {
795 return vertex_mapping_.at(v);
799 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
803 return this->csr_.numRows();
806 template <
typename VertexID,
bool TrackCompressedIdx,
bool PermitSelfConnections>
810 const auto& ia = this->startPointers();
812 return ia.empty() ? 0 : ia.back();
Offset numEdges() const
Retrieve number of edges (non-zero matrix elements) in input graph.
Definition: CSRGraphFromCoordinates_impl.hpp:808
VertexID getFinalVertexID(VertexID originalVertexID) const
Get the final vertex ID after all merges and renumbering for a given original vertex ID...
Definition: CSRGraphFromCoordinates_impl.hpp:789
std::vector< BaseVertexID > Neighbours
Representation of neighbouring regions.
Definition: CSRGraphFromCoordinates.hpp:65
Offset numVertices() const
Retrieve number of rows (source entities) in input graph.
Definition: CSRGraphFromCoordinates_impl.hpp:801
typename Neighbours::size_type Offset
Offset into neighbour array.
Definition: CSRGraphFromCoordinates.hpp:68
Offset applyVertexMerges()
Apply vertex merges to all vertex groups.
Definition: CSRGraphFromCoordinates_impl.hpp:739
void addVertexGroup(const std::vector< VertexID > &vertices)
Add a group of vertices that should be merged together.
Definition: CSRGraphFromCoordinates_impl.hpp:674
void addConnection(VertexID v1, VertexID v2)
Add flow rate connection between regions.
Definition: CSRGraphFromCoordinates_impl.hpp:651
void compress(Offset maxNumVertices, bool expandExistingIdxMap=false)
Form CSR adjacency matrix representation of input graph from connections established in previous call...
Definition: CSRGraphFromCoordinates_impl.hpp:768
Form CSR adjacency matrix representation of unstructured graphs.
Definition: CSRGraphFromCoordinates.hpp:55
void clear()
Clear all internal buffers, but preserve allocated capacity.
Definition: CSRGraphFromCoordinates_impl.hpp:642
std::vector< Offset > Start
CSR start pointers.
Definition: CSRGraphFromCoordinates.hpp:71