@@ -302,7 +302,7 @@ void SparsityPattern::finalize()
302302 auto it = std::ranges::lower_bound (src0, owner);
303303 assert (it != src0.end () and *it == owner);
304304 return static_cast <int >(
305- std::distance (src0.begin (), it));
305+ std::ranges:: distance (src0.begin (), it));
306306 });
307307
308308 // Compute size of data to send to each process
@@ -428,33 +428,54 @@ void SparsityPattern::finalize()
428428 // Reserve the exact pre-dedup edge count
429429 _edges.reserve (cache_cols.size () + recv_cols_bucketed.size ());
430430
431- // Sort and remove duplicates per row, building CSR offsets as we
432- // go. Offsets are int64_t to avoid overflow.
431+ // De-duplicate each row's raw (unsorted, repeats included) column
432+ // list with a generation-stamped marker: last_seen[col] == i means
433+ // col has already been recorded for row i. Rows are visited exactly
434+ // once in increasing order, so the row index itself is the stamp --
435+ // no reset between rows needed. This turns per-row de-duplication
436+ // from O(m log m) (sort the raw, repeat-laden list) into
437+ // O(m + k log k), where k <= m is the de-duplicated count: sorting
438+ // only ever runs over the much smaller de-duplicated list.
439+ const std::int32_t num_cols0
440+ = local_size1 + static_cast <std::int32_t >(_col_ghosts.size ());
441+ std::vector<std::int32_t > last_seen (num_cols0, -1 );
442+
443+ // Build CSR offsets as we go. Offsets are int64_t to avoid overflow.
433444 _off_diagonal_offsets.resize (num_rows0);
434445 _offsets.reserve (num_rows0 + 1 );
435446 _offsets.push_back (0 );
436447 std::vector<std::int32_t > row;
437448 for (std::int32_t i = 0 ; i < num_rows0; ++i)
438449 {
439450 row.clear ();
440- row.insert (row.end (), cache_cols.begin () + cache_offsets[i],
441- cache_cols.begin () + cache_offsets[i + 1 ]);
451+ for (std::int64_t k = cache_offsets[i]; k < cache_offsets[i + 1 ]; ++k)
452+ {
453+ if (std::int32_t c = cache_cols[k]; last_seen[c] != i)
454+ {
455+ last_seen[c] = i;
456+ row.push_back (c);
457+ }
458+ }
442459 if (i < local_size0)
443460 {
444- row.insert (row.end (), recv_cols_bucketed.begin () + recv_offsets[i],
445- recv_cols_bucketed.begin () + recv_offsets[i + 1 ]);
461+ for (std::int64_t k = recv_offsets[i]; k < recv_offsets[i + 1 ]; ++k)
462+ {
463+ if (std::int32_t c = recv_cols_bucketed[k]; last_seen[c] != i)
464+ {
465+ last_seen[c] = i;
466+ row.push_back (c);
467+ }
468+ }
446469 }
447470
448471 std::ranges::sort (row);
449- auto it_end = std::ranges::unique (row).begin ();
450472
451473 // Find position of first "off-diagonal" column
452- _off_diagonal_offsets[i] = std::distance (
453- row.begin (),
454- std::ranges::lower_bound (row.begin (), it_end, local_size1));
474+ _off_diagonal_offsets[i] = std::ranges::distance (
475+ row.begin (), std::ranges::lower_bound (row, local_size1));
455476
456- _edges.insert (_edges.end (), row.begin (), it_end );
457- _offsets.push_back (_offsets.back () + std::distance ( row.begin (), it_end ));
477+ _edges.insert (_edges.end (), row.begin (), row. end () );
478+ _offsets.push_back (_offsets.back () + row.size ( ));
458479 }
459480
460481 _edges.shrink_to_fit ();
0 commit comments