LCOV - code coverage report
Current view: top level - experimental/algorithm - LAGraph_AllKTruss.c (source / functions) Hit Total Coverage
Test: LAGraph code coverage report. Commit id: 7b9d2ee. Current time (UTC): 2025-06-03T21:57:17Z Lines: 45 45 100.0 %
Date: 2025-06-03 22:02:40 Functions: 1 1 100.0 %

          Line data    Source code
       1             : //------------------------------------------------------------------------------
       2             : // LAGraph_AllKTruss.c: find all k-trusses of a graph
       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             : // LAGraph_AllKTruss: find all k-trusses of a graph via GraphBLAS.
      19             : 
      20             : // Given a symmetric graph A with no-self edges, LAGraph_AllKTruss finds all
      21             : // k-trusses of A.
      22             : 
      23             : // The output matrices Cset [3..kmax-1] are the k-trusses of A.  Their edges
      24             : // are a subset of A.  Each edge in C = Cset [k] is part of at least k-2
      25             : // triangles in C.  The structure of C is the adjacency matrix of the k-truss
      26             : // subgraph of A.  The edge weights of C are the support of each edge.  That
      27             : // is, C(i,j)=nt if the edge (i,j) is part of nt triangles in C.  All edges in
      28             : // C have support of at least k-2.  The total number of triangles in C is
      29             : // sum(C)/6.  The number of edges in C is nnz(C)/2.  C = Cset [k] is returned
      30             : // as symmetric with a zero-free diagonal.  Cset [kmax] is an empty matrix
      31             : // since the kmax-truss is empty.
      32             : 
      33             : // The arrays ntris, nedges, and nstepss hold the output statistics.
      34             : // ntris   [k] = # of triangles in the k-truss
      35             : // nedges  [k] = # of edges in the k-truss
      36             : // nstepss [k] = # of steps required to compute the k-truss
      37             : 
      38             : // Usage: constructs all k-trusses of A, for k = 3:kmax
      39             : 
      40             : //      int64_t kmax ;
      41             : //      GrB_Matrix_nrows (&n, A) ;
      42             : //      GrB_Matrix *Cset = array of size max(n,4)
      43             : //      int64_t *ntris   = array of size max(n,4)
      44             : //      int64_t *nedges  = array of size max(n,4)
      45             : //      int64_t *nstepss = array of size max(n,4)
      46             : //      int result = LAGraph_AllKTruss (&Cset, &kmax, ntris, nedges,
      47             : //          nstepss, G, msg) ;
      48             : 
      49             : // todo: add experimental/benchmark/ktruss_demo.c to benchmark k-truss
      50             : // and all-k-truss
      51             : 
      52             : // todo: consider LAGraph_KTrussNext to compute the (k+1)-truss from the
      53             : // k-truss
      54             : 
      55             : // TODO: ready for src
      56             : 
      57             : #define LG_FREE_ALL                         \
      58             : {                                           \
      59             :     for (int64_t kk = 3 ; kk <= k ; kk++)   \
      60             :     {                                       \
      61             :         GrB_free (&(Cset [kk])) ;           \
      62             :     }                                       \
      63             : }
      64             : 
      65             : #include "LG_internal.h"
      66             : #include "LAGraphX.h"
      67             : 
      68             : //------------------------------------------------------------------------------
      69             : // C = LAGraph_AllKTruss: find all k-trusses a graph
      70             : //------------------------------------------------------------------------------
      71             : 
      72          22 : int LAGraph_AllKTruss   // compute all k-trusses of a graph
      73             : (
      74             :     // outputs
      75             :     GrB_Matrix *Cset,   // size n, output k-truss subgraphs
      76             :     int64_t *kmax,      // smallest k where k-truss is empty
      77             :     int64_t *ntris,     // size max(n,4), ntris [k] is #triangles in k-truss
      78             :     int64_t *nedges,    // size max(n,4), nedges [k] is #edges in k-truss
      79             :     int64_t *nstepss,   // size max(n,4), nstepss [k] is #steps for k-truss
      80             :     // input
      81             :     LAGraph_Graph G,    // input graph
      82             :     char *msg
      83             : )
      84             : {
      85             : 
      86             :     //--------------------------------------------------------------------------
      87             :     // check inputs
      88             :     //--------------------------------------------------------------------------
      89             : 
      90          22 :     LG_CLEAR_MSG ;
      91          22 :     int64_t k = 0 ;
      92          22 :     LG_ASSERT (Cset != NULL && nstepss != NULL, GrB_NULL_POINTER) ;
      93          22 :     LG_ASSERT (kmax != NULL && ntris != NULL, GrB_NULL_POINTER) ;
      94          21 :     LG_ASSERT (nedges != NULL, GrB_NULL_POINTER) ;
      95          21 :     LG_TRY (LAGraph_CheckGraph (G, msg)) ;
      96             : 
      97          20 :     if (G->kind == LAGraph_ADJACENCY_UNDIRECTED ||
      98          10 :        (G->kind == LAGraph_ADJACENCY_DIRECTED &&
      99          10 :         G->is_symmetric_structure == LAGraph_TRUE))
     100             :     {
     101             :         // the structure of A is known to be symmetric
     102             :         ;
     103             :     }
     104             :     else
     105             :     {
     106             :         // A is not known to be symmetric
     107           1 :         LG_ASSERT_MSG (false, -1005, "G->A must be symmetric") ;
     108             :     }
     109             : 
     110             :     // no self edges can be present
     111          19 :     LG_ASSERT_MSG (G->nself_edges == 0, -1004, "G->nself_edges must be zero") ;
     112             : 
     113             :     //--------------------------------------------------------------------------
     114             :     // initializations
     115             :     //--------------------------------------------------------------------------
     116             : 
     117          90 :     for (k = 0 ; k <= 3 ; k++)
     118             :     {
     119          72 :         Cset [k] = NULL ;
     120          72 :         ntris   [k] = 0 ;
     121          72 :         nedges  [k] = 0 ;
     122          72 :         nstepss [k] = 0 ;
     123             :     }
     124          18 :     k = 3 ;
     125          18 :     (*kmax) = 0 ;
     126             : 
     127             :     //--------------------------------------------------------------------------
     128             :     // initialzations
     129             :     //--------------------------------------------------------------------------
     130             : 
     131             :     GrB_Index n ;
     132          18 :     GrB_Matrix S = G->A ;
     133          18 :     GRB_TRY (GrB_Matrix_nrows (&n, S)) ;
     134          18 :     GRB_TRY (GrB_Matrix_new (&(Cset [k]), GrB_UINT32, n, n)) ;
     135          18 :     GrB_Matrix C = Cset [k] ;
     136             :     GrB_Index nvals, nvals_last ;
     137          18 :     GRB_TRY (GrB_Matrix_nvals (&nvals_last, S)) ;
     138          18 :     int64_t nsteps = 0 ;
     139             : 
     140             :     //--------------------------------------------------------------------------
     141             :     // find all k-trusses
     142             :     //--------------------------------------------------------------------------
     143             : 
     144             :     #if 0
     145             :     int mtx = 0 ;
     146             :     #endif
     147             : 
     148             :     while (true)
     149             :     {
     150             :         #if 0
     151             :         // dump the matrix S to a file
     152             :         uint64_t snvals ;
     153             :         GRB_TRY (GrB_Matrix_nvals (&snvals, S)) ;
     154             :         char filename [2000] ;
     155             :         sprintf (filename, "mtx_%04d.mtx", mtx) ;
     156             :         FILE *f = fopen (filename, "w") ;
     157             :         printf ("%s: with %" PRId64 " values\n", filename, snvals) ;
     158             :         LAGraph_MMWrite (S, f, NULL, msg) ;
     159             :         fclose (f) ;
     160             :         mtx++ ;
     161             :         #endif
     162             : 
     163             :         // C{S} = S*S'
     164         434 :         GRB_TRY (GrB_mxm (C, S, NULL, LAGraph_plus_one_uint32, S, S,
     165             :             GrB_DESC_RST1)) ;
     166             :         // keep entries in C that are >= k-2
     167         434 :         GRB_TRY (GrB_select (C, NULL, NULL, GrB_VALUEGE_UINT32, C, k-2, NULL)) ;
     168         434 :         nsteps++ ;
     169             :         // check if k-truss has been found
     170         434 :         GRB_TRY (GrB_Matrix_nvals (&nvals, C)) ;
     171         434 :         if (nvals == nvals_last)
     172             :         {
     173             :             // k-truss has been found
     174          96 :             int64_t nt = 0 ;
     175         114 :             GRB_TRY (GrB_reduce (&nt, NULL, GrB_PLUS_MONOID_INT64, C, NULL)) ;
     176          96 :             ntris   [k] = nt / 6 ;
     177          96 :             nedges  [k] = nvals / 2 ;
     178          96 :             nstepss [k] = nsteps ;
     179          96 :             nsteps = 0 ;
     180          96 :             if (nvals == 0)
     181             :             {
     182             :                 // this is the last k-truss
     183          18 :                 (*kmax) = k ;
     184          18 :                 return (GrB_SUCCESS) ;
     185             :             }
     186          78 :             S = C ;             // S = current k-truss for k+1 iteration
     187          78 :             k++ ;               // advance to the next k-tryss
     188          78 :             GRB_TRY (GrB_Matrix_new (&(Cset [k]), GrB_UINT32, n, n)) ;
     189          78 :             C = Cset [k] ;      // C = new matrix for next k-truss
     190             :         }
     191             :         else
     192             :         {
     193             :             // advance to the next step, still computing the current k-truss
     194         338 :             nvals_last = nvals ;
     195         338 :             S = C ;
     196             :         }
     197             :     }
     198             : }

Generated by: LCOV version 1.14