File: LG_check_ktruss.c

package info (click to toggle)
suitesparse 1%3A7.10.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 254,920 kB
  • sloc: ansic: 1,134,743; cpp: 46,133; makefile: 4,875; fortran: 2,087; java: 1,826; sh: 996; ruby: 725; python: 495; asm: 371; sed: 166; awk: 44
file content (180 lines) | stat: -rw-r--r-- 6,772 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
//------------------------------------------------------------------------------
// LG_check_ktruss: construct the ktruss of a graph (simple method)
//------------------------------------------------------------------------------

// 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 Timothy A. Davis, Texas A&M University

//------------------------------------------------------------------------------

// A very slow, bare-bones ktruss method.  This method is for testing only, to
// check the result of other, faster methods.  Do not benchmark this method; it
// is slow and simple by design.  G->A must be symmetric, with no entries on
// its diagonal.

#define LG_FREE_WORK                            \
{                                               \
    LAGraph_Free ((void **) &Cp, NULL) ;        \
    LAGraph_Free ((void **) &Cj, NULL) ;        \
    LAGraph_Free ((void **) &Cx, NULL) ;        \
    LAGraph_Free ((void **) &Ax, NULL) ;        \
}

#define LG_FREE_ALL                             \
{                                               \
    LG_FREE_WORK ;                              \
    GrB_free (&C) ;                             \
}

#include "LG_internal.h"
#include "LG_test.h"

int LG_check_ktruss
(
    // output
    GrB_Matrix *C_handle,   // the ktruss of G->A, of type GrB_UINT32
    // input
    LAGraph_Graph G,        // the structure of G->A must be symmetric
    uint32_t k,
    char *msg
)
{

    //--------------------------------------------------------------------------
    // check inputs
    //--------------------------------------------------------------------------

    LG_CLEAR_MSG ;

    GrB_Matrix C = NULL ;
    GrB_Index *Cp = NULL, *Cj = NULL ;
    uint32_t *Cx = NULL ;
    void *Ax = NULL ;
    GrB_Index n, ncols, Cp_len, Cj_len, Cx_len, nvals1, nvals2 ;
    LG_ASSERT (C_handle != NULL, GrB_NULL_POINTER) ;
    LG_TRY (LAGraph_CheckGraph (G, msg)) ;
    LG_ASSERT_MSG (G->nself_edges == 0, -104, "G->nself_edges must be zero") ;
    if (G->kind == LAGraph_ADJACENCY_UNDIRECTED ||
       (G->kind == LAGraph_ADJACENCY_DIRECTED &&
        G->is_symmetric_structure == LAGraph_TRUE))
    {
        // the structure of A is known to be symmetric
        ;
    }
    else
    {
        // A is not known to be symmetric
        LG_ASSERT_MSG (false, -1005, "G->A must be symmetric") ;
    }
    GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ;
    GRB_TRY (GrB_Matrix_ncols (&ncols, G->A)) ;
    LG_ASSERT_MSG (n == ncols, -1001, "A must be square") ;

    //--------------------------------------------------------------------------
    // export G->A in CSR form and discard its values
    //--------------------------------------------------------------------------

    size_t typesize ;
    LG_TRY (LG_check_export (G, &Cp, &Cj, &Ax, &Cp_len, &Cj_len, &Cx_len,
        &typesize, msg)) ;
    LAGraph_Free ((void **) &Ax, NULL) ;

    //--------------------------------------------------------------------------
    // allocate Cx
    //--------------------------------------------------------------------------

    LG_TRY (LAGraph_Malloc ((void **) &Cx, Cx_len, sizeof (uint32_t), msg)) ;

    //--------------------------------------------------------------------------
    // construct the k-truss of G->A
    //--------------------------------------------------------------------------

    while (true)
    {

        //----------------------------------------------------------------------
        // compute the # of triangles incident on each edge of C
        //----------------------------------------------------------------------

        // masked dot-product method: C{C}=C*C' using the PLUS_ONE semiring
        int64_t i;
        #if !defined ( COVERAGE )
        #pragma omp parallel for schedule(dynamic,1024)
        #endif
        for (i = 0 ; i < n ; i++)
        {
            // for each entry in C(i,:)
            for (int64_t p = Cp [i] ; p < Cp [i+1] ; p++)
            {
                const int64_t j = Cj [p] ;
                uint32_t cij = 0 ;
                // cij += C(i,:) * C(j,:)'
                int64_t p1 = Cp [i] ;
                int64_t p1_end = Cp [i+1] ;
                int64_t p2 = Cp [j] ;
                int64_t p2_end = Cp [j+1] ;
                while (p1 < p1_end && p2 < p2_end)
                {
                    int64_t j1 = Cj [p1] ;
                    int64_t j2 = Cj [p2] ;
                    if (j1 < j2)
                    {
                        // C(i,j1) appears before C(j,j2)
                        p1++ ;
                    }
                    else if (j2 < j1)
                    {
                        // C(j,j2) appears before C(i,j1)
                        p2++ ;
                    }
                    else // j1 == j2
                    {
                        // C(i,j1) and C(j,j1) are the next entries to merge
                        cij++ ;
                        p1++ ;
                        p2++ ;
                    }
                }
                Cx [p] = cij ;
            }
        }

        //----------------------------------------------------------------------
        // import C in CSR form
        //----------------------------------------------------------------------

        GRB_TRY (GrB_Matrix_import_UINT32 (&C, GrB_UINT32, n, n,
            Cp, Cj, Cx, Cp_len, Cj_len, Cx_len, GrB_CSR_FORMAT)) ;
        GRB_TRY (GrB_Matrix_nvals (&nvals1, C)) ;

        //----------------------------------------------------------------------
        // keep entries >= k-2 and check for convergence
        //----------------------------------------------------------------------

        GRB_TRY (GrB_select (C, NULL, NULL, GrB_VALUEGE_UINT32, C, k-2, NULL)) ;
        GRB_TRY (GrB_Matrix_nvals (&nvals2, C)) ;
        if (nvals1 == nvals2)
        {
            // C is now the k-truss of G->A
            LG_FREE_WORK ;
            (*C_handle) = C ;
            return (GrB_SUCCESS) ;
        }

        //----------------------------------------------------------------------
        // export C in CSR form for the next iteration and free it
        //----------------------------------------------------------------------

        GRB_TRY (GrB_Matrix_export_UINT32 (Cp, Cj, Cx,
            &Cp_len, &Cj_len, &Cx_len, GrB_CSR_FORMAT, C)) ;
        GRB_TRY (GrB_free (&C)) ;
    }
}