Skip to content

Week-1 pgr_maximumWeightedMatching #552

Open
mayurgalhate wants to merge 6 commits into
pgRouting:mainfrom
mayurgalhate:week1-matching
Open

Week-1 pgr_maximumWeightedMatching #552
mayurgalhate wants to merge 6 commits into
pgRouting:mainfrom
mayurgalhate:week1-matching

Conversation

@mayurgalhate
Copy link
Copy Markdown
Contributor

@mayurgalhate mayurgalhate commented May 26, 2026

Summary by CodeRabbit

  • New Features
    • Added a maximum weighted matching feature for undirected graphs (no parallel edges). New SQL-facing function accepts an edges query and returns rows: seq, start_vid, end_vid, agg_cost. Marked experimental and exposes computed optimal pairings with aggregate costs.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b170bfbf-23e7-4aa4-b4ff-c765b05cd8ad

📥 Commits

Reviewing files that changed from the base of the PR and between 3bf436b and 0df3b75.

📒 Files selected for processing (5)
  • include/drivers/max_flow/maximum_weighted_matching_driver.h
  • include/max_flow/maximumWeightedMatching.hpp
  • src/max_flow/maximumWeightedMatching.c
  • src/max_flow/maximumWeightedMatching_process.cpp
  • src/max_flow/maximumWeighted_matching_driver.cpp
💤 Files with no reviewable changes (2)
  • include/drivers/max_flow/maximum_weighted_matching_driver.h
  • include/max_flow/maximumWeightedMatching.hpp
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/max_flow/maximumWeighted_matching_driver.cpp
  • src/max_flow/maximumWeightedMatching_process.cpp
  • src/max_flow/maximumWeightedMatching.c

Walkthrough

Adds maximum weighted matching: a C SRF bridge and public SQL wrapper, a Boost-based C++ matching implementation, a C driver and headers to expose results to Postgres, and wiring to call the C driver from the SRF.

Changes

Maximum Weighted Matching

Layer / File(s) Summary
SQL internal and public wrappers
sql/max_flow/_maximumWeightedMatching.sql, sql/max_flow/maximumWeightedMatching.sql
Adds _pgr_maximumWeightedMatching(TEXT) C-backed SRF declaration and the public pgr_maximumWeightedMatching(TEXT) SQL wrapper that normalizes input and returns seq, start_vid, end_vid, agg_cost.
C SRF bridge
src/max_flow/maximumWeightedMatching.c
Implements the SRF: SPI lifecycle, calls the driver pgr_do_maximum_weighted_matching, collects result tuples, reports logs/notices/errors, and yields rows to SQL callers.
C++ matching algorithm
src/max_flow/maximumWeightedMatching_process.cpp
Implements maximumWeightedMatching_process using Boost’s maximum_weighted_matching on an undirected weighted graph and returns matched vertex ids as a flat vector.
Driver and headers
include/drivers/max_flow/maximum_weighted_matching_driver.h, include/max_flow/maximumWeightedMatching.hpp, src/max_flow/maximumWeighted_matching_driver.cpp
Adds the C driver entrypoint pgr_do_maximum_weighted_matching, driver wiring that currently constructs edges vector (TODO: fetch from SQL), pallocs result array, and public C++/driver headers declarations.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • cvvergara
  • robe2
  • sanak

Poem

🐰 I chased edges down the graphy night,
Weighing each hop by moonlit light,
Pairs found their dance, a tidy set,
C, C++, and SQL met—what a duet!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Week-1 pgr_maximumWeightedMatching' is partially related to the changeset, referring to a component being added, but lacks clarity about what is being done and uses a vague sprint/week identifier. Improve the title to be more descriptive of the actual change, such as 'Add pgr_maximumWeightedMatching function' or 'Implement maximum weighted matching algorithm', removing the sprint reference.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@sql/matching/_maximumWeightedMatching.sql`:
- Around line 1-2: Add the project's standard license/copyright header at the
top of the new SQL file _maximumWeightedMatching.sql to satisfy repository
license checks; open _maximumWeightedMatching.sql and prepend the exact
multi-line header block used elsewhere in the repo (copy from another SQL file)
including year and copyright holder, then commit so CI recognizes the header.

In `@sql/matching/maximumWeightedMatching.sql`:
- Around line 1-2: Add the project's standard license/header to the top of
maximumWeightedMatching.sql: insert the required copyright line, license
identifier (e.g., SPDX or full license text) and any contributor or year
metadata used by other SQL files in the repo so the file passes the mandatory
header checks; place this header above the existing "--v4.1" line and match the
exact formatting used in other SQL files to satisfy the automated check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0979b4db-49e9-4e0f-a941-7ccbf4a90900

📥 Commits

Reviewing files that changed from the base of the PR and between be1200a and e51279c.

📒 Files selected for processing (2)
  • sql/matching/_maximumWeightedMatching.sql
  • sql/matching/maximumWeightedMatching.sql

Comment thread sql/max_flow/_maximumWeightedMatching.sql
Comment thread sql/max_flow/maximumWeightedMatching.sql
@mayurgalhate mayurgalhate changed the title Week1- pgr_maximumWeightedMatching Week-1 pgr_maximumWeightedMatching May 26, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/max_flow/maximumWeighted_matching_driver.cpp`:
- Around line 54-63: The driver currently constructs an empty
std::vector<Basic_edge> edges and never reads the SQL input (edges_sql), so
maximumWeightedMatching_process(edges) always runs on an empty graph; fix by
executing/parsing the SQL result identified by edges_sql, iterate over each
returned row, convert each row into a Basic_edge (populate the edge fields used
by Basic_edge such as source/target/weight or the names used in your struct),
push_back into the edges vector, handle SQL errors and type conversions, then
call maximumWeightedMatching_process(edges) as before so the returned matching
reflects the queried data.
- Line 31: The include directive uses the wrong header name; replace the old
include "drivers/max_flow/maximumWeighted_matching_driver.h" with the correct
new header filename "drivers/max_flow/maximum_weighted_matching_driver.h" in the
file that contains the include (referenced symbol: the `#include` line in
maximumWeighted_matching_driver.cpp) so case-sensitive builds can find
maximum_weighted_matching_driver.h.

In `@src/max_flow/maximumWeightedMatching_process.cpp`:
- Around line 56-75: The code is using raw SQL vertex IDs as graph indices which
can create huge sparse graphs and misinterpret mate results; before creating the
Boost graph, collect all unique IDs from edges (edge.source and edge.target),
build a contiguous index mapping (e.g., unordered_map<OriginalId, size_t>
id_to_idx and vector<size_t> idx_to_id), then allocate vertices using
boost::add_vertex(graph) for each mapped index and add edges using
boost::add_edge(id_to_idx[edge.source], id_to_idx[edge.target], edge.cost,
graph); after running the matching, translate mate/index descriptors back to
original IDs via idx_to_id when returning mates.

In `@src/max_flow/maximumWeightedMatching.c`:
- Line 50: Remove the redundant leading blank lines that cpplint flags at the
start of blocks in this file: delete the empty lines that precede block starts
inside the maximumWeightedMatching function and its helper functions (e.g., any
blank line before an if/for/while/return block or before helper function blocks
such as augmenting path helpers), so each block opens immediately without an
extra blank line; run cpplint locally to confirm the whitespace/blank_line
warnings are resolved.
- Line 39: The include at the top of maximumWeightedMatching.c is referencing
the old header name "maximumWeighted_matching_driver.h"; update the `#include` to
use the new header filename "maximum_weighted_matching_driver.h" so the
preprocessor pulls the correct header (look for the existing include statement
in maximumWeightedMatching.c and replace the old header name with
maximum_weighted_matching_driver.h).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f1c61e47-9c74-4522-bb7e-5300ca86bc32

📥 Commits

Reviewing files that changed from the base of the PR and between 8c3046f and 3bf436b.

📒 Files selected for processing (5)
  • include/drivers/max_flow/maximum_weighted_matching_driver.h
  • include/max_flow/maximumWeightedMatching.hpp
  • src/max_flow/maximumWeightedMatching.c
  • src/max_flow/maximumWeightedMatching_process.cpp
  • src/max_flow/maximumWeighted_matching_driver.cpp
✅ Files skipped from review due to trivial changes (1)
  • include/max_flow/maximumWeightedMatching.hpp

Comment thread src/max_flow/maximumWeighted_matching_driver.cpp Outdated
Comment on lines +54 to +63
std::vector<Basic_edge> edges;

/*
* TODO:
* Fetch edges from SQL query
*/

std::vector<int64_t> result =
maximumWeightedMatching_process(edges);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Driver currently ignores SQL input and always returns an empty matching.

edges_sql is never parsed/fetched, so edges stays empty and the function returns success with no rows. This breaks the feature contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/max_flow/maximumWeighted_matching_driver.cpp` around lines 54 - 63, The
driver currently constructs an empty std::vector<Basic_edge> edges and never
reads the SQL input (edges_sql), so maximumWeightedMatching_process(edges)
always runs on an empty graph; fix by executing/parsing the SQL result
identified by edges_sql, iterate over each returned row, convert each row into a
Basic_edge (populate the edge fields used by Basic_edge such as
source/target/weight or the names used in your struct), push_back into the edges
vector, handle SQL errors and type conversions, then call
maximumWeightedMatching_process(edges) as before so the returned matching
reflects the queried data.

Comment on lines +56 to +75
size_t max_vertex = 0;

for (const auto &edge : edges) {
max_vertex = std::max(
max_vertex,
static_cast<size_t>(
std::max(edge.source, edge.target)));
}

for (size_t i = 0; i <= max_vertex; ++i) {
boost::add_vertex(graph);
}

for (const auto &edge : edges) {

boost::add_edge(
edge.source,
edge.target,
edge.cost,
graph);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Map vertex IDs to contiguous indices before building the vecS graph.

This code treats SQL vertex IDs as direct graph indices. With sparse/large IDs, Line 65 can allocate an enormous graph, and returned mates are index descriptors rather than guaranteed original IDs.

Suggested direction
+// Build bijection: original vid <-> contiguous index [0..n)
+std::unordered_map<int64_t, size_t> vid_to_idx;
+std::vector<int64_t> idx_to_vid;
+auto ensure_idx = [&](int64_t vid) -> size_t {
+    auto it = vid_to_idx.find(vid);
+    if (it != vid_to_idx.end()) return it->second;
+    size_t idx = idx_to_vid.size();
+    vid_to_idx.emplace(vid, idx);
+    idx_to_vid.push_back(vid);
+    boost::add_vertex(graph);
+    return idx;
+};
+
+for (const auto &edge : edges) {
+    auto u = ensure_idx(edge.source);
+    auto v = ensure_idx(edge.target);
+    boost::add_edge(u, v, edge.cost, graph);
+}
...
-            result.push_back(static_cast<int64_t>(i));
-            result.push_back(static_cast<int64_t>(mate[i]));
+            result.push_back(idx_to_vid[i]);
+            result.push_back(idx_to_vid[mate[i]]);

Also applies to: 88-99

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/max_flow/maximumWeightedMatching_process.cpp` around lines 56 - 75, The
code is using raw SQL vertex IDs as graph indices which can create huge sparse
graphs and misinterpret mate results; before creating the Boost graph, collect
all unique IDs from edges (edge.source and edge.target), build a contiguous
index mapping (e.g., unordered_map<OriginalId, size_t> id_to_idx and
vector<size_t> idx_to_id), then allocate vertices using boost::add_vertex(graph)
for each mapped index and add edges using
boost::add_edge(id_to_idx[edge.source], id_to_idx[edge.target], edge.cost,
graph); after running the matching, translate mate/index descriptors back to
original IDs via idx_to_id when returning mates.

Comment thread src/max_flow/maximumWeightedMatching.c Outdated
Comment thread src/max_flow/maximumWeightedMatching.c Outdated
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 28, 2026

Actionable comments posted: 0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant