LCOV - code coverage report
Current view: top level - src/test - LG_check_sssp.c (source / functions) Hit Total Coverage
Test: LAGraph code coverage report. Commit id: cc56ed4. Current time (UTC): 2024-08-30T17:14:30Z Lines: 135 135 100.0 %
Date: 2024-08-30 17:16:41 Functions: 1 1 100.0 %

          Line data    Source code
       1             : //------------------------------------------------------------------------------
       2             : // LAGraph/src/test/LG_check_sssp: stand-alone test for SSSP
       3             : //------------------------------------------------------------------------------
       4             : 
       5             : // LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved.
       6             : // SPDX-License-Identifier: BSD-2-Clause
       7             : //
       8             : // For additional details (including references to third party source code and
       9             : // other files) see the LICENSE file or contact permission@sei.cmu.edu. See
      10             : // Contributors.txt for a full list of contributors. Created, in part, with
      11             : // funding and support from the U.S. Government (see Acknowledgments.txt file).
      12             : // DM22-0790
      13             : 
      14             : // Contributed by Timothy A. Davis, Texas A&M University
      15             : 
      16             : //------------------------------------------------------------------------------
      17             : 
      18             : #include "LG_internal.h"
      19             : #include "LG_test.h"
      20             : 
      21             : // All computations are done in double precision
      22             : 
      23             : typedef double LG_key_t ;
      24             : typedef struct
      25             : {
      26             :     int64_t name ;
      27             :     LG_key_t key ;
      28             : }
      29             : LG_Element ;
      30             : #include "LG_heap.h"
      31             : 
      32             : #undef  LG_FREE_WORK
      33             : #define LG_FREE_WORK                                    \
      34             : {                                                       \
      35             :     LAGraph_Free ((void **) &Heap, NULL) ;              \
      36             :     LAGraph_Free ((void **) &Iheap, NULL) ;             \
      37             :     LAGraph_Free ((void **) &distance, NULL) ;          \
      38             :     LAGraph_Free ((void **) &parent, NULL) ;            \
      39             :     LAGraph_Free ((void **) &path_length_in, NULL) ;    \
      40             :     LAGraph_Free ((void **) &reachable, NULL) ;         \
      41             :     LAGraph_Free ((void **) &reachable_in, NULL) ;      \
      42             :     LAGraph_Free ((void **) &neighbor_weights, NULL) ;  \
      43             :     LAGraph_Free ((void **) &neighbors, NULL) ;         \
      44             :     GrB_free (&Row) ;                                   \
      45             : }
      46             : 
      47             : #undef  LG_FREE_ALL
      48             : #define LG_FREE_ALL                                     \
      49             : {                                                       \
      50             :     LG_FREE_WORK ;                                      \
      51             :     LAGraph_Free ((void **) &Ap, NULL) ;                \
      52             :     LAGraph_Free ((void **) &Aj, NULL) ;                \
      53             :     LAGraph_Free ((void **) &Ax, NULL) ;                \
      54             : }
      55             : 
      56             : //------------------------------------------------------------------------------
      57             : // test the results from SSSP
      58             : //------------------------------------------------------------------------------
      59             : 
      60             : // Because this method does on GxB_unpack on G->A, it should not be used in a
      61             : // brutal memory test, unless the caller is prepared to reconstruct G->A
      62             : // when the brutal test causes this method to return early.
      63             : 
      64         483 : int LG_check_sssp
      65             : (
      66             :     // input
      67             :     GrB_Vector Path_Length,     // Path_Length(i) is the length of the
      68             :                                 // shortest path from src to node i.
      69             :     LAGraph_Graph G,            // all edge weights must be > 0
      70             :     GrB_Index src,
      71             :     char *msg
      72             : )
      73             : {
      74             : 
      75             :     //--------------------------------------------------------------------------
      76             :     // check inputs
      77             :     //--------------------------------------------------------------------------
      78             : 
      79         483 :     GrB_Vector Row = NULL ;
      80         483 :     GrB_Index *Ap = NULL, *Aj = NULL, *neighbors = NULL ;
      81             :     GrB_Index Ap_size, Aj_size, Ax_size, n, ncols ;
      82         483 :     int64_t *queue = NULL, *Iheap = NULL, *parent = NULL ;
      83         483 :     LG_Element *Heap = NULL ;
      84             : 
      85         483 :     double *path_length_in = NULL, *distance = NULL, *neighbor_weights = NULL ;
      86         483 :     void *Ax = NULL ;
      87         483 :     bool *reachable = NULL, *reachable_in = NULL ;
      88             : 
      89         483 :     double tt = LAGraph_WallClockTime ( ) ;
      90         483 :     LG_TRY (LAGraph_CheckGraph (G, msg)) ;
      91         483 :     GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ;
      92         483 :     GRB_TRY (GrB_Matrix_ncols (&ncols, G->A)) ;
      93             :     GrB_Type etype ;
      94             :     char atype_name [LAGRAPH_MAX_NAME_LEN] ;
      95         483 :     LG_TRY (LAGraph_Matrix_TypeName (atype_name, G->A, msg)) ;
      96         483 :     LG_TRY (LAGraph_TypeFromName (&etype, atype_name, msg)) ;
      97         483 :     int etypecode = 0 ;
      98         483 :     size_t etypesize = 0 ;
      99         483 :     double etypeinf = INFINITY ;
     100             : 
     101         483 :     if (etype == GrB_INT32)
     102             :     {
     103         257 :         etypecode = 0 ;
     104         257 :         etypesize = sizeof (int32_t) ;
     105         257 :         etypeinf  = (double) INT32_MAX ;
     106             :     }
     107         226 :     else if (etype == GrB_INT64)
     108             :     {
     109          48 :         etypecode = 1 ;
     110          48 :         etypesize = sizeof (int64_t) ;
     111          48 :         etypeinf  = (double) INT64_MAX ;
     112             :     }
     113         178 :     else if (etype == GrB_UINT32)
     114             :     {
     115          12 :         etypecode = 2 ;
     116          12 :         etypesize = sizeof (uint32_t) ;
     117          12 :         etypeinf  = (double) UINT32_MAX ;
     118             :     }
     119         166 :     else if (etype == GrB_UINT64)
     120             :     {
     121          12 :         etypecode = 3 ;
     122          12 :         etypesize = sizeof (uint64_t) ;
     123          12 :         etypeinf  = (double) UINT64_MAX ;
     124             :     }
     125         154 :     else if (etype == GrB_FP32)
     126             :     {
     127           9 :         etypecode = 4 ;
     128           9 :         etypesize = sizeof (float) ;
     129           9 :         etypeinf  = INFINITY ;
     130             :     }
     131         145 :     else if (etype == GrB_FP64)
     132             :     {
     133         145 :         etypecode = 5 ;
     134         145 :         etypesize = sizeof (double) ;
     135         145 :         etypeinf  = INFINITY ;
     136             :     }
     137             : 
     138         483 :     LG_ASSERT_MSG (etypesize > 0, GrB_NOT_IMPLEMENTED, "type not supported") ;
     139             : 
     140         483 :     bool print_timings = (n >= 2000) ;
     141             : 
     142             :     //--------------------------------------------------------------------------
     143             :     // get the contents of the Path_Length vector
     144             :     //--------------------------------------------------------------------------
     145             : 
     146         483 :     LG_TRY (LAGraph_Malloc ((void **) &path_length_in, n, sizeof (double),
     147             :         msg)) ;
     148         483 :     LG_TRY (LAGraph_Malloc ((void **) &reachable_in, n, sizeof (double), msg)) ;
     149       62662 :     for (int64_t i = 0 ; i < n ; i++)
     150             :     {
     151             :         double t ;
     152       62179 :         path_length_in [i] = INFINITY ;
     153       62179 :         int info = GrB_Vector_extractElement_FP64 (&t, Path_Length, i) ;
     154       62179 :         if (info == GrB_SUCCESS)
     155             :         {
     156       62179 :             path_length_in [i] = t ;
     157             :         }
     158       62179 :         reachable_in [i] = (path_length_in [i] < etypeinf) ;
     159             :     }
     160             : 
     161             :     //--------------------------------------------------------------------------
     162             :     // unpack the matrix in CSR form for SuiteSparse:GraphBLAS
     163             :     //--------------------------------------------------------------------------
     164             : 
     165         483 :     bool iso = false ;
     166             :     #if LAGRAPH_SUITESPARSE
     167             :     bool jumbled ;
     168         483 :     GRB_TRY (GxB_Matrix_unpack_CSR (G->A,
     169             :         &Ap, &Aj, (void **) &Ax, &Ap_size, &Aj_size, &Ax_size, &iso, &jumbled,
     170             :         NULL)) ;
     171             :     #endif
     172             : 
     173             :     //--------------------------------------------------------------------------
     174             :     // compute the SSSP of the graph, via Dijskstra's algorithm
     175             :     //--------------------------------------------------------------------------
     176             : 
     177         483 :     if (print_timings)
     178             :     {
     179          20 :         tt = LAGraph_WallClockTime ( ) - tt ;
     180          20 :         printf ("LG_check_sssp init  time: %g sec\n", tt) ;
     181          20 :         tt = LAGraph_WallClockTime ( ) ;
     182             :     }
     183             : 
     184             :     // initializations
     185         483 :     LG_TRY (LAGraph_Malloc ((void **) &distance, n, sizeof (double), msg)) ;
     186         483 :     LG_TRY (LAGraph_Malloc ((void **) &reachable, n, sizeof (bool), msg)) ;
     187       62662 :     for (int64_t i = 0 ; i < n ; i++)
     188             :     {
     189       62179 :         distance [i] = INFINITY ;
     190       62179 :         reachable [i] = false ;
     191             :     }
     192         483 :     distance [src] = 0 ;
     193         483 :     reachable [src] = true ;
     194             : 
     195             :     #if !LAGRAPH_SUITESPARSE
     196             :     GRB_TRY (GrB_Vector_new (&Row, GrB_FP64, n)) ;
     197             :     LG_TRY (LAGraph_Malloc ((void **) &neighbors, n, sizeof (GrB_Index), msg)) ;
     198             :     LG_TRY (LAGraph_Malloc ((void **) &neighbor_weights, n, sizeof (double), msg)) ;
     199             :     LG_ASSERT (neighbors != NULL, GrB_OUT_OF_MEMORY) ;
     200             :     LG_ASSERT (neighbor_weights != NULL, GrB_OUT_OF_MEMORY) ;
     201             :     #endif
     202             : 
     203             :     // place all nodes in the heap (already in heap order)
     204         483 :     LG_TRY (LAGraph_Malloc ((void **) &Heap, (n+1), sizeof (LG_Element), msg)) ;
     205         483 :     LG_TRY (LAGraph_Malloc ((void **) &Iheap, n, sizeof (int64_t), msg)) ;
     206         483 :     LG_ASSERT (Heap != NULL && Iheap != NULL, GrB_OUT_OF_MEMORY) ;
     207         483 :     Heap [1].key = 0 ;
     208         483 :     Heap [1].name = src ;
     209         483 :     Iheap [src] = 1 ;
     210         483 :     int64_t p = 2 ;
     211       62662 :     for (int64_t i = 0 ; i < n ; i++)
     212             :     {
     213       62179 :         if (i != src)
     214             :         {
     215       61696 :             Heap [p].key = INFINITY ;
     216       61696 :             Heap [p].name = i ;
     217       61696 :             Iheap [i] = p ;
     218       61696 :             p++ ;
     219             :         }
     220             :     }
     221         483 :     int64_t nheap = n ;
     222         483 :     LG_ASSERT_MSG (LG_heap_check (Heap, Iheap, n, nheap) == 0, -2000,
     223             :         "invalid heap") ;
     224             : 
     225       44388 :     while (nheap > 0)
     226             :     {
     227             :         // extract the min element u from the top of the heap
     228       44092 :         LG_Element e = Heap [1] ;
     229       44092 :         int64_t u = e.name ;
     230             : 
     231       44092 :         double u_distance = e.key ;
     232             :         ASSERT (distance [u] == u_distance) ;
     233       44092 :         LG_heap_delete (1, Heap, Iheap, n, &nheap) ;
     234             :         ASSERT (Iheap [u] == 0) ;
     235       44092 :         reachable [u] = (u_distance < etypeinf) ;
     236             : 
     237       44092 :         if (n < 200)
     238             :         {
     239        4946 :             LG_ASSERT_MSG (LG_heap_check (Heap, Iheap, n, nheap) == 0, -2000,
     240             :                 "invalid heap") ;
     241             :         }
     242             : 
     243       44092 :         if (u_distance == INFINITY)
     244             :         {
     245             :             // node u is not reachable, so no other nodes in the queue
     246             :             // are reachable either.  All work is done.
     247         187 :             break ;
     248             :         }
     249             : 
     250             :         #if LAGRAPH_SUITESPARSE
     251             :         // directly access the indices of entries in A(u,:)
     252       43905 :         GrB_Index degree = Ap [u+1] - Ap [u] ;
     253       43905 :         GrB_Index *node_u_adjacency_list = Aj + Ap [u] ;
     254       43905 :         void *weights = ((char *) Ax) + ((iso ? 0 : Ap [u]) * etypesize) ;
     255             :         #else
     256             :         // extract the indices of entries in A(u,:)
     257             :         GrB_Index degree = n ;
     258             :         GRB_TRY (GrB_Col_extract (Row, NULL, NULL, G->A, GrB_ALL, n, u,
     259             :             GrB_DESC_T0)) ;
     260             :         GRB_TRY (GrB_Vector_extractTuples_FP64 (neighbors, neighbor_weights,
     261             :             &degree, Row)) ;
     262             :         GrB_Index *node_u_adjacency_list = neighbors ;
     263             :         double *weights = neighbor_weights ;
     264             :         #endif
     265             : 
     266             :         // traverse all entries in A(u,:)
     267      614795 :         for (int64_t k = 0 ; k < degree ; k++)
     268             :         {
     269             :             // consider edge (u,v) and its weight w
     270      570890 :             int64_t v = node_u_adjacency_list [k] ;
     271      570890 :             if (Iheap [v] == 0) continue ;  // node v already in SSSP tree
     272             :             double w ;
     273             :             #if LAGRAPH_SUITESPARSE
     274      269114 :             switch (etypecode)
     275             :             {
     276      134179 :                 default:
     277      134179 :                 case 0: w = (( int32_t *) weights) [iso ? 0 : k] ; break ;
     278         312 :                 case 1: w = (( int64_t *) weights) [iso ? 0 : k] ; break ;
     279          51 :                 case 2: w = ((uint32_t *) weights) [iso ? 0 : k] ; break ;
     280          51 :                 case 3: w = ((uint64_t *) weights) [iso ? 0 : k] ; break ;
     281          90 :                 case 4: w = (( float   *) weights) [iso ? 0 : k] ; break ;
     282      134431 :                 case 5: w = (( double  *) weights) [iso ? 0 : k] ; break ;
     283             :             }
     284             :             #else
     285             :             w = weights [iso ? 0 : k] ;
     286             :             #endif
     287             : 
     288      269114 :             LG_ASSERT_MSG (w > 0, -2002, "invalid graph (weights must be > 0)");
     289      269114 :             double new_distance = u_distance + w ;
     290      269114 :             if (distance [v] > new_distance)
     291             :             {
     292             :                 // reduce the key of node v
     293       60199 :                 distance [v] = new_distance ;
     294             :                 // parent [v] = u ;
     295       60199 :                 int64_t p = Iheap [v] ;
     296       60199 :                 LG_ASSERT_MSG (Heap [p].name == v, -2000, "invalid heap") ;
     297       60199 :                 LG_heap_decrease_key (p, new_distance, Heap, Iheap, n, nheap) ;
     298             :             }
     299             :         }
     300             : 
     301       43905 :         if (n < 200)
     302             :         {
     303        4771 :             LG_ASSERT_MSG (LG_heap_check (Heap, Iheap, n, nheap) == 0, -2000,
     304             :                 "invalid heap") ;
     305             :         }
     306             :     }
     307             : 
     308         483 :     if (print_timings)
     309             :     {
     310          20 :         tt = LAGraph_WallClockTime ( ) - tt ;
     311          20 :         printf ("LG_check_sssp time: %g sec\n", tt) ;
     312          20 :         tt = LAGraph_WallClockTime ( ) ;
     313             :     }
     314             : 
     315             :     //--------------------------------------------------------------------------
     316             :     // repack the matrix in CSR form for SuiteSparse:GraphBLAS
     317             :     //--------------------------------------------------------------------------
     318             : 
     319             :     #if LAGRAPH_SUITESPARSE
     320         483 :     GRB_TRY (GxB_Matrix_pack_CSR (G->A,
     321             :         &Ap, &Aj, (void **) &Ax, Ap_size, Aj_size, Ax_size, iso, jumbled,
     322             :         NULL)) ;
     323             :     #endif
     324             : 
     325             :     //--------------------------------------------------------------------------
     326             :     // check the distance of each node
     327             :     //--------------------------------------------------------------------------
     328             : 
     329       62662 :     for (int64_t i = 0 ; i < n ; i++)
     330             :     {
     331       62179 :         bool ok = true ;
     332       62179 :         double err = 0 ;
     333       62179 :         if (isinf (distance [i]))
     334             :         {
     335       18274 :             ok = (path_length_in [i] == etypeinf || isinf (path_length_in [i]));
     336             :         }
     337             :         else
     338             :         {
     339       43905 :             err = fabs (path_length_in [i] - distance [i]) ;
     340       43905 :             double d = LAGRAPH_MAX (path_length_in [i], distance [i]) ;
     341       43905 :             if (err > 0) err = err / d ;
     342       43905 :             ok = (err < 1e-5) ;
     343             :         }
     344       62179 :         LG_ASSERT_MSG (ok, -2001, "invalid path length") ;
     345             :     }
     346             : 
     347             :     //--------------------------------------------------------------------------
     348             :     // check the reach
     349             :     //--------------------------------------------------------------------------
     350             : 
     351       62662 :     for (int64_t i = 0 ; i < n ; i++)
     352             :     {
     353       62179 :         bool ok = (reachable [i] == reachable_in [i]) ;
     354             :         #if 0
     355             :         printf ("reach [%ld]: %d %d\n", i, reachable [i], reachable_in [i]) ;
     356             :         if (!ok)
     357             :         {
     358             :             printf ("Hey! source %ld\n", src) ;
     359             :             GxB_print (G->A, 3) ;
     360             :             GxB_print (Path_Length, 3) ;
     361             :             for (int64_t i = 0 ; i < n ; i++)
     362             :             {
     363             :                 printf ("check [%ld]: reach %d %d distance %g\n", i,
     364             :                     reachable [i], reachable_in [i], distance [i]) ;
     365             :             }
     366             : 
     367             :         }
     368             :         #endif
     369       62179 :         LG_ASSERT_MSG (ok, -2001, "invalid reach") ;
     370             :     }
     371             : 
     372             :     //--------------------------------------------------------------------------
     373             :     // free workspace and return result
     374             :     //--------------------------------------------------------------------------
     375             : 
     376         483 :     LG_FREE_WORK ;
     377             : 
     378         483 :     if (print_timings)
     379             :     {
     380          20 :         tt = LAGraph_WallClockTime ( ) - tt ;
     381          20 :         printf ("LG_check_sssp check time: %g sec\n", tt) ;
     382             :     }
     383         483 :     return (GrB_SUCCESS) ;
     384             : }

Generated by: LCOV version 1.14