//------------------------------------------------------------------------------ // BF_pure_c_double.c: Bellman-Ford method, not using GraphBLAS //------------------------------------------------------------------------------ // LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause // // For additional details (including references to third party source code and // other files) see the LICENSE file or contact permission@sei.cmu.edu. See // Contributors.txt for a full list of contributors. Created, in part, with // funding and support from the U.S. Government (see Acknowledgments.txt file). // DM22-0790 // Contributed by Jinhao Chen and Timothy A. Davis, Texas A&M University //------------------------------------------------------------------------------ // LAGraph_BF_pure_c_double: Bellman-Ford single source shortest paths, // returning both the path lengths and the shortest-path tree. // LAGraph_BF_pure_c_double performs a Bellman-Ford to find out shortest path // length, parent nodes along the path from given source vertex s in the range // of [0, n) on graph with n nodes. It is implemented purely using conventional // method. It is used here for checking the correctness of the result and // comparison with the Bellman Ford implemented based on LAGraph. Therefore, it // require the graph represented as triplet format (I, J, W), which is an edge // from vertex I(k) to vertex J(k) with weight W(k), and also the number of // vertices and number of edges. // LAGraph_BF_pure_c_double returns GrB_SUCCESS if it succeeds. In this case, // there are no negative-weight cycle in the graph, and d and pi are returned. // The vector d has d(k) as the distance from source noce to k-th node. pi(k) = // p, where p is the parent node of k-th node in the shortest path. In // particular, pi(s) = -1. // If the graph has a negative-weight cycle, GrB_NO_VALUE is returned, and the // vectors d and pi (i.e., pd and ppi) will be NULL. //------------------------------------------------------------------------------ #define LG_FREE_ALL \ { \ LAGraph_Free ((void**) &d, NULL) ; \ LAGraph_Free ((void**) &pi, NULL) ; \ } #include #include "LG_internal.h" #include // Given the edges and corresponding weights of a graph in tuple // form {I, J, W} and a source vertex s. If there is no negative-weight // cycle reachable from s, returns GrB_SUCCESS and the shortest distance // d and the shortest path tree pi. Otherwise return NULL pointer for d // and pi. GrB_Info LAGraph_BF_pure_c_double ( double **pd, // pointer to distance vector d, d(k) = shorstest distance // between s and k if k is reachable from s int64_t **ppi, // pointer to parent index vector pi, pi(k) = parent of // node k in the shortest path tree const int64_t s, // given source node index const int64_t n, // number of nodes const int64_t nz,// number of edges const int64_t *I,// row index vector const int64_t *J,// column index vector const double *W // weight vector, W(i) = weight of edge (I(i),J(i)) ) { char *msg = NULL ; int64_t i, j, k; double *d = NULL; int64_t *pi = NULL; LG_ASSERT (I != NULL && J != NULL && W != NULL && pd != NULL && ppi != NULL, GrB_NULL_POINTER) ; LAGraph_Free ((void **) pd, NULL) ; LAGraph_Free ((void **) ppi, NULL) ; LG_ASSERT_MSG (s < n, GrB_INVALID_INDEX, "invalid source node") ; // allocate d and pi LAGRAPH_TRY (LAGraph_Malloc((void **) &d, n, sizeof(double), msg)); LAGRAPH_TRY (LAGraph_Malloc((void **) &pi, n, sizeof(int64_t), msg)); // initialize d to a vector of INF while set d(s) = 0 // and pi to a vector of -1 for (i = 0; i < n; i++) { d[i] = INFINITY; pi[i] = -1; } d[s] = 0; // start the RELAX process and print results after each loop bool new_path = true; //variable indicating if new path is found int64_t count = 0; //number of loops // terminate when no new path is found or more than n-1 loops while(new_path && count < n-1) { new_path = false; for (k = 0; k < nz; k++) { i = I[k]; j = J[k]; if (d[j] > d[i] + W[k]) { d[j] = d[i] + W[k]; pi[j] = i; new_path = true; } } count++; } // check for negative-weight cycle only when there was a new path in the // last loop, otherwise, there can't be a negative-weight cycle. if (new_path) { // Do another loop of RELAX to check for negative loop, // return true if there is negative-weight cycle; // otherwise, print the distance vector and return false. for (k = 0; k < nz; k++) { i = I[k]; j = J[k]; if (d[j] > d[i] + W[k] + DBL_EPSILON*d[j]) { LG_FREE_ALL ; return (GrB_NO_VALUE) ; } } } *pd = d; *ppi = pi; return (GrB_SUCCESS) ; }