LCOV - differential code coverage report
Current view: top level - src/backend/lib - bipartite_match.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 97.2 % 72 70 2 70
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 4 4 4
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * bipartite_match.c
       4                 :  *    Hopcroft-Karp maximum cardinality algorithm for bipartite graphs
       5                 :  *
       6                 :  * This implementation is based on pseudocode found at:
       7                 :  *
       8                 :  * https://en.wikipedia.org/w/index.php?title=Hopcroft%E2%80%93Karp_algorithm&oldid=593898016
       9                 :  *
      10                 :  * Copyright (c) 2015-2023, PostgreSQL Global Development Group
      11                 :  *
      12                 :  * IDENTIFICATION
      13                 :  *    src/backend/lib/bipartite_match.c
      14                 :  *
      15                 :  *-------------------------------------------------------------------------
      16                 :  */
      17                 : #include "postgres.h"
      18                 : 
      19                 : #include <limits.h>
      20                 : 
      21                 : #include "lib/bipartite_match.h"
      22                 : #include "miscadmin.h"
      23                 : 
      24                 : /*
      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.
      28                 :  */
      29                 : #define HK_INFINITY  SHRT_MAX
      30                 : 
      31                 : static bool hk_breadth_search(BipartiteMatchState *state);
      32                 : static bool hk_depth_search(BipartiteMatchState *state, int u);
      33                 : 
      34                 : /*
      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.
      37                 :  */
      38                 : BipartiteMatchState *
      39 CBC         340 : BipartiteMatch(int u_size, int v_size, short **adjacency)
      40                 : {
      41             340 :     BipartiteMatchState *state = palloc(sizeof(BipartiteMatchState));
      42                 : 
      43             340 :     if (u_size < 0 || u_size >= SHRT_MAX ||
      44             340 :         v_size < 0 || v_size >= SHRT_MAX)
      45 UBC           0 :         elog(ERROR, "invalid set size for BipartiteMatch");
      46                 : 
      47 CBC         340 :     state->u_size = u_size;
      48             340 :     state->v_size = v_size;
      49             340 :     state->adjacency = adjacency;
      50             340 :     state->matching = 0;
      51             340 :     state->pair_uv = (short *) palloc0((u_size + 1) * sizeof(short));
      52             340 :     state->pair_vu = (short *) palloc0((v_size + 1) * sizeof(short));
      53             340 :     state->distance = (short *) palloc((u_size + 1) * sizeof(short));
      54             340 :     state->queue = (short *) palloc((u_size + 2) * sizeof(short));
      55                 : 
      56             849 :     while (hk_breadth_search(state))
      57                 :     {
      58                 :         int         u;
      59                 : 
      60             706 :         for (u = 1; u <= u_size; u++)
      61                 :         {
      62             537 :             if (state->pair_uv[u] == 0)
      63             537 :                 if (hk_depth_search(state, u))
      64             255 :                     state->matching++;
      65                 :         }
      66                 : 
      67             169 :         CHECK_FOR_INTERRUPTS(); /* just in case */
      68                 :     }
      69                 : 
      70             340 :     return state;
      71                 : }
      72                 : 
      73                 : /*
      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.
      76                 :  */
      77                 : void
      78             340 : BipartiteMatchFree(BipartiteMatchState *state)
      79                 : {
      80                 :     /* adjacency matrix is treated as owned by the caller */
      81             340 :     pfree(state->pair_uv);
      82             340 :     pfree(state->pair_vu);
      83             340 :     pfree(state->distance);
      84             340 :     pfree(state->queue);
      85             340 :     pfree(state);
      86             340 : }
      87                 : 
      88                 : /*
      89                 :  * Perform the breadth-first search step of H-K matching.
      90                 :  * Returns true if successful.
      91                 :  */
      92                 : static bool
      93             509 : hk_breadth_search(BipartiteMatchState *state)
      94                 : {
      95             509 :     int         usize = state->u_size;
      96             509 :     short      *queue = state->queue;
      97             509 :     short      *distance = state->distance;
      98             509 :     int         qhead = 0;      /* we never enqueue any node more than once */
      99             509 :     int         qtail = 0;      /* so don't have to worry about wrapping */
     100                 :     int         u;
     101                 : 
     102             509 :     distance[0] = HK_INFINITY;
     103                 : 
     104            1885 :     for (u = 1; u <= usize; u++)
     105                 :     {
     106            1376 :         if (state->pair_uv[u] == 0)
     107                 :         {
     108            1121 :             distance[u] = 0;
     109            1121 :             queue[qhead++] = u;
     110                 :         }
     111                 :         else
     112             255 :             distance[u] = HK_INFINITY;
     113                 :     }
     114                 : 
     115            1813 :     while (qtail < qhead)
     116                 :     {
     117            1304 :         u = queue[qtail++];
     118                 : 
     119            1304 :         if (distance[u] < distance[0])
     120                 :         {
     121            1135 :             short      *u_adj = state->adjacency[u];
     122            1135 :             int         i = u_adj ? u_adj[0] : 0;
     123                 : 
     124            1688 :             for (; i > 0; i--)
     125                 :             {
     126             553 :                 int         u_next = state->pair_vu[u_adj[i]];
     127                 : 
     128             553 :                 if (distance[u_next] == HK_INFINITY)
     129                 :                 {
     130             183 :                     distance[u_next] = 1 + distance[u];
     131             183 :                     Assert(qhead < usize + 2);
     132             183 :                     queue[qhead++] = u_next;
     133                 :                 }
     134                 :             }
     135                 :         }
     136                 :     }
     137                 : 
     138             509 :     return (distance[0] != HK_INFINITY);
     139                 : }
     140                 : 
     141                 : /*
     142                 :  * Perform the depth-first search step of H-K matching.
     143                 :  * Returns true if successful.
     144                 :  */
     145                 : static bool
     146             792 : hk_depth_search(BipartiteMatchState *state, int u)
     147                 : {
     148             792 :     short      *distance = state->distance;
     149             792 :     short      *pair_uv = state->pair_uv;
     150             792 :     short      *pair_vu = state->pair_vu;
     151             792 :     short      *u_adj = state->adjacency[u];
     152             792 :     int         i = u_adj ? u_adj[0] : 0;
     153                 :     short       nextdist;
     154                 : 
     155             792 :     if (u == 0)
     156             255 :         return true;
     157             537 :     if (distance[u] == HK_INFINITY)
     158 UBC           0 :         return false;
     159 CBC         537 :     nextdist = distance[u] + 1;
     160                 : 
     161             537 :     check_stack_depth();
     162                 : 
     163             655 :     for (; i > 0; i--)
     164                 :     {
     165             373 :         int         v = u_adj[i];
     166                 : 
     167             373 :         if (distance[pair_vu[v]] == nextdist)
     168                 :         {
     169             255 :             if (hk_depth_search(state, pair_vu[v]))
     170                 :             {
     171             255 :                 pair_vu[v] = u;
     172             255 :                 pair_uv[u] = v;
     173             255 :                 return true;
     174                 :             }
     175                 :         }
     176                 :     }
     177                 : 
     178             282 :     distance[u] = HK_INFINITY;
     179             282 :     return false;
     180                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a