LCOV - code coverage report
Current view: top level - experimental/algorithm - LAGraph_msf.c (source / functions) Hit Total Coverage
Test: LAGraph code coverage report. Commit id: 50cd0c8. Current time (UTC): 2025-07-25T16:32:50Z Lines: 226 226 100.0 %
Date: 2025-07-25 16:38:41 Functions: 17 17 100.0 %

          Line data    Source code
       1             : //------------------------------------------------------------------------------
       2             : // LAGraph_msf.c
       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 Yongzhe Zhang (zyz915@gmail.com)
      15             : // Revised by Gabriel Gomez and Tim Davis
      16             : 
      17             : //------------------------------------------------------------------------------
      18             : 
      19             : /**
      20             :  * Code is based on Boruvka's minimum spanning forest algorithm
      21             :  * 
      22             :  * The algorithm calculates the minimum spanning forest of a graph represented 
      23             :  * by matrix A. It outputs a matrix containing lowest weight edges which connect 
      24             :  * the nodes in the forest, and a vector indicating the connected component 
      25             :  * "tree" which each node belongs to.
      26             :  */
      27             : 
      28             : // TODO: not ready for src but getting close.
      29             : 
      30             : // TODO: a "sanitize" input is fine for now in the experimental folder, but it
      31             : // doesn't fit with the standard LAGraph API.  It will need to be removed when
      32             : // this method is moved to the src folder.  The input will also become an
      33             : // LAGraph_Graph, not a plain GrB_Matrix A.
      34             : 
      35             : // FUTURE:  the idx type could be INT32 if the matrix has < 2 billion nodes,
      36             : // and the weight types could be expanded (int32 and float).
      37             : 
      38             : #include "LG_internal.h"
      39             : #include <LAGraph.h>
      40             : #include <LAGraphX.h>
      41             : 
      42             : //------------------------------------------------------------------------------
      43             : // tuple: a tuple containing (weight,index)
      44             : //------------------------------------------------------------------------------
      45             : 
      46             : // LG_MSF_tuple_int is used if the input graph uses integer weights of any type;
      47             : // LG_MSF_tuple_fp is used if the input graph is FP32 or FP64.  Likewise for the
      48             : // other *_int and *_fp types and operators.
      49             : 
      50             : typedef struct
      51             : {
      52             :     int64_t wInt;
      53             :     uint64_t idx;
      54             : } LG_MSF_tuple_int;
      55             : 
      56             : #define TUPLE_INT      \
      57             : "typedef struct    \n" \
      58             : "{                 \n" \
      59             : "    int64_t wInt; \n" \
      60             : "    uint64_t idx; \n" \
      61             : "} LG_MSF_tuple_int;"
      62             : 
      63             : typedef struct
      64             : {
      65             :     double wFp;
      66             :     uint64_t idx;
      67             : } LG_MSF_tuple_fp;
      68             : 
      69             : #define TUPLE_FP       \
      70             : "typedef struct    \n" \
      71             : "{                 \n" \
      72             : "    double wFp;   \n" \
      73             : "    uint64_t idx; \n" \
      74             : "} LG_MSF_tuple_fp;"
      75             : 
      76             : //------------------------------------------------------------------------------
      77             : // context_type: context for IndexUnaryOps (using the theta input)
      78             : //------------------------------------------------------------------------------
      79             : 
      80             : typedef struct
      81             : {
      82             :     uint64_t    *parent;   // parent of each vertex in the spanning forest
      83             :     struct
      84             :     {
      85             :         int64_t wInt;
      86             :         uint64_t idx;
      87             :     } *w_partner;          // partner vertex in the spanning forest
      88             : } LG_MSF_context_int;
      89             : 
      90             : #define LG_MSF_CONTEXT_INT    \
      91             : "typedef struct           \n" \
      92             : "{                        \n" \
      93             : "    uint64_t    *parent; \n" \
      94             : "    struct               \n" \
      95             : "    {                    \n" \
      96             : "        int64_t wInt;    \n" \
      97             : "        uint64_t idx;    \n" \
      98             : "    } *w_partner;        \n" \
      99             : "} LG_MSF_context_int;"
     100             : 
     101             : typedef struct
     102             : {
     103             :     uint64_t    *parent;   // parent of each vertex in the spanning forest
     104             :     struct
     105             :     {
     106             :         double wFp;
     107             :         uint64_t idx;
     108             :     } *w_partner;          // partner vertex in the spanning forest
     109             : } LG_MSF_context_fp;
     110             : 
     111             : #define LG_MSF_CONTEXT_FP     \
     112             : "typedef struct           \n" \
     113             : "{                        \n" \
     114             : "    uint64_t    *parent; \n" \
     115             : "    struct               \n" \
     116             : "    {                    \n" \
     117             : "        double wFp;      \n" \
     118             : "        uint64_t idx;    \n" \
     119             : "    } *w_partner;        \n" \
     120             : "} LG_MSF_context_fp;"
     121             : 
     122             : //------------------------------------------------------------------------------
     123             : // selectEdge: index-unary operator to select edges of min weight
     124             : //------------------------------------------------------------------------------
     125             : 
     126             : // generate solution:
     127             : // for each element A(i, j), it is selected if
     128             : //   1. weight[i] == A(i, j)    -- where weight[i] stores i's minimum edge weight
     129             : //   2. parent[j] == partner[i] -- j belongs to the specified connected component
     130             : 
     131       16028 : void LG_MSF_selectEdge_int 
     132             : (
     133             :     bool *z, 
     134             :     const int64_t *x, 
     135             :     GrB_Index i, 
     136             :     GrB_Index j, 
     137             :     const LG_MSF_context_int *theta
     138             : )
     139             : {
     140       32033 :     (*z) = (theta->w_partner[i].wInt == *x) && 
     141       16005 :         (theta->parent[j] == theta->w_partner[i].idx);
     142       16028 : }
     143             : 
     144             : #define SELECTEDGE_INT \
     145             : "void LG_MSF_selectEdge_int                            \n"\
     146             : "(                                                     \n"\
     147             : "    bool *z,                                          \n"\
     148             : "    const int64_t *x,                                 \n"\
     149             : "    GrB_Index i,                                      \n"\
     150             : "    GrB_Index j,                                      \n"\
     151             : "    const LG_MSF_context_int *theta                   \n"\
     152             : ")                                                     \n"\
     153             : "{                                                     \n"\
     154             : "    (*z) = (theta->w_partner[i].wInt == *x) &&        \n"\
     155             : "        (theta->parent[j] == theta->w_partner[i].idx);\n"\
     156             : "}"
     157             : 
     158      576770 : void LG_MSF_selectEdge_fp 
     159             : (
     160             :     bool *z, 
     161             :     const double *x, 
     162             :     GrB_Index i, 
     163             :     GrB_Index j, 
     164             :     const LG_MSF_context_fp *theta
     165             : )
     166             : {
     167      598783 :     (*z) = (theta->w_partner[i].wFp == *x) && 
     168       22013 :         (theta->parent[j] == theta->w_partner[i].idx);
     169      576770 : }
     170             : 
     171             : #define SELECTEDGE_FP \
     172             : "void LG_MSF_selectEdge_fp                             \n"\
     173             : "(                                                     \n"\
     174             : "    bool *z,                                          \n"\
     175             : "    const double *x,                                  \n"\
     176             : "    GrB_Index i,                                      \n"\
     177             : "    GrB_Index j,                                      \n"\
     178             : "    const LG_MSF_context_fp *theta                    \n"\
     179             : ")                                                     \n"\
     180             : "{                                                     \n"\
     181             : "    (*z) = (theta->w_partner[i].wFp == *x) &&         \n"\
     182             : "        (theta->parent[j] == theta->w_partner[i].idx);\n"\
     183             : "}"
     184             : 
     185             : //------------------------------------------------------------------------------
     186             : // removeEdge: remove edge (i,j) when i and j have the same parent
     187             : //------------------------------------------------------------------------------
     188             : 
     189             : // edge removal:
     190             : // A(i, j) is removed when parent[i] == parent[j]
     191             : 
     192       16028 : void LG_MSF_removeEdge_int 
     193             : (
     194             :     bool *z, 
     195             :     const int64_t *x, 
     196             :     GrB_Index i, 
     197             :     GrB_Index j, 
     198             :     const LG_MSF_context_int *theta
     199             : )
     200             : {
     201       16028 :     (*z) = (theta->parent[i] != theta->parent[j]);
     202       16028 : }
     203             : 
     204             : #define REMOVEEDGE_INT \
     205             : "void LG_MSF_removeEdge_int                        \n"\
     206             : "(                                                 \n"\
     207             : "    bool *z,                                      \n"\
     208             : "    const int64_t *x,                             \n"\
     209             : "    GrB_Index i,                                  \n"\
     210             : "    GrB_Index j,                                  \n"\
     211             : "    const LG_MSF_context_int *theta               \n"\
     212             : ")                                                 \n"\
     213             : "{                                                 \n"\
     214             : "    (*z) = (theta->parent[i] != theta->parent[j]);\n"\
     215             : "}"
     216             : 
     217      576770 : void LG_MSF_removeEdge_fp 
     218             : (
     219             :     bool *z, 
     220             :     const double *x, 
     221             :     GrB_Index i, 
     222             :     GrB_Index j, 
     223             :     const LG_MSF_context_fp *theta
     224             : )
     225             : {
     226      576770 :     (*z) = (theta->parent[i] != theta->parent[j]);
     227      576770 : }
     228             : 
     229             : #define REMOVEEDGE_FP \
     230             : "void LG_MSF_removeEdge_fp                         \n"\
     231             : "(                                                 \n"\
     232             : "    bool *z,                                      \n"\
     233             : "    const double *x,                              \n"\
     234             : "    GrB_Index i,                                  \n"\
     235             : "    GrB_Index j,                                  \n"\
     236             : "    const LG_MSF_context_fp *theta                \n"\
     237             : ")                                                 \n"\
     238             : "{                                                 \n"\
     239             : "    (*z) = (theta->parent[i] != theta->parent[j]);\n"\
     240             : "}"
     241             : 
     242             : //------------------------------------------------------------------------------
     243             : // combine: create a tuple from a weight and an index
     244             : //------------------------------------------------------------------------------
     245             : 
     246       11750 : void LG_MSF_combine_int 
     247             : (
     248             :     LG_MSF_tuple_int *z, 
     249             :     const int64_t *x, 
     250             :     const uint64_t *y
     251             : )
     252             : {
     253       11750 :     z->wInt = *x;
     254       11750 :     z->idx = *y;
     255       11750 : }
     256             : 
     257             : #define COMBINE_INT \
     258             : "void LG_MSF_combine_int  \n"\
     259             : "(                        \n"\
     260             : "    LG_MSF_tuple_int *z, \n"\
     261             : "    const int64_t *x,    \n"\
     262             : "    const uint64_t *y    \n"\
     263             : ")                        \n"\
     264             : "{                        \n"\
     265             : "    z->wInt = *x;        \n"\
     266             : "    z->idx = *y;         \n"\
     267             : "}"
     268             : 
     269      300726 : void LG_MSF_combine_fp 
     270             : (
     271             :     LG_MSF_tuple_fp *z, 
     272             :     const double *x, 
     273             :     const uint64_t *y
     274             : )
     275             : {
     276      300726 :     z->wFp = *x;
     277      300726 :     z->idx = *y;
     278      300726 : }
     279             : 
     280             : #define COMBINE_FP \
     281             : "void LG_MSF_combine_fp  \n"\
     282             : "(                       \n"\
     283             : "    LG_MSF_tuple_fp *z, \n"\
     284             : "    const double *x,    \n"\
     285             : "    const uint64_t *y   \n"\
     286             : ")                       \n"\
     287             : "{                       \n"\
     288             : "    z->wFp = *x;        \n"\
     289             : "    z->idx = *y;        \n"\
     290             : "}"
     291             : 
     292             : //------------------------------------------------------------------------------
     293             : // get_first:  get first item in a tuple (the weight)
     294             : //------------------------------------------------------------------------------
     295             : 
     296        1220 : void LG_MSF_get_first_int (int64_t *y, const LG_MSF_tuple_int *x)
     297             : {
     298        1220 :     *y = x->wInt;
     299        1220 : }
     300             : 
     301             : #define GET_FIRST_INT \
     302             : "void LG_MSF_get_first_int (int64_t *y, const LG_MSF_tuple_int *x)  \n" \
     303             : "{                                                                  \n" \
     304             : "    *y = x->wInt;                                                  \n" \
     305             : "}"
     306             : 
     307        2076 : void LG_MSF_get_first_fp (double *y, const LG_MSF_tuple_fp *x)
     308             : {
     309        2076 :     *y = x->wFp;
     310        2076 : }
     311             : 
     312             : #define GET_FIRST_FP \
     313             : "void LG_MSF_get_first_fp (double *y, const LG_MSF_tuple_fp *x)   \n" \
     314             : "{                                                                \n" \
     315             : "    *y = x->wFp;                                                 \n" \
     316             : "}"
     317             : 
     318             : //------------------------------------------------------------------------------
     319             : // get_second:  get second item in a tuple (the index)
     320             : //------------------------------------------------------------------------------
     321             : 
     322        3639 : void LG_MSF_get_second_int (uint64_t *y, const LG_MSF_tuple_int *x)
     323             : {
     324        3639 :     *y = x->idx;
     325        3639 : }
     326             : 
     327             : #define GET_SECOND_INT \
     328             : "void LG_MSF_get_second_int (uint64_t *y, const LG_MSF_tuple_int *x)  \n" \
     329             : "{                                                                    \n" \
     330             : "    *y = x->idx;                                                     \n" \
     331             : "}"
     332             : 
     333       12310 : void LG_MSF_get_second_fp (uint64_t *y, const LG_MSF_tuple_fp *x)
     334             : {
     335       12310 :     *y = x->idx;
     336       12310 : }
     337             : 
     338             : #define GET_SECOND_FP \
     339             : "void LG_MSF_get_second_fp (uint64_t *y, const LG_MSF_tuple_fp *x)    \n" \
     340             : "{                                                                    \n" \
     341             : "    *y = x->idx;                                                     \n" \
     342             : "}"
     343             : 
     344             : //------------------------------------------------------------------------------
     345             : // tupleMin: z = the min tuple of x and y
     346             : //------------------------------------------------------------------------------
     347             : 
     348       10530 : void LG_MSF_tupleMin_int 
     349             : (
     350             :     LG_MSF_tuple_int *z, 
     351             :     const LG_MSF_tuple_int *x, 
     352             :     const LG_MSF_tuple_int *y
     353             : )
     354             : {
     355       20613 :     bool xSmaller = x->wInt < y->wInt || 
     356       10083 :         (x->wInt == y->wInt && x->idx < y->idx);
     357       10530 :     z->wInt = (xSmaller)? x->wInt: y->wInt;
     358       10530 :     z->idx = (xSmaller)? x->idx: y->idx;
     359       10530 : }
     360             : 
     361             : #define TUPLEMIN_INT \
     362             : "void LG_MSF_tupleMin_int                        \n"\
     363             : "(                                               \n"\
     364             : "    LG_MSF_tuple_int *z,                        \n"\
     365             : "    const LG_MSF_tuple_int *x,                  \n"\
     366             : "    const LG_MSF_tuple_int *y                   \n"\
     367             : ")                                               \n"\
     368             : "{                                               \n"\
     369             : "    bool xSmaller = x->wInt < y->wInt ||        \n"\
     370             : "        (x->wInt == y->wInt && x->idx < y->idx);\n"\
     371             : "    z->wInt = (xSmaller)? x->wInt: y->wInt;     \n"\
     372             : "    z->idx = (xSmaller)? x->idx: y->idx;        \n"\
     373             : "}"
     374             : 
     375      298650 : void LG_MSF_tupleMin_fp 
     376             : (
     377             :     LG_MSF_tuple_fp *z, 
     378             :     const LG_MSF_tuple_fp *x, 
     379             :     const LG_MSF_tuple_fp *y
     380             : )
     381             : {
     382      298650 :     bool xSmaller = x->wFp < y->wFp || (x->wFp == y->wFp && x->idx < y->idx);
     383      298650 :     z->wFp = (xSmaller)? x->wFp: y->wFp;
     384      298650 :     z->idx = (xSmaller)? x->idx: y->idx;
     385      298650 : }
     386             : 
     387             : #define TUPLEMIN_FP \
     388             : "void LG_MSF_tupleMin_fp                                                      \n"\
     389             : "(                                                                            \n"\
     390             : "    LG_MSF_tuple_fp *z,                                                      \n"\
     391             : "    const LG_MSF_tuple_fp *x,                                                \n"\
     392             : "    const LG_MSF_tuple_fp *y                                                 \n"\
     393             : ")                                                                            \n"\
     394             : "{                                                                            \n"\
     395             : "    bool xSmaller = x->wFp < y->wFp || (x->wFp == y->wFp && x->idx < y->idx);\n"\
     396             : "    z->wFp = (xSmaller)? x->wFp: y->wFp;                                     \n"\
     397             : "    z->idx = (xSmaller)? x->idx: y->idx;                                     \n"\
     398             : "}"
     399             : 
     400             : //------------------------------------------------------------------------------
     401             : // tuple2nd: z = y
     402             : //------------------------------------------------------------------------------
     403             : 
     404        2419 : void LG_MSF_tuple2nd_int 
     405             : (
     406             :     LG_MSF_tuple_int *z, 
     407             :     const void *x, 
     408             :     const LG_MSF_tuple_int *y
     409             : )
     410             : {
     411        2419 :     z->wInt = y->wInt;
     412        2419 :     z->idx = y->idx;
     413        2419 : }
     414             : 
     415             : #define TUPLE2ND_INT \
     416             : "void LG_MSF_tuple2nd_int     \n"\
     417             : "(                            \n"\
     418             : "    LG_MSF_tuple_int *z,     \n"\
     419             : "    const void *x,           \n"\
     420             : "    const LG_MSF_tuple_int *y\n"\
     421             : ")                            \n"\
     422             : "{                            \n"\
     423             : "    z->wInt = y->wInt;       \n"\
     424             : "    z->idx = y->idx;         \n"\
     425             : "}"
     426             : 
     427       10234 : void LG_MSF_tuple2nd_fp 
     428             : (
     429             :     LG_MSF_tuple_fp *z, 
     430             :     const void *x, 
     431             :     const LG_MSF_tuple_fp *y
     432             : )
     433             : {
     434       10234 :     z->wFp = y->wFp;
     435       10234 :     z->idx = y->idx;
     436       10234 : }
     437             : 
     438             : #define TUPLE2ND_FP \
     439             : "void LG_MSF_tuple2nd_fp     \n"\
     440             : "(                           \n"\
     441             : "    LG_MSF_tuple_fp *z,     \n"\
     442             : "    const void *x,          \n"\
     443             : "    const LG_MSF_tuple_fp *y\n"\
     444             : ")                           \n"\
     445             : "{                           \n"\
     446             : "    z->wFp = y->wFp;        \n"\
     447             : "    z->idx = y->idx;        \n"\
     448             : "}"
     449             : 
     450             : //------------------------------------------------------------------------------
     451             : // tupleEq: true if two tuples are equal
     452             : //------------------------------------------------------------------------------
     453             : 
     454        2419 : void LG_MSF_tupleEq_int 
     455             : (
     456             :     bool *z, 
     457             :     const LG_MSF_tuple_int *x, 
     458             :     const LG_MSF_tuple_int *y
     459             : )
     460             : {
     461        2419 :     *z = (x->wInt == y->wInt) && (x->idx == y->idx);
     462        2419 : }
     463             : 
     464             : #define TUPLEEQ_INT \
     465             : "void LG_MSF_tupleEq_int                             \n"\
     466             : "(                                                   \n"\
     467             : "    bool *z,                                        \n"\
     468             : "    const LG_MSF_tuple_int *x,                      \n"\
     469             : "    const LG_MSF_tuple_int *y                       \n"\
     470             : ")                                                   \n"\
     471             : "{                                                   \n"\
     472             : "    *z = (x->wInt == y->wInt) && (x->idx == y->idx);\n"\
     473             : "}"
     474             : 
     475       10234 : void LG_MSF_tupleEq_fp 
     476             : (
     477             :     bool *z, 
     478             :     const LG_MSF_tuple_fp *x, 
     479             :     const LG_MSF_tuple_fp *y
     480             : )
     481             : {
     482       10234 :     *z = (x->wFp == y->wFp) && (x->idx == y->idx);
     483       10234 : }
     484             : 
     485             : #define TUPLEEQ_FP \
     486             : "void LG_MSF_tupleEq_fp                            \n"\
     487             : "(                                                 \n"\
     488             : "    bool *z,                                      \n"\
     489             : "    const LG_MSF_tuple_fp *x,                     \n"\
     490             : "    const LG_MSF_tuple_fp *y                      \n"\
     491             : ")                                                 \n"\
     492             : "{                                                 \n"\
     493             : "    *z = (x->wFp == y->wFp) && (x->idx == y->idx);\n"\
     494             : "}"
     495             : 
     496             : //------------------------------------------------------------------------------
     497             : 
     498             : #undef  LG_FREE_ALL
     499             : #define LG_FREE_ALL                                 \
     500             : {                                                   \
     501             :     GrB_free (&S);                                  \
     502             :     GrB_free (&T);                                  \
     503             :     LAGraph_Free ((void **) &SI, msg);              \
     504             :     LAGraph_Free ((void **) &SJ, msg);              \
     505             :     LAGraph_Free ((void **) &SX, msg);              \
     506             :     LAGraph_Free ((void **) &context_int.parent, msg);      \
     507             :     LAGraph_Free ((void **) &context_fp.parent, msg);       \
     508             :     GrB_free (&f);                                  \
     509             :     GrB_free (&w);                                  \
     510             :     GrB_free (&I);                                  \
     511             :     GrB_free (&t);                                  \
     512             :     GrB_free (&edge);                               \
     513             :     GrB_free (&cedge);                              \
     514             :     GrB_free (&tedge);                              \
     515             :     GrB_free (&mask);                               \
     516             :     GrB_free (&index_v);                            \
     517             :     GrB_free (&combine);                            \
     518             :     GrB_free (&minComb);                            \
     519             :     GrB_free (&get_first);                          \
     520             :     GrB_free (&get_second);                         \
     521             :     GrB_free (&selectEdge);                         \
     522             :     GrB_free (&removeEdge);                         \
     523             :     GrB_free (&context_type);                       \
     524             :     GrB_free (&parent_v);                           \
     525             :     GrB_free (&ramp);                               \
     526             :     GrB_free (&tupleMin);                           \
     527             :     GrB_free (&tuple2nd);                           \
     528             :     GrB_free (&tupleEq);                            \
     529             :     GrB_free (&tupleMin_monoid);                    \
     530             :     GrB_free (&tupleMin2nd);                        \
     531             :     GrB_free (&tuple);                              \
     532             :     GrB_free (&max_weight);                         \
     533             : }
     534             : 
     535             : #ifdef DBG
     536             : #undef  GRB_CATCH
     537             : #define GRB_CATCH(info)                                                 \
     538             : {                                                                       \
     539             :     printf ("GraphBLAS failure (file %s, line %d): info: %d",           \
     540             :         __FILE__, __LINE__, info) ;                                     \
     541             :     LG_ERROR_MSG ("GraphBLAS failure (file %s, line %d): info: %d",     \
     542             :         __FILE__, __LINE__, info) ;                                     \
     543             :     LG_FREE_ALL ;                                                       \
     544             :     return (info) ;                                                     \
     545             : }
     546             : #endif
     547             : 
     548             : //------------------------------------------------------------------------------
     549             : // dump_tuple_vector: debugging only
     550             : //------------------------------------------------------------------------------
     551             : 
     552             : // #define DBG
     553             : 
     554             : #ifdef DBG
     555             : static void dump_tuple_vector
     556             : (
     557             :     char *vname,
     558             :     GrB_Vector v,           // of type tuple (int or fp)
     559             :     GrB_Type weight_type
     560             : )
     561             : {
     562             :     GrB_Index n = 0 ;
     563             :     GrB_Info info ;
     564             :     GrB_Vector_size (&n, v) ;
     565             :     printf ("\ntuple vector %s, size %lu\n", vname, n) ;
     566             :     if (weight_type == GrB_INT64)
     567             :     {
     568             :         printf ("weight type: int64\n") ;
     569             :         LG_MSF_tuple_int e ;
     570             :         for (int i = 0 ; i < n ; i++)
     571             :         {
     572             :             info = GrB_Vector_extractElement_UDT (&e, v, i) ;
     573             :             if (info == GrB_SUCCESS)
     574             :             {
     575             :                 printf ("   (%d) (%ld, %lu)\n", i, e.wInt, e.idx) ;
     576             :             }
     577             :         }
     578             :     }
     579             :     else
     580             :     {
     581             :         printf ("weight type: double\n") ;
     582             :         LG_MSF_tuple_fp e ;
     583             :         for (int i = 0 ; i < n ; i++)
     584             :         {
     585             :             info = GrB_Vector_extractElement_UDT (&e, v, i) ;
     586             :             if (info == GrB_SUCCESS)
     587             :             {
     588             :                 printf ("   (%d) (%g, %lu)\n", i, e.wFp, e.idx) ;
     589             :             }
     590             :         }
     591             :     }
     592             : }
     593             : #endif
     594             : 
     595             : //------------------------------------------------------------------------------
     596             : // LAGraph_msf
     597             : //------------------------------------------------------------------------------
     598             : 
     599          29 : int LAGraph_msf
     600             : (
     601             :     GrB_Matrix *forest_edges, // output: an unsymmetrical matrix, containing
     602             :                         // the edges in the spanning forest
     603             :     GrB_Vector *componentId,  // output: The connected component of each node
     604             :                         // componentId[i] is the representative node of the 
     605             :                         // component set that i is in.
     606             :     GrB_Matrix A,       // input matrix
     607             :     bool sanitize,      // if true, ensure A is symmetric
     608             :     char *msg
     609             : )
     610             : {
     611             :     #if LG_SUITESPARSE_GRAPHBLAS_V10
     612          29 :     LG_CLEAR_MSG ;
     613             : 
     614          29 :     LG_MSF_context_int context_int = {.parent = NULL, .w_partner = NULL } ;
     615          29 :     LG_MSF_context_fp  context_fp  = {.parent = NULL, .w_partner = NULL } ;
     616          29 :     LG_MSF_tuple_int inf_int = {.wInt = INT64_MAX, .idx = UINT64_MAX};
     617          29 :     LG_MSF_tuple_fp  inf_fp  = {.wFp  = INFINITY , .idx = UINT64_MAX};
     618             : 
     619             :     GrB_Info info;
     620             :     GrB_Index n;
     621          29 :     GrB_Matrix S = NULL, T = NULL;
     622          29 :     GrB_Vector f = NULL, I = NULL, t = NULL, parent_v = NULL, tedge = NULL,
     623          29 :         edge = NULL, cedge = NULL, mask = NULL, index_v = NULL, ramp = NULL,
     624          29 :         w = NULL ;
     625             : 
     626          29 :     GrB_Index *SI = NULL, *SJ = NULL;
     627          29 :     void *SX = NULL;
     628          29 :     GrB_Type context_type = NULL, tuple = NULL, weight_type = NULL, 
     629          29 :         ignore = NULL ;
     630          29 :     GrB_BinaryOp combine = NULL, tupleMin = NULL, tuple2nd = NULL, 
     631          29 :         tupleEq = NULL;
     632          29 :     GrB_Monoid tupleMin_monoid = NULL;
     633          29 :     GrB_Semiring minComb = NULL, tupleMin2nd = NULL;
     634          29 :     GrB_UnaryOp get_first = NULL, get_second = NULL;
     635          29 :     GrB_Scalar max_weight = NULL;
     636          29 :     int edge_handling = GrB_DEFAULT;
     637          29 :     uint64_t edge_size = 0, edge_n = 0;
     638          29 :     GrB_IndexUnaryOp selectEdge = NULL, removeEdge = NULL;
     639             : 
     640             :     //--------------------------------------------------------------------------
     641             :     // Check inputs
     642             :     //--------------------------------------------------------------------------
     643             : 
     644          29 :     if (forest_edges == NULL || A == NULL) return (GrB_NULL_POINTER) ;
     645             :     GrB_Index ncols ;
     646          28 :     GRB_TRY (GrB_Matrix_nrows (&n, A)) ;
     647          28 :     GRB_TRY (GrB_Matrix_ncols (&ncols, A)) ;
     648          28 :     LG_ASSERT(n == ncols, GrB_DIMENSION_MISMATCH) ;
     649             : 
     650          27 :     GrB_BinaryOp min_weight = NULL ;
     651          27 :     size_t sx_size = 0 ;
     652             : 
     653          27 :     GrB_Type_Code tcode = 0;
     654          27 :     GrB_Matrix_get_INT32(A, (int *) &(tcode), GrB_EL_TYPE_CODE);
     655          27 :     switch (tcode)
     656             :     {
     657          19 :         case GrB_INT8_CODE:
     658             :         case GrB_INT16_CODE:
     659             :         case GrB_INT32_CODE:
     660             :         case GrB_INT64_CODE:
     661             :         case GrB_BOOL_CODE:
     662             :         case GrB_UINT8_CODE:
     663             :         case GrB_UINT16_CODE:
     664             :         case GrB_UINT32_CODE:
     665             :         case GrB_UINT64_CODE:
     666             :             // integer edge weights: use INT64
     667          19 :             weight_type = GrB_INT64 ;
     668          19 :             min_weight = GrB_MIN_INT64 ;
     669          19 :             sx_size = sizeof (int64_t) ;
     670          19 :             break;
     671             : 
     672           7 :         case GrB_FP32_CODE:
     673             :         case GrB_FP64_CODE:
     674             :             // floating-point edge weights: use FP64
     675           7 :             weight_type = GrB_FP64 ;
     676           7 :             min_weight = GrB_MIN_FP64 ;
     677           7 :             sx_size = sizeof (double) ;
     678           7 :             break;
     679             : 
     680           1 :         default:
     681             :             // other types are not supported
     682           1 :             LG_ASSERT(false, GrB_DOMAIN_MISMATCH) ;
     683             :             break;
     684             :     }
     685             : 
     686             :     //--------------------------------------------------------------------------
     687             :     // create types and operators
     688             :     //--------------------------------------------------------------------------
     689             : 
     690          26 :     GRB_TRY (GxB_Scalar_new(&max_weight, weight_type)) ;
     691          26 :     void *inf = NULL ;
     692             : 
     693          26 :     if (weight_type == GrB_INT64)
     694             :     {
     695             : 
     696             :         //----------------------------------------------------------------------
     697             :         // types and ops for INT64 weights
     698             :         //----------------------------------------------------------------------
     699             : 
     700          19 :         GRB_TRY (GxB_Type_new (&tuple, sizeof (LG_MSF_tuple_int),
     701             :             "LG_MSF_tuple_int", TUPLE_INT)) ;
     702             : 
     703          19 :         GRB_TRY (GxB_BinaryOp_new (
     704             :             &combine, (GxB_binary_function) LG_MSF_combine_int,
     705             :             tuple, weight_type, GrB_UINT64,
     706             :             "LG_MSF_combine_int", COMBINE_INT)) ;
     707             : 
     708          19 :         GRB_TRY (GxB_Scalar_setElement_INT64(max_weight, INT64_MAX)) ;
     709             : 
     710          19 :         GRB_TRY (GxB_BinaryOp_new (
     711             :             &tupleMin, (GxB_binary_function) LG_MSF_tupleMin_int,
     712             :             tuple, tuple, tuple,
     713             :             "LG_MSF_tupleMin_int", TUPLEMIN_INT)) ;
     714             : 
     715          19 :         GRB_TRY (GxB_BinaryOp_new (
     716             :             &tuple2nd, (GxB_binary_function) LG_MSF_tuple2nd_int,
     717             :             tuple, GrB_BOOL, tuple,
     718             :             "LG_MSF_tuple2nd_int", TUPLE2ND_INT)) ;
     719             : 
     720          19 :         GRB_TRY (GxB_BinaryOp_new (
     721             :             &tupleEq, (GxB_binary_function) LG_MSF_tupleEq_int,
     722             :             GrB_BOOL, tuple, tuple,
     723             :             "LG_MSF_tupleEq_int", TUPLEEQ_INT)) ;
     724             : 
     725          19 :         inf = (void *) (&inf_int) ;
     726             : 
     727          19 :         GRB_TRY (GxB_UnaryOp_new (
     728             :             &get_first, (GxB_unary_function) LG_MSF_get_first_int, weight_type, 
     729             :             tuple, "LG_MSF_get_first_int", GET_FIRST_INT)) ;
     730             : 
     731          19 :         GRB_TRY (GxB_UnaryOp_new (
     732             :             &get_second, (GxB_unary_function) LG_MSF_get_second_int, GrB_UINT64, 
     733             :             tuple, "LG_MSF_get_second_int", GET_SECOND_INT)) ;
     734             : 
     735             :         // context type
     736          19 :         GRB_TRY (GxB_Type_new (
     737             :             &context_type, sizeof (LG_MSF_context_int),
     738             :             "LG_MSF_context_int", LG_MSF_CONTEXT_INT)) ;
     739             : 
     740             :         // ops for GrB_select
     741          19 :         GRB_TRY(GxB_IndexUnaryOp_new (
     742             :             &selectEdge, (GxB_index_unary_function) LG_MSF_selectEdge_int, 
     743             :             GrB_BOOL, weight_type, context_type, 
     744             :             "LG_MSF_selectEdge_int", SELECTEDGE_INT)) ;
     745             : 
     746          19 :         GRB_TRY(GxB_IndexUnaryOp_new (
     747             :             &removeEdge, (void *) LG_MSF_removeEdge_int, GrB_BOOL, weight_type, 
     748             :             context_type, "LG_MSF_removeEdge_int", REMOVEEDGE_INT)) ;
     749             : 
     750             :     }
     751             :     else
     752             :     {
     753             : 
     754             :         //----------------------------------------------------------------------
     755             :         // types and ops for FP64 weights
     756             :         //----------------------------------------------------------------------
     757             : 
     758           7 :         GRB_TRY (GxB_Type_new (&tuple, sizeof (LG_MSF_tuple_fp),
     759             :             "LG_MSF_tuple_fp", TUPLE_FP)) ;
     760             : 
     761           7 :         GRB_TRY (GxB_BinaryOp_new (
     762             :             &combine, (GxB_binary_function) LG_MSF_combine_fp,
     763             :             tuple, weight_type, GrB_UINT64,
     764             :             "LG_MSF_combine_fp", COMBINE_FP)) ;
     765             : 
     766           7 :         GRB_TRY (GxB_Scalar_setElement_FP64(max_weight, INFINITY)) ;
     767             : 
     768           7 :         GRB_TRY (GxB_BinaryOp_new (
     769             :             &tupleMin, (GxB_binary_function) LG_MSF_tupleMin_fp,
     770             :             tuple, tuple, tuple,
     771             :             "LG_MSF_tupleMin_fp", TUPLEMIN_FP)) ;
     772             : 
     773           7 :         GRB_TRY (GxB_BinaryOp_new (
     774             :             &tuple2nd, (GxB_binary_function) LG_MSF_tuple2nd_fp,
     775             :             tuple, GrB_BOOL, tuple,
     776             :             "LG_MSF_tuple2nd_fp", TUPLE2ND_FP)) ;
     777             : 
     778           7 :         GRB_TRY (GxB_BinaryOp_new (
     779             :             &tupleEq, (GxB_binary_function) LG_MSF_tupleEq_fp,
     780             :             GrB_BOOL, tuple, tuple,
     781             :             "LG_MSF_tupleEq_fp", TUPLEEQ_FP)) ;
     782             : 
     783           7 :         inf = (void *) (&inf_fp) ;
     784             : 
     785           7 :         GRB_TRY (GxB_UnaryOp_new (
     786             :             &get_first, (GxB_unary_function) LG_MSF_get_first_fp, weight_type, 
     787             :             tuple, "LG_MSF_get_first_fp", GET_FIRST_FP)) ;
     788             : 
     789           7 :         GRB_TRY (GxB_UnaryOp_new (
     790             :             &get_second, (GxB_unary_function) LG_MSF_get_second_fp, GrB_UINT64, 
     791             :             tuple, "LG_MSF_get_second_fp", GET_SECOND_FP)) ;
     792             : 
     793           7 :         GRB_TRY (GxB_Type_new (
     794             :             &context_type, sizeof (LG_MSF_context_fp),
     795             :             "LG_MSF_context_fp", LG_MSF_CONTEXT_FP)) ;
     796             : 
     797             :         // ops for GrB_select
     798           7 :         GRB_TRY(GxB_IndexUnaryOp_new (
     799             :             &selectEdge, (GxB_index_unary_function) LG_MSF_selectEdge_fp, 
     800             :             GrB_BOOL, weight_type, context_type,
     801             :             "LG_MSF_selectEdge_fp", SELECTEDGE_FP)) ;
     802             : 
     803           7 :         GRB_TRY(GxB_IndexUnaryOp_new (
     804             :             &removeEdge, (void *) LG_MSF_removeEdge_fp, GrB_BOOL, weight_type, 
     805             :             context_type, "LG_MSF_removeEdge_fp", REMOVEEDGE_FP)) ;
     806             :     }
     807             : 
     808          26 :     GRB_TRY (GrB_Monoid_new_UDT (&tupleMin_monoid, tupleMin, inf)) ;
     809          26 :     GRB_TRY (GrB_Semiring_new (&minComb, tupleMin_monoid, combine)) ;
     810          26 :     GRB_TRY (GrB_Semiring_new (&tupleMin2nd, tupleMin_monoid, tuple2nd)) ;
     811             : 
     812             :     //--------------------------------------------------------------------------
     813             :     // create matrices and vectors
     814             :     //--------------------------------------------------------------------------
     815             : 
     816          26 :     GRB_TRY (GrB_Matrix_new (&S, weight_type, n, n)) ;
     817             : 
     818          26 :     if (sanitize)
     819             :     {
     820             :         // S = A+A', and typecasting to weight_type
     821           6 :         GRB_TRY (GrB_Matrix_eWiseAdd_BinaryOp
     822             :             (S, NULL, NULL, min_weight, A, A, GrB_DESC_T1)) ;
     823             :     }
     824             :     else
     825             :     {
     826             :         // S = A, typecasting to weight_type, if necessary 
     827          20 :         GRB_TRY (GrB_Matrix_assign
     828             :                 (S, NULL, NULL, A, GrB_ALL, n, GrB_ALL, n, NULL)) ;
     829             :     }
     830             : 
     831          26 :     GRB_TRY (GrB_Matrix_new (&T, weight_type, n, n)) ;
     832          26 :     GRB_TRY (GrB_Vector_new (&w, weight_type, n)) ;
     833          26 :     GRB_TRY (GrB_Vector_new (&t, GrB_UINT64, n)) ;
     834          26 :     GRB_TRY (GrB_Vector_new (&f, GrB_UINT64, n)) ;
     835          26 :     GRB_TRY (GrB_Vector_new (&ramp, GrB_INT64, n + 1)) ;
     836          26 :     GRB_TRY (GrB_Vector_new (&edge, tuple, n)) ;
     837          26 :     GRB_TRY (GrB_Vector_new (&cedge, tuple, n)) ;
     838          26 :     GRB_TRY (GrB_Vector_new (&tedge, tuple, n)) ;
     839          26 :     GRB_TRY (GrB_Vector_new (&mask, GrB_BOOL, n)) ;
     840          26 :     GRB_TRY (GrB_Vector_new (&index_v, GrB_UINT64, n)) ;
     841          26 :     GRB_TRY (GrB_Vector_new (&parent_v, GrB_UINT64, n)) ;
     842             : 
     843          26 :     LG_TRY (LAGraph_Malloc  ((void **) &SI, 2*n, sizeof (GrB_Index), msg)) ;
     844          26 :     LG_TRY (LAGraph_Malloc  ((void **) &SJ, 2*n, sizeof (GrB_Index), msg)) ;
     845          26 :     LG_TRY (LAGraph_Malloc  (&SX, 2*n, sx_size, msg)) ;
     846             : 
     847             :     // prepare vectors
     848          26 :     GRB_TRY (GrB_Vector_assign_UINT64 (
     849             :         f, NULL, NULL, (uint64_t) 0, GrB_ALL, n, NULL)) ;
     850          26 :     GRB_TRY (GrB_Vector_apply_IndexOp_INT64 (
     851             :         f, NULL, NULL, GrB_ROWINDEX_INT64, f, (int64_t) 0, NULL)) ;
     852          26 :     GRB_TRY (GrB_Vector_dup (&I, f)) ;
     853          26 :     GRB_TRY (GrB_Vector_assign_UINT64 (
     854             :         ramp, NULL, NULL, (uint64_t) 0, GrB_ALL, n + 1, NULL)) ;
     855          26 :     GRB_TRY (GrB_Vector_apply_IndexOp_INT64 (
     856             :         ramp, NULL, NULL, GrB_ROWINDEX_INT64, ramp, (int64_t) 0, NULL)) ;
     857             : 
     858             :     // create context
     859          26 :     if (weight_type == GrB_INT64)
     860             :     {
     861          19 :         LG_TRY (LAGraph_Malloc
     862             :             ((void **) &context_int.parent, n, sizeof (uint64_t), msg)) ;
     863          19 :         GRB_TRY (GrB_Vector_extractTuples (NULL, context_int.parent, &n, f)) ;
     864          19 :         GRB_TRY (GxB_Vector_load(parent_v, (void **) &context_int.parent,
     865             :             GrB_UINT64, n, n * sizeof (uint64_t), GxB_IS_READONLY, NULL)) ;
     866             :     }
     867             :     else
     868             :     {
     869           7 :         LG_TRY (LAGraph_Malloc
     870             :             ((void **) &context_fp.parent, n, sizeof (double), msg)) ;
     871           7 :         GRB_TRY (GrB_Vector_extractTuples (NULL, context_fp.parent, &n, f)) ;
     872           7 :         GRB_TRY (GxB_Vector_load(parent_v, (void **) &context_fp.parent,
     873             :             GrB_UINT64, n,  n * sizeof (double), GxB_IS_READONLY, NULL)) ;
     874             :     }
     875             : 
     876             :     //--------------------------------------------------------------------------
     877             :     // the main computation
     878             :     //--------------------------------------------------------------------------
     879             : 
     880          26 :     GrB_Index nvals, ntuples = 0, num;
     881          26 :     bool diff = false;
     882          26 :     GRB_TRY (GrB_Matrix_nvals (&nvals, S)) ;
     883          76 :     for (int iters = 1; nvals > 0; iters++)
     884             :     {
     885             :         // every vertex points to a root vertex at the beginning
     886             :         // edge[u] = u's minimum edge (weight and index are encoded together)
     887          50 :         GRB_TRY (GrB_Vector_assign_UDT (
     888             :             edge, NULL, NULL, inf, GrB_ALL, 0, NULL)) ;
     889             : 
     890             :         // each edge looks at its adjacent edges and picks the one with the 
     891             :         // minimum weight. This weight is put into a tuple with the 
     892             :         // representative value of the connected componect the edge connects to
     893          50 :         GRB_TRY (GrB_mxv (edge, NULL, tupleMin, minComb, S, f, NULL)) ;
     894             : 
     895             :         // cedge[u] = children's minimum edge  | if u is a root
     896             :         //          = (max_weight, u)          | otherwise
     897          50 :         GRB_TRY (GrB_Vector_apply_BinaryOp1st_Scalar (
     898             :             cedge, NULL, NULL, combine, max_weight, I, NULL)) ;
     899          50 :         LG_TRY (LAGraph_FastAssign_Semiring(
     900             :             cedge, NULL, tupleMin, parent_v, edge, ramp, tupleMin2nd, NULL, msg
     901             :         )) ;
     902             : 
     903             :         // if (f[u] == u) f[u] := get_second(cedge[u])  -- the index
     904          50 :         GRB_TRY (GrB_eWiseMult (mask, NULL, NULL, GrB_EQ_UINT64, f, I, NULL)) ;
     905          50 :         GRB_TRY (GrB_apply (
     906             :             f, mask, GrB_SECOND_UINT64, get_second, cedge, NULL)) ;
     907             : 
     908             :         // identify all the vertex pairs (u, v) where f[u] == v and f[v] == u
     909             :         // and then select the minimum of u, v as the new root;
     910             :         // if (f[f[i]] == i) f[i] = min(f[i], i)
     911          50 :         GRB_TRY (GxB_Vector_extract_Vector (t, NULL, NULL, f, f, NULL)) ;
     912          50 :         GRB_TRY (GrB_eWiseMult (mask, NULL, NULL, GrB_EQ_UINT64, I, t, NULL)) ;
     913          50 :         GRB_TRY (GrB_assign (f, mask, GrB_MIN_UINT64, I, GrB_ALL, 0, NULL)) ;
     914             : 
     915             :         // five steps to generate the solution
     916             :         // 1. new roots (f[i] == i) revise their entries in cedge
     917          50 :         GRB_TRY (GrB_eWiseMult (mask, NULL, NULL, GrB_EQ_UINT64, I, f, NULL)) ;
     918          50 :         GRB_TRY (GrB_assign (cedge, mask, NULL, inf, GrB_ALL, 0, NULL)) ;
     919             : 
     920             :         // 2. every vertex tries to know whether one of its edges is selected
     921          50 :         GRB_TRY (GxB_Vector_extract_Vector (
     922             :             tedge, NULL, NULL, cedge, parent_v, NULL)) ;
     923          50 :         GRB_TRY (GrB_eWiseMult (mask ,NULL, NULL, tupleEq, edge, tedge, NULL)) ;
     924             : 
     925             :         // 3. each root picks a vertex from its children to 
     926             :         // generate the solution
     927          50 :         GRB_TRY (GrB_assign (index_v, NULL, NULL, n, GrB_ALL, 0, NULL)) ;
     928          50 :         GRB_TRY (GrB_assign (index_v, mask, NULL, I, GrB_ALL, 0, NULL)) ;
     929          50 :         GRB_TRY (GrB_assign (t, NULL, NULL, n, GrB_ALL, 0, NULL)) ;
     930          50 :         LG_TRY (LAGraph_FastAssign_Semiring(
     931             :             t, NULL, GrB_MIN_UINT64, parent_v, index_v, ramp,
     932             :             GrB_MIN_SECOND_SEMIRING_UINT64, NULL, msg
     933             :         )) ;
     934          50 :         GRB_TRY (GxB_Vector_extract_Vector (
     935             :             index_v, NULL, NULL, t, parent_v, NULL)) ;
     936          50 :         GRB_TRY (GrB_eWiseMult (
     937             :             mask ,NULL, NULL, GrB_EQ_UINT64, I, index_v, NULL)) ;
     938             : 
     939             :         // 4. generate the select function
     940          50 :         if (weight_type == GrB_INT64)
     941             :         {
     942          28 :             GRB_TRY (GxB_Vector_unload(
     943             :                 edge, (void **) &context_int.w_partner, &ignore, &edge_n,
     944             :                 &edge_size, &edge_handling, NULL)) ;
     945          28 :             GRB_TRY (GrB_Matrix_select_UDT (T, NULL, NULL, selectEdge, S,
     946             :                 &context_int, NULL)) ;
     947          28 :             GRB_TRY (GxB_Vector_load(
     948             :                 edge, (void **) &context_int.w_partner, tuple, edge_n,
     949             :                 edge_size, edge_handling, NULL)) ;
     950             :         }
     951             :         else
     952             :         {
     953          22 :             GRB_TRY (GxB_Vector_unload(
     954             :                 edge, (void **) &context_fp.w_partner, &ignore, &edge_n, 
     955             :                 &edge_size, &edge_handling, NULL)) ;
     956          22 :             GRB_TRY (GrB_Matrix_select_UDT (
     957             :                 T, NULL, NULL, selectEdge, S, &context_fp, NULL)) ;
     958          22 :             GRB_TRY (GxB_Vector_load(
     959             :                 edge, (void **) &context_fp.w_partner, tuple, edge_n, edge_size,
     960             :                 edge_handling, NULL)) ;
     961             :         }
     962             : 
     963          50 :         GRB_TRY (GrB_Vector_clear (t)) ;
     964             : 
     965             :         // 5. the generated matrix may still have redundant edges remove the 
     966             :         //  duplicates by GrB_mxv and store them as tuples in (SI,SJ,SX)
     967          50 :         GRB_TRY (GrB_Vector_clear (edge)) ;
     968          50 :         GRB_TRY (GrB_mxv (edge, mask, tupleMin, minComb, T, I, NULL)) ;
     969          50 :         GRB_TRY (GrB_Vector_nvals (&num, edge)) ;
     970          50 :         GRB_TRY (GrB_apply (t, NULL, NULL, get_second, edge, NULL)) ;
     971          50 :         GRB_TRY (GrB_Vector_extractTuples (NULL, SJ + ntuples, &num, t)) ;
     972          50 :         GRB_TRY (GrB_apply (w, NULL, NULL, get_first, edge, NULL)) ;
     973             : 
     974          50 :         if (weight_type == GrB_INT64)
     975             :         {
     976          28 :             GRB_TRY (GrB_Vector_extractTuples_INT64 (
     977             :                 SI + ntuples, ((int64_t *) SX) + ntuples, &num, w)) ;
     978             :         }
     979             :         else
     980             :         {
     981          22 :             GRB_TRY (GrB_Vector_extractTuples_FP64 (
     982             :                 SI + ntuples, ((double *) SX) + ntuples, &num, w)) ;
     983             :         }
     984             : 
     985          50 :         ntuples += num;
     986             : 
     987             :         // path halving until every vertex points on a root
     988             :         do {
     989         152 :             GRB_TRY (GxB_Vector_extract_Vector (t, NULL, NULL, f, f, NULL)) ;
     990         152 :             GRB_TRY (GrB_eWiseMult (mask, NULL, NULL, GrB_NE_UINT64, f, t, NULL)) ;
     991         152 :             GRB_TRY (GrB_Vector_reduce_BOOL (&diff, NULL, GrB_LOR_MONOID_BOOL, mask, NULL)) ;
     992         152 :             GrB_Vector temp = f; f = t; t = temp;
     993         152 :         } while (diff);
     994             : 
     995             :         // remove the edges in the same connected component
     996          50 :         if (weight_type == GrB_INT64)
     997             :         {
     998          28 :             GRB_TRY (GrB_Vector_extractTuples (NULL, context_int.parent, &n, f)) ;
     999          28 :             GRB_TRY (GrB_Matrix_select_UDT (S, NULL, NULL, removeEdge, S, &context_int, NULL)) ;
    1000             :         }
    1001             :         else
    1002             :         {
    1003          22 :             GRB_TRY (GrB_Vector_extractTuples (NULL, context_fp.parent, &n, f)) ;
    1004          22 :             GRB_TRY (GrB_Matrix_select_UDT (S, NULL, NULL, removeEdge, S, &context_fp, NULL)) ;
    1005             :         }
    1006             : 
    1007          50 :         GrB_Matrix_nvals (&nvals, S);
    1008             :     }
    1009             : 
    1010             :     // create forest_edges
    1011          26 :     GRB_TRY (GrB_Matrix_clear (T)) ;
    1012          26 :     if (weight_type == GrB_INT64)
    1013             :     {
    1014          19 :         GRB_TRY (GrB_Matrix_build_INT64 (
    1015             :             T, SI, SJ, (int64_t *) SX, ntuples, GxB_IGNORE_DUP)) ;
    1016             :     }
    1017             :     else
    1018             :     {
    1019           7 :         GRB_TRY (GrB_Matrix_build_FP64 (
    1020             :             T, SI, SJ, (double *) SX, ntuples, GxB_IGNORE_DUP)) ;
    1021             :     }
    1022             : 
    1023             :     //--------------------------------------------------------------------------
    1024             :     // free workspace and return result
    1025             :     //--------------------------------------------------------------------------
    1026             : 
    1027          26 :     *forest_edges = T;
    1028          26 :     T = NULL ;
    1029             : 
    1030          26 :     if(componentId != NULL)
    1031             :     {
    1032          24 :         *componentId = f;
    1033          24 :         f = NULL;
    1034             :     }
    1035             : 
    1036          26 :     LG_FREE_ALL;
    1037          26 :     return (GrB_SUCCESS) ;
    1038             :     #else
    1039             :     return (GrB_NOT_IMPLEMENTED) ;
    1040             :     #endif
    1041             : }

Generated by: LCOV version 1.14