*
* bipartite_match.cpp
* Hopcroft-Karp maximum cardinality algorithm for bipartite graphs
*
* This implementation is based on pseudocode found at:
*
* https://en.wikipedia.org/w/index.php?title=Hopcroft%E2%80%93Karp_algorithm&oldid=593898016
*
* Copyright (c) 2015, PostgreSQL Global Development Group
*
* IDENTIFICATION
* src/common/backend/lib/bipartite_match.cpp
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include <limits.h>
#include "lib/bipartite_match.h"
#include "miscadmin.h"
* The distances computed in hk_breadth_search can easily be seen to never
* exceed u_size. Since we restrict u_size to be less than SHRT_MAX, we
* can therefore use SHRT_MAX as the "infinity" distance needed as a marker.
*/
#define HK_INFINITY SHRT_MAX
static bool hk_breadth_search(BipartiteMatchState* state);
static bool hk_depth_search(BipartiteMatchState* state, int u);
* Given the size of U and V, where each is indexed 1..size, and an adjacency
* list, perform the matching and return the resulting state.
*/
BipartiteMatchState* BipartiteMatch(int u_size, int v_size, short** adjacency)
{
BipartiteMatchState* state = (BipartiteMatchState*)palloc(sizeof(BipartiteMatchState));
if (u_size < 0 || u_size >= SHRT_MAX || v_size < 0 || v_size >= SHRT_MAX) {
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid set size for BipartiteMatch")));
}
state->u_size = u_size;
state->v_size = v_size;
state->adjacency = adjacency;
state->matching = 0;
state->pair_uv = (short*)palloc0((u_size + 1) * sizeof(short));
state->pair_vu = (short*)palloc0((v_size + 1) * sizeof(short));
state->distance = (short*)palloc((u_size + 1) * sizeof(short));
state->queue = (short*)palloc((u_size + 2) * sizeof(short));
while (hk_breadth_search(state) == true) {
int u;
for (u = 1; u <= u_size; u++) {
if (state->pair_uv[u] == 0) {
if (hk_depth_search(state, u)) {
state->matching++;
}
}
}
CHECK_FOR_INTERRUPTS();
}
return state;
}
* Free a state returned by BipartiteMatch, except for the original adjacency
* list, which is owned by the caller. This only frees memory, so it's optional.
*/
void BipartiteMatchFree(BipartiteMatchState* state)
{
pfree_ext(state->pair_uv);
pfree_ext(state->pair_vu);
pfree_ext(state->distance);
pfree_ext(state->queue);
pfree_ext(state);
}
* Perform the breadth-first search step of H-K matching.
* Returns true if successful.
*/
static bool hk_breadth_search(BipartiteMatchState* state)
{
int usize = state->u_size;
short* queue = state->queue;
short* distance = state->distance;
int qhead = 0;
int qtail = 0;
int u;
distance[0] = HK_INFINITY;
for (u = 1; u <= usize; u++) {
if (state->pair_uv[u] == 0) {
distance[u] = 0;
queue[qhead++] = u;
} else {
distance[u] = HK_INFINITY;
}
}
while (qtail < qhead) {
u = queue[qtail++];
if (distance[u] < distance[0]) {
short* u_adj = state->adjacency[u];
int i = u_adj ? u_adj[0] : 0;
for (; i > 0; i--) {
int u_next = state->pair_vu[u_adj[i]];
if (distance[u_next] == HK_INFINITY) {
distance[u_next] = 1 + distance[u];
Assert(qhead < usize + 2);
queue[qhead++] = u_next;
}
}
}
}
return (distance[0] != HK_INFINITY);
}
* Perform the depth-first search step of H-K matching.
* Returns true if successful.
*/
static bool hk_depth_search(BipartiteMatchState* state, int u)
{
short* distance = state->distance;
short* pair_uv = state->pair_uv;
short* pair_vu = state->pair_vu;
short* u_adj = state->adjacency[u];
int i = u_adj ? u_adj[0] : 0;
short nextdist;
if (u == 0) {
return true;
}
if (distance[u] == HK_INFINITY) {
return false;
}
nextdist = distance[u] + 1;
check_stack_depth();
for (; i > 0; i--) {
int v = u_adj[i];
if (distance[pair_vu[v]] == nextdist) {
if (hk_depth_search(state, pair_vu[v])) {
pair_vu[v] = u;
pair_uv[u] = v;
return true;
}
}
}
distance[u] = HK_INFINITY;
return false;
}