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

          Line data    Source code
       1             : //------------------------------------------------------------------------------
       2             : // BF_pure_c.c: Bellman-Ford method, not using GraphBLAS
       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 Jinhao Chen and Timothy A. Davis, Texas A&M University
      15             : 
      16             : //------------------------------------------------------------------------------
      17             : 
      18             : // LAGraph_BF_pure_c: Bellman-Ford single source shortest paths, returning
      19             : // both the path lengths and the shortest-path tree.
      20             : 
      21             : // LAGraph_BF_pure_c performs the Bellman-Ford algorithm to find out shortest
      22             : // path length, parent nodes along the path from given source vertex s in the
      23             : // range of [0, n) on graph with n nodes. It is implemented purely using
      24             : // conventional method, and is single-threaded. It is used here for checking
      25             : // the correctness of the result and comparison with the Bellman Ford
      26             : // implemented based on LAGraph.  Therefore, it require the graph represented
      27             : // as triplet format (I, J, W), which is an edge from vertex I(k) to vertex
      28             : // J(k) with weight W(k), and also the number of vertices and number of edges.
      29             : 
      30             : // LAGraph_BF_pure_c returns GrB_SUCCESS, or GrB_NO_VALUE if it detects of
      31             : // negative- weight cycle. The vector d(k) and pi(k) (i.e., *pd, and *ppi
      32             : // respectively) will be NULL when negative-weight cycle detected. Otherwise,
      33             : // the vector d has d(k) as the shortest distance from s to k. pi(k) = p, where
      34             : // p is the parent node of k-th node in the shortest path. In particular, pi(s)
      35             : // = -1.
      36             : 
      37             : //------------------------------------------------------------------------------
      38             : 
      39             : #define LG_FREE_ALL                     \
      40             : {                                       \
      41             :     LAGraph_Free ((void**) &d, NULL) ;  \
      42             :     LAGraph_Free ((void**) &pi, NULL) ; \
      43             : }
      44             : 
      45             : #include "LG_internal.h"
      46             : #include <LAGraphX.h>
      47             : 
      48             : // Given the edges and corresponding weights of a graph in tuple
      49             : // form {I, J, W} and a source vertex s. If there is no negative-weight
      50             : // cycle reachable from s, returns GrB_SUCCESS and the shortest distance
      51             : // d and the shortest path tree pi. Otherwise return NULL pointer for d
      52             : // and pi.
      53             : 
      54           3 : GrB_Info LAGraph_BF_pure_c
      55             : (
      56             :     int32_t **pd,     // pointer to distance vector d, d(k) = shorstest distance
      57             :                      // between s and k if k is reachable from s
      58             :     int64_t **ppi,   // pointer to parent index vector pi, pi(k) = parent of
      59             :                      // node k in the shortest path tree
      60             :     const int64_t s, // given source node index
      61             :     const int64_t n, // number of nodes
      62             :     const int64_t nz,// number of edges
      63             :     const int64_t *I,// row index vector
      64             :     const int64_t *J,// column index vector
      65             :     const int32_t  *W // weight vector, W(i) = weight of edge (I(i),J(i))
      66             : )
      67             : {
      68           3 :     char *msg = NULL ;
      69             :     int64_t i, j, k;
      70           3 :     int32_t *d = NULL;
      71           3 :     int64_t *pi = NULL;
      72           3 :     LG_ASSERT (I != NULL && J != NULL && W != NULL && pd != NULL &&
      73             :         ppi != NULL, GrB_NULL_POINTER) ;
      74             : 
      75           3 :     LAGraph_Free ((void **) pd, NULL) ;
      76           3 :     LAGraph_Free ((void **) ppi, NULL) ;
      77             : 
      78           3 :     LG_ASSERT_MSG (s < n, GrB_INVALID_INDEX, "invalid source node") ;
      79             : 
      80             :     // allocate d and pi
      81           3 :     LAGRAPH_TRY (LAGraph_Malloc((void **) &d,  n, sizeof(int32_t), msg));
      82           3 :     LAGRAPH_TRY (LAGraph_Malloc((void **) &pi, n, sizeof(int64_t), msg));
      83             : 
      84             :     // initialize d to a vector of INF while set d(s) = 0
      85             :     // and pi to a vector of -1
      86          51 :     for (i = 0; i < n; i++)
      87             :     {
      88          48 :         d[i] = INT32_MAX;
      89          48 :         pi[i] = -1;
      90             :     }
      91           3 :     d[s] = 0;
      92             : 
      93             :     // start the RELAX process and print results after each loop
      94           3 :     bool new_path = true;     //variable indicating if new path is found
      95           3 :     int64_t count = 0;        //number of loops
      96             :     // terminate when no new path is found or more than n-1 loops
      97          14 :     while(new_path && count < n-1)
      98             :     {
      99          11 :         new_path = false;
     100         431 :         for (k = 0; k < nz; k++)
     101             :         {
     102         420 :             i = I[k];
     103         420 :             j = J[k];
     104         420 :             if (d[i] != INT32_MAX && (d[j] == INT32_MAX || d[j] > d[i] + W[k]))
     105             :             {
     106          83 :                 d[j] = d[i] + W[k];
     107          83 :                 pi[j] = i;
     108          83 :                 new_path = true;
     109             :             }
     110             :         }
     111          11 :         count++;
     112             :     }
     113             : 
     114             :     // check for negative-weight cycle only when there was a new path in the
     115             :     // last loop, otherwise, there can't be a negative-weight cycle.
     116           3 :     if (new_path)
     117             :     {
     118             :         // Do another loop of RELAX to check for negative loop,
     119             :         // return true if there is negative-weight cycle;
     120             :         // otherwise, print the distance vector and return false.
     121           1 :         for (k = 0; k < nz; k++)
     122             :         {
     123           1 :             i = I[k];
     124           1 :             j = J[k];
     125           1 :             if (d[i] != INT32_MAX && (d[j] == INT32_MAX || d[j] > d[i] + W[k]))
     126             :             {
     127           1 :                 LG_FREE_ALL ;
     128           1 :                 return (GrB_NO_VALUE) ;
     129             :             }
     130             :         }
     131             :     }
     132             : 
     133           2 :     *pd = d;
     134           2 :     *ppi = pi;
     135           2 :     return (GrB_SUCCESS) ;
     136             : }

Generated by: LCOV version 1.14