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

          Line data    Source code
       1             : //------------------------------------------------------------------------------
       2             : // LG_BreadthFirstSearch_vanilla:  BFS using only GraphBLAS API
       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 Scott McMillan, derived from examples in the appendix of
      15             : // The GraphBLAS C API Specification, v1.3.0
      16             : 
      17             : //------------------------------------------------------------------------------
      18             : 
      19             : // This is a Basic algorithm (no extra cached properties are required),
      20             : // but it is not user-callable (see LAGr_BreadthFirstSearch instead).
      21             : 
      22             : #define LG_FREE_WORK        \
      23             : {                           \
      24             :     GrB_free (&frontier);   \
      25             : }
      26             : 
      27             : #define LG_FREE_ALL         \
      28             : {                           \
      29             :     LG_FREE_WORK ;          \
      30             :     GrB_free (&l_parent);   \
      31             :     GrB_free (&l_level);    \
      32             : }
      33             : 
      34             : #include "LG_internal.h"
      35             : 
      36        9464 : int LG_BreadthFirstSearch_vanilla
      37             : (
      38             :     GrB_Vector    *level,
      39             :     GrB_Vector    *parent,
      40             :     const LAGraph_Graph G,
      41             :     GrB_Index      src,
      42             :     char          *msg
      43             : )
      44             : {
      45             : 
      46             :     //--------------------------------------------------------------------------
      47             :     // check inputs
      48             :     //--------------------------------------------------------------------------
      49             : 
      50        9464 :     LG_CLEAR_MSG ;
      51        9464 :     GrB_Vector frontier = NULL;     // the current frontier
      52        9464 :     GrB_Vector l_parent = NULL;     // parent vector
      53        9464 :     GrB_Vector l_level = NULL;      // level vector
      54             : 
      55        9464 :     bool compute_level  = (level != NULL);
      56        9464 :     bool compute_parent = (parent != NULL);
      57        9464 :     if (compute_level ) (*level ) = NULL;
      58        9464 :     if (compute_parent) (*parent) = NULL;
      59        9464 :     LG_ASSERT_MSG (compute_level || compute_parent, GrB_NULL_POINTER,
      60             :         "either level or parent must be non-NULL") ;
      61             : 
      62        9461 :     LG_TRY (LAGraph_CheckGraph (G, msg)) ;
      63             : 
      64             :     //--------------------------------------------------------------------------
      65             :     // get the problem size
      66             :     //--------------------------------------------------------------------------
      67             : 
      68        9461 :     GrB_Matrix A = G->A ;
      69             : 
      70             :     GrB_Index n;
      71        9461 :     GRB_TRY( GrB_Matrix_nrows (&n, A) );
      72        9461 :     LG_ASSERT_MSG (src < n, GrB_INVALID_INDEX, "invalid source node") ;
      73             : 
      74             :     // determine the semiring type
      75        9459 :     GrB_Type     int_type  = (n > INT32_MAX) ? GrB_INT64 : GrB_INT32 ;
      76             :     GrB_BinaryOp
      77        9459 :         second_op = (n > INT32_MAX) ? GrB_SECOND_INT64 : GrB_SECOND_INT32 ;
      78        9459 :     GrB_Semiring semiring  = NULL;
      79        9459 :     GrB_IndexUnaryOp ramp = NULL ;
      80             : 
      81        9459 :     if (compute_parent)
      82             :     {
      83             :         // create the parent vector.  l_parent(i) is the parent id of node i
      84        5338 :         GRB_TRY (GrB_Vector_new(&l_parent, int_type, n)) ;
      85             : 
      86       10180 :         semiring = (n > INT32_MAX) ?
      87        5090 :             GrB_MIN_FIRST_SEMIRING_INT64 : GrB_MIN_FIRST_SEMIRING_INT32;
      88             : 
      89             :         // create a sparse integer vector frontier, and set frontier(src) = src
      90        5090 :         GRB_TRY (GrB_Vector_new(&frontier, int_type, n)) ;
      91        4842 :         GRB_TRY (GrB_Vector_setElement(frontier, src, src)) ;
      92             : 
      93             :         // pick the ramp operator
      94        4470 :         ramp = (n > INT32_MAX) ? GrB_ROWINDEX_INT64 : GrB_ROWINDEX_INT32 ;
      95             :     }
      96             :     else
      97             :     {
      98             :         // only the level is needed
      99        4121 :         semiring = LAGraph_any_one_bool ;
     100             : 
     101             :         // create a sparse boolean vector frontier, and set frontier(src) = true
     102        4121 :         GRB_TRY (GrB_Vector_new(&frontier, GrB_BOOL, n)) ;
     103        3873 :         GRB_TRY (GrB_Vector_setElement(frontier, true, src)) ;
     104             :     }
     105             : 
     106        7971 :     if (compute_level)
     107             :     {
     108             :         // create the level vector. v(i) is the level of node i
     109             :         // v (src) = 0 denotes the source node
     110        7791 :         GRB_TRY (GrB_Vector_new(&l_level, int_type, n)) ;
     111             :     }
     112             : 
     113             :     //--------------------------------------------------------------------------
     114             :     // BFS traversal and label the nodes
     115             :     //--------------------------------------------------------------------------
     116             : 
     117        7475 :     GrB_Index nq = 1 ;          // number of nodes in the current level
     118        7475 :     GrB_Index last_nq = 0 ;
     119        7475 :     GrB_Index current_level = 0;
     120        7475 :     GrB_Index nvals = 1;
     121             : 
     122             :     // {!mask} is the set of unvisited nodes
     123        7475 :     GrB_Vector mask = (compute_parent) ? l_parent : l_level ;
     124             : 
     125             :     // parent BFS
     126             :     do
     127             :     {
     128       39395 :         if (compute_level)
     129             :         {
     130             :             // assign levels: l_level<s(frontier)> = current_level
     131       30428 :             GRB_TRY( GrB_assign(l_level, frontier, GrB_NULL,
     132             :                                 current_level, GrB_ALL, n, GrB_DESC_S) );
     133       28066 :             ++current_level;
     134             :         }
     135             : 
     136       37033 :         if (compute_parent)
     137             :         {
     138             :             // frontier(i) currently contains the parent id of node i in tree.
     139             :             // l_parent<s(frontier)> = frontier
     140       23561 :             GRB_TRY( GrB_assign(l_parent, frontier, GrB_NULL,
     141             :                                 frontier, GrB_ALL, n, GrB_DESC_S) );
     142             : 
     143             :             // convert all stored values in frontier to their indices
     144       23005 :             GRB_TRY (GrB_apply (frontier, GrB_NULL, GrB_NULL, ramp,
     145             :                 frontier, 0, GrB_NULL)) ;
     146             :         }
     147             : 
     148             :         // frontier = kth level of the BFS
     149             :         // mask is l_parent if computing parent, l_level if computing just level
     150       36353 :         GRB_TRY( GrB_vxm(frontier, mask, GrB_NULL, semiring,
     151             :                          frontier, A, GrB_DESC_RSC) );
     152             : 
     153             :         // done if frontier is empty
     154       32671 :         GRB_TRY( GrB_Vector_nvals(&nvals, frontier) );
     155       32671 :     } while (nvals > 0);
     156             : 
     157             :     //--------------------------------------------------------------------------
     158             :     // free workspace and return result
     159             :     //--------------------------------------------------------------------------
     160             : 
     161         751 :     if (compute_parent) (*parent) = l_parent ;
     162         751 :     if (compute_level ) (*level ) = l_level ;
     163         751 :     LG_FREE_WORK ;
     164         751 :     return (GrB_SUCCESS) ;
     165             : }

Generated by: LCOV version 1.14