1 /*-------------------------------------------------------------------------
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-2024, PostgreSQL Global Development Group
13 * src/backend/lib/bipartite_match.c
15 *-------------------------------------------------------------------------
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.
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
;
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
))
60 for (u
= 1; u
<= u_size
; u
++)
62 if (state
->pair_uv
[u
] == 0)
63 if (hk_depth_search(state
, u
))
67 CHECK_FOR_INTERRUPTS(); /* just in case */
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.
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
);
89 * Perform the breadth-first search step of H-K matching.
90 * Returns true if successful.
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 */
102 distance
[0] = HK_INFINITY
;
104 for (u
= 1; u
<= usize
; u
++)
106 if (state
->pair_uv
[u
] == 0)
112 distance
[u
] = HK_INFINITY
;
115 while (qtail
< qhead
)
119 if (distance
[u
] < distance
[0])
121 short *u_adj
= state
->adjacency
[u
];
122 int i
= u_adj
? u_adj
[0] : 0;
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.
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;
157 if (distance
[u
] == HK_INFINITY
)
159 nextdist
= distance
[u
] + 1;
167 if (distance
[pair_vu
[v
]] == nextdist
)
169 if (hk_depth_search(state
, pair_vu
[v
]))
178 distance
[u
] = HK_INFINITY
;