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 16@8cea358b128 vs 17@8cea358b128 Lines: 97.2 % 72 70 2 70
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 4 4 4
Baseline: 16@8cea358b128 Branches: 77.1 % 48 37 11 37
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (240..) days: 97.2 % 72 70 2 70
Function coverage date bins:
(240..) days: 100.0 % 4 4 4
Branch coverage date bins:
(240..) days: 77.1 % 48 37 11 37

 Age         Owner                    Branch data    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-2024, 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 *
 3256 andres@anarazel.de         39                 :CBC         340 : BipartiteMatch(int u_size, int v_size, short **adjacency)
                                 40                 :                : {
                                 41                 :            340 :     BipartiteMatchState *state = palloc(sizeof(BipartiteMatchState));
                                 42                 :                : 
 3157 tgl@sss.pgh.pa.us          43   [ +  -  +  -  :            340 :     if (u_size < 0 || u_size >= SHRT_MAX ||
                                              +  - ]
                                 44         [ -  + ]:            340 :         v_size < 0 || v_size >= SHRT_MAX)
 3157 tgl@sss.pgh.pa.us          45         [ #  # ]:UBC           0 :         elog(ERROR, "invalid set size for BipartiteMatch");
                                 46                 :                : 
 3256 andres@anarazel.de         47                 :CBC         340 :     state->u_size = u_size;
                                 48                 :            340 :     state->v_size = v_size;
                                 49                 :            340 :     state->adjacency = adjacency;
 3157 tgl@sss.pgh.pa.us          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                 :                : 
 3256 andres@anarazel.de         56         [ +  + ]:            849 :     while (hk_breadth_search(state))
                                 57                 :                :     {
                                 58                 :                :         int         u;
                                 59                 :                : 
 3157 tgl@sss.pgh.pa.us          60         [ +  + ]:            706 :         for (u = 1; u <= u_size; u++)
                                 61                 :                :         {
 3256 andres@anarazel.de         62         [ +  - ]:            537 :             if (state->pair_uv[u] == 0)
 3157 tgl@sss.pgh.pa.us          63         [ +  + ]:            537 :                 if (hk_depth_search(state, u))
 3256 andres@anarazel.de         64                 :            255 :                     state->matching++;
                                 65                 :                :         }
                                 66                 :                : 
 3249 bruce@momjian.us           67         [ -  + ]:            169 :         CHECK_FOR_INTERRUPTS(); /* just in case */
                                 68                 :                :     }
                                 69                 :                : 
 3256 andres@anarazel.de         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;
 3157 tgl@sss.pgh.pa.us          97                 :            509 :     short      *distance = state->distance;
 3256 andres@anarazel.de         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                 :                : 
 3157 tgl@sss.pgh.pa.us         102                 :            509 :     distance[0] = HK_INFINITY;
                                103                 :                : 
                                104         [ +  + ]:           1885 :     for (u = 1; u <= usize; u++)
                                105                 :                :     {
 3256 andres@anarazel.de        106         [ +  + ]:           1376 :         if (state->pair_uv[u] == 0)
                                107                 :                :         {
                                108                 :           1121 :             distance[u] = 0;
                                109                 :           1121 :             queue[qhead++] = u;
                                110                 :                :         }
                                111                 :                :         else
 3157 tgl@sss.pgh.pa.us         112                 :            255 :             distance[u] = HK_INFINITY;
                                113                 :                :     }
                                114                 :                : 
 3256 andres@anarazel.de        115         [ +  + ]:           1813 :     while (qtail < qhead)
                                116                 :                :     {
                                117                 :           1304 :         u = queue[qtail++];
                                118                 :                : 
                                119         [ +  + ]:           1304 :         if (distance[u] < distance[0])
                                120                 :                :         {
 3249 bruce@momjian.us          121                 :           1135 :             short      *u_adj = state->adjacency[u];
                                122         [ +  + ]:           1135 :             int         i = u_adj ? u_adj[0] : 0;
                                123                 :                : 
 3157 tgl@sss.pgh.pa.us         124         [ +  + ]:           1688 :             for (; i > 0; i--)
                                125                 :                :             {
 3249 bruce@momjian.us          126                 :            553 :                 int         u_next = state->pair_vu[u_adj[i]];
                                127                 :                : 
 3157 tgl@sss.pgh.pa.us         128         [ +  + ]:            553 :                 if (distance[u_next] == HK_INFINITY)
                                129                 :                :                 {
 3256 andres@anarazel.de        130                 :            183 :                     distance[u_next] = 1 + distance[u];
 3157 tgl@sss.pgh.pa.us         131         [ -  + ]:            183 :                     Assert(qhead < usize + 2);
 3256 andres@anarazel.de        132                 :            183 :                     queue[qhead++] = u_next;
                                133                 :                :                 }
                                134                 :                :             }
                                135                 :                :         }
                                136                 :                :     }
                                137                 :                : 
 3157 tgl@sss.pgh.pa.us         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;
 3256 andres@anarazel.de        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;
 3157 tgl@sss.pgh.pa.us         157         [ -  + ]:            537 :     if (distance[u] == HK_INFINITY)
 3157 tgl@sss.pgh.pa.us         158                 :UBC           0 :         return false;
 3157 tgl@sss.pgh.pa.us         159                 :CBC         537 :     nextdist = distance[u] + 1;
                                160                 :                : 
                                161                 :            537 :     check_stack_depth();
                                162                 :                : 
                                163         [ +  + ]:            655 :     for (; i > 0; i--)
                                164                 :                :     {
 3249 bruce@momjian.us          165                 :            373 :         int         v = u_adj[i];
                                166                 :                : 
 3157 tgl@sss.pgh.pa.us         167         [ +  + ]:            373 :         if (distance[pair_vu[v]] == nextdist)
                                168                 :                :         {
                                169         [ +  - ]:            255 :             if (hk_depth_search(state, pair_vu[v]))
                                170                 :                :             {
 3256 andres@anarazel.de        171                 :            255 :                 pair_vu[v] = u;
                                172                 :            255 :                 pair_uv[u] = v;
                                173                 :            255 :                 return true;
                                174                 :                :             }
                                175                 :                :         }
                                176                 :                :     }
                                177                 :                : 
 3157 tgl@sss.pgh.pa.us         178                 :            282 :     distance[u] = HK_INFINITY;
 3256 andres@anarazel.de        179                 :            282 :     return false;
                                180                 :                : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622