Harmonize more parameter names in bulk.
[pgsql.git] / src / backend / lib / bipartite_match.c
blob8e1637f1e9f806371c078f17ffaefc9fcf055b40
1 /*-------------------------------------------------------------------------
3 * bipartite_match.c
4 * Hopcroft-Karp maximum cardinality algorithm for bipartite graphs
6 * This implementation is based on pseudocode found at:
8 * https://en.wikipedia.org/w/index.php?title=Hopcroft%E2%80%93Karp_algorithm&oldid=593898016
10 * Copyright (c) 2015-2022, PostgreSQL Global Development Group
12 * IDENTIFICATION
13 * src/backend/lib/bipartite_match.c
15 *-------------------------------------------------------------------------
17 #include "postgres.h"
19 #include <limits.h>
21 #include "lib/bipartite_match.h"
22 #include "miscadmin.h"
25 * The distances computed in hk_breadth_search can easily be seen to never
26 * exceed u_size. Since we restrict u_size to be less than SHRT_MAX, we
27 * can therefore use SHRT_MAX as the "infinity" distance needed as a marker.
29 #define HK_INFINITY SHRT_MAX
31 static bool hk_breadth_search(BipartiteMatchState *state);
32 static bool hk_depth_search(BipartiteMatchState *state, int u);
35 * Given the size of U and V, where each is indexed 1..size, and an adjacency
36 * list, perform the matching and return the resulting state.
38 BipartiteMatchState *
39 BipartiteMatch(int u_size, int v_size, short **adjacency)
41 BipartiteMatchState *state = palloc(sizeof(BipartiteMatchState));
43 if (u_size < 0 || u_size >= SHRT_MAX ||
44 v_size < 0 || v_size >= SHRT_MAX)
45 elog(ERROR, "invalid set size for BipartiteMatch");
47 state->u_size = u_size;
48 state->v_size = v_size;
49 state->adjacency = adjacency;
50 state->matching = 0;
51 state->pair_uv = (short *) palloc0((u_size + 1) * sizeof(short));
52 state->pair_vu = (short *) palloc0((v_size + 1) * sizeof(short));
53 state->distance = (short *) palloc((u_size + 1) * sizeof(short));
54 state->queue = (short *) palloc((u_size + 2) * sizeof(short));
56 while (hk_breadth_search(state))
58 int u;
60 for (u = 1; u <= u_size; u++)
62 if (state->pair_uv[u] == 0)
63 if (hk_depth_search(state, u))
64 state->matching++;
67 CHECK_FOR_INTERRUPTS(); /* just in case */
70 return state;
74 * Free a state returned by BipartiteMatch, except for the original adjacency
75 * list, which is owned by the caller. This only frees memory, so it's optional.
77 void
78 BipartiteMatchFree(BipartiteMatchState *state)
80 /* adjacency matrix is treated as owned by the caller */
81 pfree(state->pair_uv);
82 pfree(state->pair_vu);
83 pfree(state->distance);
84 pfree(state->queue);
85 pfree(state);
89 * Perform the breadth-first search step of H-K matching.
90 * Returns true if successful.
92 static bool
93 hk_breadth_search(BipartiteMatchState *state)
95 int usize = state->u_size;
96 short *queue = state->queue;
97 short *distance = state->distance;
98 int qhead = 0; /* we never enqueue any node more than once */
99 int qtail = 0; /* so don't have to worry about wrapping */
100 int u;
102 distance[0] = HK_INFINITY;
104 for (u = 1; u <= usize; u++)
106 if (state->pair_uv[u] == 0)
108 distance[u] = 0;
109 queue[qhead++] = u;
111 else
112 distance[u] = HK_INFINITY;
115 while (qtail < qhead)
117 u = queue[qtail++];
119 if (distance[u] < distance[0])
121 short *u_adj = state->adjacency[u];
122 int i = u_adj ? u_adj[0] : 0;
124 for (; i > 0; i--)
126 int u_next = state->pair_vu[u_adj[i]];
128 if (distance[u_next] == HK_INFINITY)
130 distance[u_next] = 1 + distance[u];
131 Assert(qhead < usize + 2);
132 queue[qhead++] = u_next;
138 return (distance[0] != HK_INFINITY);
142 * Perform the depth-first search step of H-K matching.
143 * Returns true if successful.
145 static bool
146 hk_depth_search(BipartiteMatchState *state, int u)
148 short *distance = state->distance;
149 short *pair_uv = state->pair_uv;
150 short *pair_vu = state->pair_vu;
151 short *u_adj = state->adjacency[u];
152 int i = u_adj ? u_adj[0] : 0;
153 short nextdist;
155 if (u == 0)
156 return true;
157 if (distance[u] == HK_INFINITY)
158 return false;
159 nextdist = distance[u] + 1;
161 check_stack_depth();
163 for (; i > 0; i--)
165 int v = u_adj[i];
167 if (distance[pair_vu[v]] == nextdist)
169 if (hk_depth_search(state, pair_vu[v]))
171 pair_vu[v] = u;
172 pair_uv[u] = v;
173 return true;
178 distance[u] = HK_INFINITY;
179 return false;