From cca09541a62171282ee4401d9c037cea1c238340 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Thu, 24 Mar 2022 11:42:07 -0500 Subject: [PATCH 01/53] first cut for cuda branch; use rmm_wrap in LAGr_Init --- src/benchmark/LAGraph_demo.h | 7 ++++++- src/benchmark/tc_demo.c | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/benchmark/LAGraph_demo.h b/src/benchmark/LAGraph_demo.h index e42edfc74a..5b87795c18 100644 --- a/src/benchmark/LAGraph_demo.h +++ b/src/benchmark/LAGraph_demo.h @@ -1107,7 +1107,12 @@ static inline int demo_init (bool burble) mallopt (M_TOP_PAD, 16*1024*1024) ; // increase padding to speedup malloc #endif - LAGRAPH_TRY (LAGraph_Init (NULL)) ; + // LAGRAPH_TRY (LAGraph_Init (NULL)) ; + // rmm_wrap_initialize (rmm_wrap_managed, INT32_MAX, INT64_MAX) ; + rmm_wrap_initialize (rmm_wrap_managed, 256 * 1000000L, 256 * 100000000L) ; + LAGRAPH_TRY (LAGr_Init (rmm_wrap_malloc, rmm_wrap_calloc, rmm_wrap_realloc, rmm_wrap_free, NULL)) ; + GxB_set (GxB_GPU_CONTROL, GxB_GPU_ALWAYS) ; + #if LAGRAPH_SUITESPARSE printf ("include: %s v%d.%d.%d [%s]\n", GxB_IMPLEMENTATION_NAME, diff --git a/src/benchmark/tc_demo.c b/src/benchmark/tc_demo.c index 6176ecc1ae..cc6161d2a5 100644 --- a/src/benchmark/tc_demo.c +++ b/src/benchmark/tc_demo.c @@ -254,6 +254,8 @@ int main (int argc, char **argv) nthreads_best, t_best, 1e-6 * nvals / t_best) ; LG_FREE_ALL ; LAGRAPH_TRY (LAGraph_Finalize (msg)) ; + // FIXME: + rmm_wrap_finalize ( ) ; return (GrB_SUCCESS) ; } From 4d78a2fcd5be1f28b229926462d4b47cae2f45dd Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Thu, 24 Mar 2022 12:30:38 -0500 Subject: [PATCH 02/53] force G->A to be non-iso --- src/benchmark/tc_demo.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/benchmark/tc_demo.c b/src/benchmark/tc_demo.c index cc6161d2a5..4461615f65 100644 --- a/src/benchmark/tc_demo.c +++ b/src/benchmark/tc_demo.c @@ -126,6 +126,12 @@ int main (int argc, char **argv) GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; GRB_TRY (GrB_Matrix_nvals (&nvals, G->A)) ; + GxB_print (G->A, 3) ; + GRB_TRY (GrB_Matrix_setElement (G->A, 0, 2, 2)) ; + GxB_print (G->A, 3) ; + GrB_wait (G->A, GrB_MATERIALIZE) ; + GxB_print (G->A, 3) ; + //-------------------------------------------------------------------------- // triangle counting //-------------------------------------------------------------------------- From dc68622f3820df3be8fa263b26091210fb464e5a Mon Sep 17 00:00:00 2001 From: "Corey J. Nolet" Date: Thu, 31 Mar 2022 10:26:21 -0400 Subject: [PATCH 03/53] Udpates to triangle count to force non-iso inputs --- src/algorithm/LAGr_TriangleCount.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/algorithm/LAGr_TriangleCount.c b/src/algorithm/LAGr_TriangleCount.c index b188c208cf..b070207d36 100644 --- a/src/algorithm/LAGr_TriangleCount.c +++ b/src/algorithm/LAGr_TriangleCount.c @@ -75,6 +75,9 @@ static int tricount_prep GRB_TRY (GrB_Matrix_new (L, GrB_BOOL, n, n)) ; GRB_TRY (GrB_select (*L, NULL, NULL, GrB_TRIL, A, (int64_t) (-1), NULL)) ; + GRB_TRY(GrB_Matrix_setElement(*L, false, 0, 0)); + GRB_TRY (GrB_Matrix_wait (*L, GrB_MATERIALIZE)) ; + GRB_TRY (GxB_Matrix_fprint (*L, "L", GxB_COMPLETE, stdout)) ; } if (U != NULL) @@ -82,6 +85,9 @@ static int tricount_prep // U = triu (A,1) GRB_TRY (GrB_Matrix_new (U, GrB_BOOL, n, n)) ; GRB_TRY (GrB_select (*U, NULL, NULL, GrB_TRIU, A, (int64_t) 1, NULL)) ; + GRB_TRY(GrB_Matrix_setElement(*U, 0, 0, 0)); + GRB_TRY (GrB_Matrix_wait (*U, GrB_MATERIALIZE)) ; + GRB_TRY (GxB_Matrix_fprint (*U, "U", GxB_COMPLETE, stdout)) ; } return (GrB_SUCCESS) ; } @@ -177,7 +183,7 @@ int LAGr_TriangleCount GrB_Index n ; GRB_TRY (GrB_Matrix_nrows (&n, A)) ; GRB_TRY (GrB_Matrix_new (&C, GrB_INT64, n, n)) ; - GrB_Semiring semiring = LAGraph_plus_one_int64 ; + GrB_Semiring semiring = GxB_PLUS_PAIR_INT64; //LAGraph_plus_one_int64 ; GrB_Monoid monoid = GrB_PLUS_MONOID_INT64 ; //-------------------------------------------------------------------------- @@ -292,6 +298,8 @@ int LAGr_TriangleCount // using the masked saxpy3 method LG_TRY (tricount_prep (&L, NULL, A, msg)) ; GRB_TRY (GrB_mxm (C, L, NULL, semiring, L, L, GrB_DESC_S)) ; + GRB_TRY (GxB_Matrix_fprint (C, "my mat", GxB_COMPLETE, stdout)) ; + GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; break ; @@ -300,6 +308,7 @@ int LAGr_TriangleCount // using the masked saxpy3 method LG_TRY (tricount_prep (NULL, &U, A, msg)) ; GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, U, GrB_DESC_S)) ; + GRB_TRY (GxB_Matrix_fprint (C, "my mat", GxB_COMPLETE, stdout)) ; GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; break ; @@ -312,6 +321,7 @@ int LAGr_TriangleCount // using the masked dot product LG_TRY (tricount_prep (&L, &U, A, msg)) ; GRB_TRY (GrB_mxm (C, L, NULL, semiring, L, U, GrB_DESC_ST1)) ; + GRB_TRY (GxB_Matrix_fprint (C, "my mat", GxB_COMPLETE, stdout)) ; GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; break ; @@ -320,6 +330,7 @@ int LAGr_TriangleCount // using the masked dot product LG_TRY (tricount_prep (&L, &U, A, msg)) ; GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, L, GrB_DESC_ST1)) ; + GRB_TRY (GxB_Matrix_fprint (C, "my mat", GxB_COMPLETE, stdout)) ; GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; break ; } From 9b1c4d01555ebf333c9087b0122d95eb33331ba7 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Thu, 31 Mar 2022 09:27:40 -0500 Subject: [PATCH 04/53] plus_pair_int64 semiring in tri count --- src/algorithm/LAGr_TriangleCount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithm/LAGr_TriangleCount.c b/src/algorithm/LAGr_TriangleCount.c index b188c208cf..aa817088f0 100644 --- a/src/algorithm/LAGr_TriangleCount.c +++ b/src/algorithm/LAGr_TriangleCount.c @@ -177,7 +177,7 @@ int LAGr_TriangleCount GrB_Index n ; GRB_TRY (GrB_Matrix_nrows (&n, A)) ; GRB_TRY (GrB_Matrix_new (&C, GrB_INT64, n, n)) ; - GrB_Semiring semiring = LAGraph_plus_one_int64 ; + GrB_Semiring semiring = GxB_PLUS_PAIR_INT64 ; // hack GrB_Monoid monoid = GrB_PLUS_MONOID_INT64 ; //-------------------------------------------------------------------------- From e74d6635d1743bad2eecc02725408f4faee5a74c Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Thu, 31 Mar 2022 11:21:05 -0500 Subject: [PATCH 05/53] hack triangle count --- src/algorithm/LAGr_TriangleCount.c | 13 ++++++------ src/benchmark/LAGraph_demo.h | 2 +- src/benchmark/tc_demo.c | 34 +++++++++++++++++++++++++----- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/algorithm/LAGr_TriangleCount.c b/src/algorithm/LAGr_TriangleCount.c index e03d305a1b..a447b3ad6d 100644 --- a/src/algorithm/LAGr_TriangleCount.c +++ b/src/algorithm/LAGr_TriangleCount.c @@ -75,9 +75,9 @@ static int tricount_prep GRB_TRY (GrB_Matrix_new (L, GrB_BOOL, n, n)) ; GRB_TRY (GrB_select (*L, NULL, NULL, GrB_TRIL, A, (int64_t) (-1), NULL)) ; - GRB_TRY(GrB_Matrix_setElement(*L, false, 0, 0)); - GRB_TRY (GrB_Matrix_wait (*L, GrB_MATERIALIZE)) ; - GRB_TRY (GxB_Matrix_fprint (*L, "L", GxB_COMPLETE, stdout)) ; +// GRB_TRY(GrB_Matrix_setElement(*L, false, 0, 0)); +// GRB_TRY (GrB_Matrix_wait (*L, GrB_MATERIALIZE)) ; +// GRB_TRY (GxB_Matrix_fprint (*L, "L", GxB_COMPLETE, stdout)) ; } if (U != NULL) @@ -85,9 +85,9 @@ static int tricount_prep // U = triu (A,1) GRB_TRY (GrB_Matrix_new (U, GrB_BOOL, n, n)) ; GRB_TRY (GrB_select (*U, NULL, NULL, GrB_TRIU, A, (int64_t) 1, NULL)) ; - GRB_TRY(GrB_Matrix_setElement(*U, 0, 0, 0)); - GRB_TRY (GrB_Matrix_wait (*U, GrB_MATERIALIZE)) ; - GRB_TRY (GxB_Matrix_fprint (*U, "U", GxB_COMPLETE, stdout)) ; +// GRB_TRY(GrB_Matrix_setElement(*U, 0, 0, 0)); +// GRB_TRY (GrB_Matrix_wait (*U, GrB_MATERIALIZE)) ; +// GRB_TRY (GxB_Matrix_fprint (*U, "U", GxB_COMPLETE, stdout)) ; } return (GrB_SUCCESS) ; } @@ -339,6 +339,7 @@ int LAGr_TriangleCount // return result //-------------------------------------------------------------------------- + GxB_print (C, 3) ; LG_FREE_ALL ; (*ntriangles) = (uint64_t) ntri ; return (GrB_SUCCESS) ; diff --git a/src/benchmark/LAGraph_demo.h b/src/benchmark/LAGraph_demo.h index 5b87795c18..4ceef12c3c 100644 --- a/src/benchmark/LAGraph_demo.h +++ b/src/benchmark/LAGraph_demo.h @@ -1107,7 +1107,7 @@ static inline int demo_init (bool burble) mallopt (M_TOP_PAD, 16*1024*1024) ; // increase padding to speedup malloc #endif - // LAGRAPH_TRY (LAGraph_Init (NULL)) ; +// LAGRAPH_TRY (LAGraph_Init (NULL)) ; // rmm_wrap_initialize (rmm_wrap_managed, INT32_MAX, INT64_MAX) ; rmm_wrap_initialize (rmm_wrap_managed, 256 * 1000000L, 256 * 100000000L) ; LAGRAPH_TRY (LAGr_Init (rmm_wrap_malloc, rmm_wrap_calloc, rmm_wrap_realloc, rmm_wrap_free, NULL)) ; diff --git a/src/benchmark/tc_demo.c b/src/benchmark/tc_demo.c index 4461615f65..93c424282d 100644 --- a/src/benchmark/tc_demo.c +++ b/src/benchmark/tc_demo.c @@ -126,11 +126,35 @@ int main (int argc, char **argv) GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; GRB_TRY (GrB_Matrix_nvals (&nvals, G->A)) ; - GxB_print (G->A, 3) ; - GRB_TRY (GrB_Matrix_setElement (G->A, 0, 2, 2)) ; - GxB_print (G->A, 3) ; + // HACK: make sure G->A is non-iso + + // create an iterator + GxB_Iterator iterator ; + GxB_Iterator_new (&iterator) ; + // attach it to the matrix A + GrB_Info info = GxB_Matrix_Iterator_attach (iterator, G->A, NULL) ; + if (info < 0) { abort ( ) ; } + // seek to the first entry + info = GxB_Matrix_Iterator_seek (iterator, 0) ; + printf ("info %d\n", info) ; + while (info != GxB_EXHAUSTED) + { + // get the entry A(i,j) + GrB_Index i, j ; + GxB_Matrix_Iterator_getIndex (iterator, &i, &j) ; + // set it to 0 + printf ("setting A(%d,%d) = 0\n", (int) i, (int) j) ; + GRB_TRY (GrB_Matrix_setElement (G->A, 0, i, j)) ; + break ; + } + GrB_free (&iterator) ; + + GxB_print (G->A, 2) ; +// GRB_TRY (GrB_Matrix_setElement (G->A, 0, 2, 2)) ; +// GxB_print (G->A, 3) ; GrB_wait (G->A, GrB_MATERIALIZE) ; - GxB_print (G->A, 3) ; +// GxB_print (G->A, 3) ; +// printf ("HERE ============================\n") ; //-------------------------------------------------------------------------- // triangle counting @@ -139,7 +163,7 @@ int main (int argc, char **argv) GrB_Index ntriangles, ntsimple = 0 ; double tic [2] ; -#if 0 +#if 1 // check # of triangles LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; LAGRAPH_TRY (LG_check_tri (&ntsimple, G, NULL)) ; From aca41978ea05cb6e346799eaa69884ca217a4352 Mon Sep 17 00:00:00 2001 From: Joe Eaton Date: Thu, 31 Mar 2022 13:39:22 -0500 Subject: [PATCH 06/53] Changed non-iso value to 2 instead of 0. Since we use boolean type, using 0 means the triangle doesn't get formed (the multiplyh op fails). Using 2 gives the right number of triangls --- src/benchmark/tc_demo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/benchmark/tc_demo.c b/src/benchmark/tc_demo.c index 93c424282d..4ff18b8786 100644 --- a/src/benchmark/tc_demo.c +++ b/src/benchmark/tc_demo.c @@ -143,8 +143,8 @@ int main (int argc, char **argv) GrB_Index i, j ; GxB_Matrix_Iterator_getIndex (iterator, &i, &j) ; // set it to 0 - printf ("setting A(%d,%d) = 0\n", (int) i, (int) j) ; - GRB_TRY (GrB_Matrix_setElement (G->A, 0, i, j)) ; + printf ("setting A(%d,%d) = 2\n", (int) i, (int) j) ; + GRB_TRY (GrB_Matrix_setElement (G->A, 2, i, j)) ; break ; } GrB_free (&iterator) ; From 56216d8e04f7b6a2b181703ecdab77a56b9196e0 Mon Sep 17 00:00:00 2001 From: Joe Eaton Date: Wed, 6 Apr 2022 09:24:57 -0500 Subject: [PATCH 07/53] Changed non-iso value to be 15th entry. THIS IS A WORKAROUND for a BUG in GraphBLAS semiring generation. With this we are able to run the tc_demo correctly using CUDA. --- src/benchmark/tc_demo.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/benchmark/tc_demo.c b/src/benchmark/tc_demo.c index 4ff18b8786..49264d9b86 100644 --- a/src/benchmark/tc_demo.c +++ b/src/benchmark/tc_demo.c @@ -135,7 +135,7 @@ int main (int argc, char **argv) GrB_Info info = GxB_Matrix_Iterator_attach (iterator, G->A, NULL) ; if (info < 0) { abort ( ) ; } // seek to the first entry - info = GxB_Matrix_Iterator_seek (iterator, 0) ; + info = GxB_Matrix_Iterator_seek (iterator, 15) ; printf ("info %d\n", info) ; while (info != GxB_EXHAUSTED) { @@ -143,8 +143,8 @@ int main (int argc, char **argv) GrB_Index i, j ; GxB_Matrix_Iterator_getIndex (iterator, &i, &j) ; // set it to 0 - printf ("setting A(%d,%d) = 2\n", (int) i, (int) j) ; - GRB_TRY (GrB_Matrix_setElement (G->A, 2, i, j)) ; + printf ("setting A(%d,%d) = 0\n", (int) i, (int) j) ; + GRB_TRY (GrB_Matrix_setElement (G->A, 0, i, j)) ; break ; } GrB_free (&iterator) ; @@ -259,11 +259,13 @@ int main (int argc, char **argv) ttot, 1e-6 * nvals / ttot) ; printf (" # of triangles: %" PRId64 " presort: %d\n", ntriangles, presort) ; + #if 0 if (nt2 != ntriangles) { printf ("Test failure!\n") ; abort ( ) ; } + #endif fprintf (stderr, "Avg: TC method%d.%d %3d: %10.3f sec: %s\n", method, sorting, nthreads, ttot, matrix_name) ; From 4518b4068e7a27bbb25a9bad6832f7dcaa201ab5 Mon Sep 17 00:00:00 2001 From: Joe Eaton Date: Thu, 14 Apr 2022 15:59:08 -0500 Subject: [PATCH 08/53] Removing extra prints in tc_demo and LAGr_TriangleCount --- src/algorithm/LAGr_TriangleCount.c | 18 +++++++++--------- src/benchmark/tc_demo.c | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/algorithm/LAGr_TriangleCount.c b/src/algorithm/LAGr_TriangleCount.c index a447b3ad6d..c00de0f5b4 100644 --- a/src/algorithm/LAGr_TriangleCount.c +++ b/src/algorithm/LAGr_TriangleCount.c @@ -76,8 +76,8 @@ static int tricount_prep GRB_TRY (GrB_select (*L, NULL, NULL, GrB_TRIL, A, (int64_t) (-1), NULL)) ; // GRB_TRY(GrB_Matrix_setElement(*L, false, 0, 0)); -// GRB_TRY (GrB_Matrix_wait (*L, GrB_MATERIALIZE)) ; -// GRB_TRY (GxB_Matrix_fprint (*L, "L", GxB_COMPLETE, stdout)) ; + GRB_TRY (GrB_Matrix_wait (*L, GrB_MATERIALIZE)) ; + //GRB_TRY (GxB_Matrix_fprint (*L, "L", GxB_COMPLETE, stdout)) ; } if (U != NULL) @@ -86,8 +86,8 @@ static int tricount_prep GRB_TRY (GrB_Matrix_new (U, GrB_BOOL, n, n)) ; GRB_TRY (GrB_select (*U, NULL, NULL, GrB_TRIU, A, (int64_t) 1, NULL)) ; // GRB_TRY(GrB_Matrix_setElement(*U, 0, 0, 0)); -// GRB_TRY (GrB_Matrix_wait (*U, GrB_MATERIALIZE)) ; -// GRB_TRY (GxB_Matrix_fprint (*U, "U", GxB_COMPLETE, stdout)) ; + GRB_TRY (GrB_Matrix_wait (*U, GrB_MATERIALIZE)) ; + //GRB_TRY (GxB_Matrix_fprint (*U, "U", GxB_COMPLETE, stdout)) ; } return (GrB_SUCCESS) ; } @@ -298,7 +298,7 @@ int LAGr_TriangleCount // using the masked saxpy3 method LG_TRY (tricount_prep (&L, NULL, A, msg)) ; GRB_TRY (GrB_mxm (C, L, NULL, semiring, L, L, GrB_DESC_S)) ; - GRB_TRY (GxB_Matrix_fprint (C, "my mat", GxB_COMPLETE, stdout)) ; + //GRB_TRY (GxB_Matrix_fprint (C, "my mat", GxB_COMPLETE, stdout)) ; GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; break ; @@ -308,7 +308,7 @@ int LAGr_TriangleCount // using the masked saxpy3 method LG_TRY (tricount_prep (NULL, &U, A, msg)) ; GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, U, GrB_DESC_S)) ; - GRB_TRY (GxB_Matrix_fprint (C, "my mat", GxB_COMPLETE, stdout)) ; + //GRB_TRY (GxB_Matrix_fprint (C, "my mat", GxB_COMPLETE, stdout)) ; GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; break ; @@ -321,7 +321,7 @@ int LAGr_TriangleCount // using the masked dot product LG_TRY (tricount_prep (&L, &U, A, msg)) ; GRB_TRY (GrB_mxm (C, L, NULL, semiring, L, U, GrB_DESC_ST1)) ; - GRB_TRY (GxB_Matrix_fprint (C, "my mat", GxB_COMPLETE, stdout)) ; + //GRB_TRY (GxB_Matrix_fprint (C, "my mat", GxB_COMPLETE, stdout)) ; GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; break ; @@ -330,7 +330,7 @@ int LAGr_TriangleCount // using the masked dot product LG_TRY (tricount_prep (&L, &U, A, msg)) ; GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, L, GrB_DESC_ST1)) ; - GRB_TRY (GxB_Matrix_fprint (C, "my mat", GxB_COMPLETE, stdout)) ; + //GRB_TRY (GxB_Matrix_fprint (C, "my mat", GxB_COMPLETE, stdout)) ; GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; break ; } @@ -339,7 +339,7 @@ int LAGr_TriangleCount // return result //-------------------------------------------------------------------------- - GxB_print (C, 3) ; + //GxB_print (C, 3) ; LG_FREE_ALL ; (*ntriangles) = (uint64_t) ntri ; return (GrB_SUCCESS) ; diff --git a/src/benchmark/tc_demo.c b/src/benchmark/tc_demo.c index 49264d9b86..7ad7dd65fe 100644 --- a/src/benchmark/tc_demo.c +++ b/src/benchmark/tc_demo.c @@ -135,7 +135,7 @@ int main (int argc, char **argv) GrB_Info info = GxB_Matrix_Iterator_attach (iterator, G->A, NULL) ; if (info < 0) { abort ( ) ; } // seek to the first entry - info = GxB_Matrix_Iterator_seek (iterator, 15) ; + info = GxB_Matrix_Iterator_seek (iterator, 1) ; printf ("info %d\n", info) ; while (info != GxB_EXHAUSTED) { From 44db29cb4e2d40371668fed4289acd6ccc7c2c5c Mon Sep 17 00:00:00 2001 From: Joe Eaton Date: Thu, 21 Apr 2022 09:47:11 -0500 Subject: [PATCH 09/53] Enabled CPU multi-threaded vs GPU benchmarks --- src/benchmark/tc_demo.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/benchmark/tc_demo.c b/src/benchmark/tc_demo.c index 7ad7dd65fe..a4f2ea5bec 100644 --- a/src/benchmark/tc_demo.c +++ b/src/benchmark/tc_demo.c @@ -24,12 +24,12 @@ #include "LAGraph_demo.h" -#define NTHREAD_LIST 1 +//#define NTHREAD_LIST 1 // #define NTHREAD_LIST 2 -#define THREAD_LIST 0 +//#define THREAD_LIST 0 -// #define NTHREAD_LIST 6 -// #define THREAD_LIST 64, 32, 24, 12, 8, 4 + #define NTHREAD_LIST 7 + #define THREAD_LIST 64, 32, 24, 12, 8, 4, 0 #define LG_FREE_ALL \ { \ @@ -83,7 +83,7 @@ int main (int argc, char **argv) bool burble = false ; demo_init (burble) ; - int ntrials = 3 ; + int ntrials = 5 ; // ntrials = 1 ; // HACK printf ("# of trials: %d\n", ntrials) ; @@ -236,6 +236,17 @@ int main (int argc, char **argv) { int nthreads = Nthreads [t] ; if (nthreads > nthreads_max) continue ; + if (nthreads != 0) // Use GPU + { + GxB_Global_Option_set( GxB_GLOBAL_GPU_CONTROL, GxB_GPU_NEVER); + printf(" CPU ONLY using %d threads", nthreads); + } + else + { + GxB_Global_Option_set( GxB_GLOBAL_GPU_CONTROL, GxB_GPU_ALWAYS); + printf(" GPU ONLY using %d threads", nthreads); + } + LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads, msg)) ; GrB_Index nt2 ; double ttot = 0, ttrial [100] ; From b89224fe687dbc9001333cbeb424e1ffc46236ee Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Thu, 19 May 2022 10:12:44 -0500 Subject: [PATCH 10/53] check # triangles in tc_demo --- src/benchmark/tc_demo.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/benchmark/tc_demo.c b/src/benchmark/tc_demo.c index a4f2ea5bec..04e77de9df 100644 --- a/src/benchmark/tc_demo.c +++ b/src/benchmark/tc_demo.c @@ -190,11 +190,13 @@ int main (int argc, char **argv) printf ("nthreads: %3d time: %12.6f rate: %6.2f (SandiaDot2, one trial)\n", nthreads_max, ttot, 1e-6 * nvals / ttot) ; -#if 0 +#if 1 if (ntriangles != ntsimple) { printf ("wrong # triangles: %g %g\n", (double) ntriangles, (double) ntsimple) ; + fflush (stdout) ; + fflush (stderr) ; abort ( ) ; } #endif @@ -269,11 +271,13 @@ int main (int argc, char **argv) printf ("nthreads: %3d time: %12.6f rate: %6.2f", nthreads, ttot, 1e-6 * nvals / ttot) ; printf (" # of triangles: %" PRId64 " presort: %d\n", - ntriangles, presort) ; - #if 0 + nt2, presort) ; + #if 1 if (nt2 != ntriangles) { printf ("Test failure!\n") ; + fflush (stdout) ; + fflush (stderr) ; abort ( ) ; } #endif From 4e8e439c18b200620c6f2706201e34bff8eb25af Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Thu, 19 May 2022 13:01:34 -0500 Subject: [PATCH 11/53] tc_demo: cpu and gpu warmups --- src/benchmark/tc_demo.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/benchmark/tc_demo.c b/src/benchmark/tc_demo.c index 04e77de9df..296760d6d2 100644 --- a/src/benchmark/tc_demo.c +++ b/src/benchmark/tc_demo.c @@ -161,7 +161,7 @@ int main (int argc, char **argv) //-------------------------------------------------------------------------- GrB_Index ntriangles, ntsimple = 0 ; - double tic [2] ; + double tic [2], ttot ; #if 1 // check # of triangles @@ -179,13 +179,13 @@ int main (int argc, char **argv) int presort = LAGraph_TriangleCount_AutoSort ; // = 2 (auto selection) print_method (stdout, 6, presort) ; - // warmup method: + // warmup method: without the GPU // LAGraph_TriangleCount_SandiaDot2 = 6, // sum (sum ((U * L') .* U)) + GxB_set (GxB_GPU_CONTROL, GxB_GPU_NEVER) ; LAGRAPH_TRY (LAGr_TriangleCount (&ntriangles, G, LAGraph_TriangleCount_SandiaDot2, &presort, msg) ); - printf ("# of triangles: %" PRIu64 "\n", ntriangles) ; + printf ("# of triangles: %" PRIu64 " (CPU)\n", ntriangles) ; print_method (stdout, 6, presort) ; - double ttot ; LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; printf ("nthreads: %3d time: %12.6f rate: %6.2f (SandiaDot2, one trial)\n", nthreads_max, ttot, 1e-6 * nvals / ttot) ; @@ -201,6 +201,29 @@ int main (int argc, char **argv) } #endif + // warmup method: with the GPU + // LAGraph_TriangleCount_SandiaDot2 = 6, // sum (sum ((U * L') .* U)) + GrB_Index ntriangles_gpu ; + GxB_set (GxB_GPU_CONTROL, GxB_GPU_ALWAYS) ; + LAGRAPH_TRY (LAGr_TriangleCount (&ntriangles_gpu, G, + LAGraph_TriangleCount_SandiaDot2, &presort, msg) ); + printf ("# of triangles: %" PRIu64 " (GPU)\n", ntriangles_gpu) ; + print_method (stdout, 6, presort) ; + LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; + printf ("nthreads: %3d time: %12.6f rate: %6.2f (SandiaDot2, warmup GPU)\n", + nthreads_max, ttot, 1e-6 * nvals / ttot) ; + +#if 1 + if (ntriangles_gpu != ntsimple) + { + printf ("wrong # triangles: %g %g\n", (double) ntriangles_gpu, + (double) ntsimple) ; + fflush (stdout) ; + fflush (stderr) ; + abort ( ) ; + } +#endif + double t_best = INFINITY ; int method_best = -1 ; int nthreads_best = -1 ; From 3fbd9318d9eb25d2a8cdedd0cbb9031dab216af4 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Fri, 20 May 2022 14:09:42 -0500 Subject: [PATCH 12/53] merge from reorg branch --- .github/workflows/build.yml | 4 +- CMakeLists.txt | 4 +- Contributors.txt | 2 + doc/Delete_Me_for_V1/TODO.txt | 14 +- doc/Delete_Me_for_V1/naming.c | 6 +- doc/UserGuide/ExPageRank.c | 2 +- doc/UserGuide/LAGraphX_h.tex | 532 ++++++++++ doc/UserGuide/LAGraph_UserGuide.pdf | Bin 593889 -> 591640 bytes doc/UserGuide/LAGraph_h.tex | 905 ++++++++++++++++++ doc/UserGuide/func_extract.py | 54 ++ doc/UserGuide/makefile | 6 +- experimental/algorithm/LAGraph_AllKCore.c | 143 +++ experimental/algorithm/LAGraph_AllKTruss.c | 9 +- experimental/algorithm/LAGraph_BF_full.c | 6 +- experimental/algorithm/LAGraph_BF_full1.c | 6 +- experimental/algorithm/LAGraph_BF_full1a.c | 6 +- experimental/algorithm/LAGraph_BF_full2.c | 6 +- experimental/algorithm/LAGraph_KCore.c | 131 +++ .../algorithm/LAGraph_KCoreDecompose.c | 105 ++ experimental/algorithm/LAGraph_KTruss.c | 4 +- .../algorithm/LAGraph_MaximalIndependentSet.c | 23 +- .../LAGraph_VertexCentrality_Triangle.c | 4 +- experimental/algorithm/LAGraph_cdlp.c | 4 +- experimental/algorithm/LG_CC_FastSV5.c | 8 +- experimental/benchmark/AllKCore_demo.c | 143 +++ experimental/benchmark/KCore_demo.c | 143 +++ experimental/benchmark/dnn_demo.c | 9 +- experimental/benchmark/mis_demo.c | 11 +- experimental/benchmark/tcc_demo.c | 9 +- experimental/test/LG_check_kcore.c | 176 ++++ experimental/test/LG_check_kcoredecompose.c | 114 +++ experimental/test/LG_check_ktruss.c | 4 +- experimental/test/LG_check_mis.c | 3 +- experimental/test/include/LG_Xtest.h | 22 + experimental/test/test_AllKCore.c | 173 ++++ experimental/test/test_AllKtruss.c | 22 +- experimental/test/test_KCore.c | 165 ++++ experimental/test/test_KCoreDecompose.c | 168 ++++ experimental/test/test_KTruss.c | 22 +- .../test/test_MaximalIndependentSet.c | 34 +- experimental/test/test_TriangleCentrality.c | 26 +- experimental/test/test_cdlp.c | 6 +- experimental/test/test_lcc.c | 6 +- experimental/utility/LAGraph_SRead.c | 6 +- include/LAGraph.h | 404 ++++---- include/LAGraphX.h | 70 +- src/algorithm/LAGr_Betweenness.c | 5 +- src/algorithm/LAGr_BreadthFirstSearch.c | 4 +- src/algorithm/LAGr_ConnectedComponents.c | 2 +- src/algorithm/LAGr_PageRank.c | 25 +- src/algorithm/LAGr_PageRankGAP.c | 16 +- src/algorithm/LAGr_SingleSourceShortestPath.c | 8 +- src/algorithm/LAGr_TriangleCount.c | 32 +- src/algorithm/LAGraph_TriangleCount.c | 19 +- src/algorithm/LG_BreadthFirstSearch_SSGrB.c | 18 +- src/algorithm/LG_BreadthFirstSearch_vanilla.c | 6 +- src/algorithm/LG_CC_Boruvka.c | 4 +- src/algorithm/LG_CC_FastSV6.c | 13 +- src/benchmark/LAGraph_demo.h | 18 +- src/benchmark/bc_demo.c | 9 +- src/benchmark/bfs_demo.c | 17 +- src/benchmark/cc_demo.c | 15 +- src/benchmark/gappagerank_demo.c | 15 +- src/benchmark/ss2_demo.c | 9 +- src/benchmark/sssp_demo.c | 9 +- src/benchmark/tc_demo.c | 107 +-- src/benchmark/tc_gpu_demo.c | 332 +++++++ src/test/LG_brutal_setup.c | 3 +- src/test/LG_check_cc.c | 2 +- src/test/LG_check_tri.c | 4 +- src/test/test_Betweenness.c | 2 +- src/test/test_BreadthFirstSearch.c | 32 +- .../{test_Property_AT.c => test_Cached_AT.c} | 32 +- ...Property_Degree.c => test_Cached_Degree.c} | 68 +- ...t_Property_NDiag.c => test_Cached_NDiag.c} | 26 +- ...ure.c => test_Cached_SymmetricStructure.c} | 78 +- src/test/test_CheckGraph.c | 44 +- src/test/test_ConnectedComponents.c | 2 +- ...DeleteProperties.c => test_DeleteCached.c} | 68 +- src/test/test_DisplayGraph.c | 22 +- src/test/test_Init.c | 29 +- src/test/test_Init_errors.c | 59 ++ src/test/test_New.c | 4 +- src/test/test_NumThreads.c | 47 +- src/test/test_PageRank.c | 10 +- src/test/test_SampleDegree.c | 16 +- src/test/test_SingleSourceShortestPath.c | 4 +- src/test/test_Sort.c | 20 +- src/test/test_SortByDegree.c | 76 +- src/test/test_TriangleCount.c | 42 +- src/test/test_Xinit.c | 19 +- src/test/test_minmax.c | 30 +- src/utility/LAGr_Init.c | 82 +- ...raph_Property_AT.c => LAGraph_Cached_AT.c} | 15 +- ..._Property_EMax.c => LAGraph_Cached_EMax.c} | 8 +- ..._Property_EMin.c => LAGraph_Cached_EMin.c} | 8 +- ..._ColDegree.c => LAGraph_Cached_InDegree.c} | 44 +- ... => LAGraph_Cached_IsSymmetricStructure.c} | 20 +- ...ty_NDiag.c => LAGraph_Cached_NSelfEdges.c} | 12 +- ...RowDegree.c => LAGraph_Cached_OutDegree.c} | 28 +- src/utility/LAGraph_CheckGraph.c | 24 +- src/utility/LAGraph_Delete.c | 2 +- ...eteProperties.c => LAGraph_DeleteCached.c} | 22 +- ...DeleteDiag.c => LAGraph_DeleteSelfEdges.c} | 20 +- src/utility/LAGraph_DisplayGraph.c | 25 +- src/utility/LAGraph_Finalize.c | 22 +- src/utility/LAGraph_GetNumThreads.c | 39 +- src/utility/LAGraph_Global.c | 21 +- src/utility/LAGraph_Init.c | 4 +- src/utility/LAGraph_MMWrite.c | 10 +- src/utility/LAGraph_New.c | 18 +- src/utility/LAGraph_Realloc.c | 5 +- src/utility/LAGraph_SampleDegree.c | 11 +- src/utility/LAGraph_SetNumThreads.c | 22 +- src/utility/LAGraph_Sort1.c | 2 +- src/utility/LAGraph_Sort2.c | 2 +- src/utility/LAGraph_Sort3.c | 2 +- src/utility/LAGraph_SortByDegree.c | 28 +- src/utility/LG_internal.h | 16 +- src/utility/{LG_ndiag.c => LG_nself_edges.c} | 14 +- 120 files changed, 4580 insertions(+), 1088 deletions(-) create mode 100644 doc/UserGuide/LAGraphX_h.tex create mode 100644 doc/UserGuide/LAGraph_h.tex create mode 100644 doc/UserGuide/func_extract.py create mode 100644 experimental/algorithm/LAGraph_AllKCore.c create mode 100644 experimental/algorithm/LAGraph_KCore.c create mode 100644 experimental/algorithm/LAGraph_KCoreDecompose.c create mode 100644 experimental/benchmark/AllKCore_demo.c create mode 100644 experimental/benchmark/KCore_demo.c create mode 100644 experimental/test/LG_check_kcore.c create mode 100644 experimental/test/LG_check_kcoredecompose.c create mode 100644 experimental/test/test_AllKCore.c create mode 100644 experimental/test/test_KCore.c create mode 100644 experimental/test/test_KCoreDecompose.c create mode 100644 src/benchmark/tc_gpu_demo.c rename src/test/{test_Property_AT.c => test_Cached_AT.c} (88%) rename src/test/{test_Property_Degree.c => test_Cached_Degree.c} (85%) rename src/test/{test_Property_NDiag.c => test_Cached_NDiag.c} (90%) rename src/test/{test_Property_ASymmetricStructure.c => test_Cached_SymmetricStructure.c} (75%) rename src/test/{test_DeleteProperties.c => test_DeleteCached.c} (69%) create mode 100644 src/test/test_Init_errors.c rename src/utility/{LAGraph_Property_AT.c => LAGraph_Cached_AT.c} (84%) rename src/utility/{LAGraph_Property_EMax.c => LAGraph_Cached_EMax.c} (95%) rename src/utility/{LAGraph_Property_EMin.c => LAGraph_Cached_EMin.c} (95%) rename src/utility/{LAGraph_Property_ColDegree.c => LAGraph_Cached_InDegree.c} (65%) rename src/utility/{LAGraph_Property_SymmetricStructure.c => LAGraph_Cached_IsSymmetricStructure.c} (84%) rename src/utility/{LAGraph_Property_NDiag.c => LAGraph_Cached_NSelfEdges.c} (78%) rename src/utility/{LAGraph_Property_RowDegree.c => LAGraph_Cached_OutDegree.c} (73%) rename src/utility/{LAGraph_DeleteProperties.c => LAGraph_DeleteCached.c} (75%) rename src/utility/{LAGraph_DeleteDiag.c => LAGraph_DeleteSelfEdges.c} (73%) rename src/utility/{LG_ndiag.c => LG_nself_edges.c} (87%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8f2d7cc819..e8845529b8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,6 +11,7 @@ jobs: - {grb_version: 6.0.2, conda_grb_package_hash: h9c3ff4c} - {grb_version: 6.1.4, conda_grb_package_hash: h9c3ff4c} - {grb_version: 6.2.4, conda_grb_package_hash: h27087fc} + - {grb_version: 7.0.1, conda_grb_package_hash: h27087fc} steps: - name: Checkout uses: actions/checkout@v2.0.0 @@ -37,7 +38,7 @@ jobs: with: branch: gh-pages folder: build/test_coverage/ - if: ${{ matrix.config.grb_version }} == '6.2.4' && github.event_name == 'push' && github.ref == 'refs/heads/reorg' + if: ${{ matrix.config.grb_version }} == '7.0.1' && github.event_name == 'push' && github.ref == 'refs/heads/reorg' - name: Save output uses: actions/upload-artifact@v2.2.3 with: @@ -51,6 +52,7 @@ jobs: - {grb_version: 6.0.2, conda_grb_package_hash: h4a89273} - {grb_version: 6.1.4, conda_grb_package_hash: h4a89273} - {grb_version: 6.2.4, conda_grb_package_hash: h3f3baac} + - {grb_version: 7.0.1, conda_grb_package_hash: h3f3baac} steps: - name: Checkout uses: actions/checkout@v2.0.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ee125a978..225b13656b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,10 +56,10 @@ set ( CMAKE_MACOSX_RPATH TRUE ) # version of LAGraph # FIXME: use config to create include/LAGraph.h from these definitions -set ( LAGraph_DATE "Mar 11, 2022" ) +set ( LAGraph_DATE "May 20, 2022" ) set ( LAGraph_VERSION_MAJOR 0 ) set ( LAGraph_VERSION_MINOR 9 ) -set ( LAGraph_VERSION_SUB 13 ) +set ( LAGraph_VERSION_SUB 23 ) project ( lagraph VERSION "${LAGraph_VERSION_MAJOR}.${LAGraph_VERSION_MINOR}.${LAGraph_VERSION_SUB}" ) diff --git a/Contributors.txt b/Contributors.txt index 6b9f89ea0e..248c46ffe7 100644 --- a/Contributors.txt +++ b/Contributors.txt @@ -21,3 +21,5 @@ Contributors: Carl Yang Tze Meng Low, Florentin Dorre + Pranav Konduri, Texas A&M University + diff --git a/doc/Delete_Me_for_V1/TODO.txt b/doc/Delete_Me_for_V1/TODO.txt index be591fe08c..a014a533b5 100644 --- a/doc/Delete_Me_for_V1/TODO.txt +++ b/doc/Delete_Me_for_V1/TODO.txt @@ -1,4 +1,7 @@ -As of Mar 11, 2022: +As of May 18, 2022: + + * cmake: need to find the right liblagraph and libgraphblas + (not in /usr/local/lib*, but the one being compiled/tested). * entire user guide experimental -> src, how to do it. @@ -9,16 +12,11 @@ As of Mar 11, 2022: * document all src & experimental: algorithms, utilities, and tests. - * draft name scheme: LAGraph_* are Basic algorithms, LAGr_* are Advanced - Basic: in/out, can set properties - Adv: in only, prop must be provided on input, can also have extra - parameters, ... - * check function names and API * add FUTURE to User Guide (see below) - * error messages in src/benchmark + * for BFS (with SS:GrB): if AT not present, use push-only method? -------------------------------------------------------------------------------- add FUTURE items as a section in the User Guide: @@ -28,7 +26,7 @@ FUTURE: LAGraph_SingleSourceShortestPath: Write a Basic method that Delta on its own (hard to do). FUTURE: LAGraph_BreadthFirstSearch basic method that computes G->AT - and G->rowdegree first. + and G->out_degree first. FUTURE: all algorithms can use Basic and Advanced variants. diff --git a/doc/Delete_Me_for_V1/naming.c b/doc/Delete_Me_for_V1/naming.c index 0bdd4208ad..0e42eef721 100644 --- a/doc/Delete_Me_for_V1/naming.c +++ b/doc/Delete_Me_for_V1/naming.c @@ -1,8 +1,8 @@ // Basic vs Advanced algorithms, not utilities -// Basic algorithm: G can be modified (input/output). Properties computed -// if needed. Sometimes fewer inputs than Advanced (parameters computed -// automically, or with defaults). +// Basic algorithm: G can be modified (input/output). Cached properties +// computed if needed. Sometimes fewer inputs than Advanced (parameters +// computed automically, or with defaults). LAGraph_WhatEver // is a Basic method diff --git a/doc/UserGuide/ExPageRank.c b/doc/UserGuide/ExPageRank.c index 7213c94ec7..7d7e4515d5 100644 --- a/doc/UserGuide/ExPageRank.c +++ b/doc/UserGuide/ExPageRank.c @@ -19,7 +19,7 @@ void test_PageRank(void) OK (fclose (f)) ; OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_UNDIRECTED, msg)) ; TEST_CHECK (A == NULL) ; // A has been moved into G->A - OK (LAGraph_Property_RowDegree (G, msg)) ; + OK (LAGraph_Cached_OutDegree (G, msg)) ; // compute its pagerank OK (LAGr_PageRank (¢rality, &niters, G, 0.85, 1e-4, 100, msg)) ; diff --git a/doc/UserGuide/LAGraphX_h.tex b/doc/UserGuide/LAGraphX_h.tex new file mode 100644 index 0000000000..1e1afed429 --- /dev/null +++ b/doc/UserGuide/LAGraphX_h.tex @@ -0,0 +1,532 @@ +\begin{verbatim} +int LAGraph_Random_Init +( + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Random_Finalize +( + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Random_Seed // construct a random seed vector +( + // input/output + GrB_Vector Seed, // vector of random number seeds, normally GrB_UINT64 + // input + uint64_t seed, // scalar input seed + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Random_Next // advance to next random vector +( + // input/output + GrB_Vector Seed, + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +GrB_Info LAGraph_Random_Matrix // random matrix of any built-in type +( + // output + GrB_Matrix *A, // A is constructed on output + // input + GrB_Type type, // type of matrix to construct + GrB_Index nrows, // # of rows of A + GrB_Index ncols, // # of columns of A + double density, // density: build a sparse matrix with + // density*nrows*cols values if not INFINITY; + // build a dense matrix if INFINITY. + uint64_t seed, // random number seed + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_SWrite_HeaderStart // write the first part of the JSON header +( + FILE *f, // file to write to + const char *name, // name of this collection of matrices + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_SWrite_HeaderItem // write a single item to the JSON header +( + // inputs: + FILE *f, // file to write to + LAGraph_Contents_kind kind, // matrix, vector, or text + const char *name, // name of the matrix/vector/text; matrices from + // sparse.tamu.edu use the form "Group/Name" + const char *type, // name of type of the matrix/vector + int compression, // text compression method + GrB_Index blob_size, // exact size of serialized blob for this item + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_SWrite_HeaderItem // write a single item to the JSON header +( + // inputs: + FILE *f, // file to write to + LAGraph_Contents_kind kind, // matrix, vector, or text + const char *name, // name of the matrix/vector/text; matrices from + // sparse.tamu.edu use the form "Group/Name" + const char *type, // name of type of the matrix/vector + // todo: text not yet supported by LAGraph_SWrithe_HeaderItem + int compression, // text compression method + GrB_Index blob_size, // exact size of serialized blob for this item + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_SWrite_HeaderEnd // write the end of the JSON header +( + FILE *f, // file to write to + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_SWrite_Item // write the serialized blob of a matrix/vector/text +( + // input: + FILE *f, // file to write to + const void *blob, // serialized blob from G*B_Matrix_serialize + GrB_Index blob_size, // exact size of the serialized blob + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_SRead // read a set of matrices from a *.lagraph file +( + FILE *f, // file to read from + // output + char **collection, // name of collection (allocated string) + LAGraph_Contents **Contents, // array contents of contents + GrB_Index *ncontents, // # of items in the Contents array + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +void LAGraph_SFreeContents // free the Contents returned by LAGraph_SRead +( + // input/output + LAGraph_Contents **Contents, // array of size ncontents + GrB_Index ncontents +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_SSaveSet // save a set of matrices from a *.lagraph file +( + // inputs: + char *filename, // name of file to write to + GrB_Matrix *Set, // array of GrB_Matrix of size nmatrices + GrB_Index nmatrices, // # of matrices to write to *.lagraph file +// todo: handle vectors and text in LAGraph_SSaveSet + char *collection, // name of this collection of matrices + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +void LAGraph_SFreeSet // free a set of matrices +( + // input/output + GrB_Matrix **Set_handle, // array of GrB_Matrix of size nmatrices + GrB_Index nmatrices // # of matrices in the set +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_AllKTruss // compute all k-trusses of a graph +( + // outputs + GrB_Matrix *Cset, // size n, output k-truss subgraphs + int64_t *kmax, // smallest k where k-truss is empty + int64_t *ntris, // size max(n,4), ntris [k] is #triangles in k-truss + int64_t *nedges, // size max(n,4), nedges [k] is #edges in k-truss + int64_t *nstepss, // size max(n,4), nstepss [k] is #steps for k-truss + // input + LAGraph_Graph G, // input graph + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_KTruss // compute the k-truss of a graph +( + // outputs: + GrB_Matrix *C, // output k-truss subgraph, C + // inputs: + LAGraph_Graph G, // input graph + uint32_t k, // find the k-truss, where k >= 3 + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_cc_lacc ( + GrB_Vector *result, + GrB_Matrix A, + bool sanitize, + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +GrB_Info LAGraph_BF_basic +( + GrB_Vector *pd_output, + const GrB_Matrix A, + const GrB_Index s +) ; +\end{verbatim} + + + + +\begin{verbatim} +GrB_Info LAGraph_BF_basic_pushpull +( + GrB_Vector *pd_output, + const GrB_Matrix A, + const GrB_Matrix AT, + const GrB_Index s +) ; +\end{verbatim} + + + + +\begin{verbatim} +GrB_Info LAGraph_BF_basic_mxv +( + GrB_Vector *pd_output, //the pointer to the vector of distance + const GrB_Matrix AT, //transposed adjacency matrix for the graph + const GrB_Index s //given index of the source +) ; +\end{verbatim} + + + + +\begin{verbatim} +GrB_Info LAGraph_BF_full +( + GrB_Vector *pd_output, + GrB_Vector *ppi_output, + GrB_Vector *ph_output, + const GrB_Matrix A, + const GrB_Index s +) ; +\end{verbatim} + + + + +\begin{verbatim} +GrB_Info LAGraph_BF_full1 +( + GrB_Vector *pd_output, + GrB_Vector *ppi_output, + GrB_Vector *ph_output, + const GrB_Matrix A, + const GrB_Index s +) ; +\end{verbatim} + + + + +\begin{verbatim} +GrB_Info LAGraph_BF_full1a +( + GrB_Vector *pd_output, + GrB_Vector *ppi_output, + GrB_Vector *ph_output, + const GrB_Matrix A, + const GrB_Index s +) ; +\end{verbatim} + + + + +\begin{verbatim} +GrB_Info LAGraph_BF_full2 +( + GrB_Vector *pd_output, //the pointer to the vector of distance + GrB_Vector *ppi_output, //the pointer to the vector of parent + GrB_Vector *ph_output, //the pointer to the vector of hops + const GrB_Matrix A, //matrix for the graph + const GrB_Index s //given index of the source +) ; +\end{verbatim} + + + + +\begin{verbatim} +GrB_Info LAGraph_BF_full_mxv +( + GrB_Vector *pd_output, + GrB_Vector *ppi_output, + GrB_Vector *ph_output, + const GrB_Matrix AT, + const GrB_Index s +) ; +\end{verbatim} + + + + +\begin{verbatim} +GrB_Info LAGraph_BF_pure_c +( + int32_t **pd, + + int64_t **ppi, + + const int64_t s, + const int64_t n, + const int64_t nz, + const int64_t *I, + const int64_t *J, + const int32_t *W +) ; +\end{verbatim} + + + + +\begin{verbatim} +GrB_Info LAGraph_BF_pure_c_double +( + double **pd, + + int64_t **ppi, + + const int64_t s, + const int64_t n, + const int64_t nz, + const int64_t *I, + const int64_t *J, + const double *W +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_cdlp +( + GrB_Vector *CDLP_handle, + const GrB_Matrix A, + bool symmetric, + bool sanitize, + int itermax, + double *t, + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +GrB_Info LAGraph_dnn +( + // output + GrB_Matrix *Yhandle, + // input: not modified + GrB_Matrix *W, + GrB_Matrix *Bias, + int nlayers, + GrB_Matrix Y0 +) ; +\end{verbatim} + + + + +\begin{verbatim} +GrB_Info LAGraph_FW +( + const GrB_Matrix G, + GrB_Matrix *D, + GrB_Type *D_type +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_lcc // compute lcc for all nodes in A +( + GrB_Vector *LCC_handle, // output vector + const GrB_Matrix A, // input matrix + bool symmetric, // if true, the matrix is symmetric + bool sanitize, // if true, ensure A is binary + double t [2], // t [0] = sanitize time, t [1] = lcc time, + // in seconds + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_msf +( + GrB_Matrix *result, // output: an unsymmetrical matrix, the spanning forest + GrB_Matrix A, // input matrix + bool sanitize, // if true, ensure A is symmetric + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_scc ( + GrB_Vector *result, // output: array of component identifiers + GrB_Matrix A, // input matrix + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_VertexCentrality_Triangle // vertex triangle-centrality +( + // outputs: + GrB_Vector *centrality, // centrality(i): triangle centrality of i + uint64_t *ntriangles, // # of triangles in the graph + // inputs: + int method, // 0, 1, 2, or 3 + LAGraph_Graph G, // input graph + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_MaximalIndependentSet // maximal independent set +( + // outputs: + GrB_Vector *mis, // mis(i) = true if i is in the set + // inputs: + LAGraph_Graph G, // input graph + uint64_t seed, // random number seed + GrB_Vector ignore_node, // if NULL, no nodes are ignored. Otherwise + // ignore_node(i) = true if node i is to be + // ignored, and not treated as a candidate + // added to maximal independent set. + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LG_CC_FastSV5 // SuiteSparse:GraphBLAS method, with GxB extensions +( + // output + GrB_Vector *component, // output: array of component identifiers + // inputs + LAGraph_Graph G, // input graph, modified then restored + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +typedef enum +{ + LAGraph_unknown_kind = -1, // unknown kind + LAGraph_matrix_kind = 0, // a serialized GrB_Matrix + LAGraph_vector_kind = 1, // a serialized GrB_Vector (SS:GrB only) + LAGraph_text_kind = 2, // text (char *), possibly compressed +} +LAGraph_Contents_kind ; +\end{verbatim} + + + + diff --git a/doc/UserGuide/LAGraph_UserGuide.pdf b/doc/UserGuide/LAGraph_UserGuide.pdf index 8b9a3f22c5cf7813f44d04efff68ff261b2c8da1..2e23adfbf427008cf16eb4299ce90119359cce5e 100644 GIT binary patch delta 195653 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%0DF)%5cj>O<~I|Gnu8Q7?fE<=Iyl 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
EJN`-Q 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

(_hw8w1 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

HuC%DY+m6XLvSEg?lpN5q<9qSK*CV*{ug* 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 delta 197899 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%0DwLzgS~+xDjdO5S zn2w^Deqn!7IogI03r->ntH2}&mcZ^%_zZ~#fqmE#P$U|h6S!KBbF{s5E>sRC(#TW2$WlFm13?? z?EXTnTRF~7nqeOUp0U``9q9>;4q_Y+o+Q)nAB-?YdNRsMcmM7v3=tweEoj??YW5zh zR$l=l)UlV-%bz=a_Lo1;>GPeINWWcWH{Da&jlW7|e`1s-r;WSQXL7@RVx9+Er0rY8 z&$53AqQ;&@>KPWPKb%SrwN>9|Pv?i)s-MB0E`NY&C&RAYw-^rjXRo$-HI9`p(iU&;`2Wh~IghY*Lpl$m2;?;Z!L zJnP%d<*j50mG57%vWLkog--^A-9A4o55wW*ejO~nFPkz{^!-p#9~fif^S1A^IQY=F zrTxH2^w77ZGYCX{QtW-+CuUgzEl&1R$+2SiLo?J4J0I+oy6+Wxuvh#HulSB7t)puI z!V{;o-Fu+~aNesHTcK(uG zIFQendb~Sbyjd1Kqn{$lv7PJ}+l>`2n~*eT^5jqoSYBue#d3ENAK12iZhb{z_kUtU znd6gTDHD_MRTlv^lVJoXlQ330f1)_UncsZS@y-2BeDm&``0V+^?Kf|J(&i?KRT-Db z&F${SW=d;)Q^ci;4N$f>zeOL@BwqdN_HW~RZ+^;c_)?-(X<&qAAKRv_w>baJPiYxW z)0rxB?dN^BS|^E4qqog!txFSChkLh5qB|f*T~$MK!vp=$oshTz(m<^aPg;%#H*M3` z{ZKbZzh_#zlV>B7w(YU1n{QWZ6PHotzt{KeYMt6>Q&&U%#|m09{jP4R?n%~opgFFq zhPM0mObQ?&w7~|+;oW%+JBs}=gxvl#cYty*xRVfMI zqm=T+Qj&d>u~#2|_EX+Ic2B+Q))NCXclMo4=c>WU%k;^`kjvL!4gfPjIp65W+_{uDHF29J21fwc2lyy&2T~$!qL&PQ=YF$n%g?||UXFss zvjvOKH16#B`B;D@I~|Z+tdX1cctq|_Lx?1WSGVF>uqgttDbBzKNuYNiKIa$NZtJ0L z5y-SPDDZ^~@FoxIMfzGU7ROLO9O_MlTgC4dbh?j>M%a~Yd^T+hYSqm{?GA=@_tb-LSu26io!nCtXN@vni89mxkd`aI51)B)f?Yda4R;ejQ zxu)^!+yes65g9rcpn%#XZpuuVY-A?+B4*Hu7=unkkdx##YA#|e$-4k~qhrR_lMD!E zlBXrmZR&k}5S@g9vr}P?&Q#($s3xXVX&y*3S&piI*=tbsUAM{rQM_N&0AE0$zeRQx zXpE%TfOlzC_@CTK+B(Be~rHHhZlJ0|S9_9#>KLONE^gr6F%{D}v<`o8Vj zQ!lHqPxC6D5nf-FY!<7unBXu?zgSO2pw%T6v??$37r7>*@(GQ>$!;)oDYIzfx&e`& zJ1uDpVjptWe>0T=mogV0(IY^_=^PZ9s3p`YFGg5Ebq9A8?UuDUgn|Zy3cJ(cx(wr3 z!O2fD)QfGM0+}L@?lA@vyAgNB`zg3i^btJe+Ez~v&M(E+Qxh?*zln(g8oDZ zLR+M<@_%OGIp9H&KV#!2PWbyEHrPUc+0HElDS?@1+J+%AetQ-o6UB2Sn}b-kkr9q? zo)xH0tTJU_q|0-SF+#=&41y%BEH}t93?ya%dzdm|pvI&mjGD2FAcN`x8QFU4o5&%B zXAY8Si#4;%=4&4lVATdqGLT zrI>t@>GI6vgWHg4FfZwh7poFGn!xwpU)*$}>=c!=6TY_N61GqVX7#l)i@MpmPoUy) z9-TP$#3sNjSdC-bL0A9Gu@rGROFSSzc#BDZf5D^xakiF-#z-n}N=b;3ARk29S+I+v zoDiQ4a*l!J03Pz#ZVB5B`;C`eqA8L|(91J~AeGi&P>kFg^hZqK&@Lm;1&DT@d}t}j zgyv(7;EXNt{<%K~UU15%u-`dAo8EgizXrTncicQkI^v^8Tn>!4S%l-SNDZj4QIt`8 ze}~WL-ynn@LrrM=dPQNy*}}9rX5x@Ajf0{Kw46Wg6)RuQWIw6PBLGDAWZ~<(B}}-(r|v0uacYS>TjKcRt&+d?;6?4mOhNDOJ>Z zX+kr&Pk)0Xt~<_XnN1)(bS*^a$3+!DZN5^jx^H_d59iq>6*!VsVDQDZ__Zq95|A z5Fa6n8ytCC>WAgz^Oa#1t#BNN4^?x2s_xw)mCIjw7Xdj!fS1&zm;yA0w1wge9tiz3 zblcO=LvD>7t`Q@V-MJbV)#%WCGNLCks!*RSQIA5%Y26!u3CAwU8iJ=O$!Pw2a?OTv;)`|8SlPtP%*Di%34f=TOv*Fm0fJYal+%BFPHKW@&j}3DrE&zVnKgw2lYhvtx1*X< zYT4Xi;i?(AdZQ$+S z3%7L{Kxt5}Hu+boR1$yS0S|6)&-@QU7ipN*fFFE||7eNlNliHyI}#`&g?SslK2iA^ z2I=)6>tEJM7dH z%kgMm(?+b6AF);OW0uh)fxS1j%F8u4pm1t|P}jn&&d{YT#)m$oordh1=3EAHNe7Sm|MkMq15@&T(t>US` z|NiG+e!ac;4r@J+pb=wPk^PH!HzH+3Cn zrMfATI!-iDHaCAnO@BDqEul~u^gB^GM?Oj$ye;Xz= zX20jsxHBV`(&%YuZ_{YBj;mw8WJsd^6Aken+X!K><7wzze0!&ritan6c71o7mC>g? zzOjrNtbA^}$Gh8qJ^XE2=*xFX-Q;mymIW^IP8V@mWY9$G%W`$by_AV?-=!+fbTcvT8mf>69{NwK*et-M$_PV4K z9VdmJMXgth`e+6N^R+{~YESb8chF0RFH~7vW$?mG#c5u0-;Y_EoV}{3f5J{MyLwvE z!NAm7vv2=rFUmcOi(=ZXzuexXiK?PkpuOeNa?12f=b;^y2OGk7q-0h=eA?NLOYIpu z>Oo41KxD6apsK1$s5SGgDed>fcDimi;2m_9&oVAnZ{}#mw(oGBMFH0HF;Tj+8?Jsr zHU7$Fo)r|F{qMtGMQdTZtRao8Xu;-MiqEo!|{HRp`?X zZk2?p)tY3SV-MD}U>z_qoh9PNbe4*yU}@GMI}vgk#ggXi4CjLj!p@?O}`2_qM) zlMn}MHqyCi`e6g-%#xeb5DV{72Ihz(ihUy+?cyr2)XzVd_Ha^`d5Nw@gU1P64OYoc zO0g3ph`gYLUId?=fBh3hg!Z6S8SQ(sAu%HhZ8)tOYDW0`?yf%?5H{C0W;EQ@jl-#d z(_0!2hSg<-Ac|!Du|aa^N6T{s?@8vY>u_OMowgV&fv4Rd)Tq|RQ6I(=%pWNiFb&3;&mF(e?Yqmz!d3v^C6p2i4vQ^ z63-6`XW&b*)nH+JLY;QLFRd4!=r^BQCtMB6cW1gs&-V$%_Vw&7!%4R0AO!c-jrQQV z@I^-6?@l7>ei+?6%o-78t3}k}79K=@Xq!MG0Ic>~ezLVE>B6?4`UW3K^y&ky;69d` z?;MI235}7Kf7#U_hz|77H?xn$vhiKf`)k3^eoAYEqShWvAriS$0K_MM!&Q`xQu=!+ zGEIwE)z1O1MN(b>uh$_VLgmGB^)JGN&20`l-HrCkcxgFG$C)kyOjws0DTvB7_*OR> z20TzBdFEP-1_~i$gz6i9h_1;9theA>C^qt{i%rJyf74kjlnHcUtLLJF>$qEu~2kBS1wp0Tz%R{0e6QLaW;e<5z-^aUOE&~WGnp@OE#iqSl;?r2`c zx(;@9eLx^MqTpmk+i}cB69C%MXmhOr*Kq_$Y)cC(WXs@ray~qzbr&TCSL0w>8F-3R zMIPd$S|2o$`@jhZf8gJ_b&cz&*PhoryL6dqNC~4L_0@-aE?mMo$j5dJ3?Twz3dc@E zf7_oN6YLk;oP5^=Q9po%$JTPru8iKChC$u{Ub|A!Z)?_Gt`7lt@rX+Jm;hW7E`v4} zTIUVLsX1n(RY0Sec<3y}QqdR781*3oHkQ^Bbu$I#SVb=pP4j;L0Sn zRr#$l{Y6;jI1re@zeg(KymeCGys_%He;i2%V%uCygdy}x$~?@3r2usQDtR2oXDiuc z&qp;Mw)_ayw_0R{szM}4X$r*7(-Gdvpy#QAYhq3dkeDiGIj@f!{6VJz6ugkH)*#>P zXTf3_m(_Fk5pgZD6ggx8RSOAPWEFG3R& z#BVs)e%f0mfhQlyz2#83?=J0iS|o8XpX7K^fkyM0az_YtuGvgc#MwMm%HLMYq;VBS zL)TMosw_ahfo88y#q%8ur;+_Ve^8ZpWSoTAL`oCPRJlK@ChJV*tRYtV(?~(bX_WdL zCd(*OB3HnF;tyOa6FN)XrUF8cWQNC+H+bhs(gv!^iBjlbq!G`)f7baV8Pk4j z-YSIvb_Q!@@jO_Pl#}+Bd|6mhYPpSVjLM#7$jGUu!snn$5IPgs%>jYnv_pHBUaVul z5+(sbN_giec|hnU`m^n)H*`~)s#xkWvhOH(PB5VUOj@{3xz>j$$GvInI#5u34-^z| z{>F6<=pTI&c;~7Hj{v>3f0Dj&8ZY(#<_|cbvwZ1qa=&8=G~B@Kvr>?t+s9bZIT_gOO2X?^uN&{JZ#^9;=6&rRO`yXmeePx-zSgC8iv ziV5dmLOT!+mwAYGs#HaW!HU7uTJB-JyJbMYK4I(27?qq6#kic?i_QD>pvz?LrchO^&3HQq`- zyz7aOMNZ<92IZ-Pe++!}O$L7PSG=nL-~)z>{wpdVyw^*#_%Q`_VDS#_n6W?;*3nVaONZE#-lE3_li! z5fYwuGG-k{_mlk=mCURT_Ik5U8PzWevM-XKcY zFx=A|lIduB>KdP<)pG&}TLu&?me{H7$M#5&xzdv5b6k-~3CCRG7Um=shZ6cfe4>h9 z{XC(HRWhFz)p~&2&lq#qV;Vfu3U52%nSpv7dh}aJ^DqSwlVszqdUi=4)$e+6ZBtaP=KOvT|y3N=y~dMG8X;1pY*iN=rB2nywbdUD?QWg1K6XP-(U8-*fJ2qceHlnSXX zi~(Lle@^&Y`qV3BG9o3}6zW1B9pDUh_A8gpuFtrQ3r!D3)r_l@aQ(L_WN)VfeXvQ} zPv1Z)zGBP3E~ZsGuJZ>+z~CUL7aDzIfdy;$@Mn%tRRwM0(}76b_AB$SF9qsw+WX=7 z)j=C5-_F8c+t3G5I4iqd^)*Jl8bM>qil;7DZ@!to@+E>#GK_0czHD+2f=~+ zgR`lQVJ~JGe-FejU!Q?7Cn~2 z6$+VuX3;i9UHR2|>BnYeym4#wW_5r0`{Kb**QQz3U`mvGhpFWjQz;4w1E*lY z8wsS{t9Db4*+~_doXm>0uI-hAwE)t$$peM{Bu@K@KN z!QV+5j5|8dp}BT+-hq?raTEdBl5!M7a7vQVCvrc#m>&Kh2SoA|A_vX*>=SUp-?WYd z3#E8m{h7>QB0gx4U&#L$1rrhzoCLklqa>pl!|q%Wsm<(C2qJ~`??lu5cKz(%<Q* zXKcnSC5-Bswu*4YX1A+nAO4`T1w4E+qeNtO_SJP=VRu24%x25k`)7amE03pURugUo z43-hWw4eLeVtZSa59#THtZ;U!_|WXqGJp6j;l4G!r0waACRWOsHi`%xR{kr_2_0c7 z5GZy1GC~Chu@Wu9H*WU3&@UR0aiZX>S{;A6xMbQSM+MbrO71j0vbY9GN8@x)y^nU?h zb#3{2;Ty{fHebWC=gp(VW|f!g@b2c$cl&ao^gOT1&3@|}URU|U{mZvk??bU^Y%h5<#4G?%=#7au7Vso}s( zD0S$hdUU2W(l4oXO5j{$n?^0KQGX;eM2nxZHW96@M{SjHhI|^e)r?pcwBa|eXUjcm zWWFmvIfK4=B^E6umbDTK5Ma}m&|VQMtL!MN?}F0ZZ}<6f`IuDR3}6LgJ4$!i6D(8= z+mVGDQUdY+ui#w~@MBB)BoTZc4|=p*!iZE&q~+2Q9+sJVjoYvD>M7es_R>0>09p zTa%C!P&p9`0hU^hVVqz@S`p!tHStUk?AEv9`XD6rKeoUn7wf=15LF>ji>*(ixv@e1 z832d$Eqvn_jM!ba8#>iNk4tv_eS}ojPO^PPxobjSUD%K{>&!VwLpxbDj8g9W^K$Du zcqYTmwg^w0MSuoeWVv1x-@==JwGk>pg#fxdOCsS`pvWe!H1=~xfZiKDBFj@F$Rjd;N^G4-TzgQv z-wy$_9JDhOOa

87W-JMTX=~&V1mYwFBN0#;(NkrSLIYvA?IKWg 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
ekf8tsjrU8e2E2 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 z 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

m9}&6UB~HB*n0!S34ksrXV*`7cRBeC~!zFAjW5 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

&%5J}7@XVqo*}FX1|uA|@u0QA)~274>x3 zay4oh5q$pDr}>u-kNJAm^I~|CUW;gVTLQ7!_VVQBn6Qb}U7l%>Bp5DdBU)vDOyR@# zT3Kx>+1P!jePOUJ*m#BWPMldYv8Cr>kMujZ%AtK7^diro=^aX)`GMtsmAMH2iy6hk z#+I(}1w#sCV>f_fR}*sOsSG{SMh!zUyICIA$4p3y1F+ z>;Ifdkmw1pa!Im_a&fVXNpMPXu(I*+vPw#@OLDVuu(3*rv$L@Zk^KKJLHhn9d2@S9 zSF7)X#>)EN+L|(5&elK+Gwiv2x%+v|=|lEnv0=aSLLhrZF`MT$ZeNRF#65f2i6{>J z*u-a$M701d84d+JUpW#<7L`%b3fXEPze%-185)yZ#0puNUrh2xJt~57U}fcCgz5CN z$DMT@aNFgI*XN&4ja#f@TE}qBu8PMfEMCQ zh+WayaCZ#5U-iTUV)!EXWC93r`Gn&56asKivte^_=tSTnbHj5OXCvZPjaJ|xZ$;=< z@pG>9f(I~bd~2v;UB+|Q>z*)Z%Dgw-X^XlAu+oXuO@en zuI@>e$R~s~(0*E$*cNOBIc{*Kd_w7UX&!i{!W_wk-!p-7R(HD0y8_xGdLj#Hj6oBU zCt0)JFzLORO@vl!S5+YAuLf2fuyw)sR@k#MW15N^N*mmQOFcycm6Gk3y5NAv@Ad z(N^TAC7NE^%ETZQH9_Lq)T6Hk_YeXsH;~dc?Z&A87wiaCb@q*C{|9Ulb(~!PR%Gxm z7RS94synGO_SR>$P23SGhD@Fa*n8^i97p%kqN@AAKz9A~sqd#^lA;TQvx4a86?Mcp zDNX*i6WA{QN#c2Sg&0zrgi)AVcADEz# z^c1{^T`$`oc^cNXE0{Ty1DjQn75W5kjl*6O_!D1RIN2Rp;DFJb;`J=BE#sLp`VnnO z?jYg@#`f-EO2043%v>3|GQXUi{xVLbYqf1Yazsb4Qfpk z+KTgeBRcai1gfNx&p1Cu3J%#D639h)4wZA%eH+O{J{F=U;?tIuh(z6yc?l|eG`=W! z)cr4sNsVa!{xLZC$ndj_Dy3`nUf%0Dp)HTmY7d6HYb0XuR}Mt*(bikMMR?Tj7cmvB z%Z?qN9m$(vtj01BFK&Fuy8|7Ot4XQJE@C(A88wwH7wCFZDY~gr5Lga!exL>Vk^g%` z?JrQXe%tAdaHAymNEJD{^j_CY>JU(eOG3A+!;h>Ey|(bLtY z0jpLPO6ivOCjpRxkfrO^mE7n|33f4Iw z+>(3&5gKHXWLI2zJk@zS*%9P>{*8LuNnwd(&HPVUoBx#8NQq$7q~SaXAf%_3j213f z1B~_(R*zas5WzL}P#dWQ=N)C#ISCn?T8k@KeDde{k<>}3C%f;=KYSiuq++61T? zT9$!y$7sLU-`ApQe;qre-e7@BvM&eiMtBZggj#UvM&&?QhZI$odjZ~Lw!v8~ne2QIqkGfyB6 zu$7jvYuU+qUhHSVp8^a;#BSd~F7t&!kb;C}ksTw2Cu?|Ub3^w2QqTK(w~H(BpPYt& zkl_5(ycShDQ3^;lhR6mh>!aZTKgkk^O`=YJaS8aAqlI=o@&_hS&%P;SeZHA?(NRt; zD7{4o*l#9F325GO==h_S_vnJ1RhFw5cBNoR6JmTOl(FA&gI262CkQrAo=;r|X^03P zSm%D=d4dpuu?44d)4=B9?KDX4IDxmotdNz98AmHSGz$xs=@2p2mj;%=cS`3|Bj8Zn zzy&^W8;A9FKmy%Fo0>t{AyUZ*P(A<7g0hI`n<7;5IEO?b(qlME7>9!W=SIfS0gV6e z0f}Du;7&vUE|>+($kdmkOdY3HNrg^qSoOm+KOUl9TZ3K^y5^Pc!bx!|H5Mmc!`(c# zob&kjd7h2y+IXID-CX%!!H))@lx6jmR-Lu$(wPvwHHXDxW1iJPjnLPRA{R}ak9Mhj z&DY&dspFcvbS;j|dcgGro`UYp~x?=xs(D-OHAO2Epwn7>p#FRk#JdatcgjhgF! zismG%{3w*dc&k3Yb&(PfM^^*%89Tb^9i65Fr^*7onK-ZC==z7+x_LFM5K?a*Dtd_y zWj$@}YGuQtUHoG9_Vn!pn5Lba;-X#jv(MMniHj;-|L}|qwY7Wu`R(lyU?2Z?CN#FV za$?%#=;YO_BmU_>GAaU_B1%{ejj0UDISYbUQ}7YLw+0ycBnAfr_oQD#!4e|yvU0Jp M!BJ95DoMfpU!3wWHvj+t diff --git a/doc/UserGuide/LAGraph_h.tex b/doc/UserGuide/LAGraph_h.tex new file mode 100644 index 0000000000..8331a824a2 --- /dev/null +++ b/doc/UserGuide/LAGraph_h.tex @@ -0,0 +1,905 @@ +\begin{verbatim} +int LAGraph_Malloc +( + // output: + void **p, // pointer to allocated block of memory + // input: + size_t nitems, // number of items + size_t size_of_item, // size of each item + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Calloc +( + // output: + void **p, // pointer to allocated block of memory + // input: + size_t nitems, // number of items + size_t size_of_item, // size of each item + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Realloc +( + // input/output: + void **p, // old block to reallocate + // input: + size_t nitems_new, // new number of items in the object + size_t nitems_old, // old number of items in the object + size_t size_of_item, // size of each item + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Free // free a block of memory and set p to NULL +( + // input/output: + void **p, // pointer to object to free, does nothing if NULL + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Init +( + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Version +( + // output: + int version_number [3], // user-provided array of size 3 + char *version_date, // user-provided array of size >= LAGRAPH_MSG_LEN + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Finalize +( + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_New +( + // output: + LAGraph_Graph *G, // the graph to create, NULL if failure + // input/output: + GrB_Matrix *A, // the adjacency matrix of the graph, may be NULL. + // A is moved into G as G->A, and A itself is set + // to NULL to denote that is now a part of G. + // That is, { G->A = A ; A = NULL ; } is performed. + // When G is deleted, G->A is freed. If A is NULL, + // the graph is invalid until G->A is set. + // input: + LAGraph_Kind kind, // the kind of graph. This may be LAGRAPH_UNKNOWN, + // which must then be revised later before the + // graph can be used. + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Delete +( + // input/output: + LAGraph_Graph *G, // the graph to delete; G set to NULL on output. + // All internal GrB_Matrix and GrB_Vector objects are + // freed, including G->A. To keep G->A while deleting + // the graph G, use: + // { A = G->A ; G->A = NULL ; LAGraph_Delete (&G, msg);} + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_DeleteCached +( + // input/output: + LAGraph_Graph G, // G stays valid, only cached properties are freed + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Cached_AT +( + // input/output: + LAGraph_Graph G, // graph for which to compute G->AT + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Cached_IsSymmetricStructure +( + // input/output: + LAGraph_Graph G, // graph to determine the symmetry of structure of A + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Cached_OutDegree +( + // input/output: + LAGraph_Graph G, // graph to determine G->out_degree + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Cached_InDegree +( + // input/output: + LAGraph_Graph G, // graph to determine G->in_degree + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Cached_NSelfEdges +( + // input/output: + LAGraph_Graph G, // graph to compute G->nself_edges + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Cached_EMin +( + // input/output: + LAGraph_Graph G, // graph to determine G->emin + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Cached_EMax +( + // input/output: + LAGraph_Graph G, // graph to determine G->emax + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_DeleteSelfEdges +( + // input/output: + LAGraph_Graph G, // diagonal entries removed, most cached properties + // cleared + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_CheckGraph +( + // input/output: + LAGraph_Graph G, // graph to check + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_GetNumThreads +( + // output: + int *nthreads_hi, // for outer region for nested parallelism + int *nthreads_lo, // for inner region of nested parallelism, or for the + // underlying GraphBLAS library + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_SetNumThreads +( + // input: + int nthreads_hi, + int nthreads_lo, + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Tic +( + double tic [2], // tic [0]: seconds, tic [1]: nanoseconds + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Toc +( + // output: + double *t, // time since last call to LAGraph_Tic + // input: + const double tic [2], // tic from last call to LAGraph_Tic + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_MMRead +( + // output: + GrB_Matrix *A, // handle of matrix to create + // input: + FILE *f, // file to read from, already open + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_MMWrite +( + // input: + GrB_Matrix A, // matrix to write to the file + FILE *f, // file to write it to, must be already open + FILE *fcomments, // optional file with extra comments, may be NULL + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Matrix_Structure +( + // output: + GrB_Matrix *C, // a boolean matrix with same structure of A, with C(i,j) + // set to true if A(i,j) appears in the sparsity structure + // of A. + // input: + GrB_Matrix A, + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Vector_Structure +( + // output: + GrB_Vector *w, // a boolean vector with same structure of u, with w(i) + // set to true if u(i) appears in the sparsity structure + // of u. + // input: + GrB_Vector u, + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_NameOfType +( + // output: + char *name, // name of the type: user provided array of size at + // least LAGRAPH_MAX_NAME_LEN. + // input: + GrB_Type type, // GraphBLAS type + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_TypeFromName +( + // output: + GrB_Type *type, // GraphBLAS type + // input: + char *name, // name of the type: a null-terminated string + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_SizeOfType +( + // output: + size_t *size, // size of the type + // input: + GrB_Type type, // GraphBLAS type + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Matrix_TypeName +( + // output: + char *name, // name of the type of the matrix A (user-provided array + // of size at least LAGRAPH_MAX_NAME_LEN). + // input: + GrB_Matrix A, // matrix to query + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Vector_TypeName +( + // output: + char *name, // name of the type of the vector v (user-provided array + // of size at least LAGRAPH_MAX_NAME_LEN). + // input: + GrB_Vector v, // vector to query + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Scalar_TypeName +( + // output: + char *name, // name of the type of the scalar s (user-provided array + // of size at least LAGRAPH_MAX_NAME_LEN). + // input: + GrB_Scalar s, // scalar to query + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_KindName +( + // output: + char *name, // name of the kind (user provided array of size at least + // LAGRAPH_MAX_NAME_LEN) + // input: + LAGraph_Kind kind, // graph kind + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_SortByDegree +( + // output: + int64_t **P_handle, // P is returned as a permutation vector of size n + // input: + const LAGraph_Graph G, // graph of n nodes + bool byout, // if true, sort G->out_degree, else G->in_degree + bool ascending, // sort in ascending or descending order + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_SampleDegree +( + // output: + double *sample_mean, // sampled mean degree + double *sample_median, // sampled median degree + // input: + const LAGraph_Graph G, // graph of n nodes + bool byout, // if true, sample G->out_degree, else G->in_degree + int64_t nsamples, // number of samples + uint64_t seed, // random number seed + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_DisplayGraph +( + // input: + const LAGraph_Graph G, // graph to display + LAGraph_Print_Level pr, // print level (0 to 5) + FILE *f, // file to write to, must already be open + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Matrix_IsEqual +( + // output: + bool *result, // true if A == B, false if A != B or error + // input: + const GrB_Matrix A, + const GrB_Matrix B, + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Matrix_IsEqual_op +( + // output: + bool *result, // true if A == B, false if A != B or error + // input: + const GrB_Matrix A, + const GrB_Matrix B, + const GrB_BinaryOp op, // comparator to use + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Vector_IsEqual +( + // output: + bool *result, // true if A == B, false if A != B or error + // input: + const GrB_Vector A, + const GrB_Vector B, + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Vector_IsEqual_op +( + // output: + bool *result, // true if A == B, false if A != B or error + // input: + const GrB_Vector A, + const GrB_Vector B, + const GrB_BinaryOp op, // comparator to use + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Matrix_Print +( + // input: + const GrB_Matrix A, // matrix to pretty-print to the file + LAGraph_Print_Level pr, // print level (0 to 5) + FILE *f, // file to write it to, must be already open; use + // stdout or stderr to print to those locations. + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Vector_Print +( + // input: + const GrB_Vector v, // vector to pretty-print to the file + LAGraph_Print_Level pr, // print level (0 to 5) + FILE *f, // file to write it to, must be already open; use + // stdout or stderr to print to those locations. + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Sort1 +( + // input/output: + int64_t *A_0, // size n array + // input: + const int64_t n, + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Sort2 +( + // input/output: + int64_t *A_0, // size n array + int64_t *A_1, // size n array + // input: + const int64_t n, + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_Sort3 +( + // input/output: + int64_t *A_0, // size n array + int64_t *A_1, // size n array + int64_t *A_2, // size n array + // input: + const int64_t n, + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGraph_TriangleCount +( + // output: + uint64_t *ntriangles, // # of triangles + // input/output: + LAGraph_Graph G, + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGr_Init +( + // input: + void * (* user_malloc_function ) (size_t), + void * (* user_calloc_function ) (size_t, size_t), + void * (* user_realloc_function ) (void *, size_t), + void (* user_free_function ) (void *), + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGr_BreadthFirstSearch +( + // output: + GrB_Vector *level, + GrB_Vector *parent, + // input: + const LAGraph_Graph G, + GrB_Index src, + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGr_ConnectedComponents +( + // output: + GrB_Vector *component, // component(i)=s if node i is in the component + // whose representative node is s + // input: + const LAGraph_Graph G, // input graph + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGr_SingleSourceShortestPath +( + // output: + GrB_Vector *path_length, // path_length (i) is the length of the shortest + // path from the source vertex to vertex i + // input: + const LAGraph_Graph G, + GrB_Index source, // source vertex + GrB_Scalar Delta, // delta value for delta stepping + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGr_Betweenness +( + // output: + GrB_Vector *centrality, // centrality(i): betweeness centrality of i + // input: + const LAGraph_Graph G, // input graph + const GrB_Index *sources, // source vertices to compute shortest paths + int32_t ns, // number of source vertices + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGr_PageRank +( + // output: + GrB_Vector *centrality, // centrality(i): pagerank of node i + int *iters, // number of iterations taken + // input: + const LAGraph_Graph G, // input graph + float damping, // damping factor (typically 0.85) + float tol, // stopping tolerance (typically 1e-4) ; + int itermax, // maximum number of iterations (typically 100) + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGr_PageRankGAP +( + // output: + GrB_Vector *centrality, // centrality(i): GAP-style pagerank of node i + int *iters, // number of iterations taken + // input: + const LAGraph_Graph G, // input graph + float damping, // damping factor (typically 0.85) + float tol, // stopping tolerance (typically 1e-4) ; + int itermax, // maximum number of iterations (typically 100) + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +int LAGr_TriangleCount +( + // output: + uint64_t *ntriangles, + // input: + const LAGraph_Graph G, + LAGraph_TriangleCount_Method method, + LAGraph_TriangleCount_Presort *presort, + char *msg +) ; +\end{verbatim} + + + + +\begin{verbatim} +typedef enum +{ + LAGraph_ADJACENCY_UNDIRECTED = 0, // A is square and symmetric; both upper + // and lower triangular parts are + // present. A(i,j) is the edge (i,j) + + LAGraph_ADJACENCY_DIRECTED = 1, // A is square; A(i,j) is the edge (i,j) + + // possible future kinds of graphs: + // LAGraph_ADJACENCY_UNDIRECTED_UNWEIGHTED + // LAGraph_ADJACENCY_DIRECTED_UNWEIGHTED + // LAGraph_ADJACENCY_UNDIRECTED_TRIL + // LAGraph_ADJACENCY_UNDIRECTED_TRIU + // LAGraph_BIPARTITE + // LAGraph_BIPARTITE_DIRECTED + // LAGraph_BIPARTITE_UNDIRECTED + // LAGraph_INCIDENCE_* + // LAGraph_MULTIGRAPH_* + // LAGraph_HYPERGRAPH + // LAGraph_HYPERGRAPH_DIRECTED + // ... + + LAGraph_KIND_UNKNOWN = LAGRAPH_UNKNOWN // the graph kind is unknown +} +LAGraph_Kind ; +\end{verbatim} + + + + +\begin{verbatim} +typedef enum +{ + LAGraph_FALSE = 0, + LAGraph_TRUE = 1, + LAGraph_BOOLEAN_UNKNOWN = LAGRAPH_UNKNOWN +} +LAGraph_Boolean ; +\end{verbatim} + + + + +\begin{verbatim} +typedef enum +{ + LAGraph_VALUE = 0, // cached property is a known value (ignoring roundoff) + LAGraph_BOUND = 1, // cached property is a bound (upper or lower, + // depending on the particular cached property) + LAGraph_STATE_UNKNOWN = LAGRAPH_UNKNOWN, +} +LAGraph_State ; +\end{verbatim} + + + + +\begin{verbatim} +typedef enum +{ + LAGraph_SILENT = 0, // nothing is printed + LAGraph_SUMMARY = 1, // print a terse summary + LAGraph_SHORT = 2, // short description, about 30 entries of a matrix + LAGraph_COMPLETE = 3, // print the entire contents of the object + LAGraph_SHORT_VERBOSE = 4, // LAGraph_SHORT but with "%.15g" for doubles + LAGraph_COMPLETE_VERBOSE = 5 // LAGraph_COMPLETE, but "%.15g" for doubles +} +LAGraph_Print_Level ; +\end{verbatim} + + + + +\begin{verbatim} +typedef enum +{ + LAGraph_TriangleCount_Default = 0, // use default method + LAGraph_TriangleCount_Burkhardt = 1, // sum (sum ((A^2) .* A)) / 6 + LAGraph_TriangleCount_Cohen = 2, // sum (sum ((L * U) .* A)) / 2 + LAGraph_TriangleCount_Sandia = 3, // sum (sum ((L * L) .* L)) + LAGraph_TriangleCount_Sandia2 = 4, // sum (sum ((U * U) .* U)) + LAGraph_TriangleCount_SandiaDot = 5, // sum (sum ((L * U') .* L)) + LAGraph_TriangleCount_SandiaDot2 = 6, // sum (sum ((U * L') .* U)) +} +LAGraph_TriangleCount_Method ; +\end{verbatim} + + + + +\begin{verbatim} +typedef enum +{ + LAGraph_TriangleCount_NoSort = 0, // no sort + LAGraph_TriangleCount_Ascending = 1, // sort by degree, ascending order + LAGraph_TriangleCount_Descending = -1, // sort by degree, descending order + LAGraph_TriangleCount_AutoSort = 2, // auto selection: no sort if rule + // is not triggered. Otherwise: sort in ascending order for methods 3 and + // 5, descending ordering for methods 4 and 6. On output, presort is + // modified to reflect the sorting method used (0, -1, or 1). If presort + // is NULL on input, no sort is performed. +} +LAGraph_TriangleCount_Presort ; +\end{verbatim} + + + + diff --git a/doc/UserGuide/func_extract.py b/doc/UserGuide/func_extract.py new file mode 100644 index 0000000000..74a08bcdfa --- /dev/null +++ b/doc/UserGuide/func_extract.py @@ -0,0 +1,54 @@ +import re +import os +import sys + +def usage(): + print("func_extract.py ") + +def main(): + if len(sys.argv) != 2: + usage() + exit(1) + + header_filename = sys.argv[1] + + # make sure input file exists + if not os.path.isfile(header_filename): + print("{} seems to be missing\n".format(header_filename)) + exit(1) + + # regex pattern + # looking for: + # "LAGRAPH_PUBLIC" followed by new line + # followed by anything (can be multiple lines) + # ends with new line ) ; + # + # e.g. + # + # LAGRAPH_PUBLIC + # int LAGraph_TriangleCount + # ( + # // output: + # uint64_t *ntriangles, // # of triangles + # // input/output: + # LAGraph_Graph G, + # char *msg + # ) ; + # + pattern = "LAGRAPH_PUBLIC\n((.|\n)*?)\n\) ;" + pattern_enum = "typedef enum\n((.|\n)*?) ;" + + with open(header_filename, "r") as f: + header = f.read() + matches = re.findall(pattern, header) + for func in matches: + print("{0}\n\n".format("\\begin{verbatim}\n" + func[0] + + "\n) ;\n\\end{verbatim}\n\n")) + matches = re.findall(pattern_enum, header) + for func in matches: + print("{0}\n\n".format("\\begin{verbatim}\ntypedef enum\n" + + func[0] + " ;\n\\end{verbatim}\n\n")) + +if __name__ == "__main__": + main() + diff --git a/doc/UserGuide/makefile b/doc/UserGuide/makefile index f97993a07a..4c4417a7fc 100644 --- a/doc/UserGuide/makefile +++ b/doc/UserGuide/makefile @@ -1,8 +1,12 @@ -pdf: +pdf: headers pdflatex LAGraph_UserGuide.tex pdflatex LAGraph_UserGuide.tex pdflatex LAGraph_UserGuide.tex +headers: + python3 func_extract.py ../../include/LAGraph.h > LAGraph_h.tex + python3 func_extract.py ../../include/LAGraphX.h > LAGraphX_h.tex + clean: rm -f *.toc *.log *.aux *.out *.lof *.lot diff --git a/experimental/algorithm/LAGraph_AllKCore.c b/experimental/algorithm/LAGraph_AllKCore.c new file mode 100644 index 0000000000..9dde753e45 --- /dev/null +++ b/experimental/algorithm/LAGraph_AllKCore.c @@ -0,0 +1,143 @@ +//------------------------------------------------------------------------------ +// LAGraph_AllKCore: Full K-core Decomposition Using the GraphBLAS API +//------------------------------------------------------------------------------ +// LAGraph, (c) 2022 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause + +// Contributed by Pranav Konduri, Texas A&M University + +//------------------------------------------------------------------------------ + +#define LG_FREE_WORK \ +{ \ + GrB_free (°) ; \ + GrB_free (&q) ; \ + GrB_free (&delta) ; \ + GrB_free (&done) ; \ +} + +#define LG_FREE_ALL \ +{ \ + LG_FREE_WORK \ + GrB_free (decomp) ; \ +} + +#include "LG_internal.h" + + +int LAGraph_KCore_All +( + // outputs: + GrB_Vector *decomp, // kcore decomposition + uint64_t *kmax, + // inputs: + LAGraph_Graph G, // input graph + char *msg +) +{ + LG_CLEAR_MSG ; + + // declare items + GrB_Matrix A = NULL; + GrB_Vector deg = NULL, q = NULL, done = NULL, delta = NULL; + + LG_ASSERT (decomp != NULL, GrB_NULL_POINTER) ; + (*decomp) = NULL ; + + LG_TRY (LAGraph_CheckGraph (G, msg)) ; + + 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 + A = G->A ; + } + else + { + // A is not known to be symmetric + LG_ASSERT_MSG (false, -1005, "G->A must be symmetric") ; + } + + // no self edges can be present + LG_ASSERT_MSG (G->nself_edges == 0, -1004, "G->nself_edges must be zero") ; + + //create work scalars + uint64_t level = 0; //don't set at 1 in case of empty graph getting returned as kmax = 1 + GrB_Index n, todo, nvals, maxDeg ; + GRB_TRY (GrB_Matrix_nrows(&n, A)) ; + + //create deg vector using out_degree property + LG_TRY (LAGraph_Cached_OutDegree(G, msg)) ; + + GRB_TRY (GrB_Vector_dup(°, G->out_degree)) ; //original deg vector is technically 1-core since 0 is omitted + GRB_TRY (GrB_Vector_nvals(&todo, deg)) ; //use todo instead of n since some values are omitted (1-core) + + //retrieve the max degree level of the graph + GRB_TRY (GrB_reduce(&maxDeg, GrB_NULL, GrB_MAX_MONOID_INT64, G->out_degree, GrB_NULL)) ; + + //select int type for work vectors and semirings + GrB_Type int_type = (maxDeg > INT32_MAX) ? GrB_INT64 : GrB_INT32 ; + + GRB_TRY (GrB_Vector_new(&q, int_type, n)); + GRB_TRY (GrB_Vector_new(&done, GrB_BOOL, n)) ; + GRB_TRY (GrB_Vector_new(&delta, int_type, n)) ; + //set output to int64 + GRB_TRY (GrB_Vector_new(decomp, int_type, n)) ; + + //change deg vector to int32 if needed + if(int_type == GrB_INT32){ + GRB_TRY (GrB_Vector_new(°, int_type, n)) ; + GRB_TRY (GrB_assign (deg, G->out_degree, NULL, G->out_degree, GrB_ALL, n, NULL)) ; + } + + // determine semiring types + GrB_IndexUnaryOp valueEQ = (maxDeg > INT32_MAX) ? GrB_VALUEEQ_INT64 : GrB_VALUEEQ_INT32 ; + GrB_IndexUnaryOp valueLE = (maxDeg > INT32_MAX) ? GrB_VALUELE_INT64 : GrB_VALUELE_INT32 ; + GrB_BinaryOp minus_op = (maxDeg > INT32_MAX) ? GrB_MINUS_INT64 : GrB_MINUS_INT32 ; + GrB_Semiring semiring = (maxDeg > INT32_MAX) ? LAGraph_plus_one_int64 : LAGraph_plus_one_int32 ; + +#if LG_SUITESPARSE + GRB_TRY (GxB_set (done, GxB_SPARSITY_CONTROL, GxB_BITMAP + GxB_FULL)) ; // try this + //GRB_TRY (GxB_set (*decomp, GxB_SPARSITY_CONTROL, GxB_BITMAP + GxB_FULL)) ; // try this ... likely not needed... +#endif + + //printf ("\n================================== COMPUTING GrB_KCORE: ==================================\n") ; + while(todo > 0){ + //printf("Level: %ld, todo: %ld\n", level, todo) ; + level++; + // Creating q + GRB_TRY (GrB_select (q, GrB_NULL, GrB_NULL, valueEQ, deg, level, GrB_NULL)) ; // get all nodes with degree = level + GRB_TRY (GrB_Vector_nvals(&nvals, q)); + + //Assign values of deg into decomp (output) + GRB_TRY (GrB_assign (*decomp, deg, NULL, level, GrB_ALL, n, GrB_NULL)) ; + + int round = 0; + // while q not empty + while(nvals > 0){ + // Decrease todo by number of nvals + todo = todo - nvals ; + //add anything in q as true into the done list + GRB_TRY (GrB_assign (done, q, NULL, (bool) true, GrB_ALL, n, GrB_DESC_S)) ; //structure to take care of 0-node cases + + // Create delta (the nodes who lost friends, and how many they lost) + GRB_TRY (GrB_vxm (delta, GrB_NULL, GrB_NULL, semiring, q, A, GrB_NULL)); + + // Create new deg vector (keep anything not in done vector w/ replace command) + GRB_TRY (GrB_eWiseAdd(deg, done, GrB_NULL, minus_op, deg, delta, GrB_DESC_RSC /* try GrB_DESC_RSC */)) ; + + // Update q, set new nvals + GRB_TRY (GrB_select (q, GrB_NULL, GrB_NULL, valueLE, deg, level, GrB_NULL)) ; + + GRB_TRY (GrB_Vector_nvals(&nvals, q)) ; + round++; + } + } + //set kmax + (*kmax) = level; + + LG_FREE_WORK ; + return (GrB_SUCCESS) ; +} + diff --git a/experimental/algorithm/LAGraph_AllKTruss.c b/experimental/algorithm/LAGraph_AllKTruss.c index f0dccb65b6..df9015f03e 100644 --- a/experimental/algorithm/LAGraph_AllKTruss.c +++ b/experimental/algorithm/LAGraph_AllKTruss.c @@ -84,13 +84,14 @@ int LAGraph_AllKTruss // compute all k-trusses of a graph LG_CLEAR_MSG ; int64_t k = 0 ; - LG_ASSERT (Cset != NULL && nstepss != NULL && kmax != NULL && ntris != NULL - && nedges != NULL, GrB_NULL_POINTER) ; + LG_ASSERT (Cset != NULL && nstepss != NULL, GrB_NULL_POINTER) ; + LG_ASSERT (kmax != NULL && ntris != NULL, GrB_NULL_POINTER) ; + LG_ASSERT (nedges != NULL, GrB_NULL_POINTER) ; LG_TRY (LAGraph_CheckGraph (G, msg)) ; if (G->kind == LAGraph_ADJACENCY_UNDIRECTED || (G->kind == LAGraph_ADJACENCY_DIRECTED && - G->structure_is_symmetric == LAGraph_TRUE)) + G->is_symmetric_structure == LAGraph_TRUE)) { // the structure of A is known to be symmetric ; @@ -102,7 +103,7 @@ int LAGraph_AllKTruss // compute all k-trusses of a graph } // no self edges can be present - LG_ASSERT_MSG (G->ndiag == 0, -1004, "G->ndiag must be zero") ; + LG_ASSERT_MSG (G->nself_edges == 0, -1004, "G->nself_edges must be zero") ; //-------------------------------------------------------------------------- // initializations diff --git a/experimental/algorithm/LAGraph_BF_full.c b/experimental/algorithm/LAGraph_BF_full.c index d0258d3004..aebd747872 100644 --- a/experimental/algorithm/LAGraph_BF_full.c +++ b/experimental/algorithm/LAGraph_BF_full.c @@ -208,9 +208,11 @@ GrB_Info LAGraph_BF_full //-------------------------------------------------------------------------- // create matrix Atmp based on A, while its entries become BF_Tuple3 type //-------------------------------------------------------------------------- + GRB_TRY (GrB_Matrix_extractTuples_FP64(I, J, w, &nz, A)); - int nthreads; - LG_TRY (LAGraph_GetNumThreads (&nthreads, NULL)) ; + int nthreads, nthreads_hi, nthreads_lo ; + LG_TRY (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + nthreads = nthreads_hi * nthreads_lo ; printf ("nthreads %d\n", nthreads) ; #pragma omp parallel for num_threads(nthreads) schedule(static) for (GrB_Index k = 0; k < nz; k++) diff --git a/experimental/algorithm/LAGraph_BF_full1.c b/experimental/algorithm/LAGraph_BF_full1.c index b295808223..0a56470a54 100644 --- a/experimental/algorithm/LAGraph_BF_full1.c +++ b/experimental/algorithm/LAGraph_BF_full1.c @@ -238,9 +238,11 @@ GrB_Info LAGraph_BF_full1 //-------------------------------------------------------------------------- // create matrix Atmp based on A, while its entries become BF_Tuple3 type //-------------------------------------------------------------------------- + GRB_TRY (GrB_Matrix_extractTuples_FP64(I, J, w, &nz, A)); - int nthreads; - LG_TRY (LAGraph_GetNumThreads (&nthreads, NULL)) ; + int nthreads, nthreads_hi, nthreads_lo ; + LG_TRY (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + nthreads = nthreads_hi * nthreads_lo ; printf ("nthreads %d\n", nthreads) ; #pragma omp parallel for num_threads(nthreads) schedule(static) for (GrB_Index k = 0; k < nz; k++) diff --git a/experimental/algorithm/LAGraph_BF_full1a.c b/experimental/algorithm/LAGraph_BF_full1a.c index 0d636867e1..cb1581c5af 100644 --- a/experimental/algorithm/LAGraph_BF_full1a.c +++ b/experimental/algorithm/LAGraph_BF_full1a.c @@ -230,9 +230,11 @@ GrB_Info LAGraph_BF_full1a //-------------------------------------------------------------------------- // create matrix Atmp based on A, while its entries become BF_Tuple3 type //-------------------------------------------------------------------------- + GRB_TRY (GrB_Matrix_extractTuples_FP64(I, J, w, &nz, A)); - int nthreads; - LG_TRY (LAGraph_GetNumThreads (&nthreads, NULL)) ; + int nthreads, nthreads_hi, nthreads_lo ; + LG_TRY (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + nthreads = nthreads_hi * nthreads_lo ; printf ("nthreads %d\n", nthreads) ; #pragma omp parallel for num_threads(nthreads) schedule(static) for (GrB_Index k = 0; k < nz; k++) diff --git a/experimental/algorithm/LAGraph_BF_full2.c b/experimental/algorithm/LAGraph_BF_full2.c index e9e6f52a9f..4c1b1cc913 100644 --- a/experimental/algorithm/LAGraph_BF_full2.c +++ b/experimental/algorithm/LAGraph_BF_full2.c @@ -228,9 +228,11 @@ GrB_Info LAGraph_BF_full2 //-------------------------------------------------------------------------- // create matrix Atmp based on A, while its entries become BF_Tuple3 type //-------------------------------------------------------------------------- + GRB_TRY (GrB_Matrix_extractTuples_FP64(I, J, w, &nz, A)); - int nthreads; - LG_TRY( LAGraph_GetNumThreads (&nthreads, NULL)) ; + int nthreads, nthreads_hi, nthreads_lo ; + LG_TRY (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + nthreads = nthreads_hi * nthreads_lo ; printf ("nthreads %d\n", nthreads) ; #pragma omp parallel for num_threads(nthreads) schedule(static) for (GrB_Index k = 0; k < nz; k++) diff --git a/experimental/algorithm/LAGraph_KCore.c b/experimental/algorithm/LAGraph_KCore.c new file mode 100644 index 0000000000..9091389301 --- /dev/null +++ b/experimental/algorithm/LAGraph_KCore.c @@ -0,0 +1,131 @@ +//------------------------------------------------------------------------------ +// LAGraph_KCore: Single K-core Decomposition Using the GraphBLAS API +//------------------------------------------------------------------------------ +// LAGraph, (c) 2022 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause + +// Contributed by Pranav Konduri, Texas A&M University + +//------------------------------------------------------------------------------ + +#define LG_FREE_WORK \ +{ \ + GrB_free (°) ; \ + GrB_free (&q) ; \ + GrB_free (&delta) ; \ + GrB_free (&done) ; \ +} + +#define LG_FREE_ALL \ +{ \ + LG_FREE_WORK \ + GrB_free (decomp) ; \ +} + +#include "LG_internal.h" + + +int LAGraph_KCore +( + // outputs: + GrB_Vector *decomp, // kcore decomposition + // inputs: + LAGraph_Graph G, // input graph + uint64_t k, //k level to compare to + char *msg +) +{ + LG_CLEAR_MSG ; + + // declare items + GrB_Matrix A = NULL; + GrB_Vector deg = NULL, q = NULL, done = NULL, delta = NULL; + + LG_ASSERT (decomp != NULL, GrB_NULL_POINTER) ; + (*decomp) = NULL ; + + LG_TRY (LAGraph_CheckGraph (G, msg)) ; + + 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 + A = G->A ; + } + else + { + // A is not known to be symmetric + LG_ASSERT_MSG (false, -1005, "G->A must be symmetric") ; + } + + // no self edges can be present + LG_ASSERT_MSG (G->nself_edges == 0, -1004, "G->nself_edges must be zero") ; + + //create work scalars + GrB_Index n, qnvals, degnvals, maxDeg; + GRB_TRY (GrB_Matrix_nrows(&n, A)) ; + + //create deg vector using rowdegree property + LG_TRY (LAGraph_Cached_OutDegree(G, msg)) ; + GRB_TRY (GrB_Vector_dup(°, G->out_degree)) ; //original deg vector is technically 1-core since 0 is omitted + GRB_TRY (GrB_Vector_nvals(°nvals, deg)) ; + + //retrieve the max degree level of the graph + GRB_TRY (GrB_reduce(&maxDeg, GrB_NULL, GrB_MAX_MONOID_INT64, G->out_degree, GrB_NULL)) ; + + //select int type for work vectors and semirings + GrB_Type int_type = (maxDeg > INT32_MAX) ? GrB_INT64 : GrB_INT32 ; + + GRB_TRY (GrB_Vector_new(&q, int_type, n)); + GRB_TRY (GrB_Vector_new(&done, GrB_BOOL, n)) ; + GRB_TRY (GrB_Vector_new(&delta, int_type, n)) ; + //set output to int64 + GRB_TRY (GrB_Vector_new(decomp, int_type, n)) ; + + //change deg vector to int32 if needed + if(int_type == GrB_INT32){ + GRB_TRY (GrB_Vector_new(°, int_type, n)) ; + GRB_TRY (GrB_assign (deg, G->out_degree, NULL, G->out_degree, GrB_ALL, n, NULL)) ; + } + + // determine semiring types + GrB_IndexUnaryOp valueLT = (maxDeg > INT32_MAX) ? GrB_VALUELT_INT64 : GrB_VALUELT_INT32 ; + GrB_BinaryOp minus_op = (maxDeg > INT32_MAX) ? GrB_MINUS_INT64 : GrB_MINUS_INT32 ; + GrB_Semiring semiring = (maxDeg > INT32_MAX) ? LAGraph_plus_one_int64 : LAGraph_plus_one_int32 ; + + +#if LG_SUITESPARSE + GRB_TRY (GxB_set (done, GxB_SPARSITY_CONTROL, GxB_BITMAP + GxB_FULL)) ; // try this + //GRB_TRY (GxB_set (*decomp, GxB_SPARSITY_CONTROL, GxB_BITMAP + GxB_FULL)) ; // try this ... likely not needed +#endif + + // Creating q + GRB_TRY (GrB_select (q, GrB_NULL, GrB_NULL, valueLT, deg, k, GrB_NULL)) ; // get all nodes with degree = level + GRB_TRY (GrB_Vector_nvals(&qnvals, q)); + + // while q not empty + int round = 0; + while(qnvals > 0 && degnvals > 0){ + round++; + //add anything in q as true into the done list + GRB_TRY (GrB_assign (done, q, NULL, (bool) true, GrB_ALL, n, GrB_DESC_S)) ; //structure to take care of 0-node cases + + // Create delta (the nodes who lost friends, and how many they lost) (push version) + GRB_TRY (GrB_vxm (delta, GrB_NULL, GrB_NULL, semiring, q, A, GrB_NULL)); + + // Create new deg vector (keep anything not in done vector) + GRB_TRY (GrB_eWiseAdd(deg, done, GrB_NULL, minus_op, deg, delta, GrB_DESC_RSC)) ; + + // Update q, set new nvals + GRB_TRY (GrB_select (q, GrB_NULL, GrB_NULL, valueLT, deg, k, GrB_NULL)) ; + GRB_TRY (GrB_Vector_nvals(&qnvals, q)) ; + GRB_TRY (GrB_Vector_nvals(°nvals, deg)) ; + } + //Assign values of deg to decomp + GRB_TRY (GrB_assign (*decomp, deg, NULL, k, GrB_ALL, n, GrB_NULL)) ; + GRB_TRY(GrB_Vector_wait(*decomp, GrB_MATERIALIZE)); + LG_FREE_WORK ; + return (GrB_SUCCESS) ; +} + diff --git a/experimental/algorithm/LAGraph_KCoreDecompose.c b/experimental/algorithm/LAGraph_KCoreDecompose.c new file mode 100644 index 0000000000..2cf4b9fb63 --- /dev/null +++ b/experimental/algorithm/LAGraph_KCoreDecompose.c @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------------ +// LAGraph_KCoreDecompose: Helper method to LAGraph_KCore and LAGraph_AllKCore +// that performs graph decomposition given a specified value k. +//------------------------------------------------------------------------------ +// LAGraph, (c) 2022 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause + +// Contributed by Pranav Konduri, Texas A&M University + +//------------------------------------------------------------------------------ + +#define LG_FREE_WORK \ +{ \ + GrB_free (&C) ; \ + GrB_free (°) ; \ +} + +#define LG_FREE_ALL \ +{ \ + LG_FREE_WORK \ + GrB_free (D) ; \ +} + +#include "LG_internal.h" + + +int LAGraph_KCore_Decompose +( + // outputs: + GrB_Matrix *D, // kcore decomposition + // inputs: + LAGraph_Graph G, // input graph + GrB_Vector decomp, // input decomposition matrix + uint64_t k, + char *msg +) +{ + LG_CLEAR_MSG ; + + // declare items + GrB_Matrix A = NULL, C = NULL; + GrB_Vector deg = NULL; + + + LG_ASSERT (D != NULL, GrB_NULL_POINTER) ; + (*D) = NULL ; + + LG_TRY (LAGraph_CheckGraph (G, msg)) ; + + 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 + A = G->A ; + } + else + { + // A is not known to be symmetric + LG_ASSERT_MSG (false, -1005, "G->A must be symmetric") ; + } + + // no self edges can be present + // todo: what would happen if there are self edges? + LG_ASSERT_MSG (G->nself_edges == 0, -1004, "G->nself_edges must be zero") ; + + //create work scalars + GrB_Index nrows, n; + GRB_TRY (GrB_Matrix_nrows(&nrows, A)) ; + GRB_TRY (GrB_Vector_size(&n, decomp)) ; + LG_ASSERT_MSG (nrows == n, -1003, "Size of vector and rows of matrix must be same") ; + + //Create Vectors and Matrices + GRB_TRY (GrB_Vector_new(°, GrB_INT64, n)) ; + GRB_TRY (GrB_Matrix_new(D, GrB_INT64, n, n)) ; + + //create deg vector using select + GRB_TRY (GrB_select (deg, GrB_NULL, GrB_NULL, GrB_VALUEGE_INT64, decomp, k, GrB_NULL)) ; + + //create decomposition matrix (C * A * C) + + #if LAGRAPH_SUITESPARSE + #if GxB_IMPLEMENTATION >= GxB_VERSION (7,0,0) + // SuiteSparse 7.x and later: + GRB_TRY (GrB_Matrix_diag(&C, deg, 0)) ; + #else + // SuiteSparse 6.x and earlier, which had the incorrect signature: + GRB_TRY (GrB_Matrix_new(&C, GrB_INT64, n, n)) ; + GRB_TRY (GrB_Matrix_diag(C, deg, 0)) ; + #endif + #else + // standard GrB: + GRB_TRY (GrB_Matrix_diag(&C, deg, 0)) ; + #endif + + GRB_TRY (GrB_mxm (*D, NULL, NULL, GxB_ANY_SECONDI_INT64, C, A, GrB_NULL)) ; + GRB_TRY (GrB_mxm (*D, NULL, NULL, GxB_MIN_SECONDI_INT64, *D, C, GrB_NULL)) ; + + //Assigns all values as 1 (todo: change to something cleaner) + GRB_TRY (GrB_assign (*D, *D, NULL, (int64_t) 1, GrB_ALL, n, GrB_ALL, n, GrB_DESC_S)) ; + + LG_FREE_WORK ; + return (GrB_SUCCESS) ; +} + diff --git a/experimental/algorithm/LAGraph_KTruss.c b/experimental/algorithm/LAGraph_KTruss.c index d8007fbcaa..b4294bed6d 100644 --- a/experimental/algorithm/LAGraph_KTruss.c +++ b/experimental/algorithm/LAGraph_KTruss.c @@ -60,7 +60,7 @@ int LAGraph_KTruss // compute the k-truss of a graph if (G->kind == LAGraph_ADJACENCY_UNDIRECTED || (G->kind == LAGraph_ADJACENCY_DIRECTED && - G->structure_is_symmetric == LAGraph_TRUE)) + G->is_symmetric_structure == LAGraph_TRUE)) { // the structure of A is known to be symmetric ; @@ -72,7 +72,7 @@ int LAGraph_KTruss // compute the k-truss of a graph } // no self edges can be present - LG_ASSERT_MSG (G->ndiag == 0, -1004, "G->ndiag must be zero") ; + LG_ASSERT_MSG (G->nself_edges == 0, -1004, "G->nself_edges must be zero") ; //-------------------------------------------------------------------------- // initializations diff --git a/experimental/algorithm/LAGraph_MaximalIndependentSet.c b/experimental/algorithm/LAGraph_MaximalIndependentSet.c index 46f0649965..b485d1486f 100644 --- a/experimental/algorithm/LAGraph_MaximalIndependentSet.c +++ b/experimental/algorithm/LAGraph_MaximalIndependentSet.c @@ -42,9 +42,9 @@ // mis[i] == true implies node i is a member of the set. // The graph cannot have any self edges, and it must be symmetric. Self-edges -// (diagonal entries) will cause the method to stall, and thus G->ndiag must be -// zero on input. G->rowdegree must be present on input. It must not contain -// any explicit zeros (this is handled by LAGraph_Property_RowDegree). +// (diagonal entries) will cause the method to stall, and thus G->nself_edges +// must be zero on input. G->out_degree must be present on input. It must not +// contain any explicit zeros (this is handled by LAGraph_Cached_OutDegree). // Singletons require special treatment. Since they have no neighbors, their // score is never greater than the max of their neighbors, so they never get @@ -79,7 +79,7 @@ int LAGraph_MaximalIndependentSet // maximal independent set GrB_Vector candidates = NULL ; // candidate nodes GrB_Vector empty = NULL ; // an empty vector GrB_Vector Seed = NULL ; // random number seed vector - GrB_Vector degree = NULL ; // (float) G->rowdegree + GrB_Vector degree = NULL ; // (float) G->out_degree GrB_Matrix A ; // G->A, the adjacency matrix GrB_Index n ; // # of nodes @@ -88,7 +88,7 @@ int LAGraph_MaximalIndependentSet // maximal independent set if (G->kind == LAGraph_ADJACENCY_UNDIRECTED || (G->kind == LAGraph_ADJACENCY_DIRECTED && - G->structure_is_symmetric == LAGraph_TRUE)) + G->is_symmetric_structure == LAGraph_TRUE)) { // the structure of A is known to be symmetric A = G->A ; @@ -99,8 +99,9 @@ int LAGraph_MaximalIndependentSet // maximal independent set LG_ASSERT_MSG (false, -105, "G->A must be symmetric") ; } - LG_ASSERT_MSG (G->rowdegree != NULL, -106, "G->rowdegree must be defined") ; - LG_ASSERT_MSG (G->ndiag == 0, -107, "G->ndiag must be zero") ; + LG_ASSERT_MSG (G->out_degree != NULL, -106, + "G->out_degree must be defined") ; + LG_ASSERT_MSG (G->nself_edges == 0, -107, "G->nself_edges must be zero") ; //-------------------------------------------------------------------------- // initializations @@ -117,8 +118,8 @@ int LAGraph_MaximalIndependentSet // maximal independent set GRB_TRY (GrB_Vector_new (&score, GrB_FP32, n)) ; GRB_TRY (GrB_Vector_new (&iset, GrB_BOOL, n)) ; - // degree = (float) G->rowdegree - GRB_TRY (GrB_assign (degree, NULL, NULL, G->rowdegree, GrB_ALL, n, NULL)) ; + // degree = (float) G->out_degree + GRB_TRY (GrB_assign (degree, NULL, NULL, G->out_degree, GrB_ALL, n, NULL)) ; //-------------------------------------------------------------------------- // remove singletons (nodes of degree zero) and handle ignore_node @@ -258,14 +259,14 @@ int LAGraph_MaximalIndependentSet // maximal independent set // push // new_neighbors{candidates,replace} = new_members' * A GRB_TRY (GrB_vxm (new_neighbors, candidates, NULL, - LAGraph_structural_bool, new_members, A, GrB_DESC_RS)) ; + LAGraph_any_one_bool, new_members, A, GrB_DESC_RS)) ; } else { // pull // new_neighbors{candidates,replace} = A * new_members GRB_TRY (GrB_mxv (new_neighbors, candidates, NULL, - LAGraph_structural_bool, A, new_members, GrB_DESC_RS)) ; + LAGraph_any_one_bool, A, new_members, GrB_DESC_RS)) ; } // remove new neighbors of new members from set of candidates diff --git a/experimental/algorithm/LAGraph_VertexCentrality_Triangle.c b/experimental/algorithm/LAGraph_VertexCentrality_Triangle.c index 14a4b1633e..b0ff6de416 100644 --- a/experimental/algorithm/LAGraph_VertexCentrality_Triangle.c +++ b/experimental/algorithm/LAGraph_VertexCentrality_Triangle.c @@ -109,7 +109,7 @@ int LAGraph_VertexCentrality_Triangle // vertex triangle-centrality if (G->kind == LAGraph_ADJACENCY_UNDIRECTED || (G->kind == LAGraph_ADJACENCY_DIRECTED && - G->structure_is_symmetric == LAGraph_TRUE)) + G->is_symmetric_structure == LAGraph_TRUE)) { // the structure of A is known to be symmetric A = G->A ; @@ -121,7 +121,7 @@ int LAGraph_VertexCentrality_Triangle // vertex triangle-centrality } // no self edges can be present - LG_ASSERT_MSG (G->ndiag == 0, -1004, "G->ndiag must be zero") ; + LG_ASSERT_MSG (G->nself_edges == 0, -1004, "G->nself_edges must be zero") ; //-------------------------------------------------------------------------- // create the T matrix diff --git a/experimental/algorithm/LAGraph_cdlp.c b/experimental/algorithm/LAGraph_cdlp.c index 9102b8ab26..b1fecbc321 100644 --- a/experimental/algorithm/LAGraph_cdlp.c +++ b/experimental/algorithm/LAGraph_cdlp.c @@ -258,8 +258,6 @@ int LAGraph_cdlp GRB_TRY (GrB_transpose (AT, NULL, NULL, A, NULL)) ; } - int nthreads; - LAGraph_GetNumThreads(&nthreads, NULL); for (int iteration = 0; iteration < itermax; iteration++) { // Initialize data structures for extraction from 'AL_in' and (for directed graphs) 'AL_out' @@ -282,7 +280,7 @@ int LAGraph_cdlp GrB_NULL, &X[nz], &nz, AT)); } - LAGraph_Sort2((int64_t *) I, (int64_t *) X, nnz, nthreads, NULL); + LAGraph_Sort2((int64_t *) I, (int64_t *) X, nnz, NULL); // save current labels for comparison by swapping L and L_prev GrB_Matrix L_swap = L; diff --git a/experimental/algorithm/LG_CC_FastSV5.c b/experimental/algorithm/LG_CC_FastSV5.c index bd868a3e30..1f3818e8a0 100644 --- a/experimental/algorithm/LG_CC_FastSV5.c +++ b/experimental/algorithm/LG_CC_FastSV5.c @@ -347,7 +347,7 @@ int LG_CC_FastSV5 // SuiteSparse:GraphBLAS method, with GxB extensions LG_ASSERT_MSG ((G->kind == LAGraph_ADJACENCY_UNDIRECTED || (G->kind == LAGraph_ADJACENCY_DIRECTED && - G->structure_is_symmetric == LAGraph_TRUE)), + G->is_symmetric_structure == LAGraph_TRUE)), -1001, "G->A must be known to be symmetric") ; GrB_Matrix S = G->A ; @@ -368,8 +368,10 @@ int LG_CC_FastSV5 // SuiteSparse:GraphBLAS method, with GxB extensions //-------------------------------------------------------------------------- // determine # of threads to use for Reduce_assign - int nthreads ; - LG_TRY (LAGraph_GetNumThreads (&nthreads, NULL)) ; + int nthreads, nthreads_hi, nthreads_lo ; + LG_TRY (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + nthreads = nthreads_hi * nthreads_lo ; + nthreads = LAGRAPH_MIN (nthreads, n / 16) ; nthreads = LAGRAPH_MAX (nthreads, 1) ; diff --git a/experimental/benchmark/AllKCore_demo.c b/experimental/benchmark/AllKCore_demo.c new file mode 100644 index 0000000000..cd21354698 --- /dev/null +++ b/experimental/benchmark/AllKCore_demo.c @@ -0,0 +1,143 @@ +//------------------------------------------------------------------------------ +// LAGraph/experimental/benchmark/AllKCore_demo.c: benchmark for kcore (single k-core) +//------------------------------------------------------------------------------ + +// LAGraph, (c) 2022 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause + +// Contributed by Pranav Konduri, Texas A&M University + +//------------------------------------------------------------------------------ + + +#include "../../src/benchmark/LAGraph_demo.h" +#include "LAGraphX.h" + +// #define NTHREAD_LIST 2 + +#define NTHREAD_LIST 1 +#define THREAD_LIST 0 + +// #define NTHREAD_LIST 6 +// #define THREAD_LIST 64, 32, 24, 12, 8, 4 + +// #define NTHREAD_LIST 7 +// #define THREAD_LIST 40, 20, 16, 8, 4, 2, 1 + +#define LG_FREE_ALL \ +{ \ + LAGraph_Delete (&G, NULL) ; \ + GrB_free (&A) ; \ + GrB_free (&D) ; \ + GrB_free (&c) ; \ +} + +int main (int argc, char **argv) +{ + //-------------------------------------------------------------------------- + // initialize LAGraph and GraphBLAS + //-------------------------------------------------------------------------- + char msg [LAGRAPH_MSG_LEN] ; + + GrB_Vector c = NULL ; + GrB_Matrix A = NULL ; + GrB_Matrix D = NULL ; + LAGraph_Graph G = NULL ; + uint64_t kmax; + + // start GraphBLAS and LAGraph + bool burble = false ; + demo_init (burble) ; + + int ntrials = 1 ; //todo: change to higher # later + printf ("# of trials: %d\n", ntrials) ; + + int nt = NTHREAD_LIST ; + int Nthreads [20] = { 0, THREAD_LIST } ; + int nthreads_min ; + int nthreads_max ; + LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_max, &nthreads_min, NULL)) ; + if (Nthreads [1] == 0) + { + // create thread list automatically + Nthreads [1] = nthreads_max ; + for (int t = 2 ; t <= nt ; t++) + { + Nthreads [t] = Nthreads [t-1] / 2 ; + if (Nthreads [t] == 0) nt = t-1 ; + } + } + printf ("threads to test: ") ; + for (int t = 1 ; t <= nt ; t++) + { + int nthreads = Nthreads [t] ; + if (nthreads > nthreads_max) continue ; + printf (" %d", nthreads) ; + } + printf ("\n") ; + + //-------------------------------------------------------------------------- + // read in the graph + //-------------------------------------------------------------------------- + + char *matrix_name = (argc > 1) ? argv [1] : "stdin" ; + LAGRAPH_TRY (readproblem (&G, NULL, + true, true, true, NULL, false, argc, argv)) ; + + GrB_Index n, nvals ; + GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; + GRB_TRY (GrB_Matrix_nvals (&nvals, G->A)) ; + // LAGRAPH_TRY (LAGraph_DisplayGraph (G, LAGraph_SHORT, stdout, msg)) ; + GRB_TRY (GrB_Matrix_new (&A, GrB_INT64, n, n)) ; + GRB_TRY (GrB_assign (A, G->A, NULL, (double) 1, + GrB_ALL, n, GrB_ALL, n, GrB_DESC_S)) ; + GrB_free (&(G->A)) ; + G->A = A ; + + GRB_TRY (GrB_Matrix_new (&D, GrB_INT64, n, n)) ; + + //-------------------------------------------------------------------------- + // kcore testing + //-------------------------------------------------------------------------- + + // warmup for more accurate timing + double tic [2], tt ; + LAGRAPH_TRY (LAGraph_SetNumThreads (24, 24, msg)) ; + LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; + LAGRAPH_TRY (LAGraph_KCore_All (&c, &kmax, G, msg)) ; + LAGRAPH_TRY (LAGraph_Toc (&tt, tic, NULL)) ; + printf("warmup time: %g sec\n\n", tt) ; + //LAGRAPH_TRY (LAGraph_KCore_Decompose (&D, G, &c, kmax, msg)) ; + + GRB_TRY (GrB_free (&c)) ; + + //GRB_TRY (GrB_free (&D)) ; + + for (int t = 1 ; t <= nt ; t++) + { + int nthreads = Nthreads [t] ; + if (nthreads > nthreads_max) continue ; + LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads, nthreads, msg)) ; + double ttot = 0, ttrial [100] ; + for (int trial = 0 ; trial < ntrials ; trial++) + { + LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; + LAGRAPH_TRY (LAGraph_KCore_All (&c, &kmax, G, msg)) ; + GRB_TRY (GrB_free (&c)) ; + LAGRAPH_TRY (LAGraph_Toc (&ttrial [trial], tic, NULL)) ; + ttot += ttrial [trial] ; + printf ("threads %2d trial %2d: %12.6f sec\n", + nthreads, trial, ttrial [trial]) ; + } + ttot = ttot / ntrials ; + + printf ("Avg: " + "nthreads: %3d time: %12.6f matrix: %s\n", + nthreads, ttot, matrix_name) ; + } + + LG_FREE_ALL ; + LAGRAPH_TRY (LAGraph_Finalize (msg)) ; + return (GrB_SUCCESS) ; +} + diff --git a/experimental/benchmark/KCore_demo.c b/experimental/benchmark/KCore_demo.c new file mode 100644 index 0000000000..6905b4d4fe --- /dev/null +++ b/experimental/benchmark/KCore_demo.c @@ -0,0 +1,143 @@ +//------------------------------------------------------------------------------ +// LAGraph/experimental/benchmark/KCore_demo.c: benchmark for kcore (single k-core) +//------------------------------------------------------------------------------ + +// LAGraph, (c) 2022 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause + +// Contributed by Pranav Konduri, Texas A&M University + +//------------------------------------------------------------------------------ + + + +#include "../../src/benchmark/LAGraph_demo.h" +#include "LAGraphX.h" + +// #define NTHREAD_LIST 2 + +// #define NTHREAD_LIST 1 +// #define THREAD_LIST 0 + +// #define NTHREAD_LIST 6 +// #define THREAD_LIST 64, 32, 24, 12, 8, 4 + +#define NTHREAD_LIST 7 +#define THREAD_LIST 40, 20, 16, 8, 4, 2, 1 + +#define LG_FREE_ALL \ +{ \ + LAGraph_Delete (&G, NULL) ; \ + GrB_free (&A) ; \ + GrB_free (&D) ; \ + GrB_free (&c) ; \ +} + +int main (int argc, char **argv) +{ + //-------------------------------------------------------------------------- + // initialize LAGraph and GraphBLAS + //-------------------------------------------------------------------------- + char msg [LAGRAPH_MSG_LEN] ; + + GrB_Vector c = NULL ; + GrB_Matrix A = NULL ; + GrB_Matrix D = NULL ; + LAGraph_Graph G = NULL ; + + + // start GraphBLAS and LAGraph + bool burble = false ; + demo_init (burble) ; + + int ntrials = 3 ; + printf ("# of trials: %d\n", ntrials) ; + + int nt = NTHREAD_LIST ; + int Nthreads [20] = { 0, THREAD_LIST } ; + int nthreads_min ; + int nthreads_max ; + LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_max, &nthreads_min, NULL)) ; + if (Nthreads [1] == 0) + { + // create thread list automatically + Nthreads [1] = nthreads_max ; + for (int t = 2 ; t <= nt ; t++) + { + Nthreads [t] = Nthreads [t-1] / 2 ; + if (Nthreads [t] == 0) nt = t-1 ; + } + } + printf ("threads to test: ") ; + for (int t = 1 ; t <= nt ; t++) + { + int nthreads = Nthreads [t] ; + if (nthreads > nthreads_max) continue ; + printf (" %d", nthreads) ; + } + printf ("\n") ; + + //-------------------------------------------------------------------------- + // read in the graph + //-------------------------------------------------------------------------- + + char *matrix_name = (argc > 1) ? argv [1] : "stdin" ; + int k = (argc > 2) ? atoi(argv [2]) : 0; + LAGRAPH_TRY (readproblem (&G, NULL, + true, true, true, NULL, false, argc, argv)) ; + + GrB_Index n, nvals ; + GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; + GRB_TRY (GrB_Matrix_nvals (&nvals, G->A)) ; + // LAGRAPH_TRY (LAGraph_DisplayGraph (G, LAGraph_SHORT, stdout, msg)) ; + GRB_TRY (GrB_Matrix_new (&A, GrB_INT64, n, n)) ; + GRB_TRY (GrB_assign (A, G->A, NULL, (double) 1, + GrB_ALL, n, GrB_ALL, n, GrB_DESC_S)) ; + GrB_free (&(G->A)) ; + G->A = A ; + + GRB_TRY (GrB_Matrix_new (&D, GrB_INT64, n, n)) ; + + //-------------------------------------------------------------------------- + // kcore testing + //-------------------------------------------------------------------------- + + // warmup for more accurate timing + double tic [2], tt ; + LAGRAPH_TRY (LAGraph_SetNumThreads (24, 24, msg)) ; + LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; + LAGRAPH_TRY (LAGraph_KCore (&c, G, k, msg)) ; + LAGRAPH_TRY (LAGraph_Toc (&tt, tic, NULL)) ; + printf("warmup time: %g sec\n\n", tt) ; + // LAGRAPH_TRY (LAGraph_KCore_Decompose (&D, G, &c, k, msg)) ; + GRB_TRY (GrB_free (&c)) ; + //GRB_TRY (GrB_free(&D)) ; + + for (int t = 1 ; t <= nt ; t++) + { + int nthreads = Nthreads [t] ; + if (nthreads > nthreads_max) continue ; + LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads, nthreads, msg)) ; + double ttot = 0, ttrial [100] ; + for (int trial = 0 ; trial < ntrials ; trial++) + { + LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; + LAGRAPH_TRY (LAGraph_KCore (&c, G, k, msg)) ; + GRB_TRY (GrB_free (&c)) ; + LAGRAPH_TRY (LAGraph_Toc (&ttrial [trial], tic, NULL)) ; + ttot += ttrial [trial] ; + printf ("threads %2d trial %2d: %12.6f sec\n", + nthreads, trial, ttrial [trial]) ; + } + ttot = ttot / ntrials ; + + printf ("Avg: " + "nthreads: %3d time: %12.6f matrix: %s\n", + nthreads, ttot, matrix_name) ; + } + + LG_FREE_ALL ; + LAGRAPH_TRY (LAGraph_Finalize (msg)) ; + return (GrB_SUCCESS) ; +} + diff --git a/experimental/benchmark/dnn_demo.c b/experimental/benchmark/dnn_demo.c index b83c9f0eb4..09592771b2 100644 --- a/experimental/benchmark/dnn_demo.c +++ b/experimental/benchmark/dnn_demo.c @@ -280,8 +280,9 @@ int main (int argc, char **argv) if (type == GrB_FP64) printf ("double\n") ; else printf ("float\n") ; // get the max # of threads that can be used - int nthreads_max; - LG_TRY (LAGraph_GetNumThreads (&nthreads_max, NULL)) ; + int nthreads_max, nthreads_hi, nthreads_lo ; + LG_TRY (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + nthreads_max = nthreads_hi * nthreads_lo ; printf ("max # of nthreads: %d\n", nthreads_max) ; #define NNTHREADS 12 @@ -474,7 +475,7 @@ int main (int argc, char **argv) int nthreads = nthreads_list [kth] ; if (nthreads > nthreads_max) break ; - LAGraph_SetNumThreads (nthreads, NULL) ; + LAGraph_SetNumThreads (1, nthreads, NULL) ; printf ("nthreads %3d: ", nthreads) ; fflush (stdout) ; @@ -553,7 +554,7 @@ int main (int argc, char **argv) printf ("\n# entries in final Y: %g million\n", (double) final_ynvals / 1e6) ; printf ("check time: %g sec\n", tcheck) ; - LAGraph_SetNumThreads (nthreads_max, NULL) ; + LAGraph_SetNumThreads (nthreads_hi, nthreads_lo, NULL) ; } //---------------------------------------------------------------------- diff --git a/experimental/benchmark/mis_demo.c b/experimental/benchmark/mis_demo.c index 400fb82a80..17287bcf82 100644 --- a/experimental/benchmark/mis_demo.c +++ b/experimental/benchmark/mis_demo.c @@ -61,8 +61,11 @@ int main (int argc, char **argv) int nt = NTHREAD_LIST ; int Nthreads [20] = { 0, THREAD_LIST } ; - int nthreads_max ; - LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_max, NULL)) ; + + int nthreads_max, nthreads_hi, nthreads_lo ; + LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + nthreads_max = nthreads_hi * nthreads_lo ; + if (Nthreads [1] == 0) { // create thread list automatically @@ -94,7 +97,7 @@ int main (int argc, char **argv) GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; GRB_TRY (GrB_Matrix_nvals (&nvals, G->A)) ; // LAGRAPH_TRY (LAGraph_DisplayGraph (G, LAGraph_SHORT, stdout, msg)) ; - LAGRAPH_TRY (LAGraph_Property_RowDegree (G, msg)) ; + LAGRAPH_TRY (LAGraph_Cached_OutDegree (G, msg)) ; //-------------------------------------------------------------------------- // maximal independent set @@ -113,7 +116,7 @@ int main (int argc, char **argv) { int nthreads = Nthreads [t] ; if (nthreads > nthreads_max) continue ; - LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads, msg)) ; + LAGRAPH_TRY (LAGraph_SetNumThreads (1, nthreads, msg)) ; double ttot = 0, ttrial [100] ; for (int trial = 0 ; trial < ntrials ; trial++) { diff --git a/experimental/benchmark/tcc_demo.c b/experimental/benchmark/tcc_demo.c index 4178ee4be3..bf899cefe4 100644 --- a/experimental/benchmark/tcc_demo.c +++ b/experimental/benchmark/tcc_demo.c @@ -59,8 +59,11 @@ int main (int argc, char **argv) int nt = NTHREAD_LIST ; int Nthreads [20] = { 0, THREAD_LIST } ; - int nthreads_max ; - LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_max, NULL)) ; + + int nthreads_max, nthreads_hi, nthreads_lo ; + LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + nthreads_max = nthreads_hi * nthreads_lo ; + if (Nthreads [1] == 0) { // create thread list automatically @@ -118,7 +121,7 @@ int main (int argc, char **argv) { int nthreads = Nthreads [t] ; if (nthreads > nthreads_max) continue ; - LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads, msg)) ; + LAGRAPH_TRY (LAGraph_SetNumThreads (1, nthreads, msg)) ; double ttot = 0, ttrial [100] ; for (int trial = 0 ; trial < ntrials ; trial++) { diff --git a/experimental/test/LG_check_kcore.c b/experimental/test/LG_check_kcore.c new file mode 100644 index 0000000000..faf86d7e9a --- /dev/null +++ b/experimental/test/LG_check_kcore.c @@ -0,0 +1,176 @@ +//------------------------------------------------------------------------------ +// LG_check_kcore: construct the kcore of a graph (simple method) +//------------------------------------------------------------------------------ + +// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause +// +// See additional acknowledgments in the LICENSE file, +// or contact permission@sei.cmu.edu for the full terms. + +// Contributed by Pranav Konduri, Texas A&M University + +//------------------------------------------------------------------------------ + +// An implementation of the BZ algorithm (2003) for k-core decomposition. +// This method is for testing only, to check the result of other, faster methods. +// Do not benchmark this method; it is simple by design. + +#define LG_FREE_ALL \ +{ \ + LAGraph_Free ((void **) &Ap, msg) ; \ + LAGraph_Free ((void **) &Aj, msg) ; \ + LAGraph_Free ((void **) &Ax, msg) ; \ +} + +#include "LG_internal.h" +#include "LG_test.h" +#include "LG_test.h" +#include "LG_Xtest.h" + +int LG_check_kcore +( + // outputs: + GrB_Vector *decomp, // kcore decomposition + uint64_t *kmax, // max kcore- if kfinal == -1, kmax = -1 + // inputs + LAGraph_Graph G, // input graph + int64_t kfinal, // max k to check for graph. + char *msg +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + LG_CLEAR_MSG ; + + GrB_Index *Ap = NULL, *Aj = NULL, *Ai = NULL ; + void *Ax = NULL ; + GrB_Index Ap_size, Aj_size, Ax_size, n, ncols, Ap_len, Aj_len, Ax_len ; + LG_ASSERT (kmax != NULL, GrB_NULL_POINTER) ; + LG_TRY (LAGraph_CheckGraph (G, msg)) ; + LG_ASSERT (G->nself_edges == 0, LAGRAPH_NO_SELF_EDGES_ALLOWED) ; + LG_ASSERT_MSG ((G->kind == LAGraph_ADJACENCY_UNDIRECTED || + (G->kind == LAGraph_ADJACENCY_DIRECTED && + G->is_symmetric_structure == LAGraph_TRUE)), + LAGRAPH_SYMMETRIC_STRUCTURE_REQUIRED, + "G->A must be known to be symmetric") ; + GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; //set n to number of rows + GRB_TRY (GrB_Matrix_ncols (&ncols, G->A)) ; + + //-------------------------------------------------------------------------- + // export the matrix in CSR form + //-------------------------------------------------------------------------- + + size_t typesize ; + LG_TRY (LG_check_export (G, &Ap, &Aj, &Ax, &Ap_len, &Aj_len, &Ax_len, + &typesize, msg)) ; + + //-------------------------------------------------------------------------- + // compute the k-core + //-------------------------------------------------------------------------- + //printf ("\n================================== COMPUTING BZ_KCORE: ==================================\n") ; + //printf("ap_len = %ld, aj_len = %ld, ax_len = %ld\n", Ap_len, Aj_len, Ax_len) ; + + //create the arrays + uint64_t *vert = NULL, *pos = NULL, *bin = NULL, *deg = NULL /*, *core = NULL */; + uint64_t maxDeg = 0; + LAGraph_Malloc((void **) °, n, sizeof(uint64_t), msg) ; + LAGraph_Malloc((void **) &vert, n, sizeof(uint64_t), msg) ; + LAGraph_Malloc((void **) &pos, n, sizeof(uint64_t), msg) ; + //core = AGraph_Malloc(n, sizeof(uint64_t)) ; + + for(uint64_t i = 0; i < n; i++){ + deg[i] = Ap[i+1] - Ap[i]; + if (deg[i] > maxDeg) + maxDeg = deg[i]; + } + + //setup output vector + GrB_Type int_type = (maxDeg > INT32_MAX) ? GrB_INT64 : GrB_INT32 ; + GRB_TRY (GrB_Vector_new(decomp, int_type, n)) ; + GrB_IndexUnaryOp valueGE = (maxDeg > INT32_MAX) ? GrB_VALUEGE_INT64 : GrB_VALUEGE_INT32 ; + + //setup bin array + LAGraph_Calloc((void **) &bin, maxDeg + 1, sizeof(uint64_t), msg) ; + + for(uint64_t i = 0; i < n; i++){ + bin[deg[i]]++; + } + + uint64_t start = 0; + for(uint64_t d = 0; d < maxDeg + 1; d++){ + uint64_t num = bin[d]; + bin[d] = start; + start = start + num; + } + + //Do bin-sort + //vert -- contains the vertices in sorted order of degree + //pos -- contains the positon of a vertex in vert array + for(uint64_t i = 0; i < n; i++){ + pos[i] = bin[ deg[i] ]; + vert[pos[i]] = i; + bin[deg[i]] ++; + } + + for(uint64_t d = maxDeg; d >= 1; d --) + bin[d] = bin[d-1]; + bin[0] = 0; + + uint64_t level = 0; + + //Compute k-core + for(uint64_t i = 0; i < n; i++){ + //get the vertex to check + uint64_t v = vert[i]; + + //set the element in the output vector: if doing KCALL, then add deg. + //If not, just set to kfinal's value. + if((int64_t) deg[v] >= kfinal){ + if(kfinal == -1){ + GRB_TRY(GrB_Vector_setElement(*decomp, deg[v], v)) ; + } + else{ + GRB_TRY(GrB_Vector_setElement(*decomp, kfinal, v)) ; + } + } + + if(bin[deg[v]] == i){ + level = deg[v]; + } + + uint64_t start = Ap[v]; + int64_t original_deg = Ap[v+1] - Ap[v]; //original deg before decremented + for(uint64_t j = 0; j < original_deg; j++){ + uint64_t u = Aj[start + j]; //a neighbor node of v + + //if we need to lower the neighbor's deg value, and relocate in bin + if(deg[u] > deg[v]){ + uint64_t du = deg[u]; + uint64_t pu = pos[u]; + uint64_t pw = bin[du]; + uint64_t w = vert[pw]; //the vertex situated at the beginning of the bin + + //swap around the vertices- w goes to the end, u goes to the beginning + if(u != w){ + pos[u] = pw; vert[pu] = w; + pos[w] = pu; vert[pw] = u; + } + + //increase starting index of bin @ du + bin[du]++; + //decrease degree of u + deg[u]--; + } + } + } + + LG_FREE_ALL; + (*kmax) = level ; + GRB_TRY (GrB_Vector_wait(*decomp, GrB_MATERIALIZE)); + return (GrB_SUCCESS); +} + diff --git a/experimental/test/LG_check_kcoredecompose.c b/experimental/test/LG_check_kcoredecompose.c new file mode 100644 index 0000000000..69d88b383b --- /dev/null +++ b/experimental/test/LG_check_kcoredecompose.c @@ -0,0 +1,114 @@ +//------------------------------------------------------------------------------ +// LG_check_kcoredecompose: deconstruct the graph into a k-core, given a +// decompostion vector (simple method) +//------------------------------------------------------------------------------ + +// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause +// +// See additional acknowledgments in the LICENSE file, +// or contact permission@sei.cmu.edu for the full terms. + +// Contributed by Pranav Konduri, Texas A&M University + +//------------------------------------------------------------------------------ + +// 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. + +#define LG_FREE_WORK \ +{ \ + GrB_free (&C) ; \ + GrB_free (°) ; \ +} + +#define LG_FREE_ALL \ +{ \ + LG_FREE_WORK \ + GrB_free (D) ; \ +} + + +#include "LG_internal.h" +#include "LG_test.h" +#include "LG_Xtest.h" + +int LG_check_kcore_decompose +( + // outputs: + GrB_Matrix *D, // kcore decomposition + // inputs: + LAGraph_Graph G, // input graph + GrB_Vector decomp, + uint64_t k, + char *msg +) +{ + LG_CLEAR_MSG ; + + // declare items + GrB_Matrix A = NULL, C = NULL; + GrB_Vector deg = NULL; + + LG_ASSERT (D != NULL, GrB_NULL_POINTER) ; + (*D) = NULL ; + + LG_TRY (LAGraph_CheckGraph (G, msg)) ; + + 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 + A = G->A ; + } + else + { + // A is not known to be symmetric + LG_ASSERT_MSG (false, -1005, "G->A must be symmetric") ; + } + + // no self edges can be present + LG_ASSERT_MSG (G->nself_edges == 0, -1004, "G->nself_edges must be zero") ; + + //create work scalars + GrB_Index size_matrix, nvals_matrix, size_vector, nvals_vector; + GRB_TRY (GrB_Matrix_nrows(&size_matrix, A)) ; + GRB_TRY (GrB_Vector_size(&size_vector, decomp)) ; + + LG_ASSERT_MSG (size_matrix == size_vector, -1003, "Size of vector and of matrix must be same") ; + + //create D and nvals scalars + GRB_TRY (GrB_Matrix_new(D, GrB_INT64, size_matrix, size_matrix)) ; + GRB_TRY (GrB_Matrix_nvals(&nvals_matrix, A)) ; + GRB_TRY (GrB_Vector_nvals(&nvals_vector, decomp)); + + //extract out the values of the input graph + GrB_Index *row = NULL, *col = NULL , *matrix_values = NULL, *vector = NULL, *vector_values = NULL; + LG_TRY (LAGraph_Malloc ((void **) &row, nvals_matrix, sizeof (GrB_Index), msg)); + LG_TRY (LAGraph_Malloc ((void **) &col, nvals_matrix, sizeof (GrB_Index), msg)); + LG_TRY (LAGraph_Malloc ((void **) &matrix_values, nvals_matrix, sizeof (GrB_Index), msg)); + + LG_TRY (LAGraph_Malloc ((void **) &vector, nvals_vector, sizeof (GrB_Index), msg)); + LG_TRY (LAGraph_Malloc ((void **) &vector_values, nvals_vector, sizeof (GrB_Index), msg)); + + GRB_TRY(GrB_Matrix_extractTuples(row, col, (int64_t *) matrix_values, &nvals_matrix, A)); + GRB_TRY(GrB_Vector_extractTuples(vector, (int64_t *) vector_values, &size_vector, decomp)); + //take all values that have row and col indices + for(uint64_t i = 0; i < nvals_matrix; i++){ + bool ok_row = false, ok_col = false; + for(uint64_t j = 0; (j < nvals_vector) && (!ok_row || !ok_col); j++){ + if(row[i] == vector[j] && vector_values[j] >= k) + ok_row = true; + if(col[i] == vector[j] && vector_values[j] >= k) + ok_col = true; + } + if(ok_row && ok_col){ + GRB_TRY(GrB_Matrix_setElement(*D, matrix_values[i], row[i], col[i])); + } + } + LG_FREE_WORK; + GRB_TRY (GrB_Matrix_wait(*D, GrB_MATERIALIZE)); + return (GrB_SUCCESS); +} + diff --git a/experimental/test/LG_check_ktruss.c b/experimental/test/LG_check_ktruss.c index ee4a67a6dc..c4c3fbe8f0 100644 --- a/experimental/test/LG_check_ktruss.c +++ b/experimental/test/LG_check_ktruss.c @@ -57,10 +57,10 @@ int LG_check_ktruss 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->ndiag == 0, -104, "G->ndiag must be zero") ; + 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->structure_is_symmetric == LAGraph_TRUE)) + G->is_symmetric_structure == LAGraph_TRUE)) { // the structure of A is known to be symmetric ; diff --git a/experimental/test/LG_check_mis.c b/experimental/test/LG_check_mis.c index 0ab650c30d..f85e81064a 100644 --- a/experimental/test/LG_check_mis.c +++ b/experimental/test/LG_check_mis.c @@ -103,8 +103,7 @@ int LG_check_mis // check if iset is a valid MIS of A } // e = (e || A*iset), using the structural semiring - GRB_TRY (GrB_vxm (e, NULL, GrB_LOR, LAGraph_structural_bool, iset, A, - NULL)) ; + GRB_TRY (GrB_vxm (e, NULL, GrB_LOR, LAGraph_any_one_bool, iset, A, NULL)) ; // drop explicit zeros from e // e = e diff --git a/experimental/test/include/LG_Xtest.h b/experimental/test/include/LG_Xtest.h index 37fab6e6df..669c79817f 100644 --- a/experimental/test/include/LG_Xtest.h +++ b/experimental/test/include/LG_Xtest.h @@ -36,4 +36,26 @@ int LG_check_ktruss char *msg ) ; +int LG_check_kcore +( + // outputs: + GrB_Vector *decomp, // kcore decomposition + uint64_t *kmax, // max kcore- if kfinal == -1, kmax = -1 + // inputs + LAGraph_Graph G, // input graph + int64_t kfinal, // max k to check for graph. + char *msg +) ; + +int LG_check_kcore_decompose +( + // outputs: + GrB_Matrix *D, // kcore decomposition + // inputs: + LAGraph_Graph G, // input graph + GrB_Vector decomp, + uint64_t k, + char *msg +) ; + #endif diff --git a/experimental/test/test_AllKCore.c b/experimental/test/test_AllKCore.c new file mode 100644 index 0000000000..103ea3e541 --- /dev/null +++ b/experimental/test/test_AllKCore.c @@ -0,0 +1,173 @@ +//---------------------------------------------------------------------------- +// LAGraph/expirimental/test/test_AllKCore.c: test cases for full k-core +// decomposition +// ---------------------------------------------------------------------------- + +// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause +// +// See additional acknowledgments in the LICENSE file, +// or contact permission@sei.cmu.edu for the full terms. + +// Contributed by Pranav Konduri, Texas A&M University + +//----------------------------------------------------------------------------- + +#include +#include + +#include +#include +#include "LG_Xtest.h" + +char msg [LAGRAPH_MSG_LEN] ; +LAGraph_Graph G = NULL ; +GrB_Matrix A = NULL ; +GrB_Vector c1 = NULL, c2 = NULL; +#define LEN 512 +char filename [LEN+1] ; + +typedef struct +{ + uint64_t kmax ; + const char *name ; +} +matrix_info ; + +const matrix_info files [ ] = +{ + { 4, "karate.mtx" }, + // { 10, "amazon0601.mtx" }, + // { 64, "cit-Patents.mtx"}, + // { 2208, "hollywood-2009.mtx"}, + // { 111, "as-Skitter.mtx"}, + { 0, "" }, +} ; + + +void test_AllKCore (void) +{ + LAGraph_Init (msg) ; + + for (int k = 0 ; ; k++) + { + // load the matrix as A + const char *aname = files [k].name ; + uint64_t kmax = files [k].kmax ; + if (strlen (aname) == 0) break; + printf ("\n================================== %s: ==================================\n", aname) ; + TEST_CASE (aname) ; + snprintf (filename, LEN, LG_DATA_DIR "%s", aname) ; + FILE *f = fopen (filename, "r") ; + TEST_CHECK (f != NULL) ; + OK (LAGraph_MMRead (&A, f, msg)) ; + TEST_MSG ("Loading of adjacency matrix failed") ; + + // construct an undirected graph G with adjacency matrix A + OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_DIRECTED, msg)) ; + TEST_CHECK (A == NULL) ; + + // check if the pattern is symmetric - if it isn't make it. + OK (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; + + if (G->is_symmetric_structure == LAGraph_FALSE) + { + printf("This matrix is not symmetric. \n"); + // make the adjacency matrix symmetric + OK (LAGraph_Cached_AT (G, msg)) ; + OK (GrB_eWiseAdd (G->A, NULL, NULL, GrB_LOR, G->A, G->AT, NULL)) ; + G->is_symmetric_structure = true ; + } + G->kind = LAGraph_ADJACENCY_UNDIRECTED ; + + // check for self-edges, and remove them. + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; + if (G->nself_edges != 0) + { + // remove self-edges + printf ("graph has %g self edges\n", (double) G->nself_edges) ; + OK (LAGraph_DeleteSelfEdges (G, msg)) ; + printf ("now has %g self edges\n", (double) G->nself_edges) ; + TEST_CHECK (G->nself_edges == 0) ; + } + + int64_t check_kmax = -1; //flag to check kmax in LG_check_kcore + uint64_t km1; + uint64_t km2; + bool ok; + //test the k-core + OK(LAGraph_KCore_All(&c1, &km1, G, msg)) ; + TEST_CHECK(kmax == km1) ; + + OK(LG_check_kcore(&c2, &km2, G, check_kmax, msg)) ; + + TEST_CHECK(kmax == km2) ; + TEST_CHECK(km1 == km2) ; + OK (LAGraph_Vector_IsEqual (&ok, c1, c2, msg)) ; + TEST_CHECK (ok) ; + + OK (LAGraph_Delete (&G, msg)) ; + } + + LAGraph_Finalize (msg) ; +} + +//------------------------------------------------------------------------------ +// test_errors +//------------------------------------------------------------------------------ + +void test_errors (void) +{ + LAGraph_Init (msg) ; + + snprintf (filename, LEN, LG_DATA_DIR "%s", "karate.mtx") ; + FILE *f = fopen (filename, "r") ; + TEST_CHECK (f != NULL) ; + OK (LAGraph_MMRead (&A, f, msg)) ; + TEST_MSG ("Loading of adjacency matrix failed") ; + + // construct an undirected graph G with adjacency matrix A + OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_UNDIRECTED, msg)) ; + TEST_CHECK (A == NULL) ; + + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; + + uint64_t kmax ; + GrB_Vector c = NULL ; + + // c is NULL + int result = LAGraph_KCore_All (NULL, &kmax, G, msg) ; + printf ("\nresult: %d %s\n", result, msg) ; + TEST_CHECK (result == GrB_NULL_POINTER) ; + + // G is invalid + result = LAGraph_KCore_All (&c, &kmax, NULL, msg) ; + printf ("\nresult: %d %s\n", result, msg) ; + TEST_CHECK (result == GrB_NULL_POINTER) ; + TEST_CHECK (c == NULL) ; + + // G may have self edges + G->nself_edges = LAGRAPH_UNKNOWN ; + result = LAGraph_KCore_All (&c, &kmax, G, msg) ; + printf ("\nresult: %d %s\n", result, msg) ; + TEST_CHECK (result == -1004) ; + TEST_CHECK (c == NULL) ; + + // G is undirected + G->nself_edges = 0 ; + G->kind = LAGraph_ADJACENCY_DIRECTED ; + G->is_symmetric_structure = LAGraph_FALSE ; + result = LAGraph_KCore_All (&c, &kmax, G, msg) ; + printf ("\nresult: %d %s\n", result, msg) ; + TEST_CHECK (result == -1005) ; + TEST_CHECK (c == NULL) ; + + OK (LAGraph_Delete (&G, msg)) ; + LAGraph_Finalize (msg) ; +} + +TEST_LIST = { + {"AllKCore", test_AllKCore}, + {"AllKCore_errors", test_errors}, + {NULL, NULL} +}; diff --git a/experimental/test/test_AllKtruss.c b/experimental/test/test_AllKtruss.c index cd326ab41c..85b1540e68 100644 --- a/experimental/test/test_AllKtruss.c +++ b/experimental/test/test_AllKtruss.c @@ -72,14 +72,14 @@ void test_AllKTruss (void) TEST_CHECK (A == NULL) ; // check for self-edges - OK (LAGraph_Property_NDiag (G, msg)) ; - if (G->ndiag != 0) + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; + if (G->nself_edges != 0) { // remove self-edges - printf ("graph has %g self edges\n", (double) G->ndiag) ; - OK (LAGraph_DeleteDiag (G, msg)) ; - printf ("now has %g self edges\n", (double) G->ndiag) ; - TEST_CHECK (G->ndiag == 0) ; + printf ("graph has %g self edges\n", (double) G->nself_edges) ; + OK (LAGraph_DeleteSelfEdges (G, msg)) ; + printf ("now has %g self edges\n", (double) G->nself_edges) ; + TEST_CHECK (G->nself_edges == 0) ; } // compute each k-truss @@ -134,7 +134,7 @@ void test_AllKTruss (void) // convert to directed with symmetric structure and recompute G->kind = LAGraph_ADJACENCY_DIRECTED ; - G->structure_is_symmetric = true ; + G->is_symmetric_structure = LAGraph_TRUE ; int64_t k2 ; GrB_Matrix *Cset2 ; int64_t *ntris2, *nedges2, *nsteps2 ; @@ -204,7 +204,7 @@ void test_allktruss_errors (void) OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_UNDIRECTED, msg)) ; TEST_CHECK (A == NULL) ; - OK (LAGraph_Property_NDiag (G, msg)) ; + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; GrB_Index n ; int64_t kmax ; @@ -227,15 +227,15 @@ void test_allktruss_errors (void) TEST_CHECK (result == GrB_NULL_POINTER) ; // G may have self edges - G->ndiag = LAGRAPH_UNKNOWN ; + G->nself_edges = LAGRAPH_UNKNOWN ; result = LAGraph_AllKTruss (Cset, &kmax, ntris, nedges, nsteps, G, msg) ; printf ("\nresult: %d %s\n", result, msg) ; TEST_CHECK (result == -1004) ; // G is undirected - G->ndiag = 0 ; + G->nself_edges = 0 ; G->kind = LAGraph_ADJACENCY_DIRECTED ; - G->structure_is_symmetric = LAGraph_FALSE ; + G->is_symmetric_structure = LAGraph_FALSE ; result = LAGraph_AllKTruss (Cset, &kmax, ntris, nedges, nsteps, G, msg) ; printf ("\nresult: %d %s\n", result, msg) ; TEST_CHECK (result == -1005) ; diff --git a/experimental/test/test_KCore.c b/experimental/test/test_KCore.c new file mode 100644 index 0000000000..2f4180bbe6 --- /dev/null +++ b/experimental/test/test_KCore.c @@ -0,0 +1,165 @@ +//---------------------------------------------------------------------------- +// LAGraph/expirimental/test/test_KCore.c: test cases for single k-core +// ---------------------------------------------------------------------------- + +// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause +// +// See additional acknowledgments in the LICENSE file, +// or contact permission@sei.cmu.edu for the full terms. + +// Contributed by Pranav Konduri, Texas A&M University + +//----------------------------------------------------------------------------- + +#include +#include + +#include +#include +#include "LG_Xtest.h" + +char msg [LAGRAPH_MSG_LEN] ; +LAGraph_Graph G = NULL ; +GrB_Matrix A = NULL ; +GrB_Vector c1 = NULL, c2 = NULL; +#define LEN 512 +char filename [LEN+1] ; + +typedef struct +{ + const char *name ; +} +matrix_info ; + +const matrix_info files [ ] = +{ + {"karate.mtx" }, + // {"amazon0601.mtx" }, + // {"cit-Patents.mtx"}, + // {"hollywood-2009.mtx"}, + // {"as-Skitter.mtx"}, + {""}, +} ; + + +void test_KCore (void) +{ + LAGraph_Init (msg) ; + + for (int k = 0 ; ; k++) + { + // load the matrix as A + const char *aname = files [k].name ; + if (strlen (aname) == 0) break; + printf ("\n================================== %s: ==================================\n", aname) ; + TEST_CASE (aname) ; + snprintf (filename, LEN, LG_DATA_DIR "%s", aname) ; + FILE *f = fopen (filename, "r") ; + TEST_CHECK (f != NULL) ; + OK (LAGraph_MMRead (&A, f, msg)) ; + TEST_MSG ("Loading of adjacency matrix failed") ; + + // construct an undirected graph G with adjacency matrix A + OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_DIRECTED, msg)) ; + TEST_CHECK (A == NULL) ; + + // check if the pattern is symmetric - if it isn't make it. + OK (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; + + if (G->is_symmetric_structure == LAGraph_FALSE) + { + printf("This matrix is not symmetric. \n"); + // make the adjacency matrix symmetric + OK (LAGraph_Cached_AT (G, msg)) ; + OK (GrB_eWiseAdd (G->A, NULL, NULL, GrB_LOR, G->A, G->AT, NULL)) ; + G->is_symmetric_structure = true ; + } + G->kind = LAGraph_ADJACENCY_UNDIRECTED ; + + // check for self-edges, and remove them. + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; + if (G->nself_edges != 0) + { + // remove self-edges + printf ("graph has %g self edges\n", (double) G->nself_edges) ; + OK (LAGraph_DeleteSelfEdges (G, msg)) ; + printf ("now has %g self edges\n", (double) G->nself_edges) ; + TEST_CHECK (G->nself_edges == 0) ; + } + + + uint64_t kmax; + bool ok; + //test the k-core + OK(LAGraph_KCore(&c1, G, 2, msg)) ; + OK(LG_check_kcore(&c2, &kmax, G, 2, msg)) ; + + OK (LAGraph_Vector_IsEqual (&ok, c1, c2, msg)) ; + TEST_CHECK (ok) ; + + OK (LAGraph_Delete (&G, msg)) ; + } + + LAGraph_Finalize (msg) ; +} + +//------------------------------------------------------------------------------ +// test_errors +//------------------------------------------------------------------------------ + +void test_errors (void) +{ + LAGraph_Init (msg) ; + + snprintf (filename, LEN, LG_DATA_DIR "%s", "karate.mtx") ; + FILE *f = fopen (filename, "r") ; + TEST_CHECK (f != NULL) ; + OK (LAGraph_MMRead (&A, f, msg)) ; + TEST_MSG ("Loading of adjacency matrix failed") ; + + // construct an undirected graph G with adjacency matrix A + OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_UNDIRECTED, msg)) ; + TEST_CHECK (A == NULL) ; + + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; + + uint64_t k = 1; //some test k + GrB_Vector c = NULL ; + + // c is NULL + int result = LAGraph_KCore (NULL, G, k, msg) ; + printf ("\nresult: %d %s\n", result, msg) ; + TEST_CHECK (result == GrB_NULL_POINTER) ; + + // G is invalid + result = LAGraph_KCore (&c, NULL, k, msg) ; + printf ("\nresult: %d %s\n", result, msg) ; + TEST_CHECK (result == GrB_NULL_POINTER) ; + TEST_CHECK (c == NULL) ; + + // G may have self edges + G->nself_edges = LAGRAPH_UNKNOWN ; + result = LAGraph_KCore (&c, G, k, msg) ; + printf ("\nresult: %d %s\n", result, msg) ; + TEST_CHECK (result == -1004) ; + TEST_CHECK (c == NULL) ; + + // G is undirected + G->nself_edges = 0 ; + G->kind = LAGraph_ADJACENCY_DIRECTED ; + G->is_symmetric_structure = LAGraph_FALSE ; + result = LAGraph_KCore (&c, G, k, msg) ; + printf ("\nresult: %d %s\n", result, msg) ; + TEST_CHECK (result == -1005) ; + TEST_CHECK (c == NULL) ; + + OK (LAGraph_Delete (&G, msg)) ; + LAGraph_Finalize (msg) ; +} + +TEST_LIST = { + {"KCore", test_KCore}, + {"KCore_errors", test_errors}, + {NULL, NULL} +}; diff --git a/experimental/test/test_KCoreDecompose.c b/experimental/test/test_KCoreDecompose.c new file mode 100644 index 0000000000..b4f96ec9d7 --- /dev/null +++ b/experimental/test/test_KCoreDecompose.c @@ -0,0 +1,168 @@ +//---------------------------------------------------------------------------- +// LAGraph/expirimental/test/test_KCoreDecompose.c: test cases for k-core +// decomposition +// ---------------------------------------------------------------------------- + +// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause + +// Contributed by Pranav Konduri, Texas A&M University + +//----------------------------------------------------------------------------- + +#include +#include + +#include +#include +#include "LG_Xtest.h" + +char msg [LAGRAPH_MSG_LEN] ; +LAGraph_Graph G = NULL ; +GrB_Matrix A = NULL, D1 = NULL, D2 = NULL; +GrB_Vector c = NULL; +#define LEN 512 +char filename [LEN+1] ; + +typedef struct +{ + uint64_t kval ; + const char *name ; +} +matrix_info ; + +const matrix_info files [ ] = +{ + { 4, "karate.mtx" }, + // { 10, "amazon0601.mtx" }, + // { 64, "cit-Patents.mtx"}, + // { 2208, "hollywood-2009.mtx"}, + // { 111, "as-Skitter.mtx"}, + { 0, "" }, +} ; + + +void test_KCoreDecompose (void) +{ + LAGraph_Init (msg) ; + + for (int k = 0 ; ; k++) + { + // load the matrix as A + const char *aname = files [k].name ; + uint64_t kval = files [k].kval ; + if (strlen (aname) == 0) break; + TEST_CASE (aname) ; + snprintf (filename, LEN, LG_DATA_DIR "%s", aname) ; + FILE *f = fopen (filename, "r") ; + TEST_CHECK (f != NULL) ; + OK (LAGraph_MMRead (&A, f, msg)) ; + TEST_MSG ("Loading of adjacency matrix failed") ; + + // construct an undirected graph G with adjacency matrix A + OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_DIRECTED, msg)) ; + TEST_CHECK (A == NULL) ; + + // check if the pattern is symmetric - if it isn't make it. + OK (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; + + if (G->is_symmetric_structure == LAGraph_FALSE) + { + printf("This matrix is not symmetric. \n"); + // make the adjacency matrix symmetric + OK (LAGraph_Cached_AT (G, msg)) ; + OK (GrB_eWiseAdd (G->A, NULL, NULL, GrB_LOR, G->A, G->AT, NULL)) ; + G->is_symmetric_structure = true ; + } + G->kind = LAGraph_ADJACENCY_UNDIRECTED ; + + // check for self-edges, and remove them. + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; + if (G->nself_edges != 0) + { + // remove self-edges + printf ("graph has %g self edges\n", (double) G->nself_edges) ; + OK (LAGraph_DeleteSelfEdges (G, msg)) ; + printf ("now has %g self edges\n", (double) G->nself_edges) ; + TEST_CHECK (G->nself_edges == 0) ; + } + + bool ok; + //get the kcore at the designated k-value + LAGraph_KCore(&c, G, kval, msg) ; + + //decompose the k-core from vector c into D1 + LAGraph_KCore_Decompose(&D1, G, c, kval, msg); + + //decompose the k-core from vector c into D2 + LG_check_kcore_decompose(&D2, G, c, kval, msg); + + //check equality + OK (LAGraph_Matrix_IsEqual (&ok, D1, D2, msg)) ; + TEST_CHECK(ok); + + OK (LAGraph_Delete (&G, msg)) ; + } + + LAGraph_Finalize (msg) ; +} + +//------------------------------------------------------------------------------ +// test_errors +//------------------------------------------------------------------------------ + +void test_errors (void) +{ + LAGraph_Init (msg) ; + + snprintf (filename, LEN, LG_DATA_DIR "%s", "karate.mtx") ; + FILE *f = fopen (filename, "r") ; + TEST_CHECK (f != NULL) ; + OK (LAGraph_MMRead (&A, f, msg)) ; + TEST_MSG ("Loading of adjacency matrix failed") ; + + // construct an undirected graph G with adjacency matrix A + OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_UNDIRECTED, msg)) ; + TEST_CHECK (A == NULL) ; + + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; + + uint64_t kval = 2 ; + GrB_Vector c = NULL ; + + // c is NULL + int result = LAGraph_KCore_Decompose (&D1, G, NULL, kval, msg) ; + printf ("\nresult: %d %s\n", result, msg) ; + TEST_CHECK (result == GrB_NULL_POINTER) ; + + // G is invalid + result = LAGraph_KCore_Decompose (&D1, NULL, c, kval, msg) ; + printf ("\nresult: %d %s\n", result, msg) ; + TEST_CHECK (result == GrB_NULL_POINTER) ; + TEST_CHECK (c == NULL) ; + + // G may have self edges + G->nself_edges = LAGRAPH_UNKNOWN ; + result = LAGraph_KCore_Decompose(&D1, G, c, kval, msg); + printf ("\nresult: %d %s\n", result, msg) ; + TEST_CHECK (result == -1004) ; + TEST_CHECK (c == NULL) ; + + // G is undirected + G->nself_edges = 0 ; + G->kind = LAGraph_ADJACENCY_DIRECTED ; + G->is_symmetric_structure = LAGraph_FALSE ; + result = LAGraph_KCore_Decompose(&D1, G, c, kval, msg); + printf ("\nresult: %d %s\n", result, msg) ; + TEST_CHECK (result == -1005) ; + TEST_CHECK (c == NULL) ; + + OK (LAGraph_Delete (&G, msg)) ; + LAGraph_Finalize (msg) ; +} + +TEST_LIST = { + {"KCoreDecompose", test_KCoreDecompose}, + {"KCoreDecompose_errors", test_errors}, + {NULL, NULL} +}; diff --git a/experimental/test/test_KTruss.c b/experimental/test/test_KTruss.c index 2c6beef258..865b9af1a3 100644 --- a/experimental/test/test_KTruss.c +++ b/experimental/test/test_KTruss.c @@ -71,14 +71,14 @@ void test_ktruss (void) TEST_CHECK (A == NULL) ; // check for self-edges - OK (LAGraph_Property_NDiag (G, msg)) ; - if (G->ndiag != 0) + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; + if (G->nself_edges != 0) { // remove self-edges - printf ("graph has %g self edges\n", (double) G->ndiag) ; - OK (LAGraph_DeleteDiag (G, msg)) ; - printf ("now has %g self edges\n", (double) G->ndiag) ; - TEST_CHECK (G->ndiag == 0) ; + printf ("graph has %g self edges\n", (double) G->nself_edges) ; + OK (LAGraph_DeleteSelfEdges (G, msg)) ; + printf ("now has %g self edges\n", (double) G->nself_edges) ; + TEST_CHECK (G->nself_edges == 0) ; } // compute each k-truss until the result is empty @@ -115,7 +115,7 @@ void test_ktruss (void) // convert to directed with symmetric structure and recompute G->kind = LAGraph_ADJACENCY_DIRECTED ; - G->structure_is_symmetric = true ; + G->is_symmetric_structure = LAGraph_TRUE ; OK (LAGraph_KTruss (&C1, G, 3, msg)) ; OK (LG_check_ktruss (&C2, G, 3, msg)) ; OK (LAGraph_Matrix_IsEqual (&ok, C1, C2, msg)) ; @@ -145,7 +145,7 @@ void test_ktruss_errors (void) OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_UNDIRECTED, msg)) ; TEST_CHECK (A == NULL) ; - OK (LAGraph_Property_NDiag (G, msg)) ; + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; // C is NULL int result = LAGraph_KTruss (NULL, G, 3, msg) ; @@ -165,16 +165,16 @@ void test_ktruss_errors (void) TEST_CHECK (C1 == NULL) ; // G may have self edges - G->ndiag = LAGRAPH_UNKNOWN ; + G->nself_edges = LAGRAPH_UNKNOWN ; result = LAGraph_KTruss (&C1, G, 3, msg) ; printf ("\nresult: %d %s\n", result, msg) ; TEST_CHECK (result == -1004) ; TEST_CHECK (C1 == NULL) ; // G is undirected - G->ndiag = 0 ; + G->nself_edges = 0 ; G->kind = LAGraph_ADJACENCY_DIRECTED ; - G->structure_is_symmetric = LAGraph_FALSE ; + G->is_symmetric_structure = LAGraph_FALSE ; result = LAGraph_KTruss (&C1, G, 3, msg) ; printf ("\nresult: %d %s\n", result, msg) ; TEST_CHECK (result == -1005) ; diff --git a/experimental/test/test_MaximalIndependentSet.c b/experimental/test/test_MaximalIndependentSet.c index 3195e9b4c9..624f5e8442 100644 --- a/experimental/test/test_MaximalIndependentSet.c +++ b/experimental/test/test_MaximalIndependentSet.c @@ -107,30 +107,30 @@ void test_MIS (void) TEST_CHECK (mis == NULL) ; // check if the pattern is symmetric - OK (LAGraph_Property_SymmetricStructure (G, msg)) ; + OK (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; - if (G->structure_is_symmetric == LAGraph_FALSE) + if (G->is_symmetric_structure == LAGraph_FALSE) { // make the adjacency matrix symmetric - OK (LAGraph_Property_AT (G, msg)) ; + OK (LAGraph_Cached_AT (G, msg)) ; OK (GrB_eWiseAdd (G->A, NULL, NULL, GrB_LOR, G->A, G->AT, NULL)) ; - G->structure_is_symmetric = true ; + G->is_symmetric_structure = LAGraph_TRUE ; } G->kind = LAGraph_ADJACENCY_UNDIRECTED ; // check for self-edges - OK (LAGraph_Property_NDiag (G, msg)) ; - if (G->ndiag != 0) + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; + if (G->nself_edges != 0) { // remove self-edges - printf ("graph has %g self edges\n", (double) G->ndiag) ; - OK (LAGraph_DeleteDiag (G, msg)) ; - printf ("now has %g self edges\n", (double) G->ndiag) ; - TEST_CHECK (G->ndiag == 0) ; + printf ("graph has %g self edges\n", (double) G->nself_edges) ; + OK (LAGraph_DeleteSelfEdges (G, msg)) ; + printf ("now has %g self edges\n", (double) G->nself_edges) ; + TEST_CHECK (G->nself_edges == 0) ; } // compute the row degree - OK (LAGraph_Property_RowDegree (G, msg)) ; + OK (LAGraph_Cached_OutDegree (G, msg)) ; GrB_Index n ; GrB_Matrix_nrows (&n, G->A) ; @@ -175,16 +175,16 @@ void test_MIS (void) } printf ("creating at least %g singletons\n", (double) nsingletons) ; - OK (LAGraph_DeleteProperties (G, msg)) ; + OK (LAGraph_DeleteCached (G, msg)) ; G->kind = LAGraph_ADJACENCY_UNDIRECTED ; - G->structure_is_symmetric = true ; - G->ndiag = 0 ; + G->is_symmetric_structure = LAGraph_TRUE ; + G->nself_edges = 0 ; - // recompute the row degree - OK (LAGraph_Property_RowDegree (G, msg)) ; + // recompute the out degree + OK (LAGraph_Cached_OutDegree (G, msg)) ; GrB_Index nonsingletons, nsingletons_actual ; - OK (GrB_Vector_nvals (&nonsingletons, G->rowdegree)) ; + OK (GrB_Vector_nvals (&nonsingletons, G->out_degree)) ; nsingletons_actual = n - nonsingletons ; printf ("actual # of singletons: %g\n", (double) nsingletons_actual) ; TEST_CHECK (nsingletons <= nsingletons_actual) ; diff --git a/experimental/test/test_TriangleCentrality.c b/experimental/test/test_TriangleCentrality.c index 9d9ca018bc..30321c9be9 100644 --- a/experimental/test/test_TriangleCentrality.c +++ b/experimental/test/test_TriangleCentrality.c @@ -1,7 +1,7 @@ -//---------------------------------------------------------------------------- +//------------------------------------------------------------------------------ // LAGraph/src/test/test_TriangleCentrality.c: test cases for triangle // centrality -// ---------------------------------------------------------------------------- +//------------------------------------------------------------------------------ // LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause @@ -10,7 +10,7 @@ // Contributed by Timothy A. Davis, Texas A&M University -//----------------------------------------------------------------------------- +//------------------------------------------------------------------------------ #include #include @@ -81,14 +81,14 @@ void test_TriangleCentrality (void) TEST_CHECK (C == NULL) ; // check for self-edges - OK (LAGraph_Property_NDiag (G, msg)) ; - if (G->ndiag != 0) + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; + if (G->nself_edges != 0) { // remove self-edges - printf ("graph has %g self edges\n", (double) G->ndiag) ; - OK (LAGraph_DeleteDiag (G, msg)) ; - printf ("now has %g self edges\n", (double) G->ndiag) ; - TEST_CHECK (G->ndiag == 0) ; + printf ("graph has %g self edges\n", (double) G->nself_edges) ; + OK (LAGraph_DeleteSelfEdges (G, msg)) ; + printf ("now has %g self edges\n", (double) G->nself_edges) ; + TEST_CHECK (G->nself_edges == 0) ; } uint64_t ntri ; @@ -138,7 +138,7 @@ void test_errors (void) OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_UNDIRECTED, msg)) ; TEST_CHECK (A == NULL) ; - OK (LAGraph_Property_NDiag (G, msg)) ; + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; uint64_t ntri ; GrB_Vector c = NULL ; @@ -155,16 +155,16 @@ void test_errors (void) TEST_CHECK (c == NULL) ; // G may have self edges - G->ndiag = LAGRAPH_UNKNOWN ; + G->nself_edges = LAGRAPH_UNKNOWN ; result = LAGraph_VertexCentrality_Triangle (&c, &ntri, 3, G, msg) ; printf ("\nresult: %d %s\n", result, msg) ; TEST_CHECK (result == -1004) ; TEST_CHECK (c == NULL) ; // G is undirected - G->ndiag = 0 ; + G->nself_edges = 0 ; G->kind = LAGraph_ADJACENCY_DIRECTED ; - G->structure_is_symmetric = LAGraph_FALSE ; + G->is_symmetric_structure = LAGraph_FALSE ; result = LAGraph_VertexCentrality_Triangle (&c, &ntri, 3, G, msg) ; printf ("\nresult: %d %s\n", result, msg) ; TEST_CHECK (result == -1005) ; diff --git a/experimental/test/test_cdlp.c b/experimental/test/test_cdlp.c index 2427e14152..a58df3b98e 100644 --- a/experimental/test/test_cdlp.c +++ b/experimental/test/test_cdlp.c @@ -150,8 +150,8 @@ void test_cdlp (void) TEST_CHECK (A == NULL) ; // check for self-edges - OK (LAGraph_Property_NDiag (G, msg)) ; - bool sanitize = (G->ndiag != 0) ; + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; + bool sanitize = (G->nself_edges != 0) ; GrB_Vector c = NULL ; double t [2] ; @@ -208,7 +208,7 @@ void test_errors (void) OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_UNDIRECTED, msg)) ; TEST_CHECK (A == NULL) ; - OK (LAGraph_Property_NDiag (G, msg)) ; + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; GrB_Vector c = NULL ; double t [2] ; diff --git a/experimental/test/test_lcc.c b/experimental/test/test_lcc.c index 80804b9af0..6d0ad694d1 100644 --- a/experimental/test/test_lcc.c +++ b/experimental/test/test_lcc.c @@ -143,8 +143,8 @@ void test_lcc (void) TEST_CHECK (A == NULL) ; // check for self-edges - OK (LAGraph_Property_NDiag (G, msg)) ; - bool sanitize = (G->ndiag != 0) ; + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; + bool sanitize = (G->nself_edges != 0) ; GrB_Vector c = NULL ; double t [2] ; @@ -207,7 +207,7 @@ void test_errors (void) OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_UNDIRECTED, msg)) ; TEST_CHECK (A == NULL) ; - OK (LAGraph_Property_NDiag (G, msg)) ; + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; GrB_Vector c = NULL ; double t [2] ; diff --git a/experimental/utility/LAGraph_SRead.c b/experimental/utility/LAGraph_SRead.c index 919ac40f72..a78ebbfee5 100644 --- a/experimental/utility/LAGraph_SRead.c +++ b/experimental/utility/LAGraph_SRead.c @@ -115,8 +115,10 @@ int LAGraph_SRead // read a set of matrices from a *.lagraph file LAGraph_Contents *Contents = NULL ; GrB_Index ncontents = 0 ; - LG_ASSERT (collection_handle != NULL && Contents_handle != NULL && f != NULL - && ncontents_handle != NULL, GrB_NULL_POINTER) ; + LG_ASSERT (collection_handle != NULL, GrB_NULL_POINTER) ; + LG_ASSERT (Contents_handle != NULL, GrB_NULL_POINTER) ; + LG_ASSERT (f != NULL, GrB_NULL_POINTER) ; + LG_ASSERT (ncontents_handle != NULL, GrB_NULL_POINTER) ; (*collection_handle) = NULL ; (*Contents_handle) = NULL ; (*ncontents_handle) = 0 ; diff --git a/include/LAGraph.h b/include/LAGraph.h index 8852b67965..f330b18388 100644 --- a/include/LAGraph.h +++ b/include/LAGraph.h @@ -33,10 +33,10 @@ // See also the LAGraph_Version utility method, which returns these values. // These definitions must match the same definitions in LAGraph/CMakeLists.txt. // FIXME: use config to create include/LAGraph.h from LAGraph/CMakeLists.txt -#define LAGRAPH_DATE "Mar 16, 2022" +#define LAGRAPH_DATE "May 20, 2022" #define LAGRAPH_VERSION_MAJOR 0 #define LAGRAPH_VERSION_MINOR 9 -#define LAGRAPH_VERSION_UPDATE 14 +#define LAGRAPH_VERSION_UPDATE 23 //============================================================================== // include files and helper macros @@ -187,34 +187,41 @@ // LAGRAPH_SYMMETRIC_STRUCTURE_REQUIRED: the method requires an undirected // graph, or a directed graph with an adjacency matrix that is known to -// have a symmetric structure. LAGraph_Property_SymmetricStructure can -// be used to determine this property. +// have a symmetric structure. LAGraph_Cached_IsSymmetricStructure can +// be used to determine this cached property. // LAGRAPH_IO_ERROR: a file input or output method failed, or an input file // has an incorrect format that cannot be parsed. -// LAGRAPH_PROPERTY_MISSING: some methods require one or more cached -// properties to be computed before calling them (AT, rowdegree, or -// coldegree. Use LAGraph_Property_AT, LAGraph_Property_RowDegree, -// and/or LAGraph_Property_ColDegree to compute them. +// LAGRAPH_NOT_CACHED: some methods require one or more cached properties to +// be computed before calling them (AT, out_degree, or in_degree. Use +// LAGraph_Cached_AT, LAGraph_Cached_OutDegree, and/or +// LAGraph_Cached_InDegree to compute them. // LAGRAPH_NO_SELF_EDGES_ALLOWED: some methods requires that the graph have // no self edges, which correspond to the entries on the diagonal of the -// adjacency matrix. If the G->ndiag property is nonzero or unknown, this -// error condition is returned. Use LAGraph_Property_NDiag to compute -// G->ndiag, or LAGraph_DeleteDiag to remove all diagonal entries from -// G->A. +// adjacency matrix. If the G->nself_edges cached property is nonzero or +// unknown, this error condition is returned. Use LAGraph_Cached_NSelfEdges to +// compute G->nself_edges, or LAGraph_DeleteSelfEdges to remove all diagonal +// entries from G->A. // LAGRAPH_CONVERGENCE_FAILURE: an iterative process failed to converge to // a good solution. +// LAGRAPH_CACHE_NOT_NEEDED: this is a warning, not an error. It is returned +// by LAGraph_Cached_* methods when asked to compute cached properties +// that are not needed. These include G->AT and G->in_degree for an +// undirected graph. + #define LAGRAPH_INVALID_GRAPH (-1000) #define LAGRAPH_SYMMETRIC_STRUCTURE_REQUIRED (-1001) #define LAGRAPH_IO_ERROR (-1002) -#define LAGRAPH_PROPERTY_MISSING (-1003) +#define LAGRAPH_NOT_CACHED (-1003) #define LAGRAPH_NO_SELF_EDGES_ALLOWED (-1004) #define LAGRAPH_CONVERGENCE_FAILURE (-1005) +#define LAGRAPH_CACHE_NOT_NEEDED ( 1000) + // @retval GrB_SUCCESS if successful // @retval a negative GrB_Info value on error (in range -999 to -1) // @retval a positive GrB_Info value if successful but with extra information @@ -404,8 +411,6 @@ int LAGraph_Free // free a block of memory and set p to NULL // LAGRAPH_UNKNOWN is used for all scalars whose value is not known #define LAGRAPH_UNKNOWN (-1) -// FIXME: start here on Mar 16, 2022 - //------------------------------------------------------------------------------ // LAGraph_Kind: the kind of a graph //------------------------------------------------------------------------------ @@ -443,7 +448,7 @@ typedef enum LAGraph_Kind ; //------------------------------------------------------------------------------ -// LAGraph_BooleanProperty: true, false, or unknown +// LAGraph_Boolean: true, false, or unknown //------------------------------------------------------------------------------ typedef enum @@ -452,36 +457,32 @@ typedef enum LAGraph_TRUE = 1, LAGraph_BOOLEAN_UNKNOWN = LAGRAPH_UNKNOWN } -LAGraph_BooleanProperty ; +LAGraph_Boolean ; //------------------------------------------------------------------------------ -// LAGraph_BoundKind: exact, bound, approximate, or unknown +// LAGraph_State: value, bound, or unknown //------------------------------------------------------------------------------ -// LAGraph_BoundKind describes the status of a graph property or other metric. -// If the metric is computed in floating-point arithmetic, it may have been -// computed with roundoff error, but it may still be declared as "exact" if the -// roundoff error is expected to be small, or if the metric was computed as -// carefully as possible (to within reasonable roundoff error). The -// "approximate" state is used when the metric is a rough estimate, not because -// of roundoff error but because of other algorithmic approximations. The -// decision of when to tag a metric as "exact" or "approximate" is up to the -// particular algorithm, which each algorithm must document. +// LAGraph_State describes the status of a cached property of a graph. If the +// cached property is computed in floating-point arithmetic, it may have been +// computed with roundoff error, but it may still be declared as "value" if the +// roundoff error is expected to be small, or if the cached property was +// computed as carefully as possible (to within reasonable roundoff error). -// The "bound" state indicates that the metric is an upper or lower bound, -// depending on the particular metric. If computed in floating-point -// arithmetic, an "upper bound" metric may be actually slightly lower than the -// actual upper bound, because of floating-point roundoff. +// The "bound" state indicates that the cached property is an upper or lower +// bound, depending on the particular cached property. If computed in +// floating-point arithmetic, an "upper bound" cached property may be actually +// slightly lower than the actual upper bound, because of floating-point +// roundoff. typedef enum { - LAGraph_EXACT = 0, // the metric is exact (possibly ignoring roundoff) - LAGraph_BOUND = 1, // the metric is a bound (upper or lower, depending - // on the particular metric) - LAGraph_APPROX = 2, // the metric is a rough approximation - LAGraph_BOUND_UNKNOWN = LAGRAPH_UNKNOWN, + LAGraph_VALUE = 0, // cached property is a known value (ignoring roundoff) + LAGraph_BOUND = 1, // cached property is a bound (upper or lower, + // depending on the particular cached property) + LAGraph_STATE_UNKNOWN = LAGRAPH_UNKNOWN, } -LAGraph_BoundKind ; +LAGraph_State ; //------------------------------------------------------------------------------ // LAGraph_Graph: the primary graph data structure of LAGraph @@ -500,10 +501,12 @@ LAGraph_BoundKind ; // (2) cached properties of the graph, which can be recreated any time: // AT AT = A' -// rowdegree rowdegree(i) = # of entries in A(i,:) -// coldegree coldegree(j) = # of entries in A(:,j) -// structure_is_symmetric: true if the structure of A is symmetric -// ndiag the number of entries on the diagonal of A +// out_degree out_degree(i) = # of entries in A(i,:) +// in_degree in_degree(j) = # of entries in A(:,j) +// is_symmetric_structure: true if the structure of A is symmetric +// nself_edges the number of entries on the diagonal of A +// emin minimum edge weight +// emax maximum edge weight struct LAGraph_Graph_struct { @@ -527,75 +530,75 @@ struct LAGraph_Graph_struct // All of these components may be deleted or set to 'unknown' at any time. // For example, if AT is NULL, then the transpose of A has not been - // computed. A scalar property of type LAGraph_BooleanProperty would be - // set to LAGRAPH_UNKNOWN to denote that its value is unknown. + // computed. A scalar cached property of type LAGraph_Boolean would be set + // to LAGRAPH_UNKNOWN to denote that its value is unknown. - // If present, the properties must be valid and accurate. If the graph - // changes, these properties can either be recomputed or deleted to denote - // the fact that they are unknown. This choice is up to individual LAGraph - // methods and utilities. + // If present, the cached properties must be valid and accurate. If the + // graph changes, these cached properties can either be recomputed or + // deleted to denote the fact that they are unknown. This choice is up to + // individual LAGraph methods and utilities. - // LAGraph methods can set non-scalar properties only if they are + // LAGraph methods can set non-scalar cached properties only if they are // constructing the graph. They cannot modify them or create them if the // graph is declared as a read-only object in the parameter list of the // method. GrB_Matrix AT ; // AT = A', the transpose of A, with the same type. - GrB_Vector rowdegree ; // a GrB_INT64 vector of length m, if A is m-by-n. - // where rowdegree(i) is the number of entries in A(i,:). If - // rowdegree is sparse and the entry rowdegree(i) is not present, + GrB_Vector out_degree ; // a GrB_INT64 vector of length m, if A is m-by-n. + // where out_degree(i) is the number of entries in A(i,:). If + // out_degree is sparse and the entry out_degree(i) is not present, // then it is assumed to be zero. - GrB_Vector coldegree ; // a GrB_INT64 vector of length n, if A is m-by-n. - // where coldegree(j) is the number of entries in A(:,j). If - // coldegree is sparse and the entry coldegree(j) is not present, + GrB_Vector in_degree ; // a GrB_INT64 vector of length n, if A is m-by-n. + // where in_degree(j) is the number of entries in A(:,j). If + // in_degree is sparse and the entry in_degree(j) is not present, // then it is assumed to be zero. If A is known to have a // symmetric structure, the convention is that the degree is held in - // rowdegree, and coldegree is left as NULL. + // out_degree, and in_degree is left as NULL. // If G is held as an incidence matrix, then G->A might be rectangular, // in the future, but the graph G may have a symmetric structure anyway. - LAGraph_BooleanProperty structure_is_symmetric ; // For an undirected - // graph, this property will always be implicitly true and can be - // ignored. The matrix A for a directed weighted graph will + LAGraph_Boolean is_symmetric_structure ; // For an undirected + // graph, this cached property will always be implicitly true and + // can be ignored. The matrix A for a directed weighted graph will // typically be unsymmetric, but might have a symmetric structure. - // In that case, this scalar property can be set to true. - // By default, this property is set to LAGRAPH_UNKNOWN. + // In that case, this scalar cached property can be set to true. + // By default, this cached property is set to LAGRAPH_UNKNOWN. - int64_t ndiag ; // # of entries on the diagonal of A, or LAGRAPH_UNKNOWN if - // unknown. For the adjacency matrix of a directed or undirected - // graph, this is the number of self-edges in the graph. + int64_t nself_edges ; // # of entries on the diagonal of A, or + // LAGRAPH_UNKNOWN if unknown. For the adjacency matrix of a + // directed or undirected graph, this is the number of self-edges + // in the graph. - GrB_Scalar emin ; // minimum edge weight: exact, lower bound, or estimate - LAGraph_BoundKind emin_kind ; - // EXACT: emin is exactly equal to the smallest entry, min(G->A) + GrB_Scalar emin ; // minimum edge weight: value, lower bound, or unknown + LAGraph_State emin_state ; + // VALUE: emin is equal to the smallest entry, min(G->A) // BOUND: emin <= min(G->A) - // APPROX: emin is a rough estimate of min(G->A) // UNKNOWN: emin is unknown - GrB_Scalar emax ; // maximum edge weight: exact, upper bound, or estimate - LAGraph_BoundKind emax_kind ; - // EXACT: emax is exactly equal to the largest entry, max(G->A) + GrB_Scalar emax ; // maximum edge weight: value, upper bound, or unknown + LAGraph_State emax_state ; + // VALUE: emax is equal to the largest entry, max(G->A) // BOUND: emax >= max(G->A) - // APPROX: emax is a rough estimate of max(G->A) // UNKNOWN: emax is unknown // possible future cached properties: // Some algorithms may want to know if the graph has any edge weights // exactly equal to zero. In some cases, this can be inferred from the - // emin/emax bounds, or it can be indicated via the following property: - // LAGraph_BooleanProperty nonzero ; // If true, then all entries in + // emin/emax bounds, or it can be indicated via the following cached + // property: + // LAGraph_Boolean nonzero ; // If true, then all entries in // G->A are known to be nonzero. If false, G->A may contain // entries in its structure that are identically equal to zero. If // unknown, then G->A may or may not have entries equal to zero. // other edge weight metrics: median, standard deviation.... Might be // useful for computing Delta for a Basic SSSP. - // GrB_Vector rowsum, colsum ; - // rowsum(i) = sum(A(i,:)), regardless of kind - // colsum(j) = sum(A(:,j)), regardless of kind - // LAGraph_BooleanProperty connected ; // true if G is a connected graph + // GrB_Vector row_sum, col_sum ; + // row_sum(i) = sum(abs(A(i,:))), regardless of kind + // col_sum(j) = sum(abs(A(:,j))), regardless of kind + // LAGraph_Boolean connected ; // true if G is a connected graph } ; typedef struct LAGraph_Graph_struct *LAGraph_Graph ; @@ -611,10 +614,16 @@ typedef struct LAGraph_Graph_struct *LAGraph_Graph ; // This method must be called before calling any other GrB* or LAGraph* method. // It initializes GraphBLAS with GrB_init and then performs LAGraph-specific // initializations. In particular, the LAGraph semirings listed below are -// created. +// created. GrB_init can also safely be called before calling LAGr_Init +// or LAGraph_Init. LAGRAPH_PUBLIC -int LAGraph_Init (char *msg) ; +int LAGraph_Init +( + char *msg +) ; + +// FUTURE: include these as built-in semirings in v2.1 C API, Table 3.9: // LAGraph semirings, created by LAGraph_Init or LAGr_Init: LAGRAPH_PUBLIC GrB_Semiring @@ -658,22 +667,21 @@ LAGRAPH_PUBLIC GrB_Semiring LAGraph_plus_one_fp32 , LAGraph_plus_one_fp64 , - // LAGraph_structural_T: using the GrB_MIN_MONOID_T for non-boolean types - // or GrB_LOR_MONOID_BOOL for boolean, and the GrB_ONEB_T multiplicative - // op. These semirings are very useful for unweighted graphs, or for - // algorithms that operate only on the sparsity structure of unweighted - // graphs. - LAGraph_structural_bool , - LAGraph_structural_int8 , - LAGraph_structural_int16 , - LAGraph_structural_int32 , - LAGraph_structural_int64 , - LAGraph_structural_uint8 , - LAGraph_structural_uint16 , - LAGraph_structural_uint32 , - LAGraph_structural_uint64 , - LAGraph_structural_fp32 , - LAGraph_structural_fp64 ; + // LAGraph_any_one_T: using the GrB_MIN_MONOID_T for non-boolean types or + // GrB_LOR_MONOID_BOOL for boolean, and the GrB_ONEB_T multiplicative op. + // These semirings are very useful for unweighted graphs, or for algorithms + // that operate only on the sparsity structure of unweighted graphs. + LAGraph_any_one_bool , // (or, true) semiring + LAGraph_any_one_int8 , // (min, 1) semiring + LAGraph_any_one_int16 , + LAGraph_any_one_int32 , + LAGraph_any_one_int64 , + LAGraph_any_one_uint8 , + LAGraph_any_one_uint16 , + LAGraph_any_one_uint32 , + LAGraph_any_one_uint64 , + LAGraph_any_one_fp32 , + LAGraph_any_one_fp64 ; //------------------------------------------------------------------------------ // LAGraph_Version: determine the version of LAGraph @@ -697,8 +705,8 @@ LAGRAPH_PUBLIC int LAGraph_Version ( // output: - int version_number [3], // user-provided array of size 3 - char version_date [LAGRAPH_MSG_LEN], // user-provided array + int version_number [3], // user-provided array of size 3 + char *version_date, // user-provided array of size >= LAGRAPH_MSG_LEN char *msg ) ; @@ -712,15 +720,18 @@ int LAGraph_Version // may be used. LAGRAPH_PUBLIC -int LAGraph_Finalize (char *msg) ; +int LAGraph_Finalize +( + char *msg +) ; //------------------------------------------------------------------------------ // LAGraph_New: create a new graph //------------------------------------------------------------------------------ -// LAGraph_New creates a new graph G. The properties G->AT, G->rowdegree, and -// G->coldegree are set to NULL, and scalar properties are set to -// LAGRAPH_UNKNOWN. +// LAGraph_New creates a new graph G. The cached properties G->AT, +// G->out_degree, and G->in_degree are set to NULL, and scalar +// cached properties are set to LAGRAPH_UNKNOWN. LAGRAPH_PUBLIC int LAGraph_New @@ -746,7 +757,7 @@ int LAGraph_New //------------------------------------------------------------------------------ // LAGraph_Delete frees a graph G, including its adjacency matrix G->A and the -// cached properties G->AT, G->rowdegree, and G->coldegree. +// cached properties G->AT, G->out_degree, and G->in_degree. LAGRAPH_PUBLIC int LAGraph_Delete @@ -761,15 +772,15 @@ int LAGraph_Delete ) ; //------------------------------------------------------------------------------ -// LAGraph_DeleteProperties: free any internal cached properties of a graph +// LAGraph_DeleteCached: free any internal cached properties of a graph //------------------------------------------------------------------------------ -// LAGraph_DeleteProperties frees all cached properies of a graph G. The graph +// LAGraph_DeleteCached frees all cached properies of a graph G. The graph // is still valid. This method should be used if G->A changes, since such -// changes will normally invalidate G->AT, G->rowdgree, and/or G->coldegree. +// changes will normally invalidate G->AT, G->out_degree, and/or G->in_degree. LAGRAPH_PUBLIC -int LAGraph_DeleteProperties +int LAGraph_DeleteCached ( // input/output: LAGraph_Graph G, // G stays valid, only cached properties are freed @@ -777,10 +788,10 @@ int LAGraph_DeleteProperties ) ; //------------------------------------------------------------------------------ -// LAGraph_Property_AT: construct G->AT for a graph +// LAGraph_Cached_AT: construct G->AT for a graph //------------------------------------------------------------------------------ -// LAGraph_Property_AT constructs G->AT, the transpose of G->A. This matrix is +// LAGraph_Cached_AT constructs G->AT, the transpose of G->A. This matrix is // required by some of the algorithms. Basic algorithms may construct G->AT if // they require it. The matrix G->AT is then available for subsequent use. // If G->A changes, G->AT should be freed and recomputed. If G->AT already @@ -788,7 +799,7 @@ int LAGraph_DeleteProperties // be explictly freed. LAGRAPH_PUBLIC -int LAGraph_Property_AT +int LAGraph_Cached_AT ( // input/output: LAGraph_Graph G, // graph for which to compute G->AT @@ -796,18 +807,18 @@ int LAGraph_Property_AT ) ; //------------------------------------------------------------------------------ -// LAGraph_Property_SymmetricStructure: determine G->structure_is_symmetric +// LAGraph_Cached_IsSymmetricStructure: determine G->is_symmetric_structure //------------------------------------------------------------------------------ -// LAGraph_Property_SymmetricStructure determines if the sparsity structure -// of G->A is symmetric (ignoring its values). If G->kind denotes that the -// graph is undirected, this property is implicitly true (and not checked). +// LAGraph_Cached_IsSymmetricStructure determines if the sparsity structure of +// G->A is symmetric (ignoring its values). If G->kind denotes that the graph +// is undirected, this cached property is implicitly true (and not checked). // Otherwise, this method determines if the structure of G->A for a directed -// graph G has a symmetric sparsity structure. No work is performend if the -// property is already known. +// graph G has a symmetric sparsity structure. No work is performed if the +// cached property is already known. LAGRAPH_PUBLIC -int LAGraph_Property_SymmetricStructure +int LAGraph_Cached_IsSymmetricStructure ( // input/output: LAGraph_Graph G, // graph to determine the symmetry of structure of A @@ -815,62 +826,62 @@ int LAGraph_Property_SymmetricStructure ) ; //------------------------------------------------------------------------------ -// LAGraph_Property_RowDegree: determine G->rowdegree +// LAGraph_Cached_OutDegree: determine G->out_degree //------------------------------------------------------------------------------ -// LAGraph_Property_RowDegree computes G->rowdegree. No work is performed if +// LAGraph_Cached_OutDegree computes G->out_degree. No work is performed if // it already exists in G. LAGRAPH_PUBLIC -int LAGraph_Property_RowDegree +int LAGraph_Cached_OutDegree ( // input/output: - LAGraph_Graph G, // graph to determine G->rowdegree + LAGraph_Graph G, // graph to determine G->out_degree char *msg ) ; //------------------------------------------------------------------------------ -// LAGraph_Property_ColDegree: determine G->coldegree +// LAGraph_Cached_InDegree: determine G->in_degree //------------------------------------------------------------------------------ -// LAGraph_Property_ColDegree computes G->coldegree. No work is performed if -// it already exists in G. If G is undirected, G->coldegree is never computed. -// Instead, G->rowdegree is used instead. No work is performed it is already -// exists in G. +// LAGraph_Cached_InDegree computes G->in_degree. No work is performed if it +// already exists in G. If G is undirected, G->in_degree is never computed +// and remains NULL (the method returns LAGRAPH_CACHE_NOT_NEEDED). No work is +// performed if it is already exists in G. LAGRAPH_PUBLIC -int LAGraph_Property_ColDegree +int LAGraph_Cached_InDegree ( // input/output: - LAGraph_Graph G, // graph to determine G->coldegree + LAGraph_Graph G, // graph to determine G->in_degree char *msg ) ; //------------------------------------------------------------------------------ -// LAGraph_Property_NDiag: determine G->ndiag +// LAGraph_Cached_NSelfEdges: determine G->nself_edges //------------------------------------------------------------------------------ -// LAGraph_Property_NDiag computes G->ndiag, the number of diagonal entries +// LAGraph_Cached_NSelfEdges computes G->nself_edges, the number of diagonal entries // that appear in the G->A matrix. For an undirected or directed graph with an // adjacency matrix G->A, these are the number of self-edges in G. No work is // performed it is already computed. LAGRAPH_PUBLIC -int LAGraph_Property_NDiag +int LAGraph_Cached_NSelfEdges ( // input/output: - LAGraph_Graph G, // graph to compute G->ndiag + LAGraph_Graph G, // graph to compute G->nself_edges char *msg ) ; //------------------------------------------------------------------------------ -// LAGraph_Property_EMin: determine G->emin +// LAGraph_Cached_EMin: determine G->emin //------------------------------------------------------------------------------ -// LAGraph_Property_EMin computes G->emin = min (G->A). +// LAGraph_Cached_EMin computes G->emin = min (G->A). LAGRAPH_PUBLIC -int LAGraph_Property_EMin +int LAGraph_Cached_EMin ( // input/output: LAGraph_Graph G, // graph to determine G->emin @@ -878,13 +889,13 @@ int LAGraph_Property_EMin ) ; //------------------------------------------------------------------------------ -// LAGraph_Property_EMax: determine G->emax +// LAGraph_Cached_EMax: determine G->emax //------------------------------------------------------------------------------ -// LAGraph_Property_EMax computes G->emax = max (G->A). +// LAGraph_Cached_EMax computes G->emax = max (G->A). LAGRAPH_PUBLIC -int LAGraph_Property_EMax +int LAGraph_Cached_EMax ( // input/output: LAGraph_Graph G, // graph to determine G->emax @@ -892,18 +903,19 @@ int LAGraph_Property_EMax ) ; //------------------------------------------------------------------------------ -// LAGraph_DeleteDiag: remove all diagonal entries from G->A +// LAGraph_DeleteSelfEdges: remove all diagonal entries from G->A //------------------------------------------------------------------------------ -// LAGraph_DeleteDiag removes any diagonal entries from G->A. Most properties -// are cleared or set to LAGRAPH_UNKNOWN. G->ndiag is set to zero, and -// G->structure_is_symmetric is left unchanged. +// LAGraph_DeleteSelfEdges removes any diagonal entries from G->A. Most cached +// properties are cleared or set to LAGRAPH_UNKNOWN. G->nself_edges is set to +// zero, and G->is_symmetric_structure is left unchanged. LAGRAPH_PUBLIC -int LAGraph_DeleteDiag +int LAGraph_DeleteSelfEdges ( // input/output: - LAGraph_Graph G, // diagonal entries removed, most properties cleared + LAGraph_Graph G, // diagonal entries removed, most cached properties + // cleared char *msg ) ; @@ -927,15 +939,17 @@ int LAGraph_CheckGraph //------------------------------------------------------------------------------ // LAGraph_GetNumThreads determines the current number of OpenMP threads that -// can be used. This is provided by SuiteSparse:GraphBLAS via a GxB extension, -// or by omp_get_max_threads() otherwise. If OpenMP is not in use, then 1 is -// returned. +// can be used. + +// FIXME: start here for next LAGraph meeting. LAGRAPH_PUBLIC int LAGraph_GetNumThreads ( // output: - int *nthreads, // # of threads to use + int *nthreads_hi, // for outer region for nested parallelism + int *nthreads_lo, // for inner region of nested parallelism, or for the + // underlying GraphBLAS library char *msg ) ; @@ -944,15 +958,14 @@ int LAGraph_GetNumThreads //------------------------------------------------------------------------------ // LAGraph_SetNumThreads sets the current number of OpenMP threads that -// can be used. This is provided by SuiteSparse:GraphBLAS via a GxB extension, -// or by omp_set_max_threads() otherwise. If OpenMP is not in use, then this -// function silently returns with no error message. +// can be used. LAGRAPH_PUBLIC int LAGraph_SetNumThreads ( // input: - int nthreads, // # of threads to use + int nthreads_hi, + int nthreads_lo, char *msg ) ; @@ -1119,6 +1132,8 @@ int LAGraph_Toc * column-major order. This rule is follwed by LAGraph_MMWrite. However, * LAGraph_MMRead can read the entries in any order. * + * FUTURE: add support for user-defined types. + * * @param[out] A handle of the matrix to create * @param[in] f handle to an open file to read from * @param[in,out] msg any error messages @@ -1149,6 +1164,8 @@ int LAGraph_MMRead // containing the GraphBLAS type: // %%GraphBLAS type +// FUTURE: add support for user-defined types. + LAGRAPH_PUBLIC int LAGraph_MMWrite ( @@ -1314,7 +1331,7 @@ int LAGraph_Scalar_TypeName //------------------------------------------------------------------------------ // LAGraph_KindName: return the name of a graph kind. For example, if given -// LAGaphH_ADJACENCY_UNDIRECTED, the string "undirected" is returned. +// LAGraph_ADJACENCY_UNDIRECTED, the string "undirected" is returned. LAGRAPH_PUBLIC int LAGraph_KindName @@ -1331,9 +1348,10 @@ int LAGraph_KindName // LAGraph_SortByDegree: sort a graph by its row or column degree //------------------------------------------------------------------------------ -// LAGraph_SortByDegree sorts the nodes of a graph by their row or column -// degrees. The graph G->A itself is not changed. Refer to LAGr_TriangleCount -// for an example of how to permute G->A after calling this function. +// LAGraph_SortByDegree sorts the nodes of a graph by their out or in degrees. +// The graph G->A itself is not changed. Refer to LAGr_TriangleCount for an +// example of how to permute G->A after calling this function. The output &P +// must be freed by LAGraph_Free. LAGRAPH_PUBLIC int LAGraph_SortByDegree @@ -1342,7 +1360,7 @@ int LAGraph_SortByDegree int64_t **P_handle, // P is returned as a permutation vector of size n // input: const LAGraph_Graph G, // graph of n nodes - bool byrow, // if true, sort G->rowdegree, else G->coldegree + bool byout, // if true, sort G->out_degree, else G->in_degree bool ascending, // sort in ascending or descending order char *msg ) ; @@ -1351,8 +1369,8 @@ int LAGraph_SortByDegree // LAGraph_SampleDegree: sample the degree median and mean //------------------------------------------------------------------------------ -// LAGraph_SampleDegree computes an estimate of the median and mean of the row -// or column degree, by randomly sampling the G->rowdegree or G->coldegree +// LAGraph_SampleDegree computes an estimate of the median and mean of the out +// or in degree, by randomly sampling the G->out_degree or G->in_degree // vector. LAGRAPH_PUBLIC @@ -1363,7 +1381,7 @@ int LAGraph_SampleDegree double *sample_median, // sampled median degree // input: const LAGraph_Graph G, // graph of n nodes - bool byrow, // if true, sample G->rowdegree, else G->coldegree + bool byout, // if true, sample G->out_degree, else G->in_degree int64_t nsamples, // number of samples uint64_t seed, // random number seed char *msg @@ -1450,7 +1468,8 @@ int LAGraph_Matrix_IsEqual_op * @param[out] result Set to true on return is vectors are "equal" * @param[in] A First vector to compare * @param[in] B Second vector to compare - * @param[out] msg If an error code is returned, this may hold an error msg. + * @param[out] msg If an error code is returned, + * this may hold an error msg. * * @retval GrB_SUCCESS if completed successfully (equal or not) * @retval GrB_NULL_POINTER A, result or type is NULL @@ -1481,7 +1500,8 @@ int LAGraph_Vector_IsEqual * @param[in] A First vector to compare * @param[in] B Second vector to compare * @param[in] op Binary operator to use for the comparisons - * @param[out] msg If an error code is returned, this may hold an error msg. + * @param[out] msg If an error code is returned, + * this may hold an error msg. * * @retval GrB_SUCCESS if completed successfully (equal or not) * @retval GrB_NULL_POINTER result or op is NULL @@ -1551,7 +1571,6 @@ int LAGraph_Sort1 int64_t *A_0, // size n array // input: const int64_t n, - int nthreads, // # of threads to use char *msg ) ; @@ -1572,7 +1591,6 @@ int LAGraph_Sort2 int64_t *A_1, // size n array // input: const int64_t n, - int nthreads, // # of threads to use char *msg ) ; @@ -1595,7 +1613,6 @@ int LAGraph_Sort3 int64_t *A_2, // size n array // input: const int64_t n, - int nthreads, // # of threads to use char *msg ) ; @@ -1606,9 +1623,9 @@ int LAGraph_Sort3 // Basic algorithm are meant to be easy to use. They may encompass many // underlying Advanced algorithms, each with various parameters that may be // controlled. For the Basic API, these parameters are determined -// automatically. Graph properties may be determined, and as a result, the -// graph G is both an input and an output of these methods, since they may be -// modified. +// automatically. Cached graph properties may be determined, and as a result, +// the graph G is both an input and an output of these methods, since they may +// be modified. // LAGraph Basic algorithms are named with the LAGraph_* prefix. @@ -1616,8 +1633,8 @@ int LAGraph_Sort3 // LAGraph_TriangleCount //------------------------------------------------------------------------------ -// This is a Basic algorithm (G->ndiag, G->rowdegree, G->structure_is_symmetric -// are computed, if not present). +// This is a Basic algorithm (G->nself_edges, G->out_degree, +// G->is_symmetric_structure are computed, if not present). /* * Count the triangles in a graph. @@ -1626,14 +1643,15 @@ int LAGraph_Sort3 * @param[in,out] G The graph, symmetric, no self loops. * @param[out] msg Error message if a failure code is returned. */ + LAGRAPH_PUBLIC int LAGraph_TriangleCount ( // output: - uint64_t *ntriangles, // # of triangles + uint64_t *ntriangles, // # of triangles // input/output: LAGraph_Graph G, - char *msg + char *msg ) ; //============================================================================== @@ -1642,9 +1660,9 @@ int LAGraph_TriangleCount // The Advanced algorithms require the caller to select the algorithm and choose // any parameter settings. G is not modified, and so it is an input-only -// parameter to these methods. If an Advanced algorithm requires a graph -// property to be computed, it must be computed prior to calling the Advanced -// method. +// parameter to these methods. If an Advanced algorithm requires a cached +// graph property to be computed, it must be computed prior to calling the +// Advanced method. // Advanced algorithms are named with the LAGr_* prefix, to distinguish them // from Basic algorithms. @@ -1654,11 +1672,11 @@ int LAGraph_TriangleCount //------------------------------------------------------------------------------ // LAGr_Init is identical to LAGraph_Init, except that it allows the user -// application to provide four memory management functions, replacing the -// standard malloc, calloc, realloc, and free. The functions pointed to by -// user_malloc_function, user_calloc_function, user_realloc_function, and -// user_free_function have the same signature as the ANSI C malloc, calloc, -// realloc, and free functions, respectively. +// application to specify the GraphBLAS mode. It also provides four memory +// management functions, replacing the standard malloc, calloc, realloc, and +// free. The functions user_malloc_function, user_calloc_function, +// user_realloc_function, and user_free_function have the same signature as the +// ANSI C malloc, calloc, realloc, and free functions, respectively. // Only user_malloc_function and user_free_function are required. // user_calloc_function may be NULL, in which case LAGraph_Calloc uses @@ -1669,6 +1687,7 @@ LAGRAPH_PUBLIC int LAGr_Init ( // input: + GrB_Mode mode, // mode for GrB_Init or GxB_Init void * (* user_malloc_function ) (size_t), void * (* user_calloc_function ) (size_t, size_t), void * (* user_realloc_function ) (void *, size_t), @@ -1708,19 +1727,19 @@ LAGRAPH_PUBLIC int LAGr_BreadthFirstSearch ( // output: - GrB_Vector *level, - GrB_Vector *parent, + GrB_Vector *level, + GrB_Vector *parent, // input: const LAGraph_Graph G, - GrB_Index src, - char *msg + GrB_Index src, + char *msg ) ; //------------------------------------------------------------------------------ // LAGr_ConnectedComponents: connected components of an undirected graph //------------------------------------------------------------------------------ -// This is an Advanced algorithm (G->structure_is_symmetric must be known), +// This is an Advanced algorithm (G->is_symmetric_structure must be known), LAGRAPH_PUBLIC int LAGr_ConnectedComponents @@ -1781,7 +1800,7 @@ int LAGr_Betweenness // LAGr_PageRank: pagerank //------------------------------------------------------------------------------ -// This is an Advanced algorithm (G->AT and G->rowdegree are required). +// This is an Advanced algorithm (G->AT and G->out_degree are required). // LAGr_PageRank computes the standard pagerank of a // directed graph G. Sinks (nodes with no out-going edges) are handled. @@ -1804,7 +1823,7 @@ int LAGr_PageRank // LAGr_PageRankGAP: GAP-style pagerank //------------------------------------------------------------------------------ -// This is an Advanced algorithm (G->AT and G->rowdegree are required). +// This is an Advanced algorithm (G->AT and G->out_degree are required). // LAGr_PageRankGAP computes the GAP-style pagerank of a // directed graph G. Sinks (nodes with no out-going edges) are not handled. @@ -1828,14 +1847,15 @@ int LAGr_PageRankGAP // LAGr_TriangleCount: triangle counting //------------------------------------------------------------------------------ -// This is an Advanced algorithm (G->ndiag, G->rowdegree, -// G->structure_is_symmetric are required). +// This is an Advanced algorithm (G->nself_edges, G->out_degree, +// G->is_symmetric_structure are required). /* Count the triangles in a graph. Advanced API * * @param[out] ntriangles On successful return, contains the number of tris. - * @param[in] G The graph, symmetric, no self loops, and for some methods - * (3-6), must have the row degree property calculated + * @param[in] G The graph, symmetric, no self loops, and for some + * methods (3-6), must have the cached row degree + * property calculated * @param[in] method specifies which algorithm to use * 0: use the default method * 1: Burkhardt: ntri = sum (sum ((A^2) .* A)) / 6 @@ -1893,12 +1913,12 @@ LAGRAPH_PUBLIC int LAGr_TriangleCount ( // output: - uint64_t *ntriangles, + uint64_t *ntriangles, // input: const LAGraph_Graph G, LAGraph_TriangleCount_Method method, LAGraph_TriangleCount_Presort *presort, - char *msg + char *msg ) ; #endif diff --git a/include/LAGraphX.h b/include/LAGraphX.h index efa4f5b404..e748185a0f 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -28,8 +28,16 @@ // Random number generator //**************************************************************************** -LAGRAPH_PUBLIC int LAGraph_Random_Init (char *msg) ; -LAGRAPH_PUBLIC int LAGraph_Random_Finalize (char *msg) ; +LAGRAPH_PUBLIC +int LAGraph_Random_Init +( + char *msg +) ; +LAGRAPH_PUBLIC +int LAGraph_Random_Finalize +( + char *msg +) ; #if defined ( COVERAGE ) // for testing only @@ -398,7 +406,7 @@ GrB_Info LAGraph_BF_basic_mxv GrB_Vector *pd_output, //the pointer to the vector of distance const GrB_Matrix AT, //transposed adjacency matrix for the graph const GrB_Index s //given index of the source -); +) ; /** * Bellman-Ford single source shortest paths, returning both the path lengths @@ -452,7 +460,7 @@ GrB_Info LAGraph_BF_full1 GrB_Vector *ph_output, const GrB_Matrix A, const GrB_Index s -); +) ; /** * Bellman-Ford single source shortest paths, returning both the path lengths @@ -479,7 +487,7 @@ GrB_Info LAGraph_BF_full1a GrB_Vector *ph_output, const GrB_Matrix A, const GrB_Index s -); +) ; /** * Bellman-Ford single source shortest paths, returning both the path lengths @@ -506,7 +514,7 @@ GrB_Info LAGraph_BF_full2 GrB_Vector *ph_output, //the pointer to the vector of hops const GrB_Matrix A, //matrix for the graph const GrB_Index s //given index of the source -); +) ; /** * Bellman-Ford single source shortest paths, returning both the path lengths @@ -533,7 +541,7 @@ GrB_Info LAGraph_BF_full_mxv GrB_Vector *ph_output, const GrB_Matrix AT, const GrB_Index s -); +) ; /** * Bellman-Ford single source shortest paths, returning both the path lengths @@ -570,7 +578,7 @@ GrB_Info LAGraph_BF_pure_c const int64_t *I, const int64_t *J, const int32_t *W -); +) ; /** * Bellman-Ford single source shortest paths, returning both the path lengths @@ -607,7 +615,7 @@ GrB_Info LAGraph_BF_pure_c_double const int64_t *I, const int64_t *J, const double *W -); +) ; //**************************************************************************** /** @@ -637,7 +645,7 @@ int LAGraph_cdlp int itermax, double *t, char *msg -); +) ; //**************************************************************************** /** @@ -666,7 +674,7 @@ GrB_Info LAGraph_dnn GrB_Matrix *Bias, int nlayers, GrB_Matrix Y0 -); +) ; //**************************************************************************** /** @@ -687,7 +695,7 @@ GrB_Info LAGraph_FW const GrB_Matrix G, GrB_Matrix *D, GrB_Type *D_type -); +) ; //**************************************************************************** /** @@ -776,4 +784,42 @@ int LG_CC_FastSV5 // SuiteSparse:GraphBLAS method, with GxB extensions char *msg ) ; +//------------------------------------------------------------------------------ +// kcore algorithms +//------------------------------------------------------------------------------ + +LAGRAPH_PUBLIC +int LAGraph_KCore_All +( + // outputs: + GrB_Vector *decomp, // kcore decomposition + uint64_t *kmax, + // inputs: + LAGraph_Graph G, // input graph + char *msg +) ; + +LAGRAPH_PUBLIC +int LAGraph_KCore +( + // outputs: + GrB_Vector *decomp, // kcore decomposition + // inputs: + LAGraph_Graph G, // input graph + uint64_t k, //k level to compare to + char *msg +) ; + +LAGRAPH_PUBLIC +int LAGraph_KCore_Decompose +( + // outputs: + GrB_Matrix *D, // kcore decomposition + // inputs: + LAGraph_Graph G, // input graph + GrB_Vector decomp, // input decomposition matrix + uint64_t k, + char *msg +) ; + #endif diff --git a/src/algorithm/LAGr_Betweenness.c b/src/algorithm/LAGr_Betweenness.c index c347db1d6f..b29ff5eb34 100644 --- a/src/algorithm/LAGr_Betweenness.c +++ b/src/algorithm/LAGr_Betweenness.c @@ -127,7 +127,7 @@ int LAGr_Betweenness GrB_Matrix A = G->A ; GrB_Matrix AT ; if (G->kind == LAGraph_ADJACENCY_UNDIRECTED || - G->structure_is_symmetric == LAGraph_TRUE) + G->is_symmetric_structure == LAGraph_TRUE) { // A and A' have the same structure AT = A ; @@ -136,8 +136,7 @@ int LAGr_Betweenness { // A and A' differ AT = G->AT ; - LG_ASSERT_MSG (AT != NULL, - LAGRAPH_PROPERTY_MISSING, "G->AT is required") ; + LG_ASSERT_MSG (AT != NULL, LAGRAPH_NOT_CACHED, "G->AT is required") ; } // ========================================================================= diff --git a/src/algorithm/LAGr_BreadthFirstSearch.c b/src/algorithm/LAGr_BreadthFirstSearch.c index e53e1545c6..dfc8bcfe84 100644 --- a/src/algorithm/LAGr_BreadthFirstSearch.c +++ b/src/algorithm/LAGr_BreadthFirstSearch.c @@ -32,10 +32,10 @@ int LAGr_BreadthFirstSearch { #if LAGRAPH_SUITESPARSE - // requires G->AT and G->rowdegree + // requires G->AT and G->out_degree return LG_BreadthFirstSearch_SSGrB (level, parent, G, src, msg) ; #else - // requires no properties, but G is input-only anyway + // requires no cached properties, but G is input-only anyway return LG_BreadthFirstSearch_vanilla (level, parent, G, src, msg) ; #endif } diff --git a/src/algorithm/LAGr_ConnectedComponents.c b/src/algorithm/LAGr_ConnectedComponents.c index 819a8e56d3..9ef3bf1597 100644 --- a/src/algorithm/LAGr_ConnectedComponents.c +++ b/src/algorithm/LAGr_ConnectedComponents.c @@ -11,7 +11,7 @@ //------------------------------------------------------------------------------ -// This is an Advanced algorithm (G->structure_is_symmetric must be known). +// This is an Advanced algorithm (G->is_symmetric_structure must be known). // Connected Components via LG_CC_FastSV6 if using SuiteSparse:GraphBLAS and // its GxB extensions, or LG_CC_Boruvka otherwise. The former is much faster. diff --git a/src/algorithm/LAGr_PageRank.c b/src/algorithm/LAGr_PageRank.c index 9908b957b5..2a2038746d 100644 --- a/src/algorithm/LAGr_PageRank.c +++ b/src/algorithm/LAGr_PageRank.c @@ -11,7 +11,7 @@ //------------------------------------------------------------------------------ -// This is an Advanced algorithm (G->AT and G->rowdegree are required). +// This is an Advanced algorithm (G->AT and G->out_degree are required). // PageRank (not for the GAP benchmark, but for production use). Do not use // this method for the GAP benchmark. Use LAGr_PageRankGAP instead. @@ -21,10 +21,10 @@ // thus sum(centrality) is not maintained as 1. This method handles sinks // properly, and thus keeps sum(centrality) equal to 1. -// The G->AT and G->rowdegree properties must be defined for this method. If G -// is undirected or G->A is known to have a symmetric structure, then G->A is -// used instead of G->AT, however. G->rowdegree must be computed so that it -// contains no explicit zeros; as done by LAGraph_Property_RowDegree. +// The G->AT and G->out_degree cached properties must be defined for this +// method. If G is undirected or G->A is known to have a symmetric structure, +// then G->A is used instead of G->AT, however. G->out_degree must be computed +// so that it contains no explicit zeros; as done by LAGraph_Cached_OutDegree. #define LG_FREE_WORK \ { \ @@ -69,7 +69,7 @@ int LAGr_PageRank LG_TRY (LAGraph_CheckGraph (G, msg)) ; GrB_Matrix AT ; if (G->kind == LAGraph_ADJACENCY_UNDIRECTED || - G->structure_is_symmetric == LAGraph_TRUE) + G->is_symmetric_structure == LAGraph_TRUE) { // A and A' have the same structure AT = G->A ; @@ -78,12 +78,11 @@ int LAGr_PageRank { // A and A' differ AT = G->AT ; - LG_ASSERT_MSG (AT != NULL, - LAGRAPH_PROPERTY_MISSING, "G->AT is required") ; + LG_ASSERT_MSG (AT != NULL, LAGRAPH_NOT_CACHED, "G->AT is required") ; } - GrB_Vector d_out = G->rowdegree ; + GrB_Vector d_out = G->out_degree ; LG_ASSERT_MSG (d_out != NULL, - LAGRAPH_PROPERTY_MISSING, "G->rowdegree is required") ; + LAGRAPH_NOT_CACHED, "G->out_degree is required") ; //-------------------------------------------------------------------------- // initializations @@ -104,8 +103,8 @@ int LAGr_PageRank GRB_TRY (GrB_assign (r, NULL, NULL, (float) (1.0 / n), GrB_ALL, n, NULL)) ; // find all sinks, where sink(i) = true if node i has d_out(i)=0, or with - // d_out(i) not present. LAGraph_Property_RowDegree computes d_out = - // G->rowdegree so that it has no explicit zeros, so a structural mask can + // d_out(i) not present. LAGraph_Cached_OutDegree computes d_out = + // G->out_degree so that it has no explicit zeros, so a structural mask can // be used here. GrB_Index nsinks, nvals ; GRB_TRY (GrB_Vector_nvals (&nvals, d_out)) ; @@ -141,7 +140,7 @@ int LAGr_PageRank // check for convergence LG_ASSERT_MSGF ((*iters) < itermax, LAGRAPH_CONVERGENCE_FAILURE, "pagerank failed to converge in %d iterations", itermax) ; - // determine the teleport property and handle any sinks + // determine teleport and handle any sinks float teleport = scaled_damping ; // teleport = (1 - damping) / n if (nsinks > 0) { diff --git a/src/algorithm/LAGr_PageRankGAP.c b/src/algorithm/LAGr_PageRankGAP.c index 29ba4dd2c8..0ac5c332dc 100644 --- a/src/algorithm/LAGr_PageRankGAP.c +++ b/src/algorithm/LAGr_PageRankGAP.c @@ -11,7 +11,7 @@ //------------------------------------------------------------------------------ -// This is an Advanced algorithm (G->AT and G->rowdegree are required). +// This is an Advanced algorithm (G->AT and G->out_degree are required). // PageRank for the GAP benchmark (only). Do not use in production. @@ -24,9 +24,9 @@ // handles sinks correctly. This method does not return a centrality metric // such that sum(centrality) is 1, if sinks are present. -// The G->AT and G->rowdegree properties must be defined for this method. If G -// is undirected or G->A is known to have a symmetric structure, then G->A is -// used instead of G->AT, however. +// The G->AT and G->out_degree cached properties must be defined for this +// method. If G is undirected or G->A is known to have a symmetric structure, +// then G->A is used instead of G->AT, however. #define LG_FREE_WORK \ { \ @@ -68,7 +68,7 @@ int LAGr_PageRankGAP LG_TRY (LAGraph_CheckGraph (G, msg)) ; GrB_Matrix AT ; if (G->kind == LAGraph_ADJACENCY_UNDIRECTED || - G->structure_is_symmetric == LAGraph_TRUE) + G->is_symmetric_structure == LAGraph_TRUE) { // A and A' have the same structure AT = G->A ; @@ -78,11 +78,11 @@ int LAGr_PageRankGAP // A and A' differ AT = G->AT ; LG_ASSERT_MSG (AT != NULL, - LAGRAPH_PROPERTY_MISSING, "G->AT is required") ; + LAGRAPH_NOT_CACHED, "G->AT is required") ; } - GrB_Vector d_out = G->rowdegree ; + GrB_Vector d_out = G->out_degree ; LG_ASSERT_MSG (d_out != NULL, - LAGRAPH_PROPERTY_MISSING, "G->rowdegree is required") ; + LAGRAPH_NOT_CACHED, "G->out_degree is required") ; //-------------------------------------------------------------------------- // initializations diff --git a/src/algorithm/LAGr_SingleSourceShortestPath.c b/src/algorithm/LAGr_SingleSourceShortestPath.c index 99687ad5de..b7b70eb9a8 100644 --- a/src/algorithm/LAGr_SingleSourceShortestPath.c +++ b/src/algorithm/LAGr_SingleSourceShortestPath.c @@ -253,8 +253,8 @@ int LAGr_SingleSourceShortestPath { double emin = -1 ; if (G->emin != NULL && - (G->emin_kind == LAGraph_EXACT || - G->emin_kind == LAGraph_BOUND)) + (G->emin_state == LAGraph_VALUE || + G->emin_state == LAGraph_BOUND)) { GRB_TRY (GrB_Scalar_extractElement_FP64 (&emin, G->emin)) ; } @@ -303,8 +303,8 @@ int LAGr_SingleSourceShortestPath // tmasked = t // FUTURE: this is costly, typically using Method 06s in SuiteSparse, // which is a very general-purpose one. Write a specialized kernel to - // exploit the given properties (reach and t are bitmap, tmasked starts - // empty), or fuse this assignment with the GrB_select below. + // exploit the fact that reach and t are bitmap and tmasked starts + // empty, or fuse this assignment with the GrB_select below. GRB_TRY (GrB_assign (tmasked, reach, NULL, t, GrB_ALL, n, NULL)) ; // tmasked = select (tmasked < (step+1)*Delta) GRB_TRY (GrB_select (tmasked, NULL, NULL, lt, tmasked, uBound, NULL)) ; diff --git a/src/algorithm/LAGr_TriangleCount.c b/src/algorithm/LAGr_TriangleCount.c index c00de0f5b4..11d2ed7776 100644 --- a/src/algorithm/LAGr_TriangleCount.c +++ b/src/algorithm/LAGr_TriangleCount.c @@ -13,8 +13,8 @@ // Count the number of triangles in a graph, -// This is an Advanced algorithm (G->ndiag, G->rowdegree, -// G->structure_is_symmetric are required). +// This is an Advanced algorithm (G->nself_edges, G->out_degree, +// G->is_symmetric_structure are required). // Given a symmetric graph A with no-self edges, LAGr_TriangleCount counts the // number of triangles in the graph. A triangle is a clique of size three, @@ -75,9 +75,7 @@ static int tricount_prep GRB_TRY (GrB_Matrix_new (L, GrB_BOOL, n, n)) ; GRB_TRY (GrB_select (*L, NULL, NULL, GrB_TRIL, A, (int64_t) (-1), NULL)) ; -// GRB_TRY(GrB_Matrix_setElement(*L, false, 0, 0)); - GRB_TRY (GrB_Matrix_wait (*L, GrB_MATERIALIZE)) ; - //GRB_TRY (GxB_Matrix_fprint (*L, "L", GxB_COMPLETE, stdout)) ; + GRB_TRY (GrB_Matrix_wait (*L, GrB_MATERIALIZE)) ; } if (U != NULL) @@ -85,9 +83,7 @@ static int tricount_prep // U = triu (A,1) GRB_TRY (GrB_Matrix_new (U, GrB_BOOL, n, n)) ; GRB_TRY (GrB_select (*U, NULL, NULL, GrB_TRIU, A, (int64_t) 1, NULL)) ; -// GRB_TRY(GrB_Matrix_setElement(*U, 0, 0, 0)); - GRB_TRY (GrB_Matrix_wait (*U, GrB_MATERIALIZE)) ; - //GRB_TRY (GxB_Matrix_fprint (*U, "U", GxB_COMPLETE, stdout)) ; + GRB_TRY (GrB_Matrix_wait (*U, GrB_MATERIALIZE)) ; } return (GrB_SUCCESS) ; } @@ -145,7 +141,7 @@ int LAGr_TriangleCount } LG_TRY (LAGraph_CheckGraph (G, msg)) ; LG_ASSERT (ntriangles != NULL, GrB_NULL_POINTER) ; - LG_ASSERT (G->ndiag == 0, LAGRAPH_NO_SELF_EDGES_ALLOWED) ; + LG_ASSERT (G->nself_edges == 0, LAGRAPH_NO_SELF_EDGES_ALLOWED) ; if (method == LAGraph_TriangleCount_Default) { @@ -155,7 +151,7 @@ int LAGr_TriangleCount LG_ASSERT_MSG ((G->kind == LAGraph_ADJACENCY_UNDIRECTED || (G->kind == LAGraph_ADJACENCY_DIRECTED && - G->structure_is_symmetric == LAGraph_TRUE)), + G->is_symmetric_structure == LAGraph_TRUE)), LAGRAPH_SYMMETRIC_STRUCTURE_REQUIRED, "G->A must be known to be symmetric") ; @@ -167,13 +163,13 @@ int LAGr_TriangleCount method == LAGraph_TriangleCount_SandiaDot2 ; // 6: sum (sum ((U * L') .* U)) GrB_Matrix A = G->A ; - GrB_Vector Degree = G->rowdegree ; + GrB_Vector Degree = G->out_degree ; bool auto_sort = (presort != NULL) && ((*presort) == LAGraph_TriangleCount_AutoSort) ; if (auto_sort && method_can_use_presort) { LG_ASSERT_MSG (Degree != NULL, - LAGRAPH_PROPERTY_MISSING, "G->rowdegree is required") ; + LAGRAPH_NOT_CACHED, "G->out_degree is required") ; } //-------------------------------------------------------------------------- @@ -183,7 +179,11 @@ int LAGr_TriangleCount GrB_Index n ; GRB_TRY (GrB_Matrix_nrows (&n, A)) ; GRB_TRY (GrB_Matrix_new (&C, GrB_INT64, n, n)) ; - GrB_Semiring semiring = GxB_PLUS_PAIR_INT64 ; // hack + #if LAGRAPH_SUITESPARSE + GrB_Semiring semiring = GxB_PLUS_PAIR_INT64 ; + #else + GrB_Semiring semiring = LAGraph_plus_one_int64 ; + #endif GrB_Monoid monoid = GrB_PLUS_MONOID_INT64 ; //-------------------------------------------------------------------------- @@ -298,8 +298,6 @@ int LAGr_TriangleCount // using the masked saxpy3 method LG_TRY (tricount_prep (&L, NULL, A, msg)) ; GRB_TRY (GrB_mxm (C, L, NULL, semiring, L, L, GrB_DESC_S)) ; - //GRB_TRY (GxB_Matrix_fprint (C, "my mat", GxB_COMPLETE, stdout)) ; - GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; break ; @@ -308,7 +306,6 @@ int LAGr_TriangleCount // using the masked saxpy3 method LG_TRY (tricount_prep (NULL, &U, A, msg)) ; GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, U, GrB_DESC_S)) ; - //GRB_TRY (GxB_Matrix_fprint (C, "my mat", GxB_COMPLETE, stdout)) ; GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; break ; @@ -321,7 +318,6 @@ int LAGr_TriangleCount // using the masked dot product LG_TRY (tricount_prep (&L, &U, A, msg)) ; GRB_TRY (GrB_mxm (C, L, NULL, semiring, L, U, GrB_DESC_ST1)) ; - //GRB_TRY (GxB_Matrix_fprint (C, "my mat", GxB_COMPLETE, stdout)) ; GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; break ; @@ -330,7 +326,6 @@ int LAGr_TriangleCount // using the masked dot product LG_TRY (tricount_prep (&L, &U, A, msg)) ; GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, L, GrB_DESC_ST1)) ; - //GRB_TRY (GxB_Matrix_fprint (C, "my mat", GxB_COMPLETE, stdout)) ; GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; break ; } @@ -339,7 +334,6 @@ int LAGr_TriangleCount // return result //-------------------------------------------------------------------------- - //GxB_print (C, 3) ; LG_FREE_ALL ; (*ntriangles) = (uint64_t) ntri ; return (GrB_SUCCESS) ; diff --git a/src/algorithm/LAGraph_TriangleCount.c b/src/algorithm/LAGraph_TriangleCount.c index 96ff31b2d3..ec873b0ba7 100644 --- a/src/algorithm/LAGraph_TriangleCount.c +++ b/src/algorithm/LAGraph_TriangleCount.c @@ -11,8 +11,8 @@ //------------------------------------------------------------------------------ -// This is a Basic algorithm (G->ndiag, G->rowdegree, G->structure_is_symmetric -// are computed, if not present). +// This is a Basic algorithm (G->nself_edges, G->out_degree, +// G->is_symmetric_structure are computed, if not present). #define LG_FREE_ALL ; @@ -22,7 +22,7 @@ //**************************************************************************** // Pick the default method with auto presort -// Compute G->ndiag, and G->rowdegree if needed. Determine if G->A is +// Compute G->nself_edges, and G->out_degree if needed. Determine if G->A is // symmetric, if not known. int LAGraph_TriangleCount @@ -30,15 +30,16 @@ int LAGraph_TriangleCount // output: uint64_t *ntriangles, // # of triangles // input/output: - LAGraph_Graph G, // G->ndiag, G->rowdegree, G->structure_is_symmetric - // are computed, if not already present + LAGraph_Graph G, // G->nself_edges, G->out_degree, + // G->is_symmetric_structure are computed, if not + // already present char *msg ) { - // find out if graph is symmetric, compute G->rowdegree, and G->ndiag - LG_TRY (LAGraph_Property_SymmetricStructure (G, msg)) ; - LG_TRY (LAGraph_Property_RowDegree (G, msg)) ; - LG_TRY (LAGraph_Property_NDiag (G, msg)) ; + // find out if graph is symmetric, compute G->out_degree, and G->nself_edges + LG_TRY (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; + LG_TRY (LAGraph_Cached_OutDegree (G, msg)) ; + LG_TRY (LAGraph_Cached_NSelfEdges (G, msg)) ; // default method and auto selection of sort int method = LAGraph_TriangleCount_Default ; diff --git a/src/algorithm/LG_BreadthFirstSearch_SSGrB.c b/src/algorithm/LG_BreadthFirstSearch_SSGrB.c index c2e59063ca..31805a07cf 100644 --- a/src/algorithm/LG_BreadthFirstSearch_SSGrB.c +++ b/src/algorithm/LG_BreadthFirstSearch_SSGrB.c @@ -11,7 +11,7 @@ //------------------------------------------------------------------------------ -// This is an Advanced algorithm (G->AT and G->rowdegree are required), +// This is an Advanced algorithm (G->AT and G->out_degree are required), // but it is not user-callable (see LAGr_BreadthFirstSearch instead). // References: @@ -80,7 +80,7 @@ int LG_BreadthFirstSearch_SSGrB } //-------------------------------------------------------------------------- - // get the problem size and properties + // get the problem size and cached properties //-------------------------------------------------------------------------- GrB_Matrix A = G->A ; @@ -92,10 +92,10 @@ int LG_BreadthFirstSearch_SSGrB GRB_TRY (GrB_Matrix_nvals (&nvals, A)) ; GrB_Matrix AT ; - GrB_Vector Degree = G->rowdegree ; + GrB_Vector Degree = G->out_degree ; if (G->kind == LAGraph_ADJACENCY_UNDIRECTED || (G->kind == LAGraph_ADJACENCY_DIRECTED && - G->structure_is_symmetric == LAGraph_TRUE)) + G->is_symmetric_structure == LAGraph_TRUE)) { // AT and A have the same structure and can be used in both directions AT = G->A ; @@ -105,14 +105,14 @@ int LG_BreadthFirstSearch_SSGrB // AT = A' is different from A AT = G->AT ; LG_ASSERT_MSG (AT != NULL, - LAGRAPH_PROPERTY_MISSING, "G->AT is required") ; + LAGRAPH_NOT_CACHED, "G->AT is required") ; } // FIXME: if AT is not present, do push-only? - // direction-optimization requires G->AT and G->rowdegree + // direction-optimization requires G->AT and G->out_degree LG_ASSERT_MSG (Degree != NULL, - LAGRAPH_PROPERTY_MISSING, "G->rowdegree is required") ; + LAGRAPH_NOT_CACHED, "G->out_degree is required") ; bool push_pull = true ; @@ -139,8 +139,8 @@ int LG_BreadthFirstSearch_SSGrB } else { - // only the level is needed, use the LAGraph_structural_bool semiring - semiring = LAGraph_structural_bool ; + // only the level is needed, use the LAGraph_any_one_bool semiring + semiring = LAGraph_any_one_bool ; // create a sparse boolean vector q, and set q(src) = true GRB_TRY (GrB_Vector_new (&q, GrB_BOOL, n)) ; diff --git a/src/algorithm/LG_BreadthFirstSearch_vanilla.c b/src/algorithm/LG_BreadthFirstSearch_vanilla.c index 27ccfc942d..09bb6ab8da 100644 --- a/src/algorithm/LG_BreadthFirstSearch_vanilla.c +++ b/src/algorithm/LG_BreadthFirstSearch_vanilla.c @@ -12,7 +12,7 @@ //------------------------------------------------------------------------------ -// This is a Basic algorithm (no extra G-> properties are required), +// This is a Basic algorithm (no extra cached properties are required), // but it is not user-callable (see LAGr_BreadthFirstSearch instead). #define LG_FREE_WORK \ @@ -62,7 +62,7 @@ int LG_BreadthFirstSearch_vanilla } //-------------------------------------------------------------------------- - // get the problem size and properties + // get the problem size //-------------------------------------------------------------------------- GrB_Matrix A = G->A ; @@ -96,7 +96,7 @@ int LG_BreadthFirstSearch_vanilla else { // only the level is needed - semiring = LAGraph_structural_bool ; + semiring = LAGraph_any_one_bool ; // create a sparse boolean vector frontier, and set frontier(src) = true GRB_TRY (GrB_Vector_new(&frontier, GrB_BOOL, n)) ; diff --git a/src/algorithm/LG_CC_Boruvka.c b/src/algorithm/LG_CC_Boruvka.c index 4dd0627950..a9c427d2a4 100644 --- a/src/algorithm/LG_CC_Boruvka.c +++ b/src/algorithm/LG_CC_Boruvka.c @@ -12,7 +12,7 @@ //------------------------------------------------------------------------------ -// This is an Advanced algorithm (G->structure_is_symmetric must be known), +// This is an Advanced algorithm (G->is_symmetric_structure must be known), // but it is not user-callable (see LAGr_ConnectedComponents instead). // Code is based on Boruvka's minimum spanning forest algorithm. @@ -123,7 +123,7 @@ int LG_CC_Boruvka LG_ASSERT_MSG ((G->kind == LAGraph_ADJACENCY_UNDIRECTED || (G->kind == LAGraph_ADJACENCY_DIRECTED && - G->structure_is_symmetric == LAGraph_TRUE)), + G->is_symmetric_structure == LAGraph_TRUE)), LAGRAPH_SYMMETRIC_STRUCTURE_REQUIRED, "G->A must be known to be symmetric") ; diff --git a/src/algorithm/LG_CC_FastSV6.c b/src/algorithm/LG_CC_FastSV6.c index 10b0c26707..69881a5487 100644 --- a/src/algorithm/LG_CC_FastSV6.c +++ b/src/algorithm/LG_CC_FastSV6.c @@ -12,7 +12,7 @@ //------------------------------------------------------------------------------ -// This is an Advanced algorithm (G->structure_is_symmetric must be known), +// This is an Advanced algorithm (G->is_symmetric_structure must be known), // but it is not user-callable (see LAGr_ConnectedComponents instead). // Code is based on the algorithm described in the following paper: @@ -28,7 +28,7 @@ // Modified by Tim Davis, Texas A&M University: revised Reduce_assign to use // purely GrB* and GxB* methods and the matrix C. Added warmup phase. Changed // to use GxB pack/unpack instead of GxB import/export. Converted to use the -// LAGraph_Graph object. Exploiting iso property for the temporary matrices +// LAGraph_Graph object. Exploiting iso status for the temporary matrices // C and T. // The input graph G must be undirected, or directed and with an adjacency @@ -229,7 +229,7 @@ int LG_CC_FastSV6 // SuiteSparse:GraphBLAS method, with GxB extensions LG_ASSERT_MSG ((G->kind == LAGraph_ADJACENCY_UNDIRECTED || (G->kind == LAGraph_ADJACENCY_DIRECTED && - G->structure_is_symmetric == LAGraph_TRUE)), + G->is_symmetric_structure == LAGraph_TRUE)), LAGRAPH_SYMMETRIC_STRUCTURE_REQUIRED, "G->A must be known to be symmetric") ; @@ -287,8 +287,9 @@ int LG_CC_FastSV6 // SuiteSparse:GraphBLAS method, with GxB extensions // [ todo: nthreads will not be needed once GxB_select with a GxB_RankUnaryOp // and a new GxB_extract are added to SuiteSparse:GraphBLAS. // determine # of threads to use - int nthreads ; - LG_TRY (LAGraph_GetNumThreads (&nthreads, NULL)) ; + int nthreads, nthreads_hi, nthreads_lo ; + LG_TRY (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + nthreads = nthreads_hi * nthreads_lo ; nthreads = LAGRAPH_MIN (nthreads, n / 16) ; nthreads = LAGRAPH_MAX (nthreads, 1) ; // ] @@ -530,7 +531,7 @@ int LG_CC_FastSV6 // SuiteSparse:GraphBLAS method, with GxB extensions // This method will not insert the new entries T(i,key) for rows i that have // had entries deleted. That can be done with GrB_assign, with an n-by-1 mask // M computed from the before-and-after row degrees of A and T: -// M = (parent != key) && (row_degree(T) < row_degree(A)) +// M = (parent != key) && (out_degree(T) < out_degree(A)) // J [0] = key. // GxB_Matrix_subassign_BOOL (T, M, NULL, true, GrB_ALL, n, J, 1, NULL) // or with diff --git a/src/benchmark/LAGraph_demo.h b/src/benchmark/LAGraph_demo.h index 4ceef12c3c..ad59edf614 100644 --- a/src/benchmark/LAGraph_demo.h +++ b/src/benchmark/LAGraph_demo.h @@ -945,7 +945,7 @@ static int readproblem // returns 0 if successful, -1 if failure if (remove_self_edges) { - LAGRAPH_TRY (LAGraph_DeleteDiag (*G, msg)) ; + LAGRAPH_TRY (LAGraph_DeleteSelfEdges (*G, msg)) ; } // LAGRAPH_TRY (LAGraph_DisplayGraph (*G, 2, stdout, msg)) ; @@ -1004,8 +1004,8 @@ static int readproblem // returns 0 if successful, -1 if failure if (!A_is_symmetric) { // compute G->AT and determine if A has a symmetric structure - LAGRAPH_TRY (LAGraph_Property_SymmetricStructure (*G, msg)) ; - if ((*G)->structure_is_symmetric && structural) + LAGRAPH_TRY (LAGraph_Cached_IsSymmetricStructure (*G, msg)) ; + if (((*G)->is_symmetric_structure == LAGraph_TRUE) && structural) { // if G->A has a symmetric structure, declare the graph undirected // and free G->AT since it isn't needed. @@ -1042,7 +1042,7 @@ static int readproblem // returns 0 if successful, -1 if failure GRB_TRY (GrB_Matrix_free (&((*G)->AT))) ; } (*G)->kind = LAGraph_ADJACENCY_UNDIRECTED ; - (*G)->structure_is_symmetric = true ; + (*G)->is_symmetric_structure = LAGraph_TRUE ; } } // LAGRAPH_TRY (LAGraph_DisplayGraph (*G, 2, stdout, msg)) ; @@ -1107,11 +1107,17 @@ static inline int demo_init (bool burble) mallopt (M_TOP_PAD, 16*1024*1024) ; // increase padding to speedup malloc #endif -// LAGRAPH_TRY (LAGraph_Init (NULL)) ; +#if 0 + // just use the CPU + LAGRAPH_TRY (LAGraph_Init (NULL)) ; +#else + // use the GPU // rmm_wrap_initialize (rmm_wrap_managed, INT32_MAX, INT64_MAX) ; rmm_wrap_initialize (rmm_wrap_managed, 256 * 1000000L, 256 * 100000000L) ; - LAGRAPH_TRY (LAGr_Init (rmm_wrap_malloc, rmm_wrap_calloc, rmm_wrap_realloc, rmm_wrap_free, NULL)) ; + LAGRAPH_TRY (LAGr_Init (GxB_NONBLOCKING_GPU, rmm_wrap_malloc, + rmm_wrap_calloc, rmm_wrap_realloc, rmm_wrap_free, NULL)) ; GxB_set (GxB_GPU_CONTROL, GxB_GPU_ALWAYS) ; +#endif #if LAGRAPH_SUITESPARSE printf ("include: %s v%d.%d.%d [%s]\n", diff --git a/src/benchmark/bc_demo.c b/src/benchmark/bc_demo.c index afa3f1d73d..b7f9274af1 100644 --- a/src/benchmark/bc_demo.c +++ b/src/benchmark/bc_demo.c @@ -70,8 +70,9 @@ int main (int argc, char **argv) int nt = NTHREAD_LIST ; int Nthreads [20] = { 0, THREAD_LIST } ; - int nthreads_max ; - LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_max, NULL)) ; + int nthreads_max, nthreads_hi, nthreads_lo ; + LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + nthreads_max = nthreads_hi * nthreads_lo ; if (Nthreads [1] == 0) { // create thread list automatically @@ -152,12 +153,12 @@ int main (int argc, char **argv) //---------------------------------------------------------------------- // back to default - LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads_max, msg)) ; + LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads_hi, nthreads_lo, msg)) ; for (int t = 1 ; t <= nt ; t++) { if (Nthreads [t] > nthreads_max) continue ; - LAGRAPH_TRY (LAGraph_SetNumThreads (Nthreads [t], msg)) ; + LAGRAPH_TRY (LAGraph_SetNumThreads (1, Nthreads [t], msg)) ; GrB_free (¢rality) ; double tic [2] ; diff --git a/src/benchmark/bfs_demo.c b/src/benchmark/bfs_demo.c index bcd83a24a1..93f9334677 100644 --- a/src/benchmark/bfs_demo.c +++ b/src/benchmark/bfs_demo.c @@ -54,8 +54,9 @@ int main (int argc, char **argv) int nt = NTHREAD_LIST ; int Nthreads [20] = { 0, THREAD_LIST } ; - int nthreads_max ; - LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_max, NULL)) ; + int nthreads_max, nthreads_hi, nthreads_lo ; + LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + nthreads_max = nthreads_hi * nthreads_lo ; printf ("nthreads_max: %d\n", nthreads_max) ; if (Nthreads [1] == 0) { @@ -88,11 +89,11 @@ int main (int argc, char **argv) LAGRAPH_TRY (readproblem (&G, &SourceNodes, false, false, true, NULL, false, argc, argv)) ; - // compute G->rowdegree - LAGRAPH_TRY (LAGraph_Property_RowDegree (G, msg)) ; + // compute G->out_degree + LAGRAPH_TRY (LAGraph_Cached_OutDegree (G, msg)) ; - // compute G->coldegree, just to test it (not needed for any tests) - LAGRAPH_TRY (LAGraph_Property_ColDegree (G, msg)) ; + // compute G->in_degree, just to test it (not needed for any tests) + LAGRAPH_TRY (LAGraph_Cached_InDegree (G, msg)) ; GrB_Index n ; GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; @@ -128,7 +129,7 @@ int main (int argc, char **argv) { int nthreads = Nthreads [tt] ; if (nthreads > nthreads_max) continue ; - LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads, msg)) ; + LAGRAPH_TRY (LAGraph_SetNumThreads (1, nthreads, msg)) ; tp [nthreads] = 0 ; tl [nthreads] = 0 ; @@ -285,7 +286,7 @@ int main (int argc, char **argv) } } // restore default - LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads_max, msg)) ; + LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads_hi, nthreads_lo, msg)) ; printf ("\n") ; //-------------------------------------------------------------------------- diff --git a/src/benchmark/cc_demo.c b/src/benchmark/cc_demo.c index afd73c0f2e..cde1a0ea45 100644 --- a/src/benchmark/cc_demo.c +++ b/src/benchmark/cc_demo.c @@ -75,8 +75,9 @@ int main (int argc, char **argv) int nt = NTHREAD_LIST ; int Nthreads [20] = { 0, THREAD_LIST } ; - int nthreads_max ; - LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_max, NULL)) ; + int nthreads_max, nthreads_hi, nthreads_lo ; + LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + nthreads_max = nthreads_hi * nthreads_lo ; if (Nthreads [1] == 0) { // create thread list automatically @@ -151,7 +152,7 @@ int main (int argc, char **argv) { int nthreads = Nthreads [trial] ; if (nthreads > nthreads_max) continue ; - LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads, NULL)) ; + LAGRAPH_TRY (LAGraph_SetNumThreads (1, nthreads, NULL)) ; double ttt = 0 ; int ntrials = NTRIALS ; for (int k = 0 ; k < ntrials ; k++) @@ -185,7 +186,7 @@ int main (int argc, char **argv) { int nthreads = Nthreads [trial] ; if (nthreads > nthreads_max) continue ; - LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads, NULL)) ; + LAGRAPH_TRY (LAGraph_SetNumThreads (1, nthreads, NULL)) ; double ttt = 0 ; int ntrials = NTRIALS ; for (int k = 0 ; k < ntrials ; k++) @@ -220,7 +221,7 @@ int main (int argc, char **argv) { int nthreads = Nthreads [trial] ; if (nthreads > nthreads_max) continue ; - LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads, NULL)) ; + LAGRAPH_TRY (LAGraph_SetNumThreads (1, nthreads, NULL)) ; double ttt = 0 ; int ntrials = NTRIALS ; for (int k = 0 ; k < ntrials ; k++) @@ -255,7 +256,7 @@ int main (int argc, char **argv) { int nthreads = Nthreads [trial] ; if (nthreads > nthreads_max) continue ; - LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads, NULL)) ; + LAGRAPH_TRY (LAGraph_SetNumThreads (1, nthreads, NULL)) ; double ttt = 0 ; int ntrials = 1 /* NTRIALS */ ; for (int k = 0 ; k < ntrials ; k++) @@ -290,7 +291,7 @@ int main (int argc, char **argv) { int nthreads = Nthreads [trial] ; if (nthreads > nthreads_max) continue ; - LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads, NULL)) ; + LAGRAPH_TRY (LAGraph_SetNumThreads (1, nthreads, NULL)) ; double ttt = 0 ; int ntrials = 1 /* NTRIALS */ ; for (int k = 0 ; k < ntrials ; k++) diff --git a/src/benchmark/gappagerank_demo.c b/src/benchmark/gappagerank_demo.c index 0366d0bb75..ba26287563 100644 --- a/src/benchmark/gappagerank_demo.c +++ b/src/benchmark/gappagerank_demo.c @@ -48,8 +48,9 @@ int main (int argc, char **argv) int nt = NTHREAD_LIST ; int Nthreads [20] = { 0, THREAD_LIST } ; - int nthreads_max ; - LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_max, NULL)) ; + int nthreads_max, nthreads_hi, nthreads_lo ; + LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + nthreads_max = nthreads_hi * nthreads_lo ; if (Nthreads [1] == 0) { // create thread list automatically @@ -82,12 +83,12 @@ int main (int argc, char **argv) GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; GRB_TRY (GrB_Matrix_nvals (&nvals, G->A)) ; - // determine the row degree property - LAGRAPH_TRY (LAGraph_Property_RowDegree (G, msg)) ; + // determine the cached out degree property + LAGRAPH_TRY (LAGraph_Cached_OutDegree (G, msg)) ; // check # of sinks: GrB_Index nsinks ; - GRB_TRY (GrB_Vector_nvals (&nvals, G->rowdegree)) ; + GRB_TRY (GrB_Vector_nvals (&nvals, G->out_degree)) ; nsinks = n - nvals ; printf ("nsinks: %" PRIu64 "\n", nsinks) ; @@ -108,7 +109,7 @@ int main (int argc, char **argv) { int nthreads = Nthreads [kk] ; if (nthreads > nthreads_max) continue ; - LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads, msg)) ; + LAGRAPH_TRY (LAGraph_SetNumThreads (1, nthreads, msg)) ; printf ("\n--------------------------- nthreads: %2d\n", nthreads) ; double total_time = 0 ; @@ -148,7 +149,7 @@ int main (int argc, char **argv) { int nthreads = Nthreads [kk] ; if (nthreads > nthreads_max) continue ; - LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads, msg)) ; + LAGRAPH_TRY (LAGraph_SetNumThreads (1, nthreads, msg)) ; printf ("\n--------------------------- nthreads: %2d\n", nthreads) ; double total_time = 0 ; diff --git a/src/benchmark/ss2_demo.c b/src/benchmark/ss2_demo.c index 4283c16c1b..d95637aabf 100644 --- a/src/benchmark/ss2_demo.c +++ b/src/benchmark/ss2_demo.c @@ -56,8 +56,9 @@ int main (int argc, char **argv) int nt = NTHREAD_LIST ; int Nthreads [20] = { 0, THREAD_LIST } ; - int nthreads_max ; - LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_max, NULL)) ; + int nthreads_max, nthreads_hi, nthreads_lo ; + LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + nthreads_max = nthreads_hi * nthreads_lo ; if (Nthreads [1] == 0) { // create thread list automatically @@ -111,7 +112,7 @@ int main (int argc, char **argv) GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; GRB_TRY (GrB_Matrix_nvals (&nvals, G->A)) ; - LAGRAPH_TRY (LAGraph_Property_EMin (G, msg)) ; + LAGRAPH_TRY (LAGraph_Cached_EMin (G, msg)) ; //-------------------------------------------------------------------------- // get delta @@ -152,7 +153,7 @@ int main (int argc, char **argv) { int nthreads = Nthreads [tt] ; if (nthreads > nthreads_max) continue ; - LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads, msg)) ; + LAGRAPH_TRY (LAGraph_SetNumThreads (1, nthreads, msg)) ; double total_time = 0 ; for (int trial = 0 ; trial < ntrials ; trial++) diff --git a/src/benchmark/sssp_demo.c b/src/benchmark/sssp_demo.c index 27cbeb7cd6..ea81cc9d1b 100644 --- a/src/benchmark/sssp_demo.c +++ b/src/benchmark/sssp_demo.c @@ -52,8 +52,9 @@ int main (int argc, char **argv) int nt = NTHREAD_LIST ; int Nthreads [20] = { 0, THREAD_LIST } ; - int nthreads_max ; - LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_max, NULL)) ; + int nthreads_max, nthreads_hi, nthreads_lo ; + LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + nthreads_max = nthreads_hi * nthreads_lo ; if (Nthreads [1] == 0) { // create thread list automatically @@ -83,7 +84,7 @@ int main (int argc, char **argv) GrB_Index n, nvals ; GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; GRB_TRY (GrB_Matrix_nvals (&nvals, G->A)) ; - LAGRAPH_TRY (LAGraph_Property_EMin (G, msg)) ; + LAGRAPH_TRY (LAGraph_Cached_EMin (G, msg)) ; //-------------------------------------------------------------------------- // get delta @@ -120,7 +121,7 @@ int main (int argc, char **argv) { int nthreads = Nthreads [tt] ; if (nthreads > nthreads_max) continue ; - LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads, msg)) ; + LAGRAPH_TRY (LAGraph_SetNumThreads (1, nthreads, msg)) ; double total_time = 0 ; for (int trial = 0 ; trial < ntrials ; trial++) diff --git a/src/benchmark/tc_demo.c b/src/benchmark/tc_demo.c index 296760d6d2..f864448c28 100644 --- a/src/benchmark/tc_demo.c +++ b/src/benchmark/tc_demo.c @@ -24,12 +24,12 @@ #include "LAGraph_demo.h" -//#define NTHREAD_LIST 1 +#define NTHREAD_LIST 1 // #define NTHREAD_LIST 2 -//#define THREAD_LIST 0 +#define THREAD_LIST 0 - #define NTHREAD_LIST 7 - #define THREAD_LIST 64, 32, 24, 12, 8, 4, 0 +// #define NTHREAD_LIST 6 +// #define THREAD_LIST 64, 32, 24, 12, 8, 4 #define LG_FREE_ALL \ { \ @@ -83,14 +83,15 @@ int main (int argc, char **argv) bool burble = false ; demo_init (burble) ; - int ntrials = 5 ; + int ntrials = 3 ; // ntrials = 1 ; // HACK printf ("# of trials: %d\n", ntrials) ; int nt = NTHREAD_LIST ; int Nthreads [20] = { 0, THREAD_LIST } ; - int nthreads_max ; - LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_max, NULL)) ; + int nthreads_max, nthreads_hi, nthreads_lo ; + LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + nthreads_max = nthreads_hi * nthreads_lo ; if (Nthreads [1] == 0) { // create thread list automatically @@ -119,51 +120,21 @@ int main (int argc, char **argv) true, true, true, NULL, false, argc, argv)) ; LAGRAPH_TRY (LAGraph_DisplayGraph (G, LAGraph_SHORT, stdout, msg)) ; - // determine the row degree property - LAGRAPH_TRY (LAGraph_Property_RowDegree (G, msg)) ; + // determine the cached out degree property + LAGRAPH_TRY (LAGraph_Cached_OutDegree (G, msg)) ; GrB_Index n, nvals ; GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; GRB_TRY (GrB_Matrix_nvals (&nvals, G->A)) ; - // HACK: make sure G->A is non-iso - - // create an iterator - GxB_Iterator iterator ; - GxB_Iterator_new (&iterator) ; - // attach it to the matrix A - GrB_Info info = GxB_Matrix_Iterator_attach (iterator, G->A, NULL) ; - if (info < 0) { abort ( ) ; } - // seek to the first entry - info = GxB_Matrix_Iterator_seek (iterator, 1) ; - printf ("info %d\n", info) ; - while (info != GxB_EXHAUSTED) - { - // get the entry A(i,j) - GrB_Index i, j ; - GxB_Matrix_Iterator_getIndex (iterator, &i, &j) ; - // set it to 0 - printf ("setting A(%d,%d) = 0\n", (int) i, (int) j) ; - GRB_TRY (GrB_Matrix_setElement (G->A, 0, i, j)) ; - break ; - } - GrB_free (&iterator) ; - - GxB_print (G->A, 2) ; -// GRB_TRY (GrB_Matrix_setElement (G->A, 0, 2, 2)) ; -// GxB_print (G->A, 3) ; - GrB_wait (G->A, GrB_MATERIALIZE) ; -// GxB_print (G->A, 3) ; -// printf ("HERE ============================\n") ; - //-------------------------------------------------------------------------- // triangle counting //-------------------------------------------------------------------------- GrB_Index ntriangles, ntsimple = 0 ; - double tic [2], ttot ; + double tic [2] ; -#if 1 +#if 0 // check # of triangles LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; LAGRAPH_TRY (LG_check_tri (&ntsimple, G, NULL)) ; @@ -179,47 +150,22 @@ int main (int argc, char **argv) int presort = LAGraph_TriangleCount_AutoSort ; // = 2 (auto selection) print_method (stdout, 6, presort) ; - // warmup method: without the GPU + // warmup method: // LAGraph_TriangleCount_SandiaDot2 = 6, // sum (sum ((U * L') .* U)) - GxB_set (GxB_GPU_CONTROL, GxB_GPU_NEVER) ; LAGRAPH_TRY (LAGr_TriangleCount (&ntriangles, G, LAGraph_TriangleCount_SandiaDot2, &presort, msg) ); - printf ("# of triangles: %" PRIu64 " (CPU)\n", ntriangles) ; + printf ("# of triangles: %" PRIu64 "\n", ntriangles) ; print_method (stdout, 6, presort) ; + double ttot ; LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; printf ("nthreads: %3d time: %12.6f rate: %6.2f (SandiaDot2, one trial)\n", nthreads_max, ttot, 1e-6 * nvals / ttot) ; -#if 1 +#if 0 if (ntriangles != ntsimple) { printf ("wrong # triangles: %g %g\n", (double) ntriangles, (double) ntsimple) ; - fflush (stdout) ; - fflush (stderr) ; - abort ( ) ; - } -#endif - - // warmup method: with the GPU - // LAGraph_TriangleCount_SandiaDot2 = 6, // sum (sum ((U * L') .* U)) - GrB_Index ntriangles_gpu ; - GxB_set (GxB_GPU_CONTROL, GxB_GPU_ALWAYS) ; - LAGRAPH_TRY (LAGr_TriangleCount (&ntriangles_gpu, G, - LAGraph_TriangleCount_SandiaDot2, &presort, msg) ); - printf ("# of triangles: %" PRIu64 " (GPU)\n", ntriangles_gpu) ; - print_method (stdout, 6, presort) ; - LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; - printf ("nthreads: %3d time: %12.6f rate: %6.2f (SandiaDot2, warmup GPU)\n", - nthreads_max, ttot, 1e-6 * nvals / ttot) ; - -#if 1 - if (ntriangles_gpu != ntsimple) - { - printf ("wrong # triangles: %g %g\n", (double) ntriangles_gpu, - (double) ntsimple) ; - fflush (stdout) ; - fflush (stderr) ; abort ( ) ; } #endif @@ -261,18 +207,7 @@ int main (int argc, char **argv) { int nthreads = Nthreads [t] ; if (nthreads > nthreads_max) continue ; - if (nthreads != 0) // Use GPU - { - GxB_Global_Option_set( GxB_GLOBAL_GPU_CONTROL, GxB_GPU_NEVER); - printf(" CPU ONLY using %d threads", nthreads); - } - else - { - GxB_Global_Option_set( GxB_GLOBAL_GPU_CONTROL, GxB_GPU_ALWAYS); - printf(" GPU ONLY using %d threads", nthreads); - } - - LAGRAPH_TRY (LAGraph_SetNumThreads (nthreads, msg)) ; + LAGRAPH_TRY (LAGraph_SetNumThreads (1, nthreads, msg)) ; GrB_Index nt2 ; double ttot = 0, ttrial [100] ; for (int trial = 0 ; trial < ntrials ; trial++) @@ -294,16 +229,12 @@ int main (int argc, char **argv) printf ("nthreads: %3d time: %12.6f rate: %6.2f", nthreads, ttot, 1e-6 * nvals / ttot) ; printf (" # of triangles: %" PRId64 " presort: %d\n", - nt2, presort) ; - #if 1 + ntriangles, presort) ; if (nt2 != ntriangles) { printf ("Test failure!\n") ; - fflush (stdout) ; - fflush (stderr) ; abort ( ) ; } - #endif fprintf (stderr, "Avg: TC method%d.%d %3d: %10.3f sec: %s\n", method, sorting, nthreads, ttot, matrix_name) ; @@ -324,8 +255,6 @@ int main (int argc, char **argv) nthreads_best, t_best, 1e-6 * nvals / t_best) ; LG_FREE_ALL ; LAGRAPH_TRY (LAGraph_Finalize (msg)) ; - // FIXME: - rmm_wrap_finalize ( ) ; return (GrB_SUCCESS) ; } diff --git a/src/benchmark/tc_gpu_demo.c b/src/benchmark/tc_gpu_demo.c new file mode 100644 index 0000000000..937cdfbdda --- /dev/null +++ b/src/benchmark/tc_gpu_demo.c @@ -0,0 +1,332 @@ +//------------------------------------------------------------------------------ +// LAGraph/src/benchmark/tc_demo.c: benchmark for LAGr_TriangleCount +//------------------------------------------------------------------------------ + +// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause +// See additional acknowledgments in the LICENSE file, +// or contact permission@sei.cmu.edu for the full terms. + +// Contributed by Timothy A. Davis, Texas A&M University + +//------------------------------------------------------------------------------ + +// Usage: test_tc < matrixmarketfile.mtx +// test_tc matrixmarketfile.mtx +// test_tc matrixmarketfile.grb + +// Known triangle counts: +// kron: 106873365648 +// urand: 5378 +// twitter: 34824916864 +// web: 84907041475 +// road: 438804 + +#include "LAGraph_demo.h" + +//#define NTHREAD_LIST 1 +// #define NTHREAD_LIST 2 +//#define THREAD_LIST 0 + + #define NTHREAD_LIST 7 + #define THREAD_LIST 64, 32, 24, 12, 8, 4, 0 + +#define LG_FREE_ALL \ +{ \ + LAGraph_Delete (&G, NULL) ; \ + GrB_free (&A) ; \ +} + +char t [256] ; + +char *method_name (int method, int sorting) +{ + char *s ; + switch (method) + { + case LAGraph_TriangleCount_Default: s = "default (SandiaDot) " ; break ; + case LAGraph_TriangleCount_Burkhardt: s = "Burkhardt: sum ((A^2) .* A) / 6" ; break ; + case LAGraph_TriangleCount_Cohen: s = "Cohen: sum ((L*U) .* A) / 2" ; break ; + case LAGraph_TriangleCount_Sandia: s = "Sandia: sum ((L*L) .* L) " ; break ; + case LAGraph_TriangleCount_Sandia2: s = "Sandia2: sum ((U*U) .* U) " ; break ; + case LAGraph_TriangleCount_SandiaDot: s = "SandiaDot: sum ((L*U') .* L) " ; break ; + case LAGraph_TriangleCount_SandiaDot2: s = "SandiaDot2: sum ((U*L') .* U) " ; break ; + default: abort ( ) ; + } + + if (sorting == LAGraph_TriangleCount_Descending) sprintf (t, "%s sort: descending degree", s) ; + else if (sorting == LAGraph_TriangleCount_Ascending) sprintf (t, "%s ascending degree", s) ; + else if (sorting == LAGraph_TriangleCount_AutoSort) sprintf (t, "%s auto-sort", s) ; + else sprintf (t, "%s sort: none", s) ; + return (t) ; +} + + +void print_method (FILE *f, int method, int sorting) +{ + fprintf (f, "%s\n", method_name (method, sorting)) ; +} + +int main (int argc, char **argv) +{ + + //-------------------------------------------------------------------------- + // initialize LAGraph and GraphBLAS + //-------------------------------------------------------------------------- + + char msg [LAGRAPH_MSG_LEN] ; + + GrB_Matrix A = NULL ; + LAGraph_Graph G = NULL ; + + // start GraphBLAS and LAGraph + bool burble = false ; + demo_init (burble) ; + + int ntrials = 5 ; + // ntrials = 1 ; // HACK + printf ("# of trials: %d\n", ntrials) ; + + int nt = NTHREAD_LIST ; + int Nthreads [20] = { 0, THREAD_LIST } ; + int nthreads_max, nthreads_hi, nthreads_lo ; + LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + nthreads_max = nthreads_hi * nthreads_lo ; + if (Nthreads [1] == 0) + { + // create thread list automatically + Nthreads [1] = nthreads_max ; + for (int t = 2 ; t <= nt ; t++) + { + Nthreads [t] = Nthreads [t-1] / 2 ; + if (Nthreads [t] == 0) nt = t-1 ; + } + } + printf ("threads to test: ") ; + for (int t = 1 ; t <= nt ; t++) + { + int nthreads = Nthreads [t] ; + if (nthreads > nthreads_max) continue ; + printf (" %d", nthreads) ; + } + printf ("\n") ; + + //-------------------------------------------------------------------------- + // read in the graph + //-------------------------------------------------------------------------- + + char *matrix_name = (argc > 1) ? argv [1] : "stdin" ; + LAGRAPH_TRY (readproblem (&G, NULL, + true, true, true, NULL, false, argc, argv)) ; + LAGRAPH_TRY (LAGraph_DisplayGraph (G, LAGraph_SHORT, stdout, msg)) ; + + // determine the cached out degree property + LAGRAPH_TRY (LAGraph_Cached_OutDegree (G, msg)) ; + + GrB_Index n, nvals ; + GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; + GRB_TRY (GrB_Matrix_nvals (&nvals, G->A)) ; + + // HACK: make sure G->A is non-iso + + // create an iterator + GxB_Iterator iterator ; + GxB_Iterator_new (&iterator) ; + // attach it to the matrix A + GrB_Info info = GxB_Matrix_Iterator_attach (iterator, G->A, NULL) ; + if (info < 0) { abort ( ) ; } + // seek to the first entry + info = GxB_Matrix_Iterator_seek (iterator, 1) ; + printf ("info %d\n", info) ; + while (info != GxB_EXHAUSTED) + { + // get the entry A(i,j) + GrB_Index i, j ; + GxB_Matrix_Iterator_getIndex (iterator, &i, &j) ; + // set it to 0 + printf ("setting A(%d,%d) = 0\n", (int) i, (int) j) ; + GRB_TRY (GrB_Matrix_setElement (G->A, 0, i, j)) ; + break ; + } + GrB_free (&iterator) ; + + GxB_print (G->A, 2) ; +// GRB_TRY (GrB_Matrix_setElement (G->A, 0, 2, 2)) ; +// GxB_print (G->A, 3) ; + GrB_wait (G->A, GrB_MATERIALIZE) ; +// GxB_print (G->A, 3) ; +// printf ("HERE ============================\n") ; + + //-------------------------------------------------------------------------- + // triangle counting + //-------------------------------------------------------------------------- + + GrB_Index ntriangles, ntsimple = 0 ; + double tic [2], ttot ; + +#if 1 + // check # of triangles + LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; + LAGRAPH_TRY (LG_check_tri (&ntsimple, G, NULL)) ; + double tsimple ; + LAGRAPH_TRY (LAGraph_Toc (&tsimple, tic, NULL)) ; + printf ("# of triangles: %" PRId64 " slow time: %g sec\n", + ntsimple, tsimple) ; +#endif + + // warmup for more accurate timing, and also print # of triangles + LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; + printf ("\nwarmup method: ") ; + int presort = LAGraph_TriangleCount_AutoSort ; // = 2 (auto selection) + print_method (stdout, 6, presort) ; + + // warmup method: without the GPU + // LAGraph_TriangleCount_SandiaDot2 = 6, // sum (sum ((U * L') .* U)) + GxB_set (GxB_GPU_CONTROL, GxB_GPU_NEVER) ; + LAGRAPH_TRY (LAGr_TriangleCount (&ntriangles, G, + LAGraph_TriangleCount_SandiaDot2, &presort, msg) ); + printf ("# of triangles: %" PRIu64 " (CPU)\n", ntriangles) ; + print_method (stdout, 6, presort) ; + LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; + printf ("nthreads: %3d time: %12.6f rate: %6.2f (SandiaDot2, one trial)\n", + nthreads_max, ttot, 1e-6 * nvals / ttot) ; + +#if 1 + if (ntriangles != ntsimple) + { + printf ("wrong # triangles: %g %g\n", (double) ntriangles, + (double) ntsimple) ; + fflush (stdout) ; + fflush (stderr) ; + abort ( ) ; + } +#endif + + // warmup method: with the GPU + // LAGraph_TriangleCount_SandiaDot2 = 6, // sum (sum ((U * L') .* U)) + GrB_Index ntriangles_gpu ; + GxB_set (GxB_GPU_CONTROL, GxB_GPU_ALWAYS) ; + LAGRAPH_TRY (LAGr_TriangleCount (&ntriangles_gpu, G, + LAGraph_TriangleCount_SandiaDot2, &presort, msg) ); + printf ("# of triangles: %" PRIu64 " (GPU)\n", ntriangles_gpu) ; + print_method (stdout, 6, presort) ; + LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; + printf ("nthreads: %3d time: %12.6f rate: %6.2f (SandiaDot2, warmup GPU)\n", + nthreads_max, ttot, 1e-6 * nvals / ttot) ; + +#if 1 + if (ntriangles_gpu != ntsimple) + { + printf ("wrong # triangles: %g %g\n", (double) ntriangles_gpu, + (double) ntsimple) ; + fflush (stdout) ; + fflush (stderr) ; + abort ( ) ; + } +#endif + + double t_best = INFINITY ; + int method_best = -1 ; + int nthreads_best = -1 ; + int sorting_best = 0 ; + + // kron: input graph: nodes: 134217726 edges: 4223264644 + // fails on methods 3 and 4. + + // just try methods 5 and 6 + // for (int method = 5 ; method <= 6 ; method++) + + // try all methods 3 to 5 + for (int method = 3 ; method <= 5 ; method++) + { + // for (int sorting = -1 ; sorting <= 2 ; sorting++) + + int sorting = LAGraph_TriangleCount_AutoSort ; // just use auto-sort + { + printf ("\nMethod: ") ; + int presort ; + print_method (stdout, method, sorting) ; + if (n == 134217726 && method < 5) + { + printf ("kron fails on method %d; skipped\n", method) ; + continue ; + } + if (n != 134217728 && method < 5) + { + printf ("all but urand is slow with method %d: skipped\n", + method) ; + continue ; + } + + for (int t = 1 ; t <= nt ; t++) + { + int nthreads = Nthreads [t] ; + if (nthreads > nthreads_max) continue ; + if (nthreads != 0) // Use GPU + { + GxB_Global_Option_set( GxB_GLOBAL_GPU_CONTROL, GxB_GPU_NEVER); + printf(" CPU ONLY using %d threads", nthreads); + } + else + { + GxB_Global_Option_set( GxB_GLOBAL_GPU_CONTROL, GxB_GPU_ALWAYS); + printf(" GPU ONLY using %d threads", nthreads); + } + + LAGRAPH_TRY (LAGraph_SetNumThreads (1, nthreads, msg)) ; + GrB_Index nt2 ; + double ttot = 0, ttrial [100] ; + for (int trial = 0 ; trial < ntrials ; trial++) + { + LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; + presort = sorting ; + + LAGRAPH_TRY( + LAGr_TriangleCount (&nt2, G, method, + &presort, msg) ); + + LAGRAPH_TRY (LAGraph_Toc (&ttrial [trial], tic, NULL)) ; + ttot += ttrial [trial] ; + printf ("trial %2d: %12.6f sec rate %6.2f # triangles: " + "%g\n", trial, ttrial [trial], + 1e-6 * nvals / ttrial [trial], (double) nt2) ; + } + ttot = ttot / ntrials ; + printf ("nthreads: %3d time: %12.6f rate: %6.2f", nthreads, + ttot, 1e-6 * nvals / ttot) ; + printf (" # of triangles: %" PRId64 " presort: %d\n", + nt2, presort) ; + #if 1 + if (nt2 != ntriangles) + { + printf ("Test failure!\n") ; + fflush (stdout) ; + fflush (stderr) ; + abort ( ) ; + } + #endif + fprintf (stderr, "Avg: TC method%d.%d %3d: %10.3f sec: %s\n", + method, sorting, nthreads, ttot, matrix_name) ; + + if (ttot < t_best) + { + t_best = ttot ; + method_best = method ; + nthreads_best = nthreads ; + sorting_best = sorting ; + } + } + } + } + + printf ("\nBest method: ") ; + print_method (stdout, method_best, sorting_best) ; + printf ("nthreads: %3d time: %12.6f rate: %6.2f\n", + nthreads_best, t_best, 1e-6 * nvals / t_best) ; + LG_FREE_ALL ; + LAGRAPH_TRY (LAGraph_Finalize (msg)) ; + // FIXME: + rmm_wrap_finalize ( ) ; + return (GrB_SUCCESS) ; +} + diff --git a/src/test/LG_brutal_setup.c b/src/test/LG_brutal_setup.c index 69d9541f6e..e7532eb72e 100644 --- a/src/test/LG_brutal_setup.c +++ b/src/test/LG_brutal_setup.c @@ -18,7 +18,8 @@ int LG_brutal_setup (char *msg) { LG_brutal = -1 ; // disable brutal testing for now LG_nmalloc = 0 ; // assuming nothing is malloc'd - int result = LAGr_Init (LG_brutal_malloc, LG_brutal_calloc, + int result = LAGr_Init (GrB_NONBLOCKING, + LG_brutal_malloc, LG_brutal_calloc, LG_brutal_realloc, LG_brutal_free, msg) ; if (result != 0) return (result) ; #if LAGRAPH_SUITESPARSE diff --git a/src/test/LG_check_cc.c b/src/test/LG_check_cc.c index 56fb15f641..4e85875a27 100644 --- a/src/test/LG_check_cc.c +++ b/src/test/LG_check_cc.c @@ -73,7 +73,7 @@ int LG_check_cc LG_ASSERT_MSG ((G->kind == LAGraph_ADJACENCY_UNDIRECTED || (G->kind == LAGraph_ADJACENCY_DIRECTED && - G->structure_is_symmetric == LAGraph_TRUE)), + G->is_symmetric_structure == LAGraph_TRUE)), LAGRAPH_SYMMETRIC_STRUCTURE_REQUIRED, "G->A must be known to be symmetric") ; diff --git a/src/test/LG_check_tri.c b/src/test/LG_check_tri.c index 7b61689ed7..45ca4b8362 100644 --- a/src/test/LG_check_tri.c +++ b/src/test/LG_check_tri.c @@ -56,10 +56,10 @@ int LG_check_tri // -1 if out of memory, 0 if successful GrB_Index Ap_size, Aj_size, Ax_size, n, ncols, Ap_len, Aj_len, Ax_len ; LG_ASSERT (ntri != NULL, GrB_NULL_POINTER) ; LG_TRY (LAGraph_CheckGraph (G, msg)) ; - LG_ASSERT (G->ndiag == 0, LAGRAPH_NO_SELF_EDGES_ALLOWED) ; + LG_ASSERT (G->nself_edges == 0, LAGRAPH_NO_SELF_EDGES_ALLOWED) ; LG_ASSERT_MSG ((G->kind == LAGraph_ADJACENCY_UNDIRECTED || (G->kind == LAGraph_ADJACENCY_DIRECTED && - G->structure_is_symmetric == LAGraph_TRUE)), + G->is_symmetric_structure == LAGraph_TRUE)), LAGRAPH_SYMMETRIC_STRUCTURE_REQUIRED, "G->A must be known to be symmetric") ; GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; diff --git a/src/test/test_Betweenness.c b/src/test/test_Betweenness.c index 110d3f937b..61439ed86e 100644 --- a/src/test/test_Betweenness.c +++ b/src/test/test_Betweenness.c @@ -254,7 +254,7 @@ void test_bc (void) OK (fclose (f)) ; OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_DIRECTED, msg)) ; TEST_CHECK (A == NULL) ; // A has been moved into G->A - OK (LAGraph_Property_AT (G, msg)) ; + OK (LAGraph_Cached_AT (G, msg)) ; // compute its betweenness centrality OK (LAGr_Betweenness (¢rality, G, west0067_sources, 4, msg)) ; diff --git a/src/test/test_BreadthFirstSearch.c b/src/test/test_BreadthFirstSearch.c index 3d893d6606..bf881259ee 100644 --- a/src/test/test_BreadthFirstSearch.c +++ b/src/test/test_BreadthFirstSearch.c @@ -292,7 +292,7 @@ void test_BreadthFirstSearch_parent(void) GrB_Vector parent = NULL; GrB_Vector parent_do = NULL; - OK (LAGraph_Property_RowDegree (G, msg)) ; + OK (LAGraph_Cached_OutDegree (G, msg)) ; retval = LAGr_BreadthFirstSearch(NULL, &parent, G, 30, msg); TEST_CHECK(retval == 0); @@ -358,7 +358,7 @@ void test_BreadthFirstSearch_level(void) GrB_Vector level = NULL; GrB_Vector level_do = NULL; - OK (LAGraph_Property_RowDegree (G, msg)) ; + OK (LAGraph_Cached_OutDegree (G, msg)) ; retval = LAGr_BreadthFirstSearch(&level, NULL, G, 30, msg); TEST_CHECK(retval == 0); @@ -412,7 +412,7 @@ void test_BreadthFirstSearch_both(void) setup(); int retval; - OK (LAGraph_Property_RowDegree (G, msg)) ; + OK (LAGraph_Cached_OutDegree (G, msg)) ; GrB_Vector parent = NULL; GrB_Vector level = NULL; retval = LAGr_BreadthFirstSearch(&level, &parent, G, 30, msg); @@ -481,14 +481,19 @@ void test_BreadthFirstSearch_many(void) OK (LAGraph_New (&G, &A, kind, msg)) ; TEST_CHECK (A == NULL) ; // A has been moved into G->A - // create its properties - OK (LAGraph_Property_AT (G, msg)) ; + // create its cached properties + int ok_result = (kind == LAGraph_ADJACENCY_UNDIRECTED) ? + LAGRAPH_CACHE_NOT_NEEDED : GrB_SUCCESS ; + int result = LAGraph_Cached_AT (G, msg) ; + TEST_CHECK (result == ok_result) ; + OK (LAGraph_CheckGraph (G, msg)) ; - OK (LAGraph_Property_RowDegree (G, msg)) ; + OK (LAGraph_Cached_OutDegree (G, msg)) ; OK (LAGraph_CheckGraph (G, msg)) ; - OK (LAGraph_Property_ColDegree (G, msg)) ; + result = LAGraph_Cached_InDegree (G, msg) ; + TEST_CHECK (result == ok_result) ; OK (LAGraph_CheckGraph (G, msg)) ; GrB_Index n = 0 ; @@ -592,10 +597,15 @@ void test_bfs_brutal (void) continue ; } - // create its properties - OK (LAGraph_Property_AT (G, msg)) ; - OK (LAGraph_Property_RowDegree (G, msg)) ; - OK (LAGraph_Property_ColDegree (G, msg)) ; + // create its cached properties + int ok_result = (kind == LAGraph_ADJACENCY_UNDIRECTED) ? + LAGRAPH_CACHE_NOT_NEEDED : GrB_SUCCESS ; + int result = LAGraph_Cached_AT (G, msg) ; + TEST_CHECK (result == ok_result) ; + + OK (LAGraph_Cached_OutDegree (G, msg)) ; + result = LAGraph_Cached_InDegree (G, msg) ; + TEST_CHECK (result == ok_result) ; // run the BFS int64_t step = (n > 100) ? (3*n/4) : ((n/4) + 1) ; diff --git a/src/test/test_Property_AT.c b/src/test/test_Cached_AT.c similarity index 88% rename from src/test/test_Property_AT.c rename to src/test/test_Cached_AT.c index 8dcf66fd8a..6f91c9ea25 100644 --- a/src/test/test_Property_AT.c +++ b/src/test/test_Cached_AT.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// LAGraph/src/test/test_Property_AT.c: test LAGraph_Property_AT +// LAGraph/src/test/test_Cached_AT.c: test LAGraph_Cached_AT //------------------------------------------------------------------------------ // LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. @@ -44,7 +44,7 @@ void teardown (void) } //------------------------------------------------------------------------------ -// test_Property_AT: test LAGraph_Property_AT +// test_Cached_AT: test LAGraph_Cached_AT //------------------------------------------------------------------------------ typedef struct @@ -63,10 +63,10 @@ const matrix_info files [ ] = } ; //----------------------------------------------------------------------------- -// test_Property_AT +// test_Cached_AT //----------------------------------------------------------------------------- -void test_Property_AT (void) +void test_Cached_AT (void) { setup ( ) ; @@ -89,11 +89,15 @@ void test_Property_AT (void) OK (LAGraph_New (&G, &A, kind, msg)) ; TEST_CHECK (A == NULL) ; - // create the G->AT property - OK (LAGraph_Property_AT (G, msg)) ; + // create the G->AT cached property + int ok_result = (kind == LAGraph_ADJACENCY_UNDIRECTED) ? + LAGRAPH_CACHE_NOT_NEEDED : GrB_SUCCESS ; + int result = LAGraph_Cached_AT (G, msg) ; + TEST_CHECK (result == ok_result) ; // try to create it again; this should safely do nothing - OK (LAGraph_Property_AT (G, msg)) ; + result = LAGraph_Cached_AT (G, msg) ; + TEST_CHECK (result == ok_result) ; // check the result if (kind == LAGraph_ADJACENCY_UNDIRECTED) @@ -127,11 +131,11 @@ void test_Property_AT (void) } //----------------------------------------------------------------------------- -// test_Property_AT_brutal +// test_Cached_AT_brutal //----------------------------------------------------------------------------- #if LAGRAPH_SUITESPARSE -void test_Property_AT_brutal (void) +void test_Cached_AT_brutal (void) { OK (LG_brutal_setup (msg)) ; @@ -154,11 +158,11 @@ void test_Property_AT_brutal (void) OK (LAGraph_New (&G, &A, kind, msg)) ; TEST_CHECK (A == NULL) ; - // create the G->AT property - LG_BRUTAL (LAGraph_Property_AT (G, msg)) ; + // create the G->AT cached property + LG_BRUTAL (LAGraph_Cached_AT (G, msg)) ; // try to create it again; this should safely do nothing - LG_BRUTAL (LAGraph_Property_AT (G, msg)) ; + LG_BRUTAL (LAGraph_Cached_AT (G, msg)) ; // check the result if (kind == LAGraph_ADJACENCY_UNDIRECTED) @@ -198,9 +202,9 @@ void test_Property_AT_brutal (void) TEST_LIST = { - { "Property_AT", test_Property_AT }, + { "test_AT", test_Cached_AT }, #if LAGRAPH_SUITESPARSE - { "Property_AT_brutal", test_Property_AT_brutal }, + { "test_AT_brutal", test_Cached_AT_brutal }, #endif { NULL, NULL } } ; diff --git a/src/test/test_Property_Degree.c b/src/test/test_Cached_Degree.c similarity index 85% rename from src/test/test_Property_Degree.c rename to src/test/test_Cached_Degree.c index 35989202e8..f1a74a5c36 100644 --- a/src/test/test_Property_Degree.c +++ b/src/test/test_Cached_Degree.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// LAGraph/src/test/test_Property_Degree.c: test LAGraph_Property_*Degree +// LAGraph/src/test/test_Cached_Degree.c: test LAGraph_Cached_*Degree //------------------------------------------------------------------------------ // LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. @@ -72,14 +72,14 @@ void check_degree } //------------------------------------------------------------------------------ -// test_Property_Degree: test LAGraph_Property_*Degree +// test_Cached_Degree: test LAGraph_Cached_*Degree //------------------------------------------------------------------------------ typedef struct { const char *name ; - const int rowdeg [67] ; - const int coldeg [67] ; + const int out_deg [67] ; + const int in_deg [67] ; } matrix_info ; @@ -232,10 +232,10 @@ const matrix_info files [ ] = } ; //----------------------------------------------------------------------------- -// test_Property_Degree +// test_Cached_Degree //----------------------------------------------------------------------------- -void test_Property_Degree (void) +void test_Cached_Degree (void) { setup ( ) ; @@ -245,8 +245,8 @@ void test_Property_Degree (void) // load the matrix as A const char *aname = files [k].name ; if (strlen (aname) == 0) break; - const int *rowdeg = files [k].rowdeg ; - const int *coldeg = files [k].coldeg ; + const int *out_deg = files [k].out_deg ; + const int *in_deg = files [k].in_deg ; TEST_CASE (aname) ; snprintf (filename, LEN, LG_DATA_DIR "%s", aname) ; FILE *f = fopen (filename, "r") ; @@ -261,33 +261,33 @@ void test_Property_Degree (void) for (int trial = 0 ; trial <= 2 ; trial++) { - // create the G->rowdegree property and check it - OK (LAGraph_Property_RowDegree (G, msg)) ; + // create the G->out_degree cached property and check it + OK (LAGraph_Cached_OutDegree (G, msg)) ; GrB_Index n ; OK (GrB_Matrix_nrows (&n, G->A)) ; - check_degree (G->rowdegree, n, rowdeg) ; + check_degree (G->out_degree, n, out_deg) ; if (trial == 2) { - // use G->AT to compute G->coldegree - OK (LAGraph_DeleteProperties (G, msg)) ; - OK (LAGraph_Property_AT (G, msg)) ; + // use G->AT to compute G->in_degree + OK (LAGraph_DeleteCached (G, msg)) ; + OK (LAGraph_Cached_AT (G, msg)) ; } - // create the G->ColDegree property and check it - OK (LAGraph_Property_ColDegree (G, msg)) ; + // create the G->in_degree cached property and check it + OK (LAGraph_Cached_InDegree (G, msg)) ; OK (GrB_Matrix_ncols (&n, G->A)) ; - check_degree (G->coldegree, n, coldeg) ; + check_degree (G->in_degree, n, in_deg) ; } OK (LAGraph_Delete (&G, msg)) ; } // check error handling - int status = LAGraph_Property_RowDegree (NULL, msg) ; + int status = LAGraph_Cached_OutDegree (NULL, msg) ; printf ("\nstatus: %d, msg: %s\n", status, msg) ; TEST_CHECK (status == GrB_NULL_POINTER) ; - status = LAGraph_Property_ColDegree (NULL, msg) ; + status = LAGraph_Cached_InDegree (NULL, msg) ; printf ("status: %d, msg: %s\n", status, msg) ; TEST_CHECK (status == GrB_NULL_POINTER) ; @@ -295,11 +295,11 @@ void test_Property_Degree (void) } //----------------------------------------------------------------------------- -// test_Property_Degree_brutal +// test_Cached_Degree_brutal //----------------------------------------------------------------------------- #if LAGRAPH_SUITESPARSE -void test_Property_Degree_brutal (void) +void test_Cached_Degree_brutal (void) { OK (LG_brutal_setup (msg)) ; @@ -309,8 +309,8 @@ void test_Property_Degree_brutal (void) // load the matrix as A const char *aname = files [k].name ; if (strlen (aname) == 0) break; - const int *rowdeg = files [k].rowdeg ; - const int *coldeg = files [k].coldeg ; + const int *out_deg = files [k].out_deg ; + const int *in_deg = files [k].in_deg ; TEST_CASE (aname) ; snprintf (filename, LEN, LG_DATA_DIR "%s", aname) ; FILE *f = fopen (filename, "r") ; @@ -325,23 +325,23 @@ void test_Property_Degree_brutal (void) for (int trial = 0 ; trial <= 2 ; trial++) { - // create the G->rowdegree property and check it - LG_BRUTAL (LAGraph_Property_RowDegree (G, msg)) ; + // create the G->out_degree cached property and check it + LG_BRUTAL (LAGraph_Cached_OutDegree (G, msg)) ; GrB_Index n ; OK (GrB_Matrix_nrows (&n, G->A)) ; - check_degree (G->rowdegree, n, rowdeg) ; + check_degree (G->out_degree, n, out_deg) ; if (trial == 2) { - // use G->AT to compute G->coldegree - OK (LAGraph_DeleteProperties (G, msg)) ; - OK (LAGraph_Property_AT (G, msg)) ; + // use G->AT to compute G->in_degree + OK (LAGraph_DeleteCached (G, msg)) ; + OK (LAGraph_Cached_AT (G, msg)) ; } - // create the G->ColDegree property and check it - LG_BRUTAL (LAGraph_Property_ColDegree (G, msg)) ; + // create the G->in_degree cached property and check it + LG_BRUTAL (LAGraph_Cached_InDegree (G, msg)) ; OK (GrB_Matrix_ncols (&n, G->A)) ; - check_degree (G->coldegree, n, coldeg) ; + check_degree (G->in_degree, n, in_deg) ; } OK (LAGraph_Delete (&G, msg)) ; @@ -357,9 +357,9 @@ void test_Property_Degree_brutal (void) TEST_LIST = { - { "Property_Degree", test_Property_Degree }, + { "test_Degree", test_Cached_Degree }, #if LAGRAPH_SUITESPARSE - { "Property_Degree_brutal", test_Property_Degree_brutal }, + { "test_Degree_brutal", test_Cached_Degree_brutal }, #endif { NULL, NULL } } ; diff --git a/src/test/test_Property_NDiag.c b/src/test/test_Cached_NDiag.c similarity index 90% rename from src/test/test_Property_NDiag.c rename to src/test/test_Cached_NDiag.c index 97cabc6741..a71d96f8db 100644 --- a/src/test/test_Property_NDiag.c +++ b/src/test/test_Cached_NDiag.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// LAGraph/src/test/test_Property_NDiag.c: test LAGraph_Property_NDiag +// LAGraph/src/test/test_Cached_NSelfEdges.c: test LAGraph_Cached_NSelfEdges //------------------------------------------------------------------------------ // LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. @@ -30,7 +30,7 @@ char filename [LEN+1] ; typedef struct { - GrB_Index ndiag ; + GrB_Index nself_edges ; const char *name ; } matrix_info ; @@ -107,10 +107,10 @@ void teardown (void) } //------------------------------------------------------------------------------ -// test_Property_NDiag: test LAGraph_Property_NDiag +// test_Cached_NSelfEdges: test LAGraph_Cached_NSelfEdges //------------------------------------------------------------------------------ -void test_Property_NDiag (void) +void test_Cached_NSelfEdges (void) { //-------------------------------------------------------------------------- @@ -141,8 +141,8 @@ void test_Property_NDiag (void) //---------------------------------------------------------------------- OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_DIRECTED, msg)) ; - OK (LAGraph_Property_NDiag (G, msg)) ; - TEST_CHECK (G->ndiag == files [k].ndiag) ; + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; + TEST_CHECK (G->nself_edges == files [k].nself_edges) ; //---------------------------------------------------------------------- // free the graph @@ -151,7 +151,7 @@ void test_Property_NDiag (void) OK (LAGraph_Delete (&G, msg)) ; } - TEST_CHECK (LAGraph_Property_NDiag (NULL, msg) == GrB_NULL_POINTER) ; + TEST_CHECK (LAGraph_Cached_NSelfEdges (NULL, msg) == GrB_NULL_POINTER) ; //-------------------------------------------------------------------------- // finish the test @@ -161,11 +161,11 @@ void test_Property_NDiag (void) } //------------------------------------------------------------------------------ -// test_Property_NDiag_brutal +// test_Cached_NSelfEdges_brutal //------------------------------------------------------------------------------ #if LAGRAPH_SUITESPARSE -void test_Property_NDiag_brutal (void) +void test_Cached_NSelfEdges_brutal (void) { OK (LG_brutal_setup (msg)) ; @@ -191,8 +191,8 @@ void test_Property_NDiag_brutal (void) //---------------------------------------------------------------------- OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_DIRECTED, msg)) ; - LG_BRUTAL (LAGraph_Property_NDiag (G, msg)) ; - TEST_CHECK (G->ndiag == files [k].ndiag) ; + LG_BRUTAL (LAGraph_Cached_NSelfEdges (G, msg)) ; + TEST_CHECK (G->nself_edges == files [k].nself_edges) ; //---------------------------------------------------------------------- // free the graph @@ -211,9 +211,9 @@ void test_Property_NDiag_brutal (void) TEST_LIST = { - { "NDiag", test_Property_NDiag }, + { "NSelfEdges", test_Cached_NSelfEdges }, #if LAGRAPH_SUITESPARSE - { "NDiag_brutal", test_Property_NDiag_brutal }, + { "NSelfEdges_brutal", test_Cached_NSelfEdges_brutal }, #endif { NULL, NULL } } ; diff --git a/src/test/test_Property_ASymmetricStructure.c b/src/test/test_Cached_SymmetricStructure.c similarity index 75% rename from src/test/test_Property_ASymmetricStructure.c rename to src/test/test_Cached_SymmetricStructure.c index 8d14dcde0b..d819168ea7 100644 --- a/src/test/test_Property_ASymmetricStructure.c +++ b/src/test/test_Cached_SymmetricStructure.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// LAGraph/src/test/test_Property_Symmetric_Structure.c +// LAGraph/src/test/test_Cached_Symmetric_Structure.c //------------------------------------------------------------------------------ // LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. @@ -42,7 +42,7 @@ void teardown (void) } //------------------------------------------------------------------------------ -// test_Property_Symmetric_Structure: +// test_Cached_Symmetric_Structure: //------------------------------------------------------------------------------ typedef struct @@ -112,7 +112,7 @@ const matrix_info files [ ] = 0, 0, "" } ; -void test_Property_Symmetric_Structure (void) +void test_Cached_Symmetric_Structure (void) { setup ( ) ; @@ -137,46 +137,46 @@ void test_Property_Symmetric_Structure (void) OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_DIRECTED, msg)) ; TEST_CHECK (A == NULL) ; - // compute the structure_is_symmetric property - OK (LAGraph_Property_SymmetricStructure (G, msg)) ; + // compute the is_symmetric_structure cached property + OK (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; // check the result if (sym_structure) { - TEST_CHECK (G->structure_is_symmetric == LAGraph_TRUE) ; + TEST_CHECK (G->is_symmetric_structure == LAGraph_TRUE) ; } else { - TEST_CHECK (G->structure_is_symmetric == LAGraph_FALSE) ; + TEST_CHECK (G->is_symmetric_structure == LAGraph_FALSE) ; } - // delete all properties - OK (LAGraph_DeleteProperties (G, msg)) ; + // delete all cached properties + OK (LAGraph_DeleteCached (G, msg)) ; // try again, but precompute G->AT - OK (LAGraph_Property_AT (G, msg)) ; - OK (LAGraph_Property_SymmetricStructure (G, msg)) ; + OK (LAGraph_Cached_AT (G, msg)) ; + OK (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; // check the result if (sym_structure) { - TEST_CHECK (G->structure_is_symmetric == LAGraph_TRUE) ; + TEST_CHECK (G->is_symmetric_structure == LAGraph_TRUE) ; } else { - TEST_CHECK (G->structure_is_symmetric == LAGraph_FALSE) ; + TEST_CHECK (G->is_symmetric_structure == LAGraph_FALSE) ; } - // delete all properties - OK (LAGraph_DeleteProperties (G, msg)) ; + // delete all cached properties + OK (LAGraph_DeleteCached (G, msg)) ; // change the graph to directed, if matrix is symmetric if (sym_values) { G->kind = LAGraph_ADJACENCY_UNDIRECTED ; - // recompute the symmetry property - OK (LAGraph_Property_SymmetricStructure (G, msg)) ; - TEST_CHECK (G->structure_is_symmetric == LAGraph_TRUE) ; + // recompute the symmetry cached property + OK (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; + TEST_CHECK (G->is_symmetric_structure == LAGraph_TRUE) ; } OK (LAGraph_Delete (&G, msg)) ; @@ -184,7 +184,7 @@ void test_Property_Symmetric_Structure (void) } // check error handling - int status = LAGraph_Property_SymmetricStructure (NULL, msg) ; + int status = LAGraph_Cached_IsSymmetricStructure (NULL, msg) ; printf ("\nstatus: %d, msg: %s\n", status, msg) ; TEST_CHECK (status == GrB_NULL_POINTER) ; @@ -192,11 +192,11 @@ void test_Property_Symmetric_Structure (void) } //----------------------------------------------------------------------------- -// test_Property_Symmetric_Structure_brutal +// test_Cached_Symmetric_Structure_brutal //----------------------------------------------------------------------------- #if LAGRAPH_SUITESPARSE -void test_Property_Symmetric_Structure_brutal (void) +void test_Cached_Symmetric_Structure_brutal (void) { OK (LG_brutal_setup (msg)) ; @@ -221,46 +221,46 @@ void test_Property_Symmetric_Structure_brutal (void) OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_DIRECTED, msg)) ; TEST_CHECK (A == NULL) ; - // compute the structure_is_symmetric property - LG_BRUTAL (LAGraph_Property_SymmetricStructure (G, msg)) ; + // compute the is_symmetric_structure cached property + LG_BRUTAL (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; // check the result if (sym_structure) { - TEST_CHECK (G->structure_is_symmetric == LAGraph_TRUE) ; + TEST_CHECK (G->is_symmetric_structure == LAGraph_TRUE) ; } else { - TEST_CHECK (G->structure_is_symmetric == LAGraph_FALSE) ; + TEST_CHECK (G->is_symmetric_structure == LAGraph_FALSE) ; } - // delete all properties - OK (LAGraph_DeleteProperties (G, msg)) ; + // delete all cached properties + OK (LAGraph_DeleteCached (G, msg)) ; // try again, but precompute G->AT - LG_BRUTAL (LAGraph_Property_AT (G, msg)) ; - LG_BRUTAL (LAGraph_Property_SymmetricStructure (G, msg)) ; + LG_BRUTAL (LAGraph_Cached_AT (G, msg)) ; + LG_BRUTAL (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; // check the result if (sym_structure) { - TEST_CHECK (G->structure_is_symmetric == LAGraph_TRUE) ; + TEST_CHECK (G->is_symmetric_structure == LAGraph_TRUE) ; } else { - TEST_CHECK (G->structure_is_symmetric == LAGraph_FALSE) ; + TEST_CHECK (G->is_symmetric_structure == LAGraph_FALSE) ; } - // delete all properties - OK (LAGraph_DeleteProperties (G, msg)) ; + // delete all cached properties + OK (LAGraph_DeleteCached (G, msg)) ; // change the graph to directed, if matrix is symmetric if (sym_values) { G->kind = LAGraph_ADJACENCY_UNDIRECTED ; - // recompute the symmetry property - LG_BRUTAL (LAGraph_Property_SymmetricStructure (G, msg)) ; - TEST_CHECK (G->structure_is_symmetric == LAGraph_TRUE) ; + // recompute the symmetry cached property + LG_BRUTAL (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; + TEST_CHECK (G->is_symmetric_structure == LAGraph_TRUE) ; } OK (LAGraph_Delete (&G, msg)) ; @@ -276,10 +276,10 @@ void test_Property_Symmetric_Structure_brutal (void) TEST_LIST = { - { "Property_Symmetric_Structure", test_Property_Symmetric_Structure }, + { "test_Symmetric_Structure", test_Cached_Symmetric_Structure }, #if LAGRAPH_SUITESPARSE - { "Property_Symmetric_Structure_brutal", - test_Property_Symmetric_Structure_brutal }, + { "test_Symmetric_Structure_brutal", + test_Cached_Symmetric_Structure_brutal }, #endif { NULL, NULL } } ; diff --git a/src/test/test_CheckGraph.c b/src/test/test_CheckGraph.c index 218f4dc98e..d119c6b8df 100644 --- a/src/test/test_CheckGraph.c +++ b/src/test/test_CheckGraph.c @@ -89,21 +89,25 @@ void test_CheckGraph (void) TEST_CHECK (G->kind == kind) ; if (kind == LAGraph_ADJACENCY_DIRECTED) { - TEST_CHECK (G->structure_is_symmetric == LAGRAPH_UNKNOWN) ; + TEST_CHECK (G->is_symmetric_structure == LAGRAPH_UNKNOWN) ; } else { - TEST_CHECK (G->structure_is_symmetric == LAGraph_TRUE) ; + TEST_CHECK (G->is_symmetric_structure == LAGraph_TRUE) ; } - // create its properties - OK (LAGraph_Property_AT (G, msg)) ; + // create its cached properties + int ok_result = (kind == LAGraph_ADJACENCY_UNDIRECTED) ? + LAGRAPH_CACHE_NOT_NEEDED : GrB_SUCCESS ; + int result = LAGraph_Cached_AT (G, msg) ; OK (LAGraph_CheckGraph (G, msg)) ; + TEST_CHECK (result == ok_result) ; - OK (LAGraph_Property_RowDegree (G, msg)) ; + OK (LAGraph_Cached_OutDegree (G, msg)) ; OK (LAGraph_CheckGraph (G, msg)) ; - OK (LAGraph_Property_ColDegree (G, msg)) ; + result = LAGraph_Cached_InDegree (G, msg) ; + TEST_CHECK (result == ok_result) ; OK (LAGraph_CheckGraph (G, msg)) ; // free the graph @@ -182,29 +186,29 @@ void test_CheckGraph_failures (void) G->AT = NULL ; - // G->rowdegree has the right type, but wrong size - G->rowdegree = d_int64 ; + // G->out_degree has the right type, but wrong size + G->out_degree = d_int64 ; TEST_CHECK (LAGraph_CheckGraph (G, msg) == LAGRAPH_INVALID_GRAPH) ; printf ("msg: %s\n", msg) ; - // G->rowdegree has the right size, but wrong type - G->rowdegree = d_bool ; + // G->out_degree has the right size, but wrong type + G->out_degree = d_bool ; TEST_CHECK (LAGraph_CheckGraph (G, msg) == LAGRAPH_INVALID_GRAPH) ; printf ("msg: %s\n", msg) ; - G->rowdegree = NULL ; + G->out_degree = NULL ; - // G->coldegree has the right type, but wrong size - G->coldegree = d_int64 ; + // G->in_degree has the right type, but wrong size + G->in_degree = d_int64 ; TEST_CHECK (LAGraph_CheckGraph (G, msg) == LAGRAPH_INVALID_GRAPH) ; printf ("msg: %s\n", msg) ; - // G->coldegree has the right size, but wrong type - G->coldegree = d_bool ; + // G->in_degree has the right size, but wrong type + G->in_degree = d_bool ; TEST_CHECK (LAGraph_CheckGraph (G, msg) == LAGRAPH_INVALID_GRAPH) ; printf ("msg: %s\n", msg) ; - G->coldegree = NULL ; + G->in_degree = NULL ; #if LAGRAPH_SUITESPARSE // G->A must be by-row @@ -265,12 +269,12 @@ void test_CheckGraph_brutal (void) TEST_CHECK (A == NULL) ; // A has been moved into G->A LG_BRUTAL_BURBLE (LAGraph_CheckGraph (G, msg)) ; - // create its properties - LG_BRUTAL_BURBLE (LAGraph_Property_AT (G, msg)) ; + // create its cached properties + LG_BRUTAL_BURBLE (LAGraph_Cached_AT (G, msg)) ; LG_BRUTAL_BURBLE (LAGraph_CheckGraph (G, msg)) ; - LG_BRUTAL_BURBLE (LAGraph_Property_RowDegree (G, msg)) ; + LG_BRUTAL_BURBLE (LAGraph_Cached_OutDegree (G, msg)) ; LG_BRUTAL_BURBLE (LAGraph_CheckGraph (G, msg)) ; - LG_BRUTAL_BURBLE (LAGraph_Property_ColDegree (G, msg)) ; + LG_BRUTAL_BURBLE (LAGraph_Cached_InDegree (G, msg)) ; LG_BRUTAL_BURBLE (LAGraph_CheckGraph (G, msg)) ; LG_BRUTAL_BURBLE (LAGraph_Delete (&G, msg)) ; diff --git a/src/test/test_ConnectedComponents.c b/src/test/test_ConnectedComponents.c index be3c8be585..5b4032f6da 100644 --- a/src/test/test_ConnectedComponents.c +++ b/src/test/test_ConnectedComponents.c @@ -167,7 +167,7 @@ void test_cc_matrices (void) // convert to directed with symmetric pattern for next trial G->kind = LAGraph_ADJACENCY_DIRECTED ; - G->structure_is_symmetric = LAGraph_TRUE ; + G->is_symmetric_structure = LAGraph_TRUE ; } OK (LAGraph_Delete (&G, msg)) ; diff --git a/src/test/test_DeleteProperties.c b/src/test/test_DeleteCached.c similarity index 69% rename from src/test/test_DeleteProperties.c rename to src/test/test_DeleteCached.c index b91210a3ce..08295a8c1e 100644 --- a/src/test/test_DeleteProperties.c +++ b/src/test/test_DeleteCached.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// LAGraph/src/test/test_DeleteProperties.c: test LAGraph_DeleteProperties +// LAGraph/src/test/test_DeleteCached.c: test LAGraph_DeleteCached //------------------------------------------------------------------------------ // LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. @@ -42,7 +42,7 @@ void teardown (void) } //------------------------------------------------------------------------------ -// test_DeleteProperties: test LAGraph_DeleteProperties +// test_DeleteCached: test LAGraph_DeleteCached //------------------------------------------------------------------------------ typedef struct @@ -62,7 +62,7 @@ const matrix_info files [ ] = LAGRAPH_UNKNOWN, "" } ; -void test_DeleteProperties (void) +void test_DeleteCached (void) { setup ( ) ; @@ -85,47 +85,51 @@ void test_DeleteProperties (void) OK (LAGraph_New (&G, &A, kind, msg)) ; TEST_CHECK (A == NULL) ; - // create all properties (see test_Property_* for tests of content) - OK (LAGraph_Property_RowDegree (G, msg)) ; - OK (LAGraph_Property_ColDegree (G, msg)) ; - OK (LAGraph_Property_AT (G, msg)) ; - OK (LAGraph_Property_SymmetricStructure (G, msg)) ; + // create all cached properties (see test_Cached_* for tests of content) + int ok_result = (kind == LAGraph_ADJACENCY_UNDIRECTED) ? + LAGRAPH_CACHE_NOT_NEEDED : GrB_SUCCESS ; + OK (LAGraph_Cached_OutDegree (G, msg)) ; + int result = LAGraph_Cached_InDegree (G, msg) ; + TEST_CHECK (result == ok_result) ; + result = LAGraph_Cached_AT (G, msg) ; + TEST_CHECK (result == ok_result) ; + OK (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; // print them - printf ("\nGraph: ndiag %g, symmetric structure: %d\n", - (double) G->ndiag, G->structure_is_symmetric) ; + printf ("\nGraph: nself_edges %g, symmetric structure: %d\n", + (double) G->nself_edges, G->is_symmetric_structure) ; printf (" adj matrix: ") ; int rr = (LAGraph_Matrix_Print (G->A, LAGraph_SHORT, stdout, msg)) ; printf ("result: %d msg: %s\n", rr, msg) ; - printf (" row degree: ") ; - OK (LAGraph_Vector_Print (G->rowdegree, LAGraph_SHORT, stdout, msg)) ; + printf (" out degree: ") ; + OK (LAGraph_Vector_Print (G->out_degree, LAGraph_SHORT, stdout, msg)) ; if (kind == LAGraph_ADJACENCY_DIRECTED) { printf (" adj transposed: ") ; OK (LAGraph_Matrix_Print (G->AT, LAGraph_SHORT, stdout, msg)) ; - printf (" col degree: ") ; - OK (LAGraph_Vector_Print (G->coldegree, LAGraph_SHORT, stdout, + printf (" in degree: ") ; + OK (LAGraph_Vector_Print (G->in_degree, LAGraph_SHORT, stdout, msg)) ; } else { TEST_CHECK (G->AT == NULL) ; - TEST_CHECK (G->coldegree == NULL) ; + TEST_CHECK (G->in_degree == NULL) ; } for (int trial = 0 ; trial <= 1 ; trial++) { - // delete all the properties - OK (LAGraph_DeleteProperties (G, msg)) ; + // delete all the cached properties + OK (LAGraph_DeleteCached (G, msg)) ; TEST_CHECK (G->AT == NULL) ; - TEST_CHECK (G->rowdegree == NULL) ; - TEST_CHECK (G->coldegree == NULL) ; + TEST_CHECK (G->out_degree == NULL) ; + TEST_CHECK (G->in_degree == NULL) ; } OK (LAGraph_Delete (&G, msg)) ; } - OK (LAGraph_DeleteProperties (NULL, msg)) ; + OK (LAGraph_DeleteCached (NULL, msg)) ; teardown ( ) ; } @@ -156,23 +160,23 @@ void test_del_brutal (void) LG_BRUTAL (LAGraph_New (&G, &A, kind, msg)) ; TEST_CHECK (A == NULL) ; - // create all properties (see test_Property_* for tests of content) - LG_BRUTAL (LAGraph_Property_RowDegree (G, msg)) ; - LG_BRUTAL (LAGraph_Property_ColDegree (G, msg)) ; - LG_BRUTAL (LAGraph_Property_AT (G, msg)) ; - LG_BRUTAL (LAGraph_Property_SymmetricStructure (G, msg)) ; + // create all cached properties (see test_Cached_* for tests of content) + LG_BRUTAL (LAGraph_Cached_OutDegree (G, msg)) ; + LG_BRUTAL (LAGraph_Cached_InDegree (G, msg)) ; + LG_BRUTAL (LAGraph_Cached_AT (G, msg)) ; + LG_BRUTAL (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; for (int trial = 0 ; trial <= 1 ; trial++) { - // delete all the properties - LG_BRUTAL (LAGraph_DeleteProperties (G, msg)) ; + // delete all the cached properties + LG_BRUTAL (LAGraph_DeleteCached (G, msg)) ; TEST_CHECK (G->AT == NULL) ; - TEST_CHECK (G->rowdegree == NULL) ; - TEST_CHECK (G->coldegree == NULL) ; + TEST_CHECK (G->out_degree == NULL) ; + TEST_CHECK (G->in_degree == NULL) ; } LG_BRUTAL (LAGraph_Delete (&G, msg)) ; - LG_BRUTAL (LAGraph_DeleteProperties (NULL, msg)) ; + LG_BRUTAL (LAGraph_DeleteCached (NULL, msg)) ; } OK (LG_brutal_teardown (msg)) ; @@ -185,8 +189,8 @@ void test_del_brutal (void) TEST_LIST = { - { "Property_DeleteProperties", test_DeleteProperties }, - { "Property_DeleteProperties_brutal", test_del_brutal }, + { "test_DeleteCached", test_DeleteCached }, + { "test_DeleteCached_brutal", test_del_brutal }, { NULL, NULL } } ; diff --git a/src/test/test_DisplayGraph.c b/src/test/test_DisplayGraph.c index ec41dbd1fd..f2aee050d3 100644 --- a/src/test/test_DisplayGraph.c +++ b/src/test/test_DisplayGraph.c @@ -69,7 +69,7 @@ const char *prwhat (int pr) typedef struct { LAGraph_Kind kind ; - int ndiag ; + int nself_edges ; const char *name ; } matrix_info ; @@ -123,10 +123,13 @@ void test_DisplayGraph (void) LAGraph_Print_Level prl = pr ; OK (LAGraph_DisplayGraph (G, prl, stdout, msg)) ; } - OK (LAGraph_Property_AT (G, msg)) ; - OK (LAGraph_Property_SymmetricStructure (G, msg)) ; - OK (LAGraph_Property_NDiag (G, msg)) ; - TEST_CHECK (G->ndiag == files [k].ndiag) ; + int ok_result = (kind == LAGraph_ADJACENCY_UNDIRECTED) ? + LAGRAPH_CACHE_NOT_NEEDED : GrB_SUCCESS ; + int result = LAGraph_Cached_AT (G, msg) ; + TEST_CHECK (result == ok_result) ; + OK (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; + TEST_CHECK (G->nself_edges == files [k].nself_edges) ; } // free the graph @@ -264,9 +267,12 @@ void test_DisplayGraph_brutal (void) LG_BRUTAL (LAGraph_DisplayGraph (G, prl, stdout, msg)) ; } } - OK (LAGraph_Property_AT (G, msg)) ; - OK (LAGraph_Property_SymmetricStructure (G, msg)) ; - OK (LAGraph_Property_NDiag (G, msg)) ; + int ok_result = (kind == LAGraph_ADJACENCY_UNDIRECTED) ? + LAGRAPH_CACHE_NOT_NEEDED : GrB_SUCCESS ; + int result = LAGraph_Cached_AT (G, msg) ; + TEST_CHECK (result == ok_result) ; + OK (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; + OK (LAGraph_Cached_NSelfEdges (G, msg)) ; } // free the graph diff --git a/src/test/test_Init.c b/src/test/test_Init.c index 818dd654fc..add50e8809 100644 --- a/src/test/test_Init.c +++ b/src/test/test_Init.c @@ -32,9 +32,9 @@ void test_Init (void) #if LAGRAPH_SUITESPARSE const char *name, *date ; - OK (GxB_get (GxB_LIBRARY_NAME, &name)) ; - OK (GxB_get (GxB_LIBRARY_DATE, &date)) ; - OK (GxB_get (GxB_LIBRARY_VERSION, ver)) ; + OK (GxB_Global_Option_get (GxB_LIBRARY_NAME, &name)) ; + OK (GxB_Global_Option_get (GxB_LIBRARY_DATE, &date)) ; + OK (GxB_Global_Option_get (GxB_LIBRARY_VERSION, ver)) ; printf ("\nlibrary: %s %d.%d.%d (%s)\n", name, ver [0], ver [1], ver [2], date) ; printf ( "include: %s %d.%d.%d (%s)\n", GxB_IMPLEMENTATION_NAME, @@ -45,6 +45,16 @@ void test_Init (void) TEST_CHECK (ver [1] == GxB_IMPLEMENTATION_MINOR) ; TEST_CHECK (ver [2] == GxB_IMPLEMENTATION_SUB) ; OK (strcmp (date, GxB_IMPLEMENTATION_DATE)) ; + + #if ( GxB_IMPLEMENTATION_MAJOR >= 7 ) + char *compiler ; + int compiler_version [3] ; + OK (GxB_Global_Option_get (GxB_COMPILER_NAME, &compiler)) ; + OK (GxB_Global_Option_get (GxB_COMPILER_VERSION, compiler_version)) ; + printf ("GraphBLAS compiled with: %s v%d.%d.%d\n", compiler, + compiler_version [0], compiler_version [1], compiler_version [2]) ; + #endif + #else printf ("\nVanilla GraphBLAS: no GxB* extensions\n") ; #endif @@ -67,20 +77,7 @@ void test_Init (void) TEST_CHECK (ver [2] == LAGRAPH_VERSION_UPDATE) ; OK (strcmp (version_date, LAGRAPH_DATE)) ; - // LAGraph_Init cannot be called twice - status = LAGraph_Init (msg) ; - printf ("\nstatus: %d msg: %s\n", status, msg) ; - TEST_CHECK (status != GrB_SUCCESS) ; - OK (LAGraph_Finalize (msg)) ; - - // calling LAGraph_Finalize twice leads to undefined behavior; - // for SuiteSparse, it returns GrB_SUCCESS - status = LAGraph_Finalize (msg) ; - printf ("status %d\n", status) ; - #if LAGRAPH_SUITESPARSE - TEST_CHECK (status == GrB_SUCCESS) ; - #endif } //----------------------------------------------------------------------------- diff --git a/src/test/test_Init_errors.c b/src/test/test_Init_errors.c new file mode 100644 index 0000000000..ab8b4072b1 --- /dev/null +++ b/src/test/test_Init_errors.c @@ -0,0 +1,59 @@ +//------------------------------------------------------------------------------ +// LAGraph/src/test/test_Init_errors.c: test LAGraph_Init and LAGraph_Finalize +//------------------------------------------------------------------------------ + +// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause +// See additional acknowledgments in the LICENSE file, +// or contact permission@sei.cmu.edu for the full terms. + +// Contributed by Timothy A. Davis, Texas A&M University + +//------------------------------------------------------------------------------ + +#include "LAGraph_test.h" + +//------------------------------------------------------------------------------ +// global variables +//------------------------------------------------------------------------------ + +char msg [LAGRAPH_MSG_LEN] ; + +//------------------------------------------------------------------------------ +// test_Init_errors: test LAGraph_Init +//------------------------------------------------------------------------------ + +void test_Init_errors (void) +{ + + int status = LAGraph_Init (msg) ; + OK (status) ; + int ver [3] ; + + // LAGraph_Init cannot be called twice + status = LAGraph_Init (msg) ; + printf ("\nstatus: %d msg: %s\n", status, msg) ; + TEST_CHECK (status != GrB_SUCCESS) ; + + OK (LAGraph_Finalize (msg)) ; + + // calling LAGraph_Finalize twice leads to undefined behavior; + // for SuiteSparse, it returns GrB_SUCCESS + status = LAGraph_Finalize (msg) ; + printf ("status %d\n", status) ; + #if LAGRAPH_SUITESPARSE + TEST_CHECK (status == GrB_SUCCESS) ; + #endif +} + +//----------------------------------------------------------------------------- +// TEST_LIST: the list of tasks for this entire test +//----------------------------------------------------------------------------- + +TEST_LIST = +{ + { "Init_errors", test_Init_errors }, + // no brutal test: see test_Xinit + { NULL, NULL } +} ; + diff --git a/src/test/test_New.c b/src/test/test_New.c index e27d671c9e..4cd66bedea 100644 --- a/src/test/test_New.c +++ b/src/test/test_New.c @@ -88,11 +88,11 @@ void test_New (void) TEST_CHECK (G->kind == kind) ; if (kind == LAGraph_ADJACENCY_DIRECTED) { - TEST_CHECK (G->structure_is_symmetric == LAGRAPH_UNKNOWN) ; + TEST_CHECK (G->is_symmetric_structure == LAGRAPH_UNKNOWN) ; } else { - TEST_CHECK (G->structure_is_symmetric == LAGraph_TRUE) ; + TEST_CHECK (G->is_symmetric_structure == LAGraph_TRUE) ; } // free the graph diff --git a/src/test/test_NumThreads.c b/src/test/test_NumThreads.c index b02c73987f..5c0bdeddfb 100644 --- a/src/test/test_NumThreads.c +++ b/src/test/test_NumThreads.c @@ -17,7 +17,7 @@ // global variables //------------------------------------------------------------------------------ -int nthreads = 0 ; +int nthreads_hi = 0, nthreads_lo = 0 ; char msg [LAGRAPH_MSG_LEN] ; //------------------------------------------------------------------------------ @@ -29,24 +29,33 @@ void test_NumThreads (void) OK (LAGraph_Init (msg)) ; - nthreads = 0 ; - OK (LAGraph_GetNumThreads (&nthreads, msg)) ; - TEST_CHECK (nthreads > 0) ; - - nthreads = 0 ; - OK (LAGraph_GetNumThreads (&nthreads, NULL)) ; - TEST_CHECK (nthreads > 0) ; - - OK (LAGraph_SetNumThreads (4, msg)) ; - OK (LAGraph_GetNumThreads (&nthreads, msg)) ; - TEST_CHECK (nthreads > 0) ; - - OK (LAGraph_SetNumThreads (4, NULL)) ; - nthreads = 0 ; - OK (LAGraph_GetNumThreads (&nthreads, NULL)) ; - TEST_CHECK (nthreads > 0) ; - - TEST_CHECK (LAGraph_GetNumThreads (NULL, msg) == GrB_NULL_POINTER) ; + nthreads_hi = 0 ; + nthreads_lo = 0 ; + OK (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + TEST_CHECK (nthreads_hi > 0) ; + TEST_CHECK (nthreads_lo > 0) ; + + nthreads_hi = 0 ; + nthreads_lo = 0 ; + OK (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, NULL)) ; + TEST_CHECK (nthreads_hi > 0) ; + TEST_CHECK (nthreads_lo > 0) ; + + OK (LAGraph_SetNumThreads (2, 4, msg)) ; + nthreads_hi = 0 ; + nthreads_lo = 0 ; + OK (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; + TEST_CHECK (nthreads_hi > 0) ; + TEST_CHECK (nthreads_lo > 0) ; + + OK (LAGraph_SetNumThreads (2, 4, NULL)) ; + nthreads_hi = 0 ; + nthreads_lo = 0 ; + OK (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, NULL)) ; + TEST_CHECK (nthreads_hi > 0) ; + TEST_CHECK (nthreads_lo > 0) ; + + TEST_CHECK (LAGraph_GetNumThreads (NULL, NULL, msg) == GrB_NULL_POINTER) ; printf ("\nmsg: %s\n", msg) ; OK (LAGraph_Finalize (msg)) ; diff --git a/src/test/test_PageRank.c b/src/test/test_PageRank.c index 9453f11ffb..54c5a116df 100644 --- a/src/test/test_PageRank.c +++ b/src/test/test_PageRank.c @@ -202,7 +202,7 @@ void test_ranker(void) OK (fclose (f)) ; OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_UNDIRECTED, msg)) ; TEST_CHECK (A == NULL) ; // A has been moved into G->A - OK (LAGraph_Property_RowDegree (G, msg)) ; + OK (LAGraph_Cached_OutDegree (G, msg)) ; // compute its pagerank using the GAP method OK (LAGr_PageRankGAP (¢rality, &niters, G, 0.85, @@ -247,8 +247,8 @@ void test_ranker(void) OK (fclose (f)) ; OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_DIRECTED, msg)) ; TEST_CHECK (A == NULL) ; // A has been moved into G->A - OK (LAGraph_Property_AT (G, msg)) ; - OK (LAGraph_Property_RowDegree (G, msg)) ; + OK (LAGraph_Cached_AT (G, msg)) ; + OK (LAGraph_Cached_OutDegree (G, msg)) ; // compute its pagerank using the GAP method OK (LAGr_PageRankGAP (¢rality, &niters, G, 0.85, @@ -286,8 +286,8 @@ void test_ranker(void) OK (fclose (f)) ; OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_DIRECTED, msg)) ; TEST_CHECK (A == NULL) ; // A has been moved into G->A - OK (LAGraph_Property_AT (G, msg)) ; - OK (LAGraph_Property_RowDegree (G, msg)) ; + OK (LAGraph_Cached_AT (G, msg)) ; + OK (LAGraph_Cached_OutDegree (G, msg)) ; printf ("\n=========== ldbc-directed-example, with sink nodes 3 and 9:\n") ; OK (LAGraph_DisplayGraph (G, LAGraph_COMPLETE, stdout, msg)) ; diff --git a/src/test/test_SampleDegree.c b/src/test/test_SampleDegree.c index 2f9c3392a4..5fa4668af4 100644 --- a/src/test/test_SampleDegree.c +++ b/src/test/test_SampleDegree.c @@ -145,16 +145,16 @@ void test_SampleDegree (void) // SampleDegree requires degrees to be precomputed ret_code = LAGraph_SampleDegree (&mean, &median, G, 1, files [k].nsamples, files [k].seed, msg) ; - TEST_CHECK (ret_code == LAGRAPH_PROPERTY_MISSING) ; + TEST_CHECK (ret_code == LAGRAPH_NOT_CACHED) ; TEST_MSG ("SampleDegree without row degrees precomputed succeeded") ; ret_code = LAGraph_SampleDegree (&mean, &median, G, 0, files [k].nsamples, files [k].seed, msg) ; - TEST_CHECK (ret_code == LAGRAPH_PROPERTY_MISSING) ; + TEST_CHECK (ret_code == LAGRAPH_NOT_CACHED) ; TEST_MSG ("SampleDegree without column degrees precomputed succeeded") ; // Compute and check the row samples - OK (LAGraph_Property_RowDegree (G, msg)) ; + OK (LAGraph_Cached_OutDegree (G, msg)) ; OK (LAGraph_SampleDegree (&mean, &median, G, 1, files [k].nsamples, files [k].seed, msg)) ; @@ -167,9 +167,9 @@ void test_SampleDegree (void) TEST_MSG ("Row Median Produced: %f", median) ; // Compute the column samples - OK (LAGraph_DeleteProperties (G, msg)) ; + OK (LAGraph_DeleteCached (G, msg)) ; - OK (LAGraph_Property_ColDegree (G, msg)) ; + OK (LAGraph_Cached_InDegree (G, msg)) ; OK (LAGraph_SampleDegree (&mean, &median, G, 0, files [k].nsamples, files [k].seed, msg)) ; @@ -216,7 +216,7 @@ void test_SampleDegree_brutal (void) TEST_CHECK (A == NULL) ; // Compute and check the row samples - LG_BRUTAL (LAGraph_Property_RowDegree (G, msg)) ; + LG_BRUTAL (LAGraph_Cached_OutDegree (G, msg)) ; LG_BRUTAL (LAGraph_SampleDegree (&mean, &median, G, 1, files [k].nsamples, files [k].seed, msg)) ; @@ -224,9 +224,9 @@ void test_SampleDegree_brutal (void) TEST_CHECK (is_close(median, files [k].row_median)) ; // Compute the column samples - LG_BRUTAL (LAGraph_DeleteProperties (G, msg)) ; + LG_BRUTAL (LAGraph_DeleteCached (G, msg)) ; - LG_BRUTAL (LAGraph_Property_ColDegree (G, msg)) ; + LG_BRUTAL (LAGraph_Cached_InDegree (G, msg)) ; LG_BRUTAL (LAGraph_SampleDegree (&mean, &median, G, 0, files [k].nsamples, files [k].seed, msg)) ; diff --git a/src/test/test_SingleSourceShortestPath.c b/src/test/test_SingleSourceShortestPath.c index de87fad745..7d7e44e393 100644 --- a/src/test/test_SingleSourceShortestPath.c +++ b/src/test/test_SingleSourceShortestPath.c @@ -148,7 +148,7 @@ void test_SingleSourceShortestPath(void) // add a single negative edge and try again OK (GrB_free (&(G->emin))) ; - G->emin_kind = LAGRAPH_UNKNOWN ; + G->emin_state = LAGRAPH_UNKNOWN ; OK (GrB_Matrix_setElement_INT32 (G->A, -1, 0, 1)) ; OK (GrB_Scalar_setElement (Delta, 30)) ; OK (LAGr_SingleSourceShortestPath (&path_length, G, 0, Delta, msg)) ; @@ -269,7 +269,7 @@ void test_SingleSourceShortestPath_types (void) TEST_CHECK (A == NULL) ; // A has been moved into G->A // find the smallest entry - OK (LAGraph_Property_EMin (G, msg)) ; + OK (LAGraph_Cached_EMin (G, msg)) ; // delta values to try int32_t Deltas [ ] = { 30, 100, 50000 } ; diff --git a/src/test/test_Sort.c b/src/test/test_Sort.c index 1dc87ba965..e239e59d7a 100644 --- a/src/test/test_Sort.c +++ b/src/test/test_Sort.c @@ -23,6 +23,7 @@ char msg [LAGRAPH_MSG_LEN] ; void test_sort1 (void) { OK (LAGraph_Init (msg)) ; + OK (LAGraph_SetNumThreads (1, 4, msg)) ; for (int trial = 0 ; trial <= 1 ; trial++) { @@ -37,7 +38,7 @@ void test_sort1 (void) A0 [k] = (int64_t) LG_Random15 (&seed) ; } - OK (LAGraph_Sort1 (A0, n, 4, msg)) ; + OK (LAGraph_Sort1 (A0, n, msg)) ; for (int k = 1 ; k < n ; k++) { @@ -49,7 +50,7 @@ void test_sort1 (void) A0 [k] = (int64_t) (LG_Random15 (&seed) % 4) ; } - OK (LAGraph_Sort1 (A0, n, 4, msg)) ; + OK (LAGraph_Sort1 (A0, n, msg)) ; for (int k = 1 ; k < n ; k++) { @@ -69,6 +70,7 @@ void test_sort1 (void) void test_sort2 (void) { OK (LAGraph_Init (msg)) ; + OK (LAGraph_SetNumThreads (1, 4, msg)) ; int64_t n = 256 * 1024 ; @@ -83,7 +85,7 @@ void test_sort2 (void) A1 [k] = (int64_t) LG_Random60 (&seed) ; } - OK (LAGraph_Sort2 (A0, A1, n, 4, msg)) ; + OK (LAGraph_Sort2 (A0, A1, n, msg)) ; for (int k = 1 ; k < n ; k++) { @@ -97,7 +99,7 @@ void test_sort2 (void) A1 [k] = (int64_t) (LG_Random15 (&seed) % 4) ; } - OK (LAGraph_Sort2 (A0, A1, n, 4, msg)) ; + OK (LAGraph_Sort2 (A0, A1, n, msg)) ; for (int k = 1 ; k < n ; k++) { @@ -119,6 +121,7 @@ void test_sort2 (void) void test_sort1_brutal (void) { OK (LG_brutal_setup (msg)) ; + OK (LAGraph_SetNumThreads (1, 4, msg)) ; for (int trial = 0 ; trial <= 1 ; trial++) { @@ -133,7 +136,7 @@ void test_sort1_brutal (void) A0 [k] = (int64_t) LG_Random15 (&seed) ; } - LG_BRUTAL (LAGraph_Sort1 (A0, n, 4, msg)) ; + LG_BRUTAL (LAGraph_Sort1 (A0, n, msg)) ; for (int k = 1 ; k < n ; k++) { @@ -145,7 +148,7 @@ void test_sort1_brutal (void) A0 [k] = (int64_t) (LG_Random15 (&seed) % 4) ; } - LG_BRUTAL (LAGraph_Sort1 (A0, n, 4, msg)) ; + LG_BRUTAL (LAGraph_Sort1 (A0, n, msg)) ; for (int k = 1 ; k < n ; k++) { @@ -167,6 +170,7 @@ void test_sort1_brutal (void) void test_sort2_brutal (void) { OK (LG_brutal_setup (msg)) ; + OK (LAGraph_SetNumThreads (1, 4, msg)) ; int64_t n = 256 * 1024 ; @@ -181,7 +185,7 @@ void test_sort2_brutal (void) A1 [k] = (int64_t) LG_Random60 (&seed) ; } - LG_BRUTAL (LAGraph_Sort2 (A0, A1, n, 4, msg)) ; + LG_BRUTAL (LAGraph_Sort2 (A0, A1, n, msg)) ; for (int k = 1 ; k < n ; k++) { @@ -195,7 +199,7 @@ void test_sort2_brutal (void) A1 [k] = (int64_t) (LG_Random15 (&seed) % 4) ; } - LG_BRUTAL (LAGraph_Sort2 (A0, A1, n, 4, msg)) ; + LG_BRUTAL (LAGraph_Sort2 (A0, A1, n, msg)) ; for (int k = 1 ; k < n ; k++) { diff --git a/src/test/test_SortByDegree.c b/src/test/test_SortByDegree.c index 1e804f79ca..2fcda85810 100644 --- a/src/test/test_SortByDegree.c +++ b/src/test/test_SortByDegree.c @@ -129,22 +129,26 @@ void test_SortByDegree (void) TEST_CHECK (A == NULL) ; TEST_CHECK (G != NULL) ; - // create the properties - OK (LAGraph_Property_AT (G, msg)) ; - OK (LAGraph_Property_RowDegree (G, msg)) ; - OK (LAGraph_Property_ColDegree (G, msg)) ; - OK (LAGraph_Property_SymmetricStructure (G, msg)) ; + // create the cached properties + int ok_result = (kind == LAGraph_ADJACENCY_UNDIRECTED) ? + LAGRAPH_CACHE_NOT_NEEDED : GrB_SUCCESS ; + int result = LAGraph_Cached_AT (G, msg) ; + TEST_CHECK (result == ok_result) ; + OK (LAGraph_Cached_OutDegree (G, msg)) ; + result = LAGraph_Cached_InDegree (G, msg) ; + TEST_CHECK (result == ok_result) ; + OK (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; OK (LAGraph_DisplayGraph (G, LAGraph_SHORT, stdout, msg)) ; // sort 4 different ways for (int trial = 0 ; trial <= 3 ; trial++) { - bool byrow = (trial == 0 || trial == 1) ; + bool byout = (trial == 0 || trial == 1) ; bool ascending = (trial == 0 || trial == 2) ; // sort the graph by degree TEST_CHECK (P == NULL) ; - OK (LAGraph_SortByDegree (&P, G, byrow, ascending, msg)) ; + OK (LAGraph_SortByDegree (&P, G, byout, ascending, msg)) ; TEST_CHECK (P != NULL) ; // ensure P is a permutation of 0..n-1 @@ -166,19 +170,20 @@ void test_SortByDegree (void) TEST_CHECK (B == NULL) ; TEST_CHECK (H != NULL) ; - // get the properties of H - OK (LAGraph_Property_RowDegree (H, msg)) ; - OK (LAGraph_Property_ColDegree (H, msg)) ; - OK (LAGraph_Property_SymmetricStructure (H, msg)) ; - TEST_CHECK (G->structure_is_symmetric == - H->structure_is_symmetric) ; + // get the cached properties of H + OK (LAGraph_Cached_OutDegree (H, msg)) ; + result = LAGraph_Cached_InDegree (H, msg) ; + TEST_CHECK (result == ok_result) ; + OK (LAGraph_Cached_IsSymmetricStructure (H, msg)) ; + TEST_CHECK (G->is_symmetric_structure == + H->is_symmetric_structure) ; printf ("\nTrial %d, graph H, sorted (%s) by (%s) degrees:\n", trial, ascending ? "ascending" : "descending", - byrow ? "row" : "column") ; + byout ? "row" : "column") ; OK (LAGraph_DisplayGraph (H, LAGraph_SHORT, stdout, msg)) ; - d = (byrow || G->structure_is_symmetric) ? - H->rowdegree : H->coldegree ; + d = (byout || G->is_symmetric_structure == LAGraph_TRUE) ? + H->out_degree : H->in_degree ; // ensure d is sorted in ascending or descending order int64_t last_deg = (ascending) ? (-1) : (n+1) ; @@ -279,22 +284,26 @@ void test_SortByDegree_brutal (void) TEST_CHECK (A == NULL) ; TEST_CHECK (G != NULL) ; - // create the properties - OK (LAGraph_Property_AT (G, msg)) ; - OK (LAGraph_Property_RowDegree (G, msg)) ; - OK (LAGraph_Property_ColDegree (G, msg)) ; - OK (LAGraph_Property_SymmetricStructure (G, msg)) ; + // create the cached properties + int ok_result = (kind == LAGraph_ADJACENCY_UNDIRECTED) ? + LAGRAPH_CACHE_NOT_NEEDED : GrB_SUCCESS ; + int result = LAGraph_Cached_AT (G, msg) ; + TEST_CHECK (result == ok_result) ; + OK (LAGraph_Cached_OutDegree (G, msg)) ; + result = LAGraph_Cached_InDegree (G, msg) ; + TEST_CHECK (result == ok_result) ; + OK (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; // OK (LAGraph_DisplayGraph (G, LAGraph_SHORT, stdout, msg)) ; // sort 4 different ways for (int trial = 0 ; trial <= 3 ; trial++) { - bool byrow = (trial == 0 || trial == 1) ; + bool byout = (trial == 0 || trial == 1) ; bool ascending = (trial == 0 || trial == 2) ; // sort the graph by degree TEST_CHECK (P == NULL) ; - OK (LAGraph_SortByDegree (&P, G, byrow, ascending, msg)) ; + OK (LAGraph_SortByDegree (&P, G, byout, ascending, msg)) ; TEST_CHECK (P != NULL) ; // ensure P is a permutation of 0..n-1 @@ -316,15 +325,16 @@ void test_SortByDegree_brutal (void) TEST_CHECK (B == NULL) ; TEST_CHECK (H != NULL) ; - // get the properties of H - OK (LAGraph_Property_RowDegree (H, msg)) ; - OK (LAGraph_Property_ColDegree (H, msg)) ; - OK (LAGraph_Property_SymmetricStructure (H, msg)) ; - TEST_CHECK (G->structure_is_symmetric == - H->structure_is_symmetric) ; + // get the cached properties of H + OK (LAGraph_Cached_OutDegree (H, msg)) ; + result = LAGraph_Cached_InDegree (H, msg) ; + TEST_CHECK (result == ok_result) ; + OK (LAGraph_Cached_IsSymmetricStructure (H, msg)) ; + TEST_CHECK (G->is_symmetric_structure == + H->is_symmetric_structure) ; - d = (byrow || G->structure_is_symmetric) ? - H->rowdegree : H->coldegree ; + d = (byout || G->is_symmetric_structure == LAGraph_TRUE) ? + H->out_degree : H->in_degree ; // ensure d is sorted in ascending or descending order int64_t last_deg = (ascending) ? (-1) : (n+1) ; @@ -397,10 +407,10 @@ void test_SortByDegree_failures (void) TEST_MSG ("Loading of adjacency matrix failed") ; OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_UNDIRECTED, msg)) ; - // degree property must first be computed + // cached degree property must first be computed result = LAGraph_SortByDegree (&P, G, true, true, msg) ; printf ("\nresult %d: msg: %s\n", result, msg) ; - TEST_CHECK (result == LAGRAPH_PROPERTY_MISSING) ; + TEST_CHECK (result == LAGRAPH_NOT_CACHED) ; teardown ( ) ; } diff --git a/src/test/test_TriangleCount.c b/src/test/test_TriangleCount.c index c221146d6b..f8dd164e52 100644 --- a/src/test/test_TriangleCount.c +++ b/src/test/test_TriangleCount.c @@ -62,11 +62,11 @@ void setup(void) TEST_CHECK(retval == 0); TEST_MSG("retval = %d (%s)", retval, msg); - retval = LAGraph_Property_NDiag(G, msg); + retval = LAGraph_Cached_NSelfEdges(G, msg); TEST_CHECK(retval == 0); TEST_MSG("retval = %d (%s)", retval, msg); - TEST_CHECK(G->ndiag == 0); + TEST_CHECK(G->nself_edges == 0); } //**************************************************************************** @@ -137,10 +137,10 @@ void test_TriangleCount_Methods3(void) // LAGraph_TriangleCount_Sandia = 3, // sum (sum ((L * L) .* L)) retval = LAGr_TriangleCount(&ntriangles, G, LAGraph_TriangleCount_Sandia, &presort, msg); - TEST_CHECK(retval == LAGRAPH_PROPERTY_MISSING); // should fail (rowdegrees needs to be defined) + TEST_CHECK(retval == LAGRAPH_NOT_CACHED); // should fail (out_degrees needs to be defined) TEST_MSG("retval = %d (%s)", retval, msg); - retval = LAGraph_Property_RowDegree(G, msg); + retval = LAGraph_Cached_OutDegree(G, msg); TEST_CHECK(retval == 0); TEST_MSG("retval = %d (%s)", retval, msg); @@ -167,10 +167,10 @@ void test_TriangleCount_Methods4(void) // LAGraph_TriangleCount_Sandia2 = 4, // sum (sum ((U * U) .* U)) retval = LAGr_TriangleCount(&ntriangles, G, LAGraph_TriangleCount_Sandia2, &presort, msg); - TEST_CHECK(retval == LAGRAPH_PROPERTY_MISSING); // should fail (rowdegrees needs to be defined) + TEST_CHECK(retval == LAGRAPH_NOT_CACHED); // should fail (out_degrees needs to be defined) TEST_MSG("retval = %d (%s)", retval, msg); - retval = LAGraph_Property_RowDegree(G, msg); + retval = LAGraph_Cached_OutDegree(G, msg); TEST_CHECK(retval == 0); TEST_MSG("retval = %d (%s)", retval, msg); @@ -198,10 +198,10 @@ void test_TriangleCount_Methods5(void) // LAGraph_TriangleCount_SandiaDot = 5, // sum (sum ((L * U') .* L)) retval = LAGr_TriangleCount(&ntriangles, G, LAGraph_TriangleCount_SandiaDot, &presort, msg); - TEST_CHECK(retval == LAGRAPH_PROPERTY_MISSING); // should fail (rowdegrees needs to be defined) + TEST_CHECK(retval == LAGRAPH_NOT_CACHED); // should fail (out_degrees needs to be defined) TEST_MSG("retval = %d (%s)", retval, msg); - retval = LAGraph_Property_RowDegree(G, msg); + retval = LAGraph_Cached_OutDegree(G, msg); TEST_CHECK(retval == 0); TEST_MSG("retval = %d (%s)", retval, msg); @@ -228,10 +228,10 @@ void test_TriangleCount_Methods6(void) // LAGraph_TriangleCount_SandiaDot2 = 6, // sum (sum ((U * L') .* U)) retval = LAGr_TriangleCount(&ntriangles, G, LAGraph_TriangleCount_SandiaDot2 , &presort, msg); - TEST_CHECK(retval == LAGRAPH_PROPERTY_MISSING); // should fail (rowdegrees needs to be defined) + TEST_CHECK(retval == LAGRAPH_NOT_CACHED); // should fail (out_degrees needs to be defined) TEST_MSG("retval = %d (%s)", retval, msg); - retval = LAGraph_Property_RowDegree(G, msg); + retval = LAGraph_Cached_OutDegree(G, msg); TEST_CHECK(retval == 0); TEST_MSG("retval = %d (%s)", retval, msg); @@ -253,7 +253,7 @@ void test_TriangleCount(void) uint64_t ntriangles = 0UL; int retval = LAGraph_TriangleCount(&ntriangles, G, msg); - TEST_CHECK(retval == 0); // should not fail (rowdegrees will be calculated) + TEST_CHECK(retval == 0); // should not fail (out_degrees will be calculated) TEST_MSG("retval = %d (%s)", retval, msg); TEST_CHECK( ntriangles == 45 ); @@ -292,10 +292,10 @@ void test_TriangleCount_many (void) TEST_CHECK (A == NULL) ; // A has been moved into G->A // delete any diagonal entries - OK (LAGraph_DeleteDiag (G, msg)) ; - TEST_CHECK (G->ndiag == 0) ; - OK (LAGraph_DeleteDiag (G, msg)) ; - TEST_CHECK (G->ndiag == 0) ; + OK (LAGraph_DeleteSelfEdges (G, msg)) ; + TEST_CHECK (G->nself_edges == 0) ; + OK (LAGraph_DeleteSelfEdges (G, msg)) ; + TEST_CHECK (G->nself_edges == 0) ; // get the # of triangles uint64_t nt0, nt1 ; @@ -307,7 +307,7 @@ void test_TriangleCount_many (void) // convert to directed but with symmetric pattern G->kind = LAGraph_ADJACENCY_DIRECTED ; - G->structure_is_symmetric = LAGraph_TRUE ; + G->is_symmetric_structure = LAGraph_TRUE ; OK (LAGraph_TriangleCount (&nt1, G, msg)) ; TEST_CHECK (nt1 == ntriangles) ; @@ -358,10 +358,10 @@ void test_TriangleCount_autosort (void) OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_UNDIRECTED, msg)) ; TEST_CHECK (A == NULL) ; // A has been moved into G->A - OK (LAGraph_DeleteDiag (G, msg)) ; - TEST_CHECK (G->ndiag == 0) ; + OK (LAGraph_DeleteSelfEdges (G, msg)) ; + TEST_CHECK (G->nself_edges == 0) ; - OK (LAGraph_Property_RowDegree (G, msg)) ; + OK (LAGraph_Cached_OutDegree (G, msg)) ; // try each method GrB_Index nt1 = 0 ; @@ -409,7 +409,7 @@ void test_TriangleCount_brutal (void) OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_UNDIRECTED, msg)) ; // delete any diagonal entries - OK (LAGraph_DeleteDiag (G, msg)) ; + OK (LAGraph_DeleteSelfEdges (G, msg)) ; // get the # of triangles uint64_t nt0, nt1 ; @@ -422,7 +422,7 @@ void test_TriangleCount_brutal (void) // convert to directed but with symmetric pattern G->kind = LAGraph_ADJACENCY_DIRECTED ; - G->structure_is_symmetric = LAGraph_TRUE ; + G->is_symmetric_structure = LAGraph_TRUE ; LG_BRUTAL (LAGraph_TriangleCount (&nt1, G, msg)) ; TEST_CHECK (nt1 == ntriangles) ; diff --git a/src/test/test_Xinit.c b/src/test/test_Xinit.c index 3194392d32..7162080f8c 100644 --- a/src/test/test_Xinit.c +++ b/src/test/test_Xinit.c @@ -28,23 +28,24 @@ void test_Xinit (void) printf ("\nTesting LAGr_Init:\n") ; - TEST_CHECK (LAGr_Init (NULL, NULL, NULL, NULL, msg) + TEST_CHECK (LAGr_Init (GrB_NONBLOCKING, NULL, NULL, NULL, NULL, msg) == GrB_NULL_POINTER) ; printf ("msg: %s\n", msg) ; - TEST_CHECK (LAGr_Init (malloc, NULL, NULL, NULL, msg) + TEST_CHECK (LAGr_Init (GrB_NONBLOCKING, malloc, NULL, NULL, NULL, msg) == GrB_NULL_POINTER) ; printf ("msg: %s\n", msg) ; - TEST_CHECK (LAGr_Init (NULL, NULL, NULL, free, msg) + TEST_CHECK (LAGr_Init (GrB_NONBLOCKING, NULL, NULL, NULL, free, msg) == GrB_NULL_POINTER) ; printf ("msg: %s\n", msg) ; - OK (LAGr_Init (malloc, calloc, realloc, free, msg)) ; + OK (LAGr_Init (GrB_NONBLOCKING, malloc, calloc, realloc, free, msg)) ; printf ("msg: [%s]\n", msg) ; // LAGr_Init cannot be called twice - int status = LAGr_Init (malloc, calloc, realloc, free, msg) ; + int status = LAGr_Init (GrB_NONBLOCKING, + malloc, calloc, realloc, free, msg) ; TEST_CHECK (status != GrB_SUCCESS) ; printf ("msg: %s\n", msg) ; @@ -61,8 +62,9 @@ void test_Xinit_brutal (void) // no brutal memory failures, but test LG_brutal_malloc/calloc/realloc/free LG_brutal = -1 ; LG_nmalloc = 0 ; - OK (LAGr_Init (LG_brutal_malloc, LG_brutal_calloc, LG_brutal_realloc, - LG_brutal_free, msg)) ; + OK (LAGr_Init (GrB_NONBLOCKING, + LG_brutal_malloc, LG_brutal_calloc, LG_brutal_realloc, LG_brutal_free, + msg)) ; int32_t *p = LG_brutal_malloc (42 * sizeof (int32_t)) ; TEST_CHECK (p != NULL) ; @@ -124,7 +126,8 @@ void test_Xinit_brutal (void) { LG_brutal = nbrutal ; GB_Global_GrB_init_called_set (false) ; - int result = LAGr_Init (LG_brutal_malloc, LG_brutal_calloc, + int result = LAGr_Init (GrB_NONBLOCKING, + LG_brutal_malloc, LG_brutal_calloc, LG_brutal_realloc, LG_brutal_free, msg) ; if (result == 0) { diff --git a/src/test/test_minmax.c b/src/test/test_minmax.c index c081a6ecb3..f471e41007 100644 --- a/src/test/test_minmax.c +++ b/src/test/test_minmax.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// LAGraph/src/test/test_minmax.c: test LAGraph_Property_EMin/EMax +// LAGraph/src/test/test_minmax.c: test LAGraph_Cached_EMin/EMax //------------------------------------------------------------------------------ // LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. @@ -194,10 +194,10 @@ void test_minmax (void) // compute emin and emax //---------------------------------------------------------------------- - OK (LAGraph_Property_EMin (G, msg)) ; - TEST_CHECK (G->emin_kind == LAGraph_EXACT) ; - OK (LAGraph_Property_EMax (G, msg)) ; - TEST_CHECK (G->emax_kind == LAGraph_EXACT) ; + OK (LAGraph_Cached_EMin (G, msg)) ; + TEST_CHECK (G->emin_state == LAGraph_VALUE) ; + OK (LAGraph_Cached_EMax (G, msg)) ; + TEST_CHECK (G->emax_state == LAGraph_VALUE) ; //---------------------------------------------------------------------- // check the result @@ -285,10 +285,10 @@ void test_minmax_int64 (void) // compute emin and emax //------------------------------------------------------------------ - OK (LAGraph_Property_EMin (G, msg)) ; - TEST_CHECK (G->emin_kind == LAGraph_EXACT) ; - OK (LAGraph_Property_EMax (G, msg)) ; - TEST_CHECK (G->emax_kind == LAGraph_EXACT) ; + OK (LAGraph_Cached_EMin (G, msg)) ; + TEST_CHECK (G->emin_state == LAGraph_VALUE) ; + OK (LAGraph_Cached_EMax (G, msg)) ; + TEST_CHECK (G->emax_state == LAGraph_VALUE) ; //------------------------------------------------------------------ // check the result @@ -359,10 +359,10 @@ void test_minmax_uint64 (void) // compute emin and emax //---------------------------------------------------------------------- - OK (LAGraph_Property_EMin (G, msg)) ; - TEST_CHECK (G->emin_kind == LAGraph_EXACT) ; - OK (LAGraph_Property_EMax (G, msg)) ; - TEST_CHECK (G->emax_kind == LAGraph_EXACT) ; + OK (LAGraph_Cached_EMin (G, msg)) ; + TEST_CHECK (G->emin_state == LAGraph_VALUE) ; + OK (LAGraph_Cached_EMax (G, msg)) ; + TEST_CHECK (G->emax_state == LAGraph_VALUE) ; //---------------------------------------------------------------------- // check the result @@ -407,10 +407,10 @@ void test_minmax_failures (void) OK (GrB_Type_new (&MyInt, sizeof (myint))) ; OK (GrB_Matrix_new (&A, MyInt, 4, 4)) ; OK (LAGraph_New (&G, &A, LAGraph_ADJACENCY_DIRECTED, msg)) ; - int result = LAGraph_Property_EMax (G, msg) ; + int result = LAGraph_Cached_EMax (G, msg) ; printf ("\nresult: %d msg: %s\n", result, msg) ; TEST_CHECK (result == GrB_NOT_IMPLEMENTED) ; - result = LAGraph_Property_EMin (G, msg) ; + result = LAGraph_Cached_EMin (G, msg) ; printf ("result: %d msg: %s\n", result, msg) ; TEST_CHECK (result == GrB_NOT_IMPLEMENTED) ; OK (GrB_free (&MyInt)) ; diff --git a/src/utility/LAGr_Init.c b/src/utility/LAGr_Init.c index 55fe6367a5..aa997c8c95 100644 --- a/src/utility/LAGr_Init.c +++ b/src/utility/LAGr_Init.c @@ -19,6 +19,8 @@ // LAGraph global objects //------------------------------------------------------------------------------ +bool LG_init_has_been_called = false ; + // LAGraph_plus_first_T: using the GrB_PLUS_MONOID_T monoid and the // corresponding GrB_FIRST_T multiplicative operator. GrB_Semiring LAGraph_plus_first_int8 = NULL ; @@ -59,21 +61,21 @@ GrB_Semiring LAGraph_plus_one_fp32 = NULL ; GrB_Semiring LAGraph_plus_one_fp64 = NULL ; -// use LAGraph_structural_bool, etc +// use LAGraph_any_one_bool, etc -// LAGraph_structural_T: using the GrB_MIN_MONOID_T for non-boolean types +// LAGraph_any_one_T: using the GrB_MIN_MONOID_T for non-boolean types // or GrB_LOR_MONOID_BOOL for boolean, and the GrB_ONEB_T multiplicative op. -GrB_Semiring LAGraph_structural_bool = NULL ; -GrB_Semiring LAGraph_structural_int8 = NULL ; -GrB_Semiring LAGraph_structural_int16 = NULL ; -GrB_Semiring LAGraph_structural_int32 = NULL ; -GrB_Semiring LAGraph_structural_int64 = NULL ; -GrB_Semiring LAGraph_structural_uint8 = NULL ; -GrB_Semiring LAGraph_structural_uint16 = NULL ; -GrB_Semiring LAGraph_structural_uint32 = NULL ; -GrB_Semiring LAGraph_structural_uint64 = NULL ; -GrB_Semiring LAGraph_structural_fp32 = NULL ; -GrB_Semiring LAGraph_structural_fp64 = NULL ; +GrB_Semiring LAGraph_any_one_bool = NULL ; +GrB_Semiring LAGraph_any_one_int8 = NULL ; +GrB_Semiring LAGraph_any_one_int16 = NULL ; +GrB_Semiring LAGraph_any_one_int32 = NULL ; +GrB_Semiring LAGraph_any_one_int64 = NULL ; +GrB_Semiring LAGraph_any_one_uint8 = NULL ; +GrB_Semiring LAGraph_any_one_uint16 = NULL ; +GrB_Semiring LAGraph_any_one_uint32 = NULL ; +GrB_Semiring LAGraph_any_one_uint64 = NULL ; +GrB_Semiring LAGraph_any_one_fp32 = NULL ; +GrB_Semiring LAGraph_any_one_fp64 = NULL ; //------------------------------------------------------------------------------ // LAGr_Init @@ -83,6 +85,7 @@ LAGRAPH_PUBLIC int LAGr_Init ( // input: + GrB_Mode mode, // mode for GrB_Init or GxB_Init void * (* user_malloc_function ) (size_t), void * (* user_calloc_function ) (size_t, size_t), void * (* user_realloc_function ) (void *, size_t), @@ -101,13 +104,18 @@ int LAGr_Init LG_ASSERT (user_free_function != NULL, GrB_NULL_POINTER) ; GrB_Info info ; + // ensure LAGr_Init has not already been called + LG_ASSERT_MSG (!LG_init_has_been_called, GrB_INVALID_VALUE, + "LAGr*_Init can only be called once") ; + LG_init_has_been_called = true ; + //-------------------------------------------------------------------------- // start GraphBLAS //-------------------------------------------------------------------------- #if LAGRAPH_SUITESPARSE - info = GxB_init (GrB_NONBLOCKING, + info = GxB_init (mode, user_malloc_function, user_calloc_function, user_realloc_function, @@ -116,11 +124,11 @@ int LAGr_Init #else // GxB_init is not available. Use GrB_init instead. - info = GrB_init (GrB_NONBLOCKING) ; + info = GrB_init (mode) ; #endif - LG_ASSERT_MSG (info == GrB_SUCCESS, info, + LG_ASSERT_MSG (info == GrB_SUCCESS || info == GrB_INVALID_VALUE, info, "failed to initialize GraphBLAS") ; #undef LG_FREE_ALL @@ -138,6 +146,24 @@ int LAGr_Init LAGraph_Realloc_function = user_realloc_function ; LAGraph_Free_function = user_free_function ; + //-------------------------------------------------------------------------- + // set # of LAGraph threads + //-------------------------------------------------------------------------- + + LG_nthreads_hi = 1 ; // for LAGraph itself, if nested + // regions call GraphBLAS + #ifdef _OPENMP + LG_nthreads_lo = omp_get_max_threads ( ) ; // for lower-level parallelism + #else + LG_nthreads_lo = 1 ; + #endif + + #if LAGRAPH_SUITESPARSE + { + GRB_TRY (GxB_set (GxB_NTHREADS, LG_nthreads_lo)) ; + } + #endif + //-------------------------------------------------------------------------- // create global objects //-------------------------------------------------------------------------- @@ -228,7 +254,7 @@ int LAGr_Init GRB_TRY (GrB_Semiring_new (&LAGraph_plus_one_fp64, GrB_PLUS_MONOID_FP64 , GrB_ONEB_FP64 )) ; - // LAGraph_structural_T: using the GrB_MIN_MONOID_T for non-boolean types, + // LAGraph_any_one_T: using the GrB_MIN_MONOID_T for non-boolean types, // or GrB_LOR_MONOID_BOOL for boolean, and the GrB_ONEB_T multiplicative // operator. Given any matrices A and B, C = A*B when using this semiring // computes a matrix C whose values (for entries present) are all equal to @@ -244,27 +270,27 @@ int LAGr_Init // of 1, or true, and thus any of these monoids will compute the same // thing. - GRB_TRY (GrB_Semiring_new (&LAGraph_structural_bool, + GRB_TRY (GrB_Semiring_new (&LAGraph_any_one_bool, GrB_LOR_MONOID_BOOL , GrB_ONEB_BOOL )) ; - GRB_TRY (GrB_Semiring_new (&LAGraph_structural_int8, + GRB_TRY (GrB_Semiring_new (&LAGraph_any_one_int8, GrB_MIN_MONOID_INT8 , GrB_ONEB_INT8 )) ; - GRB_TRY (GrB_Semiring_new (&LAGraph_structural_int16, + GRB_TRY (GrB_Semiring_new (&LAGraph_any_one_int16, GrB_MIN_MONOID_INT16 , GrB_ONEB_INT16 )) ; - GRB_TRY (GrB_Semiring_new (&LAGraph_structural_int32, + GRB_TRY (GrB_Semiring_new (&LAGraph_any_one_int32, GrB_MIN_MONOID_INT32 , GrB_ONEB_INT32 )) ; - GRB_TRY (GrB_Semiring_new (&LAGraph_structural_int64, + GRB_TRY (GrB_Semiring_new (&LAGraph_any_one_int64, GrB_MIN_MONOID_INT64 , GrB_ONEB_INT64 )) ; - GRB_TRY (GrB_Semiring_new (&LAGraph_structural_uint8, + GRB_TRY (GrB_Semiring_new (&LAGraph_any_one_uint8, GrB_MIN_MONOID_UINT8 , GrB_ONEB_UINT8 )) ; - GRB_TRY (GrB_Semiring_new (&LAGraph_structural_uint16, + GRB_TRY (GrB_Semiring_new (&LAGraph_any_one_uint16, GrB_MIN_MONOID_UINT16 , GrB_ONEB_UINT16)) ; - GRB_TRY (GrB_Semiring_new (&LAGraph_structural_uint32, + GRB_TRY (GrB_Semiring_new (&LAGraph_any_one_uint32, GrB_MIN_MONOID_UINT32 , GrB_ONEB_UINT32)) ; - GRB_TRY (GrB_Semiring_new (&LAGraph_structural_uint64, + GRB_TRY (GrB_Semiring_new (&LAGraph_any_one_uint64, GrB_MIN_MONOID_UINT64 , GrB_ONEB_UINT64)) ; - GRB_TRY (GrB_Semiring_new (&LAGraph_structural_fp32, + GRB_TRY (GrB_Semiring_new (&LAGraph_any_one_fp32, GrB_MIN_MONOID_FP32 , GrB_ONEB_FP32 )) ; - GRB_TRY (GrB_Semiring_new (&LAGraph_structural_fp64, + GRB_TRY (GrB_Semiring_new (&LAGraph_any_one_fp64, GrB_MIN_MONOID_FP64 , GrB_ONEB_FP64 )) ; return (GrB_SUCCESS) ; diff --git a/src/utility/LAGraph_Property_AT.c b/src/utility/LAGraph_Cached_AT.c similarity index 84% rename from src/utility/LAGraph_Property_AT.c rename to src/utility/LAGraph_Cached_AT.c index 5b96267121..6fa52033ab 100644 --- a/src/utility/LAGraph_Property_AT.c +++ b/src/utility/LAGraph_Cached_AT.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// LAGraph_Property_AT: construct G->AT for a graph +// LAGraph_Cached_AT: construct G->AT for a graph //------------------------------------------------------------------------------ // LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. @@ -15,7 +15,7 @@ #include "LG_internal.h" -int LAGraph_Property_AT +int LAGraph_Cached_AT ( // input/output: LAGraph_Graph G, // graph for which to compute G->AT @@ -30,14 +30,19 @@ int LAGraph_Property_AT GrB_Matrix AT = NULL ; LG_CLEAR_MSG_AND_BASIC_ASSERT (G, msg) ; GrB_Matrix A = G->A ; - LAGraph_Kind kind = G->kind ; - if (G->AT != NULL || kind == LAGraph_ADJACENCY_UNDIRECTED) + if (G->AT != NULL) { - // G->AT already computed, or not needed since A is symmetric + // G->AT already computed return (GrB_SUCCESS) ; } + if (G->kind == LAGraph_ADJACENCY_UNDIRECTED) + { + // G->AT not needed since A is symmetric (warning only, not an error) + return (LAGRAPH_CACHE_NOT_NEEDED) ; + } + //-------------------------------------------------------------------------- // G->AT = (G->A)' //-------------------------------------------------------------------------- diff --git a/src/utility/LAGraph_Property_EMax.c b/src/utility/LAGraph_Cached_EMax.c similarity index 95% rename from src/utility/LAGraph_Property_EMax.c rename to src/utility/LAGraph_Cached_EMax.c index 5c0c0cdc69..9e584fc55c 100644 --- a/src/utility/LAGraph_Property_EMax.c +++ b/src/utility/LAGraph_Cached_EMax.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// LAGraph_Property_EMax: determine G->emax +// LAGraph_Cached_EMax: determine G->emax //------------------------------------------------------------------------------ // LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. @@ -18,7 +18,7 @@ #include "LG_internal.h" -int LAGraph_Property_EMax +int LAGraph_Cached_EMax ( // input/output: LAGraph_Graph G, // graph to determine G->emax @@ -38,7 +38,7 @@ int LAGraph_Property_EMax return (GrB_SUCCESS) ; } - G->emax_kind = LAGRAPH_UNKNOWN ; + G->emax_state = LAGRAPH_UNKNOWN ; //-------------------------------------------------------------------------- // determine the type of G->A and the corresponding max monoid @@ -71,7 +71,7 @@ int LAGraph_Property_EMax GRB_TRY (GrB_Scalar_new (&(G->emax), atype)) ; GRB_TRY (GrB_reduce (G->emax, NULL, monoid, G->A, NULL)) ; - G->emax_kind = LAGraph_EXACT ; + G->emax_state = LAGraph_VALUE ; return (GrB_SUCCESS) ; } diff --git a/src/utility/LAGraph_Property_EMin.c b/src/utility/LAGraph_Cached_EMin.c similarity index 95% rename from src/utility/LAGraph_Property_EMin.c rename to src/utility/LAGraph_Cached_EMin.c index ced34ae727..823efae0a7 100644 --- a/src/utility/LAGraph_Property_EMin.c +++ b/src/utility/LAGraph_Cached_EMin.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// LAGraph_Property_EMin: determine G->emin +// LAGraph_Cached_EMin: determine G->emin //------------------------------------------------------------------------------ // LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. @@ -18,7 +18,7 @@ #include "LG_internal.h" -int LAGraph_Property_EMin +int LAGraph_Cached_EMin ( // input/output: LAGraph_Graph G, // graph to determine G->emin @@ -38,7 +38,7 @@ int LAGraph_Property_EMin return (GrB_SUCCESS) ; } - G->emin_kind = LAGRAPH_UNKNOWN ; + G->emin_state = LAGRAPH_UNKNOWN ; //-------------------------------------------------------------------------- // determine the type of G->A and the corresponding min monoid @@ -71,7 +71,7 @@ int LAGraph_Property_EMin GRB_TRY (GrB_Scalar_new (&(G->emin), atype)) ; GRB_TRY (GrB_reduce (G->emin, NULL, monoid, G->A, NULL)) ; - G->emin_kind = LAGraph_EXACT ; + G->emin_state = LAGraph_VALUE ; return (GrB_SUCCESS) ; } diff --git a/src/utility/LAGraph_Property_ColDegree.c b/src/utility/LAGraph_Cached_InDegree.c similarity index 65% rename from src/utility/LAGraph_Property_ColDegree.c rename to src/utility/LAGraph_Cached_InDegree.c index 1c25df29e8..53fba43e5f 100644 --- a/src/utility/LAGraph_Property_ColDegree.c +++ b/src/utility/LAGraph_Cached_InDegree.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// LAGraph_Property_ColDegree: determine G->coldegree +// LAGraph_Cached_InDegree: determine G->in_degree //------------------------------------------------------------------------------ // LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. @@ -11,13 +11,13 @@ //------------------------------------------------------------------------------ -// LAGraph_Property_ColDegree computes G->coldegree, where G->coldegree(j) is +// LAGraph_Cached_InDegree computes G->in_degree, where G->in_degree(j) is // the number of entries in G->A (:,j). If there are no entries in G->A (:,j), -// G->coldgree(j) is not present in the structure of G->coldegree. That is, -// G->coldegree contains no explicit zero entries. +// G->coldgree(j) is not present in the structure of G->in_degree. That is, +// G->in_degree contains no explicit zero entries. -// G->coldegree is not computed if the graph is undirected. Use G->rowdegree -// instead, and LAGraph_Property_RowDegree. +// G->in_degree is not computed if the graph is undirected. Use G->out_degree +// instead, and LAGraph_Cached_OutDegree. #define LG_FREE_WORK \ { \ @@ -28,15 +28,15 @@ #define LG_FREE_ALL \ { \ LG_FREE_WORK ; \ - GrB_free (&coldegree) ; \ + GrB_free (&in_degree) ; \ } #include "LG_internal.h" -int LAGraph_Property_ColDegree +int LAGraph_Cached_InDegree ( // input/output: - LAGraph_Graph G, // graph to determine G->coldegree + LAGraph_Graph G, // graph to determine G->in_degree char *msg ) { @@ -46,15 +46,21 @@ int LAGraph_Property_ColDegree //-------------------------------------------------------------------------- GrB_Matrix S = NULL ; - GrB_Vector coldegree = NULL, x = NULL ; + GrB_Vector in_degree = NULL, x = NULL ; LG_CLEAR_MSG_AND_BASIC_ASSERT (G, msg) ; - if (G->coldegree != NULL || G->kind == LAGraph_ADJACENCY_UNDIRECTED) + if (G->in_degree != NULL) { - // G->coldegree already computed, or not needed + // G->in_degree already computed return (GrB_SUCCESS) ; } + if (G->kind == LAGraph_ADJACENCY_UNDIRECTED) + { + // G->in_degree is not computed since A is symmetric (warning only) + return (LAGRAPH_CACHE_NOT_NEEDED) ; + } + //-------------------------------------------------------------------------- // determine the size of A //-------------------------------------------------------------------------- @@ -66,29 +72,29 @@ int LAGraph_Property_ColDegree GRB_TRY (GrB_Matrix_ncols (&ncols, A)) ; //-------------------------------------------------------------------------- - // compute the coldegree + // compute the in_degree //-------------------------------------------------------------------------- - GRB_TRY (GrB_Vector_new (&coldegree, GrB_INT64, ncols)) ; + GRB_TRY (GrB_Vector_new (&in_degree, GrB_INT64, ncols)) ; // x = zeros (nrows,1) GRB_TRY (GrB_Vector_new (&x, GrB_INT64, nrows)) ; GRB_TRY (GrB_assign (x, NULL, NULL, 0, GrB_ALL, nrows, NULL)) ; if (AT != NULL) { - // G->coldegree = row degree of AT; this will be faster assuming + // G->in_degree = row degree of AT; this will be faster assuming // AT is held in a row-oriented format. - GRB_TRY (GrB_mxv (coldegree, NULL, NULL, LAGraph_plus_one_int64, + GRB_TRY (GrB_mxv (in_degree, NULL, NULL, LAGraph_plus_one_int64, AT, x, NULL)) ; } else { - // G->coldegree = column degree of A - GRB_TRY (GrB_mxv (coldegree, NULL, NULL, LAGraph_plus_one_int64, + // G->in_degree = column degree of A + GRB_TRY (GrB_mxv (in_degree, NULL, NULL, LAGraph_plus_one_int64, A, x, GrB_DESC_T0)) ; } - G->coldegree = coldegree ; + G->in_degree = in_degree ; LG_FREE_WORK ; return (GrB_SUCCESS) ; diff --git a/src/utility/LAGraph_Property_SymmetricStructure.c b/src/utility/LAGraph_Cached_IsSymmetricStructure.c similarity index 84% rename from src/utility/LAGraph_Property_SymmetricStructure.c rename to src/utility/LAGraph_Cached_IsSymmetricStructure.c index 25e0e44d47..da7368027f 100644 --- a/src/utility/LAGraph_Property_SymmetricStructure.c +++ b/src/utility/LAGraph_Cached_IsSymmetricStructure.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// LAGraph_Property_SymmetricStructure: determine G->structure_is_symmetric +// LAGraph_Cached_IsSymmetricStructure: determine G->is_symmetric_structure //------------------------------------------------------------------------------ // LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. @@ -23,7 +23,7 @@ #include "LG_internal.h" -int LAGraph_Property_SymmetricStructure +int LAGraph_Cached_IsSymmetricStructure ( // input/output: LAGraph_Graph G, // graph to determine the symmetry of structure of A @@ -38,17 +38,16 @@ int LAGraph_Property_SymmetricStructure GrB_Matrix C = NULL, S1 = NULL, S2 = NULL ; LG_CLEAR_MSG_AND_BASIC_ASSERT (G, msg) ; - LAGraph_Kind kind = G->kind ; - if (kind == LAGraph_ADJACENCY_UNDIRECTED) + if (G->kind == LAGraph_ADJACENCY_UNDIRECTED) { // assume A is symmetric for an undirected graph - G->structure_is_symmetric = true ; + G->is_symmetric_structure = LAGraph_TRUE ; return (GrB_SUCCESS) ; } - if (G->structure_is_symmetric != LAGRAPH_UNKNOWN) + if (G->is_symmetric_structure != LAGRAPH_UNKNOWN) { - // symmetric property is already known + // cached symmetric property is already known return (GrB_SUCCESS) ; } @@ -63,7 +62,7 @@ int LAGraph_Property_SymmetricStructure if (n != ncols) { // A is rectangular and thus cannot be symmetric - G->structure_is_symmetric = false ; + G->is_symmetric_structure = LAGraph_FALSE ; return (GrB_SUCCESS) ; } @@ -73,7 +72,7 @@ int LAGraph_Property_SymmetricStructure if (G->AT == NULL) { - LG_TRY (LAGraph_Property_AT (G, msg)) ; + LG_TRY (LAGraph_Cached_AT (G, msg)) ; } //-------------------------------------------------------------------------- @@ -88,7 +87,8 @@ int LAGraph_Property_SymmetricStructure GrB_Index nvals1, nvals2 ; GRB_TRY (GrB_Matrix_nvals (&nvals1, C)) ; GRB_TRY (GrB_Matrix_nvals (&nvals2, A)) ; - G->structure_is_symmetric = (nvals1 == nvals2) ; + G->is_symmetric_structure = + (nvals1 == nvals2) ? LAGraph_TRUE : LAGraph_FALSE ; //-------------------------------------------------------------------------- // free workspace and return result diff --git a/src/utility/LAGraph_Property_NDiag.c b/src/utility/LAGraph_Cached_NSelfEdges.c similarity index 78% rename from src/utility/LAGraph_Property_NDiag.c rename to src/utility/LAGraph_Cached_NSelfEdges.c index b62d0b6787..64f5d82a70 100644 --- a/src/utility/LAGraph_Property_NDiag.c +++ b/src/utility/LAGraph_Cached_NSelfEdges.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// LAGraph_Property_NDiag: count the # of diagonal entries of a graph +// LAGraph_Cached_NSelfEdges: count the # of diagonal entries of a graph //------------------------------------------------------------------------------ // LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. @@ -13,10 +13,10 @@ #include "LG_internal.h" -int LAGraph_Property_NDiag +int LAGraph_Cached_NSelfEdges ( // input/output: - LAGraph_Graph G, // graph to compute G->ndiag + LAGraph_Graph G, // graph to compute G->nself_edges char *msg ) { @@ -28,15 +28,15 @@ int LAGraph_Property_NDiag LG_CLEAR_MSG_AND_BASIC_ASSERT (G, msg) ; // already computed - if (G->ndiag != LAGRAPH_UNKNOWN) + if (G->nself_edges != LAGRAPH_UNKNOWN) { return (GrB_SUCCESS) ; } //-------------------------------------------------------------------------- - // compute G->ndiag + // compute G->nself_edges //-------------------------------------------------------------------------- - return (LG_ndiag (&G->ndiag, G->A, msg)) ; + return (LG_nself_edges (&G->nself_edges, G->A, msg)) ; } diff --git a/src/utility/LAGraph_Property_RowDegree.c b/src/utility/LAGraph_Cached_OutDegree.c similarity index 73% rename from src/utility/LAGraph_Property_RowDegree.c rename to src/utility/LAGraph_Cached_OutDegree.c index f45dad1c78..1a76320108 100644 --- a/src/utility/LAGraph_Property_RowDegree.c +++ b/src/utility/LAGraph_Cached_OutDegree.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// LAGraph_Property_RowDegree: determine G->rowdegree +// LAGraph_Cached_OutDegree: determine G->out_degree //------------------------------------------------------------------------------ // LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. @@ -11,10 +11,10 @@ //------------------------------------------------------------------------------ -// LAGraph_Property_RowDegree computes G->rowdegree, where G->rowdegree(i) is +// LAGraph_Cached_OutDegree computes G->out_degree, where G->out_degree(i) is // the number of entries in G->A (i,:). If there are no entries in G->A (i,:), -// G->rowdgree(i) is not present in the structure of G->rowdegree. That is, -// G->rowdegree contains no explicit zero entries. +// G->rowdgree(i) is not present in the structure of G->out_degree. That is, +// G->out_degree contains no explicit zero entries. #define LG_FREE_WORK \ { \ @@ -24,15 +24,15 @@ #define LG_FREE_ALL \ { \ LG_FREE_WORK ; \ - GrB_free (&rowdegree) ; \ + GrB_free (&out_degree) ; \ } #include "LG_internal.h" -int LAGraph_Property_RowDegree +int LAGraph_Cached_OutDegree ( // input/output: - LAGraph_Graph G, // graph to determine G->rowdegree + LAGraph_Graph G, // graph to determine G->out_degree char *msg ) { @@ -41,12 +41,12 @@ int LAGraph_Property_RowDegree // clear msg and check G //-------------------------------------------------------------------------- - GrB_Vector rowdegree = NULL, x = NULL ; + GrB_Vector out_degree = NULL, x = NULL ; LG_CLEAR_MSG_AND_BASIC_ASSERT (G, msg) ; - if (G->rowdegree != NULL) + if (G->out_degree != NULL) { - // G->rowdegree already computed + // G->out_degree already computed return (GrB_SUCCESS) ; } @@ -60,18 +60,18 @@ int LAGraph_Property_RowDegree GRB_TRY (GrB_Matrix_ncols (&ncols, A)) ; //-------------------------------------------------------------------------- - // compute the rowdegree + // compute the out_degree //-------------------------------------------------------------------------- - GRB_TRY (GrB_Vector_new (&rowdegree, GrB_INT64, nrows)) ; + GRB_TRY (GrB_Vector_new (&out_degree, GrB_INT64, nrows)) ; // x = zeros (ncols,1) GRB_TRY (GrB_Vector_new (&x, GrB_INT64, ncols)) ; GRB_TRY (GrB_assign (x, NULL, NULL, 0, GrB_ALL, ncols, NULL)) ; - GRB_TRY (GrB_mxv (rowdegree, NULL, NULL, LAGraph_plus_one_int64, + GRB_TRY (GrB_mxv (out_degree, NULL, NULL, LAGraph_plus_one_int64, A, x, NULL)) ; - G->rowdegree = rowdegree ; + G->out_degree = out_degree ; LG_FREE_WORK ; return (GrB_SUCCESS) ; diff --git a/src/utility/LAGraph_CheckGraph.c b/src/utility/LAGraph_CheckGraph.c index 0b0f30959b..e52a63cafb 100644 --- a/src/utility/LAGraph_CheckGraph.c +++ b/src/utility/LAGraph_CheckGraph.c @@ -81,32 +81,32 @@ int LAGraph_CheckGraph LAGRAPH_INVALID_GRAPH, "A and AT must have the same type") ; } - GrB_Vector rowdegree = G->rowdegree ; - if (rowdegree != NULL) + GrB_Vector out_degree = G->out_degree ; + if (out_degree != NULL) { GrB_Index m ; - GRB_TRY (GrB_Vector_size (&m, rowdegree)) ; + GRB_TRY (GrB_Vector_size (&m, out_degree)) ; LG_ASSERT_MSG (m == nrows, LAGRAPH_INVALID_GRAPH, - "rowdegree invalid size") ; + "out_degree invalid size") ; char rtype [LAGRAPH_MAX_NAME_LEN] ; - LG_TRY (LAGraph_Vector_TypeName (rtype, rowdegree, msg)) ; + LG_TRY (LAGraph_Vector_TypeName (rtype, out_degree, msg)) ; LG_ASSERT_MSG (MATCHNAME (rtype, "int64_t"), LAGRAPH_INVALID_GRAPH, - "rowdegree has wrong type; must be GrB_INT64") ; + "out_degree has wrong type; must be GrB_INT64") ; } - GrB_Vector coldegree = G->coldegree ; - if (coldegree != NULL) + GrB_Vector in_degree = G->in_degree ; + if (in_degree != NULL) { GrB_Index n ; - GRB_TRY (GrB_Vector_size (&n, coldegree)) ; + GRB_TRY (GrB_Vector_size (&n, in_degree)) ; LG_ASSERT_MSG (n == ncols, LAGRAPH_INVALID_GRAPH, - "coldegree invalid size") ; + "in_degree invalid size") ; char ctype [LAGRAPH_MAX_NAME_LEN] ; - LG_TRY (LAGraph_Vector_TypeName (ctype, coldegree, msg)) ; + LG_TRY (LAGraph_Vector_TypeName (ctype, in_degree, msg)) ; LG_ASSERT_MSG (MATCHNAME (ctype, "int64_t"), LAGRAPH_INVALID_GRAPH, - "coldegree has wrong type; must be GrB_INT64") ; + "in_degree has wrong type; must be GrB_INT64") ; } return (GrB_SUCCESS) ; diff --git a/src/utility/LAGraph_Delete.c b/src/utility/LAGraph_Delete.c index e7335f9bdf..46dd757c94 100644 --- a/src/utility/LAGraph_Delete.c +++ b/src/utility/LAGraph_Delete.c @@ -40,7 +40,7 @@ int LAGraph_Delete // free the cached contents of the graph //-------------------------------------------------------------------------- - LG_TRY (LAGraph_DeleteProperties (*G, msg)) ; + LG_TRY (LAGraph_DeleteCached (*G, msg)) ; //-------------------------------------------------------------------------- // delete the primary contents of the graph, and the graph itself diff --git a/src/utility/LAGraph_DeleteProperties.c b/src/utility/LAGraph_DeleteCached.c similarity index 75% rename from src/utility/LAGraph_DeleteProperties.c rename to src/utility/LAGraph_DeleteCached.c index dad40acd72..be7ad62018 100644 --- a/src/utility/LAGraph_DeleteProperties.c +++ b/src/utility/LAGraph_DeleteCached.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// LAGraph_DeleteProperties: deletes the cached properties of a graph +// LAGraph_DeleteCached: deletes the cached properties of a graph //------------------------------------------------------------------------------ // LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. @@ -13,7 +13,7 @@ #include "LG_internal.h" -int LAGraph_DeleteProperties +int LAGraph_DeleteCached ( // input/output: LAGraph_Graph G, // G stays valid, only cached properties are freed @@ -37,19 +37,21 @@ int LAGraph_DeleteProperties //-------------------------------------------------------------------------- GRB_TRY (GrB_free (&(G->AT))) ; - GRB_TRY (GrB_free (&(G->rowdegree))) ; - GRB_TRY (GrB_free (&(G->coldegree))) ; + GRB_TRY (GrB_free (&(G->out_degree))) ; + GRB_TRY (GrB_free (&(G->in_degree))) ; GRB_TRY (GrB_free (&(G->emin))) ; GRB_TRY (GrB_free (&(G->emax))) ; //-------------------------------------------------------------------------- - // clear the scalar properties of the graph + // clear the cached scalar properties of the graph //-------------------------------------------------------------------------- - G->structure_is_symmetric = LAGRAPH_UNKNOWN ; - G->emin_kind = LAGRAPH_UNKNOWN ; - G->emax_kind = LAGRAPH_UNKNOWN ; -// G->nonzero = LAGRAPH_UNKNOWN ; - G->ndiag = LAGRAPH_UNKNOWN ; + G->is_symmetric_structure = + (G->kind == LAGraph_ADJACENCY_UNDIRECTED) + ? LAGraph_TRUE + : LAGRAPH_UNKNOWN ; + G->emin_state = LAGRAPH_UNKNOWN ; + G->emax_state = LAGRAPH_UNKNOWN ; + G->nself_edges = LAGRAPH_UNKNOWN ; return (GrB_SUCCESS) ; } diff --git a/src/utility/LAGraph_DeleteDiag.c b/src/utility/LAGraph_DeleteSelfEdges.c similarity index 73% rename from src/utility/LAGraph_DeleteDiag.c rename to src/utility/LAGraph_DeleteSelfEdges.c index f7b8178196..d8de4ade18 100644 --- a/src/utility/LAGraph_DeleteDiag.c +++ b/src/utility/LAGraph_DeleteSelfEdges.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// LAGraph_DeleteDiag: removes the diagonal entries from G->A +// LAGraph_DeleteSelfEdges: removes the diagonal entries from G->A //------------------------------------------------------------------------------ // LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. @@ -13,10 +13,10 @@ #include "LG_internal.h" -int LAGraph_DeleteDiag +int LAGraph_DeleteSelfEdges ( // input/output: - LAGraph_Graph G, // diagonal entries removed, most properties cleared + LAGraph_Graph G, // diagonal entries removed, most cached properties cleared char *msg ) { @@ -26,19 +26,19 @@ int LAGraph_DeleteDiag //-------------------------------------------------------------------------- LG_CLEAR_MSG_AND_BASIC_ASSERT (G, msg) ; - if (G->ndiag == 0) + if (G->nself_edges == 0) { // nothing to do return (GrB_SUCCESS) ; } //-------------------------------------------------------------------------- - // delete all properties not affected by the removal of the diagonal + // delete all cached properties not affected by the removal of the diagonal //-------------------------------------------------------------------------- - LAGraph_BooleanProperty structure_is_symmetric = G->structure_is_symmetric ; - LG_TRY (LAGraph_DeleteProperties (G, msg)) ; - G->structure_is_symmetric = structure_is_symmetric ; + LAGraph_Boolean is_symmetric_structure = G->is_symmetric_structure ; + LG_TRY (LAGraph_DeleteCached (G, msg)) ; + G->is_symmetric_structure = is_symmetric_structure ; //-------------------------------------------------------------------------- // remove diagonal entries @@ -47,10 +47,10 @@ int LAGraph_DeleteDiag GRB_TRY (GrB_select (G->A, NULL, NULL, GrB_OFFDIAG, G->A, 0, NULL)) ; //-------------------------------------------------------------------------- - // free workspace, G->ndiag now known to be zero + // free workspace, G->nself_edges now known to be zero //-------------------------------------------------------------------------- - G->ndiag = 0 ; + G->nself_edges = 0 ; return (GrB_SUCCESS) ; } diff --git a/src/utility/LAGraph_DisplayGraph.c b/src/utility/LAGraph_DisplayGraph.c index 9fb9ebe2e4..4d13fbb026 100644 --- a/src/utility/LAGraph_DisplayGraph.c +++ b/src/utility/LAGraph_DisplayGraph.c @@ -50,19 +50,22 @@ int LAGraph_DisplayGraph LG_TRY (LAGraph_Matrix_TypeName (typename, A, msg)) ; LG_TRY (LAGraph_KindName (kindname, kind, msg)) ; - // print the basic scalar properties + // print the basic cached scalar properties FPRINTF (f, "Graph: kind: %s, nodes: %g entries: %g type: %s\n", kindname, (double)n, (double)nvals, typename) ; // print the scalar cached properties FPRINTF (f, " structural symmetry: ") ; - switch (G->structure_is_symmetric) + switch (G->is_symmetric_structure) { case LAGraph_FALSE : FPRINTF (f, "unsymmetric") ; break ; case LAGraph_TRUE : FPRINTF (f, "symmetric") ; break ; default : FPRINTF (f, "unknown") ; break ; } - if (G->ndiag >= 0) FPRINTF (f, " self-edges: %g", (double) G->ndiag) ; + if (G->nself_edges >= 0) + { + FPRINTF (f, " self-edges: %g", (double) G->nself_edges) ; + } FPRINTF (f, "\n") ; FPRINTF (f, " adjacency matrix: ") ; @@ -81,18 +84,18 @@ int LAGraph_DisplayGraph LG_TRY (LAGraph_Matrix_Print (AT, pr2, stdout, msg)) ; } - GrB_Vector rowdegree = G->rowdegree ; - if (rowdegree != NULL) + GrB_Vector out_degree = G->out_degree ; + if (out_degree != NULL) { - FPRINTF (f, " row degree: ") ; - LG_TRY (LAGraph_Vector_Print (rowdegree, pr2, stdout, msg)) ; + FPRINTF (f, " out degree: ") ; + LG_TRY (LAGraph_Vector_Print (out_degree, pr2, stdout, msg)) ; } - GrB_Vector coldegree = G->coldegree ; - if (coldegree != NULL) + GrB_Vector in_degree = G->in_degree ; + if (in_degree != NULL) { - FPRINTF (f, " column degree: ") ; - LG_TRY (LAGraph_Vector_Print (coldegree, pr2, stdout, msg)) ; + FPRINTF (f, " in degree: ") ; + LG_TRY (LAGraph_Vector_Print (in_degree, pr2, stdout, msg)) ; } return (GrB_SUCCESS) ; diff --git a/src/utility/LAGraph_Finalize.c b/src/utility/LAGraph_Finalize.c index b725aad59b..c4f265ec87 100644 --- a/src/utility/LAGraph_Finalize.c +++ b/src/utility/LAGraph_Finalize.c @@ -59,17 +59,17 @@ int LAGraph_Finalize (char *msg) GRB_TRY (GrB_Semiring_free (&LAGraph_plus_one_fp32 )) ; GRB_TRY (GrB_Semiring_free (&LAGraph_plus_one_fp64 )) ; - GRB_TRY (GrB_Semiring_free (&LAGraph_structural_bool )) ; - GRB_TRY (GrB_Semiring_free (&LAGraph_structural_int8 )) ; - GRB_TRY (GrB_Semiring_free (&LAGraph_structural_int16 )) ; - GRB_TRY (GrB_Semiring_free (&LAGraph_structural_int32 )) ; - GRB_TRY (GrB_Semiring_free (&LAGraph_structural_int64 )) ; - GRB_TRY (GrB_Semiring_free (&LAGraph_structural_uint8 )) ; - GRB_TRY (GrB_Semiring_free (&LAGraph_structural_uint16)) ; - GRB_TRY (GrB_Semiring_free (&LAGraph_structural_uint32)) ; - GRB_TRY (GrB_Semiring_free (&LAGraph_structural_uint64)) ; - GRB_TRY (GrB_Semiring_free (&LAGraph_structural_fp32 )) ; - GRB_TRY (GrB_Semiring_free (&LAGraph_structural_fp64 )) ; + GRB_TRY (GrB_Semiring_free (&LAGraph_any_one_bool )) ; + GRB_TRY (GrB_Semiring_free (&LAGraph_any_one_int8 )) ; + GRB_TRY (GrB_Semiring_free (&LAGraph_any_one_int16 )) ; + GRB_TRY (GrB_Semiring_free (&LAGraph_any_one_int32 )) ; + GRB_TRY (GrB_Semiring_free (&LAGraph_any_one_int64 )) ; + GRB_TRY (GrB_Semiring_free (&LAGraph_any_one_uint8 )) ; + GRB_TRY (GrB_Semiring_free (&LAGraph_any_one_uint16)) ; + GRB_TRY (GrB_Semiring_free (&LAGraph_any_one_uint32)) ; + GRB_TRY (GrB_Semiring_free (&LAGraph_any_one_uint64)) ; + GRB_TRY (GrB_Semiring_free (&LAGraph_any_one_fp32 )) ; + GRB_TRY (GrB_Semiring_free (&LAGraph_any_one_fp64 )) ; //-------------------------------------------------------------------------- // finalize GraphBLAS diff --git a/src/utility/LAGraph_GetNumThreads.c b/src/utility/LAGraph_GetNumThreads.c index 8df8247ec9..45e8c6218e 100644 --- a/src/utility/LAGraph_GetNumThreads.c +++ b/src/utility/LAGraph_GetNumThreads.c @@ -18,38 +18,25 @@ int LAGraph_GetNumThreads ( // output: - int *nthreads, // # of threads to use + int *nthreads_hi, + int *nthreads_lo, char *msg ) { - //--------------------------------------------------------------------------- - // check inputs - //--------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- LG_CLEAR_MSG ; - LG_ASSERT (nthreads != NULL, GrB_NULL_POINTER) ; - - //--------------------------------------------------------------------------- - // get number of threads - //--------------------------------------------------------------------------- - - #if LAGRAPH_SUITESPARSE - { - // SuiteSparse:GraphBLAS: get # of threads from global setting - GRB_TRY (GxB_get (GxB_NTHREADS, nthreads)) ; - } - #elif defined ( _OPENMP ) - { - // get # of threads from OpenMP global setting - (*nthreads) = omp_get_max_threads ( ) ; - } - #else - { - // single-threaded if not using SuiteSparse:GraphBLAS or OpenMP - (*nthreads) = 1 ; - } - #endif + LG_ASSERT (nthreads_hi != NULL && nthreads_lo != NULL, GrB_NULL_POINTER) ; + + //-------------------------------------------------------------------------- + // get number of threads + //-------------------------------------------------------------------------- + + (*nthreads_hi) = LG_nthreads_hi ; + (*nthreads_lo) = LG_nthreads_lo ; return (GrB_SUCCESS) ; } diff --git a/src/utility/LAGraph_Global.c b/src/utility/LAGraph_Global.c index fd12730caf..6056da63df 100644 --- a/src/utility/LAGraph_Global.c +++ b/src/utility/LAGraph_Global.c @@ -13,10 +13,29 @@ #include "LG_internal.h" -// These are modified by LAGraph_Init and LAGr_Init. +//------------------------------------------------------------------------------ +// memory management +//------------------------------------------------------------------------------ +// These are modified by LAGraph_Init and LAGr_Init: void * (* LAGraph_Malloc_function ) (size_t) = malloc ; void * (* LAGraph_Calloc_function ) (size_t, size_t) = calloc ; void * (* LAGraph_Realloc_function ) (void *, size_t) = realloc ; void (* LAGraph_Free_function ) (void *) = free ; +//------------------------------------------------------------------------------ +// threading control +//------------------------------------------------------------------------------ + +// These are initialized by LAGraph_Init and LAGr_Init, modified by +// LAGraph_SetNumThreads and accessed by LAGraph_GetNumThreads. +// They are not intendend to be directly access by the end user. + +int LG_nthreads_hi ; // # of threads to use at the higher level of a nested + // parallel region in LAGraph. Default: 1. + +int LG_nthreads_lo ; // # of threads to use at the lower level of a nested + // parallel region, or to use inside GraphBLAS. + // Default: the value obtained by omp_get_max_threads + // if OpenMP is in use, or 1 otherwise. + diff --git a/src/utility/LAGraph_Init.c b/src/utility/LAGraph_Init.c index 717cc6387d..e534b10568 100644 --- a/src/utility/LAGraph_Init.c +++ b/src/utility/LAGraph_Init.c @@ -18,6 +18,6 @@ int LAGraph_Init (char *msg) LG_CLEAR_MSG ; - // use ANSI C memory allocation functions - return (LAGr_Init (malloc, calloc, realloc, free, msg)) ; + // use GraphBLAS nonblocking mode, and ANSI C memory allocation functions + return (LAGr_Init (GrB_NONBLOCKING, malloc, calloc, realloc, free, msg)) ; } diff --git a/src/utility/LAGraph_MMWrite.c b/src/utility/LAGraph_MMWrite.c index 28b5cc387d..933aaa97b3 100644 --- a/src/utility/LAGraph_MMWrite.c +++ b/src/utility/LAGraph_MMWrite.c @@ -448,10 +448,10 @@ int LAGraph_MMWrite if (!is_general) { // count the entries on the diagonal - int64_t ndiag = 0 ; - LG_TRY (LG_ndiag (&ndiag, A, msg)) ; + int64_t nself_edges = 0 ; + LG_TRY (LG_nself_edges (&nself_edges, A, msg)) ; // nvals_to_print = # of entries in tril(A), including diagonal - nvals_to_print = ndiag + (nvals - ndiag) / 2 ; + nvals_to_print = nself_edges + (nvals - nself_edges) / 2 ; } FPRINTF (f, "%" PRIu64 " %" PRIu64 " %" PRIu64 "\n", @@ -475,8 +475,6 @@ int LAGraph_MMWrite { K [k] = k ; } - int nthreads ; - LG_TRY (LAGraph_GetNumThreads (&nthreads, msg)) ; GrB_Index nvals_printed = 0 ; bool coord = (MM_fmt == MM_coordinate) ; @@ -487,7 +485,7 @@ int LAGraph_MMWrite LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (ctype), msg)) ;\ GRB_TRY (GrB_Matrix_extractTuples (I, J, X, &nvals, A)) ; \ LG_TRY (LAGraph_Sort3 ((int64_t *) J, (int64_t *) I, \ - (int64_t *) K, nvals, nthreads, msg)) ; \ + (int64_t *) K, nvals, msg)) ; \ for (int64_t k = 0 ; k < nvals ; k++) \ { \ /* convert the row and column index to 1-based */ \ diff --git a/src/utility/LAGraph_New.c b/src/utility/LAGraph_New.c index a68dd618e6..c283cfde8a 100644 --- a/src/utility/LAGraph_New.c +++ b/src/utility/LAGraph_New.c @@ -46,7 +46,8 @@ int LAGraph_New // allocate the graph //-------------------------------------------------------------------------- - LG_TRY (LAGraph_Malloc ((void **) G, 1, sizeof (struct LAGraph_Graph_struct), msg)) ; + LG_TRY (LAGraph_Malloc ((void **) G, 1, + sizeof (struct LAGraph_Graph_struct), msg)) ; //-------------------------------------------------------------------------- // initialize its members @@ -55,15 +56,14 @@ int LAGraph_New (*G)->A = NULL ; (*G)->kind = LAGraph_KIND_UNKNOWN ; (*G)->AT = NULL ; - (*G)->rowdegree = NULL ; - (*G)->coldegree = NULL ; - (*G)->structure_is_symmetric = LAGRAPH_UNKNOWN ; - (*G)->ndiag = LAGRAPH_UNKNOWN ; + (*G)->out_degree = NULL ; + (*G)->in_degree = NULL ; + (*G)->is_symmetric_structure = LAGRAPH_UNKNOWN ; + (*G)->nself_edges = LAGRAPH_UNKNOWN ; (*G)->emin = NULL ; - (*G)->emin_kind = LAGRAPH_UNKNOWN ; + (*G)->emin_state = LAGRAPH_UNKNOWN ; (*G)->emax = NULL ; - (*G)->emax_kind = LAGRAPH_UNKNOWN ; -// (*G)->nonzero = LAGRAPH_UNKNOWN ; // future property + (*G)->emax_state = LAGRAPH_UNKNOWN ; //-------------------------------------------------------------------------- // assign its primary components @@ -81,7 +81,7 @@ int LAGraph_New (*A) = NULL ; (*G)->kind = kind ; - (*G)->structure_is_symmetric = + (*G)->is_symmetric_structure = (kind == LAGraph_ADJACENCY_UNDIRECTED) ? LAGraph_TRUE : LAGRAPH_UNKNOWN ; diff --git a/src/utility/LAGraph_Realloc.c b/src/utility/LAGraph_Realloc.c index 69a360965a..7c87b37885 100644 --- a/src/utility/LAGraph_Realloc.c +++ b/src/utility/LAGraph_Realloc.c @@ -132,10 +132,7 @@ int LAGraph_Realloc //---------------------------------------------------------------------- pnew = LAGraph_Realloc_function (*p, newsize) ; - if (pnew == NULL) - { - return (GrB_OUT_OF_MEMORY) ; - } + if (pnew == NULL) return (GrB_OUT_OF_MEMORY) ; (*p) = pnew ; } diff --git a/src/utility/LAGraph_SampleDegree.c b/src/utility/LAGraph_SampleDegree.c index 4f78dcc977..d087c59c1e 100644 --- a/src/utility/LAGraph_SampleDegree.c +++ b/src/utility/LAGraph_SampleDegree.c @@ -25,7 +25,7 @@ int LAGraph_SampleDegree double *sample_median, // sampled median degree // input: const LAGraph_Graph G, // graph of n nodes - bool byrow, // if true, sample G->rowdegree, else G->coldegree + bool byout, // if true, sample G->out_degree, else G->in_degree int64_t nsamples, // number of samples uint64_t seed, // random number seed char *msg @@ -47,19 +47,18 @@ int LAGraph_SampleDegree if (G->kind == LAGraph_ADJACENCY_UNDIRECTED || (G->kind == LAGraph_ADJACENCY_DIRECTED && - G->structure_is_symmetric == LAGraph_TRUE)) + G->is_symmetric_structure == LAGraph_TRUE)) { // the structure of A is known to be symmetric - Degree = G->rowdegree ; + Degree = G->out_degree ; } else { // A is not known to be symmetric - Degree = (byrow) ? G->rowdegree : G->coldegree ; + Degree = (byout) ? G->out_degree : G->in_degree ; } - LG_ASSERT_MSG (Degree != NULL, - LAGRAPH_PROPERTY_MISSING, "degree property unknown") ; + LG_ASSERT_MSG (Degree != NULL, LAGRAPH_NOT_CACHED, "degree unknown") ; //-------------------------------------------------------------------------- // allocate workspace diff --git a/src/utility/LAGraph_SetNumThreads.c b/src/utility/LAGraph_SetNumThreads.c index 71d9cd5894..f8379264fa 100644 --- a/src/utility/LAGraph_SetNumThreads.c +++ b/src/utility/LAGraph_SetNumThreads.c @@ -16,7 +16,8 @@ int LAGraph_SetNumThreads ( // input: - int nthreads, // # of threads to use + int nthreads_hi, + int nthreads_lo, char *msg ) { @@ -31,22 +32,21 @@ int LAGraph_SetNumThreads // set number of threads to use //-------------------------------------------------------------------------- + nthreads_hi = LAGRAPH_MAX (nthreads_hi, 1) ; + nthreads_lo = LAGRAPH_MAX (nthreads_lo, 1) ; + #if LAGRAPH_SUITESPARSE { // SuiteSparse:GraphBLAS: set # of threads with global setting - GRB_TRY (GxB_set (GxB_NTHREADS, nthreads)) ; - } - #elif defined ( _OPENMP ) - { - // set # of threads with OpenMP global setting - omp_set_num_threads (nthreads) ; - } - #else - { - // nothing to do + GRB_TRY (GxB_set (GxB_NTHREADS, nthreads_lo)) ; } #endif + // set # of LAGraph threads + LG_nthreads_hi = nthreads_hi ; // for LAGraph itself, if nested + // regions call GraphBLAS + LG_nthreads_lo = nthreads_lo ; // for lower-level parallelism + return (GrB_SUCCESS) ; } diff --git a/src/utility/LAGraph_Sort1.c b/src/utility/LAGraph_Sort1.c index 9cc2a64fc0..0e7980e826 100644 --- a/src/utility/LAGraph_Sort1.c +++ b/src/utility/LAGraph_Sort1.c @@ -318,7 +318,6 @@ int LAGraph_Sort1 int64_t *A_0, // size n array // input: const int64_t n, - int nthreads, // # of threads to use char *msg ) { @@ -335,6 +334,7 @@ int LAGraph_Sort1 // handle small problems with a single thread //-------------------------------------------------------------------------- + int nthreads = LG_nthreads_hi * LG_nthreads_lo ; // # of threads to use if (nthreads <= 1 || n <= LG_BASECASE) { // sequential quicksort diff --git a/src/utility/LAGraph_Sort2.c b/src/utility/LAGraph_Sort2.c index f4690584ad..5d00ea168c 100644 --- a/src/utility/LAGraph_Sort2.c +++ b/src/utility/LAGraph_Sort2.c @@ -333,7 +333,6 @@ int LAGraph_Sort2 int64_t *A_1, // size n array // input: const int64_t n, - int nthreads, // # of threads to use char *msg ) { @@ -351,6 +350,7 @@ int LAGraph_Sort2 // handle small problems with a single thread //-------------------------------------------------------------------------- + int nthreads = LG_nthreads_hi * LG_nthreads_lo ; // # of threads to use if (nthreads <= 1 || n <= LG_BASECASE) { // sequential quicksort diff --git a/src/utility/LAGraph_Sort3.c b/src/utility/LAGraph_Sort3.c index d94a2a3400..bb44572d07 100644 --- a/src/utility/LAGraph_Sort3.c +++ b/src/utility/LAGraph_Sort3.c @@ -347,7 +347,6 @@ int LAGraph_Sort3 int64_t *A_2, // size n array // input: const int64_t n, - int nthreads, // # of threads to use char *msg ) { @@ -366,6 +365,7 @@ int LAGraph_Sort3 // handle small problems with a single thread //-------------------------------------------------------------------------- + int nthreads = LG_nthreads_hi * LG_nthreads_lo ; // # of threads to use if (nthreads <= 1 || n <= LG_BASECASE) { // sequential quicksort diff --git a/src/utility/LAGraph_SortByDegree.c b/src/utility/LAGraph_SortByDegree.c index 8d8020fa95..53a918af3a 100644 --- a/src/utility/LAGraph_SortByDegree.c +++ b/src/utility/LAGraph_SortByDegree.c @@ -14,13 +14,13 @@ // LAGraph_SortByDegree computes a permutation vector P that sorts a graph // by degree (either row or column degree of its adjacency matrix A). // If G is undirected, or if G is directed but is known to have a symmetric -// adjacency matrix, then G->rowdegree is used (and byrow is ignored). -// Otherwise, if G->rowdegree is used if byrow is true, and G->coldegree is -// used if byrow is false. +// adjacency matrix, then G->out_degree is used (and byout is ignored). +// Otherwise, if G->out_degree is used if byout is true, and G->in_degree is +// used if byout is false. -// G->rowdegree or G->coldegree must first be computed. An error is returned +// G->out_degree or G->in_degree must first be computed. An error is returned // if the required degree vector has not yet been computed. See -// LAGraph_Property_RowDegree and LAGraph_Property_ColDegree. +// LAGraph_Cached_OutDegree and LAGraph_Cached_InDegree. // The permutation is in ascending order of degree if ascending is true, and // in descending order otherwise. @@ -31,7 +31,7 @@ // The output is a permutation P where P [k] = i if row i is the kth row in // the permutation (or P [k] = j if column j is the kth column in the -// permutation, with byrow false). +// permutation, with byout false). #define LG_FREE_WORK \ { \ @@ -53,7 +53,7 @@ int LAGraph_SortByDegree int64_t **P_handle, // P is returned as a permutation vector of size n // input: const LAGraph_Graph G, // graph of n nodes - bool byrow, // if true, sort G->rowdegree, else G->coldegree + bool byout, // if true, sort G->out_degree, else G->in_degree bool ascending, // sort in ascending or descending order char *msg ) @@ -75,19 +75,18 @@ int LAGraph_SortByDegree if (G->kind == LAGraph_ADJACENCY_UNDIRECTED || (G->kind == LAGraph_ADJACENCY_DIRECTED && - G->structure_is_symmetric == LAGraph_TRUE)) + G->is_symmetric_structure == LAGraph_TRUE)) { // the structure of A is known to be symmetric - Degree = G->rowdegree ; + Degree = G->out_degree ; } else { // A is not known to be symmetric - Degree = (byrow) ? G->rowdegree : G->coldegree ; + Degree = (byout) ? G->out_degree : G->in_degree ; } - LG_ASSERT_MSG (Degree != NULL, - LAGRAPH_PROPERTY_MISSING, "degree property unknown") ; + LG_ASSERT_MSG (Degree != NULL, LAGRAPH_NOT_CACHED, "degree unknown") ; //-------------------------------------------------------------------------- // decide how many threads to use @@ -97,8 +96,7 @@ int LAGraph_SortByDegree GRB_TRY (GrB_Vector_size (&n, Degree)) ; #define CHUNK (64*1024) - int nthreads ; - LG_TRY (LAGraph_GetNumThreads (&nthreads, msg)) ; + int nthreads = LG_nthreads_hi * LG_nthreads_lo ; nthreads = LAGRAPH_MIN (nthreads, n/CHUNK) ; nthreads = LAGRAPH_MAX (nthreads, 1) ; @@ -152,7 +150,7 @@ int LAGraph_SortByDegree // sort by degrees, with ties by node id //-------------------------------------------------------------------------- - LG_TRY (LAGraph_Sort2 (D, P, n, nthreads, msg)) ; + LG_TRY (LAGraph_Sort2 (D, P, n, msg)) ; //-------------------------------------------------------------------------- // free workspace and return result diff --git a/src/utility/LG_internal.h b/src/utility/LG_internal.h index f5f6ecc3f7..568980ba23 100644 --- a/src/utility/LG_internal.h +++ b/src/utility/LG_internal.h @@ -348,6 +348,16 @@ MM_storage_enum ; // LG_PART and LG_PARTITION: definitions for partitioning an index range //------------------------------------------------------------------------------ +LAGRAPH_PUBLIC +int LG_nthreads_hi ; // # of threads to use at the higher level of a nested + // parallel region in LAGraph. Default: 1. + +LAGRAPH_PUBLIC +int LG_nthreads_lo ; // # of threads to use at the lower level of a nested + // parallel region, or to use inside GraphBLAS. + // Default: the value obtained by omp_get_max_threads + // if OpenMP is in use, or 1 otherwise. + // LG_PART and LG_PARTITION: divide the index range 0:n-1 uniformly // for nthreads. LG_PART(tid,n,nthreads) is the first index for thread tid. #define LG_PART(tid,n,nthreads) \ @@ -384,7 +394,7 @@ static inline void LG_eslice // All of the LG_qsort_* functions are single-threaded, by design. The // LAGraph_Sort* functions are parallel. None of these sorting methods are // guaranteed to be stable. These functions are contributed by Tim Davis, and -// are derived from SuiteSparse:GraphBLAS v4.0.3. Functions named LG_* are not +// are derived from SuiteSparse:GraphBLAS. Functions named LG_* are not // meant to be accessible by end users of LAGraph. #define LG_BASECASE (64 * 1024) @@ -505,10 +515,10 @@ void LG_qsort_3 // sort array A of size 3-by-n, using 3 keys (A [0:2][]) // count entries on the diagonal of a matrix //------------------------------------------------------------------------------ -int LG_ndiag +int LG_nself_edges ( // output - int64_t *ndiag, // # of entries + int64_t *nself_edges, // # of entries // input GrB_Matrix A, // matrix to count char *msg // error message diff --git a/src/utility/LG_ndiag.c b/src/utility/LG_nself_edges.c similarity index 87% rename from src/utility/LG_ndiag.c rename to src/utility/LG_nself_edges.c index 84b11d244c..c99a264f9d 100644 --- a/src/utility/LG_ndiag.c +++ b/src/utility/LG_nself_edges.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// LG_ndiag: count the # of diagonal entries in a matrix +// LG_nself_edges: count the # of diagonal entries in a matrix //------------------------------------------------------------------------------ // LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. @@ -20,10 +20,10 @@ #include "LG_internal.h" -int LG_ndiag +int LG_nself_edges ( // output: - int64_t *ndiag, // # of entries + int64_t *nself_edges, // # of entries // input: GrB_Matrix A, // matrix to count char *msg // error message @@ -36,8 +36,8 @@ int LG_ndiag GrB_Matrix D = NULL, M = NULL ; GrB_Vector d = NULL ; - LG_ASSERT (ndiag != NULL, GrB_NULL_POINTER) ; - (*ndiag) = LAGRAPH_UNKNOWN ; + LG_ASSERT (nself_edges != NULL, GrB_NULL_POINTER) ; + (*nself_edges) = LAGRAPH_UNKNOWN ; GrB_Index nrows, ncols ; GRB_TRY (GrB_Matrix_nrows (&nrows, A)) ; @@ -57,7 +57,7 @@ int LG_ndiag GRB_TRY (GrB_Vector_new (&d, atype, n)) ; GRB_TRY (GxB_Vector_diag (d, A, 0, NULL)) ; - GRB_TRY (GrB_Vector_nvals ((GrB_Index *) ndiag, d)) ; + GRB_TRY (GrB_Vector_nvals ((GrB_Index *) nself_edges, d)) ; #else @@ -76,7 +76,7 @@ int LG_ndiag // D = A GRB_TRY (GrB_assign (D, M, NULL, A, GrB_ALL, nrows, GrB_ALL, ncols, GrB_DESC_S)) ; - GRB_TRY (GrB_Matrix_nvals ((GrB_Index *) ndiag, D)) ; + GRB_TRY (GrB_Matrix_nvals ((GrB_Index *) nself_edges, D)) ; #endif From 8e36bd2e8f6bcaba3e666f7ed584f3d230720fb6 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Tue, 31 May 2022 10:41:05 -0500 Subject: [PATCH 13/53] sync with LAGraph_reorg, 0.9.26 --- .github/workflows/build.yml | 5 +- CMakeLists.txt | 16 +- config/LAGraph.h.in | 1948 +++++++++++++++++++ doc/Delete_Me_for_V1/TODO.txt | 4 +- include/LAGraph.h | 56 +- src/algorithm/LAGr_BreadthFirstSearch.c | 14 +- src/algorithm/LG_BreadthFirstSearch_SSGrB.c | 38 +- src/test/test_BreadthFirstSearch.c | 209 +- 8 files changed, 2133 insertions(+), 157 deletions(-) create mode 100644 config/LAGraph.h.in diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e8845529b8..8ffab683f5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,6 +12,7 @@ jobs: - {grb_version: 6.1.4, conda_grb_package_hash: h9c3ff4c} - {grb_version: 6.2.4, conda_grb_package_hash: h27087fc} - {grb_version: 7.0.1, conda_grb_package_hash: h27087fc} + - {grb_version: 7.1.0, conda_grb_package_hash: h27087fc} steps: - name: Checkout uses: actions/checkout@v2.0.0 @@ -35,10 +36,11 @@ jobs: make test_coverage - name: Deploy uses: JamesIves/github-pages-deploy-action@4.1.1 + if: ${{ matrix.config.grb_version }} == '7.1.0' && github.event_name == 'push' && github.ref == 'refs/heads/reorg' with: branch: gh-pages folder: build/test_coverage/ - if: ${{ matrix.config.grb_version }} == '7.0.1' && github.event_name == 'push' && github.ref == 'refs/heads/reorg' + single-commit: true - name: Save output uses: actions/upload-artifact@v2.2.3 with: @@ -53,6 +55,7 @@ jobs: - {grb_version: 6.1.4, conda_grb_package_hash: h4a89273} - {grb_version: 6.2.4, conda_grb_package_hash: h3f3baac} - {grb_version: 7.0.1, conda_grb_package_hash: h3f3baac} + - {grb_version: 7.1.0, conda_grb_package_hash: h7881ed4} steps: - name: Checkout uses: actions/checkout@v2.0.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 225b13656b..0ac61e9d0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,22 +48,24 @@ cmake_minimum_required ( VERSION 3.13 ) set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake) -if ( CMAKE_VERSION VERSION_GREATER "3.0" ) - cmake_policy ( SET CMP0042 NEW ) - cmake_policy ( SET CMP0048 NEW ) -endif ( ) +cmake_policy ( SET CMP0042 NEW ) +cmake_policy ( SET CMP0048 NEW ) set ( CMAKE_MACOSX_RPATH TRUE ) # version of LAGraph -# FIXME: use config to create include/LAGraph.h from these definitions -set ( LAGraph_DATE "May 20, 2022" ) +set ( LAGraph_DATE "May 31, 2022" ) set ( LAGraph_VERSION_MAJOR 0 ) set ( LAGraph_VERSION_MINOR 9 ) -set ( LAGraph_VERSION_SUB 23 ) +set ( LAGraph_VERSION_SUB 26 ) project ( lagraph VERSION "${LAGraph_VERSION_MAJOR}.${LAGraph_VERSION_MINOR}.${LAGraph_VERSION_SUB}" ) +# configure LAGraph.h with the LAGraph date and version +configure_file ( + "config/LAGraph.h.in" + "${PROJECT_SOURCE_DIR}/include/LAGraph.h" ) + #------------------------------------------------------------------------------- # code coverage and build type #------------------------------------------------------------------------------- diff --git a/config/LAGraph.h.in b/config/LAGraph.h.in new file mode 100644 index 0000000000..e1ce401b8e --- /dev/null +++ b/config/LAGraph.h.in @@ -0,0 +1,1948 @@ +//------------------------------------------------------------------------------ +// LAGraph.h: user-visible include file for LAGraph +//------------------------------------------------------------------------------ + +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. +// SPDX-License-Identifier: BSD-2-Clause +// See additional acknowledgments in the LICENSE file, +// or contact permission@sei.cmu.edu for the full terms. + +//------------------------------------------------------------------------------ + +// LAGraph is a package of graph algorithms based on GraphBLAS. GraphBLAS +// defines a set of sparse matrix operations on an extended algebra of +// semirings, using an almost unlimited variety of operators and types. When +// applied to sparse adjacency matrices, these algebraic operations are +// equivalent to computations on graphs. GraphBLAS provides a powerful and +// expressive framework creating graph algorithms based on the elegant +// mathematics of sparse matrix operations on a semiring. + +// However, GraphBLAS itself does not have graph algorithms. The purpose of +// LAGraph is to provide a robust, easy-to-use high-performance library of +// graph algorithms that rely on GraphBLAS. + +//------------------------------------------------------------------------------ + +#ifndef LAGRAPH_H +#define LAGRAPH_H + +//============================================================================== +// LAGraph version +//============================================================================== + +// See also the LAGraph_Version utility method, which returns these values. +// These definitions are derived from LAGraph/CMakeLists.txt. + +#define LAGRAPH_DATE "@LAGraph_DATE@" +#define LAGRAPH_VERSION_MAJOR @LAGraph_VERSION_MAJOR@ +#define LAGRAPH_VERSION_MINOR @LAGraph_VERSION_MINOR@ +#define LAGRAPH_VERSION_UPDATE @LAGraph_VERSION_SUB@ + +//============================================================================== +// include files and helper macros +//============================================================================== + +#include +#if defined ( _OPENMP ) + #include +#endif + +// LAGRAPH_MIN/MAX: suitable for integers, and non-NaN floating point +#define LAGRAPH_MIN(x,y) (((x) < (y)) ? (x) : (y)) +#define LAGRAPH_MAX(x,y) (((x) > (y)) ? (x) : (y)) + +//============================================================================== +// GraphBLAS platform specifics +//============================================================================== + +// GraphBLAS C API specification, OpenMP, and vanilla vs +// SuiteSparse:GraphBLAS GxB extensions. + +#if ( GRB_VERSION < 2 ) + #error "The GraphBLAS library must support the v2.0 C API Specification" +#endif + +#if ( _MSC_VER && !__INTEL_COMPILER ) + #ifdef LG_LIBRARY + // compiling LAGraph itself, exporting symbols to user apps + #define LAGRAPH_PUBLIC extern __declspec ( dllexport ) + #else + // compiling the user application, importing symbols from LAGraph + #define LAGRAPH_PUBLIC extern __declspec ( dllimport ) + #endif +#else + // for other compilers + #define LAGRAPH_PUBLIC extern +#endif + +#if defined ( __cplusplus ) + // C++ does not have the restrict keyword + #define LAGRAPH_RESTRICT +#elif ( _MSC_VER && !__INTEL_COMPILER ) + // Microsoft Visual Studio uses __restrict instead of restrict for C + #define LAGRAPH_RESTRICT __restrict +#else + // use the restrict keyword for ANSI C99 compilers + #define LAGRAPH_RESTRICT restrict +#endif + +// vanilla vs SuiteSparse: +#if !defined ( LAGRAPH_VANILLA ) + // by default, set LAGRAPH_VANILLA to false + #define LAGRAPH_VANILLA 0 +#endif + +#if ( !LAGRAPH_VANILLA ) && defined ( GxB_SUITESPARSE_GRAPHBLAS ) + // use SuiteSparse, and its GxB* extensions + #define LAGRAPH_SUITESPARSE 1 +#else + // use any GraphBLAS library (possibly SuiteSparse) but with no GxB* + #define LAGRAPH_SUITESPARSE 0 +#endif + +// maximum length of the name of a GrB type, including the null-terminator +#if LAGRAPH_SUITESPARSE +#define LAGRAPH_MAX_NAME_LEN GxB_MAX_NAME_LEN +#else +#define LAGRAPH_MAX_NAME_LEN 128 +#endif + +//============================================================================== +// LAGraph error handling +//============================================================================== + +// All LAGraph functions return an int to indicate an error status (described +// below), where zero (GrB_SUCCESS) denotes success, negative values indicate +// an error, and positive values denote success but with some kind of +// algorithm-specific note or warning. + +// In addition, all LAGraph functions also have a final parameter that is a +// pointer to a user-allocated string in which an algorithm-specific error +// message can be returned. If NULL, no error message is returned. This is +// not itself an error condition, it just indicates that the caller does not +// need the message returned. If the message string is provided but no error +// occurs, an empty string is returned. + +// LAGRAPH_MSG_LEN: The maximum required length of a message string +#define LAGRAPH_MSG_LEN 256 + +// For example, the following call computes the breadth-first-search of an +// LAGraph_Graph G, starting at a given source node. It returns a status of +// zero if it succeeds and a negative value on failure. + +/* + GrB_Vector level, parent ; + char msg [LAGRAPH_MSG_LEN] ; + int status = LAGr_BreadthFirstSearch (&level, &parent, G, src, msg) ; + if (status < 0) + { + printf ("error: %s\n", msg) ; + // take corrective action ... + } +*/ + +//------------------------------------------------------------------------------ +// LAGraph error status: +//------------------------------------------------------------------------------ + +// All LAGraph methods return an int to denote their status: zero if they are +// successful (which is the value of GrB_SUCCESS), negative on error, or +// positive for an informational value (such as GrB_NO_VALUE). Integers in the +// range -999 to 999 are reserved for GraphBLAS GrB_Info return values: + +// successful results: +// GrB_SUCCESS = 0 // all is well +// GrB_NO_VALUE = 1 // A(i,j) requested but not there + +// errors: +// GrB_UNINITIALIZED_OBJECT = -1 // object has not been initialized +// GrB_NULL_POINTER = -2 // input pointer is NULL +// GrB_INVALID_VALUE = -3 // generic error; some value is bad +// GrB_INVALID_INDEX = -4 // row or column index is out of bounds +// GrB_DOMAIN_MISMATCH = -5 // object domains are not compatible +// GrB_DIMENSION_MISMATCH = -6 // matrix dimensions do not match +// GrB_OUTPUT_NOT_EMPTY = -7 // output matrix already has values +// GrB_NOT_IMPLEMENTED = -8 // method not implemented +// GrB_PANIC = -101 // unknown error +// GrB_OUT_OF_MEMORY = -102 // out of memory +// GrB_INSUFFICIENT_SPACE = -103, // output array not large enough +// GrB_INVALID_OBJECT = -104 // object is corrupted +// GrB_INDEX_OUT_OF_BOUNDS = -105 // row or col index out of bounds +// GrB_EMPTY_OBJECT = -106 // an object does not contain a value + +// LAGraph returns any errors it receives from GraphBLAS, and also uses the +// GrB_* error codes in these cases: +// GrB_INVALID_INDEX: if a source node id is out of range +// GrB_INVALID_VALUE: if an enum to select a method or option is out of range +// GrB_NOT_IMPLEMENTED: if a type is not supported, or when SuiteSparse +// GraphBLAS is required. + +// Many LAGraph methods share common error cases, described below. These +// return values are in the range -1000 to -1999. Return values of -2000 or +// greater may be used by specific LAGraph methods, which denote errors not in +// this list: + +// LAGRAPH_INVALID_GRAPH: the input graph is invalid; the details are given +// in the error msg string returned by the method. + +// LAGRAPH_SYMMETRIC_STRUCTURE_REQUIRED: the method requires an undirected +// graph, or a directed graph with an adjacency matrix that is known to +// have a symmetric structure. LAGraph_Cached_IsSymmetricStructure can +// be used to determine this cached property. + +// LAGRAPH_IO_ERROR: a file input or output method failed, or an input file +// has an incorrect format that cannot be parsed. + +// LAGRAPH_NOT_CACHED: some methods require one or more cached properties to +// be computed before calling them (AT, out_degree, or in_degree. Use +// LAGraph_Cached_AT, LAGraph_Cached_OutDegree, and/or +// LAGraph_Cached_InDegree to compute them. + +// LAGRAPH_NO_SELF_EDGES_ALLOWED: some methods requires that the graph have +// no self edges, which correspond to the entries on the diagonal of the +// adjacency matrix. If the G->nself_edges cached property is nonzero or +// unknown, this error condition is returned. Use LAGraph_Cached_NSelfEdges to +// compute G->nself_edges, or LAGraph_DeleteSelfEdges to remove all diagonal +// entries from G->A. + +// LAGRAPH_CONVERGENCE_FAILURE: an iterative process failed to converge to +// a good solution. + +// LAGRAPH_CACHE_NOT_NEEDED: this is a warning, not an error. It is returned +// by LAGraph_Cached_* methods when asked to compute cached properties +// that are not needed. These include G->AT and G->in_degree for an +// undirected graph. + +// LAGraph errors: +#define LAGRAPH_INVALID_GRAPH (-1000) +#define LAGRAPH_SYMMETRIC_STRUCTURE_REQUIRED (-1001) +#define LAGRAPH_IO_ERROR (-1002) +#define LAGRAPH_NOT_CACHED (-1003) +#define LAGRAPH_NO_SELF_EDGES_ALLOWED (-1004) +#define LAGRAPH_CONVERGENCE_FAILURE (-1005) + +// LAGraph warnings: +#define LAGRAPH_CACHE_NOT_NEEDED ( 1000) + +// @retval GrB_SUCCESS if successful +// @retval a negative GrB_Info value on error (in range -999 to -1) +// @retval a positive GrB_Info value if successful but with extra information +// (in range 1 to 999) + +// @retval -1999 to -1000: a common LAGraph-specific error, given in the list +// above +// @retval 1000 to 1999: if successful, with extra LAGraph-specific information + +// @retval <= -2000 an LAGraph error specific to a particular LAGraph method +// >= 2000 + +// @param[in,out] msg any error messages + +//------------------------------------------------------------------------------ +// LAGRAPH_TRY: try an LAGraph method and check for errors +//------------------------------------------------------------------------------ + +// In a robust application, the return values from each call to LAGraph and +// GraphBLAS should be checked, and corrective action should be taken if an +// error occurs. The LAGRAPH_TRY and GRB_TRY macros assist in this effort. + +// LAGraph and GraphBLAS are written in C, and so they cannot rely on the +// try/catch mechanism of C++. To accomplish a similar goal, each LAGraph file +// must #define its own file-specific macro called LAGRAPH_CATCH. The typical +// usage of macro is to free any temporary matrices/vectors or workspace when +// an error occurs, and then "throw" the error by returning to the caller. A +// user application may also #define LAGRAPH_CATCH and use these macros. + +// A typical example of a user function that calls LAGraph might #define +// LAGRAPH_CATCH as follows. Suppose workvector is a GrB_vector used for +// computations internal to the mybfs function, and W is a (double *) space +// created by malloc. + +#if example_usage_only + + // an example user-defined LAGRAPH_CATCH macro + #define LAGRAPH_CATCH(status) \ + { \ + /* an LAGraph error has occurred */ \ + printf ("LAGraph error: (%d): file: %s, line: %d\n%s\n", \ + status, __FILE__, __LINE__, msg) ; \ + /* free any internal workspace and return the status */ \ + GrB_free (*parent) ; \ + GrB_free (workvector) ; \ + LAGraph_Free ((void **) &W, NULL) ; \ + return (status) ; \ + } + + // an example user function that uses LAGRAPH_TRY / LAGRAPH_CATCH + int mybfs (LAGraph_Graph G, GrB_Vector *parent, int64_t src) + { + GrB_Vector workvector = NULL ; + double *W = NULL ; + char msg [LAGRAPH_MSG_LEN] ; + (*parent) = NULL ; + LAGRAPH_TRY (LAGr_BreadthFirstSearch (NULL, parent, G, src, true, + msg)) ; + // ... + return (GrB_SUCCESS) ; + } + +#endif + +#define LAGRAPH_TRY(LAGraph_method) \ +{ \ + int LG_status = LAGraph_method ; \ + if (LG_status < GrB_SUCCESS) \ + { \ + LAGRAPH_CATCH (LG_status) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// GRB_TRY: try a GraphBLAS method and check for errors +//------------------------------------------------------------------------------ + +// LAGraph provides a similar functionality for calling GraphBLAS methods. +// GraphBLAS returns info = 0 (GrB_SUCCESS) or 1 (GrB_NO_VALUE) on success, and +// a value < 0 on failure. The user application must #define GRB_CATCH to use +// GRB_TRY. Note that GraphBLAS_info is internal to this macro. If the +// user application or LAGraph method wants a copy, a statement such as +// info = GraphBLAS_info ; where info is defined outside of this macro. + +// GraphBLAS and LAGraph both use the convention that negative values are +// errors, and the LAGraph_status is a superset of the GrB_Info enum. As a +// result, the user can define LAGRAPH_CATCH and GRB_TRY as the same operation. +// The main difference between the two would be the error message string. For +// LAGraph, the string is the last parameter, and LAGRAPH_CATCH can optionally +// print it out. For GraphBLAS, the GrB_error mechanism can return a string. + +#define GRB_TRY(GrB_method) \ +{ \ + GrB_Info LG_GrB_Info = GrB_method ; \ + if (LG_GrB_Info < GrB_SUCCESS) \ + { \ + GRB_CATCH (LG_GrB_Info) ; \ + } \ +} + +//============================================================================== +// LAGraph memory management +//============================================================================== + +// LAGraph provides wrappers for the malloc/calloc/realloc/free set of memory +// management functions, initialized by LAGraph_Init or LAGr_Init. By default, +// the following are pointers to the ANSI C11 malloc/calloc/realloc/free +// functions. + +LAGRAPH_PUBLIC void * (* LAGraph_Malloc_function ) (size_t) ; +LAGRAPH_PUBLIC void * (* LAGraph_Calloc_function ) (size_t, size_t) ; +LAGRAPH_PUBLIC void * (* LAGraph_Realloc_function ) (void *, size_t) ; +LAGRAPH_PUBLIC void (* LAGraph_Free_function ) (void *) ; + +//------------------------------------------------------------------------------ +// LAGraph_Malloc: allocate a block of memory (wrapper for malloc) +//------------------------------------------------------------------------------ + +LAGRAPH_PUBLIC +int LAGraph_Malloc +( + // output: + void **p, // pointer to allocated block of memory + // input: + size_t nitems, // number of items + size_t size_of_item, // size of each item + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Calloc: allocate a block of memory (wrapper for calloc) +//------------------------------------------------------------------------------ + +LAGRAPH_PUBLIC +int LAGraph_Calloc +( + // output: + void **p, // pointer to allocated block of memory + // input: + size_t nitems, // number of items + size_t size_of_item, // size of each item + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Realloc: reallocate a block of memory (wrapper for realloc) +//------------------------------------------------------------------------------ + +LAGRAPH_PUBLIC +int LAGraph_Realloc +( + // input/output: + void **p, // old block to reallocate + // input: + size_t nitems_new, // new number of items in the object + size_t nitems_old, // old number of items in the object + size_t size_of_item, // size of each item + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Free: free a block of memory (wrapper for free) +//------------------------------------------------------------------------------ + +// If LAGraph_Malloc (&p, ...) is the pointer to the allocated block of memory, +// LAGraph_Free (&p, ...) is the method to free it. The parameter is passed as +// &p so that p can be set to NULL on return, to guard against double-free. +// LAGraph_Free does nothing if &p or p are NULL on input. + +LAGRAPH_PUBLIC +int LAGraph_Free // free a block of memory and set p to NULL +( + // input/output: + void **p, // pointer to object to free, does nothing if NULL + char *msg +) ; + +//============================================================================== +// LAGraph data structures +//============================================================================== + +// In addition to relying on underlying GraphBLAS objects (GrB_Matrix, +// GrB_Vector, GrB_Descriptor, ...), LAGraph adds the LAGraph_Graph. This +// object contains a representation of a graph and its associated data. Unlike +// the GrB_* objects, the LAGraph_Graph is not opaque. + +// LAGRAPH_UNKNOWN is used for all scalars whose value is not known +#define LAGRAPH_UNKNOWN (-1) + +//------------------------------------------------------------------------------ +// LAGraph_Kind: the kind of a graph +//------------------------------------------------------------------------------ + +// Currently, only two types of graphs are supported: undirected graphs and +// directed graphs. Edge weights are assumed to be present. Unweighted graphs +// can be represented by setting all entries present in the sparsity structure +// to the same value, typically 1. Additional types of graphs will be added in +// the future. + +typedef enum +{ + LAGraph_ADJACENCY_UNDIRECTED = 0, // A is square and symmetric; both upper + // and lower triangular parts are + // present. A(i,j) is the edge (i,j) + + LAGraph_ADJACENCY_DIRECTED = 1, // A is square; A(i,j) is the edge (i,j) + + // possible future kinds of graphs: + // LAGraph_ADJACENCY_UNDIRECTED_UNWEIGHTED + // LAGraph_ADJACENCY_DIRECTED_UNWEIGHTED + // LAGraph_ADJACENCY_UNDIRECTED_TRIL + // LAGraph_ADJACENCY_UNDIRECTED_TRIU + // LAGraph_BIPARTITE + // LAGraph_BIPARTITE_DIRECTED + // LAGraph_BIPARTITE_UNDIRECTED + // LAGraph_INCIDENCE_* + // LAGraph_MULTIGRAPH_* + // LAGraph_HYPERGRAPH + // LAGraph_HYPERGRAPH_DIRECTED + // ... + + LAGraph_KIND_UNKNOWN = LAGRAPH_UNKNOWN // the graph kind is unknown +} +LAGraph_Kind ; + +//------------------------------------------------------------------------------ +// LAGraph_Boolean: true, false, or unknown +//------------------------------------------------------------------------------ + +typedef enum +{ + LAGraph_FALSE = 0, + LAGraph_TRUE = 1, + LAGraph_BOOLEAN_UNKNOWN = LAGRAPH_UNKNOWN +} +LAGraph_Boolean ; + +//------------------------------------------------------------------------------ +// LAGraph_State: value, bound, or unknown +//------------------------------------------------------------------------------ + +// LAGraph_State describes the status of a cached property of a graph. If the +// cached property is computed in floating-point arithmetic, it may have been +// computed with roundoff error, but it may still be declared as "value" if the +// roundoff error is expected to be small, or if the cached property was +// computed as carefully as possible (to within reasonable roundoff error). + +// The "bound" state indicates that the cached property is an upper or lower +// bound, depending on the particular cached property. If computed in +// floating-point arithmetic, an "upper bound" cached property may be actually +// slightly lower than the actual upper bound, because of floating-point +// roundoff. + +typedef enum +{ + LAGraph_VALUE = 0, // cached property is a known value (ignoring roundoff) + LAGraph_BOUND = 1, // cached property is a bound (upper or lower, + // depending on the particular cached property) + LAGraph_STATE_UNKNOWN = LAGRAPH_UNKNOWN, +} +LAGraph_State ; + +//------------------------------------------------------------------------------ +// LAGraph_Graph: the primary graph data structure of LAGraph +//------------------------------------------------------------------------------ + +// The LAGraph_Graph object contains a GrB_Matrix A as its primary component. +// For graphs represented with adjacency matrices, A(i,j) denotes the edge +// (i,j). Unlike GrB_* objects in GraphBLAS, the LAGraph_Graph data structure +// is not opaque. User applications have full access to its contents. + +// An LAGraph_Graph G contains two kinds of components: + +// (1) primary components of the graph, which fully define the graph: +// A the adjacency matrix of the graph +// kind the kind of graph (undirected, directed, bipartite, ...) + +// (2) cached properties of the graph, which can be recreated any time: +// AT AT = A' +// out_degree out_degree(i) = # of entries in A(i,:) +// in_degree in_degree(j) = # of entries in A(:,j) +// is_symmetric_structure: true if the structure of A is symmetric +// nself_edges the number of entries on the diagonal of A +// emin minimum edge weight +// emax maximum edge weight + +struct LAGraph_Graph_struct +{ + + //-------------------------------------------------------------------------- + // primary components of the graph + //-------------------------------------------------------------------------- + + GrB_Matrix A; // the adjacency matrix of the graph + LAGraph_Kind kind; // the kind of graph + + // possible future components: + // multigraph .. + // GrB_Matrix *Amult ; // array of size nmatrices + // int nmatrices ; + // GrB_Vector VertexWeights ; + + //-------------------------------------------------------------------------- + // cached properties of the graph + //-------------------------------------------------------------------------- + + // All of these components may be deleted or set to 'unknown' at any time. + // For example, if AT is NULL, then the transpose of A has not been + // computed. A scalar cached property of type LAGraph_Boolean would be set + // to LAGRAPH_UNKNOWN to denote that its value is unknown. + + // If present, the cached properties must be valid and accurate. If the + // graph changes, these cached properties can either be recomputed or + // deleted to denote the fact that they are unknown. This choice is up to + // individual LAGraph methods and utilities. + + // LAGraph methods can set non-scalar cached properties only if they are + // constructing the graph. They cannot modify them or create them if the + // graph is declared as a read-only object in the parameter list of the + // method. + + GrB_Matrix AT ; // AT = A', the transpose of A, with the same type. + + GrB_Vector out_degree ; // a GrB_INT64 vector of length m, if A is m-by-n. + // where out_degree(i) is the number of entries in A(i,:). If + // out_degree is sparse and the entry out_degree(i) is not present, + // then it is assumed to be zero. + + GrB_Vector in_degree ; // a GrB_INT64 vector of length n, if A is m-by-n. + // where in_degree(j) is the number of entries in A(:,j). If + // in_degree is sparse and the entry in_degree(j) is not present, + // then it is assumed to be zero. If A is known to have a + // symmetric structure, the convention is that the degree is held in + // out_degree, and in_degree is left as NULL. + + // If G is held as an incidence matrix, then G->A might be rectangular, + // in the future, but the graph G may have a symmetric structure anyway. + LAGraph_Boolean is_symmetric_structure ; // For an undirected + // graph, this cached property will always be implicitly true and + // can be ignored. The matrix A for a directed weighted graph will + // typically be unsymmetric, but might have a symmetric structure. + // In that case, this scalar cached property can be set to true. + // By default, this cached property is set to LAGRAPH_UNKNOWN. + + int64_t nself_edges ; // # of entries on the diagonal of A, or + // LAGRAPH_UNKNOWN if unknown. For the adjacency matrix of a + // directed or undirected graph, this is the number of self-edges + // in the graph. + + GrB_Scalar emin ; // minimum edge weight: value, lower bound, or unknown + LAGraph_State emin_state ; + // VALUE: emin is equal to the smallest entry, min(G->A) + // BOUND: emin <= min(G->A) + // UNKNOWN: emin is unknown + + GrB_Scalar emax ; // maximum edge weight: value, upper bound, or unknown + LAGraph_State emax_state ; + // VALUE: emax is equal to the largest entry, max(G->A) + // BOUND: emax >= max(G->A) + // UNKNOWN: emax is unknown + + // possible future cached properties: + + // Some algorithms may want to know if the graph has any edge weights + // exactly equal to zero. In some cases, this can be inferred from the + // emin/emax bounds, or it can be indicated via the following cached + // property: + // LAGraph_Boolean nonzero ; // If true, then all entries in + // G->A are known to be nonzero. If false, G->A may contain + // entries in its structure that are identically equal to zero. If + // unknown, then G->A may or may not have entries equal to zero. + // other edge weight metrics: median, standard deviation.... Might be + // useful for computing Delta for a Basic SSSP. + // GrB_Vector row_sum, col_sum ; + // row_sum(i) = sum(abs(A(i,:))), regardless of kind + // col_sum(j) = sum(abs(A(:,j))), regardless of kind + // LAGraph_Boolean connected ; // true if G is a connected graph +} ; + +typedef struct LAGraph_Graph_struct *LAGraph_Graph ; + +//============================================================================== +// LAGraph utilities +//============================================================================== + +//------------------------------------------------------------------------------ +// LAGraph_Init: start GraphBLAS and LAGraph +//------------------------------------------------------------------------------ + +// This method must be called before calling any other GrB* or LAGraph* method. +// It initializes GraphBLAS with GrB_init and then performs LAGraph-specific +// initializations. In particular, the LAGraph semirings listed below are +// created. GrB_init can also safely be called before calling LAGr_Init +// or LAGraph_Init. + +LAGRAPH_PUBLIC +int LAGraph_Init +( + char *msg +) ; + +// FUTURE: include these as built-in semirings in v2.1 C API, Table 3.9: + +// LAGraph semirings, created by LAGraph_Init or LAGr_Init: +LAGRAPH_PUBLIC GrB_Semiring + + // LAGraph_plus_first_T: using the GrB_PLUS_MONOID_T monoid and the + // corresponding GrB_FIRST_T multiplicative operator. + LAGraph_plus_first_int8 , + LAGraph_plus_first_int16 , + LAGraph_plus_first_int32 , + LAGraph_plus_first_int64 , + LAGraph_plus_first_uint8 , + LAGraph_plus_first_uint16 , + LAGraph_plus_first_uint32 , + LAGraph_plus_first_uint64 , + LAGraph_plus_first_fp32 , + LAGraph_plus_first_fp64 , + + // LAGraph_plus_second_T: using the GrB_PLUS_MONOID_T monoid and the + // corresponding GrB_SECOND_T multiplicative operator. + LAGraph_plus_second_int8 , + LAGraph_plus_second_int16 , + LAGraph_plus_second_int32 , + LAGraph_plus_second_int64 , + LAGraph_plus_second_uint8 , + LAGraph_plus_second_uint16 , + LAGraph_plus_second_uint32 , + LAGraph_plus_second_uint64 , + LAGraph_plus_second_fp32 , + LAGraph_plus_second_fp64 , + + // LAGraph_plus_one_T: using the GrB_PLUS_MONOID_T monoid and the + // corresponding GrB_ONEB_T multiplicative operator. + LAGraph_plus_one_int8 , + LAGraph_plus_one_int16 , + LAGraph_plus_one_int32 , + LAGraph_plus_one_int64 , + LAGraph_plus_one_uint8 , + LAGraph_plus_one_uint16 , + LAGraph_plus_one_uint32 , + LAGraph_plus_one_uint64 , + LAGraph_plus_one_fp32 , + LAGraph_plus_one_fp64 , + + // LAGraph_any_one_T: using the GrB_MIN_MONOID_T for non-boolean types or + // GrB_LOR_MONOID_BOOL for boolean, and the GrB_ONEB_T multiplicative op. + // These semirings are very useful for unweighted graphs, or for algorithms + // that operate only on the sparsity structure of unweighted graphs. + LAGraph_any_one_bool , // (or, true) semiring + LAGraph_any_one_int8 , // (min, 1) semiring + LAGraph_any_one_int16 , + LAGraph_any_one_int32 , + LAGraph_any_one_int64 , + LAGraph_any_one_uint8 , + LAGraph_any_one_uint16 , + LAGraph_any_one_uint32 , + LAGraph_any_one_uint64 , + LAGraph_any_one_fp32 , + LAGraph_any_one_fp64 ; + +//------------------------------------------------------------------------------ +// LAGraph_Version: determine the version of LAGraph +//------------------------------------------------------------------------------ + +// The version number and date can also be obtained via compile-time constants +// from LAGraph.h. However, it is possible to compile a user application that +// #includes one version of LAGraph.h and then links with another version of +// the LAGraph library later on, so the version number and date may differ from +// the compile-time constants. + +// The LAGraph_Version method allows the library itself to be +// queried, after it is linked in with the user application. + +// The version_number array is set to LAGRAPH_VERSION_MAJOR, +// LAGRAPH_VERSION_MINOR, and LAGRAPH_VERSION_UPDATE, in that order. +// The LAGRAPH_DATE string is copied into the user-provided version_date +// string, and is null-terminated. + +LAGRAPH_PUBLIC +int LAGraph_Version +( + // output: + int version_number [3], // user-provided array of size 3 + char *version_date, // user-provided array of size >= LAGRAPH_MSG_LEN + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Finalize: finish LAGraph +//------------------------------------------------------------------------------ + +// LAGraph_Finalize must be called as the last LAGraph method. It calls +// GrB_finalize and frees any LAGraph objects created by LAGraph_Init or +// LAGr_Init. After calling this method, no LAGraph or GraphBLAS methods +// may be used. + +LAGRAPH_PUBLIC +int LAGraph_Finalize +( + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_New: create a new graph +//------------------------------------------------------------------------------ + +// LAGraph_New creates a new graph G. The cached properties G->AT, +// G->out_degree, and G->in_degree are set to NULL, and scalar +// cached properties are set to LAGRAPH_UNKNOWN. + +LAGRAPH_PUBLIC +int LAGraph_New +( + // output: + LAGraph_Graph *G, // the graph to create, NULL if failure + // input/output: + GrB_Matrix *A, // the adjacency matrix of the graph, may be NULL. + // A is moved into G as G->A, and A itself is set + // to NULL to denote that is now a part of G. + // That is, { G->A = A ; A = NULL ; } is performed. + // When G is deleted, G->A is freed. If A is NULL, + // the graph is invalid until G->A is set. + // input: + LAGraph_Kind kind, // the kind of graph. This may be LAGRAPH_UNKNOWN, + // which must then be revised later before the + // graph can be used. + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Delete: free a graph and all its contents +//------------------------------------------------------------------------------ + +// LAGraph_Delete frees a graph G, including its adjacency matrix G->A and the +// cached properties G->AT, G->out_degree, and G->in_degree. + +LAGRAPH_PUBLIC +int LAGraph_Delete +( + // input/output: + LAGraph_Graph *G, // the graph to delete; G set to NULL on output. + // All internal GrB_Matrix and GrB_Vector objects are + // freed, including G->A. To keep G->A while deleting + // the graph G, use: + // { A = G->A ; G->A = NULL ; LAGraph_Delete (&G, msg);} + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_DeleteCached: free any internal cached properties of a graph +//------------------------------------------------------------------------------ + +// LAGraph_DeleteCached frees all cached properies of a graph G. The graph +// is still valid. This method should be used if G->A changes, since such +// changes will normally invalidate G->AT, G->out_degree, and/or G->in_degree. + +LAGRAPH_PUBLIC +int LAGraph_DeleteCached +( + // input/output: + LAGraph_Graph G, // G stays valid, only cached properties are freed + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Cached_AT: construct G->AT for a graph +//------------------------------------------------------------------------------ + +// LAGraph_Cached_AT constructs G->AT, the transpose of G->A. This matrix is +// required by some of the algorithms. Basic algorithms may construct G->AT if +// they require it. The matrix G->AT is then available for subsequent use. +// If G->A changes, G->AT should be freed and recomputed. If G->AT already +// exists, it is left unchanged. As a result, if G->A changes, G->AT should +// be explictly freed. + +LAGRAPH_PUBLIC +int LAGraph_Cached_AT +( + // input/output: + LAGraph_Graph G, // graph for which to compute G->AT + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Cached_IsSymmetricStructure: determine G->is_symmetric_structure +//------------------------------------------------------------------------------ + +// LAGraph_Cached_IsSymmetricStructure determines if the sparsity structure of +// G->A is symmetric (ignoring its values). If G->kind denotes that the graph +// is undirected, this cached property is implicitly true (and not checked). +// Otherwise, this method determines if the structure of G->A for a directed +// graph G has a symmetric sparsity structure. No work is performed if the +// cached property is already known. + +LAGRAPH_PUBLIC +int LAGraph_Cached_IsSymmetricStructure +( + // input/output: + LAGraph_Graph G, // graph to determine the symmetry of structure of A + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Cached_OutDegree: determine G->out_degree +//------------------------------------------------------------------------------ + +// LAGraph_Cached_OutDegree computes G->out_degree. No work is performed if +// it already exists in G. + +LAGRAPH_PUBLIC +int LAGraph_Cached_OutDegree +( + // input/output: + LAGraph_Graph G, // graph to determine G->out_degree + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Cached_InDegree: determine G->in_degree +//------------------------------------------------------------------------------ + +// LAGraph_Cached_InDegree computes G->in_degree. No work is performed if it +// already exists in G. If G is undirected, G->in_degree is never computed +// and remains NULL (the method returns LAGRAPH_CACHE_NOT_NEEDED). No work is +// performed if it is already exists in G. + +LAGRAPH_PUBLIC +int LAGraph_Cached_InDegree +( + // input/output: + LAGraph_Graph G, // graph to determine G->in_degree + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Cached_NSelfEdges: determine G->nself_edges +//------------------------------------------------------------------------------ + +// LAGraph_Cached_NSelfEdges computes G->nself_edges, the number of diagonal entries +// that appear in the G->A matrix. For an undirected or directed graph with an +// adjacency matrix G->A, these are the number of self-edges in G. No work is +// performed it is already computed. + +LAGRAPH_PUBLIC +int LAGraph_Cached_NSelfEdges +( + // input/output: + LAGraph_Graph G, // graph to compute G->nself_edges + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Cached_EMin: determine G->emin +//------------------------------------------------------------------------------ + +// LAGraph_Cached_EMin computes G->emin = min (G->A). + +LAGRAPH_PUBLIC +int LAGraph_Cached_EMin +( + // input/output: + LAGraph_Graph G, // graph to determine G->emin + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Cached_EMax: determine G->emax +//------------------------------------------------------------------------------ + +// LAGraph_Cached_EMax computes G->emax = max (G->A). + +LAGRAPH_PUBLIC +int LAGraph_Cached_EMax +( + // input/output: + LAGraph_Graph G, // graph to determine G->emax + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_DeleteSelfEdges: remove all diagonal entries from G->A +//------------------------------------------------------------------------------ + +// LAGraph_DeleteSelfEdges removes any diagonal entries from G->A. Most cached +// properties are cleared or set to LAGRAPH_UNKNOWN. G->nself_edges is set to +// zero, and G->is_symmetric_structure is left unchanged. + +LAGRAPH_PUBLIC +int LAGraph_DeleteSelfEdges +( + // input/output: + LAGraph_Graph G, // diagonal entries removed, most cached properties + // cleared + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_CheckGraph: determine if a graph is valid +//------------------------------------------------------------------------------ + +// LAGraph_CheckGraph determines if a graph is valid. Only basic checks are +// performed on the cached properties, taking O(1) time. + +LAGRAPH_PUBLIC +int LAGraph_CheckGraph +( + // input/output: + LAGraph_Graph G, // graph to check + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_GetNumThreads: determine # of OpenMP threads to use +//------------------------------------------------------------------------------ + +// FIXME: start here for next LAGraph meeting: June 1, 2022 + +// LAGraph_GetNumThreads determines the current number of OpenMP threads that +// can be used. See LAGraph_SetNumThreads for a description of nthreads_hi +// and nthreads_lo. + +LAGRAPH_PUBLIC +int LAGraph_GetNumThreads +( + // output: + int *nthreads_hi, // for outer region for nested parallelism + int *nthreads_lo, // for inner region of nested parallelism, or for the + // underlying GraphBLAS library + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_SetNumThreads: set # of OpenMP threads to use +//------------------------------------------------------------------------------ + +// LAGraph_SetNumThreads sets the current number of OpenMP threads that +// can be used. + +// Two thread counts can be controlled: +// +// nthreads_hi: this is the # of threads to be used in outer regions of a +// nested parallel construct, assuming that nthreads_lo is used in the +// inner region. The total number of threads used for an entire nested +// region in LAGraph is given by nthreads_hi*nthreads_lo. This product is +// also the # of threads that a flat parallel region in LAGraph may use. +// +// nthreads_lo: this is the # of threads to be used in an inner region of a +// nested parallel construct, or for the # of threads to be used in each +// call to the underlying GraphBLAS library. + +LAGRAPH_PUBLIC +int LAGraph_SetNumThreads +( + // input: + int nthreads_hi, + int nthreads_lo, + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Tic: start the timer +//------------------------------------------------------------------------------ + +// LAGraph_Tic starts a wallclock timer. Normally, this is simply a wrapper +// for omp_get_wtime, if OpenMP is in use. Otherwise, an OS-specific timing +// function is called. + +LAGRAPH_PUBLIC +int LAGraph_Tic +( + double tic [2], // tic [0]: seconds, tic [1]: nanoseconds + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Toc: return time since last call to LAGraph_Tic +//------------------------------------------------------------------------------ + +// LAGraph_Toc returns the time since the last call to LAGraph_Tic with the +// same tic input array (which is not modified). + +LAGRAPH_PUBLIC +int LAGraph_Toc +( + // output: + double *t, // time since last call to LAGraph_Tic + // input: + const double tic [2], // tic from last call to LAGraph_Tic + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_MMRead: read a matrix in MatrixMarket format +//------------------------------------------------------------------------------ + +/* The file format used here is compatible with all variations of the Matrix + * Market "coordinate" and "array" format (http://www.nist.gov/MatrixMarket), + * for sparse and dense matrices repsectively. The format is fully described + * in LAGraph/Doc/MatrixMarket.pdf, and summarized here (with extensions for + * LAGraph). + * + * The first line of the file starts with %%MatrixMarket, with the following + * format: + * + * %%MatrixMarket matrix + * + * is one of: coordinate or array. The former is a sparse matrix in + * triplet form. The latter is a dense matrix in column-major form. + * Both formats are returned as a GrB_Matrix. + * + * is one of: real, complex, pattern, or integer. The real, + * integer, and pattern formats are returned as GrB_FP64, GrB_INT64, and + * GrB_BOOL, respectively, but these types are modified by the %%GraphBLAS + * structured comment described below. Complex matrices are currently not + * supported. + * + * is one of: general, Hermitian, symmetric, or skew-symmetric. + * The Matrix Market format is case-insensitive, so "hermitian" and + * "Hermitian" are treated the same). + * + * Not all combinations are permitted. Only the following are meaningful: + * + * (1) (coordinate or array) x (real, integer, or complex) + * x (general, symmetric, or skew-symmetric) + * + * (2) (coordinate or array) x (complex) x (Hermitian) + * + * (3) (coodinate) x (pattern) x (general or symmetric) + * + * The second line is an optional extension to the Matrix Market format: + * + * %%GraphBLAS type + * + * is one of the 11 built-in types (bool, int8_t, int16_t, + * int32_t, int64_t, uint8_t, uint16_t, uint32_t, uint64_t, float, or + * double. + * + * If this second line is included, it overrides the default GraphBLAS + * types for the Matrix Market on line one of the file: real, + * pattern, and integer. The Matrix Market complex is not yet + * supported. + * + * Any other lines starting with "%" are treated as comments, and are ignored. + * Comments may be interspersed throughout the file. Blank lines are ignored. + * The Matrix Market header is optional in this routine (it is not optional in + * the Matrix Market format). If not present, the defaults to + * coordinate, defaults to real, and defaults to general. The + * remaining lines are space delimited, and free format (one or more spaces can + * appear, and each field has arbitrary width). + * + * The Matrix Market file can be coordinate or array: + * + * coordinate: for this format, the first non-comment line must appear, + * and it must contain three integers: + * + * nrows ncols nvals + * + * For example, a 5-by-12 matrix with 42 entries would have: + * + * 5 12 42 + * + * Each of the remaining lines defines one entry. The order is + * arbitrary. If the Matrix Market is real or integer, each + * line contains three numbers: row index, column index, and value. + * For example, if A(3,4) is equal to 5.77, a line: + * + * 3 4 5.77 + * + * would appear in the file. The indices in the Matrix Market are + * 1-based, so this entry becomes A(2,3) in the GrB_Matrix returned to + * the caller. If the is pattern, then only the row and column + * index appears. If is complex, four values appear. If + * A(8,4) has a real part of 6.2 and an imaginary part of -9.3, then + * the line is: + * + * 8 4 6.2 -9.3 + * + * and since the file is 1-based but a GraphBLAS matrix is always + * 0-based, one is subtracted from the row and column indices in the + * file, so this entry becomes A(7,3). + * + * array: for this format, the first non-comment line must appear, and it + * must contain just two integers: + * + * nrows ncols + * + * A 5-by-12 matrix would thus have the line + * + * 5 12 + * + * Each of the remaining lines defines one entry, in column major + * order. If the is real or integer, this is the value of the + * entry. An entry if of complex consists of two values, the + * real and imaginary part (not yet supported). The cannot be + * pattern in this case. + * + * For both coordinate and array formats, real and complex values may use + * the terms INF, +INF, -INF, and NAN to represent floating-point infinity + * and NaN values, in either upper or lower case. + * + * The token is general, symmetric, skew-symmetric, or Hermitian: + * + * general: the matrix has no symmetry properties (or at least none that + * were exploited when the file was created). + * + * symmetric: A(i,j) == A(j,i). Only entries on or below the diagonal + * appear in the file. Each off-diagonal entry in the file creates two + * entries in the GrB_Matrix that is returned. + * + * skew-symmetric: A(i,j) == -A(i,j). There are no entries on the + * diagonal. Only entries below the diagonal appear in the file. Each + * off-diagonal entry in the file creates two entries in the GrB_Matrix + * that is returned. + * + * Hermitian: square complex matrix with A(i,j) = conj (A(j,i)). All + * entries on the diagonal are real. Each off-diagonal entry in the file + * creates two entries in the GrB_Matrix that is returned. + * + * According to the Matrix Market format, entries are always listed in + * column-major order. This rule is follwed by LAGraph_MMWrite. However, + * LAGraph_MMRead can read the entries in any order. + * + * FUTURE: add support for user-defined types. + * + * @param[out] A handle of the matrix to create + * @param[in] f handle to an open file to read from + * @param[in,out] msg any error messages + * + * @retval GrB_SUCCESS if successful, + * @retval LAGRAPH_IO_ERROR if the file could not + * be read or contains a matrix with an invalid format + * @retval GrB_NOT_IMPLEMENTED if the type is not supported + */ + +LAGRAPH_PUBLIC +int LAGraph_MMRead +( + // output: + GrB_Matrix *A, // handle of matrix to create + // input: + FILE *f, // file to read from, already open + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_MMWrite: write a matrix in MatrixMarket format +//------------------------------------------------------------------------------ + +// LAGraph_MMWrite writes a matrix in MatrixMarket format. Refer to +// LAGraph_MMRead for a description of the output file format. The +// MatrixMarket header line always appears, followed by the second line +// containing the GraphBLAS type: +// %%GraphBLAS type + +// FUTURE: add support for user-defined types. + +LAGRAPH_PUBLIC +int LAGraph_MMWrite +( + // input: + GrB_Matrix A, // matrix to write to the file + FILE *f, // file to write it to, must be already open + FILE *fcomments, // optional file with extra comments, may be NULL + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Matrix_Structure: return the structure of a matrix +//------------------------------------------------------------------------------ + +// LAGraph_Matrix_Structure returns the sparsity structure of a matrix A as a +// boolean (GrB_BOOL) matrix C. If A(i,j) appears in the sparsity structure of +// A, then C(i,j) is set to true. The sparsity structure of A and C are +// identical. + +LAGRAPH_PUBLIC +int LAGraph_Matrix_Structure +( + // output: + GrB_Matrix *C, // a boolean matrix with same structure of A, with C(i,j) + // set to true if A(i,j) appears in the sparsity structure + // of A. + // input: + GrB_Matrix A, + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Vector_Structure: return the structure of a vector +//------------------------------------------------------------------------------ + +// LAGraph_Vector_Structure return the sparsity structure of a vector u as a +// boolean (GrB_BOOL) vector w. If u(i) appears in the sparsity structure of +// u, then w(i) is set to true. The sparsity structure of u and w are +// identical. + +LAGRAPH_PUBLIC +int LAGraph_Vector_Structure +( + // output: + GrB_Vector *w, // a boolean vector with same structure of u, with w(i) + // set to true if u(i) appears in the sparsity structure + // of u. + // input: + GrB_Vector u, + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_NameOfType: return the name of a type +//------------------------------------------------------------------------------ + +// LAGraph_NameOfType returns the name of a GraphBLAS type as a string. The +// names for the 11 built-in types (GrB_BOOL, GrB_INT8, etc) correspond to the +// names of the corresponding C types (bool, int8_t, etc). + +LAGRAPH_PUBLIC +int LAGraph_NameOfType +( + // output: + char *name, // name of the type: user provided array of size at + // least LAGRAPH_MAX_NAME_LEN. + // input: + GrB_Type type, // GraphBLAS type + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_TypeFromName: return a GrB_Type from its name +//------------------------------------------------------------------------------ + +// LAGraph_TypeFromName returns the GrB_Type corresponding to its name. That +// is, given the string "bool", this method returns GrB_BOOL. + +LAGRAPH_PUBLIC +int LAGraph_TypeFromName +( + // output: + GrB_Type *type, // GraphBLAS type + // input: + char *name, // name of the type: a null-terminated string + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_SizeOfType: return sizeof(...) of a GraphBLAS GrB_Type +//------------------------------------------------------------------------------ + +// LAGraph_SizeOfType returns sizeof(...) of a GraphBLAS GrB_Type. For +// example, if given the GrB_Type of GrB_FP64, the value sizeof(double) is +// returned. + +LAGRAPH_PUBLIC +int LAGraph_SizeOfType +( + // output: + size_t *size, // size of the type + // input: + GrB_Type type, // GraphBLAS type + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Matrix_TypeName: return the name of the GrB_Type of a GrB_Matrix +//------------------------------------------------------------------------------ + +// LAGraph_Matrix_TypeName returns the name of the GrB_Type of a GrB_Matrix. +// Currently, this method requires SuiteSparse:GraphBLAS. + +LAGRAPH_PUBLIC +int LAGraph_Matrix_TypeName +( + // output: + char *name, // name of the type of the matrix A (user-provided array + // of size at least LAGRAPH_MAX_NAME_LEN). + // input: + GrB_Matrix A, // matrix to query + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Vector_TypeName: return the name of the GrB_Type of a GrB_Vector +//------------------------------------------------------------------------------ + +// LAGraph_Vector_TypeName returns the name of the GrB_Type of a GrB_Vector. +// Currently, this method requires SuiteSparse:GraphBLAS. + +LAGRAPH_PUBLIC +int LAGraph_Vector_TypeName +( + // output: + char *name, // name of the type of the vector v (user-provided array + // of size at least LAGRAPH_MAX_NAME_LEN). + // input: + GrB_Vector v, // vector to query + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Scalar_TypeName: return the name of the GrB_Type of a GrB_Scalar +//------------------------------------------------------------------------------ + +// LAGraph_Scalar_TypeName returns the name of the GrB_Type of a GrB_Scalar. +// Currently, this method requires SuiteSparse:GraphBLAS. + +LAGRAPH_PUBLIC +int LAGraph_Scalar_TypeName +( + // output: + char *name, // name of the type of the scalar s (user-provided array + // of size at least LAGRAPH_MAX_NAME_LEN). + // input: + GrB_Scalar s, // scalar to query + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_KindName: return the name of a kind +//------------------------------------------------------------------------------ + +// LAGraph_KindName: return the name of a graph kind. For example, if given +// LAGraph_ADJACENCY_UNDIRECTED, the string "undirected" is returned. + +LAGRAPH_PUBLIC +int LAGraph_KindName +( + // output: + char *name, // name of the kind (user provided array of size at least + // LAGRAPH_MAX_NAME_LEN) + // input: + LAGraph_Kind kind, // graph kind + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_SortByDegree: sort a graph by its row or column degree +//------------------------------------------------------------------------------ + +// LAGraph_SortByDegree sorts the nodes of a graph by their out or in degrees. +// The graph G->A itself is not changed. Refer to LAGr_TriangleCount for an +// example of how to permute G->A after calling this function. The output &P +// must be freed by LAGraph_Free. + +LAGRAPH_PUBLIC +int LAGraph_SortByDegree +( + // output: + int64_t **P_handle, // P is returned as a permutation vector of size n + // input: + const LAGraph_Graph G, // graph of n nodes + bool byout, // if true, sort G->out_degree, else G->in_degree + bool ascending, // sort in ascending or descending order + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_SampleDegree: sample the degree median and mean +//------------------------------------------------------------------------------ + +// LAGraph_SampleDegree computes an estimate of the median and mean of the out +// or in degree, by randomly sampling the G->out_degree or G->in_degree +// vector. + +LAGRAPH_PUBLIC +int LAGraph_SampleDegree +( + // output: + double *sample_mean, // sampled mean degree + double *sample_median, // sampled median degree + // input: + const LAGraph_Graph G, // graph of n nodes + bool byout, // if true, sample G->out_degree, else G->in_degree + int64_t nsamples, // number of samples + uint64_t seed, // random number seed + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_DisplayGraph: print the contents of a graph +//------------------------------------------------------------------------------ + +// LAGraph_DisplayGraph prints the contents of a graph to a file in a human- +// readable form. This method is not meant for saving a graph to a file; +// see LAGraph_MMWrite for that method. + +typedef enum +{ + LAGraph_SILENT = 0, // nothing is printed + LAGraph_SUMMARY = 1, // print a terse summary + LAGraph_SHORT = 2, // short description, about 30 entries of a matrix + LAGraph_COMPLETE = 3, // print the entire contents of the object + LAGraph_SHORT_VERBOSE = 4, // LAGraph_SHORT but with "%.15g" for doubles + LAGraph_COMPLETE_VERBOSE = 5 // LAGraph_COMPLETE, but "%.15g" for doubles +} +LAGraph_Print_Level ; + +LAGRAPH_PUBLIC +int LAGraph_DisplayGraph +( + // input: + const LAGraph_Graph G, // graph to display + LAGraph_Print_Level pr, // print level (0 to 5) + FILE *f, // file to write to, must already be open + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Matrix_IsEqual: compare for exact equality +//------------------------------------------------------------------------------ + +// LAGraph_Matrix_IsEqual compares two matrices for exact equality. If the two +// matrices must have different data types, the result is always false (no +// typecasting is performed). Only the 11 built-in GrB* types are supported. + +LAGRAPH_PUBLIC +int LAGraph_Matrix_IsEqual +( + // output: + bool *result, // true if A == B, false if A != B or error + // input: + const GrB_Matrix A, + const GrB_Matrix B, + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Matrix_IsEqual_op: check if two matrices are equal with given op +//------------------------------------------------------------------------------ + +// LAGraph_Matrix_IsEqual_op compares two matrices using the given binary +// operator. The op may be built-in or user-defined. + +LAGRAPH_PUBLIC +int LAGraph_Matrix_IsEqual_op +( + // output: + bool *result, // true if A == B, false if A != B or error + // input: + const GrB_Matrix A, + const GrB_Matrix B, + const GrB_BinaryOp op, // comparator to use + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Vector_IsEqual: check if two vectors are equal +//------------------------------------------------------------------------------ + +/** + * Checks if two vectors are identically equal (same size, type (if accessible), + * pattern, and values) according to an equal operator of a type determined + * internally. + * + * @note If either or both contain NaN's, result will be false + * + * @param[out] result Set to true on return is vectors are "equal" + * @param[in] A First vector to compare + * @param[in] B Second vector to compare + * @param[out] msg If an error code is returned, + * this may hold an error msg. + * + * @retval GrB_SUCCESS if completed successfully (equal or not) + * @retval GrB_NULL_POINTER A, result or type is NULL + * @retval GrB_NOT_IMPLEMENTED type is not supported + * @return Any GraphBLAS errors that may have been encountered + */ +LAGRAPH_PUBLIC +int LAGraph_Vector_IsEqual +( + // output: + bool *result, // true if A == B, false if A != B or error + // input: + const GrB_Vector A, + const GrB_Vector B, + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Vector_IsEqual_op: check if two vectors are equal with given op +//------------------------------------------------------------------------------ + +/** + * Checks if two vectors are identically equal (same size, pattern, + * and values) according to a user specified comparator op. + * + * + * @param[out] result Set to true on return is vectors are "equal" + * @param[in] A First vector to compare + * @param[in] B Second vector to compare + * @param[in] op Binary operator to use for the comparisons + * @param[out] msg If an error code is returned, + * this may hold an error msg. + * + * @retval GrB_SUCCESS if completed successfully (equal or not) + * @retval GrB_NULL_POINTER result or op is NULL + * @return Any GraphBLAS errors that may have been encountered + */ +LAGRAPH_PUBLIC +int LAGraph_Vector_IsEqual_op +( + // output: + bool *result, // true if A == B, false if A != B or error + // input: + const GrB_Vector A, + const GrB_Vector B, + const GrB_BinaryOp op, // comparator to use + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Matrix_Print: pretty-print a matrix +//------------------------------------------------------------------------------ + +// LAGraph_Matrix_Print displays a matrix in a human-readable form. This +// method is not meant for saving a GrB_Matrix to a file; see LAGraph_MMWrite +// for that method. + +LAGRAPH_PUBLIC +int LAGraph_Matrix_Print +( + // input: + const GrB_Matrix A, // matrix to pretty-print to the file + LAGraph_Print_Level pr, // print level (0 to 5) + FILE *f, // file to write it to, must be already open; use + // stdout or stderr to print to those locations. + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Vector_Print: pretty-print a matrix +//------------------------------------------------------------------------------ + +// LAGraph_Vector_Print displays a vector in a human-readable form. This +// method is not meant for saving a GrB_Vector to a file. To perform that +// operation, copy the GrB_Vector into an n-by-1 GrB_Matrix and use +// LAGraph_MMWrite. + +LAGRAPH_PUBLIC +int LAGraph_Vector_Print +( + // input: + const GrB_Vector v, // vector to pretty-print to the file + LAGraph_Print_Level pr, // print level (0 to 5) + FILE *f, // file to write it to, must be already open; use + // stdout or stderr to print to those locations. + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Sort1: sort array of size n +//------------------------------------------------------------------------------ + +// LAGraph_Sort1 sorts an int64_t array of size n in ascending order. + +LAGRAPH_PUBLIC +int LAGraph_Sort1 +( + // input/output: + int64_t *A_0, // size n array + // input: + const int64_t n, + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Sort2: sort two arrays of size n +//------------------------------------------------------------------------------ + +// LAGraph_Sort2 sorts two int64_t arrays A of size n in ascending order. +// The arrays are kept in the same order, where the pair (A_0 [k], A_1 [k]) is +// treated as a single pair. The pairs are sorted by the first value A_0, +// with ties broken by A_1. + +LAGRAPH_PUBLIC +int LAGraph_Sort2 +( + // input/output: + int64_t *A_0, // size n array + int64_t *A_1, // size n array + // input: + const int64_t n, + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGraph_Sort2: sort three arrays of size n +//------------------------------------------------------------------------------ + +// LAGraph_Sort3 sorts three int64_t arrays A of size n in ascending order. +// The arrays are kept in the same order, where the triplet (A_0 [k], A_1 [k], +// A_2 [k]) is treated as a single triplet. The triplets are sorted by the +// first value A_0, with ties broken by A_1, and then by A_2 if the values of +// A_0 and A_1 are identical. + +LAGRAPH_PUBLIC +int LAGraph_Sort3 +( + // input/output: + int64_t *A_0, // size n array + int64_t *A_1, // size n array + int64_t *A_2, // size n array + // input: + const int64_t n, + char *msg +) ; + +//============================================================================== +// LAGraph Basic algorithms +//============================================================================== + +// Basic algorithm are meant to be easy to use. They may encompass many +// underlying Advanced algorithms, each with various parameters that may be +// controlled. For the Basic API, these parameters are determined +// automatically. Cached graph properties may be determined, and as a result, +// the graph G is both an input and an output of these methods, since they may +// be modified. + +// LAGraph Basic algorithms are named with the LAGraph_* prefix. + +//------------------------------------------------------------------------------ +// LAGraph_TriangleCount +//------------------------------------------------------------------------------ + +// This is a Basic algorithm (G->nself_edges, G->out_degree, +// G->is_symmetric_structure are computed, if not present). + +/* + * Count the triangles in a graph. + * + * @param[out] ntriangles On successful return, contains the number of tris. + * @param[in,out] G The graph, symmetric, no self loops. + * @param[out] msg Error message if a failure code is returned. + */ + +LAGRAPH_PUBLIC +int LAGraph_TriangleCount +( + // output: + uint64_t *ntriangles, // # of triangles + // input/output: + LAGraph_Graph G, + char *msg +) ; + +//============================================================================== +// LAGraph Advanced algorithms and utilities +//============================================================================== + +// The Advanced algorithms require the caller to select the algorithm and choose +// any parameter settings. G is not modified, and so it is an input-only +// parameter to these methods. If an Advanced algorithm requires a cached +// graph property to be computed, it must be computed prior to calling the +// Advanced method. + +// Advanced algorithms are named with the LAGr_* prefix, to distinguish them +// from Basic algorithms. + +//------------------------------------------------------------------------------ +// LAGr_Init: start GraphBLAS and LAGraph, and set malloc/etc functions +//------------------------------------------------------------------------------ + +// LAGr_Init is identical to LAGraph_Init, except that it allows the user +// application to specify the GraphBLAS mode. It also provides four memory +// management functions, replacing the standard malloc, calloc, realloc, and +// free. The functions user_malloc_function, user_calloc_function, +// user_realloc_function, and user_free_function have the same signature as the +// ANSI C malloc, calloc, realloc, and free functions, respectively. + +// Only user_malloc_function and user_free_function are required. +// user_calloc_function may be NULL, in which case LAGraph_Calloc uses +// LAGraph_Malloc and memset. Likewise, user_realloc_function may be NULL, in +// which case LAGraph_Realloc uses LAGraph_Malloc, memcpy, and LAGraph_Free. + +LAGRAPH_PUBLIC +int LAGr_Init +( + // input: + GrB_Mode mode, // mode for GrB_Init or GxB_Init + void * (* user_malloc_function ) (size_t), + void * (* user_calloc_function ) (size_t, size_t), + void * (* user_realloc_function ) (void *, size_t), + void (* user_free_function ) (void *), + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGr_BreadthFirstSearch: breadth-first search +//------------------------------------------------------------------------------ + +// This is an Advanced algorithm. G->AT and G->rowdgree are required to use +// the fastest push/pull method when using SuiteSparse:GraphBLAS. If these +// cached properties are not present, or if a vanilla GraphBLAS library is +// being used, then a push-only method is used (which can be slower). G is not +// modified; that is, G->AT and G->out_degree are not computed if not already +// cached. + +/* + * Perform breadth-first traversal, computing parent vertex ID's + * and/or level encountered. + * + * @param[out] level If non-NULL on input, on successful return, it + * contains the levels of each vertex reached. The + * src vertex is assigned level 0. If a vertex i is not + * reached, parent(i) is not present. + * The level vector is not computed if NULL. + * @param[out] parent If non-NULL on input, on successful return, it + * contains parent vertex IDs for each vertex reached. + * The src vertex will have itself as its parent. If a + * vertex i is not reached, parent(i) is not present. + * The parent vector is not computed if NULL. + * @param[in] G The graph, directed or undirected. + * @param[in] src The index of the src vertex (0-based) + * @param[out] msg Error message if a failure code is returned. + * + * @retval GrB_SUCCESS successful + * @retval LAGRAPH_INVALID_GRAPH Graph is invalid (LAGraph_CheckGraph failed) + */ + +LAGRAPH_PUBLIC +int LAGr_BreadthFirstSearch +( + // output: + GrB_Vector *level, + GrB_Vector *parent, + // input: + const LAGraph_Graph G, + GrB_Index src, + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGr_ConnectedComponents: connected components of an undirected graph +//------------------------------------------------------------------------------ + +// This is an Advanced algorithm (G->is_symmetric_structure must be known), + +LAGRAPH_PUBLIC +int LAGr_ConnectedComponents +( + // output: + GrB_Vector *component, // component(i)=s if node i is in the component + // whose representative node is s + // input: + const LAGraph_Graph G, // input graph + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGr_SingleSourceShortestPath: single-source shortest path +//------------------------------------------------------------------------------ + +// This is an Advanced algorithm (G->emin is required). + +// The graph G must have an adjacency matrix of type GrB_INT32, GrB_INT64, +// GrB_UINT32, GrB_UINT64, GrB_FP32, or GrB_FP64. If G->A has any other type, +// GrB_NOT_IMPLEMENTED is returned. + +// FUTURE: add a Basic algorithm that computes G->emin, G->emax, and then uses +// that information to compute an appropriate (estimated) Delta, + +LAGRAPH_PUBLIC +int LAGr_SingleSourceShortestPath +( + // output: + GrB_Vector *path_length, // path_length (i) is the length of the shortest + // path from the source vertex to vertex i + // input: + const LAGraph_Graph G, + GrB_Index source, // source vertex + GrB_Scalar Delta, // delta value for delta stepping + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGr_Betweenness: betweeness centrality metric +//------------------------------------------------------------------------------ + +// This is an Advanced algorithm (G->AT is required). + +LAGRAPH_PUBLIC +int LAGr_Betweenness +( + // output: + GrB_Vector *centrality, // centrality(i): betweeness centrality of i + // input: + const LAGraph_Graph G, // input graph + const GrB_Index *sources, // source vertices to compute shortest paths + int32_t ns, // number of source vertices + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGr_PageRank: pagerank +//------------------------------------------------------------------------------ + +// This is an Advanced algorithm (G->AT and G->out_degree are required). + +// LAGr_PageRank computes the standard pagerank of a directed graph G. Sinks +// (nodes with no out-going edges) are handled. This method should be used for +// production only, not for the GAP benchmark. + +LAGRAPH_PUBLIC +int LAGr_PageRank +( + // output: + GrB_Vector *centrality, // centrality(i): pagerank of node i + int *iters, // number of iterations taken + // input: + const LAGraph_Graph G, // input graph + float damping, // damping factor (typically 0.85) + float tol, // stopping tolerance (typically 1e-4) ; + int itermax, // maximum number of iterations (typically 100) + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGr_PageRankGAP: GAP-style pagerank +//------------------------------------------------------------------------------ + +// This is an Advanced algorithm (G->AT and G->out_degree are required). + +// LAGr_PageRankGAP computes the GAP-style pagerank of a directed graph G. +// Sinks (nodes with no out-going edges) are not handled. This method should +// be used for the GAP benchmark only, not for production. + +LAGRAPH_PUBLIC +int LAGr_PageRankGAP +( + // output: + GrB_Vector *centrality, // centrality(i): GAP-style pagerank of node i + int *iters, // number of iterations taken + // input: + const LAGraph_Graph G, // input graph + float damping, // damping factor (typically 0.85) + float tol, // stopping tolerance (typically 1e-4) ; + int itermax, // maximum number of iterations (typically 100) + char *msg +) ; + +//------------------------------------------------------------------------------ +// LAGr_TriangleCount: triangle counting +//------------------------------------------------------------------------------ + +// This is an Advanced algorithm (G->nself_edges, G->out_degree, +// G->is_symmetric_structure are required). + +/* Count the triangles in a graph. Advanced API + * + * @param[out] ntriangles On successful return, contains the number of tris. + * @param[in] G The graph, symmetric, no self loops, and for some + * methods (3-6), must have the cached row degree + * property calculated + * @param[in] method specifies which algorithm to use + * 0: use the default method + * 1: Burkhardt: ntri = sum (sum ((A^2) .* A)) / 6 + * 2: Cohen: ntri = sum (sum ((L * U) .* A)) / 2 + * 3: Sandia: ntri = sum (sum ((L * L) .* L)) + * 4: Sandia2: ntri = sum (sum ((U * U) .* U)) + * 5: SandiaDot: ntri = sum (sum ((L * U') .* L)). + * 6: SandiaDot2: ntri = sum (sum ((U * L') .* U)). + * @param[in,out] presort controls the presort of the graph. If set to 2 on + * input, presort will be set to sort type used + * on output: + * 0: no sort + * 1: sort by degree, ascending order + * -1: sort by degree, descending order + * 2: auto selection: + * Method Presort return value + * 1 0 + * 2 0 + * 3 1 + * 4 -1 + * 5 1 + * 6 -1 + * @param[out] msg Error message if a failure code is returned. + * + * @retval GrB_SUCCESS successful + * @retval GrB_INVALID_VALUE invalid method value + */ + +// FIXME: should these typedefs be LAGr_* since they are only used for +// Advanced methods? + +typedef enum +{ + LAGraph_TriangleCount_Default = 0, // use default method + LAGraph_TriangleCount_Burkhardt = 1, // sum (sum ((A^2) .* A)) / 6 + LAGraph_TriangleCount_Cohen = 2, // sum (sum ((L * U) .* A)) / 2 + LAGraph_TriangleCount_Sandia = 3, // sum (sum ((L * L) .* L)) + LAGraph_TriangleCount_Sandia2 = 4, // sum (sum ((U * U) .* U)) + LAGraph_TriangleCount_SandiaDot = 5, // sum (sum ((L * U') .* L)) + LAGraph_TriangleCount_SandiaDot2 = 6, // sum (sum ((U * L') .* U)) +} +LAGraph_TriangleCount_Method ; + +typedef enum +{ + LAGraph_TriangleCount_NoSort = 0, // no sort + LAGraph_TriangleCount_Ascending = 1, // sort by degree, ascending order + LAGraph_TriangleCount_Descending = -1, // sort by degree, descending order + LAGraph_TriangleCount_AutoSort = 2, // auto selection: no sort if rule + // is not triggered. Otherwise: sort in ascending order for methods 3 and + // 5, descending ordering for methods 4 and 6. On output, presort is + // modified to reflect the sorting method used (0, -1, or 1). If presort + // is NULL on input, no sort is performed. +} +LAGraph_TriangleCount_Presort ; + +LAGRAPH_PUBLIC +int LAGr_TriangleCount +( + // output: + uint64_t *ntriangles, + // input: + const LAGraph_Graph G, + LAGraph_TriangleCount_Method method, + LAGraph_TriangleCount_Presort *presort, + char *msg +) ; + +#endif diff --git a/doc/Delete_Me_for_V1/TODO.txt b/doc/Delete_Me_for_V1/TODO.txt index a014a533b5..b1cf9c8246 100644 --- a/doc/Delete_Me_for_V1/TODO.txt +++ b/doc/Delete_Me_for_V1/TODO.txt @@ -1,4 +1,4 @@ -As of May 18, 2022: +As of May 31, 2022: * cmake: need to find the right liblagraph and libgraphblas (not in /usr/local/lib*, but the one being compiled/tested). @@ -16,8 +16,6 @@ As of May 18, 2022: * add FUTURE to User Guide (see below) - * for BFS (with SS:GrB): if AT not present, use push-only method? - -------------------------------------------------------------------------------- add FUTURE items as a section in the User Guide: diff --git a/include/LAGraph.h b/include/LAGraph.h index f330b18388..cc82322cf6 100644 --- a/include/LAGraph.h +++ b/include/LAGraph.h @@ -31,12 +31,12 @@ //============================================================================== // See also the LAGraph_Version utility method, which returns these values. -// These definitions must match the same definitions in LAGraph/CMakeLists.txt. -// FIXME: use config to create include/LAGraph.h from LAGraph/CMakeLists.txt -#define LAGRAPH_DATE "May 20, 2022" -#define LAGRAPH_VERSION_MAJOR 0 -#define LAGRAPH_VERSION_MINOR 9 -#define LAGRAPH_VERSION_UPDATE 23 +// These definitions are derived from LAGraph/CMakeLists.txt. + +#define LAGRAPH_DATE "May 31, 2022" +#define LAGRAPH_VERSION_MAJOR 0 +#define LAGRAPH_VERSION_MINOR 9 +#define LAGRAPH_VERSION_UPDATE 26 //============================================================================== // include files and helper macros @@ -213,6 +213,7 @@ // that are not needed. These include G->AT and G->in_degree for an // undirected graph. +// LAGraph errors: #define LAGRAPH_INVALID_GRAPH (-1000) #define LAGRAPH_SYMMETRIC_STRUCTURE_REQUIRED (-1001) #define LAGRAPH_IO_ERROR (-1002) @@ -220,6 +221,7 @@ #define LAGRAPH_NO_SELF_EDGES_ALLOWED (-1004) #define LAGRAPH_CONVERGENCE_FAILURE (-1005) +// LAGraph warnings: #define LAGRAPH_CACHE_NOT_NEEDED ( 1000) // @retval GrB_SUCCESS if successful @@ -938,10 +940,11 @@ int LAGraph_CheckGraph // LAGraph_GetNumThreads: determine # of OpenMP threads to use //------------------------------------------------------------------------------ -// LAGraph_GetNumThreads determines the current number of OpenMP threads that -// can be used. +// FIXME: start here for next LAGraph meeting: June 1, 2022 -// FIXME: start here for next LAGraph meeting. +// LAGraph_GetNumThreads determines the current number of OpenMP threads that +// can be used. See LAGraph_SetNumThreads for a description of nthreads_hi +// and nthreads_lo. LAGRAPH_PUBLIC int LAGraph_GetNumThreads @@ -960,6 +963,18 @@ int LAGraph_GetNumThreads // LAGraph_SetNumThreads sets the current number of OpenMP threads that // can be used. +// Two thread counts can be controlled: +// +// nthreads_hi: this is the # of threads to be used in outer regions of a +// nested parallel construct, assuming that nthreads_lo is used in the +// inner region. The total number of threads used for an entire nested +// region in LAGraph is given by nthreads_hi*nthreads_lo. This product is +// also the # of threads that a flat parallel region in LAGraph may use. +// +// nthreads_lo: this is the # of threads to be used in an inner region of a +// nested parallel construct, or for the # of threads to be used in each +// call to the underlying GraphBLAS library. + LAGRAPH_PUBLIC int LAGraph_SetNumThreads ( @@ -1699,7 +1714,12 @@ int LAGr_Init // LAGr_BreadthFirstSearch: breadth-first search //------------------------------------------------------------------------------ -// This is an Advanced algorithm (G->AT and G->rowdgree are required). +// This is an Advanced algorithm. G->AT and G->rowdgree are required to use +// the fastest push/pull method when using SuiteSparse:GraphBLAS. If these +// cached properties are not present, or if a vanilla GraphBLAS library is +// being used, then a push-only method is used (which can be slower). G is not +// modified; that is, G->AT and G->out_degree are not computed if not already +// cached. /* * Perform breadth-first traversal, computing parent vertex ID's @@ -1802,8 +1822,9 @@ int LAGr_Betweenness // This is an Advanced algorithm (G->AT and G->out_degree are required). -// LAGr_PageRank computes the standard pagerank of a -// directed graph G. Sinks (nodes with no out-going edges) are handled. +// LAGr_PageRank computes the standard pagerank of a directed graph G. Sinks +// (nodes with no out-going edges) are handled. This method should be used for +// production only, not for the GAP benchmark. LAGRAPH_PUBLIC int LAGr_PageRank @@ -1825,9 +1846,9 @@ int LAGr_PageRank // This is an Advanced algorithm (G->AT and G->out_degree are required). -// LAGr_PageRankGAP computes the GAP-style pagerank of a -// directed graph G. Sinks (nodes with no out-going edges) are not handled. -// This method should be used for the GAP benchmark only, not for production. +// LAGr_PageRankGAP computes the GAP-style pagerank of a directed graph G. +// Sinks (nodes with no out-going edges) are not handled. This method should +// be used for the GAP benchmark only, not for production. LAGRAPH_PUBLIC int LAGr_PageRankGAP @@ -1884,6 +1905,9 @@ int LAGr_PageRankGAP * @retval GrB_INVALID_VALUE invalid method value */ +// FIXME: should these typedefs be LAGr_* since they are only used for +// Advanced methods? + typedef enum { LAGraph_TriangleCount_Default = 0, // use default method @@ -1916,7 +1940,7 @@ int LAGr_TriangleCount uint64_t *ntriangles, // input: const LAGraph_Graph G, - LAGraph_TriangleCount_Method method, + LAGraph_TriangleCount_Method method, LAGraph_TriangleCount_Presort *presort, char *msg ) ; diff --git a/src/algorithm/LAGr_BreadthFirstSearch.c b/src/algorithm/LAGr_BreadthFirstSearch.c index dfc8bcfe84..e4214a3e06 100644 --- a/src/algorithm/LAGr_BreadthFirstSearch.c +++ b/src/algorithm/LAGr_BreadthFirstSearch.c @@ -15,27 +15,27 @@ // and its GxB extensions, or a push-only method otherwise. The former is // much faster. -// This is an Advanced algorithm (G->AT and G->rowdgree are required). +// This is an Advanced algorithm. SuiteSparse can use a push/pull method if +// G->AT and G->rowdgree are provided. G->AT is not required if G is +// undirected. The vanilla method is always push-only. #include "LG_alg_internal.h" int LAGr_BreadthFirstSearch ( // output: - GrB_Vector *level, - GrB_Vector *parent, + GrB_Vector *level, + GrB_Vector *parent, // input: const LAGraph_Graph G, - GrB_Index src, - char *msg + GrB_Index src, + char *msg ) { #if LAGRAPH_SUITESPARSE - // requires G->AT and G->out_degree return LG_BreadthFirstSearch_SSGrB (level, parent, G, src, msg) ; #else - // requires no cached properties, but G is input-only anyway return LG_BreadthFirstSearch_vanilla (level, parent, G, src, msg) ; #endif } diff --git a/src/algorithm/LG_BreadthFirstSearch_SSGrB.c b/src/algorithm/LG_BreadthFirstSearch_SSGrB.c index 31805a07cf..3328d697b6 100644 --- a/src/algorithm/LG_BreadthFirstSearch_SSGrB.c +++ b/src/algorithm/LG_BreadthFirstSearch_SSGrB.c @@ -11,9 +11,12 @@ //------------------------------------------------------------------------------ -// This is an Advanced algorithm (G->AT and G->out_degree are required), -// but it is not user-callable (see LAGr_BreadthFirstSearch instead). - +// This is an Advanced algorithm. G->AT and G->out_degree are required for +// this method to use push-pull optimization. If not provided, this method +// defaults to a push-only algorithm, which can be slower. This is not +// user-callable (see LAGr_BreadthFirstSearch instead). G->AT and +// G->out_degree are not computed if not present. + // References: // // Carl Yang, Aydin Buluc, and John D. Owens. 2018. Implementing Push-Pull @@ -44,11 +47,11 @@ //**************************************************************************** int LG_BreadthFirstSearch_SSGrB ( - GrB_Vector *level, - GrB_Vector *parent, + GrB_Vector *level, + GrB_Vector *parent, const LAGraph_Graph G, - GrB_Index src, - char *msg + GrB_Index src, + char *msg ) { @@ -91,7 +94,7 @@ int LG_BreadthFirstSearch_SSGrB GRB_TRY (GrB_Matrix_nvals (&nvals, A)) ; - GrB_Matrix AT ; + GrB_Matrix AT = NULL ; GrB_Vector Degree = G->out_degree ; if (G->kind == LAGraph_ADJACENCY_UNDIRECTED || (G->kind == LAGraph_ADJACENCY_DIRECTED && @@ -102,19 +105,14 @@ int LG_BreadthFirstSearch_SSGrB } else { - // AT = A' is different from A + // AT = A' is different from A. If G->AT is NULL, then a push-only + // method is used. AT = G->AT ; - LG_ASSERT_MSG (AT != NULL, - LAGRAPH_NOT_CACHED, "G->AT is required") ; } - // FIXME: if AT is not present, do push-only? - - // direction-optimization requires G->AT and G->out_degree - LG_ASSERT_MSG (Degree != NULL, - LAGRAPH_NOT_CACHED, "G->out_degree is required") ; - - bool push_pull = true ; + // direction-optimization requires G->AT (if G is directed) and + // G->out_degree (for both undirected and directed cases) + bool push_pull = (Degree != NULL && AT != NULL) ; // determine the semiring type GrB_Type int_type = (n > INT32_MAX) ? GrB_INT64 : GrB_INT32 ; @@ -252,12 +250,12 @@ int LG_BreadthFirstSearch_SSGrB // mask is pi if computing parent, v if computing just level if (do_push) { - // q'{!mask} = q'*A + // push (saxpy-based vxm): q'{!mask} = q'*A GRB_TRY (GrB_vxm (q, mask, NULL, semiring, q, A, GrB_DESC_RSC)) ; } else { - // q{!mask} = AT*q + // pull (dot-product-based mxv): q{!mask} = AT*q GRB_TRY (GrB_mxv (q, mask, NULL, semiring, AT, q, GrB_DESC_RSC)) ; } diff --git a/src/test/test_BreadthFirstSearch.c b/src/test/test_BreadthFirstSearch.c index bf881259ee..83239328b3 100644 --- a/src/test/test_BreadthFirstSearch.c +++ b/src/test/test_BreadthFirstSearch.c @@ -481,79 +481,80 @@ void test_BreadthFirstSearch_many(void) OK (LAGraph_New (&G, &A, kind, msg)) ; TEST_CHECK (A == NULL) ; // A has been moved into G->A - // create its cached properties - int ok_result = (kind == LAGraph_ADJACENCY_UNDIRECTED) ? - LAGRAPH_CACHE_NOT_NEEDED : GrB_SUCCESS ; - int result = LAGraph_Cached_AT (G, msg) ; - TEST_CHECK (result == ok_result) ; - - OK (LAGraph_CheckGraph (G, msg)) ; - - OK (LAGraph_Cached_OutDegree (G, msg)) ; - OK (LAGraph_CheckGraph (G, msg)) ; - - result = LAGraph_Cached_InDegree (G, msg) ; - TEST_CHECK (result == ok_result) ; - OK (LAGraph_CheckGraph (G, msg)) ; - GrB_Index n = 0 ; OK (GrB_Matrix_nrows (&n, G->A)) ; - // run the BFS - int64_t step = (n > 100) ? (3*n/4) : ((n/4) + 1) ; - for (int64_t src = 0 ; src < n ; src += step) + for (int caching = 0 ; caching <= 1 ; caching++) { - GrB_Vector parent = NULL ; - GrB_Vector level = NULL ; - - int64_t maxlevel ; - GrB_Index nvisited ; - - OK (LAGr_BreadthFirstSearch (&level, &parent, G, src, msg)) ; - OK (LG_check_bfs (level, parent, G, src, msg)) ; - OK (GrB_reduce (&maxlevel, NULL, GrB_MAX_MONOID_INT64, - level, NULL)) ; - OK (GrB_Vector_nvals (&nvisited, level)) ; + // run the BFS + int64_t step = (n > 100) ? (3*n/4) : ((n/4) + 1) ; + for (int64_t src = 0 ; src < n ; src += step) { - printf ("src %g n: %g max level: %g nvisited: %g\n", - (double) src, (double) n, (double) maxlevel, - (double) nvisited) ; - } - OK (GrB_free(&parent)); - OK (GrB_free(&level)); - - OK (LG_BreadthFirstSearch_vanilla (&level, &parent, - G, src, msg)) ; - OK (LG_check_bfs (level, parent, G, src, msg)) ; - OK (GrB_reduce (&maxlevel, NULL, GrB_MAX_MONOID_INT64, - level, NULL)) ; - OK (GrB_Vector_nvals (&nvisited, level)) ; - { - printf ("src %g n: %g max level: %g nvisited: %g\n", - (double) src, (double) n, (double) maxlevel, - (double) nvisited) ; - } - OK (GrB_free(&parent)); - OK (GrB_free(&level)); - - OK (LAGr_BreadthFirstSearch (NULL, &parent, G, src, msg)) ; - OK (LG_check_bfs (NULL, parent, G, src, msg)) ; - OK (GrB_free(&parent)); + GrB_Vector parent = NULL ; + GrB_Vector level = NULL ; + + int64_t maxlevel ; + GrB_Index nvisited ; + + OK (LAGr_BreadthFirstSearch (&level, &parent, G, src, msg)) ; + OK (LG_check_bfs (level, parent, G, src, msg)) ; + OK (GrB_reduce (&maxlevel, NULL, GrB_MAX_MONOID_INT64, + level, NULL)) ; + OK (GrB_Vector_nvals (&nvisited, level)) ; + { + printf ("src %g n: %g max level: %g nvisited: %g\n", + (double) src, (double) n, (double) maxlevel, + (double) nvisited) ; + } + OK (GrB_free(&parent)); + OK (GrB_free(&level)); + + OK (LG_BreadthFirstSearch_vanilla (&level, &parent, + G, src, msg)) ; + OK (LG_check_bfs (level, parent, G, src, msg)) ; + OK (GrB_reduce (&maxlevel, NULL, GrB_MAX_MONOID_INT64, + level, NULL)) ; + OK (GrB_Vector_nvals (&nvisited, level)) ; + { + printf ("src %g n: %g max level: %g nvisited: %g\n", + (double) src, (double) n, (double) maxlevel, + (double) nvisited) ; + } + OK (GrB_free(&parent)); + OK (GrB_free(&level)); + + OK (LAGr_BreadthFirstSearch (NULL, &parent, G, src, msg)) ; + OK (LG_check_bfs (NULL, parent, G, src, msg)) ; + OK (GrB_free(&parent)); + + OK (LG_BreadthFirstSearch_vanilla (NULL, &parent, + G, src, msg)) ; + OK (LG_check_bfs (NULL, parent, G, src, msg)) ; + OK (GrB_free(&parent)); - OK (LG_BreadthFirstSearch_vanilla (NULL, &parent, - G, src, msg)) ; - OK (LG_check_bfs (NULL, parent, G, src, msg)) ; - OK (GrB_free(&parent)); + OK (LAGr_BreadthFirstSearch (&level, NULL, G, src, msg)) ; + OK (LG_check_bfs (level, NULL, G, src, msg)) ; + OK (GrB_free(&level)); - OK (LAGr_BreadthFirstSearch (&level, NULL, G, src, msg)) ; - OK (LG_check_bfs (level, NULL, G, src, msg)) ; - OK (GrB_free(&level)); + OK (LG_BreadthFirstSearch_vanilla (&level, NULL, G, src, msg)) ; + OK (LG_check_bfs (level, NULL, G, src, msg)) ; + OK (GrB_free(&level)); - OK (LG_BreadthFirstSearch_vanilla (&level, NULL, G, src, msg)) ; - OK (LG_check_bfs (level, NULL, G, src, msg)) ; - OK (GrB_free(&level)); + } + // create its cached properties + int ok_result = (kind == LAGraph_ADJACENCY_UNDIRECTED) ? + LAGRAPH_CACHE_NOT_NEEDED : GrB_SUCCESS ; + int result = LAGraph_Cached_AT (G, msg) ; + TEST_CHECK (result == ok_result) ; + OK (LAGraph_CheckGraph (G, msg)) ; + OK (LAGraph_Cached_OutDegree (G, msg)) ; + OK (LAGraph_CheckGraph (G, msg)) ; + result = LAGraph_Cached_InDegree (G, msg) ; + TEST_CHECK (result == ok_result) ; + OK (LAGraph_CheckGraph (G, msg)) ; } + OK (LAGraph_Delete (&G, msg)) ; } @@ -597,46 +598,48 @@ void test_bfs_brutal (void) continue ; } - // create its cached properties - int ok_result = (kind == LAGraph_ADJACENCY_UNDIRECTED) ? - LAGRAPH_CACHE_NOT_NEEDED : GrB_SUCCESS ; - int result = LAGraph_Cached_AT (G, msg) ; - TEST_CHECK (result == ok_result) ; - - OK (LAGraph_Cached_OutDegree (G, msg)) ; - result = LAGraph_Cached_InDegree (G, msg) ; - TEST_CHECK (result == ok_result) ; - - // run the BFS - int64_t step = (n > 100) ? (3*n/4) : ((n/4) + 1) ; - for (int64_t src = 0 ; src < n ; src += step) + for (int caching = 0 ; caching <= 1 ; caching++) { - GrB_Vector parent = NULL ; - GrB_Vector level = NULL ; - - // parent and level with SS:GrB - LG_BRUTAL_BURBLE (LAGr_BreadthFirstSearch (&level, &parent, G, src, msg)) ; - OK (LG_check_bfs (level, parent, G, src, msg)) ; - OK (GrB_free (&parent)) ; - OK (GrB_free (&level)) ; - - // level only with SS:GrB - LG_BRUTAL (LAGr_BreadthFirstSearch (&level, NULL, G, src, msg)) ; - OK (LG_check_bfs (level, NULL, G, src, msg)) ; - OK (GrB_free (&level)) ; - - // parent and level with vanilla - LG_BRUTAL (LG_BreadthFirstSearch_vanilla (&level, - &parent, G, src, msg)) ; - OK (LG_check_bfs (level, parent, G, src, msg)) ; - OK (GrB_free (&parent)) ; - OK (GrB_free (&level)) ; - - // level-only with vanilla - LG_BRUTAL (LG_BreadthFirstSearch_vanilla (&level, NULL, - G, src, msg)) ; - OK (LG_check_bfs (level, NULL, G, src, msg)) ; - OK (GrB_free (&level)) ; + // run the BFS + int64_t step = (n > 100) ? (3*n/4) : ((n/4) + 1) ; + for (int64_t src = 0 ; src < n ; src += step) + { + GrB_Vector parent = NULL ; + GrB_Vector level = NULL ; + + // parent and level with SS:GrB + LG_BRUTAL_BURBLE (LAGr_BreadthFirstSearch (&level, &parent, G, src, msg)) ; + OK (LG_check_bfs (level, parent, G, src, msg)) ; + OK (GrB_free (&parent)) ; + OK (GrB_free (&level)) ; + + // level only with SS:GrB + LG_BRUTAL (LAGr_BreadthFirstSearch (&level, NULL, G, src, msg)) ; + OK (LG_check_bfs (level, NULL, G, src, msg)) ; + OK (GrB_free (&level)) ; + + // parent and level with vanilla + LG_BRUTAL (LG_BreadthFirstSearch_vanilla (&level, + &parent, G, src, msg)) ; + OK (LG_check_bfs (level, parent, G, src, msg)) ; + OK (GrB_free (&parent)) ; + OK (GrB_free (&level)) ; + + // level-only with vanilla + LG_BRUTAL (LG_BreadthFirstSearch_vanilla (&level, NULL, + G, src, msg)) ; + OK (LG_check_bfs (level, NULL, G, src, msg)) ; + OK (GrB_free (&level)) ; + } + + // create its cached properties + int ok_result = (kind == LAGraph_ADJACENCY_UNDIRECTED) ? + LAGRAPH_CACHE_NOT_NEEDED : GrB_SUCCESS ; + int result = LAGraph_Cached_AT (G, msg) ; + TEST_CHECK (result == ok_result) ; + OK (LAGraph_Cached_OutDegree (G, msg)) ; + result = LAGraph_Cached_InDegree (G, msg) ; + TEST_CHECK (result == ok_result) ; } OK (LAGraph_Delete (&G, msg)) ; @@ -658,5 +661,5 @@ TEST_LIST = { {"BreadthFirstSearch_many", test_BreadthFirstSearch_many}, {"BreadthFirstSearch_brutal", test_bfs_brutal }, {NULL, NULL} -}; +} ; From 81e75985ce496f928938120459bb4f63ef6f44eb Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Tue, 31 May 2022 11:29:27 -0500 Subject: [PATCH 14/53] only 7.1.0 --- .github/workflows/build.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8ffab683f5..cbac7eb876 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,10 +8,6 @@ jobs: strategy: matrix: config: - - {grb_version: 6.0.2, conda_grb_package_hash: h9c3ff4c} - - {grb_version: 6.1.4, conda_grb_package_hash: h9c3ff4c} - - {grb_version: 6.2.4, conda_grb_package_hash: h27087fc} - - {grb_version: 7.0.1, conda_grb_package_hash: h27087fc} - {grb_version: 7.1.0, conda_grb_package_hash: h27087fc} steps: - name: Checkout @@ -51,10 +47,6 @@ jobs: strategy: matrix: config: - - {grb_version: 6.0.2, conda_grb_package_hash: h4a89273} - - {grb_version: 6.1.4, conda_grb_package_hash: h4a89273} - - {grb_version: 6.2.4, conda_grb_package_hash: h3f3baac} - - {grb_version: 7.0.1, conda_grb_package_hash: h3f3baac} - {grb_version: 7.1.0, conda_grb_package_hash: h7881ed4} steps: - name: Checkout From 39b969ecadd25bad4bf73219a11c7922266052a2 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Fri, 3 Jun 2022 13:21:20 -0500 Subject: [PATCH 15/53] debug --- src/algorithm/LAGr_TriangleCount.c | 3 ++- src/benchmark/LAGraph_demo.h | 2 +- src/benchmark/tc_gpu_demo.c | 27 +++++++++++++++------------ 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/algorithm/LAGr_TriangleCount.c b/src/algorithm/LAGr_TriangleCount.c index 11d2ed7776..1dbe32d6da 100644 --- a/src/algorithm/LAGr_TriangleCount.c +++ b/src/algorithm/LAGr_TriangleCount.c @@ -280,7 +280,8 @@ int LAGr_TriangleCount case LAGraph_TriangleCount_Burkhardt: // 1: sum (sum ((A^2) .* A)) / 6 - GRB_TRY (GrB_mxm (C, A, NULL, semiring, A, A, GrB_DESC_S)) ; + // using the dot product method, A*A' instead of A^2: + GRB_TRY (GrB_mxm (C, A, NULL, semiring, A, A, GrB_DESC_ST1)) ; GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; ntri /= 6 ; break ; diff --git a/src/benchmark/LAGraph_demo.h b/src/benchmark/LAGraph_demo.h index ad59edf614..30787b5538 100644 --- a/src/benchmark/LAGraph_demo.h +++ b/src/benchmark/LAGraph_demo.h @@ -1113,7 +1113,7 @@ static inline int demo_init (bool burble) #else // use the GPU // rmm_wrap_initialize (rmm_wrap_managed, INT32_MAX, INT64_MAX) ; - rmm_wrap_initialize (rmm_wrap_managed, 256 * 1000000L, 256 * 100000000L) ; + rmm_wrap_initialize (rmm_wrap_managed, 256 * 1000000L, 256 * 1000000000L) ; LAGRAPH_TRY (LAGr_Init (GxB_NONBLOCKING_GPU, rmm_wrap_malloc, rmm_wrap_calloc, rmm_wrap_realloc, rmm_wrap_free, NULL)) ; GxB_set (GxB_GPU_CONTROL, GxB_GPU_ALWAYS) ; diff --git a/src/benchmark/tc_gpu_demo.c b/src/benchmark/tc_gpu_demo.c index 937cdfbdda..4ab7663eae 100644 --- a/src/benchmark/tc_gpu_demo.c +++ b/src/benchmark/tc_gpu_demo.c @@ -80,7 +80,7 @@ int main (int argc, char **argv) LAGraph_Graph G = NULL ; // start GraphBLAS and LAGraph - bool burble = false ; + bool burble = true ; demo_init (burble) ; int ntrials = 5 ; @@ -177,7 +177,8 @@ int main (int argc, char **argv) // warmup for more accurate timing, and also print # of triangles LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; printf ("\nwarmup method: ") ; - int presort = LAGraph_TriangleCount_AutoSort ; // = 2 (auto selection) +// int presort = LAGraph_TriangleCount_AutoSort ; // = 2 (auto selection) + int presort = LAGraph_TriangleCount_NoSort ; // HACK print_method (stdout, 6, presort) ; // warmup method: without the GPU @@ -198,7 +199,7 @@ int main (int argc, char **argv) (double) ntsimple) ; fflush (stdout) ; fflush (stderr) ; - abort ( ) ; + // abort ( ) ; } #endif @@ -221,7 +222,7 @@ int main (int argc, char **argv) (double) ntsimple) ; fflush (stdout) ; fflush (stderr) ; - abort ( ) ; + // abort ( ) ; } #endif @@ -237,11 +238,13 @@ int main (int argc, char **argv) // for (int method = 5 ; method <= 6 ; method++) // try all methods 3 to 5 - for (int method = 3 ; method <= 5 ; method++) +// for (int method = 3 ; method <= 5 ; method++) + for (int method = 1 ; method <= 1 ; method++) // HACK { // for (int sorting = -1 ; sorting <= 2 ; sorting++) int sorting = LAGraph_TriangleCount_AutoSort ; // just use auto-sort + sorting = LAGraph_TriangleCount_NoSort ; // HACK: no-sort { printf ("\nMethod: ") ; int presort ; @@ -251,12 +254,12 @@ int main (int argc, char **argv) printf ("kron fails on method %d; skipped\n", method) ; continue ; } - if (n != 134217728 && method < 5) - { - printf ("all but urand is slow with method %d: skipped\n", - method) ; - continue ; - } +// if (n != 134217728 && method < 5) +// { +// printf ("all but urand is slow with method %d: skipped\n", +// method) ; +// continue ; +// } for (int t = 1 ; t <= nt ; t++) { @@ -302,7 +305,7 @@ int main (int argc, char **argv) printf ("Test failure!\n") ; fflush (stdout) ; fflush (stderr) ; - abort ( ) ; + // abort ( ) ; } #endif fprintf (stderr, "Avg: TC method%d.%d %3d: %10.3f sec: %s\n", From 105ccc6d95bc53987a98b7c0f8392811763b13e0 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Fri, 3 Jun 2022 13:27:15 -0500 Subject: [PATCH 16/53] threads --- src/benchmark/tc_gpu_demo.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/benchmark/tc_gpu_demo.c b/src/benchmark/tc_gpu_demo.c index 4ab7663eae..c2d5163d64 100644 --- a/src/benchmark/tc_gpu_demo.c +++ b/src/benchmark/tc_gpu_demo.c @@ -24,12 +24,12 @@ #include "LAGraph_demo.h" -//#define NTHREAD_LIST 1 +#define NTHREAD_LIST 1 // #define NTHREAD_LIST 2 -//#define THREAD_LIST 0 +#define THREAD_LIST 40 0 - #define NTHREAD_LIST 7 - #define THREAD_LIST 64, 32, 24, 12, 8, 4, 0 +// #define NTHREAD_LIST 7 +// #define THREAD_LIST 64, 32, 24, 12, 8, 4, 0 #define LG_FREE_ALL \ { \ @@ -265,7 +265,7 @@ int main (int argc, char **argv) { int nthreads = Nthreads [t] ; if (nthreads > nthreads_max) continue ; - if (nthreads != 0) // Use GPU + if (nthreads != 0) // Use CPU { GxB_Global_Option_set( GxB_GLOBAL_GPU_CONTROL, GxB_GPU_NEVER); printf(" CPU ONLY using %d threads", nthreads); From b4886bbd7f8b1ed83f4ff55ee2ae1236134d28bc Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Fri, 3 Jun 2022 13:33:14 -0500 Subject: [PATCH 17/53] debug --- src/benchmark/tc_gpu_demo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/benchmark/tc_gpu_demo.c b/src/benchmark/tc_gpu_demo.c index c2d5163d64..0a4db8ef8c 100644 --- a/src/benchmark/tc_gpu_demo.c +++ b/src/benchmark/tc_gpu_demo.c @@ -26,7 +26,7 @@ #define NTHREAD_LIST 1 // #define NTHREAD_LIST 2 -#define THREAD_LIST 40 0 +#define THREAD_LIST 40, 0 // #define NTHREAD_LIST 7 // #define THREAD_LIST 64, 32, 24, 12, 8, 4, 0 From 253783ea10d36eade7e6bb877a5d6eb7fa26a357 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Fri, 3 Jun 2022 13:46:43 -0500 Subject: [PATCH 18/53] gpu_demo --- src/benchmark/tc_gpu_demo.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/benchmark/tc_gpu_demo.c b/src/benchmark/tc_gpu_demo.c index 0a4db8ef8c..384fad5f43 100644 --- a/src/benchmark/tc_gpu_demo.c +++ b/src/benchmark/tc_gpu_demo.c @@ -24,8 +24,7 @@ #include "LAGraph_demo.h" -#define NTHREAD_LIST 1 -// #define NTHREAD_LIST 2 +#define NTHREAD_LIST 2 #define THREAD_LIST 40, 0 // #define NTHREAD_LIST 7 From ffe5ccb644f3d1ce890b1b2eecc19293ef8131ba Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Fri, 3 Jun 2022 14:24:42 -0500 Subject: [PATCH 19/53] debug merge path --- src/algorithm/LAGr_TriangleCount.c | 39 ++++++++++++++++++++++++++++++ src/benchmark/tc_gpu_demo.c | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/algorithm/LAGr_TriangleCount.c b/src/algorithm/LAGr_TriangleCount.c index 1dbe32d6da..cad776c040 100644 --- a/src/algorithm/LAGr_TriangleCount.c +++ b/src/algorithm/LAGr_TriangleCount.c @@ -96,6 +96,8 @@ static int tricount_prep #define LG_FREE_ALL \ { \ GrB_free (&C) ; \ + GrB_free (&C_gpu) ; \ + GrB_free (&Delta) ; \ GrB_free (&L) ; \ GrB_free (&T) ; \ GrB_free (&U) ; \ @@ -120,6 +122,7 @@ int LAGr_TriangleCount LG_CLEAR_MSG ; GrB_Matrix C = NULL, L = NULL, U = NULL, T = NULL ; + GrB_Matrix C_gpu = NULL, Delta = NULL, Work = NULL ; int64_t *P = NULL ; LG_ASSERT_MSG ( method == LAGraph_TriangleCount_Default || // 0: use default method @@ -179,6 +182,9 @@ int LAGr_TriangleCount GrB_Index n ; GRB_TRY (GrB_Matrix_nrows (&n, A)) ; GRB_TRY (GrB_Matrix_new (&C, GrB_INT64, n, n)) ; + GRB_TRY (GrB_Matrix_new (&C_gpu, GrB_INT64, n, n)) ; + GRB_TRY (GrB_Matrix_new (&Delta, GrB_INT64, n, n)) ; + GRB_TRY (GrB_Matrix_new (&Work, GrB_INT64, n, n)) ; #if LAGRAPH_SUITESPARSE GrB_Semiring semiring = GxB_PLUS_PAIR_INT64 ; #else @@ -274,6 +280,7 @@ int LAGr_TriangleCount //-------------------------------------------------------------------------- int64_t ntri ; + GrB_Desc_Value save ; switch (method) { @@ -281,7 +288,39 @@ int LAGr_TriangleCount case LAGraph_TriangleCount_Burkhardt: // 1: sum (sum ((A^2) .* A)) / 6 // using the dot product method, A*A' instead of A^2: + GxB_get (GxB_GPU_CONTROL, &save) ; + + // use the CPU + GxB_set (GxB_GPU_CONTROL, GxB_GPU_NEVER) ; GRB_TRY (GrB_mxm (C, A, NULL, semiring, A, A, GrB_DESC_ST1)) ; + + // use the GPU + GxB_set (GxB_GPU_CONTROL, GxB_GPU_ALWAYS) ; + GRB_TRY (GrB_mxm (C_gpu, A, NULL, semiring, A, A, GrB_DESC_ST1)) ; + + // compare: Delta = C - C_gpu + GRB_TRY (GrB_eWiseAdd (Delta, NULL, NULL, GrB_MINUS_INT64, + C, C_gpu, NULL)) ; + // drop explicit zeros from Delta + GRB_TRY (GrB_Matrix_select_INT64 (Delta, NULL, NULL, + GrB_VALUENE_INT64, Delta, (int64_t) 0, NULL)) ; + GRB_TRY (GxB_print (Delta, 3)) ; + + // look at Delta in C and C_gpu: + GRB_TRY (GrB_assign (Work, Delta, NULL, C, + GrB_ALL, n, GrB_ALL, n, GrB_DESC_S)) ; + printf ("relevant entries in C:\n") ; + GRB_TRY (GxB_print (Work, 3)) ; + GRB_TRY (GrB_Matrix_clear (Work)) ; + GRB_TRY (GrB_assign (Work, Delta, NULL, C_gpu, + GrB_ALL, n, GrB_ALL, n, GrB_DESC_S)) ; + printf ("relevant entries in C_gpu:\n") ; + GRB_TRY (GxB_print (Work, 3)) ; + GRB_TRY (GrB_Matrix_clear (Work)) ; + + // restore + GxB_set (GxB_GPU_CONTROL, save) ; + GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; ntri /= 6 ; break ; diff --git a/src/benchmark/tc_gpu_demo.c b/src/benchmark/tc_gpu_demo.c index 384fad5f43..3597f241fa 100644 --- a/src/benchmark/tc_gpu_demo.c +++ b/src/benchmark/tc_gpu_demo.c @@ -83,7 +83,7 @@ int main (int argc, char **argv) demo_init (burble) ; int ntrials = 5 ; - // ntrials = 1 ; // HACK + ntrials = 1 ; // HACK printf ("# of trials: %d\n", ntrials) ; int nt = NTHREAD_LIST ; From 9a5e3e6b4a593049bc3b043a391292a8aad9eaa2 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Fri, 3 Jun 2022 18:03:24 -0500 Subject: [PATCH 20/53] debugging mergepath --- src/algorithm/LAGr_TriangleCount.c | 33 ++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/algorithm/LAGr_TriangleCount.c b/src/algorithm/LAGr_TriangleCount.c index cad776c040..3396e2eb88 100644 --- a/src/algorithm/LAGr_TriangleCount.c +++ b/src/algorithm/LAGr_TriangleCount.c @@ -365,7 +365,40 @@ int LAGr_TriangleCount // using the masked dot product LG_TRY (tricount_prep (&L, &U, A, msg)) ; + + GxB_get (GxB_GPU_CONTROL, &save) ; + + // use the CPU + GxB_set (GxB_GPU_CONTROL, GxB_GPU_NEVER) ; GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, L, GrB_DESC_ST1)) ; + + // use the GPU + GxB_set (GxB_GPU_CONTROL, GxB_GPU_ALWAYS) ; + GRB_TRY (GrB_mxm (C_gpu, U, NULL, semiring, U, L, GrB_DESC_ST1)) ; + + // compare: Delta = C - C_gpu + GRB_TRY (GrB_eWiseAdd (Delta, NULL, NULL, GrB_MINUS_INT64, + C, C_gpu, NULL)) ; + // drop explicit zeros from Delta + GRB_TRY (GrB_Matrix_select_INT64 (Delta, NULL, NULL, + GrB_VALUENE_INT64, Delta, (int64_t) 0, NULL)) ; + GRB_TRY (GxB_print (Delta, 3)) ; + + // look at Delta in C and C_gpu: + GRB_TRY (GrB_assign (Work, Delta, NULL, C, + GrB_ALL, n, GrB_ALL, n, GrB_DESC_S)) ; + printf ("relevant entries in C:\n") ; + GRB_TRY (GxB_print (Work, 3)) ; + GRB_TRY (GrB_Matrix_clear (Work)) ; + GRB_TRY (GrB_assign (Work, Delta, NULL, C_gpu, + GrB_ALL, n, GrB_ALL, n, GrB_DESC_S)) ; + printf ("relevant entries in C_gpu:\n") ; + GRB_TRY (GxB_print (Work, 3)) ; + GRB_TRY (GrB_Matrix_clear (Work)) ; + + // restore + GxB_set (GxB_GPU_CONTROL, save) ; + GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; break ; } From 8aec0bb5dad0183d0daa8784133439f4f612b65c Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Tue, 7 Jun 2022 16:09:36 -0500 Subject: [PATCH 21/53] comment out debug code in LAGr_TriangleCount --- src/algorithm/LAGr_TriangleCount.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/algorithm/LAGr_TriangleCount.c b/src/algorithm/LAGr_TriangleCount.c index 3396e2eb88..844c9d0c7f 100644 --- a/src/algorithm/LAGr_TriangleCount.c +++ b/src/algorithm/LAGr_TriangleCount.c @@ -287,6 +287,15 @@ int LAGr_TriangleCount case LAGraph_TriangleCount_Burkhardt: // 1: sum (sum ((A^2) .* A)) / 6 +#if 1 + // using the dot product method, A*A' instead of A^2: + GRB_TRY (GrB_mxm (C, A, NULL, semiring, A, A, GrB_DESC_ST1)) ; + + // do it again for timing + GRB_TRY (GrB_Matrix_clear (C)) ; + GRB_TRY (GrB_mxm (C, A, NULL, semiring, A, A, GrB_DESC_ST1)) ; + +#else // using the dot product method, A*A' instead of A^2: GxB_get (GxB_GPU_CONTROL, &save) ; @@ -321,6 +330,7 @@ int LAGr_TriangleCount // restore GxB_set (GxB_GPU_CONTROL, save) ; +#endif GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; ntri /= 6 ; break ; @@ -366,6 +376,13 @@ int LAGr_TriangleCount // using the masked dot product LG_TRY (tricount_prep (&L, &U, A, msg)) ; +#if 1 + GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, L, GrB_DESC_ST1)) ; + + // do it again for timing + GRB_TRY (GrB_Matrix_clear (C)) ; + GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, L, GrB_DESC_ST1)) ; +#else GxB_get (GxB_GPU_CONTROL, &save) ; // use the CPU @@ -398,7 +415,7 @@ int LAGr_TriangleCount // restore GxB_set (GxB_GPU_CONTROL, save) ; - +#endif GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; break ; } From 80ebfaeaa6556cecdf375336cb95365dcfdabf8d Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Thu, 9 Jun 2022 09:28:23 -0500 Subject: [PATCH 22/53] iso in tc gpu --- src/benchmark/tc_gpu_demo.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/benchmark/tc_gpu_demo.c b/src/benchmark/tc_gpu_demo.c index 3597f241fa..ff7abc3684 100644 --- a/src/benchmark/tc_gpu_demo.c +++ b/src/benchmark/tc_gpu_demo.c @@ -126,6 +126,8 @@ int main (int argc, char **argv) GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; GRB_TRY (GrB_Matrix_nvals (&nvals, G->A)) ; + GxB_print (G->A, 2) ; +#if 0 // HACK: make sure G->A is non-iso // create an iterator @@ -150,11 +152,13 @@ int main (int argc, char **argv) GrB_free (&iterator) ; GxB_print (G->A, 2) ; -// GRB_TRY (GrB_Matrix_setElement (G->A, 0, 2, 2)) ; -// GxB_print (G->A, 3) ; GrB_wait (G->A, GrB_MATERIALIZE) ; -// GxB_print (G->A, 3) ; -// printf ("HERE ============================\n") ; + +#else + bool A_iso ; + GxB_Matrix_iso (&A_iso, A) ; + printf ("G->A iso: %d\n", A_iso) ; +#endif //-------------------------------------------------------------------------- // triangle counting From 96f2981954a2b01724b71eda7af1e719f5151cae Mon Sep 17 00:00:00 2001 From: Joe Eaton Date: Fri, 10 Jun 2022 08:55:25 -0500 Subject: [PATCH 23/53] Try SandiaDot2 for TC, add 'just kernel' timers for TC --- src/algorithm/LAGr_TriangleCount.c | 13 +++++++++++++ src/benchmark/tc_gpu_demo.c | 21 ++++++++++----------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/algorithm/LAGr_TriangleCount.c b/src/algorithm/LAGr_TriangleCount.c index 844c9d0c7f..1ea6d260ca 100644 --- a/src/algorithm/LAGr_TriangleCount.c +++ b/src/algorithm/LAGr_TriangleCount.c @@ -282,6 +282,8 @@ int LAGr_TriangleCount int64_t ntri ; GrB_Desc_Value save ; + double tic [2], ttot ; + switch (method) { @@ -347,16 +349,22 @@ int LAGr_TriangleCount // using the masked saxpy3 method LG_TRY (tricount_prep (&L, NULL, A, msg)) ; + LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; GRB_TRY (GrB_mxm (C, L, NULL, semiring, L, L, GrB_DESC_S)) ; GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; + LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; + printf (" Sandia tc_kernel_time: %14.8f \n", ttot); break ; case LAGraph_TriangleCount_Sandia2: // 4: sum (sum ((U * U) .* U)) // using the masked saxpy3 method LG_TRY (tricount_prep (NULL, &U, A, msg)) ; + LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, U, GrB_DESC_S)) ; GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; + LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; + printf (" Sandia2 tc_kernel_time: %14.8f \n", ttot); break ; default: @@ -367,8 +375,11 @@ int LAGr_TriangleCount // using the masked dot product LG_TRY (tricount_prep (&L, &U, A, msg)) ; + LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; GRB_TRY (GrB_mxm (C, L, NULL, semiring, L, U, GrB_DESC_ST1)) ; GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; + LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; + printf (" SandiaDot tc_kernel_time: %14.8f \n", ttot); break ; case LAGraph_TriangleCount_SandiaDot2: // 6: sum (sum ((U * L') .* U)) @@ -417,6 +428,8 @@ int LAGr_TriangleCount GxB_set (GxB_GPU_CONTROL, save) ; #endif GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; + LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; + printf (" SandiaDot2 tc_kernel_time: %14.8f \n", ttot); break ; } diff --git a/src/benchmark/tc_gpu_demo.c b/src/benchmark/tc_gpu_demo.c index ff7abc3684..ca9eec52df 100644 --- a/src/benchmark/tc_gpu_demo.c +++ b/src/benchmark/tc_gpu_demo.c @@ -178,7 +178,6 @@ int main (int argc, char **argv) #endif // warmup for more accurate timing, and also print # of triangles - LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; printf ("\nwarmup method: ") ; // int presort = LAGraph_TriangleCount_AutoSort ; // = 2 (auto selection) int presort = LAGraph_TriangleCount_NoSort ; // HACK @@ -187,6 +186,7 @@ int main (int argc, char **argv) // warmup method: without the GPU // LAGraph_TriangleCount_SandiaDot2 = 6, // sum (sum ((U * L') .* U)) GxB_set (GxB_GPU_CONTROL, GxB_GPU_NEVER) ; + LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; LAGRAPH_TRY (LAGr_TriangleCount (&ntriangles, G, LAGraph_TriangleCount_SandiaDot2, &presort, msg) ); printf ("# of triangles: %" PRIu64 " (CPU)\n", ntriangles) ; @@ -209,7 +209,9 @@ int main (int argc, char **argv) // warmup method: with the GPU // LAGraph_TriangleCount_SandiaDot2 = 6, // sum (sum ((U * L') .* U)) GrB_Index ntriangles_gpu ; + //presort = LAGraph_TriangleCount_NoSort ; //turn off sorting on GPU GxB_set (GxB_GPU_CONTROL, GxB_GPU_ALWAYS) ; + LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; LAGRAPH_TRY (LAGr_TriangleCount (&ntriangles_gpu, G, LAGraph_TriangleCount_SandiaDot2, &presort, msg) ); printf ("# of triangles: %" PRIu64 " (GPU)\n", ntriangles_gpu) ; @@ -218,6 +220,7 @@ int main (int argc, char **argv) printf ("nthreads: %3d time: %12.6f rate: %6.2f (SandiaDot2, warmup GPU)\n", nthreads_max, ttot, 1e-6 * nvals / ttot) ; + presort = LAGraph_TriangleCount_AutoSort ; // = 2 (auto selection) #if 1 if (ntriangles_gpu != ntsimple) { @@ -241,8 +244,7 @@ int main (int argc, char **argv) // for (int method = 5 ; method <= 6 ; method++) // try all methods 3 to 5 -// for (int method = 3 ; method <= 5 ; method++) - for (int method = 1 ; method <= 1 ; method++) // HACK + for (int method = 6 ; method <= 6 ; method++) { // for (int sorting = -1 ; sorting <= 2 ; sorting++) @@ -257,26 +259,23 @@ int main (int argc, char **argv) printf ("kron fails on method %d; skipped\n", method) ; continue ; } -// if (n != 134217728 && method < 5) -// { -// printf ("all but urand is slow with method %d: skipped\n", -// method) ; -// continue ; -// } for (int t = 1 ; t <= nt ; t++) { int nthreads = Nthreads [t] ; if (nthreads > nthreads_max) continue ; - if (nthreads != 0) // Use CPU + if (nthreads != 0) // Don't Use GPU { GxB_Global_Option_set( GxB_GLOBAL_GPU_CONTROL, GxB_GPU_NEVER); printf(" CPU ONLY using %d threads", nthreads); + presort = LAGraph_TriangleCount_AutoSort ; // = 2 (auto selection) } else { + nthreads = 40; GxB_Global_Option_set( GxB_GLOBAL_GPU_CONTROL, GxB_GPU_ALWAYS); printf(" GPU ONLY using %d threads", nthreads); + presort = LAGraph_TriangleCount_NoSort ; //turn off sorting on GPU } LAGRAPH_TRY (LAGraph_SetNumThreads (1, nthreads, msg)) ; @@ -285,7 +284,7 @@ int main (int argc, char **argv) for (int trial = 0 ; trial < ntrials ; trial++) { LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; - presort = sorting ; + //presort = sorting ; LAGRAPH_TRY( LAGr_TriangleCount (&nt2, G, method, From 1f3419ed09710fe4c318e5f6fbabe80ce7eb097a Mon Sep 17 00:00:00 2001 From: Joe Eaton Date: Thu, 7 Jul 2022 11:05:51 -0500 Subject: [PATCH 24/53] Added kernel timers and run SandiaDot2 for warmup, Burkhardt for timings --- src/algorithm/LAGr_TriangleCount.c | 12 ++++++++---- src/benchmark/tc_gpu_demo.c | 10 ++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/algorithm/LAGr_TriangleCount.c b/src/algorithm/LAGr_TriangleCount.c index 1ea6d260ca..ffd7a971e9 100644 --- a/src/algorithm/LAGr_TriangleCount.c +++ b/src/algorithm/LAGr_TriangleCount.c @@ -291,10 +291,11 @@ int LAGr_TriangleCount #if 1 // using the dot product method, A*A' instead of A^2: - GRB_TRY (GrB_mxm (C, A, NULL, semiring, A, A, GrB_DESC_ST1)) ; + //GRB_TRY (GrB_mxm (C, A, NULL, semiring, A, A, GrB_DESC_ST1)) ; // do it again for timing - GRB_TRY (GrB_Matrix_clear (C)) ; + // GRB_TRY (GrB_Matrix_clear (C)) ; + LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; GRB_TRY (GrB_mxm (C, A, NULL, semiring, A, A, GrB_DESC_ST1)) ; #else @@ -334,6 +335,8 @@ int LAGr_TriangleCount #endif GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; + LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; + printf (" Burkhardt tc_kernel_time: %14.8f \n", ttot); ntri /= 6 ; break ; @@ -388,10 +391,11 @@ int LAGr_TriangleCount LG_TRY (tricount_prep (&L, &U, A, msg)) ; #if 1 - GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, L, GrB_DESC_ST1)) ; + //GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, L, GrB_DESC_ST1)) ; // do it again for timing - GRB_TRY (GrB_Matrix_clear (C)) ; + //GRB_TRY (GrB_Matrix_clear (C)) ; + LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, L, GrB_DESC_ST1)) ; #else GxB_get (GxB_GPU_CONTROL, &save) ; diff --git a/src/benchmark/tc_gpu_demo.c b/src/benchmark/tc_gpu_demo.c index ca9eec52df..d54da2632c 100644 --- a/src/benchmark/tc_gpu_demo.c +++ b/src/benchmark/tc_gpu_demo.c @@ -83,7 +83,7 @@ int main (int argc, char **argv) demo_init (burble) ; int ntrials = 5 ; - ntrials = 1 ; // HACK + ntrials = 3 ; // HACK printf ("# of trials: %d\n", ntrials) ; int nt = NTHREAD_LIST ; @@ -189,9 +189,9 @@ int main (int argc, char **argv) LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; LAGRAPH_TRY (LAGr_TriangleCount (&ntriangles, G, LAGraph_TriangleCount_SandiaDot2, &presort, msg) ); + LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; printf ("# of triangles: %" PRIu64 " (CPU)\n", ntriangles) ; print_method (stdout, 6, presort) ; - LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; printf ("nthreads: %3d time: %12.6f rate: %6.2f (SandiaDot2, one trial)\n", nthreads_max, ttot, 1e-6 * nvals / ttot) ; @@ -214,12 +214,14 @@ int main (int argc, char **argv) LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; LAGRAPH_TRY (LAGr_TriangleCount (&ntriangles_gpu, G, LAGraph_TriangleCount_SandiaDot2, &presort, msg) ); + LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; printf ("# of triangles: %" PRIu64 " (GPU)\n", ntriangles_gpu) ; print_method (stdout, 6, presort) ; - LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; printf ("nthreads: %3d time: %12.6f rate: %6.2f (SandiaDot2, warmup GPU)\n", nthreads_max, ttot, 1e-6 * nvals / ttot) ; + GxB_set (GxB_GPU_CONTROL, GxB_GPU_NEVER) ; + presort = LAGraph_TriangleCount_AutoSort ; // = 2 (auto selection) #if 1 if (ntriangles_gpu != ntsimple) @@ -244,7 +246,7 @@ int main (int argc, char **argv) // for (int method = 5 ; method <= 6 ; method++) // try all methods 3 to 5 - for (int method = 6 ; method <= 6 ; method++) + for (int method = 1 ; method <= 1 ; method++) { // for (int sorting = -1 ; sorting <= 2 ; sorting++) From eec73b2426035d13414ea41ae207954e228e2010 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Thu, 25 Aug 2022 14:12:46 -0500 Subject: [PATCH 25/53] force hypersparse inputs --- src/benchmark/tc_gpu_demo.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/benchmark/tc_gpu_demo.c b/src/benchmark/tc_gpu_demo.c index d54da2632c..89568b513b 100644 --- a/src/benchmark/tc_gpu_demo.c +++ b/src/benchmark/tc_gpu_demo.c @@ -126,6 +126,8 @@ int main (int argc, char **argv) GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; GRB_TRY (GrB_Matrix_nvals (&nvals, G->A)) ; + GxB_set (G->A, GxB_SPARSITY_CONTROL, GxB_HYPERSPARSE) ; + GxB_print (G->A, 2) ; #if 0 // HACK: make sure G->A is non-iso From 99365b5d670860110d0c8dd26e626e66223a0b5f Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Fri, 26 Aug 2022 11:27:01 -0500 Subject: [PATCH 26/53] hyper_hash testing --- src/benchmark/tc_gpu_demo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/benchmark/tc_gpu_demo.c b/src/benchmark/tc_gpu_demo.c index 89568b513b..bcb0c95aaa 100644 --- a/src/benchmark/tc_gpu_demo.c +++ b/src/benchmark/tc_gpu_demo.c @@ -126,6 +126,7 @@ int main (int argc, char **argv) GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; GRB_TRY (GrB_Matrix_nvals (&nvals, G->A)) ; + printf ("Hack: force hypersparse\n") ; GxB_set (G->A, GxB_SPARSITY_CONTROL, GxB_HYPERSPARSE) ; GxB_print (G->A, 2) ; From 2a878e4119ba4d3d1c09d63ffea1a650889dcd58 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Thu, 8 Sep 2022 11:06:47 -0500 Subject: [PATCH 27/53] add Makefile --- Makefile | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..6e20eb754b --- /dev/null +++ b/Makefile @@ -0,0 +1,91 @@ +#------------------------------------------------------------------------------- +# LAGraph/Makefile +#------------------------------------------------------------------------------- + +# LAGraph, (c) 2021-2022 by The LAGraph Contributors, All Rights Reserved. +# SPDX-License-Identifier: BSD-2-Clause +# See additional acknowledgments in the LICENSE file, +# or contact permission@sei.cmu.edu for the full terms. + +#------------------------------------------------------------------------------- + +# A simple Makefile for LAGraph, which relies on cmake to do the actual build. +# All the work is done in cmake so this Makefile is just for convenience. + +# To compile and run the tests: +# +# make +# make test +# +# To compile with an alternate compiler: +# +# make CC=gcc CXX=g++ +# +# To compile/install for system-wide usage (typically in /usr/local): +# +# make +# sudo make install +# +# To compile/install for elsewhere (for example, in /home/me/mystuff/lib +# and /home/me/mystuff/include), do not use this Makefile. Instead, do: +# +# cd build +# cmake -DCMAKE_INSTALL_PREFIX="/home/me/mystuff" .. +# make +# make install +# +# To clean up the files: +# +# make clean +# +# To uninstall: +# +# make uninstall +# +# To compile and run test coverage: use "make cov". Next, open your browser to +# your local file, LAGraph/build/test_coverage/index.html. Be sure to do "make +# clean" afterwards, and then "make" to compile without test coverage. + +JOBS ?= 8 + +default: library + +library: + ( cd build && cmake $(CMAKE_OPTIONS) .. && $(MAKE) --jobs=${JOBS} ) + +# compile with -g for debugging +debug: + ( cd build && cmake $(CMAKE_OPTIONS) -DCMAKE_BUILD_TYPE=Debug .. && $(MAKE) --jobs=${JOBS} ) + +all: library + +test: library + ( cd build && make test ) + +# just compile after running cmake; do not run cmake again +remake: + ( cd build && $(MAKE) --jobs=${JOBS} ) + +# just run cmake to set things up +setup: + ( cd build ; cmake $(CMAKE_OPTIONS) .. ) + +install: + ( cd build ; $(MAKE) install ) + +# remove any installed libraries and #include files +uninstall: + - xargs rm < build/install_manifest.txt + +# clean, compile, and run test coverage +cov: distclean + ( cd build && cmake -DCOVERAGE=1 .. && $(MAKE) --jobs=${JOBS} && make test_coverage ) + +# remove all files not in the distribution +clean: distclean + +purge: distclean + +distclean: + - $(RM) -rf build/* config/*.tmp + From 10f6079fe3e791b91c918e5a53ac6ac25be063cd Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Mon, 12 Sep 2022 10:06:00 -0500 Subject: [PATCH 28/53] testing bitmap --- src/algorithm/LAGr_TriangleCount.c | 5 +++++ src/benchmark/tc_gpu_demo.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/algorithm/LAGr_TriangleCount.c b/src/algorithm/LAGr_TriangleCount.c index ffd7a971e9..af6520beac 100644 --- a/src/algorithm/LAGr_TriangleCount.c +++ b/src/algorithm/LAGr_TriangleCount.c @@ -396,6 +396,11 @@ int LAGr_TriangleCount // do it again for timing //GRB_TRY (GrB_Matrix_clear (C)) ; LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; + + // HACK: + GxB_set (L, GxB_SPARSITY_CONTROL, GxB_BITMAP) ; + GxB_print (L, 2) ; // FIXME SLOW!! + GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, L, GrB_DESC_ST1)) ; #else GxB_get (GxB_GPU_CONTROL, &save) ; diff --git a/src/benchmark/tc_gpu_demo.c b/src/benchmark/tc_gpu_demo.c index bcb0c95aaa..606c9baef6 100644 --- a/src/benchmark/tc_gpu_demo.c +++ b/src/benchmark/tc_gpu_demo.c @@ -126,8 +126,8 @@ int main (int argc, char **argv) GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; GRB_TRY (GrB_Matrix_nvals (&nvals, G->A)) ; - printf ("Hack: force hypersparse\n") ; - GxB_set (G->A, GxB_SPARSITY_CONTROL, GxB_HYPERSPARSE) ; +// printf ("Hack: force hypersparse\n") ; +// GxB_set (G->A, GxB_SPARSITY_CONTROL, GxB_HYPERSPARSE) ; GxB_print (G->A, 2) ; #if 0 From 26c12a25a779b1a2fbd42980f34b23858564b860 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Thu, 15 Sep 2022 11:30:54 -0500 Subject: [PATCH 29/53] bitmap dot3 testing --- src/algorithm/LAGr_TriangleCount.c | 108 ++++------------------------- src/benchmark/tc_gpu_demo.c | 1 - 2 files changed, 12 insertions(+), 97 deletions(-) diff --git a/src/algorithm/LAGr_TriangleCount.c b/src/algorithm/LAGr_TriangleCount.c index af6520beac..f22e40071c 100644 --- a/src/algorithm/LAGr_TriangleCount.c +++ b/src/algorithm/LAGr_TriangleCount.c @@ -289,51 +289,8 @@ int LAGr_TriangleCount case LAGraph_TriangleCount_Burkhardt: // 1: sum (sum ((A^2) .* A)) / 6 -#if 1 - // using the dot product method, A*A' instead of A^2: - //GRB_TRY (GrB_mxm (C, A, NULL, semiring, A, A, GrB_DESC_ST1)) ; - - // do it again for timing - // GRB_TRY (GrB_Matrix_clear (C)) ; LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; GRB_TRY (GrB_mxm (C, A, NULL, semiring, A, A, GrB_DESC_ST1)) ; - -#else - // using the dot product method, A*A' instead of A^2: - GxB_get (GxB_GPU_CONTROL, &save) ; - - // use the CPU - GxB_set (GxB_GPU_CONTROL, GxB_GPU_NEVER) ; - GRB_TRY (GrB_mxm (C, A, NULL, semiring, A, A, GrB_DESC_ST1)) ; - - // use the GPU - GxB_set (GxB_GPU_CONTROL, GxB_GPU_ALWAYS) ; - GRB_TRY (GrB_mxm (C_gpu, A, NULL, semiring, A, A, GrB_DESC_ST1)) ; - - // compare: Delta = C - C_gpu - GRB_TRY (GrB_eWiseAdd (Delta, NULL, NULL, GrB_MINUS_INT64, - C, C_gpu, NULL)) ; - // drop explicit zeros from Delta - GRB_TRY (GrB_Matrix_select_INT64 (Delta, NULL, NULL, - GrB_VALUENE_INT64, Delta, (int64_t) 0, NULL)) ; - GRB_TRY (GxB_print (Delta, 3)) ; - - // look at Delta in C and C_gpu: - GRB_TRY (GrB_assign (Work, Delta, NULL, C, - GrB_ALL, n, GrB_ALL, n, GrB_DESC_S)) ; - printf ("relevant entries in C:\n") ; - GRB_TRY (GxB_print (Work, 3)) ; - GRB_TRY (GrB_Matrix_clear (Work)) ; - GRB_TRY (GrB_assign (Work, Delta, NULL, C_gpu, - GrB_ALL, n, GrB_ALL, n, GrB_DESC_S)) ; - printf ("relevant entries in C_gpu:\n") ; - GRB_TRY (GxB_print (Work, 3)) ; - GRB_TRY (GrB_Matrix_clear (Work)) ; - - // restore - GxB_set (GxB_GPU_CONTROL, save) ; - -#endif GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; printf (" Burkhardt tc_kernel_time: %14.8f \n", ttot); @@ -352,22 +309,22 @@ int LAGr_TriangleCount // using the masked saxpy3 method LG_TRY (tricount_prep (&L, NULL, A, msg)) ; - LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; + LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; GRB_TRY (GrB_mxm (C, L, NULL, semiring, L, L, GrB_DESC_S)) ; GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; - LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; - printf (" Sandia tc_kernel_time: %14.8f \n", ttot); + LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; + printf (" Sandia tc_kernel_time: %14.8f \n", ttot); break ; case LAGraph_TriangleCount_Sandia2: // 4: sum (sum ((U * U) .* U)) // using the masked saxpy3 method LG_TRY (tricount_prep (NULL, &U, A, msg)) ; - LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; + LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, U, GrB_DESC_S)) ; GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; - LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; - printf (" Sandia2 tc_kernel_time: %14.8f \n", ttot); + LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; + printf (" Sandia2 tc_kernel_time: %14.8f \n", ttot); break ; default: @@ -378,11 +335,11 @@ int LAGr_TriangleCount // using the masked dot product LG_TRY (tricount_prep (&L, &U, A, msg)) ; - LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; + LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; GRB_TRY (GrB_mxm (C, L, NULL, semiring, L, U, GrB_DESC_ST1)) ; GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; - LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; - printf (" SandiaDot tc_kernel_time: %14.8f \n", ttot); + LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; + printf (" SandiaDot tc_kernel_time: %14.8f \n", ttot); break ; case LAGraph_TriangleCount_SandiaDot2: // 6: sum (sum ((U * L') .* U)) @@ -390,55 +347,14 @@ int LAGr_TriangleCount // using the masked dot product LG_TRY (tricount_prep (&L, &U, A, msg)) ; -#if 1 - //GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, L, GrB_DESC_ST1)) ; - - // do it again for timing - //GRB_TRY (GrB_Matrix_clear (C)) ; - LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; - // HACK: GxB_set (L, GxB_SPARSITY_CONTROL, GxB_BITMAP) ; - GxB_print (L, 2) ; // FIXME SLOW!! + LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, L, GrB_DESC_ST1)) ; -#else - GxB_get (GxB_GPU_CONTROL, &save) ; - - // use the CPU - GxB_set (GxB_GPU_CONTROL, GxB_GPU_NEVER) ; - GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, L, GrB_DESC_ST1)) ; - - // use the GPU - GxB_set (GxB_GPU_CONTROL, GxB_GPU_ALWAYS) ; - GRB_TRY (GrB_mxm (C_gpu, U, NULL, semiring, U, L, GrB_DESC_ST1)) ; - - // compare: Delta = C - C_gpu - GRB_TRY (GrB_eWiseAdd (Delta, NULL, NULL, GrB_MINUS_INT64, - C, C_gpu, NULL)) ; - // drop explicit zeros from Delta - GRB_TRY (GrB_Matrix_select_INT64 (Delta, NULL, NULL, - GrB_VALUENE_INT64, Delta, (int64_t) 0, NULL)) ; - GRB_TRY (GxB_print (Delta, 3)) ; - - // look at Delta in C and C_gpu: - GRB_TRY (GrB_assign (Work, Delta, NULL, C, - GrB_ALL, n, GrB_ALL, n, GrB_DESC_S)) ; - printf ("relevant entries in C:\n") ; - GRB_TRY (GxB_print (Work, 3)) ; - GRB_TRY (GrB_Matrix_clear (Work)) ; - GRB_TRY (GrB_assign (Work, Delta, NULL, C_gpu, - GrB_ALL, n, GrB_ALL, n, GrB_DESC_S)) ; - printf ("relevant entries in C_gpu:\n") ; - GRB_TRY (GxB_print (Work, 3)) ; - GRB_TRY (GrB_Matrix_clear (Work)) ; - - // restore - GxB_set (GxB_GPU_CONTROL, save) ; -#endif GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; - LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; - printf (" SandiaDot2 tc_kernel_time: %14.8f \n", ttot); + LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; + printf (" SandiaDot2 tc_kernel_time: %14.8f \n", ttot); break ; } diff --git a/src/benchmark/tc_gpu_demo.c b/src/benchmark/tc_gpu_demo.c index 606c9baef6..2a6477604b 100644 --- a/src/benchmark/tc_gpu_demo.c +++ b/src/benchmark/tc_gpu_demo.c @@ -129,7 +129,6 @@ int main (int argc, char **argv) // printf ("Hack: force hypersparse\n") ; // GxB_set (G->A, GxB_SPARSITY_CONTROL, GxB_HYPERSPARSE) ; - GxB_print (G->A, 2) ; #if 0 // HACK: make sure G->A is non-iso From 90304b75e353d0785bc33391d57125b856beaa41 Mon Sep 17 00:00:00 2001 From: Scott McMillan Date: Thu, 6 Oct 2022 09:46:46 -0700 Subject: [PATCH 30/53] Adding new header comments to all the source files. --- CMakeLists.txt | 10 +- experimental/CMakeLists.txt | 10 +- experimental/algorithm/LAGraph_AllKCore.c | 42 ++++---- experimental/algorithm/LAGraph_AllKTruss.c | 11 +- experimental/algorithm/LAGraph_BF_basic.c | 10 +- experimental/algorithm/LAGraph_BF_basic_mxv.c | 10 +- .../algorithm/LAGraph_BF_basic_pushpull.c | 10 +- experimental/algorithm/LAGraph_BF_full.c | 10 +- experimental/algorithm/LAGraph_BF_full1.c | 10 +- experimental/algorithm/LAGraph_BF_full1a.c | 10 +- experimental/algorithm/LAGraph_BF_full2.c | 10 +- experimental/algorithm/LAGraph_BF_full_mxv.c | 10 +- experimental/algorithm/LAGraph_BF_pure_c.c | 10 +- .../algorithm/LAGraph_BF_pure_c_double.c | 10 +- .../algorithm/LAGraph_FastGraphletTransform.c | 18 ++-- experimental/algorithm/LAGraph_HelloWorld.c | 11 +- experimental/algorithm/LAGraph_KCore.c | 32 +++--- .../algorithm/LAGraph_KCoreDecompose.c | 30 +++--- experimental/algorithm/LAGraph_KTruss.c | 11 +- .../algorithm/LAGraph_MaximalIndependentSet.c | 17 +-- .../algorithm/LAGraph_SquareClustering.c | 10 +- .../LAGraph_VertexCentrality_Triangle.c | 11 +- experimental/algorithm/LAGraph_cc_lacc.c | 10 +- experimental/algorithm/LAGraph_cdlp.c | 10 +- experimental/algorithm/LAGraph_dnn.c | 10 +- experimental/algorithm/LAGraph_lcc.c | 10 +- experimental/algorithm/LAGraph_msf.c | 10 +- experimental/algorithm/LAGraph_scc.c | 10 +- experimental/algorithm/LG_CC_FastSV5.c | 10 +- experimental/benchmark/AllKCore_demo.c | 9 +- experimental/benchmark/CMakeLists.txt | 10 +- experimental/benchmark/KCore_demo.c | 15 ++- experimental/benchmark/dnn_demo.c | 12 ++- experimental/benchmark/fglt_demo.c | 12 ++- experimental/benchmark/helloworld2_demo.c | 11 +- experimental/benchmark/helloworld_demo.c | 11 +- experimental/benchmark/mis_demo.c | 11 +- experimental/benchmark/tcc_demo.c | 13 ++- experimental/test/CMakeLists.txt | 10 +- experimental/test/LG_check_kcore.c | 26 ++--- experimental/test/LG_check_kcoredecompose.c | 36 ++++--- experimental/test/LG_check_ktruss.c | 17 +-- experimental/test/LG_check_mis.c | 13 ++- experimental/test/test_AllKCore.c | 13 ++- experimental/test/test_AllKtruss.c | 10 +- experimental/test/test_BF.c | 11 +- .../test/test_FastGraphletTransform.c | 11 +- experimental/test/test_HelloWorld.c | 10 +- experimental/test/test_KCore.c | 15 +-- experimental/test/test_KCoreDecompose.c | 14 ++- experimental/test/test_KTruss.c | 10 +- .../test/test_MaximalIndependentSet.c | 17 +-- experimental/test/test_Random.c | 11 +- experimental/test/test_Random_Matrix.c | 11 +- experimental/test/test_SSaveSet.c | 12 ++- experimental/test/test_SWrite.c | 10 +- experimental/test/test_SquareClustering.c | 8 +- experimental/test/test_TriangleCentrality.c | 10 +- experimental/test/test_cdlp.c | 10 +- experimental/test/test_dnn.c | 11 +- experimental/test/test_lcc.c | 10 +- experimental/test/test_msf.c | 10 +- experimental/test/test_scc.c | 11 +- experimental/utility/LAGraph_Random.c | 17 +-- experimental/utility/LAGraph_Random_Matrix.c | 13 ++- experimental/utility/LAGraph_SFreeContents.c | 13 ++- experimental/utility/LAGraph_SFreeSet.c | 13 ++- experimental/utility/LAGraph_SLoadSet.c | 13 ++- experimental/utility/LAGraph_SRead.c | 17 +-- experimental/utility/LAGraph_SSaveSet.c | 13 ++- experimental/utility/LAGraph_SWrite.c | 13 ++- rtdocs/CMakeLists.txt | 16 ++- src/CMakeLists.txt | 10 +- src/algorithm/LAGr_Betweenness.c | 10 +- src/algorithm/LAGr_BreadthFirstSearch.c | 11 +- src/algorithm/LAGr_ConnectedComponents.c | 11 +- src/algorithm/LAGr_PageRank.c | 11 +- src/algorithm/LAGr_PageRankGAP.c | 11 +- src/algorithm/LAGr_SingleSourceShortestPath.c | 11 +- src/algorithm/LAGr_TriangleCount.c | 12 ++- src/algorithm/LAGraph_TriangleCount.c | 11 +- src/algorithm/LG_BreadthFirstSearch_SSGrB.c | 12 ++- src/algorithm/LG_BreadthFirstSearch_vanilla.c | 10 +- src/algorithm/LG_CC_Boruvka.c | 10 +- src/algorithm/LG_CC_FastSV6.c | 14 ++- src/algorithm/LG_alg_internal.h | 10 +- src/benchmark/CMakeLists.txt | 12 ++- src/benchmark/LAGraph_demo.h | 13 ++- src/benchmark/bc_demo.c | 10 +- src/benchmark/bfs_demo.c | 10 +- src/benchmark/cc_demo.c | 10 +- src/benchmark/gappagerank_demo.c | 10 +- src/benchmark/mtx2bin_demo.c | 11 +- src/benchmark/ss2_demo.c | 10 +- src/benchmark/sssp_demo.c | 10 +- src/benchmark/tc_demo.c | 13 ++- src/test/CMakeLists.txt | 10 +- src/test/LG_brutal_malloc.c | 11 +- src/test/LG_brutal_setup.c | 11 +- src/test/LG_brutal_teardown.c | 11 +- src/test/LG_check_bfs.c | 13 ++- src/test/LG_check_cc.c | 15 +-- src/test/LG_check_export.c | 14 ++- src/test/LG_check_sssp.c | 11 +- src/test/LG_check_tri.c | 17 +-- src/test/LG_check_vector.c | 11 +- src/test/LG_heap.h | 29 ++--- src/test/test_Betweenness.c | 11 +- src/test/test_BreadthFirstSearch.c | 11 +- src/test/test_Cached_AT.c | 11 +- src/test/test_Cached_Degree.c | 101 +++++++++--------- src/test/test_Cached_NDiag.c | 13 ++- src/test/test_Cached_SymmetricStructure.c | 15 +-- src/test/test_CheckGraph.c | 11 +- src/test/test_ConnectedComponents.c | 10 +- src/test/test_DeleteCached.c | 13 ++- src/test/test_DisplayGraph.c | 11 +- src/test/test_Init.c | 11 +- src/test/test_Init_errors.c | 11 +- src/test/test_IsEqual.c | 13 ++- src/test/test_KindName.c | 11 +- src/test/test_MMRead.c | 13 ++- src/test/test_Malloc.c | 12 ++- src/test/test_Matrix_Structure.c | 11 +- src/test/test_Multiply_size_t.c | 10 +- src/test/test_New.c | 11 +- src/test/test_NumThreads.c | 11 +- src/test/test_PageRank.c | 11 +- src/test/test_SampleDegree.c | 11 +- src/test/test_SingleSourceShortestPath.c | 11 +- src/test/test_Sort.c | 10 +- src/test/test_SortByDegree.c | 61 ++++++----- src/test/test_TriangleCount.c | 13 ++- src/test/test_Type.c | 11 +- src/test/test_Vector_Print.c | 11 +- src/test/test_Vector_Structure.c | 11 +- src/test/test_WallClockTime.c | 11 +- src/test/test_Xinit.c | 11 +- src/test/test_acutest.c | 10 +- src/test/test_export.c | 11 +- src/test/test_fopen.c | 10 +- src/test/test_minmax.c | 17 +-- src/test/test_vector.c | 11 +- src/utility/LAGr_Init.c | 13 ++- src/utility/LAGr_SampleDegree.c | 10 +- src/utility/LAGr_SortByDegree.c | 10 +- src/utility/LAGraph_Cached_AT.c | 10 +- src/utility/LAGraph_Cached_EMax.c | 11 +- src/utility/LAGraph_Cached_EMin.c | 11 +- src/utility/LAGraph_Cached_InDegree.c | 12 ++- .../LAGraph_Cached_IsSymmetricStructure.c | 10 +- src/utility/LAGraph_Cached_NSelfEdges.c | 11 +- src/utility/LAGraph_Cached_OutDegree.c | 10 +- src/utility/LAGraph_Calloc.c | 10 +- src/utility/LAGraph_CheckGraph.c | 10 +- src/utility/LAGraph_Delete.c | 10 +- src/utility/LAGraph_DeleteCached.c | 10 +- src/utility/LAGraph_DeleteSelfEdges.c | 11 +- src/utility/LAGraph_Finalize.c | 11 +- src/utility/LAGraph_Free.c | 10 +- src/utility/LAGraph_GetNumThreads.c | 11 +- src/utility/LAGraph_Global.c | 11 +- src/utility/LAGraph_Graph_Print.c | 10 +- src/utility/LAGraph_Init.c | 10 +- src/utility/LAGraph_MMRead.c | 11 +- src/utility/LAGraph_MMWrite.c | 11 +- src/utility/LAGraph_Malloc.c | 10 +- src/utility/LAGraph_Matrix_IsEqual.c | 11 +- src/utility/LAGraph_Matrix_IsEqualOp.c | 11 +- src/utility/LAGraph_Matrix_Print.c | 31 +++--- src/utility/LAGraph_Matrix_Structure.c | 11 +- src/utility/LAGraph_NameOfType.c | 11 +- src/utility/LAGraph_New.c | 10 +- src/utility/LAGraph_Realloc.c | 10 +- src/utility/LAGraph_SetNumThreads.c | 11 +- src/utility/LAGraph_SizeOfType.c | 11 +- src/utility/LAGraph_TypeFromName.c | 13 ++- src/utility/LAGraph_TypeName.c | 11 +- src/utility/LAGraph_Vector_IsEqual.c | 11 +- src/utility/LAGraph_Vector_IsEqualOp.c | 11 +- src/utility/LAGraph_Vector_Print.c | 31 +++--- src/utility/LAGraph_Vector_Structure.c | 11 +- src/utility/LAGraph_Version.c | 10 +- src/utility/LAGraph_WallClockTime.c | 11 +- src/utility/LG_KindName.c | 11 +- src/utility/LG_Random.c | 11 +- src/utility/LG_internal.h | 10 +- src/utility/LG_msort1.c | 10 +- src/utility/LG_msort2.c | 10 +- src/utility/LG_msort3.c | 10 +- src/utility/LG_nself_edges.c | 13 ++- src/utility/LG_qsort_1a.c | 10 +- src/utility/LG_qsort_2.c | 10 +- src/utility/LG_qsort_3.c | 10 +- src/utility/LG_qsort_template.h | 17 +-- 195 files changed, 1603 insertions(+), 909 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e41060f52..944f8fe687 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,10 +2,14 @@ # LAGraph/CMakeLists.txt: cmake script for LAGraph #------------------------------------------------------------------------------- -# LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +# LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. # SPDX-License-Identifier: BSD-2-Clause -# See additional acknowledgments in the LICENSE file, -# or contact permission@sei.cmu.edu for the full terms. +# +# 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 #------------------------------------------------------------------------------- diff --git a/experimental/CMakeLists.txt b/experimental/CMakeLists.txt index 3f8ba893c8..404ca50bc8 100644 --- a/experimental/CMakeLists.txt +++ b/experimental/CMakeLists.txt @@ -2,10 +2,14 @@ # LAGraph/experimental/CMakeLists.txt: cmake script for LAGraph/experimental #------------------------------------------------------------------------------- -# LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +# LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. # SPDX-License-Identifier: BSD-2-Clause -# See additional acknowledgments in the LICENSE file, -# or contact permission@sei.cmu.edu for the full terms. +# +# 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 #------------------------------------------------------------------------------- diff --git a/experimental/algorithm/LAGraph_AllKCore.c b/experimental/algorithm/LAGraph_AllKCore.c index 9dde753e45..b1bad837d2 100644 --- a/experimental/algorithm/LAGraph_AllKCore.c +++ b/experimental/algorithm/LAGraph_AllKCore.c @@ -1,8 +1,15 @@ //------------------------------------------------------------------------------ // LAGraph_AllKCore: Full K-core Decomposition Using the GraphBLAS API //------------------------------------------------------------------------------ -// LAGraph, (c) 2022 by The LAGraph Contributors, All Rights Reserved. + +// 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 Pranav Konduri, Texas A&M University @@ -20,12 +27,12 @@ { \ LG_FREE_WORK \ GrB_free (decomp) ; \ -} +} #include "LG_internal.h" -int LAGraph_KCore_All +int LAGraph_KCore_All ( // outputs: GrB_Vector *decomp, // kcore decomposition @@ -43,7 +50,7 @@ int LAGraph_KCore_All LG_ASSERT (decomp != NULL, GrB_NULL_POINTER) ; (*decomp) = NULL ; - + LG_TRY (LAGraph_CheckGraph (G, msg)) ; if (G->kind == LAGraph_ADJACENCY_UNDIRECTED || @@ -68,16 +75,16 @@ int LAGraph_KCore_All GRB_TRY (GrB_Matrix_nrows(&n, A)) ; //create deg vector using out_degree property - LG_TRY (LAGraph_Cached_OutDegree(G, msg)) ; + LG_TRY (LAGraph_Cached_OutDegree(G, msg)) ; GRB_TRY (GrB_Vector_dup(°, G->out_degree)) ; //original deg vector is technically 1-core since 0 is omitted GRB_TRY (GrB_Vector_nvals(&todo, deg)) ; //use todo instead of n since some values are omitted (1-core) - + //retrieve the max degree level of the graph GRB_TRY (GrB_reduce(&maxDeg, GrB_NULL, GrB_MAX_MONOID_INT64, G->out_degree, GrB_NULL)) ; //select int type for work vectors and semirings - GrB_Type int_type = (maxDeg > INT32_MAX) ? GrB_INT64 : GrB_INT32 ; + GrB_Type int_type = (maxDeg > INT32_MAX) ? GrB_INT64 : GrB_INT32 ; GRB_TRY (GrB_Vector_new(&q, int_type, n)); GRB_TRY (GrB_Vector_new(&done, GrB_BOOL, n)) ; @@ -90,28 +97,28 @@ int LAGraph_KCore_All GRB_TRY (GrB_Vector_new(°, int_type, n)) ; GRB_TRY (GrB_assign (deg, G->out_degree, NULL, G->out_degree, GrB_ALL, n, NULL)) ; } - + // determine semiring types GrB_IndexUnaryOp valueEQ = (maxDeg > INT32_MAX) ? GrB_VALUEEQ_INT64 : GrB_VALUEEQ_INT32 ; - GrB_IndexUnaryOp valueLE = (maxDeg > INT32_MAX) ? GrB_VALUELE_INT64 : GrB_VALUELE_INT32 ; - GrB_BinaryOp minus_op = (maxDeg > INT32_MAX) ? GrB_MINUS_INT64 : GrB_MINUS_INT32 ; - GrB_Semiring semiring = (maxDeg > INT32_MAX) ? LAGraph_plus_one_int64 : LAGraph_plus_one_int32 ; - + GrB_IndexUnaryOp valueLE = (maxDeg > INT32_MAX) ? GrB_VALUELE_INT64 : GrB_VALUELE_INT32 ; + GrB_BinaryOp minus_op = (maxDeg > INT32_MAX) ? GrB_MINUS_INT64 : GrB_MINUS_INT32 ; + GrB_Semiring semiring = (maxDeg > INT32_MAX) ? LAGraph_plus_one_int64 : LAGraph_plus_one_int32 ; + #if LG_SUITESPARSE GRB_TRY (GxB_set (done, GxB_SPARSITY_CONTROL, GxB_BITMAP + GxB_FULL)) ; // try this //GRB_TRY (GxB_set (*decomp, GxB_SPARSITY_CONTROL, GxB_BITMAP + GxB_FULL)) ; // try this ... likely not needed... #endif //printf ("\n================================== COMPUTING GrB_KCORE: ==================================\n") ; - while(todo > 0){ + while(todo > 0){ //printf("Level: %ld, todo: %ld\n", level, todo) ; - level++; - // Creating q + level++; + // Creating q GRB_TRY (GrB_select (q, GrB_NULL, GrB_NULL, valueEQ, deg, level, GrB_NULL)) ; // get all nodes with degree = level GRB_TRY (GrB_Vector_nvals(&nvals, q)); //Assign values of deg into decomp (output) - GRB_TRY (GrB_assign (*decomp, deg, NULL, level, GrB_ALL, n, GrB_NULL)) ; + GRB_TRY (GrB_assign (*decomp, deg, NULL, level, GrB_ALL, n, GrB_NULL)) ; int round = 0; // while q not empty @@ -127,7 +134,7 @@ int LAGraph_KCore_All // Create new deg vector (keep anything not in done vector w/ replace command) GRB_TRY (GrB_eWiseAdd(deg, done, GrB_NULL, minus_op, deg, delta, GrB_DESC_RSC /* try GrB_DESC_RSC */)) ; - // Update q, set new nvals + // Update q, set new nvals GRB_TRY (GrB_select (q, GrB_NULL, GrB_NULL, valueLE, deg, level, GrB_NULL)) ; GRB_TRY (GrB_Vector_nvals(&nvals, q)) ; @@ -140,4 +147,3 @@ int LAGraph_KCore_All LG_FREE_WORK ; return (GrB_SUCCESS) ; } - diff --git a/experimental/algorithm/LAGraph_AllKTruss.c b/experimental/algorithm/LAGraph_AllKTruss.c index df9015f03e..514ee54c12 100644 --- a/experimental/algorithm/LAGraph_AllKTruss.c +++ b/experimental/algorithm/LAGraph_AllKTruss.c @@ -2,10 +2,14 @@ // LAGraph_AllKTruss.c: find all k-trusses of a graph //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -174,4 +178,3 @@ int LAGraph_AllKTruss // compute all k-trusses of a graph } } } - diff --git a/experimental/algorithm/LAGraph_BF_basic.c b/experimental/algorithm/LAGraph_BF_basic.c index b127d48c44..fabda49a21 100644 --- a/experimental/algorithm/LAGraph_BF_basic.c +++ b/experimental/algorithm/LAGraph_BF_basic.c @@ -2,10 +2,14 @@ // LAGraph_BF_basic: Bellman-Ford method for single source shortest paths //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/experimental/algorithm/LAGraph_BF_basic_mxv.c b/experimental/algorithm/LAGraph_BF_basic_mxv.c index 35a45c011a..0dacbbc402 100644 --- a/experimental/algorithm/LAGraph_BF_basic_mxv.c +++ b/experimental/algorithm/LAGraph_BF_basic_mxv.c @@ -2,10 +2,14 @@ // LAGraph_BF_basic: Bellman-Ford method for single source shortest paths //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/experimental/algorithm/LAGraph_BF_basic_pushpull.c b/experimental/algorithm/LAGraph_BF_basic_pushpull.c index 3216eb6325..966d5fc3e8 100644 --- a/experimental/algorithm/LAGraph_BF_basic_pushpull.c +++ b/experimental/algorithm/LAGraph_BF_basic_pushpull.c @@ -3,10 +3,14 @@ // paths //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/experimental/algorithm/LAGraph_BF_full.c b/experimental/algorithm/LAGraph_BF_full.c index 43ee3c57b8..3be0e48290 100644 --- a/experimental/algorithm/LAGraph_BF_full.c +++ b/experimental/algorithm/LAGraph_BF_full.c @@ -2,10 +2,14 @@ // LAGraph_BF_full.c: Bellman-Ford single-source shortest paths, returns tree //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/experimental/algorithm/LAGraph_BF_full1.c b/experimental/algorithm/LAGraph_BF_full1.c index 54269b9560..f49b549ef7 100644 --- a/experimental/algorithm/LAGraph_BF_full1.c +++ b/experimental/algorithm/LAGraph_BF_full1.c @@ -3,10 +3,14 @@ // while diagonal of input matrix A needs not to be explicit 0 //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/experimental/algorithm/LAGraph_BF_full1a.c b/experimental/algorithm/LAGraph_BF_full1a.c index 1ae31ff2ed..e07c1ec0ce 100644 --- a/experimental/algorithm/LAGraph_BF_full1a.c +++ b/experimental/algorithm/LAGraph_BF_full1a.c @@ -3,10 +3,14 @@ // while diagonal of input matrix A needs not to be explicit 0 //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/experimental/algorithm/LAGraph_BF_full2.c b/experimental/algorithm/LAGraph_BF_full2.c index 249bd59204..9ae239d707 100644 --- a/experimental/algorithm/LAGraph_BF_full2.c +++ b/experimental/algorithm/LAGraph_BF_full2.c @@ -4,10 +4,14 @@ // frontier idea from Roi Lipman //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/experimental/algorithm/LAGraph_BF_full_mxv.c b/experimental/algorithm/LAGraph_BF_full_mxv.c index 20df3ed1df..52bd14c59b 100644 --- a/experimental/algorithm/LAGraph_BF_full_mxv.c +++ b/experimental/algorithm/LAGraph_BF_full_mxv.c @@ -2,10 +2,14 @@ // LAGraph_BF_full.c: Bellman-Ford single-source shortest paths, returns tree //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/experimental/algorithm/LAGraph_BF_pure_c.c b/experimental/algorithm/LAGraph_BF_pure_c.c index 5d0af4776b..cbb1ab935f 100644 --- a/experimental/algorithm/LAGraph_BF_pure_c.c +++ b/experimental/algorithm/LAGraph_BF_pure_c.c @@ -2,10 +2,14 @@ // BF_pure_c.c: Bellman-Ford method, not using GraphBLAS //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/experimental/algorithm/LAGraph_BF_pure_c_double.c b/experimental/algorithm/LAGraph_BF_pure_c_double.c index 61b1565108..1c99b5da06 100644 --- a/experimental/algorithm/LAGraph_BF_pure_c_double.c +++ b/experimental/algorithm/LAGraph_BF_pure_c_double.c @@ -2,10 +2,14 @@ // BF_pure_c_double.c: Bellman-Ford method, not using GraphBLAS //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/experimental/algorithm/LAGraph_FastGraphletTransform.c b/experimental/algorithm/LAGraph_FastGraphletTransform.c index 17eaa2ba2a..c9373d985b 100644 --- a/experimental/algorithm/LAGraph_FastGraphletTransform.c +++ b/experimental/algorithm/LAGraph_FastGraphletTransform.c @@ -2,8 +2,15 @@ // LAGraph_FastGraphletTransform: fast graphlet transform //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// 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 Tanner Hoke, Texas A&M University, ... //------------------------------------------------------------------------------ @@ -212,7 +219,7 @@ int LAGraph_FastGraphletTransform // p_1_minus_one = p_1 - 1 GRB_TRY (GrB_apply (p_1_minus_one, NULL, NULL, GrB_MINUS_INT64, d_1, (int64_t) 1, NULL)) ; - // d_6 = hadamard(d_2, p_1-1) + // d_6 = hadamard(d_2, p_1-1) GRB_TRY (GrB_eWiseMult (d_6, NULL, NULL, GrB_TIMES_INT64, d_2, p_1_minus_one, NULL)) ; // d_6 -= 2c_3 @@ -277,8 +284,8 @@ int LAGraph_FastGraphletTransform // D_1 = diag(d_1) GRB_TRY (GxB_Matrix_diag (D_1, d_1, (int64_t) 0, NULL)) ; - - GRB_TRY (GrB_Matrix_nvals (&nvals, A)); + + GRB_TRY (GrB_Matrix_nvals (&nvals, A)); const GrB_Index entries_per_tile = 1000; GrB_Index ntiles = (nvals + entries_per_tile - 1) / entries_per_tile ; @@ -292,7 +299,7 @@ int LAGraph_FastGraphletTransform for (GrB_Index i = 0; i < n; ++i) { int64_t deg ; GRB_TRY (GrB_Vector_extractElement (°, d_1, i)) ; - + if (i == n - 1 || (tot_deg / entries_per_tile != (tot_deg + deg) / entries_per_tile)) { Tile_nrows [tile_cnt++] = i - last_row ; last_row = i ; @@ -551,4 +558,3 @@ int LAGraph_FastGraphletTransform return (0) ; } - diff --git a/experimental/algorithm/LAGraph_HelloWorld.c b/experimental/algorithm/LAGraph_HelloWorld.c index 6edbacbfdd..e72f3470c6 100644 --- a/experimental/algorithm/LAGraph_HelloWorld.c +++ b/experimental/algorithm/LAGraph_HelloWorld.c @@ -2,10 +2,14 @@ // LAGraph_HelloWorld: a nearly empty algorithm //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -93,4 +97,3 @@ int LAGraph_HelloWorld // a simple algorithm, just for illustration (*Yhandle) = Y ; return (GrB_SUCCESS) ; } - diff --git a/experimental/algorithm/LAGraph_KCore.c b/experimental/algorithm/LAGraph_KCore.c index 9091389301..b2bfc9ad15 100644 --- a/experimental/algorithm/LAGraph_KCore.c +++ b/experimental/algorithm/LAGraph_KCore.c @@ -1,8 +1,15 @@ //------------------------------------------------------------------------------ // LAGraph_KCore: Single K-core Decomposition Using the GraphBLAS API //------------------------------------------------------------------------------ -// LAGraph, (c) 2022 by The LAGraph Contributors, All Rights Reserved. + +// 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 Pranav Konduri, Texas A&M University @@ -20,12 +27,12 @@ { \ LG_FREE_WORK \ GrB_free (decomp) ; \ -} +} #include "LG_internal.h" -int LAGraph_KCore +int LAGraph_KCore ( // outputs: GrB_Vector *decomp, // kcore decomposition @@ -43,7 +50,7 @@ int LAGraph_KCore LG_ASSERT (decomp != NULL, GrB_NULL_POINTER) ; (*decomp) = NULL ; - + LG_TRY (LAGraph_CheckGraph (G, msg)) ; if (G->kind == LAGraph_ADJACENCY_UNDIRECTED || @@ -91,16 +98,16 @@ int LAGraph_KCore // determine semiring types GrB_IndexUnaryOp valueLT = (maxDeg > INT32_MAX) ? GrB_VALUELT_INT64 : GrB_VALUELT_INT32 ; - GrB_BinaryOp minus_op = (maxDeg > INT32_MAX) ? GrB_MINUS_INT64 : GrB_MINUS_INT32 ; - GrB_Semiring semiring = (maxDeg > INT32_MAX) ? LAGraph_plus_one_int64 : LAGraph_plus_one_int32 ; - + GrB_BinaryOp minus_op = (maxDeg > INT32_MAX) ? GrB_MINUS_INT64 : GrB_MINUS_INT32 ; + GrB_Semiring semiring = (maxDeg > INT32_MAX) ? LAGraph_plus_one_int64 : LAGraph_plus_one_int32 ; + #if LG_SUITESPARSE GRB_TRY (GxB_set (done, GxB_SPARSITY_CONTROL, GxB_BITMAP + GxB_FULL)) ; // try this //GRB_TRY (GxB_set (*decomp, GxB_SPARSITY_CONTROL, GxB_BITMAP + GxB_FULL)) ; // try this ... likely not needed #endif - // Creating q + // Creating q GRB_TRY (GrB_select (q, GrB_NULL, GrB_NULL, valueLT, deg, k, GrB_NULL)) ; // get all nodes with degree = level GRB_TRY (GrB_Vector_nvals(&qnvals, q)); @@ -113,19 +120,18 @@ int LAGraph_KCore // Create delta (the nodes who lost friends, and how many they lost) (push version) GRB_TRY (GrB_vxm (delta, GrB_NULL, GrB_NULL, semiring, q, A, GrB_NULL)); - + // Create new deg vector (keep anything not in done vector) GRB_TRY (GrB_eWiseAdd(deg, done, GrB_NULL, minus_op, deg, delta, GrB_DESC_RSC)) ; - - // Update q, set new nvals + + // Update q, set new nvals GRB_TRY (GrB_select (q, GrB_NULL, GrB_NULL, valueLT, deg, k, GrB_NULL)) ; GRB_TRY (GrB_Vector_nvals(&qnvals, q)) ; GRB_TRY (GrB_Vector_nvals(°nvals, deg)) ; } //Assign values of deg to decomp - GRB_TRY (GrB_assign (*decomp, deg, NULL, k, GrB_ALL, n, GrB_NULL)) ; + GRB_TRY (GrB_assign (*decomp, deg, NULL, k, GrB_ALL, n, GrB_NULL)) ; GRB_TRY(GrB_Vector_wait(*decomp, GrB_MATERIALIZE)); LG_FREE_WORK ; return (GrB_SUCCESS) ; } - diff --git a/experimental/algorithm/LAGraph_KCoreDecompose.c b/experimental/algorithm/LAGraph_KCoreDecompose.c index 2cf4b9fb63..3fb6d4618d 100644 --- a/experimental/algorithm/LAGraph_KCoreDecompose.c +++ b/experimental/algorithm/LAGraph_KCoreDecompose.c @@ -2,8 +2,15 @@ // LAGraph_KCoreDecompose: Helper method to LAGraph_KCore and LAGraph_AllKCore // that performs graph decomposition given a specified value k. //------------------------------------------------------------------------------ -// LAGraph, (c) 2022 by The LAGraph Contributors, All Rights Reserved. + +// 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 Pranav Konduri, Texas A&M University @@ -19,12 +26,12 @@ { \ LG_FREE_WORK \ GrB_free (D) ; \ -} +} #include "LG_internal.h" -int LAGraph_KCore_Decompose +int LAGraph_KCore_Decompose ( // outputs: GrB_Matrix *D, // kcore decomposition @@ -36,15 +43,15 @@ int LAGraph_KCore_Decompose ) { LG_CLEAR_MSG ; - + // declare items GrB_Matrix A = NULL, C = NULL; GrB_Vector deg = NULL; - + LG_ASSERT (D != NULL, GrB_NULL_POINTER) ; (*D) = NULL ; - + LG_TRY (LAGraph_CheckGraph (G, msg)) ; if (G->kind == LAGraph_ADJACENCY_UNDIRECTED || @@ -69,12 +76,12 @@ int LAGraph_KCore_Decompose GRB_TRY (GrB_Matrix_nrows(&nrows, A)) ; GRB_TRY (GrB_Vector_size(&n, decomp)) ; LG_ASSERT_MSG (nrows == n, -1003, "Size of vector and rows of matrix must be same") ; - + //Create Vectors and Matrices GRB_TRY (GrB_Vector_new(°, GrB_INT64, n)) ; GRB_TRY (GrB_Matrix_new(D, GrB_INT64, n, n)) ; - //create deg vector using select + //create deg vector using select GRB_TRY (GrB_select (deg, GrB_NULL, GrB_NULL, GrB_VALUEGE_INT64, decomp, k, GrB_NULL)) ; //create decomposition matrix (C * A * C) @@ -94,12 +101,11 @@ int LAGraph_KCore_Decompose #endif GRB_TRY (GrB_mxm (*D, NULL, NULL, GxB_ANY_SECONDI_INT64, C, A, GrB_NULL)) ; - GRB_TRY (GrB_mxm (*D, NULL, NULL, GxB_MIN_SECONDI_INT64, *D, C, GrB_NULL)) ; - + GRB_TRY (GrB_mxm (*D, NULL, NULL, GxB_MIN_SECONDI_INT64, *D, C, GrB_NULL)) ; + //Assigns all values as 1 (todo: change to something cleaner) - GRB_TRY (GrB_assign (*D, *D, NULL, (int64_t) 1, GrB_ALL, n, GrB_ALL, n, GrB_DESC_S)) ; + GRB_TRY (GrB_assign (*D, *D, NULL, (int64_t) 1, GrB_ALL, n, GrB_ALL, n, GrB_DESC_S)) ; LG_FREE_WORK ; return (GrB_SUCCESS) ; } - diff --git a/experimental/algorithm/LAGraph_KTruss.c b/experimental/algorithm/LAGraph_KTruss.c index b4294bed6d..dc1d5d6f5f 100644 --- a/experimental/algorithm/LAGraph_KTruss.c +++ b/experimental/algorithm/LAGraph_KTruss.c @@ -2,10 +2,14 @@ // LAGraph_KTruss: k-truss subgraph //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -108,4 +112,3 @@ int LAGraph_KTruss // compute the k-truss of a graph S = C ; } } - diff --git a/experimental/algorithm/LAGraph_MaximalIndependentSet.c b/experimental/algorithm/LAGraph_MaximalIndependentSet.c index b485d1486f..8e30a6abd7 100644 --- a/experimental/algorithm/LAGraph_MaximalIndependentSet.c +++ b/experimental/algorithm/LAGraph_MaximalIndependentSet.c @@ -2,10 +2,14 @@ // LAGraph_MaximalIndependentSet: maximal independent set, with constraints //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 // Modified from the GraphBLAS C API Specification, by Aydin Buluc, Timothy // Mattson, Scott McMillan, Jose' Moreira, Carl Yang. Based on "GraphBLAS @@ -34,7 +38,7 @@ #include "LG_internal.h" #include "LAGraphX.h" -// A variant of Luby's randomized algorithm [Luby 1985]. +// A variant of Luby's randomized algorithm [Luby 1985]. // Given a numeric n x n adjacency matrix A of an unweighted and undirected // graph (where the value true represents an edge), compute a maximal set of @@ -128,7 +132,7 @@ int LAGraph_MaximalIndependentSet // maximal independent set GrB_Index nonsingletons = 0 ; GRB_TRY (GrB_Vector_nvals (&nonsingletons, degree)) ; if (nonsingletons == n) - { + { if (ignore_node == NULL) { // all nodes have degree 1 or more; all nodes are candidates @@ -274,7 +278,7 @@ int LAGraph_MaximalIndependentSet // maximal independent set GRB_TRY (GrB_assign (candidates, new_neighbors, NULL, empty, GrB_ALL, n, GrB_DESC_S)) ; - // sparsify the random number seeds (just keep it for each candidate) + // sparsify the random number seeds (just keep it for each candidate) // Seed{candidates,replace} = Seed GRB_TRY (GrB_assign (Seed, candidates, NULL, Seed, GrB_ALL, n, GrB_DESC_RS)) ; @@ -308,4 +312,3 @@ int LAGraph_MaximalIndependentSet // maximal independent set LG_FREE_WORK ; return (GrB_SUCCESS) ; } - diff --git a/experimental/algorithm/LAGraph_SquareClustering.c b/experimental/algorithm/LAGraph_SquareClustering.c index 62da0d8d36..0e11b46625 100644 --- a/experimental/algorithm/LAGraph_SquareClustering.c +++ b/experimental/algorithm/LAGraph_SquareClustering.c @@ -2,10 +2,14 @@ // LAGraph_SquareClustering: vertex square-clustering //------------------------------------------------------------------------------ -// LAGraph, (c) 2022 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Erik Welch, NVIDIA. diff --git a/experimental/algorithm/LAGraph_VertexCentrality_Triangle.c b/experimental/algorithm/LAGraph_VertexCentrality_Triangle.c index b0ff6de416..e38744fdb4 100644 --- a/experimental/algorithm/LAGraph_VertexCentrality_Triangle.c +++ b/experimental/algorithm/LAGraph_VertexCentrality_Triangle.c @@ -2,10 +2,14 @@ // LAGraph_VertexCentrality_triangle: vertex triangle-centrality //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Tim Davis, Texas A&M University. @@ -312,4 +316,3 @@ int LAGraph_VertexCentrality_Triangle // vertex triangle-centrality LG_FREE_WORK ; return (GrB_SUCCESS) ; } - diff --git a/experimental/algorithm/LAGraph_cc_lacc.c b/experimental/algorithm/LAGraph_cc_lacc.c index 006e4229ec..7cc590c386 100644 --- a/experimental/algorithm/LAGraph_cc_lacc.c +++ b/experimental/algorithm/LAGraph_cc_lacc.c @@ -2,10 +2,14 @@ // LAGraph_cc_lacc.c //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Scott McMillan, SEI, Carnegie Mellon University diff --git a/experimental/algorithm/LAGraph_cdlp.c b/experimental/algorithm/LAGraph_cdlp.c index 09feb5f214..c800119020 100644 --- a/experimental/algorithm/LAGraph_cdlp.c +++ b/experimental/algorithm/LAGraph_cdlp.c @@ -2,10 +2,14 @@ // LAGraph_cdlp: community detection using label propagation //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Gabor Szarnyas and Balint Hegyi, Budapest University of // Technology and Economics (with accented characters: G\'{a}bor Sz\'{a}rnyas diff --git a/experimental/algorithm/LAGraph_dnn.c b/experimental/algorithm/LAGraph_dnn.c index d1549e19b4..dcedba80dd 100644 --- a/experimental/algorithm/LAGraph_dnn.c +++ b/experimental/algorithm/LAGraph_dnn.c @@ -2,10 +2,14 @@ // LAGraph_dnn: sparse deep neural network //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/experimental/algorithm/LAGraph_lcc.c b/experimental/algorithm/LAGraph_lcc.c index 1ae3d7bd76..07aa3d5a3d 100644 --- a/experimental/algorithm/LAGraph_lcc.c +++ b/experimental/algorithm/LAGraph_lcc.c @@ -2,10 +2,14 @@ // LAGraph_lcc: local clustering coefficient //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Gabor Szarnyas and Balint Hegyi, Budapest University of // Technology and Economics (with accented characters: G\'{a}bor Sz\'{a}rnyas diff --git a/experimental/algorithm/LAGraph_msf.c b/experimental/algorithm/LAGraph_msf.c index e6e7855ce4..8926a94798 100644 --- a/experimental/algorithm/LAGraph_msf.c +++ b/experimental/algorithm/LAGraph_msf.c @@ -2,10 +2,14 @@ // LAGraph_msf.c //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Yongzhe Zhang (zyz915@gmail.com) diff --git a/experimental/algorithm/LAGraph_scc.c b/experimental/algorithm/LAGraph_scc.c index 0cebd592a2..dad90427ef 100644 --- a/experimental/algorithm/LAGraph_scc.c +++ b/experimental/algorithm/LAGraph_scc.c @@ -2,10 +2,14 @@ // LAGraph_scc.c //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Yongzhe Zhang (zyz915@gmail.com) diff --git a/experimental/algorithm/LG_CC_FastSV5.c b/experimental/algorithm/LG_CC_FastSV5.c index 0b1a773a36..2c56061dcc 100644 --- a/experimental/algorithm/LG_CC_FastSV5.c +++ b/experimental/algorithm/LG_CC_FastSV5.c @@ -2,10 +2,14 @@ // LG_CC_FastSV5: connected components //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Yongzhe Zhang; modified by Tim Davis, Texas A&M University diff --git a/experimental/benchmark/AllKCore_demo.c b/experimental/benchmark/AllKCore_demo.c index 920681abb5..4d877a5d04 100644 --- a/experimental/benchmark/AllKCore_demo.c +++ b/experimental/benchmark/AllKCore_demo.c @@ -2,8 +2,14 @@ // LAGraph/experimental/benchmark/AllKCore_demo.c: benchmark for kcore (single k-core) //------------------------------------------------------------------------------ -// LAGraph, (c) 2022 by The LAGraph Contributors, All Rights Reserved. +// 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 Pranav Konduri, Texas A&M University @@ -139,4 +145,3 @@ int main (int argc, char **argv) LAGRAPH_TRY (LAGraph_Finalize (msg)) ; return (GrB_SUCCESS) ; } - diff --git a/experimental/benchmark/CMakeLists.txt b/experimental/benchmark/CMakeLists.txt index bec3786e84..e26887eeef 100644 --- a/experimental/benchmark/CMakeLists.txt +++ b/experimental/benchmark/CMakeLists.txt @@ -2,10 +2,14 @@ # LAGraph/experimental/benchmark/CMakeLists.txt: cmake script for LAGraph/experiment/benchmark #------------------------------------------------------------------------------- -# LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +# LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. # SPDX-License-Identifier: BSD-2-Clause -# See additional acknowledgments in the LICENSE file, -# or contact permission@sei.cmu.edu for the full terms. +# +# 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 #------------------------------------------------------------------------------- diff --git a/experimental/benchmark/KCore_demo.c b/experimental/benchmark/KCore_demo.c index 60bee50232..66ef050096 100644 --- a/experimental/benchmark/KCore_demo.c +++ b/experimental/benchmark/KCore_demo.c @@ -2,8 +2,14 @@ // LAGraph/experimental/benchmark/KCore_demo.c: benchmark for kcore (single k-core) //------------------------------------------------------------------------------ -// LAGraph, (c) 2022 by The LAGraph Contributors, All Rights Reserved. +// 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 Pranav Konduri, Texas A&M University @@ -44,13 +50,13 @@ int main (int argc, char **argv) GrB_Matrix A = NULL ; GrB_Matrix D = NULL ; LAGraph_Graph G = NULL ; - + // start GraphBLAS and LAGraph bool burble = false ; demo_init (burble) ; - int ntrials = 3 ; + int ntrials = 3 ; printf ("# of trials: %d\n", ntrials) ; int nt = NTHREAD_LIST ; @@ -80,7 +86,7 @@ int main (int argc, char **argv) //-------------------------------------------------------------------------- // read in the graph //-------------------------------------------------------------------------- - + char *matrix_name = (argc > 1) ? argv [1] : "stdin" ; int k = (argc > 2) ? atoi(argv [2]) : 0; LAGRAPH_TRY (readproblem (&G, NULL, @@ -140,4 +146,3 @@ int main (int argc, char **argv) LAGRAPH_TRY (LAGraph_Finalize (msg)) ; return (GrB_SUCCESS) ; } - diff --git a/experimental/benchmark/dnn_demo.c b/experimental/benchmark/dnn_demo.c index 52701385d7..1c6e7a0195 100644 --- a/experimental/benchmark/dnn_demo.c +++ b/experimental/benchmark/dnn_demo.c @@ -2,16 +2,20 @@ // dnn_demo: run all neural networks from http://graphchallenge.org //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Tim Davis, Texas A&M University. //------------------------------------------------------------------------------ -// dnn_demo: test for LAGraph_dnn. +// dnn_demo: test for LAGraph_dnn. // Usage: ./dnn_demo nproblems diff --git a/experimental/benchmark/fglt_demo.c b/experimental/benchmark/fglt_demo.c index 437173d3c2..7125d37afc 100644 --- a/experimental/benchmark/fglt_demo.c +++ b/experimental/benchmark/fglt_demo.c @@ -2,10 +2,14 @@ // LAGraph/experimental/benchmark/fglt_demo.c: benchmark Fast Graphlet Transform //------------------------------------------------------------------------------ -// LAGraph, (c) 2022 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Tanner Hoke @@ -86,7 +90,7 @@ int main (int argc, char **argv) //-------------------------------------------------------------------------- // compute the GAP pagerank //-------------------------------------------------------------------------- - + // warmup for more accurate timing double tt = LAGraph_WallClockTime ( ) ; LAGRAPH_TRY (LAGraph_FastGraphletTransform (&Fnet, G, true, msg)) ; diff --git a/experimental/benchmark/helloworld2_demo.c b/experimental/benchmark/helloworld2_demo.c index 15789b0c9a..900a509e47 100644 --- a/experimental/benchmark/helloworld2_demo.c +++ b/experimental/benchmark/helloworld2_demo.c @@ -2,10 +2,14 @@ // LAGraph/experimental/benchmark/helloworld2_demo.c: a simple demo //------------------------------------------------------------------------------ -// LAGraph, (c) 2022 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -117,4 +121,3 @@ int main (int argc, char **argv) LAGRAPH_TRY (LAGraph_Finalize (msg)) ; return (GrB_SUCCESS) ; } - diff --git a/experimental/benchmark/helloworld_demo.c b/experimental/benchmark/helloworld_demo.c index 112c7850aa..53ee86ce05 100644 --- a/experimental/benchmark/helloworld_demo.c +++ b/experimental/benchmark/helloworld_demo.c @@ -2,10 +2,14 @@ // LAGraph/experimental/benchmark/helloworld_demo.c: a simple demo //------------------------------------------------------------------------------ -// LAGraph, (c) 2022 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -128,4 +132,3 @@ int main (int argc, char **argv) LG_TRY (LAGraph_Finalize (msg)) ; return (GrB_SUCCESS) ; } - diff --git a/experimental/benchmark/mis_demo.c b/experimental/benchmark/mis_demo.c index 8720e490fd..209fe5e3e3 100644 --- a/experimental/benchmark/mis_demo.c +++ b/experimental/benchmark/mis_demo.c @@ -2,10 +2,14 @@ // LAGraph/experimental/benchmark/mis_demo.c: benchmark for triangle centrality //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Tim Davis, Texas A&M @@ -148,4 +152,3 @@ int main (int argc, char **argv) LAGRAPH_TRY (LAGraph_Finalize (msg)) ; return (GrB_SUCCESS) ; } - diff --git a/experimental/benchmark/tcc_demo.c b/experimental/benchmark/tcc_demo.c index b3f2cb562b..a0165d5d62 100644 --- a/experimental/benchmark/tcc_demo.c +++ b/experimental/benchmark/tcc_demo.c @@ -2,10 +2,14 @@ // LAGraph/experimental/benchmark/tcc_demo.c: benchmark for triangle centrality //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Tim Davis, Texas A&M @@ -132,7 +136,7 @@ int main (int argc, char **argv) ttot += ttrial [trial] ; printf ("threads %2d trial %2d: %12.6f sec\n", nthreads, trial, ttrial [trial]) ; - fprintf (stderr, "threads %2d trial %2d: %12.6f sec\n", + fprintf (stderr, "threads %2d trial %2d: %12.6f sec\n", nthreads, trial, ttrial [trial]) ; } ttot = ttot / ntrials ; @@ -151,4 +155,3 @@ int main (int argc, char **argv) LAGRAPH_TRY (LAGraph_Finalize (msg)) ; return (GrB_SUCCESS) ; } - diff --git a/experimental/test/CMakeLists.txt b/experimental/test/CMakeLists.txt index 286d7dce03..796e1de10f 100644 --- a/experimental/test/CMakeLists.txt +++ b/experimental/test/CMakeLists.txt @@ -2,10 +2,14 @@ # LAGraph/experimental/test/CMakeLists.txt #------------------------------------------------------------------------------- -# LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +# LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. # SPDX-License-Identifier: BSD-2-Clause -# See additional acknowledgments in the LICENSE file, -# or contact permission@sei.cmu.edu for the full terms. +# +# 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 #------------------------------------------------------------------------------- diff --git a/experimental/test/LG_check_kcore.c b/experimental/test/LG_check_kcore.c index faf86d7e9a..00e507f41d 100644 --- a/experimental/test/LG_check_kcore.c +++ b/experimental/test/LG_check_kcore.c @@ -2,19 +2,22 @@ // LG_check_kcore: construct the kcore of a graph (simple method) //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause // -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// 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 Pranav Konduri, Texas A&M University //------------------------------------------------------------------------------ -// An implementation of the BZ algorithm (2003) for k-core decomposition. -// This method is for testing only, to check the result of other, faster methods. -// Do not benchmark this method; it is simple by design. +// An implementation of the BZ algorithm (2003) for k-core decomposition. +// This method is for testing only, to check the result of other, faster methods. +// Do not benchmark this method; it is simple by design. #define LG_FREE_ALL \ { \ @@ -69,7 +72,7 @@ int LG_check_kcore &typesize, msg)) ; //-------------------------------------------------------------------------- - // compute the k-core + // compute the k-core //-------------------------------------------------------------------------- //printf ("\n================================== COMPUTING BZ_KCORE: ==================================\n") ; //printf("ap_len = %ld, aj_len = %ld, ax_len = %ld\n", Ap_len, Aj_len, Ax_len) ; @@ -89,7 +92,7 @@ int LG_check_kcore } //setup output vector - GrB_Type int_type = (maxDeg > INT32_MAX) ? GrB_INT64 : GrB_INT32 ; + GrB_Type int_type = (maxDeg > INT32_MAX) ? GrB_INT64 : GrB_INT32 ; GRB_TRY (GrB_Vector_new(decomp, int_type, n)) ; GrB_IndexUnaryOp valueGE = (maxDeg > INT32_MAX) ? GrB_VALUEGE_INT64 : GrB_VALUEGE_INT32 ; @@ -108,7 +111,7 @@ int LG_check_kcore } //Do bin-sort - //vert -- contains the vertices in sorted order of degree + //vert -- contains the vertices in sorted order of degree //pos -- contains the positon of a vertex in vert array for(uint64_t i = 0; i < n; i++){ pos[i] = bin[ deg[i] ]; @@ -170,7 +173,6 @@ int LG_check_kcore LG_FREE_ALL; (*kmax) = level ; - GRB_TRY (GrB_Vector_wait(*decomp, GrB_MATERIALIZE)); - return (GrB_SUCCESS); + GRB_TRY (GrB_Vector_wait(*decomp, GrB_MATERIALIZE)); + return (GrB_SUCCESS); } - diff --git a/experimental/test/LG_check_kcoredecompose.c b/experimental/test/LG_check_kcoredecompose.c index 69d88b383b..b5c8ae6aad 100644 --- a/experimental/test/LG_check_kcoredecompose.c +++ b/experimental/test/LG_check_kcoredecompose.c @@ -3,18 +3,21 @@ // decompostion vector (simple method) //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause // -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// 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 Pranav Konduri, Texas A&M University //------------------------------------------------------------------------------ -// 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. +// 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. #define LG_FREE_WORK \ { \ @@ -26,7 +29,7 @@ { \ LG_FREE_WORK \ GrB_free (D) ; \ -} +} #include "LG_internal.h" @@ -45,14 +48,14 @@ int LG_check_kcore_decompose ) { LG_CLEAR_MSG ; - + // declare items GrB_Matrix A = NULL, C = NULL; GrB_Vector deg = NULL; - + LG_ASSERT (D != NULL, GrB_NULL_POINTER) ; (*D) = NULL ; - + LG_TRY (LAGraph_CheckGraph (G, msg)) ; if (G->kind == LAGraph_ADJACENCY_UNDIRECTED || @@ -70,14 +73,14 @@ int LG_check_kcore_decompose // no self edges can be present LG_ASSERT_MSG (G->nself_edges == 0, -1004, "G->nself_edges must be zero") ; - + //create work scalars GrB_Index size_matrix, nvals_matrix, size_vector, nvals_vector; GRB_TRY (GrB_Matrix_nrows(&size_matrix, A)) ; GRB_TRY (GrB_Vector_size(&size_vector, decomp)) ; LG_ASSERT_MSG (size_matrix == size_vector, -1003, "Size of vector and of matrix must be same") ; - + //create D and nvals scalars GRB_TRY (GrB_Matrix_new(D, GrB_INT64, size_matrix, size_matrix)) ; GRB_TRY (GrB_Matrix_nvals(&nvals_matrix, A)) ; @@ -88,13 +91,13 @@ int LG_check_kcore_decompose LG_TRY (LAGraph_Malloc ((void **) &row, nvals_matrix, sizeof (GrB_Index), msg)); LG_TRY (LAGraph_Malloc ((void **) &col, nvals_matrix, sizeof (GrB_Index), msg)); LG_TRY (LAGraph_Malloc ((void **) &matrix_values, nvals_matrix, sizeof (GrB_Index), msg)); - + LG_TRY (LAGraph_Malloc ((void **) &vector, nvals_vector, sizeof (GrB_Index), msg)); LG_TRY (LAGraph_Malloc ((void **) &vector_values, nvals_vector, sizeof (GrB_Index), msg)); GRB_TRY(GrB_Matrix_extractTuples(row, col, (int64_t *) matrix_values, &nvals_matrix, A)); GRB_TRY(GrB_Vector_extractTuples(vector, (int64_t *) vector_values, &size_vector, decomp)); - //take all values that have row and col indices + //take all values that have row and col indices for(uint64_t i = 0; i < nvals_matrix; i++){ bool ok_row = false, ok_col = false; for(uint64_t j = 0; (j < nvals_vector) && (!ok_row || !ok_col); j++){ @@ -104,11 +107,10 @@ int LG_check_kcore_decompose ok_col = true; } if(ok_row && ok_col){ - GRB_TRY(GrB_Matrix_setElement(*D, matrix_values[i], row[i], col[i])); + GRB_TRY(GrB_Matrix_setElement(*D, matrix_values[i], row[i], col[i])); } } LG_FREE_WORK; - GRB_TRY (GrB_Matrix_wait(*D, GrB_MATERIALIZE)); - return (GrB_SUCCESS); + GRB_TRY (GrB_Matrix_wait(*D, GrB_MATERIALIZE)); + return (GrB_SUCCESS); } - diff --git a/experimental/test/LG_check_ktruss.c b/experimental/test/LG_check_ktruss.c index c4c3fbe8f0..31945c7a1b 100644 --- a/experimental/test/LG_check_ktruss.c +++ b/experimental/test/LG_check_ktruss.c @@ -2,10 +2,14 @@ // LG_check_ktruss: construct the ktruss of a graph (simple method) //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -121,17 +125,17 @@ int LG_check_ktruss 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++ ; @@ -173,4 +177,3 @@ int LG_check_ktruss GRB_TRY (GrB_free (&C)) ; } } - diff --git a/experimental/test/LG_check_mis.c b/experimental/test/LG_check_mis.c index f85e81064a..9519fdd191 100644 --- a/experimental/test/LG_check_mis.c +++ b/experimental/test/LG_check_mis.c @@ -2,10 +2,14 @@ // LG_check_mis: test if iset is a maximal independent set //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -64,7 +68,7 @@ int LG_check_mis // check if iset is a valid MIS of A isize = 0 ; for (int64_t k = 0 ; k < nvals ; k++) { - if (X [k]) + if (X [k]) { I [isize++] = I [k] ; } @@ -121,4 +125,3 @@ int LG_check_mis // check if iset is a valid MIS of A printf ("\n") ; return (GrB_SUCCESS) ; } - diff --git a/experimental/test/test_AllKCore.c b/experimental/test/test_AllKCore.c index b8301a17d8..58f75512a3 100644 --- a/experimental/test/test_AllKCore.c +++ b/experimental/test/test_AllKCore.c @@ -3,11 +3,14 @@ // decomposition // ---------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause // -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// 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 Pranav Konduri, Texas A&M University @@ -72,7 +75,7 @@ void test_AllKCore (void) OK (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; if (G->is_symmetric_structure == LAGraph_FALSE) - { + { printf("This matrix is not symmetric. \n"); // make the adjacency matrix symmetric OK (LAGraph_Cached_AT (G, msg)) ; @@ -108,7 +111,7 @@ void test_AllKCore (void) OK(LG_check_kcore(&c2, &km2, G, check_kmax, msg)) ; // printf ("kmax: %lu km1 %lu\n", kmax, km2) ; - + TEST_CHECK(kmax == km2) ; TEST_CHECK(km1 == km2) ; OK (LAGraph_Vector_IsEqual (&ok, c1, c2, msg)) ; diff --git a/experimental/test/test_AllKtruss.c b/experimental/test/test_AllKtruss.c index 85b1540e68..3f59f77474 100644 --- a/experimental/test/test_AllKtruss.c +++ b/experimental/test/test_AllKtruss.c @@ -2,10 +2,14 @@ // LAGraph/experimental/test/test_AllKtest.c: test cases for all-k-truss // ---------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/experimental/test/test_BF.c b/experimental/test/test_BF.c index e4660da411..3d942d4a72 100644 --- a/experimental/test/test_BF.c +++ b/experimental/test/test_BF.c @@ -2,10 +2,14 @@ // LAGraph/experimental/test/test_BF //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Tim Davis, Texas A&M University @@ -508,4 +512,3 @@ TEST_LIST = { "test_BF", test_BF }, { NULL, NULL } } ; - diff --git a/experimental/test/test_FastGraphletTransform.c b/experimental/test/test_FastGraphletTransform.c index 9150ed5dae..f7422a9361 100644 --- a/experimental/test/test_FastGraphletTransform.c +++ b/experimental/test/test_FastGraphletTransform.c @@ -1,11 +1,14 @@ //---------------------------------------------------------------------------- // LAGraph/src/test/test_TriangleCount.cpp: test cases for triangle -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause // -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// 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 //----------------------------------------------------------------------------- @@ -24,7 +27,7 @@ LAGraph_Graph G = NULL; #define LEN 512 char filename [LEN+1] ; -int64_t karate_graphlet_counts [ ] = +int64_t karate_graphlet_counts [ ] = { 1,16,17,102,18,81,197,13,352,6,34,171,10,2,30,7, 1,9,19,24,12,73,56,33,32,8,80,27,6,2,18,7, diff --git a/experimental/test/test_HelloWorld.c b/experimental/test/test_HelloWorld.c index 1e1e57172a..9ac693b388 100644 --- a/experimental/test/test_HelloWorld.c +++ b/experimental/test/test_HelloWorld.c @@ -2,11 +2,14 @@ // LAGraph/src/test/test_HelloWorld.c: test cases for LAGraph_HelloWorld //---------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause // -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// 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 //----------------------------------------------------------------------------- @@ -80,4 +83,3 @@ TEST_LIST = {"HelloWorld", test_HelloWorld}, // just one test in this example {NULL, NULL} } ; - diff --git a/experimental/test/test_KCore.c b/experimental/test/test_KCore.c index 8e604458b6..36cf57b9e2 100644 --- a/experimental/test/test_KCore.c +++ b/experimental/test/test_KCore.c @@ -2,11 +2,14 @@ // LAGraph/expirimental/test/test_KCore.c: test cases for single k-core // ---------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause // -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// 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 Pranav Konduri, Texas A&M University @@ -69,7 +72,7 @@ void test_KCore (void) OK (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; if (G->is_symmetric_structure == LAGraph_FALSE) - { + { printf("This matrix is not symmetric. \n"); // make the adjacency matrix symmetric OK (LAGraph_Cached_AT (G, msg)) ; @@ -93,7 +96,7 @@ void test_KCore (void) printf ("now has %g self edges\n", (double) G->nself_edges) ; TEST_CHECK (G->nself_edges == 0) ; } - + uint64_t kmax; bool ok; //test the k-core @@ -116,7 +119,7 @@ void test_KCore (void) void test_errors (void) { LAGraph_Init (msg) ; - + snprintf (filename, LEN, LG_DATA_DIR "%s", "karate.mtx") ; FILE *f = fopen (filename, "r") ; TEST_CHECK (f != NULL) ; diff --git a/experimental/test/test_KCoreDecompose.c b/experimental/test/test_KCoreDecompose.c index 1c300c11b0..ae901bd46e 100644 --- a/experimental/test/test_KCoreDecompose.c +++ b/experimental/test/test_KCoreDecompose.c @@ -3,8 +3,14 @@ // decomposition // ---------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// 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 Pranav Konduri, Texas A&M University @@ -68,7 +74,7 @@ void test_KCoreDecompose (void) OK (LAGraph_Cached_IsSymmetricStructure (G, msg)) ; if (G->is_symmetric_structure == LAGraph_FALSE) - { + { printf("This matrix is not symmetric. \n"); // make the adjacency matrix symmetric OK (LAGraph_Cached_AT (G, msg)) ; @@ -96,7 +102,7 @@ void test_KCoreDecompose (void) bool ok; //get the kcore at the designated k-value LAGraph_KCore(&c, G, kval, msg) ; - + //decompose the k-core from vector c into D1 LAGraph_KCore_Decompose(&D1, G, c, kval, msg); @@ -106,7 +112,7 @@ void test_KCoreDecompose (void) //check equality OK (LAGraph_Matrix_IsEqual (&ok, D1, D2, msg)) ; TEST_CHECK(ok); - + OK (LAGraph_Delete (&G, msg)) ; } diff --git a/experimental/test/test_KTruss.c b/experimental/test/test_KTruss.c index 865b9af1a3..bbb4652650 100644 --- a/experimental/test/test_KTruss.c +++ b/experimental/test/test_KTruss.c @@ -2,10 +2,14 @@ // LAGraph/experimental/test/test_KTruss.c: test cases for k-truss // ---------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/experimental/test/test_MaximalIndependentSet.c b/experimental/test/test_MaximalIndependentSet.c index 624f5e8442..feeb4c33e2 100644 --- a/experimental/test/test_MaximalIndependentSet.c +++ b/experimental/test/test_MaximalIndependentSet.c @@ -2,10 +2,14 @@ // LAGraph/experimental/test/test_MaximalIndependentSet //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -143,7 +147,7 @@ void test_MIS (void) } for (int64_t seed = 0 ; seed <= 4*n ; seed += n) - { + { // compute the MIS with no ignored nodes OK (LAGraph_MaximalIndependentSet (&mis, G, seed, NULL, msg)) ; // check the result @@ -167,7 +171,7 @@ void test_MIS (void) { // make node i a singleton I [0] = i ; - OK (GrB_assign (G->A, NULL, NULL, empty_col, GrB_ALL, n, I, 1, + OK (GrB_assign (G->A, NULL, NULL, empty_col, GrB_ALL, n, I, 1, NULL)) ; OK (GrB_assign (G->A, NULL, NULL, empty_row, I, 1, GrB_ALL, n, NULL)) ; @@ -190,7 +194,7 @@ void test_MIS (void) TEST_CHECK (nsingletons <= nsingletons_actual) ; for (int64_t seed = 0 ; seed <= 4*n ; seed += n) - { + { // compute the MIS with no ignored nodes OK (LAGraph_MaximalIndependentSet (&mis, G, seed, NULL, msg)) ; // check the result @@ -244,4 +248,3 @@ TEST_LIST = { "MIS", test_MIS }, { NULL, NULL } } ; - diff --git a/experimental/test/test_Random.c b/experimental/test/test_Random.c index 685cbb7bbc..f023604fe9 100644 --- a/experimental/test/test_Random.c +++ b/experimental/test/test_Random.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_Random.c: test cases for random vector generator //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -80,4 +84,3 @@ TEST_LIST = { {"Random", test_Random}, {NULL, NULL} }; - diff --git a/experimental/test/test_Random_Matrix.c b/experimental/test/test_Random_Matrix.c index c5e4133bc6..df6f80c36b 100644 --- a/experimental/test/test_Random_Matrix.c +++ b/experimental/test/test_Random_Matrix.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_Random_Matrix.c: test cases for random matrix generator //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -123,4 +127,3 @@ TEST_LIST = { {"Random_Matrix", test_Random_Matrix}, {NULL, NULL} }; - diff --git a/experimental/test/test_SSaveSet.c b/experimental/test/test_SSaveSet.c index f0c62bbe9b..d02be5f939 100644 --- a/experimental/test/test_SSaveSet.c +++ b/experimental/test/test_SSaveSet.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_SWrite.c: test cases for LAGraph_SWrite and SRead // ---------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -130,7 +134,7 @@ void test_SSaveSet (void) GrB_Matrix *Set2 = NULL ; GrB_Index nmatrices = 0 ; char *collection = NULL ; - int r = + int r = LAGraph_SLoadSet ("matrices.lagraph", &Set2, &nmatrices, &collection, msg) ; printf ("nmatrices %g r %d msg %s\n", (double) nmatrices, r, msg) ; diff --git a/experimental/test/test_SWrite.c b/experimental/test/test_SWrite.c index 002956df48..53d883e1c8 100644 --- a/experimental/test/test_SWrite.c +++ b/experimental/test/test_SWrite.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_SWrite.c: test cases for LAGraph_SWrite and SRead // ---------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/experimental/test/test_SquareClustering.c b/experimental/test/test_SquareClustering.c index f7e3896a13..b4e976aa6c 100644 --- a/experimental/test/test_SquareClustering.c +++ b/experimental/test/test_SquareClustering.c @@ -3,8 +3,14 @@ // square clustering // ----------------------------------------------------------------------------- -// LAGraph, (c) 2022 by The LAGraph Contributors, All Rights Reserved. +// 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 Erik Welch, NVIDIA diff --git a/experimental/test/test_TriangleCentrality.c b/experimental/test/test_TriangleCentrality.c index d218f28b2f..e1bcba3239 100644 --- a/experimental/test/test_TriangleCentrality.c +++ b/experimental/test/test_TriangleCentrality.c @@ -3,10 +3,14 @@ // centrality //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/experimental/test/test_cdlp.c b/experimental/test/test_cdlp.c index 805be8bab0..26a5170188 100644 --- a/experimental/test/test_cdlp.c +++ b/experimental/test/test_cdlp.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_cdlp.c: test cases for CDLP // ---------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/experimental/test/test_dnn.c b/experimental/test/test_dnn.c index 7ade2cb79a..f171ba1e7b 100644 --- a/experimental/test/test_dnn.c +++ b/experimental/test/test_dnn.c @@ -2,10 +2,14 @@ // LAGraph/experimental/test/test_dnn: test a small sparse deep neural network //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -195,4 +199,3 @@ TEST_LIST = { {"DNN", test_dnn}, {NULL, NULL} } ; - diff --git a/experimental/test/test_lcc.c b/experimental/test/test_lcc.c index 0a1114c6e4..d838eae9b1 100644 --- a/experimental/test/test_lcc.c +++ b/experimental/test/test_lcc.c @@ -2,10 +2,14 @@ // LAGraph/experimental/test/test_lcc.c: tests for Local Clustering Coefficient // ---------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/experimental/test/test_msf.c b/experimental/test/test_msf.c index bdd89cca7c..459373c6cf 100644 --- a/experimental/test/test_msf.c +++ b/experimental/test/test_msf.c @@ -2,10 +2,14 @@ // LAGraph/experimental/test/test_msf.c: test cases for Min Spanning Forest //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/experimental/test/test_scc.c b/experimental/test/test_scc.c index 4638fac5d4..d16667c6fd 100644 --- a/experimental/test/test_scc.c +++ b/experimental/test/test_scc.c @@ -2,10 +2,14 @@ // LAGraph/experimental/test/test_scc.c: tests for Strongly Connected Components //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -180,4 +184,3 @@ TEST_LIST = { {"scc_errors", test_errors}, {NULL, NULL} }; - diff --git a/experimental/utility/LAGraph_Random.c b/experimental/utility/LAGraph_Random.c index 0f3275f851..51c8e1c6e2 100644 --- a/experimental/utility/LAGraph_Random.c +++ b/experimental/utility/LAGraph_Random.c @@ -2,10 +2,14 @@ // LAGraph_Random: generate a random vector (of any sparsity structure) //------------------------------------------------------------------------------ -// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// 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 @@ -27,7 +31,7 @@ #define LG_RAND_NEXT(seed) ((seed) * 1103515245 + 12345) // extract a random 15-bit value from a seed (no longer used) -// #define LG_RAND_15_MAX 32767 +// #define LG_RAND_15_MAX 32767 // #define LG_RAND_15(seed) (((seed)/65536) % (LG_RAND_15_MAX + 1)) //------------------------------------------------------------------------------ @@ -139,7 +143,7 @@ int LAGraph_Random_Seed // construct a random seed vector { // Set all Seed values to 1, to break the random seed vector. // This is just for testing, to test algorithms that need to handle - // extreme cases when the random number generator is non-random. + // extreme cases when the random number generator is non-random. GRB_TRY (GrB_Vector_apply_BinaryOp2nd_UINT64 (Seed, NULL, NULL, GrB_ONEB_UINT64, Seed, 0, NULL)) ; } @@ -170,4 +174,3 @@ int LAGraph_Random_Next // advance to next random vector GRB_TRY (GrB_Vector_apply (Seed, NULL, NULL, LG_rand_next_op, Seed, NULL)) ; return (GrB_SUCCESS) ; } - diff --git a/experimental/utility/LAGraph_Random_Matrix.c b/experimental/utility/LAGraph_Random_Matrix.c index 49eae154e9..3a15171cac 100644 --- a/experimental/utility/LAGraph_Random_Matrix.c +++ b/experimental/utility/LAGraph_Random_Matrix.c @@ -2,10 +2,14 @@ // LAGraph_Random_Matrix: generate a random matrix //------------------------------------------------------------------------------ -// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// 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 @@ -433,4 +437,3 @@ GrB_Info LAGraph_Random_Matrix // random matrix of any built-in type LG_FREE_WORK ; return (GrB_SUCCESS) ; } - diff --git a/experimental/utility/LAGraph_SFreeContents.c b/experimental/utility/LAGraph_SFreeContents.c index 4a3b0a8955..9c7593fa8b 100644 --- a/experimental/utility/LAGraph_SFreeContents.c +++ b/experimental/utility/LAGraph_SFreeContents.c @@ -2,10 +2,14 @@ // LAGraph_SFreeContents: free the Contents returned by LAGraph_SRead. //------------------------------------------------------------------------------ -// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// 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 @@ -34,4 +38,3 @@ void LAGraph_SFreeContents // free the Contents returned by LAGraph_SRead LAGraph_Free ((void **) Contents_handle, NULL) ; } } - diff --git a/experimental/utility/LAGraph_SFreeSet.c b/experimental/utility/LAGraph_SFreeSet.c index b9a1f97309..2781ea15bb 100644 --- a/experimental/utility/LAGraph_SFreeSet.c +++ b/experimental/utility/LAGraph_SFreeSet.c @@ -2,10 +2,14 @@ // LAGraph_SFreeSet: free a set of matrices //------------------------------------------------------------------------------ -// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// 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 @@ -34,4 +38,3 @@ void LAGraph_SFreeSet // free a set of matrices LAGraph_Free ((void **) Set_handle, NULL) ; } } - diff --git a/experimental/utility/LAGraph_SLoadSet.c b/experimental/utility/LAGraph_SLoadSet.c index 0b3fcf4425..e5b7a71bf0 100644 --- a/experimental/utility/LAGraph_SLoadSet.c +++ b/experimental/utility/LAGraph_SLoadSet.c @@ -2,10 +2,14 @@ // LAGraph_SLoadSet: load a set of matrices from a *.lagraph file //------------------------------------------------------------------------------ -// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// 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 @@ -166,4 +170,3 @@ int LAGraph_SLoadSet // load a set of matrices from a *.lagraph file (*nmatrices_handle) = nmatrices ; return (GrB_SUCCESS) ; } - diff --git a/experimental/utility/LAGraph_SRead.c b/experimental/utility/LAGraph_SRead.c index a78ebbfee5..c431083bb0 100644 --- a/experimental/utility/LAGraph_SRead.c +++ b/experimental/utility/LAGraph_SRead.c @@ -2,10 +2,14 @@ // LAGraph_SRead: read a sequence of serialized objects from a file //------------------------------------------------------------------------------ -// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// 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 @@ -131,7 +135,7 @@ int LAGraph_SRead // read a set of matrices from a *.lagraph file LAGRAPH_TRY (LAGraph_Malloc ((void **) &json_string, s, sizeof (char), msg)) ; while (true) - { + { if (k == s) { // json_string is full; double its size @@ -181,7 +185,7 @@ int LAGraph_SRead // read a set of matrices from a *.lagraph file LAGRAPH_VERSION_UPDATE)) ; //-------------------------------------------------------------------------- - // check GraphBLAS library name and version + // check GraphBLAS library name and version //-------------------------------------------------------------------------- o = o->next ; @@ -368,4 +372,3 @@ int LAGraph_SRead // read a set of matrices from a *.lagraph file (*ncontents_handle) = ncontents ; return (GrB_SUCCESS) ; } - diff --git a/experimental/utility/LAGraph_SSaveSet.c b/experimental/utility/LAGraph_SSaveSet.c index ab68e1ae30..d0d8454754 100644 --- a/experimental/utility/LAGraph_SSaveSet.c +++ b/experimental/utility/LAGraph_SSaveSet.c @@ -2,10 +2,14 @@ // LAGraph_SSaveSet: save a set of matrices to a *.lagraph file //------------------------------------------------------------------------------ -// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// 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 @@ -139,4 +143,3 @@ int LAGraph_SSaveSet // save a set of matrices from a *.lagraph file LG_FREE_WORK ; return (GrB_SUCCESS) ; } - diff --git a/experimental/utility/LAGraph_SWrite.c b/experimental/utility/LAGraph_SWrite.c index b9f265a323..df75e0602f 100644 --- a/experimental/utility/LAGraph_SWrite.c +++ b/experimental/utility/LAGraph_SWrite.c @@ -2,10 +2,14 @@ // LAGraph_SWrite: write a sequence of serialized objects to a file //------------------------------------------------------------------------------ -// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// 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 @@ -174,4 +178,3 @@ int LAGraph_SWrite_Item // write the serialized blob of a matrix/vector/text "file not written properly") ; return (GrB_SUCCESS) ; } - diff --git a/rtdocs/CMakeLists.txt b/rtdocs/CMakeLists.txt index 19d7986550..10c0f9e30e 100644 --- a/rtdocs/CMakeLists.txt +++ b/rtdocs/CMakeLists.txt @@ -1,3 +1,17 @@ +#------------------------------------------------------------------------------- +# LAGraph/rtdocs/CMakeLists.txt: cmake script for LAGraph/src/test +#------------------------------------------------------------------------------- + +# 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 + +#------------------------------------------------------------------------------- find_package(Doxygen REQUIRED) find_package(Sphinx REQUIRED) @@ -56,4 +70,4 @@ add_custom_target(Sphinx ALL DEPENDS ${SPHINX_INDEX_FILE}) include(GNUInstallDirs) install(DIRECTORY ${SPHINX_BUILD} - DESTINATION ${CMAKE_INSTALL_DOCDIR}) \ No newline at end of file + DESTINATION ${CMAKE_INSTALL_DOCDIR}) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 776979cbea..5fd6cdf1cf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,10 +2,14 @@ # LAGraph/src/CMakeLists.txt: cmake script for LAGraph/src #------------------------------------------------------------------------------- -# LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +# LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. # SPDX-License-Identifier: BSD-2-Clause -# See additional acknowledgments in the LICENSE file, -# or contact permission@sei.cmu.edu for the full terms. +# +# 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 #------------------------------------------------------------------------------- diff --git a/src/algorithm/LAGr_Betweenness.c b/src/algorithm/LAGr_Betweenness.c index 712d69743d..5b8eef961d 100644 --- a/src/algorithm/LAGr_Betweenness.c +++ b/src/algorithm/LAGr_Betweenness.c @@ -2,10 +2,14 @@ // LAGr_Betweenness: vertex betweenness-centrality //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Scott Kolodziej and Tim Davis, Texas A&M University; // Adapted and revised from GraphBLAS C API Spec, Appendix B.4. diff --git a/src/algorithm/LAGr_BreadthFirstSearch.c b/src/algorithm/LAGr_BreadthFirstSearch.c index 415bb61353..7ba3b9d945 100644 --- a/src/algorithm/LAGr_BreadthFirstSearch.c +++ b/src/algorithm/LAGr_BreadthFirstSearch.c @@ -2,10 +2,14 @@ // LAGr_BreadthFirstSearch: breadth-first search dispatch //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Scott McMillan, SEI Carnegie Mellon University @@ -39,4 +43,3 @@ int LAGr_BreadthFirstSearch return LG_BreadthFirstSearch_vanilla (level, parent, G, src, msg) ; #endif } - diff --git a/src/algorithm/LAGr_ConnectedComponents.c b/src/algorithm/LAGr_ConnectedComponents.c index 9ef3bf1597..ee0b875d1c 100644 --- a/src/algorithm/LAGr_ConnectedComponents.c +++ b/src/algorithm/LAGr_ConnectedComponents.c @@ -2,10 +2,14 @@ // LAGr_ConnectedComponents: connected components of an undirected graph //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -35,4 +39,3 @@ int LAGr_ConnectedComponents return (LG_CC_Boruvka (component, G, msg)) ; #endif } - diff --git a/src/algorithm/LAGr_PageRank.c b/src/algorithm/LAGr_PageRank.c index d2920c6da6..c9eff55dcd 100644 --- a/src/algorithm/LAGr_PageRank.c +++ b/src/algorithm/LAGr_PageRank.c @@ -2,10 +2,14 @@ // LAGr_PageRank: pagerank (for use in production, not for the GAP benchmark) //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 and Mohsen Aznaveh, Texas A&M University @@ -179,4 +183,3 @@ int LAGr_PageRank LG_FREE_WORK ; return (GrB_SUCCESS) ; } - diff --git a/src/algorithm/LAGr_PageRankGAP.c b/src/algorithm/LAGr_PageRankGAP.c index 0ac5c332dc..7aea1aaa52 100644 --- a/src/algorithm/LAGr_PageRankGAP.c +++ b/src/algorithm/LAGr_PageRankGAP.c @@ -2,10 +2,14 @@ // LAGr_PageRankGAP: pagerank for the GAP benchmark //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 and Mohsen Aznaveh, Texas A&M University @@ -146,4 +150,3 @@ int LAGr_PageRankGAP LG_FREE_WORK ; return (GrB_SUCCESS) ; } - diff --git a/src/algorithm/LAGr_SingleSourceShortestPath.c b/src/algorithm/LAGr_SingleSourceShortestPath.c index b7b70eb9a8..32004003ef 100644 --- a/src/algorithm/LAGr_SingleSourceShortestPath.c +++ b/src/algorithm/LAGr_SingleSourceShortestPath.c @@ -2,10 +2,14 @@ // LAGr_SingleSourceShortestPath: single-source shortest path //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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, Scott Kolodziej and Tim Davis, Texas A&M // University. Adapted from GraphBLAS Template Library (GBTL) by Scott @@ -416,4 +420,3 @@ int LAGr_SingleSourceShortestPath LG_FREE_WORK ; return (GrB_SUCCESS) ; } - diff --git a/src/algorithm/LAGr_TriangleCount.c b/src/algorithm/LAGr_TriangleCount.c index cc91b3e50b..e809f595da 100644 --- a/src/algorithm/LAGr_TriangleCount.c +++ b/src/algorithm/LAGr_TriangleCount.c @@ -2,10 +2,14 @@ // LAGr_TriangleCount: Triangle counting using various methods //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -45,7 +49,7 @@ // Reference for the Burkhardt method: Burkhardt, Paul. "Graphing Trillions of // Triangles." Information Visualization 16, no. 3 (July 2017): 157–66. // https://doi.org/10.1177/1473871616666393. - + // Reference for the Cohen method: J. Cohen, "Graph twiddling in a mapreduce // world," Computing in Science & Engineering, vol. 11, no. 4, pp. 29–41, 2009. // https://doi.org/10.1109/MCSE.2009.120 diff --git a/src/algorithm/LAGraph_TriangleCount.c b/src/algorithm/LAGraph_TriangleCount.c index 77c5e1ccf7..fb7d6597a1 100644 --- a/src/algorithm/LAGraph_TriangleCount.c +++ b/src/algorithm/LAGraph_TriangleCount.c @@ -2,10 +2,14 @@ // LAGraph_TriangleCount: triangle counting dispatch, basic API //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Scott McMillan, SEI Carnegie Mellon University @@ -40,4 +44,3 @@ int LAGraph_TriangleCount // auto method and auto sort return (LAGr_TriangleCount (ntriangles, G, NULL, NULL, msg)) ; } - diff --git a/src/algorithm/LG_BreadthFirstSearch_SSGrB.c b/src/algorithm/LG_BreadthFirstSearch_SSGrB.c index b25214c899..9e2795c809 100644 --- a/src/algorithm/LG_BreadthFirstSearch_SSGrB.c +++ b/src/algorithm/LG_BreadthFirstSearch_SSGrB.c @@ -2,10 +2,14 @@ // LG_BreadthFirstSearch_SSGrB: BFS using Suitesparse extensions //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -16,7 +20,7 @@ // defaults to a push-only algorithm, which can be slower. This is not // user-callable (see LAGr_BreadthFirstSearch instead). G->AT and // G->out_degree are not computed if not present. - + // References: // // Carl Yang, Aydin Buluc, and John D. Owens. 2018. Implementing Push-Pull diff --git a/src/algorithm/LG_BreadthFirstSearch_vanilla.c b/src/algorithm/LG_BreadthFirstSearch_vanilla.c index 9e865674c7..2bb089b669 100644 --- a/src/algorithm/LG_BreadthFirstSearch_vanilla.c +++ b/src/algorithm/LG_BreadthFirstSearch_vanilla.c @@ -2,10 +2,14 @@ // LG_BreadthFirstSearch_vanilla: BFS using only GraphBLAS API //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Scott McMillan, derived from examples in the appendix of // The GraphBLAS C API Specification, v1.3.0 diff --git a/src/algorithm/LG_CC_Boruvka.c b/src/algorithm/LG_CC_Boruvka.c index a9c427d2a4..79cc5a3dd0 100644 --- a/src/algorithm/LG_CC_Boruvka.c +++ b/src/algorithm/LG_CC_Boruvka.c @@ -2,10 +2,14 @@ // LG_CC_Boruvka.c: connected components using GrB* methods only //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Yongzhe Zhang (zyz915@gmail.com). // Modified by Timothy A. Davis, Texas A&M University diff --git a/src/algorithm/LG_CC_FastSV6.c b/src/algorithm/LG_CC_FastSV6.c index bd0c6397ef..2a8043a851 100644 --- a/src/algorithm/LG_CC_FastSV6.c +++ b/src/algorithm/LG_CC_FastSV6.c @@ -2,10 +2,14 @@ // LG_CC_FastSV6: connected components //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Yongzhe Zhang, modified by Timothy A. Davis, Texas A&M // University @@ -241,7 +245,7 @@ int LG_CC_FastSV6 // SuiteSparse:GraphBLAS method, with GxB extensions GRB_TRY (GrB_Matrix_nrows (&n, A)) ; GRB_TRY (GrB_Matrix_nvals (&nvals, A)) ; - // determine the integer type, operators, and semirings to use + // determine the integer type, operators, and semirings to use GrB_Type Uint, Int ; GrB_IndexUnaryOp ramp ; GrB_Semiring min_2nd, min_2ndi ; @@ -527,7 +531,7 @@ int LG_CC_FastSV6 // SuiteSparse:GraphBLAS method, with GxB extensions // not changed). The key node is the representative of the (estimated) // largest component. T is constructed as a copy of A, except: // (1) all edges A(i,:) for nodes i in the key component deleted, and - // (2) for nodes i not in the key component, A(i,j) is deleted if + // (2) for nodes i not in the key component, A(i,j) is deleted if // j is in the key component. // (3) If A(i,:) has any deletions from (2), T(i,key) is added to T. diff --git a/src/algorithm/LG_alg_internal.h b/src/algorithm/LG_alg_internal.h index 7f4131171b..e29175e3b5 100644 --- a/src/algorithm/LG_alg_internal.h +++ b/src/algorithm/LG_alg_internal.h @@ -2,10 +2,14 @@ // LG_alg_internal.h: include file for use within LAGraph algorithms //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/benchmark/CMakeLists.txt b/src/benchmark/CMakeLists.txt index 4cd7729377..ac1cebe34c 100644 --- a/src/benchmark/CMakeLists.txt +++ b/src/benchmark/CMakeLists.txt @@ -1,11 +1,15 @@ #------------------------------------------------------------------------------- -# LAGraph/src/demo/CMakeLists.txt: cmake script for LAGraph/src/demo +# LAGraph/src/benchmark/CMakeLists.txt: cmake script for LAGraph/src/benchmark #------------------------------------------------------------------------------- -# LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +# LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. # SPDX-License-Identifier: BSD-2-Clause -# See additional acknowledgments in the LICENSE file, -# or contact permission@sei.cmu.edu for the full terms. +# +# 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 #------------------------------------------------------------------------------- diff --git a/src/benchmark/LAGraph_demo.h b/src/benchmark/LAGraph_demo.h index a2896df08c..3bb05feca5 100644 --- a/src/benchmark/LAGraph_demo.h +++ b/src/benchmark/LAGraph_demo.h @@ -2,10 +2,14 @@ // LAGraph_demo.h: include file for LAGraph/src/benchmark programs //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -119,7 +123,7 @@ static inline int binwrite // returns 0 if successful, < 0 on error switch (kind) { - default : + default : case 0 : // for backward compatibility with prior versions case 2 : is_sparse = true ; break ; // GxB_SPARSE = 2 case 1 : is_hyper = true ; break ; // GxB_HYPERSPARSE = 1 @@ -1144,4 +1148,3 @@ static inline int demo_init (bool burble) #undef LG_FREE_ALL #endif - diff --git a/src/benchmark/bc_demo.c b/src/benchmark/bc_demo.c index 7fa7b94d7f..a7333b4cdc 100644 --- a/src/benchmark/bc_demo.c +++ b/src/benchmark/bc_demo.c @@ -2,10 +2,14 @@ // LAGraph/src/demo/bc_demo: betweenness centrality for the GAP benchmark //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Scott Kolodziej and Timothy A. Davis, Texas A&M University diff --git a/src/benchmark/bfs_demo.c b/src/benchmark/bfs_demo.c index 1176b887dc..0cb7cefdf2 100644 --- a/src/benchmark/bfs_demo.c +++ b/src/benchmark/bfs_demo.c @@ -2,10 +2,14 @@ // LAGraph/src/benchmark/bfs_demo.c: benchmark for LAGr_BreadthFirstSearch //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/benchmark/cc_demo.c b/src/benchmark/cc_demo.c index bb2b3e615e..7974615aac 100644 --- a/src/benchmark/cc_demo.c +++ b/src/benchmark/cc_demo.c @@ -2,10 +2,14 @@ // LAGraph/src/benchmark/cc_demo.c: benchmark LAGr_ConnectedComponents //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/benchmark/gappagerank_demo.c b/src/benchmark/gappagerank_demo.c index 779f9c9fe8..526adece25 100644 --- a/src/benchmark/gappagerank_demo.c +++ b/src/benchmark/gappagerank_demo.c @@ -2,10 +2,14 @@ // LAGraph/src/benchmark/gappagerank_demo.c: benchmark GAP PageRank //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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, and Gabor Szarnyas, // BME diff --git a/src/benchmark/mtx2bin_demo.c b/src/benchmark/mtx2bin_demo.c index bb7b8e1df7..83e767194f 100644 --- a/src/benchmark/mtx2bin_demo.c +++ b/src/benchmark/mtx2bin_demo.c @@ -2,10 +2,14 @@ // mtx2bin: convert Matrix Market file to SuiteSparse:GraphBLAS binary file //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -83,4 +87,3 @@ int main (int argc, char **argv) LG_FREE_ALL ; return (GrB_SUCCESS) ; } - diff --git a/src/benchmark/ss2_demo.c b/src/benchmark/ss2_demo.c index 6bc7f6b8ab..277d5eeefc 100644 --- a/src/benchmark/ss2_demo.c +++ b/src/benchmark/ss2_demo.c @@ -2,10 +2,14 @@ // test_sssp: test for LAGraph //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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, Scott Kolodziej and Timothy A. Davis, Texas A&M // University diff --git a/src/benchmark/sssp_demo.c b/src/benchmark/sssp_demo.c index c6bc003273..a39472e20a 100644 --- a/src/benchmark/sssp_demo.c +++ b/src/benchmark/sssp_demo.c @@ -2,10 +2,14 @@ // LAGraph/src/benchmark/sssp_demo: test for LAGraph SSSP //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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, Scott Kolodziej and Timothy A. Davis, Texas A&M // University diff --git a/src/benchmark/tc_demo.c b/src/benchmark/tc_demo.c index 3e5c9788bf..d8df410122 100644 --- a/src/benchmark/tc_demo.c +++ b/src/benchmark/tc_demo.c @@ -1,11 +1,15 @@ //------------------------------------------------------------------------------ -// LAGraph/src/benchmark/tc_demo.c: benchmark for LAGr_TriangleCount +// LAGraph/src/benchmark/tc_demo.c: benchmark for LAGr_TriangleCount //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -253,4 +257,3 @@ int main (int argc, char **argv) LAGRAPH_TRY (LAGraph_Finalize (msg)) ; return (GrB_SUCCESS) ; } - diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 6e72eab9fd..dbeac48d75 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -2,10 +2,14 @@ # LAGraph/src/test/CMakeLists.txt: cmake script for LAGraph/src/test #------------------------------------------------------------------------------- -# LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +# LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. # SPDX-License-Identifier: BSD-2-Clause -# See additional acknowledgments in the LICENSE file, -# or contact permission@sei.cmu.edu for the full terms. +# +# 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 #------------------------------------------------------------------------------- diff --git a/src/test/LG_brutal_malloc.c b/src/test/LG_brutal_malloc.c index 5a4e266b78..6db6373ef6 100644 --- a/src/test/LG_brutal_malloc.c +++ b/src/test/LG_brutal_malloc.c @@ -2,10 +2,14 @@ // LG_brutal_malloc: brutal memory debugging //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -157,4 +161,3 @@ void *LG_brutal_realloc // return pointer to reallocated memory } return (p) ; } - diff --git a/src/test/LG_brutal_setup.c b/src/test/LG_brutal_setup.c index e7532eb72e..e55c9248bf 100644 --- a/src/test/LG_brutal_setup.c +++ b/src/test/LG_brutal_setup.c @@ -2,10 +2,14 @@ // LG_brutal_setup.c: setup an LAGraph test with brutal memory testing // ----------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -30,4 +34,3 @@ int LG_brutal_setup (char *msg) #endif return (result) ; } - diff --git a/src/test/LG_brutal_teardown.c b/src/test/LG_brutal_teardown.c index 7b5a26a69a..c0e39b49da 100644 --- a/src/test/LG_brutal_teardown.c +++ b/src/test/LG_brutal_teardown.c @@ -2,10 +2,14 @@ // LG_brutal_teardown.c: teardown an LAGraph test with brutal memory testing // ----------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -21,4 +25,3 @@ int LG_brutal_teardown (char *msg) if (LG_nmalloc != 0) printf ("Leak! %g\n", (double) LG_nmalloc) ; return ((LG_nmalloc == 0) ? 0 : -911) ; } - diff --git a/src/test/LG_check_bfs.c b/src/test/LG_check_bfs.c index 81df6e7af4..05c0a6e8d3 100644 --- a/src/test/LG_check_bfs.c +++ b/src/test/LG_check_bfs.c @@ -2,10 +2,14 @@ // LAGraph/src/test/LG_check_bfs: stand-alone test for BFS //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -75,7 +79,7 @@ int LG_check_bfs //-------------------------------------------------------------------------- LG_TRY (LAGraph_Malloc ((void **) &queue, n, sizeof (int64_t), msg)) ; - LG_TRY (LAGraph_Malloc ((void **) &level_check, n, sizeof (int64_t), msg)) ; + LG_TRY (LAGraph_Malloc ((void **) &level_check, n, sizeof (int64_t), msg)) ; //-------------------------------------------------------------------------- // get the contents of the Level and Parent vectors @@ -239,4 +243,3 @@ int LG_check_bfs } return (GrB_SUCCESS) ; } - diff --git a/src/test/LG_check_cc.c b/src/test/LG_check_cc.c index 142e2a83ab..278f3f7800 100644 --- a/src/test/LG_check_cc.c +++ b/src/test/LG_check_cc.c @@ -2,10 +2,14 @@ // LAGraph/src/test/LG_check_cc: stand-alone test for CC //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -38,7 +42,7 @@ // number of representatives. //------------------------------------------------------------------------------ -// test the results from LAGr_ConnectedComponents +// test the results from LAGr_ConnectedComponents //------------------------------------------------------------------------------ // Because this method does on GxB_unpack on G->A, it should not be used in a @@ -97,7 +101,7 @@ int LG_check_cc int64_t ncomp_in = 0 ; for (int64_t i = 0 ; i < n ; i++) { - int64_t comp = component_in [i] ; + int64_t comp = component_in [i] ; LG_ASSERT (comp >= 0 && comp < n, -2000) ; count [comp]++ ; if (comp == i) @@ -222,4 +226,3 @@ int LG_check_cc return (GrB_SUCCESS) ; } - diff --git a/src/test/LG_check_export.c b/src/test/LG_check_export.c index 6a0269400b..8b6dfaa653 100644 --- a/src/test/LG_check_export.c +++ b/src/test/LG_check_export.c @@ -2,10 +2,14 @@ // LG_check_export: export G->A for testing //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -95,12 +99,12 @@ int LG_check_export } else if (atype == GrB_INT16 ) { - GRB_TRY (GrB_Matrix_export (Ap, Aj, (int16_t *) Ax, + GRB_TRY (GrB_Matrix_export (Ap, Aj, (int16_t *) Ax, Ap_len, Aj_len, Ax_len, GrB_CSR_FORMAT, G->A)) ; } else if (atype == GrB_INT32 ) { - GRB_TRY (GrB_Matrix_export (Ap, Aj, (int32_t *) Ax, + GRB_TRY (GrB_Matrix_export (Ap, Aj, (int32_t *) Ax, Ap_len, Aj_len, Ax_len, GrB_CSR_FORMAT, G->A)) ; } else if (atype == GrB_INT64 ) diff --git a/src/test/LG_check_sssp.c b/src/test/LG_check_sssp.c index 2bf826b57b..4d0a20fc4a 100644 --- a/src/test/LG_check_sssp.c +++ b/src/test/LG_check_sssp.c @@ -2,10 +2,14 @@ // LAGraph/src/test/LG_check_sssp: stand-alone test for SSSP //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -378,4 +382,3 @@ int LG_check_sssp } return (GrB_SUCCESS) ; } - diff --git a/src/test/LG_check_tri.c b/src/test/LG_check_tri.c index 45ca4b8362..59fbff8983 100644 --- a/src/test/LG_check_tri.c +++ b/src/test/LG_check_tri.c @@ -2,10 +2,14 @@ // LG_check_tri: compute the number of triangles in a graph (simple method) //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -102,17 +106,17 @@ int LG_check_tri // -1 if out of memory, 0 if successful int64_t i1 = Ai [p1] ; int64_t i2 = Ai [p2] ; if (i1 < i2) - { + { // A(i1,i) appears before A(i2,j) p1++ ; } else if (i2 < i1) - { + { // A(i2,j) appears before A(i1,i) p2++ ; } else // i1 == i2 == k - { + { // A(k,i) and A(k,j) are the next entries to merge ntriangles++ ; p1++ ; @@ -132,4 +136,3 @@ int LG_check_tri // -1 if out of memory, 0 if successful (*ntri) = ntriangles ; return (GrB_SUCCESS) ; } - diff --git a/src/test/LG_check_vector.c b/src/test/LG_check_vector.c index 442d0ee916..b908cbe015 100644 --- a/src/test/LG_check_vector.c +++ b/src/test/LG_check_vector.c @@ -2,10 +2,14 @@ // LAGraph/src/test/LG_check_vector: extract contents of a vector, for testing //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -42,4 +46,3 @@ int LG_check_vector } return (GrB_SUCCESS) ; } - diff --git a/src/test/LG_heap.h b/src/test/LG_heap.h index 158e59c498..522d2858b5 100644 --- a/src/test/LG_heap.h +++ b/src/test/LG_heap.h @@ -2,10 +2,14 @@ // LG_heap: a Heap data structure and its operations //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -177,7 +181,7 @@ static inline void LG_heapify ASSERT (Heap != NULL && Iheap != NULL) ; if (p > nheap / 2 || nheap <= 1) - { + { // nothing to do. p has no children in the Heap. // Also safely do nothing if p is outside the Heap (p > nheap). return ; @@ -221,7 +225,7 @@ static inline void LG_heapify { // left node has a smaller key than the right node if (e.key > eleft.key) - { + { // key of element e is bigger than the left child of p, so // bubble up the left child into the hole at Heap [p] and // continue down the left child. The hole moves to node @@ -231,7 +235,7 @@ static inline void LG_heapify p = pleft ; } else - { + { // done! key of element e is is smaller than the left // child of p; place e in the hole at p, and we're done. Heap [p] = e ; @@ -243,7 +247,7 @@ static inline void LG_heapify { // right node has a smaller key than the left node if (e.key > eright.key) - { + { // key of element e is bigger than the right child of p, so // bubble up the right child into hole at Heap [p] and // continue down the right child. The hole moves to node @@ -253,7 +257,7 @@ static inline void LG_heapify p = pright ; } else - { + { // done! key of element e is is smaller than the right // child of p; place e in the hole at p, and we're done. Heap [p] = e ; @@ -274,7 +278,7 @@ static inline void LG_heapify // left child is in the Heap; check its key LG_Element eleft = Heap [pleft] ; if (e.key > eleft.key) - { + { // key of element e is bigger than the left child of p, so // bubble up the left child into the hole at Heap [p] and // continue down the left child. The hole moves to node @@ -329,7 +333,7 @@ static inline void LG_heap_build //-------------------------------------------------------------------------- for (int64_t p = nheap / 2 ; p >= 1 ; p--) - { + { LG_heapify (p, Heap, Iheap, n, nheap) ; } @@ -354,7 +358,7 @@ static inline void LG_heap_delete int64_t *restrict nheap // the number of nodes in the Heap; // decremented on output ) -{ +{ //-------------------------------------------------------------------------- // check inputs @@ -397,7 +401,7 @@ static inline void LG_heap_decrease_key ASSERT (p >= 1 && p < nheap) ; ASSERT (new_key < Heap [p].key) ; -// printf ("Decreasing Heap [%ld] = name: %ld key: from %ld to %ld\n", +// printf ("Decreasing Heap [%ld] = name: %ld key: from %ld to %ld\n", // p, Heap [p].name, Heap [p].key, new_key) ; Heap [p].key = new_key ; @@ -423,4 +427,3 @@ static inline void LG_heap_decrease_key } #endif - diff --git a/src/test/test_Betweenness.c b/src/test/test_Betweenness.c index 61439ed86e..d779009838 100644 --- a/src/test/test_Betweenness.c +++ b/src/test/test_Betweenness.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_Betweenness.c: test cases for BC (GAP method) // ----------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -319,4 +323,3 @@ TEST_LIST = { #endif {NULL, NULL} }; - diff --git a/src/test/test_BreadthFirstSearch.c b/src/test/test_BreadthFirstSearch.c index 995cd3651e..117ca441d7 100644 --- a/src/test/test_BreadthFirstSearch.c +++ b/src/test/test_BreadthFirstSearch.c @@ -3,10 +3,14 @@ // counting algorithms // ---------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Scott McMillan, SEI/CMU, and Timothy A. Davis, Texas A&M // University @@ -669,4 +673,3 @@ TEST_LIST = { {"BreadthFirstSearch_brutal", test_bfs_brutal }, {NULL, NULL} } ; - diff --git a/src/test/test_Cached_AT.c b/src/test/test_Cached_AT.c index 6f91c9ea25..3546f8804d 100644 --- a/src/test/test_Cached_AT.c +++ b/src/test/test_Cached_AT.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_Cached_AT.c: test LAGraph_Cached_AT //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -208,4 +212,3 @@ TEST_LIST = #endif { NULL, NULL } } ; - diff --git a/src/test/test_Cached_Degree.c b/src/test/test_Cached_Degree.c index f1a74a5c36..6d9698644e 100644 --- a/src/test/test_Cached_Degree.c +++ b/src/test/test_Cached_Degree.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_Cached_Degree.c: test LAGraph_Cached_*Degree //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -85,132 +89,132 @@ matrix_info ; const matrix_info files [ ] = { - { "A.mtx", + { "A.mtx", { 3, 5, 5, 5, 3, 4, 5, }, { 3, 5, 5, 5, 3, 4, 5, }, }, - { "LFAT5.mtx", + { "LFAT5.mtx", { 3, 2, 2, 4, 4, 3, 3, 5, 5, 2, 2, 4, 4, 3, }, { 3, 2, 2, 4, 4, 3, 3, 5, 5, 2, 2, 4, 4, 3, }, }, - { "cover.mtx", + { "cover.mtx", { 2, 2, 1, 2, 1, 1, 3, }, { 1, 1, 3, 2, 2, 2, 1, }, }, - { "cover_structure.mtx", + { "cover_structure.mtx", { 2, 2, 1, 2, 1, 1, 3, }, { 1, 1, 3, 2, 2, 2, 1, }, }, - { "full.mtx", + { "full.mtx", { 3, 3, 3, }, { 3, 3, 3, }, }, - { "full_symmetric.mtx", + { "full_symmetric.mtx", { 4, 4, 4, 4, }, { 4, 4, 4, 4, }, }, - { "karate.mtx", + { "karate.mtx", { 16, 9, 10, 6, 3, 4, 4, 4, 5, 2, 3, 1, 2, 5, 2, 2, 2, 2, 2, 3, 2, 2, 2, 5, 3, 3, 2, 4, 3, 4, 4, 6, 12, 17, }, { 16, 9, 10, 6, 3, 4, 4, 4, 5, 2, 3, 1, 2, 5, 2, 2, 2, 2, 2, 3, 2, 2, 2, 5, 3, 3, 2, 4, 3, 4, 4, 6, 12, 17, }, }, - { "ldbc-cdlp-directed-example.mtx", + { "ldbc-cdlp-directed-example.mtx", { 3, 2, 2, 2, 3, 2, 3, 1, }, { 2, 2, 2, 1, 3, 4, 3, 1, }, }, - { "ldbc-cdlp-undirected-example.mtx", + { "ldbc-cdlp-undirected-example.mtx", { 3, 2, 2, 3, 4, 3, 3, 4, }, { 3, 2, 2, 3, 4, 3, 3, 4, }, }, - { "ldbc-directed-example-bool.mtx", + { "ldbc-directed-example-bool.mtx", { 2, 3, 4, 0, 3, 2, 1, 1, 1, 0, }, { 2, 0, 3, 5, 3, 0, 0, 2, 0, 2, }, }, - { "ldbc-directed-example-unweighted.mtx", + { "ldbc-directed-example-unweighted.mtx", { 2, 3, 4, 0, 3, 2, 1, 1, 1, 0, }, { 2, 0, 3, 5, 3, 0, 0, 2, 0, 2, }, }, - { "ldbc-directed-example.mtx", + { "ldbc-directed-example.mtx", { 2, 3, 4, 0, 3, 2, 1, 1, 1, 0, }, { 2, 0, 3, 5, 3, 0, 0, 2, 0, 2, }, }, - { "ldbc-undirected-example-bool.mtx", + { "ldbc-undirected-example-bool.mtx", { 2, 4, 2, 3, 5, 2, 3, 2, 1, }, { 2, 4, 2, 3, 5, 2, 3, 2, 1, }, }, - { "ldbc-undirected-example-unweighted.mtx", + { "ldbc-undirected-example-unweighted.mtx", { 2, 4, 2, 3, 5, 2, 3, 2, 1, }, { 2, 4, 2, 3, 5, 2, 3, 2, 1, }, }, - { "ldbc-undirected-example.mtx", + { "ldbc-undirected-example.mtx", { 2, 4, 2, 3, 5, 2, 3, 2, 1, }, { 2, 4, 2, 3, 5, 2, 3, 2, 1, }, }, - { "ldbc-wcc-example.mtx", + { "ldbc-wcc-example.mtx", { 3, 3, 5, 5, 5, 2, 1, 3, 1, 2, }, { 3, 3, 5, 5, 5, 2, 1, 3, 1, 2, }, }, - { "matrix_bool.mtx", + { "matrix_bool.mtx", { 2, 2, 1, 2, 1, 1, 3, }, { 1, 1, 3, 2, 2, 2, 1, }, }, - { "matrix_fp32.mtx", + { "matrix_fp32.mtx", { 2, 2, 1, 2, 1, 1, 3, }, { 1, 1, 3, 2, 2, 2, 1, }, }, - { "matrix_fp32_structure.mtx", + { "matrix_fp32_structure.mtx", { 2, 2, 1, 2, 1, 1, 3, }, { 1, 1, 3, 2, 2, 2, 1, }, }, - { "matrix_fp64.mtx", + { "matrix_fp64.mtx", { 2, 2, 1, 2, 1, 1, 3, }, { 1, 1, 3, 2, 2, 2, 1, }, }, - { "matrix_int16.mtx", + { "matrix_int16.mtx", { 2, 2, 1, 2, 1, 1, 3, }, { 1, 1, 3, 2, 2, 2, 1, }, }, - { "matrix_int32.mtx", + { "matrix_int32.mtx", { 2, 2, 1, 2, 1, 1, 3, }, { 1, 1, 3, 2, 2, 2, 1, }, }, - { "matrix_int64.mtx", + { "matrix_int64.mtx", { 2, 2, 1, 2, 1, 1, 3, }, { 1, 1, 3, 2, 2, 2, 1, }, }, - { "matrix_int8.mtx", + { "matrix_int8.mtx", { 2, 2, 1, 2, 1, 1, 3, }, { 1, 1, 3, 2, 2, 2, 1, }, }, - { "matrix_uint16.mtx", + { "matrix_uint16.mtx", { 2, 2, 1, 2, 1, 1, 3, }, { 1, 1, 3, 2, 2, 2, 1, }, }, - { "matrix_uint32.mtx", + { "matrix_uint32.mtx", { 2, 2, 1, 2, 1, 1, 3, }, { 1, 1, 3, 2, 2, 2, 1, }, }, - { "matrix_uint64.mtx", + { "matrix_uint64.mtx", { 2, 2, 1, 2, 1, 1, 3, }, { 1, 1, 3, 2, 2, 2, 1, }, }, - { "matrix_uint8.mtx", + { "matrix_uint8.mtx", { 2, 2, 1, 2, 1, 1, 3, }, { 1, 1, 3, 2, 2, 2, 1, }, }, - { "msf1.mtx", + { "msf1.mtx", { 2, 2, 1, 1, 1, 1, }, { 1, 1, 2, 2, 0, 2, }, }, - { "msf2.mtx", + { "msf2.mtx", { 2, 3, 3, 2, 1, 1, 0, 0, }, { 0, 1, 1, 1, 2, 2, 2, 3, }, }, - { "msf3.mtx", + { "msf3.mtx", { 2, 2, 2, 1, 0, }, { 0, 1, 1, 2, 3, }, }, - { "structure.mtx", + { "structure.mtx", { 2, 2, 1, 2, 1, 1, 3, }, { 1, 1, 3, 2, 2, 2, 1, }, }, - { "sample.mtx", + { "sample.mtx", { 3, 2, 1, 2, 2, 1, 1, 0, }, { 0, 1, 3, 1, 3, 1, 1, 2, }, }, - { "sample2.mtx", + { "sample2.mtx", { 2, 3, 4, 3, 5, 5, 3, 3, }, { 2, 3, 4, 3, 5, 5, 3, 3, }, }, - { "skew_fp32.mtx", + { "skew_fp32.mtx", { 3, 3, 3, 4, 3, 4, }, { 3, 3, 3, 4, 3, 4, }, }, - { "skew_fp64.mtx", + { "skew_fp64.mtx", { 3, 3, 3, 4, 3, 4, }, { 3, 3, 3, 4, 3, 4, }, }, - { "skew_int16.mtx", + { "skew_int16.mtx", { 3, 3, 3, 4, 3, 4, }, { 3, 3, 3, 4, 3, 4, }, }, - { "skew_int32.mtx", + { "skew_int32.mtx", { 3, 3, 3, 4, 3, 4, }, { 3, 3, 3, 4, 3, 4, }, }, - { "skew_int64.mtx", + { "skew_int64.mtx", { 3, 3, 3, 4, 3, 4, }, { 3, 3, 3, 4, 3, 4, }, }, - { "skew_int8.mtx", + { "skew_int8.mtx", { 3, 3, 3, 4, 3, 4, }, { 3, 3, 3, 4, 3, 4, }, }, - { "tree-example.mtx", + { "tree-example.mtx", { 1, 1, 2, 3, 2, 1, }, { 1, 1, 2, 3, 2, 1, }, }, - { "west0067.mtx", + { "west0067.mtx", { 3, 3, 3, 3, 5, 5, 5, 5, 5, 6, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 3, 3, 3, 3, 5, 5, 5, 5, 5, 6, 3, 3, 3, 3, 4, 4, 4, 4, 4, 6, 1, 5, 5, 5, 5, @@ -219,7 +223,7 @@ const matrix_info files [ ] = 3, 3, 3, 3, 3, 4, 4, 4, 4, 3, 10, 3, 3, 3, 3, 3, 10, 5, 5, 5, 5, 4, 5, 4, 4, 4, 4, 3, 10, 3, 3, 3, 3, 3, 10, 5, 5, 5, 5, 4, 5, 4, 4, 4, 4, 3, 5, }, }, - { "west0067_jumbled.mtx", + { "west0067_jumbled.mtx", { 3, 3, 3, 3, 5, 5, 5, 5, 5, 6, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 3, 3, 3, 3, 5, 5, 5, 5, 5, 6, 3, 3, 3, 3, 4, 4, 4, 4, 4, 6, 1, 5, 5, 5, 5, @@ -269,7 +273,7 @@ void test_Cached_Degree (void) if (trial == 2) { - // use G->AT to compute G->in_degree + // use G->AT to compute G->in_degree OK (LAGraph_DeleteCached (G, msg)) ; OK (LAGraph_Cached_AT (G, msg)) ; } @@ -333,7 +337,7 @@ void test_Cached_Degree_brutal (void) if (trial == 2) { - // use G->AT to compute G->in_degree + // use G->AT to compute G->in_degree OK (LAGraph_DeleteCached (G, msg)) ; OK (LAGraph_Cached_AT (G, msg)) ; } @@ -363,4 +367,3 @@ TEST_LIST = #endif { NULL, NULL } } ; - diff --git a/src/test/test_Cached_NDiag.c b/src/test/test_Cached_NDiag.c index a71d96f8db..81544e51a3 100644 --- a/src/test/test_Cached_NDiag.c +++ b/src/test/test_Cached_NDiag.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_Cached_NSelfEdges.c: test LAGraph_Cached_NSelfEdges //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -35,7 +39,7 @@ typedef struct } matrix_info ; -const matrix_info files [ ] = +const matrix_info files [ ] = { 0, "A.mtx", 14, "LFAT5.mtx", @@ -217,4 +221,3 @@ TEST_LIST = #endif { NULL, NULL } } ; - diff --git a/src/test/test_Cached_SymmetricStructure.c b/src/test/test_Cached_SymmetricStructure.c index d819168ea7..d609de8e09 100644 --- a/src/test/test_Cached_SymmetricStructure.c +++ b/src/test/test_Cached_SymmetricStructure.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_Cached_Symmetric_Structure.c //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -170,7 +174,7 @@ void test_Cached_Symmetric_Structure (void) // delete all cached properties OK (LAGraph_DeleteCached (G, msg)) ; - // change the graph to directed, if matrix is symmetric + // change the graph to directed, if matrix is symmetric if (sym_values) { G->kind = LAGraph_ADJACENCY_UNDIRECTED ; @@ -254,7 +258,7 @@ void test_Cached_Symmetric_Structure_brutal (void) // delete all cached properties OK (LAGraph_DeleteCached (G, msg)) ; - // change the graph to directed, if matrix is symmetric + // change the graph to directed, if matrix is symmetric if (sym_values) { G->kind = LAGraph_ADJACENCY_UNDIRECTED ; @@ -283,4 +287,3 @@ TEST_LIST = #endif { NULL, NULL } } ; - diff --git a/src/test/test_CheckGraph.c b/src/test/test_CheckGraph.c index d119c6b8df..74400b47bb 100644 --- a/src/test/test_CheckGraph.c +++ b/src/test/test_CheckGraph.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_CheckGraph.c: test LAGraph_CheckGraph //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -295,4 +299,3 @@ TEST_LIST = #endif { NULL, NULL } } ; - diff --git a/src/test/test_ConnectedComponents.c b/src/test/test_ConnectedComponents.c index 0d066ca826..9ae9fe9587 100644 --- a/src/test/test_ConnectedComponents.c +++ b/src/test/test_ConnectedComponents.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_ConnectedComponents.c: test cases for CC //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/test/test_DeleteCached.c b/src/test/test_DeleteCached.c index 08295a8c1e..82b872c7be 100644 --- a/src/test/test_DeleteCached.c +++ b/src/test/test_DeleteCached.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_DeleteCached.c: test LAGraph_DeleteCached //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -174,7 +178,7 @@ void test_del_brutal (void) TEST_CHECK (G->out_degree == NULL) ; TEST_CHECK (G->in_degree == NULL) ; } - + LG_BRUTAL (LAGraph_Delete (&G, msg)) ; LG_BRUTAL (LAGraph_DeleteCached (NULL, msg)) ; } @@ -193,4 +197,3 @@ TEST_LIST = { "test_DeleteCached_brutal", test_del_brutal }, { NULL, NULL } } ; - diff --git a/src/test/test_DisplayGraph.c b/src/test/test_DisplayGraph.c index 78a07c6792..8cb707ddeb 100644 --- a/src/test/test_DisplayGraph.c +++ b/src/test/test_DisplayGraph.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_Graph_Print.c: test LAGraph_Graph_Print //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -294,4 +298,3 @@ TEST_LIST = { "Graph_Print_failures", test_Graph_Print_failures }, { NULL, NULL } } ; - diff --git a/src/test/test_Init.c b/src/test/test_Init.c index add50e8809..57974df0fd 100644 --- a/src/test/test_Init.c +++ b/src/test/test_Init.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_Init.c: test LAGraph_Init and LAGraph_Finalize //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -90,4 +94,3 @@ TEST_LIST = // no brutal test: see test_Xinit { NULL, NULL } } ; - diff --git a/src/test/test_Init_errors.c b/src/test/test_Init_errors.c index ab8b4072b1..56053b0091 100644 --- a/src/test/test_Init_errors.c +++ b/src/test/test_Init_errors.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_Init_errors.c: test LAGraph_Init and LAGraph_Finalize //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -56,4 +60,3 @@ TEST_LIST = // no brutal test: see test_Xinit { NULL, NULL } } ; - diff --git a/src/test/test_IsEqual.c b/src/test/test_IsEqual.c index 4d8fcf3ed8..d4ab4c844c 100644 --- a/src/test/test_IsEqual.c +++ b/src/test/test_IsEqual.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_IsEqual.c: test LAGraph_*_IsEqual //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -40,7 +44,7 @@ typedef struct } matrix_info ; -const matrix_info files [ ] = +const matrix_info files [ ] = { // iseq matrix1 matrix2 { 0, 0, "A.mtx" , "cover.mtx" }, @@ -444,4 +448,3 @@ TEST_LIST = { "IsEqual_brutal", test_IsEqual_brutal }, { NULL, NULL } } ; - diff --git a/src/test/test_KindName.c b/src/test/test_KindName.c index 5229d3c132..7fdd9ae8ff 100644 --- a/src/test/test_KindName.c +++ b/src/test/test_KindName.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_KindName.c: test LG_KindName //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -90,4 +94,3 @@ TEST_LIST = { "KindName_brutal", test_KindName_brutal }, { NULL, NULL } } ; - diff --git a/src/test/test_MMRead.c b/src/test/test_MMRead.c index ef05461f0e..04712b7bc3 100644 --- a/src/test/test_MMRead.c +++ b/src/test/test_MMRead.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_MMRead.c: test LAGraph_MMRead and LAGraph_MMWrite //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -44,7 +48,7 @@ typedef struct } matrix_info ; -const matrix_info files [ ] = +const matrix_info files [ ] = { // nrows ncols nvals type name { 7, 7, 30, "bool", "A.mtx" }, @@ -708,4 +712,3 @@ TEST_LIST = #endif { NULL, NULL } } ; - diff --git a/src/test/test_Malloc.c b/src/test/test_Malloc.c index ffaa70e5ae..a28f73a3a4 100644 --- a/src/test/test_Malloc.c +++ b/src/test/test_Malloc.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_Malloc.c: test LAGraph_Malloc and related methods //----------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -23,7 +27,7 @@ void test_malloc (void) char msg [LAGRAPH_MSG_LEN] ; OK (LAGraph_Init (msg)) ; - char *p ; + char *p ; OK (LAGraph_Malloc ((void **) &p, 42, sizeof (char), msg)) ; for (int k = 0 ; k < 42 ; k++) { diff --git a/src/test/test_Matrix_Structure.c b/src/test/test_Matrix_Structure.c index cfdc98cb62..bb8bc2f4df 100644 --- a/src/test/test_Matrix_Structure.c +++ b/src/test/test_Matrix_Structure.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_Matrix_Structure.c: test LAGraph_Matrix_Structure //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -180,4 +184,3 @@ TEST_LIST = #endif { NULL, NULL } } ; - diff --git a/src/test/test_Multiply_size_t.c b/src/test/test_Multiply_size_t.c index 453a547584..f2b741baaa 100644 --- a/src/test/test_Multiply_size_t.c +++ b/src/test/test_Multiply_size_t.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_Multiply_size_t.c: test LG_Multiply_size_t //----------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/test/test_New.c b/src/test/test_New.c index 4cd66bedea..49b2fc358d 100644 --- a/src/test/test_New.c +++ b/src/test/test_New.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_New.c: test LAGraph_New and LAGraph_Delete //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -181,4 +185,3 @@ TEST_LIST = { "New_brutal", test_New_brutal }, { NULL, NULL } } ; - diff --git a/src/test/test_NumThreads.c b/src/test/test_NumThreads.c index cc3761c52f..3373876665 100644 --- a/src/test/test_NumThreads.c +++ b/src/test/test_NumThreads.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_NumThreads.c: test LAGraph_(Get,Set)NumThreads //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -71,4 +75,3 @@ TEST_LIST = // no brutal test needed { NULL, NULL } } ; - diff --git a/src/test/test_PageRank.c b/src/test/test_PageRank.c index 971a7120b1..b0b8eb9b83 100644 --- a/src/test/test_PageRank.c +++ b/src/test/test_PageRank.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_PageRank.c: test cases for pagerank // ----------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -333,4 +337,3 @@ TEST_LIST = { {"test_ranker", test_ranker}, {NULL, NULL} }; - diff --git a/src/test/test_SampleDegree.c b/src/test/test_SampleDegree.c index 8425acb264..d84461dfea 100644 --- a/src/test/test_SampleDegree.c +++ b/src/test/test_SampleDegree.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_SampleDegree.c: test LAGr_SampleDegree //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -252,4 +256,3 @@ TEST_LIST = #endif { NULL, NULL } } ; - diff --git a/src/test/test_SingleSourceShortestPath.c b/src/test/test_SingleSourceShortestPath.c index 9d70f6c688..394241cdfc 100644 --- a/src/test/test_SingleSourceShortestPath.c +++ b/src/test/test_SingleSourceShortestPath.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_SingleSourceShortestPath.c: test cases for SSSP // ---------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -450,4 +454,3 @@ TEST_LIST = { #endif {NULL, NULL} }; - diff --git a/src/test/test_Sort.c b/src/test/test_Sort.c index 29c3ed8dbf..e53a077fc2 100644 --- a/src/test/test_Sort.c +++ b/src/test/test_Sort.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_Sort.c: test LG_msort* methods //----------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/test/test_SortByDegree.c b/src/test/test_SortByDegree.c index 053c84d1c6..15bd476335 100644 --- a/src/test/test_SortByDegree.c +++ b/src/test/test_SortByDegree.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_SortByDegree test LAGr_SortByDegree //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -53,31 +57,31 @@ void teardown (void) const char *files [ ] = { - "A.mtx", - "LFAT5.mtx", - "cover.mtx", - "full.mtx", - "full_symmetric.mtx", - "karate.mtx", - "ldbc-cdlp-directed-example.mtx", - "ldbc-cdlp-undirected-example.mtx", - "ldbc-directed-example-bool.mtx", - "ldbc-directed-example-unweighted.mtx", - "ldbc-directed-example.mtx", - "ldbc-undirected-example-bool.mtx", - "ldbc-undirected-example-unweighted.mtx", - "ldbc-undirected-example.mtx", - "ldbc-wcc-example.mtx", - "matrix_int16.mtx", - "msf1.mtx", - "msf2.mtx", - "msf3.mtx", - "structure.mtx", - "sample.mtx", - "sample2.mtx", - "skew_fp32.mtx", - "tree-example.mtx", - "west0067.mtx", + "A.mtx", + "LFAT5.mtx", + "cover.mtx", + "full.mtx", + "full_symmetric.mtx", + "karate.mtx", + "ldbc-cdlp-directed-example.mtx", + "ldbc-cdlp-undirected-example.mtx", + "ldbc-directed-example-bool.mtx", + "ldbc-directed-example-unweighted.mtx", + "ldbc-directed-example.mtx", + "ldbc-undirected-example-bool.mtx", + "ldbc-undirected-example-unweighted.mtx", + "ldbc-undirected-example.mtx", + "ldbc-wcc-example.mtx", + "matrix_int16.mtx", + "msf1.mtx", + "msf2.mtx", + "msf3.mtx", + "structure.mtx", + "sample.mtx", + "sample2.mtx", + "skew_fp32.mtx", + "tree-example.mtx", + "west0067.mtx", "", } ; @@ -428,4 +432,3 @@ TEST_LIST = #endif { NULL, NULL } } ; - diff --git a/src/test/test_TriangleCount.c b/src/test/test_TriangleCount.c index 7a7cf5c4d7..8f5b6d1e03 100644 --- a/src/test/test_TriangleCount.c +++ b/src/test/test_TriangleCount.c @@ -3,10 +3,14 @@ // counting algorithms // ---------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Scott McMillan, SEI, and Timothy A. Davis, Texas A&M // University @@ -377,7 +381,7 @@ void test_TriangleCount_autosort (void) OK (LAGraph_Cached_OutDegree (G, msg)) ; - // try each method; with autosort + // try each method; with autosort GrB_Index nt1 = 0 ; for (int method = 0 ; method <= 6 ; method++) { @@ -482,4 +486,3 @@ TEST_LIST = { {"TriangleCount_brutal" , test_TriangleCount_brutal}, {NULL, NULL} }; - diff --git a/src/test/test_Type.c b/src/test/test_Type.c index af1285d67d..116fe594a6 100644 --- a/src/test/test_Type.c +++ b/src/test/test_Type.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_Type.c: test LAGraph_*Type* methods //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -187,4 +191,3 @@ TEST_LIST = // no brutal test needed { NULL, NULL } } ; - diff --git a/src/test/test_Vector_Print.c b/src/test/test_Vector_Print.c index 730e091a73..8a67f503b2 100644 --- a/src/test/test_Vector_Print.c +++ b/src/test/test_Vector_Print.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_Vector_Print.c: test LAGraph_Vector_Print //----------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -212,4 +216,3 @@ TEST_LIST = { #endif {NULL, NULL} }; - diff --git a/src/test/test_Vector_Structure.c b/src/test/test_Vector_Structure.c index 2457478ca7..4791a797e8 100644 --- a/src/test/test_Vector_Structure.c +++ b/src/test/test_Vector_Structure.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_Vector_Structure.c: test LAGraph_Vector_Structure //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -181,4 +185,3 @@ TEST_LIST = #endif { NULL, NULL } } ; - diff --git a/src/test/test_WallClockTime.c b/src/test/test_WallClockTime.c index 2e7c7b8e6b..363aef8c5f 100644 --- a/src/test/test_WallClockTime.c +++ b/src/test/test_WallClockTime.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_WallClockTime.c: test LAGraph_WallClockTime //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -62,4 +66,3 @@ TEST_LIST = // no brutal test needed { NULL, NULL } } ; - diff --git a/src/test/test_Xinit.c b/src/test/test_Xinit.c index 81f9448f3e..064e8ab991 100644 --- a/src/test/test_Xinit.c +++ b/src/test/test_Xinit.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_Xinit.c: test LAGr_Init and LAGraph_Global //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -156,4 +160,3 @@ TEST_LIST = #endif { NULL, NULL } } ; - diff --git a/src/test/test_acutest.c b/src/test/test_acutest.c index 05b02d919d..d64278f1c6 100644 --- a/src/test/test_acutest.c +++ b/src/test/test_acutest.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_acutest.c: simple demo of how to use acutest //----------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 Scott McMillan, SEI Carnegie Mellon University diff --git a/src/test/test_export.c b/src/test/test_export.c index 62abba6d15..4190c1c7ff 100644 --- a/src/test/test_export.c +++ b/src/test/test_export.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_export.c: test LG_check_export //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -211,4 +215,3 @@ TEST_LIST = { {"test_export_brutal", test_export_brutal }, {NULL, NULL} }; - diff --git a/src/test/test_fopen.c b/src/test/test_fopen.c index 9b5ec74e4d..4b74f4acb0 100644 --- a/src/test/test_fopen.c +++ b/src/test/test_fopen.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_fopen.c: test fopen //----------------------------------------------------------------------------- -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/test/test_minmax.c b/src/test/test_minmax.c index f471e41007..540d573b9e 100644 --- a/src/test/test_minmax.c +++ b/src/test/test_minmax.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_minmax.c: test LAGraph_Cached_EMin/EMax //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -40,7 +44,7 @@ typedef struct } matrix_info ; -const matrix_info files [ ] = +const matrix_info files [ ] = { // amin amax name { 1, 1, "A2.mtx" } , @@ -117,7 +121,7 @@ typedef struct } matrix_info_int64 ; -const matrix_info_int64 files_int64 [ ] = +const matrix_info_int64 files_int64 [ ] = { { -9223372036854775800L, 9223372036854775807L, "matrix_int64.mtx" } , { -9223372036854775807L, 9223372036854775807L, "skew_int64.mtx" } , @@ -132,7 +136,7 @@ typedef struct } matrix_info_uint64 ; -const matrix_info_uint64 files_uint64 [ ] = +const matrix_info_uint64 files_uint64 [ ] = { { 0, 18446744073709551615UL, "matrix_uint64.mtx" } , { 0, 0, "" } @@ -430,4 +434,3 @@ TEST_LIST = { "test_minmax_failures", test_minmax_failures }, { NULL, NULL } } ; - diff --git a/src/test/test_vector.c b/src/test/test_vector.c index f9e0b01bb9..66493e08ac 100644 --- a/src/test/test_vector.c +++ b/src/test/test_vector.c @@ -2,10 +2,14 @@ // LAGraph/src/test/test_vector.c: test LG_check_vector //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -103,4 +107,3 @@ TEST_LIST = { "vector_brutal", test_vector_brutal }, { NULL, NULL } } ; - diff --git a/src/utility/LAGr_Init.c b/src/utility/LAGr_Init.c index eb9128daa7..29146ac94b 100644 --- a/src/utility/LAGr_Init.c +++ b/src/utility/LAGr_Init.c @@ -2,10 +2,14 @@ // LAGr_Init: start GraphBLAS and LAGraph, and set malloc/etc functions //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -230,7 +234,7 @@ int LAGr_Init // the matrices A and B. C(i,j) is the size of the intersection of the // structures of A(i,:) and B(:,j). In MATLAB, for the FP64 data type, // this can be written as: - // + // // C = spones (A) * spones (B) GRB_TRY (GrB_Semiring_new (&LAGraph_plus_one_int8, @@ -295,4 +299,3 @@ int LAGr_Init return (GrB_SUCCESS) ; } - diff --git a/src/utility/LAGr_SampleDegree.c b/src/utility/LAGr_SampleDegree.c index b6b2099442..347eb8fd4d 100644 --- a/src/utility/LAGr_SampleDegree.c +++ b/src/utility/LAGr_SampleDegree.c @@ -2,10 +2,14 @@ // LAGr_SampleDegree: sample the degree median and mean //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LAGr_SortByDegree.c b/src/utility/LAGr_SortByDegree.c index 77b338b30d..c2ed0aefc9 100644 --- a/src/utility/LAGr_SortByDegree.c +++ b/src/utility/LAGr_SortByDegree.c @@ -2,10 +2,14 @@ // LAGr_SortByDegree: sort a graph by its row or column degree //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LAGraph_Cached_AT.c b/src/utility/LAGraph_Cached_AT.c index 6fa52033ab..71fcd587a7 100644 --- a/src/utility/LAGraph_Cached_AT.c +++ b/src/utility/LAGraph_Cached_AT.c @@ -2,10 +2,14 @@ // LAGraph_Cached_AT: construct G->AT for a graph //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LAGraph_Cached_EMax.c b/src/utility/LAGraph_Cached_EMax.c index 9e584fc55c..6bbc00f208 100644 --- a/src/utility/LAGraph_Cached_EMax.c +++ b/src/utility/LAGraph_Cached_EMax.c @@ -2,10 +2,14 @@ // LAGraph_Cached_EMax: determine G->emax //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -74,4 +78,3 @@ int LAGraph_Cached_EMax G->emax_state = LAGraph_VALUE ; return (GrB_SUCCESS) ; } - diff --git a/src/utility/LAGraph_Cached_EMin.c b/src/utility/LAGraph_Cached_EMin.c index 823efae0a7..de100314fc 100644 --- a/src/utility/LAGraph_Cached_EMin.c +++ b/src/utility/LAGraph_Cached_EMin.c @@ -2,10 +2,14 @@ // LAGraph_Cached_EMin: determine G->emin //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -74,4 +78,3 @@ int LAGraph_Cached_EMin G->emin_state = LAGraph_VALUE ; return (GrB_SUCCESS) ; } - diff --git a/src/utility/LAGraph_Cached_InDegree.c b/src/utility/LAGraph_Cached_InDegree.c index 53fba43e5f..69d81bc695 100644 --- a/src/utility/LAGraph_Cached_InDegree.c +++ b/src/utility/LAGraph_Cached_InDegree.c @@ -2,10 +2,14 @@ // LAGraph_Cached_InDegree: determine G->in_degree //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -83,7 +87,7 @@ int LAGraph_Cached_InDegree if (AT != NULL) { // G->in_degree = row degree of AT; this will be faster assuming - // AT is held in a row-oriented format. + // AT is held in a row-oriented format. GRB_TRY (GrB_mxv (in_degree, NULL, NULL, LAGraph_plus_one_int64, AT, x, NULL)) ; } diff --git a/src/utility/LAGraph_Cached_IsSymmetricStructure.c b/src/utility/LAGraph_Cached_IsSymmetricStructure.c index da7368027f..3314b345b7 100644 --- a/src/utility/LAGraph_Cached_IsSymmetricStructure.c +++ b/src/utility/LAGraph_Cached_IsSymmetricStructure.c @@ -2,10 +2,14 @@ // LAGraph_Cached_IsSymmetricStructure: determine G->is_symmetric_structure //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LAGraph_Cached_NSelfEdges.c b/src/utility/LAGraph_Cached_NSelfEdges.c index 64f5d82a70..16d83c192f 100644 --- a/src/utility/LAGraph_Cached_NSelfEdges.c +++ b/src/utility/LAGraph_Cached_NSelfEdges.c @@ -2,10 +2,14 @@ // LAGraph_Cached_NSelfEdges: count the # of diagonal entries of a graph //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -39,4 +43,3 @@ int LAGraph_Cached_NSelfEdges return (LG_nself_edges (&G->nself_edges, G->A, msg)) ; } - diff --git a/src/utility/LAGraph_Cached_OutDegree.c b/src/utility/LAGraph_Cached_OutDegree.c index 1a76320108..3437a98da0 100644 --- a/src/utility/LAGraph_Cached_OutDegree.c +++ b/src/utility/LAGraph_Cached_OutDegree.c @@ -2,10 +2,14 @@ // LAGraph_Cached_OutDegree: determine G->out_degree //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LAGraph_Calloc.c b/src/utility/LAGraph_Calloc.c index d9c6424813..17690d970d 100644 --- a/src/utility/LAGraph_Calloc.c +++ b/src/utility/LAGraph_Calloc.c @@ -2,10 +2,14 @@ // LAGraph_Calloc: wrapper for calloc //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LAGraph_CheckGraph.c b/src/utility/LAGraph_CheckGraph.c index e52a63cafb..63bdaaca2e 100644 --- a/src/utility/LAGraph_CheckGraph.c +++ b/src/utility/LAGraph_CheckGraph.c @@ -2,10 +2,14 @@ // LAGraph_CheckGraph: check if a graph is valid //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LAGraph_Delete.c b/src/utility/LAGraph_Delete.c index 46dd757c94..732b98bad0 100644 --- a/src/utility/LAGraph_Delete.c +++ b/src/utility/LAGraph_Delete.c @@ -2,10 +2,14 @@ // LAGraph_Delete: deletes a graph and all its contents //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LAGraph_DeleteCached.c b/src/utility/LAGraph_DeleteCached.c index be7ad62018..1721050b7d 100644 --- a/src/utility/LAGraph_DeleteCached.c +++ b/src/utility/LAGraph_DeleteCached.c @@ -2,10 +2,14 @@ // LAGraph_DeleteCached: deletes the cached properties of a graph //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LAGraph_DeleteSelfEdges.c b/src/utility/LAGraph_DeleteSelfEdges.c index d8de4ade18..f80919081a 100644 --- a/src/utility/LAGraph_DeleteSelfEdges.c +++ b/src/utility/LAGraph_DeleteSelfEdges.c @@ -2,10 +2,14 @@ // LAGraph_DeleteSelfEdges: removes the diagonal entries from G->A //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -53,4 +57,3 @@ int LAGraph_DeleteSelfEdges G->nself_edges = 0 ; return (GrB_SUCCESS) ; } - diff --git a/src/utility/LAGraph_Finalize.c b/src/utility/LAGraph_Finalize.c index c4f265ec87..5dc6c7e5f7 100644 --- a/src/utility/LAGraph_Finalize.c +++ b/src/utility/LAGraph_Finalize.c @@ -2,10 +2,14 @@ // LAGraph_Finalize: finish LAGraph //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -78,4 +82,3 @@ int LAGraph_Finalize (char *msg) GRB_TRY (GrB_finalize ( )) ; return (GrB_SUCCESS) ; } - diff --git a/src/utility/LAGraph_Free.c b/src/utility/LAGraph_Free.c index 3c421a938c..abbd4e6457 100644 --- a/src/utility/LAGraph_Free.c +++ b/src/utility/LAGraph_Free.c @@ -2,10 +2,14 @@ // LAGraph_Free: wrapper for free //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LAGraph_GetNumThreads.c b/src/utility/LAGraph_GetNumThreads.c index f614368dcc..b06bb75d02 100644 --- a/src/utility/LAGraph_GetNumThreads.c +++ b/src/utility/LAGraph_GetNumThreads.c @@ -2,10 +2,14 @@ // LAGraph_GetNumThreads: get the # of threads to use //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -40,4 +44,3 @@ int LAGraph_GetNumThreads (*nthreads_inner) = LG_nthreads_inner ; return (GrB_SUCCESS) ; } - diff --git a/src/utility/LAGraph_Global.c b/src/utility/LAGraph_Global.c index c24b9bde7b..a74320f2d2 100644 --- a/src/utility/LAGraph_Global.c +++ b/src/utility/LAGraph_Global.c @@ -2,10 +2,14 @@ // LAGraph_Global: global variables for LAGraph //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -38,4 +42,3 @@ int LG_nthreads_inner ; // # of threads to use at the lower level of a nested // parallel region, or to use inside GraphBLAS. // Default: the value obtained by omp_get_max_threads // if OpenMP is in use, or 1 otherwise. - diff --git a/src/utility/LAGraph_Graph_Print.c b/src/utility/LAGraph_Graph_Print.c index e2ace3d8e0..d241ea9024 100644 --- a/src/utility/LAGraph_Graph_Print.c +++ b/src/utility/LAGraph_Graph_Print.c @@ -2,10 +2,14 @@ // LAGraph_Graph_Print: print the contents of a graph //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LAGraph_Init.c b/src/utility/LAGraph_Init.c index e534b10568..c806e94379 100644 --- a/src/utility/LAGraph_Init.c +++ b/src/utility/LAGraph_Init.c @@ -2,10 +2,14 @@ // LAGraph_Init: start GraphBLAS and LAGraph //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LAGraph_MMRead.c b/src/utility/LAGraph_MMRead.c index 3cef13c86a..f31151e18b 100644 --- a/src/utility/LAGraph_MMRead.c +++ b/src/utility/LAGraph_MMRead.c @@ -2,10 +2,14 @@ // LAGraph_MMRead: read a matrix from a Matrix Market file //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -1045,4 +1049,3 @@ int LAGraph_MMRead LG_FREE_WORK ; return (GrB_SUCCESS) ; } - diff --git a/src/utility/LAGraph_MMWrite.c b/src/utility/LAGraph_MMWrite.c index 3994fbac9c..d4f632284a 100644 --- a/src/utility/LAGraph_MMWrite.c +++ b/src/utility/LAGraph_MMWrite.c @@ -2,10 +2,14 @@ // LAGraph_MMWrite: write a matrix to a Matrix Market file //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -556,4 +560,3 @@ int LAGraph_MMWrite LG_FREE_ALL ; return (GrB_SUCCESS) ; } - diff --git a/src/utility/LAGraph_Malloc.c b/src/utility/LAGraph_Malloc.c index 9b1e7d6d55..98461ad1a0 100644 --- a/src/utility/LAGraph_Malloc.c +++ b/src/utility/LAGraph_Malloc.c @@ -2,10 +2,14 @@ // LAGraph_Malloc: wrapper for malloc //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LAGraph_Matrix_IsEqual.c b/src/utility/LAGraph_Matrix_IsEqual.c index e8691c0dee..fdb7095050 100644 --- a/src/utility/LAGraph_Matrix_IsEqual.c +++ b/src/utility/LAGraph_Matrix_IsEqual.c @@ -2,10 +2,14 @@ // LAGraph_Matrix_IsEqual: check two matrices for exact equality //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -155,4 +159,3 @@ int LAGraph_Matrix_IsEqual LG_FREE_WORK ; return (GrB_SUCCESS) ; } - diff --git a/src/utility/LAGraph_Matrix_IsEqualOp.c b/src/utility/LAGraph_Matrix_IsEqualOp.c index 854bbf949a..b679714680 100644 --- a/src/utility/LAGraph_Matrix_IsEqualOp.c +++ b/src/utility/LAGraph_Matrix_IsEqualOp.c @@ -2,10 +2,14 @@ // LAGraph_Matrix_IsEqualOp: compare two matrices with a given op //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -117,4 +121,3 @@ int LAGraph_Matrix_IsEqualOp LG_FREE_WORK ; return (GrB_SUCCESS) ; } - diff --git a/src/utility/LAGraph_Matrix_Print.c b/src/utility/LAGraph_Matrix_Print.c index a27406215b..7839523ec3 100644 --- a/src/utility/LAGraph_Matrix_Print.c +++ b/src/utility/LAGraph_Matrix_Print.c @@ -2,10 +2,14 @@ // LAGraph_Matrix_Print: pretty-print a matrix //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -144,43 +148,43 @@ int LAGraph_Matrix_Print { return (LG_Matrix_Print_BOOL (A, pr, f, msg)) ; } - else if (type == GrB_INT8) + else if (type == GrB_INT8) { return (LG_Matrix_Print_INT8 (A, pr, f, msg)) ; } - else if (type == GrB_INT16) + else if (type == GrB_INT16) { return (LG_Matrix_Print_INT16 (A, pr, f, msg)) ; } - else if (type == GrB_INT32) + else if (type == GrB_INT32) { return (LG_Matrix_Print_INT32 (A, pr, f, msg)) ; } - else if (type == GrB_INT64) + else if (type == GrB_INT64) { return (LG_Matrix_Print_INT64 (A, pr, f, msg)) ; } - else if (type == GrB_UINT8) + else if (type == GrB_UINT8) { return (LG_Matrix_Print_UINT8 (A, pr, f, msg)) ; } - else if (type == GrB_UINT16) + else if (type == GrB_UINT16) { return (LG_Matrix_Print_UINT16 (A, pr, f, msg)) ; } - else if (type == GrB_UINT32) + else if (type == GrB_UINT32) { return (LG_Matrix_Print_UINT32 (A, pr, f, msg)) ; } - else if (type == GrB_UINT64) + else if (type == GrB_UINT64) { return (LG_Matrix_Print_UINT64 (A, pr, f, msg)) ; } - else if (type == GrB_FP32) + else if (type == GrB_FP32) { return (LG_Matrix_Print_FP32 (A, pr, f, msg)) ; } - else if (type == GrB_FP64) + else if (type == GrB_FP64) { return (LG_Matrix_Print_FP64 (A, pr, f, msg)) ; } @@ -201,4 +205,3 @@ int LAGraph_Matrix_Print return (GrB_SUCCESS) ; } } - diff --git a/src/utility/LAGraph_Matrix_Structure.c b/src/utility/LAGraph_Matrix_Structure.c index c5751120f1..65870ecdcf 100644 --- a/src/utility/LAGraph_Matrix_Structure.c +++ b/src/utility/LAGraph_Matrix_Structure.c @@ -2,10 +2,14 @@ // LAGraph_Matrix_Structure: return the structure of a matrix //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 and Scott Kolodziej, Texas A&M University @@ -57,4 +61,3 @@ int LAGraph_Matrix_Structure return (GrB_SUCCESS) ; } - diff --git a/src/utility/LAGraph_NameOfType.c b/src/utility/LAGraph_NameOfType.c index 5b21d906df..512484b3ea 100644 --- a/src/utility/LAGraph_NameOfType.c +++ b/src/utility/LAGraph_NameOfType.c @@ -2,10 +2,14 @@ // LAGraph_NameOfType: return the C name of a GraphBLAS GrB_Type //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -69,4 +73,3 @@ int LAGraph_NameOfType #endif } - diff --git a/src/utility/LAGraph_New.c b/src/utility/LAGraph_New.c index c283cfde8a..55d51a3b96 100644 --- a/src/utility/LAGraph_New.c +++ b/src/utility/LAGraph_New.c @@ -2,10 +2,14 @@ // LAGraph_New: create a new graph //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LAGraph_Realloc.c b/src/utility/LAGraph_Realloc.c index 7c87b37885..4e1c4387b2 100644 --- a/src/utility/LAGraph_Realloc.c +++ b/src/utility/LAGraph_Realloc.c @@ -2,10 +2,14 @@ // LAGraph_Realloc: wrapper for realloc //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LAGraph_SetNumThreads.c b/src/utility/LAGraph_SetNumThreads.c index 8a9f9f0fa3..2246140089 100644 --- a/src/utility/LAGraph_SetNumThreads.c +++ b/src/utility/LAGraph_SetNumThreads.c @@ -2,10 +2,14 @@ // LAGraph_SetNumThreads: set the # of threads to use //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -49,4 +53,3 @@ int LAGraph_SetNumThreads return (GrB_SUCCESS) ; } - diff --git a/src/utility/LAGraph_SizeOfType.c b/src/utility/LAGraph_SizeOfType.c index 08fde81bdd..31c886a286 100644 --- a/src/utility/LAGraph_SizeOfType.c +++ b/src/utility/LAGraph_SizeOfType.c @@ -2,10 +2,14 @@ // LAGraph_SizeOfType: return the sizeof(...) of a GraphBLAS GrB_Type //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -68,4 +72,3 @@ int LAGraph_SizeOfType #endif } - diff --git a/src/utility/LAGraph_TypeFromName.c b/src/utility/LAGraph_TypeFromName.c index 8651c74d69..5b238e2dfe 100644 --- a/src/utility/LAGraph_TypeFromName.c +++ b/src/utility/LAGraph_TypeFromName.c @@ -2,17 +2,21 @@ // LAGraph_TypeFromName: return the GrB_Type corresponding to its given name //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 //------------------------------------------------------------------------------ // This method works for any GraphBLAS library. On input, name is a char array -// of length at least LAGRAPH_MAX_NAME_LEN. +// of length at least LAGRAPH_MAX_NAME_LEN. // Only built-in types are supported. User-defined types are not supported. @@ -72,4 +76,3 @@ int LAGraph_TypeFromName #endif } - diff --git a/src/utility/LAGraph_TypeName.c b/src/utility/LAGraph_TypeName.c index 1c3e8c24e1..151b9cba6b 100644 --- a/src/utility/LAGraph_TypeName.c +++ b/src/utility/LAGraph_TypeName.c @@ -2,10 +2,14 @@ // LAGraph_*TypeName: return the name of type of a matrix, vector, or scalar //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -150,4 +154,3 @@ int LAGraph_Scalar_TypeName return (GrB_NOT_IMPLEMENTED) ; #endif } - diff --git a/src/utility/LAGraph_Vector_IsEqual.c b/src/utility/LAGraph_Vector_IsEqual.c index ad4e978467..dd7b2278f6 100644 --- a/src/utility/LAGraph_Vector_IsEqual.c +++ b/src/utility/LAGraph_Vector_IsEqual.c @@ -2,10 +2,14 @@ // LAGraph_Vector_IsEqual: check two vectors for exact equality //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -159,4 +163,3 @@ int LAGraph_Vector_IsEqual LG_FREE_WORK ; return (GrB_SUCCESS) ; } - diff --git a/src/utility/LAGraph_Vector_IsEqualOp.c b/src/utility/LAGraph_Vector_IsEqualOp.c index 2c1ebaee62..4f6e0c60a7 100644 --- a/src/utility/LAGraph_Vector_IsEqualOp.c +++ b/src/utility/LAGraph_Vector_IsEqualOp.c @@ -2,10 +2,14 @@ // LAGraph_Vector_IsEqualOp: compare two vectors with a given op //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -117,4 +121,3 @@ int LAGraph_Vector_IsEqualOp LG_FREE_WORK ; return (GrB_SUCCESS) ; } - diff --git a/src/utility/LAGraph_Vector_Print.c b/src/utility/LAGraph_Vector_Print.c index 11918e35c9..a1e858297c 100644 --- a/src/utility/LAGraph_Vector_Print.c +++ b/src/utility/LAGraph_Vector_Print.c @@ -2,10 +2,14 @@ // LAGraph_Vector_Print: pretty-print a vector //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -143,43 +147,43 @@ int LAGraph_Vector_Print { return (LG_Vector_Print_BOOL (v, pr, f, msg)) ; } - else if (type == GrB_INT8) + else if (type == GrB_INT8) { return (LG_Vector_Print_INT8 (v, pr, f, msg)) ; } - else if (type == GrB_INT16) + else if (type == GrB_INT16) { return (LG_Vector_Print_INT16 (v, pr, f, msg)) ; } - else if (type == GrB_INT32) + else if (type == GrB_INT32) { return (LG_Vector_Print_INT32 (v, pr, f, msg)) ; } - else if (type == GrB_INT64) + else if (type == GrB_INT64) { return (LG_Vector_Print_INT64 (v, pr, f, msg)) ; } - else if (type == GrB_UINT8) + else if (type == GrB_UINT8) { return (LG_Vector_Print_UINT8 (v, pr, f, msg)) ; } - else if (type == GrB_UINT16) + else if (type == GrB_UINT16) { return (LG_Vector_Print_UINT16 (v, pr, f, msg)) ; } - else if (type == GrB_UINT32) + else if (type == GrB_UINT32) { return (LG_Vector_Print_UINT32 (v, pr, f, msg)) ; } - else if (type == GrB_UINT64) + else if (type == GrB_UINT64) { return (LG_Vector_Print_UINT64 (v, pr, f, msg)) ; } - else if (type == GrB_FP32) + else if (type == GrB_FP32) { return (LG_Vector_Print_FP32 (v, pr, f, msg)) ; } - else if (type == GrB_FP64) + else if (type == GrB_FP64) { return (LG_Vector_Print_FP64 (v, pr, f, msg)) ; } @@ -200,4 +204,3 @@ int LAGraph_Vector_Print return (GrB_SUCCESS) ; } } - diff --git a/src/utility/LAGraph_Vector_Structure.c b/src/utility/LAGraph_Vector_Structure.c index 65b32e09da..c2f513cb57 100644 --- a/src/utility/LAGraph_Vector_Structure.c +++ b/src/utility/LAGraph_Vector_Structure.c @@ -2,10 +2,14 @@ // LAGraph_Vector_Structure: return the structure of a vector //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -55,4 +59,3 @@ int LAGraph_Vector_Structure return (GrB_SUCCESS) ; } - diff --git a/src/utility/LAGraph_Version.c b/src/utility/LAGraph_Version.c index 08b5061ce9..cced86ad89 100644 --- a/src/utility/LAGraph_Version.c +++ b/src/utility/LAGraph_Version.c @@ -2,10 +2,14 @@ // LAGraph_Version: return the LAGraph version number and date //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LAGraph_WallClockTime.c b/src/utility/LAGraph_WallClockTime.c index bfa4bd6d6b..a324297ac7 100644 --- a/src/utility/LAGraph_WallClockTime.c +++ b/src/utility/LAGraph_WallClockTime.c @@ -2,10 +2,14 @@ // LAGraph_WallClockTime: return the current wall clock time //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -87,4 +91,3 @@ double LAGraph_WallClockTime (void) return (t_wallclock) ; } - diff --git a/src/utility/LG_KindName.c b/src/utility/LG_KindName.c index 8f611db576..907e29a010 100644 --- a/src/utility/LG_KindName.c +++ b/src/utility/LG_KindName.c @@ -2,10 +2,14 @@ // LG_KindName: return the name of a kind //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -43,4 +47,3 @@ int LG_KindName return (GrB_SUCCESS) ; } - diff --git a/src/utility/LG_Random.c b/src/utility/LG_Random.c index 20527fb609..4d33fc4737 100644 --- a/src/utility/LG_Random.c +++ b/src/utility/LG_Random.c @@ -2,10 +2,14 @@ // LG_Random.c: simple and portable random number generator //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -31,4 +35,3 @@ GrB_Index LG_Random60 (uint64_t *seed) i = i % (LG_RANDOM60_MAX + 1) ; return (i) ; } - diff --git a/src/utility/LG_internal.h b/src/utility/LG_internal.h index 633588347c..30bc9e24ab 100644 --- a/src/utility/LG_internal.h +++ b/src/utility/LG_internal.h @@ -2,10 +2,14 @@ // LG_internal.h: include file for use within LAGraph itself //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LG_msort1.c b/src/utility/LG_msort1.c index 6ef9206d47..4d8f8ec68d 100644 --- a/src/utility/LG_msort1.c +++ b/src/utility/LG_msort1.c @@ -2,10 +2,14 @@ // LG_msort1: sort a list of integers //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LG_msort2.c b/src/utility/LG_msort2.c index 625754c846..14159c4e7d 100644 --- a/src/utility/LG_msort2.c +++ b/src/utility/LG_msort2.c @@ -2,10 +2,14 @@ // LG_msort2: sort a 2-by-n list of integers, using A[0:1][ ] as the key //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LG_msort3.c b/src/utility/LG_msort3.c index c14e9107c1..f46ed6203e 100644 --- a/src/utility/LG_msort3.c +++ b/src/utility/LG_msort3.c @@ -2,10 +2,14 @@ // LG_msort3: sort a 3-by-n list of integers, using A[0:2][ ] as the key //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LG_nself_edges.c b/src/utility/LG_nself_edges.c index 610996fd85..608f370307 100644 --- a/src/utility/LG_nself_edges.c +++ b/src/utility/LG_nself_edges.c @@ -2,10 +2,14 @@ // LG_nself_edges: count the # of diagonal entries in a matrix //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -23,7 +27,7 @@ int LG_nself_edges ( // output: - int64_t *nself_edges, // # of entries + int64_t *nself_edges, // # of entries // input: GrB_Matrix A, // matrix to count char *msg // error message @@ -85,4 +89,3 @@ int LG_nself_edges LG_FREE_ALL ; return (GrB_SUCCESS) ; } - diff --git a/src/utility/LG_qsort_1a.c b/src/utility/LG_qsort_1a.c index 91d807ceee..4237dc0fdc 100644 --- a/src/utility/LG_qsort_1a.c +++ b/src/utility/LG_qsort_1a.c @@ -2,10 +2,14 @@ // LG_qsort_1a: sort an 1-by-n list of integers //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LG_qsort_2.c b/src/utility/LG_qsort_2.c index 1b74c7c1ca..5d9d59895d 100644 --- a/src/utility/LG_qsort_2.c +++ b/src/utility/LG_qsort_2.c @@ -2,10 +2,14 @@ // LG_qsort_2: sort a 2-by-n list of integers, using A[0:1][ ] as the key //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LG_qsort_3.c b/src/utility/LG_qsort_3.c index ac5ebfec4b..99ea21f11c 100644 --- a/src/utility/LG_qsort_3.c +++ b/src/utility/LG_qsort_3.c @@ -2,10 +2,14 @@ // LG_qsort_3: sort a 3-by-n list of integers, using A[0:2][] as the key //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 diff --git a/src/utility/LG_qsort_template.h b/src/utility/LG_qsort_template.h index 387b74caba..f36faf637c 100644 --- a/src/utility/LG_qsort_template.h +++ b/src/utility/LG_qsort_template.h @@ -2,10 +2,14 @@ // LG_qsort_template: quicksort of a K-by-n array //------------------------------------------------------------------------------ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. +// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. // SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +// +// 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 @@ -75,7 +79,7 @@ static inline int64_t LG_partition // However, if the two sides have met, the partition is finished. if (left >= right) - { + { // A has been partitioned into A [0:right] and A [right+1:n-1]. // k = right+1, so A is split into A [0:k-1] and A [k:n-1]. return (right + 1) ; @@ -108,14 +112,14 @@ static void LG_quicksort // sort A [0:n-1] for (int64_t k = 1 ; k < n ; k++) { for (int64_t j = k ; j > 0 && LG_lt (A, j, A, j-1) ; j--) - { + { // swap A [j-1] and A [j] LG_swap (A, j-1, j) ; } } } else - { + { // partition A [0:n-1] into A [0:k-1] and A [k:n-1] int64_t k = LG_partition (LG_arg (A), n, seed, tx) ; @@ -124,4 +128,3 @@ static void LG_quicksort // sort A [0:n-1] LG_quicksort (LG_arg_offset (A, k), n-k, seed, tx) ; // sort A [k+1:n-1] } } - From 0fca0d98c7c9b2771bee350d642b8e6d4db8828c Mon Sep 17 00:00:00 2001 From: Scott McMillan Date: Wed, 12 Oct 2022 13:24:05 -0700 Subject: [PATCH 31/53] Fix incorrect filename in header comment. --- src/benchmark/bc_demo.c | 2 +- src/benchmark/mtx2bin_demo.c | 2 +- src/benchmark/ss2_demo.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/benchmark/bc_demo.c b/src/benchmark/bc_demo.c index a7333b4cdc..76a1b1bdc8 100644 --- a/src/benchmark/bc_demo.c +++ b/src/benchmark/bc_demo.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// LAGraph/src/demo/bc_demo: betweenness centrality for the GAP benchmark +// LAGraph/src/benchmark/bc_demo.c: Benchmark for LAGr_Betweenness //------------------------------------------------------------------------------ // LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. diff --git a/src/benchmark/mtx2bin_demo.c b/src/benchmark/mtx2bin_demo.c index 83e767194f..cd5db03795 100644 --- a/src/benchmark/mtx2bin_demo.c +++ b/src/benchmark/mtx2bin_demo.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// mtx2bin: convert Matrix Market file to SuiteSparse:GraphBLAS binary file +// LAGraph/src/benchmark/mtx2bin_demo.c: convert Matrix Market file to SS:GrB binary file //------------------------------------------------------------------------------ // LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. diff --git a/src/benchmark/ss2_demo.c b/src/benchmark/ss2_demo.c index 277d5eeefc..1a20189d06 100644 --- a/src/benchmark/ss2_demo.c +++ b/src/benchmark/ss2_demo.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// test_sssp: test for LAGraph +// LAGraph/src/benchmark/ss2_demo.c: Benchmark for LAGr_SingleSourceShortestPath //------------------------------------------------------------------------------ // LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. @@ -17,8 +17,8 @@ //------------------------------------------------------------------------------ // Usage: -// test_sssp matrix.mtx sourcenodes.mtx delta -// test_sssp matrix.grb sourcenodes.mtx delta +// ss2_demo matrix.mtx sourcenodes.mtx delta +// ss2_demo matrix.grb sourcenodes.mtx delta #include "LAGraph_demo.h" #include "LAGraphX.h" From 26b647d8b01c7615d45063dd2df10dc903d7ac89 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Fri, 28 Oct 2022 13:36:43 -0500 Subject: [PATCH 32/53] bug fix for MMWrite ("array pattern" is invalid) --- CMakeLists.txt | 4 +- ChangeLog | 5 +++ data/mangled_format.mtx | 15 ++++++++ include/LAGraph.h | 4 +- src/test/test_MMRead.c | 69 +++++++++++++++++++++++++++++++++++ src/utility/LAGraph_MMWrite.c | 1 + 6 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 data/mangled_format.mtx diff --git a/CMakeLists.txt b/CMakeLists.txt index 944f8fe687..b209cbba0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,10 +49,10 @@ cmake_policy ( SET CMP0048 NEW ) set ( CMAKE_MACOSX_RPATH TRUE ) # version of LAGraph -set ( LAGraph_DATE "Sept 20, 2022" ) +set ( LAGraph_DATE "Oct 28, 2022" ) set ( LAGraph_VERSION_MAJOR 1 ) set ( LAGraph_VERSION_MINOR 0 ) -set ( LAGraph_VERSION_SUB 0 ) +set ( LAGraph_VERSION_SUB 1 ) project ( lagraph VERSION "${LAGraph_VERSION_MAJOR}.${LAGraph_VERSION_MINOR}.${LAGraph_VERSION_SUB}" ) diff --git a/ChangeLog b/ChangeLog index 6aa29a937e..6a91e87e08 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Version 1.0.1: Oct 28, 2022 + + * bug fix: LAGraph_MMWrite incorrectly created a Matrix Market + file with "array pattern" format, which is invalid. + Version 1.0.0: Sept 20, 2022 * LAGraph v1.0 released. diff --git a/data/mangled_format.mtx b/data/mangled_format.mtx new file mode 100644 index 0000000000..f9a152bd11 --- /dev/null +++ b/data/mangled_format.mtx @@ -0,0 +1,15 @@ +%%MatrixMarket matrix array pattern symmetric +%%GraphBLAS type int64_t +% This is supposed to be full 3-by-3 matrix that is +% also "iso-valued" (all entries equal to 1). This +% gets detected as a "pattern" matrix, but "array pattern" +% is an invalid combination in the Matrix Market format. +% This matrix should be written in "coordinate pattern" +% format instead. +3 3 6 + + + + + + diff --git a/include/LAGraph.h b/include/LAGraph.h index 3307520a29..e94c39d32c 100644 --- a/include/LAGraph.h +++ b/include/LAGraph.h @@ -37,10 +37,10 @@ // See also the LAGraph_Version utility method, which returns these values. // These definitions are derived from LAGraph/CMakeLists.txt. -#define LAGRAPH_DATE "Sept 20, 2022" +#define LAGRAPH_DATE "Oct 28, 2022" #define LAGRAPH_VERSION_MAJOR 1 #define LAGRAPH_VERSION_MINOR 0 -#define LAGRAPH_VERSION_UPDATE 0 +#define LAGRAPH_VERSION_UPDATE 1 //============================================================================== // include files and helper macros diff --git a/src/test/test_MMRead.c b/src/test/test_MMRead.c index 04712b7bc3..51a8e449a7 100644 --- a/src/test/test_MMRead.c +++ b/src/test/test_MMRead.c @@ -331,6 +331,7 @@ const mangled_matrix_info mangled_files [ ] = LAGRAPH_IO_ERROR, "mangled_skew.mtx", // unsigned skew invalid GrB_NOT_IMPLEMENTED, "mangled15.mtx", // complex not supported GrB_NOT_IMPLEMENTED, "mangled16.mtx", // complex not supported + LAGRAPH_IO_ERROR, "mangled_format.mtx", // "array pattern" invalid 0, "", } ; @@ -695,6 +696,73 @@ void test_MMReadWrite_brutal (void) } #endif +//------------------------------------------------------------------------------ +// test_array_pattern +//------------------------------------------------------------------------------ + +void test_array_pattern ( ) +{ + + //-------------------------------------------------------------------------- + // start up the test + //-------------------------------------------------------------------------- + + OK (LG_brutal_setup (msg)) ; + + //-------------------------------------------------------------------------- + // construct a dense 3-by-3 matrix of all 1's (iso-valued) + //-------------------------------------------------------------------------- + + OK (GrB_Matrix_new (&A, GrB_INT64, 3, 3)) ; + OK (GrB_Matrix_assign_INT64 (A, NULL, NULL, 1, GrB_ALL, 3, GrB_ALL, 3, + NULL)) ; + OK (GrB_Matrix_wait (A, GrB_MATERIALIZE)) ; + printf ("\nA matrix:\n") ; + OK (LAGraph_Matrix_Print (A, LAGraph_COMPLETE, stdout, msg)) ; + + //-------------------------------------------------------------------------- + // write it to a temporary file + //-------------------------------------------------------------------------- + + FILE *f = tmpfile ( ) ; // fopen ("/tmp/mine.mtx", "w") ; + OK (LAGraph_MMWrite (A, f, NULL, msg)) ; + TEST_MSG ("Failed to write matrix to a temp file\n") ; +// OK (fclose (f)) ; + + //-------------------------------------------------------------------------- + // load it back in again + //-------------------------------------------------------------------------- + + rewind (f) ; +// f = fopen ("/tmp/mine.mtx", "r") ; + OK (LAGraph_MMRead (&B, f, msg)) ; + TEST_MSG ("Failed to load matrix from a temp file\n") ; + OK (fclose (f)) ; // close and delete the temporary file + + printf ("\nB matrix:\n") ; + OK (LAGraph_Matrix_Print (B, LAGraph_COMPLETE, stdout, msg)) ; + + //-------------------------------------------------------------------------- + // ensure A and B are the same + //-------------------------------------------------------------------------- + + OK (LAGraph_Matrix_TypeName (btype_name, B, msg)) ; + TEST_CHECK (MATCHNAME ("int64_t", btype_name)) ; + bool ok ; + OK (LAGraph_Matrix_IsEqual (&ok, A, B, msg)) ; + TEST_CHECK (ok) ; + TEST_MSG ("Failed test for equality, dense 3-by-3\n") ; + + //-------------------------------------------------------------------------- + // finish the test + //-------------------------------------------------------------------------- + + OK (GrB_free (&A)) ; + OK (GrB_free (&B)) ; + + OK (LG_brutal_teardown (msg)) ; +} + //----------------------------------------------------------------------------- // TEST_LIST: the list of tasks for this entire test //----------------------------------------------------------------------------- @@ -710,5 +778,6 @@ TEST_LIST = #if LAGRAPH_SUITESPARSE { "MMReadWrite_brutal", test_MMReadWrite_brutal }, #endif + { "array_pattern", test_array_pattern }, { NULL, NULL } } ; diff --git a/src/utility/LAGraph_MMWrite.c b/src/utility/LAGraph_MMWrite.c index d4f632284a..51bd5841c2 100644 --- a/src/utility/LAGraph_MMWrite.c +++ b/src/utility/LAGraph_MMWrite.c @@ -360,6 +360,7 @@ int LAGraph_MMWrite if (is_structural) { MM_type = MM_pattern ; + MM_fmt = MM_coordinate ; } } From 3f61b9ddfbdbfb52e9682aaf44af9b94890d18dc Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Fri, 28 Oct 2022 16:07:30 -0500 Subject: [PATCH 33/53] replace omp_get_num_threads with LAGraph utility --- experimental/algorithm/LAGraph_FastGraphletTransform.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/experimental/algorithm/LAGraph_FastGraphletTransform.c b/experimental/algorithm/LAGraph_FastGraphletTransform.c index c9373d985b..f7bba1a28f 100644 --- a/experimental/algorithm/LAGraph_FastGraphletTransform.c +++ b/experimental/algorithm/LAGraph_FastGraphletTransform.c @@ -325,7 +325,11 @@ int LAGraph_FastGraphletTransform } \ } - GxB_set (GxB_NTHREADS, 1) ; +// GxB_set (GxB_NTHREADS, 1) ; + int save_nthreads_outer, save_nthreads_inner ; + LG_TRY (LAGraph_GetNumThreads (&save_nthreads_outer, &save_nthreads_inner, msg)) ; + LG_TRY (LAGraph_SetNumThreads (1, 1, msg)) ; + #pragma omp parallel for num_threads(omp_get_max_threads()) schedule(dynamic,1) for (int i = 0; i < tile_cnt; ++i) { GrB_Matrix A_i = NULL, e = NULL ; @@ -347,7 +351,8 @@ int LAGraph_FastGraphletTransform GrB_free (&e) ; } - GxB_set (GxB_NTHREADS, omp_get_max_threads()) ; +// GxB_set (GxB_NTHREADS, omp_get_max_threads()) ; + LG_TRY (LAGraph_SetNumThreads (save_nthreads_outer, save_nthreads_inner, msg)) ; GRB_TRY (GxB_Matrix_concat (C_4, C_Tiles, tile_cnt, 1, NULL)) ; From 590bbb8428b24aaff2acd7b5107bf8a754668a73 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Sat, 29 Oct 2022 15:09:47 -0500 Subject: [PATCH 34/53] demo linking --- src/benchmark/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/benchmark/CMakeLists.txt b/src/benchmark/CMakeLists.txt index 4cd7729377..f72f137053 100644 --- a/src/benchmark/CMakeLists.txt +++ b/src/benchmark/CMakeLists.txt @@ -18,6 +18,7 @@ foreach( demosourcefile ${DEMO_SOURCES} ) string( REPLACE ".c" "" demoname ${justname} ) # message("Adding: ${demoname}") add_executable( ${demoname} ${demosourcefile} ) + message ( STATUS "linking demo with: ${GRAPHBLAS_LIBRARIES}" ) target_link_libraries( ${demoname} lagraph lagraphx lagraphtest ${GRAPHBLAS_LIBRARIES} ) target_link_directories( ${demoname} BEFORE PUBLIC ${CMAKE_SOURCE_DIR}/build ) endforeach( demosourcefile ${DEMO_SOURCES} ) From 70afc517f4413c6512a99f8532b8440d9b16377a Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Sat, 29 Oct 2022 15:37:44 -0500 Subject: [PATCH 35/53] remove bitmap setting --- src/algorithm/LAGr_TriangleCount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithm/LAGr_TriangleCount.c b/src/algorithm/LAGr_TriangleCount.c index f22e40071c..63b3e39131 100644 --- a/src/algorithm/LAGr_TriangleCount.c +++ b/src/algorithm/LAGr_TriangleCount.c @@ -348,7 +348,7 @@ int LAGr_TriangleCount LG_TRY (tricount_prep (&L, &U, A, msg)) ; // HACK: - GxB_set (L, GxB_SPARSITY_CONTROL, GxB_BITMAP) ; +// GxB_set (L, GxB_SPARSITY_CONTROL, GxB_BITMAP) ; LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, L, GrB_DESC_ST1)) ; From f5b38b1a50c4cf4f2adbd7836c6b672d20f7ee92 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Mon, 5 Dec 2022 10:34:17 -0600 Subject: [PATCH 36/53] fix FindGraphBLAS.cmake --- cmake_modules/FindGraphBLAS.cmake | 91 ++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 21 deletions(-) diff --git a/cmake_modules/FindGraphBLAS.cmake b/cmake_modules/FindGraphBLAS.cmake index 85f61b57fc..d57493cc26 100644 --- a/cmake_modules/FindGraphBLAS.cmake +++ b/cmake_modules/FindGraphBLAS.cmake @@ -2,6 +2,8 @@ FindGraphBLAS -------- +The following copyright and license applies to just this file only, not to +the GraphBLAS library itself: LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. SPDX-License-Identifier: BSD-2-Clause See additional acknowledgments in the LICENSE file, @@ -23,7 +25,8 @@ This module defines the following variables: :: GRAPHBLAS_INCLUDE_DIR - where to find GraphBLAS.h, etc. - GRAPHBLAS_LIBRARY - GraphBLAS library + GRAPHBLAS_LIBRARY - dynamic GraphBLAS library + GRAPHBLAS_STATIC - static GraphBLAS library GRAPHBLAS_LIBRARIES - List of libraries when using GraphBLAS. GRAPHBLAS_FOUND - True if GraphBLAS found. @@ -32,8 +35,8 @@ This module defines the following variables: Hints ^^^^^ -A user may set ``GRAPHBLAS_ROOT`` to a GraphBLAS installation root to tell this -module where to look. +A user may set ``GRAPHBLAS_ROOT`` or ``GraphBLAS_ROOT`` to a GraphBLAS +installation root to tell this module where to look. Otherwise, the first place searched is in ../GraphBLAS, relative to the LAGraph source directory. That is, if GraphBLAS and LAGraph reside in the same parent @@ -43,6 +46,15 @@ This takes precedence over the system-wide installation of GraphBLAS, which might be an older version. This method gives the user the ability to compile LAGraph with their own copy of GraphBLAS, ignoring the system-wide version. +If SuiteSparse:GraphBLAS is the GraphBLAS library being utilized, +all the Find*.cmake files in SuiteSparse are installed by 'make install' into +/usr/local/lib/cmake/SuiteSparse (where '/usr/local' is the +${CMAKE_INSTALL_PREFIX}). To access this file, place the following commands +in your CMakeLists.txt file. See also SuiteSparse/Example/CMakeLists.txt: + + set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + ${CMAKE_INSTALL_PREFIX}/lib/cmake/SuiteSparse ) + #]=======================================================================] # NB: this is built around assumptions about one particular GraphBLAS @@ -50,37 +62,72 @@ LAGraph with their own copy of GraphBLAS, ignoring the system-wide version. # changes to this will likely be required. # "Include" for SuiteSparse:GraphBLAS -find_path( - GRAPHBLAS_INCLUDE_DIR +find_path ( GRAPHBLAS_INCLUDE_DIR NAMES GraphBLAS.h + HINTS ${GRAPHBLAS_ROOT} + HINTS ENV GRAPHBLAS_ROOT HINTS ${CMAKE_SOURCE_DIR}/.. HINTS ${CMAKE_SOURCE_DIR}/../GraphBLAS HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/GraphBLAS - PATHS GRAPHBLAS_ROOT ENV GRAPHBLAS_ROOT PATH_SUFFIXES include Include ) -# "build" for SuiteSparse:GraphBLAS -find_library( - GRAPHBLAS_LIBRARY +# dynamic SuiteSparse:GraphBLAS library +find_library ( GRAPHBLAS_LIBRARY NAMES graphblas + HINTS ${GRAPHBLAS_ROOT} + HINTS ENV GRAPHBLAS_ROOT HINTS ${CMAKE_SOURCE_DIR}/.. HINTS ${CMAKE_SOURCE_DIR}/../GraphBLAS HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/GraphBLAS - PATHS GRAPHBLAS_ROOT ENV GRAPHBLAS_ROOT PATH_SUFFIXES lib build alternative ) -# get version of .so using REALPATH -get_filename_component(GRAPHBLAS_LIBRARY ${GRAPHBLAS_LIBRARY} REALPATH) -string( - REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" - GRAPHBLAS_VERSION - ${GRAPHBLAS_LIBRARY} +if ( MSVC ) + set ( STATIC_SUFFIX .lib ) +else ( ) + set ( STATIC_SUFFIX .a ) +endif ( ) + +# static SuiteSparse:GraphBLAS library +set ( save ${CMAKE_FIND_LIBRARY_SUFFIXES} ) +set ( CMAKE_FIND_LIBRARY_SUFFIXES ${STATIC_SUFFIX} ${CMAKE_FIND_LIBRARY_SUFFIXES} ) +find_library ( GRAPHBLAS_STATIC + NAMES graphblas + HINTS ${GRAPHBLAS_ROOT} + HINTS ENV GRAPHBLAS_ROOT + HINTS ${CMAKE_SOURCE_DIR}/.. + HINTS ${CMAKE_SOURCE_DIR}/../GraphBLAS + HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/GraphBLAS + PATH_SUFFIXES lib build alternative + ) +set ( CMAKE_FIND_LIBRARY_SUFFIXES ${save} ) + +# get version of the library from the dynamic library name +get_filename_component ( GRAPHBLAS_LIBRARY ${GRAPHBLAS_LIBRARY} REALPATH ) +get_filename_component ( GRAPHBLAS_FILENAME ${GRAPHBLAS_LIBRARY} NAME ) +string ( + REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" + GRAPHBLAS_VERSION + ${GRAPHBLAS_FILENAME} ) -set(GRAPHBLAS_LIBRARIES ${GRAPHBLAS_LIBRARY}) -include(FindPackageHandleStandardArgs) +if ( NOT GRAPHBLAS_VERSION ) + # if the version does not appear in the filename, read the include file + foreach ( _VERSION MAJOR MINOR SUB ) + file ( STRINGS ${GRAPHBLAS_INCLUDE_DIR}/GraphBLAS.h _VERSION_LINE REGEX "define[ ]+GxB_IMPLEMENTATION_${_VERSION}" ) + if ( _VERSION_LINE ) + string (REGEX REPLACE ".*define[ ]+GxB_IMPLEMENTATION_${_VERSION}[ ]+([0-9]*).*" "\\1" _GRAPHBLAS_${_VERSION} "${_VERSION_LINE}") + endif ( ) + unset ( _VERSION_LINE ) + endforeach ( ) + set (GRAPHBLAS_VERSION "${_GRAPHBLAS_MAJOR}.${_GRAPHBLAS_MINOR}.${_GRAPHBLAS_SUB}") +endif ( ) + +set ( GRAPHBLAS_LIBRARIES ${GRAPHBLAS_LIBRARY} ) + +include ( FindPackageHandleStandardArgs ) + find_package_handle_standard_args( GraphBLAS REQUIRED_VARS GRAPHBLAS_LIBRARIES GRAPHBLAS_INCLUDE_DIR @@ -90,13 +137,15 @@ find_package_handle_standard_args( mark_as_advanced( GRAPHBLAS_INCLUDE_DIR GRAPHBLAS_LIBRARY + GRAPHBLAS_STATIC GRAPHBLAS_LIBRARIES ) if ( GRAPHBLAS_FOUND ) - message ( STATUS "GraphBLAS include dir: " ${GRAPHBLAS_INCLUDE_DIR} ) - message ( STATUS "GraphBLAS library: " ${GRAPHBLAS_LIBRARY} ) - message ( STATUS "GraphBLAS version: " ${GRAPHBLAS_VERSION} ) + message ( STATUS "GraphBLAS version: ${GRAPHBLAS_VERSION}" ) + message ( STATUS "GraphBLAS include: ${GRAPHBLAS_INCLUDE_DIR}" ) + message ( STATUS "GraphBLAS library: ${GRAPHBLAS_LIBRARY}" ) + message ( STATUS "GraphBLAS static: ${GRAPHBLAS_STATIC}" ) else ( ) message ( STATUS "GraphBLAS not found" ) endif ( ) From 7d6f5976538491c071c555f908cbeba478e27eb7 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Mon, 5 Dec 2022 11:03:24 -0600 Subject: [PATCH 37/53] print GRAPHBLAS_ROOT when building LAGraph --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b209cbba0d..9687b1c4d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,7 +116,7 @@ endif ( ) # GRAPHBLAS_ROOT= cmake .. # or uncomment the next line: # set ( ENV{GRAPHBLAS_ROOT} ${CMAKE_SOURCE_DIR}/../GraphBLAS ) -message ( STATUS "GraphBLAS root: " ${GRAPHBLAS_ROOT} ) +message ( STATUS "GraphBLAS root: ${GRAPHBLAS_ROOT} $ENV{GRAPHBLAS_ROOT}" ) find_package (GraphBLAS 7.0.1 REQUIRED MODULE) #------------------------------------------------------------------------------- From 5b1a97c73b5a399188fdc7dfe667bda1eea6784b Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Mon, 5 Dec 2022 11:31:35 -0600 Subject: [PATCH 38/53] print both GraphBLAS_ROOT and GRAPHBLAS_ROOT --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9687b1c4d6..4f7c32be6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,7 +116,8 @@ endif ( ) # GRAPHBLAS_ROOT= cmake .. # or uncomment the next line: # set ( ENV{GRAPHBLAS_ROOT} ${CMAKE_SOURCE_DIR}/../GraphBLAS ) -message ( STATUS "GraphBLAS root: ${GRAPHBLAS_ROOT} $ENV{GRAPHBLAS_ROOT}" ) +message ( STATUS "GraphBLAS_ROOT: ${GraphBLAS_ROOT} $ENV{GraphBLAS_ROOT}" ) +message ( STATUS "GRAPHBLAS_ROOT: ${GRAPHBLAS_ROOT} $ENV{GRAPHBLAS_ROOT}" ) find_package (GraphBLAS 7.0.1 REQUIRED MODULE) #------------------------------------------------------------------------------- From e9827622b8d8e727cd1370f6db428cebdcf45d5c Mon Sep 17 00:00:00 2001 From: "Corey J. Nolet" Date: Wed, 7 Dec 2022 19:34:34 -0500 Subject: [PATCH 39/53] Using new `rmm_wrap_initialize_all_same()` function. (Not in love with the name, but it does describe what it does). --- src/benchmark/LAGraph_demo.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/benchmark/LAGraph_demo.h b/src/benchmark/LAGraph_demo.h index 3bb05feca5..e60c6f41b4 100644 --- a/src/benchmark/LAGraph_demo.h +++ b/src/benchmark/LAGraph_demo.h @@ -1116,8 +1116,8 @@ static inline int demo_init (bool burble) LAGRAPH_TRY (LAGraph_Init (NULL)) ; #else // use the GPU - // rmm_wrap_initialize (rmm_wrap_managed, INT32_MAX, INT64_MAX) ; - rmm_wrap_initialize (rmm_wrap_managed, 256 * 1000000L, 256 * 100000000L) ; + // rmm_wrap_initialize (rmm_wrap_managed, INT32_MAX, INT64_MAX, 1) ; + rmm_wrap_initialize_all_same (rmm_wrap_managed, 256 * 1000000L, 256 * 100000000L, 1) ; LAGRAPH_TRY (LAGr_Init (GxB_NONBLOCKING_GPU, rmm_wrap_malloc, rmm_wrap_calloc, rmm_wrap_realloc, rmm_wrap_free, NULL)) ; GxB_set (GxB_GPU_CONTROL, GxB_GPU_ALWAYS) ; From 099836bb9e83b631105b99783d90d438bd02478a Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Thu, 8 Dec 2022 12:34:19 -0600 Subject: [PATCH 40/53] revert GPU changes (pushed to wrong branch) --- include/LAGraphX.h | 15 - src/algorithm/LAGr_TriangleCount_GPU.c | 385 -------- src/benchmark/LAGraph_demo_GPU.h | 1150 ------------------------ src/benchmark/tc_gpu_demo.c | 287 ------ src/benchmark/tc_gpu_old.c | 341 ------- 5 files changed, 2178 deletions(-) delete mode 100644 src/algorithm/LAGr_TriangleCount_GPU.c delete mode 100644 src/benchmark/LAGraph_demo_GPU.h delete mode 100644 src/benchmark/tc_gpu_demo.c delete mode 100644 src/benchmark/tc_gpu_old.c diff --git a/include/LAGraphX.h b/include/LAGraphX.h index 8d3d439f81..67d65876f5 100644 --- a/include/LAGraphX.h +++ b/include/LAGraphX.h @@ -869,19 +869,4 @@ int LAGraph_HelloWorld // a simple algorithm, just for illustration char *msg ) ; -//------------------------------------------------------------------------------ -// for GPU development -//------------------------------------------------------------------------------ - -int LAGr_TriangleCount_GPU -( - // output: - uint64_t *ntriangles, - // input: - const LAGraph_Graph G, - LAGraph_TriangleCount_Method method, - LAGraph_TriangleCount_Presort *presort, - char *msg -) ; - #endif diff --git a/src/algorithm/LAGr_TriangleCount_GPU.c b/src/algorithm/LAGr_TriangleCount_GPU.c deleted file mode 100644 index 6a801996ae..0000000000 --- a/src/algorithm/LAGr_TriangleCount_GPU.c +++ /dev/null @@ -1,385 +0,0 @@ -//------------------------------------------------------------------------------ -// LAGr_TriangleCount: Triangle counting using various methods -//------------------------------------------------------------------------------ - -// 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 - -//------------------------------------------------------------------------------ - -// Count the number of triangles in a graph, - -// This is an Advanced algorithm (G->nself_edges, G->out_degree, -// G->is_symmetric_structure are required). - -// Given a symmetric graph A with no-self edges, LAGr_TriangleCount counts the -// number of triangles in the graph. A triangle is a clique of size three, -// that is, 3 nodes that are all pairwise connected. - -// One of 6 methods are used, defined below where L and U are the strictly -// lower and strictly upper triangular parts of the symmetrix matrix A, -// respectively. Each method computes the same result, ntri: - -// 0: default: use the default method (currently method Sandia_LUT) -// 1: Burkhardt: ntri = sum (sum ((A^2) .* A)) / 6 -// 2: Cohen: ntri = sum (sum ((L * U) .* A)) / 2 -// 3: Sandia_LL: ntri = sum (sum ((L * L) .* L)) -// 4: Sandia_UU: ntri = sum (sum ((U * U) .* U)) -// 5: Sandia_LUT: ntri = sum (sum ((L * U') .* L)). Note that L=U'. -// 6: Sandia_ULT: ntri = sum (sum ((U * L') .* U)). Note that U=L'. - -// A is a square symmetric matrix, of any type. Its values are ignored. -// Results are undefined for methods 1 and 2 if self-edges exist in A. Results -// are undefined for all methods if A is unsymmetric. - -// The Sandia_* methods all tend to be faster than the Burkhardt or Cohen -// methods. For the largest graphs, Sandia_LUT tends to be fastest, except for -// the GAP-urand matrix, where the saxpy-based Sandia_LL method (L*L.*L) is -// fastest. For many small graphs, the saxpy-based Sandia_LL and Sandia_UU -// methods are often faster that the dot-product-based methods. - -// Reference for the Burkhardt method: Burkhardt, Paul. "Graphing Trillions of -// Triangles." Information Visualization 16, no. 3 (July 2017): 157–66. -// https://doi.org/10.1177/1473871616666393. - -// Reference for the Cohen method: J. Cohen, "Graph twiddling in a mapreduce -// world," Computing in Science & Engineering, vol. 11, no. 4, pp. 29–41, 2009. -// https://doi.org/10.1109/MCSE.2009.120 - -// Reference for the "Sandia_*" methods: Wolf, Deveci, Berry, Hammond, -// Rajamanickam, "Fast linear algebra- based triangle counting with -// KokkosKernels", IEEE HPEC'17, https://dx.doi.org/10.1109/HPEC.2017.8091043 - -#define LG_FREE_ALL \ -{ \ - GrB_free (L) ; \ - GrB_free (U) ; \ -} - -#include "LG_internal.h" - -//------------------------------------------------------------------------------ -// tricount_prep: construct L and U for LAGr_TriangleCount -//------------------------------------------------------------------------------ - -static int tricount_prep -( - GrB_Matrix *L, // if present, compute L = tril (A,-1) - GrB_Matrix *U, // if present, compute U = triu (A, 1) - GrB_Matrix A, // input matrix - char *msg -) -{ - GrB_Index n ; - GRB_TRY (GrB_Matrix_nrows (&n, A)) ; - - if (L != NULL) - { - // L = tril (A,-1) - GRB_TRY (GrB_Matrix_new (L, GrB_BOOL, n, n)) ; - GRB_TRY (GrB_select (*L, NULL, NULL, GrB_TRIL, A, (int64_t) (-1), - NULL)) ; - GRB_TRY (GrB_Matrix_wait (*L, GrB_MATERIALIZE)) ; - } - - if (U != NULL) - { - // U = triu (A,1) - GRB_TRY (GrB_Matrix_new (U, GrB_BOOL, n, n)) ; - GRB_TRY (GrB_select (*U, NULL, NULL, GrB_TRIU, A, (int64_t) 1, NULL)) ; - GRB_TRY (GrB_Matrix_wait (*U, GrB_MATERIALIZE)) ; - } - return (GrB_SUCCESS) ; -} - -//------------------------------------------------------------------------------ -// LAGraph_tricount: count the number of triangles in a graph -//------------------------------------------------------------------------------ - -#undef LG_FREE_ALL -#define LG_FREE_ALL \ -{ \ - GrB_free (&C) ; \ - GrB_free (&L) ; \ - GrB_free (&T) ; \ - GrB_free (&U) ; \ - LAGraph_Free ((void **) &P, NULL) ; \ -} - -int LAGr_TriangleCount -( - // output: - uint64_t *ntriangles, - // input: - const LAGraph_Graph G, - LAGr_TriangleCount_Method *p_method, - LAGr_TriangleCount_Presort *p_presort, - char *msg -) -{ - - //-------------------------------------------------------------------------- - // check inputs - //-------------------------------------------------------------------------- - - LG_CLEAR_MSG ; - GrB_Matrix C = NULL, L = NULL, U = NULL, T = NULL ; - int64_t *P = NULL ; - - // get the method - LAGr_TriangleCount_Method method ; - method = (p_method == NULL) ? LAGr_TriangleCount_AutoMethod : (*p_method) ; - LG_ASSERT_MSG ( - method == LAGr_TriangleCount_AutoMethod || // 0: use auto method - method == LAGr_TriangleCount_Burkhardt || // 1: sum (sum ((A^2) .* A))/6 - method == LAGr_TriangleCount_Cohen || // 2: sum (sum ((L * U) .*A))/2 - method == LAGr_TriangleCount_Sandia_LL || // 3: sum (sum ((L * L) .* L)) - method == LAGr_TriangleCount_Sandia_UU || // 4: sum (sum ((U * U) .* U)) - method == LAGr_TriangleCount_Sandia_LUT || // 5: sum (sum ((L * U') .* L)) - method == LAGr_TriangleCount_Sandia_ULT, // 6: sum (sum ((U * L') .* U)) - GrB_INVALID_VALUE, "method is invalid") ; - - // get the presort - LAGr_TriangleCount_Presort presort ; - presort = (p_presort == NULL) ? LAGr_TriangleCount_AutoSort : (*p_presort) ; - LG_ASSERT_MSG ( - presort == LAGr_TriangleCount_NoSort || - presort == LAGr_TriangleCount_Ascending || - presort == LAGr_TriangleCount_Descending || - presort == LAGr_TriangleCount_AutoSort, - GrB_INVALID_VALUE, "presort is invalid") ; - - LG_TRY (LAGraph_CheckGraph (G, msg)) ; - LG_ASSERT (ntriangles != NULL, GrB_NULL_POINTER) ; - LG_ASSERT (G->nself_edges == 0, LAGRAPH_NO_SELF_EDGES_ALLOWED) ; - - LG_ASSERT_MSG ((G->kind == LAGraph_ADJACENCY_UNDIRECTED || - (G->kind == LAGraph_ADJACENCY_DIRECTED && - G->is_symmetric_structure == LAGraph_TRUE)), - LAGRAPH_SYMMETRIC_STRUCTURE_REQUIRED, - "G->A must be known to be symmetric") ; - - if (method == LAGr_TriangleCount_AutoMethod) - { - // AutoMethod: use default, Sandia_LUT: sum (sum ((L * U') .* L)) - method = LAGr_TriangleCount_Sandia_LUT ; - } - - // only the Sandia_* methods can benefit from the presort - bool method_can_use_presort = - method == LAGr_TriangleCount_Sandia_LL || // sum (sum ((L * L) .* L)) - method == LAGr_TriangleCount_Sandia_UU || // sum (sum ((U * U) .* U)) - method == LAGr_TriangleCount_Sandia_LUT || // sum (sum ((L * U') .* L)) - method == LAGr_TriangleCount_Sandia_ULT ; // sum (sum ((U * L') .* U)) - - GrB_Matrix A = G->A ; - GrB_Vector Degree = G->out_degree ; - - bool auto_sort = (presort == LAGr_TriangleCount_AutoSort) ; - if (auto_sort && method_can_use_presort) - { - LG_ASSERT_MSG (Degree != NULL, - LAGRAPH_NOT_CACHED, "G->out_degree is required") ; - } - - //-------------------------------------------------------------------------- - // initializations - //-------------------------------------------------------------------------- - - GrB_Index n ; - GRB_TRY (GrB_Matrix_nrows (&n, A)) ; - GRB_TRY (GrB_Matrix_new (&C, GrB_INT64, n, n)) ; - #if LAGRAPH_SUITESPARSE - GrB_Semiring semiring = GxB_PLUS_PAIR_INT64 ; - #else - GrB_Semiring semiring = LAGraph_plus_one_int64 ; - #endif - GrB_Monoid monoid = GrB_PLUS_MONOID_INT64 ; - - //-------------------------------------------------------------------------- - // heuristic sort rule - //-------------------------------------------------------------------------- - - if (!method_can_use_presort) - { - // no sorting for the Burkhardt and Cohen methods: presort parameter - // is ignored. - presort = LAGr_TriangleCount_NoSort ; - } - else if (auto_sort) - { - // auto selection of sorting method for Sandia_* methods - presort = LAGr_TriangleCount_NoSort ; // default is not to sort - - if (method_can_use_presort) - { - // This rule is very similar to Scott Beamer's rule in the GAP TC - // benchmark, except that it is extended to handle the ascending - // sort needed by methods 3 and 5. It also uses a stricter rule, - // since the performance of triangle counting in SuiteSparse: - // GraphBLAS is less sensitive to the sorting as compared to the - // GAP algorithm. This is because the dot products in SuiteSparse: - // GraphBLAS use binary search if one vector is very sparse - // compared to the other. As a result, SuiteSparse:GraphBLAS needs - // the sort for fewer matrices, as compared to the GAP algorithm. - - // With this rule, the GAP-kron and GAP-twitter matrices are - // sorted, and the others remain unsorted. With the rule in the - // GAP tc.cc benchmark, GAP-kron and GAP-twitter are sorted, and so - // is GAP-web, but GAP-web is not sorted here. - - #define NSAMPLES 1000 - GrB_Index nvals ; - GRB_TRY (GrB_Matrix_nvals (&nvals, A)) ; - if (n > NSAMPLES && ((double) nvals / ((double) n)) >= 10) - { - // estimate the mean and median degrees - double mean, median ; - LG_TRY (LAGr_SampleDegree (&mean, &median, - G, true, NSAMPLES, n, msg)) ; - // sort if the average degree is very high vs the median - if (mean > 4 * median) - { - switch (method) - { - case LAGr_TriangleCount_Sandia_LL: - // 3:sum (sum ((L * L) .* L)) - presort = LAGr_TriangleCount_Ascending ; - break ; - case LAGr_TriangleCount_Sandia_UU: - // 4: sum (sum ((U * U) .* U)) - presort = LAGr_TriangleCount_Descending ; - break ; - default: - case LAGr_TriangleCount_Sandia_LUT: - // 5: sum (sum ((L * U') .* L)) - presort = LAGr_TriangleCount_Ascending ; - break ; - case LAGr_TriangleCount_Sandia_ULT: - // 6: sum (sum ((U * L') .* U)) - presort = LAGr_TriangleCount_Descending ; - break ; - } - } - } - } - } - - //-------------------------------------------------------------------------- - // sort the input matrix, if requested - //-------------------------------------------------------------------------- - - if (presort != LAGr_TriangleCount_NoSort) - { - // P = permutation that sorts the rows by their degree - LG_TRY (LAGr_SortByDegree (&P, G, true, - presort == LAGr_TriangleCount_Ascending, msg)) ; - - // T = A (P,P) and typecast to boolean - GRB_TRY (GrB_Matrix_new (&T, GrB_BOOL, n, n)) ; - GRB_TRY (GrB_extract (T, NULL, NULL, A, (GrB_Index *) P, n, - (GrB_Index *) P, n, NULL)) ; - A = T ; - - // free workspace - LG_TRY (LAGraph_Free ((void **) &P, NULL)) ; - } - - //-------------------------------------------------------------------------- - // count triangles - //-------------------------------------------------------------------------- - - int64_t ntri ; - double t ; - - switch (method) - { - - case LAGr_TriangleCount_Burkhardt: // 1: sum (sum ((A^2) .* A)) / 6 - - t = LAGraph_WallClockTime ( ) ; - GRB_TRY (GrB_mxm (C, A, NULL, semiring, A, A, GrB_DESC_S)) ; - GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; - ntri /= 6 ; - t = LAGraph_WallClockTime ( ) - t ; - printf ("Burkhardt time: %g\n", t) ; - break ; - - case LAGr_TriangleCount_Cohen: // 2: sum (sum ((L * U) .* A)) / 2 - - LG_TRY (tricount_prep (&L, &U, A, msg)) ; - t = LAGraph_WallClockTime ( ) ; - GRB_TRY (GrB_mxm (C, A, NULL, semiring, L, U, GrB_DESC_S)) ; - GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; - ntri /= 2 ; - t = LAGraph_WallClockTime ( ) - t ; - printf ("Cohen time: %g\n", t) ; - break ; - - case LAGr_TriangleCount_Sandia_LL: // 3: sum (sum ((L * L) .* L)) - - // using the masked saxpy3 method - LG_TRY (tricount_prep (&L, NULL, A, msg)) ; - t = LAGraph_WallClockTime ( ) ; - GRB_TRY (GrB_mxm (C, L, NULL, semiring, L, L, GrB_DESC_S)) ; - GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; - t = LAGraph_WallClockTime ( ) - t ; - printf ("Sandia_LL (saxpy) time: %g\n", t) ; - break ; - - case LAGr_TriangleCount_Sandia_UU: // 4: sum (sum ((U * U) .* U)) - - // using the masked saxpy3 method - LG_TRY (tricount_prep (NULL, &U, A, msg)) ; - t = LAGraph_WallClockTime ( ) ; - GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, U, GrB_DESC_S)) ; - GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; - t = LAGraph_WallClockTime ( ) - t ; - printf ("Sandia_UU (saxpy) time: %g\n", t) ; - break ; - - default: - case LAGr_TriangleCount_Sandia_LUT: // 5: sum (sum ((L * U') .* L)) - - // This tends to be the fastest method for most large matrices, but - // the Sandia_ULT method is also very fast. - - // using the masked dot product - LG_TRY (tricount_prep (&L, &U, A, msg)) ; - t = LAGraph_WallClockTime ( ) ; - GRB_TRY (GrB_mxm (C, L, NULL, semiring, L, U, GrB_DESC_ST1)) ; - GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; - t = LAGraph_WallClockTime ( ) - t ; - printf ("Sandia_LUT (dot) time: %g\n", t) ; - break ; - - case LAGr_TriangleCount_Sandia_ULT: // 6: sum (sum ((U * L') .* U)) - - // using the masked dot product - LG_TRY (tricount_prep (&L, &U, A, msg)) ; - t = LAGraph_WallClockTime ( ) ; - GRB_TRY (GrB_mxm (C, U, NULL, semiring, U, L, GrB_DESC_ST1)) ; - t = LAGraph_WallClockTime ( ) - t ; - GRB_TRY (GrB_reduce (&ntri, NULL, monoid, C, NULL)) ; - printf ("Sandia_ULT (dot) time: %g\n", t) ; - break ; - } - - //-------------------------------------------------------------------------- - // return result - //-------------------------------------------------------------------------- - - LG_FREE_ALL ; - if (p_method != NULL) (*p_method) = method ; - if (p_presort != NULL) (*p_presort) = presort ; - (*ntriangles) = (uint64_t) ntri ; - return (GrB_SUCCESS) ; -} diff --git a/src/benchmark/LAGraph_demo_GPU.h b/src/benchmark/LAGraph_demo_GPU.h deleted file mode 100644 index 676be668f8..0000000000 --- a/src/benchmark/LAGraph_demo_GPU.h +++ /dev/null @@ -1,1150 +0,0 @@ -//------------------------------------------------------------------------------ -// LAGraph_demo.h: include file for LAGraph/src/benchmark programs -//------------------------------------------------------------------------------ - -// 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 - -//------------------------------------------------------------------------------ - -#ifndef LAGRAPH_DEMO_H -#define LAGRAPH_DEMO_H - -#include -#include - -#if defined ( __linux__ ) -// for mallopt -#include -#endif - -// set this to 1 to check the results using a slow method -#define LG_CHECK_RESULT 0 - -#define DEAD_CODE -911 -#define CATCH(status) \ -{ \ - printf ("error: %s line: %d, status: %d\n", __FILE__, __LINE__, status) ; \ - if (msg [0] != '\0') printf ("msg: %s\n", msg) ; \ - LG_FREE_ALL ; \ - return (status) ; \ -} - -#undef LAGRAPH_CATCH -#define LAGRAPH_CATCH(status) CATCH (status) - -#undef GRB_CATCH -#define GRB_CATCH(info) CATCH (info) - -#define LAGRAPH_BIN_HEADER 512 -#define LEN LAGRAPH_BIN_HEADER - -#if !LAGRAPH_SUITESPARSE -#error "SuiteSparse:GraphBLAS v6.0.0 or later is required" -#endif - -//------------------------------------------------------------------------------ -// binwrite: write a matrix to a binary file -//------------------------------------------------------------------------------ - -#define LG_FREE_ALL \ -{ \ - GrB_free (A) ; \ - LAGraph_Free ((void **) &Ap, NULL) ; \ - LAGraph_Free ((void **) &Ab, NULL) ; \ - LAGraph_Free ((void **) &Ah, NULL) ; \ - LAGraph_Free ((void **) &Ai, NULL) ; \ - LAGraph_Free ((void **) &Ax, NULL) ; \ -} - -#define FWRITE(p,s,n) \ -{ \ - if (fwrite (p, s, n, f) != n) \ - { \ - CATCH (LAGRAPH_IO_ERROR) ; \ - } \ -} - -static inline int binwrite // returns 0 if successful, < 0 on error -( - GrB_Matrix *A, // matrix to write to the file - FILE *f, // file to write it to - const char *comments // comments to add to the file, up to 210 characters - // in length, not including the terminating null - // byte. Ignored if NULL. Characters past - // the 210 limit are silently ignored. -) -{ - - //-------------------------------------------------------------------------- - // check inputs - //-------------------------------------------------------------------------- - - char msg [LAGRAPH_MSG_LEN] ; - msg [0] = '\0' ; - -#if !LAGRAPH_SUITESPARSE - printf ("SuiteSparse:GraphBLAS required to write binary *.grb files\n") ; - return (GrB_NOT_IMPLEMENTED) ; -#else - - GrB_Index *Ap = NULL, *Ai = NULL, *Ah = NULL ; - void *Ax = NULL ; - int8_t *Ab = NULL ; - if (A == NULL || *A == NULL || f == NULL) CATCH (GrB_NULL_POINTER) ; - - GRB_TRY (GrB_wait (*A, GrB_MATERIALIZE)) ; - - //-------------------------------------------------------------------------- - // determine the basic matrix properties - //-------------------------------------------------------------------------- - - GxB_Format_Value fmt = -999 ; - GRB_TRY (GxB_get (*A, GxB_FORMAT, &fmt)) ; - - bool is_hyper = false ; - bool is_sparse = false ; - bool is_bitmap = false ; - bool is_full = false ; - GRB_TRY (GxB_get (*A, GxB_IS_HYPER, &is_hyper)) ; - int32_t kind ; - double hyper = -999 ; - - GRB_TRY (GxB_get (*A, GxB_HYPER_SWITCH, &hyper)) ; - GRB_TRY (GxB_get (*A, GxB_SPARSITY_STATUS, &kind)) ; - - switch (kind) - { - default : - case 0 : // for backward compatibility with prior versions - case 2 : is_sparse = true ; break ; // GxB_SPARSE = 2 - case 1 : is_hyper = true ; break ; // GxB_HYPERSPARSE = 1 - case 4 : is_bitmap = true ; break ; // GxB_BITMAP = 4 - case 8 : is_full = true ; break ; // GxB_FULL = 4 - } - - //-------------------------------------------------------------------------- - // export the matrix - //-------------------------------------------------------------------------- - - GrB_Type type ; - GrB_Index nrows, ncols, nvals, nvec ; - GRB_TRY (GrB_Matrix_nvals (&nvals, *A)) ; - size_t typesize ; - int64_t nonempty = -1 ; - char *fmt_string ; - bool jumbled, iso ; - GrB_Index Ap_size, Ah_size, Ab_size, Ai_size, Ax_size ; - - if (fmt == GxB_BY_COL && is_hyper) - { - // hypersparse CSC - GRB_TRY (GxB_Matrix_export_HyperCSC (A, &type, &nrows, &ncols, - &Ap, &Ah, &Ai, &Ax, &Ap_size, &Ah_size, &Ai_size, &Ax_size, - &iso, &nvec, &jumbled, NULL)) ; - fmt_string = "HCSC" ; - } - else if (fmt == GxB_BY_ROW && is_hyper) - { - // hypersparse CSR - GRB_TRY (GxB_Matrix_export_HyperCSR (A, &type, &nrows, &ncols, - &Ap, &Ah, &Ai, &Ax, &Ap_size, &Ah_size, &Ai_size, &Ax_size, - &iso, &nvec, &jumbled, NULL)) ; - fmt_string = "HCSR" ; - } - else if (fmt == GxB_BY_COL && is_sparse) - { - // standard CSC - GRB_TRY (GxB_Matrix_export_CSC (A, &type, &nrows, &ncols, - &Ap, &Ai, &Ax, &Ap_size, &Ai_size, &Ax_size, - &iso, &jumbled, NULL)) ; - nvec = ncols ; - fmt_string = "CSC " ; - } - else if (fmt == GxB_BY_ROW && is_sparse) - { - // standard CSR - GRB_TRY (GxB_Matrix_export_CSR (A, &type, &nrows, &ncols, - &Ap, &Ai, &Ax, &Ap_size, &Ai_size, &Ax_size, - &iso, &jumbled, NULL)) ; - nvec = nrows ; - fmt_string = "CSR " ; - } - else if (fmt == GxB_BY_COL && is_bitmap) - { - // bitmap by col - GRB_TRY (GxB_Matrix_export_BitmapC (A, &type, &nrows, &ncols, - &Ab, &Ax, &Ab_size, &Ax_size, - &iso, &nvals, NULL)) ; - nvec = ncols ; - fmt_string = "BITMAPC" ; - } - else if (fmt == GxB_BY_ROW && is_bitmap) - { - // bitmap by row - GRB_TRY (GxB_Matrix_export_BitmapR (A, &type, &nrows, &ncols, - &Ab, &Ax, &Ab_size, &Ax_size, - &iso, &nvals, NULL)) ; - nvec = nrows ; - fmt_string = "BITMAPR" ; - } - else if (fmt == GxB_BY_COL && is_full) - { - // full by col - GRB_TRY (GxB_Matrix_export_FullC (A, &type, &nrows, &ncols, - &Ax, &Ax_size, - &iso, NULL)) ; - nvec = ncols ; - fmt_string = "FULLC" ; - } - else if (fmt == GxB_BY_ROW && is_full) - { - // full by row - GRB_TRY (GxB_Matrix_export_FullR (A, &type, &nrows, &ncols, - &Ax, &Ax_size, - &iso, NULL)) ; - nvec = nrows ; - fmt_string = "FULLC" ; - } - else - { - CATCH (DEAD_CODE) ; // this "cannot" happen - } - - //-------------------------------------------------------------------------- - // create the type string - //-------------------------------------------------------------------------- - - GRB_TRY (GxB_Type_size (&typesize, type)) ; - - char typename [LEN] ; - int32_t typecode ; - if (type == GrB_BOOL ) - { - snprintf (typename, LEN, "GrB_BOOL ") ; - typecode = 0 ; - } - else if (type == GrB_INT8 ) - { - snprintf (typename, LEN, "GrB_INT8 ") ; - typecode = 1 ; - } - else if (type == GrB_INT16 ) - { - snprintf (typename, LEN, "GrB_INT16 ") ; - typecode = 2 ; - } - else if (type == GrB_INT32 ) - { - snprintf (typename, LEN, "GrB_INT32 ") ; - typecode = 3 ; - } - else if (type == GrB_INT64 ) - { - snprintf (typename, LEN, "GrB_INT64 ") ; - typecode = 4 ; - } - else if (type == GrB_UINT8 ) - { - snprintf (typename, LEN, "GrB_UINT8 ") ; - typecode = 5 ; - } - else if (type == GrB_UINT16) - { - snprintf (typename, LEN, "GrB_UINT16") ; - typecode = 6 ; - } - else if (type == GrB_UINT32) - { - snprintf (typename, LEN, "GrB_UINT32") ; - typecode = 7 ; - } - else if (type == GrB_UINT64) - { - snprintf (typename, LEN, "GrB_UINT64") ; - typecode = 8 ; - } - else if (type == GrB_FP32 ) - { - snprintf (typename, LEN, "GrB_FP32 ") ; - typecode = 9 ; - } - else if (type == GrB_FP64 ) - { - snprintf (typename, LEN, "GrB_FP64 ") ; - typecode = 10 ; - } - else - { - // unsupported type (GxB_FC32 and GxB_FC64 not yet supported) - CATCH (GrB_NOT_IMPLEMENTED) ; - } - typename [72] = '\0' ; - - //-------------------------------------------------------------------------- - // write the header in ascii - //-------------------------------------------------------------------------- - - // The header is informational only, for "head" command, so the file can - // be visually inspected. - - char version [LEN] ; - snprintf (version, LEN, "%d.%d.%d (LAGraph DRAFT)", - GxB_IMPLEMENTATION_MAJOR, - GxB_IMPLEMENTATION_MINOR, - GxB_IMPLEMENTATION_SUB) ; - version [25] = '\0' ; - - char user [LEN] ; - for (int k = 0 ; k < LEN ; k++) user [k] = ' ' ; - user [0] = '\n' ; - if (comments != NULL) - { - strncpy (user, comments, 210) ; - } - user [210] = '\0' ; - - char header [LAGRAPH_BIN_HEADER] ; - int32_t len = snprintf (header, LAGRAPH_BIN_HEADER, - "SuiteSparse:GraphBLAS matrix\nv%-25s\n" - "nrows: %-18" PRIu64 "\n" - "ncols: %-18" PRIu64 "\n" - "nvec: %-18" PRIu64 "\n" - "nvals: %-18" PRIu64 "\n" - "format: %-8s\n" - "size: %-18" PRIu64 "\n" - "type: %-72s\n" - "iso: %1d\n" - "%-210s\n\n", - version, nrows, ncols, nvec, nvals, fmt_string, (uint64_t) typesize, - typename, iso, user) ; - - // printf ("header len %d\n", len) ; - for (int32_t k = len ; k < LAGRAPH_BIN_HEADER ; k++) header [k] = ' ' ; - header [LAGRAPH_BIN_HEADER-1] = '\0' ; - FWRITE (header, sizeof (char), LAGRAPH_BIN_HEADER) ; - - //-------------------------------------------------------------------------- - // write the scalar content - //-------------------------------------------------------------------------- - - if (iso) - { - // kind is 1, 2, 4, or 8: add 100 if the matrix is iso - kind = kind + 100 ; - } - - FWRITE (&fmt, sizeof (GxB_Format_Value), 1) ; - FWRITE (&kind, sizeof (int32_t), 1) ; - FWRITE (&hyper, sizeof (double), 1) ; - FWRITE (&nrows, sizeof (GrB_Index), 1) ; - FWRITE (&ncols, sizeof (GrB_Index), 1) ; - FWRITE (&nonempty, sizeof (int64_t), 1) ; - FWRITE (&nvec, sizeof (GrB_Index), 1) ; - FWRITE (&nvals, sizeof (GrB_Index), 1) ; - FWRITE (&typecode, sizeof (int32_t), 1) ; - FWRITE (&typesize, sizeof (size_t), 1) ; - - //-------------------------------------------------------------------------- - // write the array content - //-------------------------------------------------------------------------- - - if (is_hyper) - { - FWRITE (Ap, sizeof (GrB_Index), nvec+1) ; - FWRITE (Ah, sizeof (GrB_Index), nvec) ; - FWRITE (Ai, sizeof (GrB_Index), nvals) ; - FWRITE (Ax, typesize, (iso ? 1 : nvals)) ; - } - else if (is_sparse) - { - FWRITE (Ap, sizeof (GrB_Index), nvec+1) ; - FWRITE (Ai, sizeof (GrB_Index), nvals) ; - FWRITE (Ax, typesize, (iso ? 1 : nvals)) ; - } - else if (is_bitmap) - { - FWRITE (Ab, sizeof (int8_t), nrows*ncols) ; - FWRITE (Ax, typesize, (iso ? 1 : (nrows*ncols))) ; - } - else - { - FWRITE (Ax, typesize, (iso ? 1 : (nrows*ncols))) ; - } - - //-------------------------------------------------------------------------- - // re-import the matrix - //-------------------------------------------------------------------------- - - if (fmt == GxB_BY_COL && is_hyper) - { - // hypersparse CSC - GRB_TRY (GxB_Matrix_import_HyperCSC (A, type, nrows, ncols, - &Ap, &Ah, &Ai, &Ax, Ap_size, Ah_size, Ai_size, Ax_size, - iso, nvec, jumbled, NULL)) ; - } - else if (fmt == GxB_BY_ROW && is_hyper) - { - // hypersparse CSR - GRB_TRY (GxB_Matrix_import_HyperCSR (A, type, nrows, ncols, - &Ap, &Ah, &Ai, &Ax, Ap_size, Ah_size, Ai_size, Ax_size, - iso, nvec, jumbled, NULL)) ; - } - else if (fmt == GxB_BY_COL && is_sparse) - { - // standard CSC - GRB_TRY (GxB_Matrix_import_CSC (A, type, nrows, ncols, - &Ap, &Ai, &Ax, Ap_size, Ai_size, Ax_size, - iso, jumbled, NULL)) ; - } - else if (fmt == GxB_BY_ROW && is_sparse) - { - // standard CSR - GRB_TRY (GxB_Matrix_import_CSR (A, type, nrows, ncols, - &Ap, &Ai, &Ax, Ap_size, Ai_size, Ax_size, - iso, jumbled, NULL)) ; - } - else if (fmt == GxB_BY_COL && is_bitmap) - { - // bitmap by col - GRB_TRY (GxB_Matrix_import_BitmapC (A, type, nrows, ncols, - &Ab, &Ax, Ab_size, Ax_size, - iso, nvals, NULL)) ; - } - else if (fmt == GxB_BY_ROW && is_bitmap) - { - // bitmap by row - GRB_TRY (GxB_Matrix_import_BitmapR (A, type, nrows, ncols, - &Ab, &Ax, Ab_size, Ax_size, - iso, nvals, NULL)) ; - } - else if (fmt == GxB_BY_COL && is_full) - { - // full by col - GRB_TRY (GxB_Matrix_import_FullC (A, type, nrows, ncols, - &Ax, Ax_size, - iso, NULL)) ; - } - else if (fmt == GxB_BY_ROW && is_full) - { - // full by row - GRB_TRY (GxB_Matrix_import_FullR (A, type, nrows, ncols, - &Ax, Ax_size, - iso, NULL)) ; - } - else - { - CATCH (DEAD_CODE) ; // this "cannot" happen - } - - GRB_TRY (GxB_set (*A, GxB_HYPER_SWITCH, hyper)) ; - return (GrB_SUCCESS) ; -#endif -} - -//------------------------------------------------------------------------------ -// binread: read a matrix from a binary file -//------------------------------------------------------------------------------ - -#define FREAD(p,s,n) \ -{ \ - if (fread (p, s, n, f) != n) \ - { \ - CATCH (-1001) ; /* file I/O error */ \ - } \ -} - -static inline int binread // returns 0 if successful, -1 if failure -( - GrB_Matrix *A, // matrix to read from the file - FILE *f // file to read it from, already open -) -{ - - //-------------------------------------------------------------------------- - // check inputs - //-------------------------------------------------------------------------- - - char msg [LAGRAPH_MSG_LEN] ; - msg [0] = '\0' ; - -#if !LAGRAPH_SUITESPARSE - printf ("SuiteSparse:GraphBLAS required to read binary *.grb files\n") ; - return (GrB_NOT_IMPLEMENTED) ; -#else - - GrB_Index *Ap = NULL, *Ai = NULL, *Ah = NULL ; - int8_t *Ab = NULL ; - void *Ax = NULL ; - if (A == NULL || f == NULL) CATCH (GrB_NULL_POINTER) ; - (*A) = NULL ; - - //-------------------------------------------------------------------------- - // basic matrix properties - //-------------------------------------------------------------------------- - - GxB_Format_Value fmt = -999 ; - bool is_hyper, is_sparse, is_bitmap, is_full ; - int32_t kind, typecode ; - double hyper = -999 ; - GrB_Type type ; - GrB_Index nrows, ncols, nvals, nvec ; - size_t typesize ; - int64_t nonempty ; - - //-------------------------------------------------------------------------- - // read the header (and ignore it) - //-------------------------------------------------------------------------- - - // The header is informational only, for "head" command, so the file can - // be visually inspected. - - char header [LAGRAPH_BIN_HEADER] ; - FREAD (header, sizeof (char), LAGRAPH_BIN_HEADER) ; - // printf ("%s\n", header) ; - - //-------------------------------------------------------------------------- - // read the scalar content - //-------------------------------------------------------------------------- - - FREAD (&fmt, sizeof (GxB_Format_Value), 1) ; - FREAD (&kind, sizeof (int32_t), 1) ; - FREAD (&hyper, sizeof (double), 1) ; - FREAD (&nrows, sizeof (GrB_Index), 1) ; - FREAD (&ncols, sizeof (GrB_Index), 1) ; - FREAD (&nonempty, sizeof (int64_t), 1) ; - FREAD (&nvec, sizeof (GrB_Index), 1) ; - FREAD (&nvals, sizeof (GrB_Index), 1) ; - FREAD (&typecode, sizeof (int32_t), 1) ; - FREAD (&typesize, sizeof (size_t), 1) ; - - bool iso = false ; - if (kind > 100) - { - iso = true ; - kind = kind - 100 ; - } - - is_hyper = (kind == 1) ; - is_sparse = (kind == 0 || kind == GxB_SPARSE) ; - is_bitmap = (kind == GxB_BITMAP) ; - is_full = (kind == GxB_FULL) ; - - switch (typecode) - { - case 0: type = GrB_BOOL ; break ; - case 1: type = GrB_INT8 ; break ; - case 2: type = GrB_INT16 ; break ; - case 3: type = GrB_INT32 ; break ; - case 4: type = GrB_INT64 ; break ; - case 5: type = GrB_UINT8 ; break ; - case 6: type = GrB_UINT16 ; break ; - case 7: type = GrB_UINT32 ; break ; - case 8: type = GrB_UINT64 ; break ; - case 9: type = GrB_FP32 ; break ; - case 10: type = GrB_FP64 ; break ; - #if 0 - case 11: type = GxB_FC32 ; break ; - case 12: type = GxB_FC64 ; break ; - #endif - default: CATCH (GrB_NOT_IMPLEMENTED) ; // unknown or unsupported type - } - - //-------------------------------------------------------------------------- - // allocate the array content - //-------------------------------------------------------------------------- - - GrB_Index Ap_len = 0, Ap_size = 0 ; - GrB_Index Ah_len = 0, Ah_size = 0 ; - GrB_Index Ab_len = 0, Ab_size = 0 ; - GrB_Index Ai_len = 0, Ai_size = 0 ; - GrB_Index Ax_len = 0, Ax_size = 0 ; - - bool ok = true ; - if (is_hyper) - { - Ap_len = nvec+1 ; - Ah_len = nvec ; - Ai_len = nvals ; - Ax_len = nvals ; - LAGraph_Malloc ((void **) &Ap, Ap_len, sizeof (GrB_Index), msg) ; - LAGraph_Malloc ((void **) &Ah, Ah_len, sizeof (GrB_Index), msg) ; - LAGraph_Malloc ((void **) &Ai, Ai_len, sizeof (GrB_Index), msg) ; - Ap_size = Ap_len * sizeof (GrB_Index) ; - Ah_size = Ah_len * sizeof (GrB_Index) ; - Ai_size = Ai_len * sizeof (GrB_Index) ; - ok = (Ap != NULL && Ah != NULL && Ai != NULL) ; - } - else if (is_sparse) - { - Ap_len = nvec+1 ; - Ai_len = nvals ; - Ax_len = nvals ; - LAGraph_Malloc ((void **) &Ap, Ap_len, sizeof (GrB_Index), msg) ; - LAGraph_Malloc ((void **) &Ai, Ai_len, sizeof (GrB_Index), msg) ; - Ap_size = Ap_len * sizeof (GrB_Index) ; - Ai_size = Ai_len * sizeof (GrB_Index) ; - ok = (Ap != NULL && Ai != NULL) ; - } - else if (is_bitmap) - { - Ab_len = nrows*ncols ; - Ax_len = nrows*ncols ; - LAGraph_Malloc ((void **) &Ab, nrows*ncols, sizeof (int8_t), msg) ; - Ab_size = Ab_len * sizeof (GrB_Index) ; - ok = (Ab != NULL) ; - } - else if (is_full) - { - Ax_len = nrows*ncols ; - } - else - { - CATCH (DEAD_CODE) ; // this "cannot" happen - } - LAGraph_Malloc ((void **) &Ax, iso ? 1 : Ax_len, typesize, msg) ; - Ax_size = (iso ? 1 : Ax_len) * typesize ; - ok = ok && (Ax != NULL) ; - if (!ok) CATCH (GrB_OUT_OF_MEMORY) ; // out of memory - - //-------------------------------------------------------------------------- - // read the array content - //-------------------------------------------------------------------------- - - if (is_hyper) - { - FREAD (Ap, sizeof (GrB_Index), Ap_len) ; - FREAD (Ah, sizeof (GrB_Index), Ah_len) ; - FREAD (Ai, sizeof (GrB_Index), Ai_len) ; - } - else if (is_sparse) - { - FREAD (Ap, sizeof (GrB_Index), Ap_len) ; - FREAD (Ai, sizeof (GrB_Index), Ai_len) ; - } - else if (is_bitmap) - { - FREAD (Ab, sizeof (int8_t), Ab_len) ; - } - - FREAD (Ax, typesize, (iso ? 1 : Ax_len)) ; - - //-------------------------------------------------------------------------- - // import the matrix - //-------------------------------------------------------------------------- - - if (fmt == GxB_BY_COL && is_hyper) - { - // hypersparse CSC - GRB_TRY (GxB_Matrix_import_HyperCSC (A, type, nrows, ncols, - &Ap, &Ah, &Ai, &Ax, Ap_size, Ah_size, Ai_size, Ax_size, - iso, nvec, false, NULL)) ; - } - else if (fmt == GxB_BY_ROW && is_hyper) - { - // hypersparse CSR - GRB_TRY (GxB_Matrix_import_HyperCSR (A, type, nrows, ncols, - &Ap, &Ah, &Ai, &Ax, Ap_size, Ah_size, Ai_size, Ax_size, - iso, nvec, false, NULL)) ; - } - else if (fmt == GxB_BY_COL && is_sparse) - { - // standard CSC - GRB_TRY (GxB_Matrix_import_CSC (A, type, nrows, ncols, - &Ap, &Ai, &Ax, Ap_size, Ai_size, Ax_size, - iso, false, NULL)) ; - } - else if (fmt == GxB_BY_ROW && is_sparse) - { - // standard CSR - GRB_TRY (GxB_Matrix_import_CSR (A, type, nrows, ncols, - &Ap, &Ai, &Ax, Ap_size, Ai_size, Ax_size, - iso, false, NULL)) ; - } - else if (fmt == GxB_BY_COL && is_bitmap) - { - // bitmap by col - GRB_TRY (GxB_Matrix_import_BitmapC (A, type, nrows, ncols, - &Ab, &Ax, Ab_size, Ax_size, - iso, nvals, NULL)) ; - } - else if (fmt == GxB_BY_ROW && is_bitmap) - { - // bitmap by row - GRB_TRY (GxB_Matrix_import_BitmapR (A, type, nrows, ncols, - &Ab, &Ax, Ab_size, Ax_size, - iso, nvals, NULL)) ; - } - else if (fmt == GxB_BY_COL && is_full) - { - // full by col - GRB_TRY (GxB_Matrix_import_FullC (A, type, nrows, ncols, - &Ax, Ax_size, - iso, NULL)) ; - } - else if (fmt == GxB_BY_ROW && is_full) - { - // full by row - GRB_TRY (GxB_Matrix_import_FullR (A, type, nrows, ncols, - &Ax, Ax_size, - iso, NULL)) ; - } - else - { - CATCH (DEAD_CODE) ; // this "cannot" happen - } - - GRB_TRY (GxB_set (*A, GxB_HYPER_SWITCH, hyper)) ; - return (GrB_SUCCESS) ; -#endif -} - -//------------------------------------------------------------------------------ -// readproblem: read a GAP problem from a file -//------------------------------------------------------------------------------ - -#undef LG_FREE_WORK -#define LG_FREE_WORK \ -{ \ - GrB_free (&A) ; \ - GrB_free (&A2) ; \ - GrB_free (&M) ; \ - if (f != NULL) fclose (f) ; \ - f = NULL ; \ -} - -#undef LG_FREE_ALL -#define LG_FREE_ALL \ -{ \ - LG_FREE_WORK ; \ - LAGraph_Delete (G, NULL) ; \ - GrB_free (src_nodes) ; \ -} - -// usage: -// test_whatever < matrixfile.mtx -// test_whatever matrixfile.mtx sourcenodes.mtx -// The matrixfile may also have a grb suffix. - -static int readproblem // returns 0 if successful, -1 if failure -( - // output - LAGraph_Graph *G, // graph from the file - GrB_Matrix *src_nodes, // source nodes - // inputs - bool make_symmetric, // if true, always return G as undirected - bool remove_self_edges, // if true, remove self edges - bool structural, // if true, return G->A as bool (all true) - GrB_Type pref, // if non-NULL, typecast G->A to this type - bool ensure_positive, // if true, ensure all entries are > 0 - int argc, // input to main test program - char **argv // input to main test program -) -{ - - //-------------------------------------------------------------------------- - // check inputs - //-------------------------------------------------------------------------- - - char msg [LAGRAPH_MSG_LEN] ; - msg [0] = '\0' ; - GrB_Matrix A = NULL, A2 = NULL, M = NULL ; - GrB_Type atype = NULL ; - FILE *f = NULL ; - if (G == NULL) CATCH (GrB_NULL_POINTER) ; - (*G) = NULL ; - if (src_nodes != NULL) (*src_nodes) = NULL ; - GrB_Type src_type = NULL; - - //-------------------------------------------------------------------------- - // read in a matrix from a file - //-------------------------------------------------------------------------- - - double t_read = LAGraph_WallClockTime ( ) ; - - if (argc > 1) - { - // Usage: - // ./test_whatever matrixfile.mtx [sources.mtx] - // ./test_whatever matrixfile.grb [sources.mtx] - - // read in the file in Matrix Market format from the input file - char *filename = argv [1] ; - printf ("matrix: %s\n", filename) ; - - // find the filename extension - size_t len = strlen (filename) ; - char *ext = NULL ; - for (int k = len-1 ; k >= 0 ; k--) - { - if (filename [k] == '.') - { - ext = filename + k ; - printf ("[%s]\n", ext) ; - break ; - } - } - - bool is_binary = (ext != NULL && strncmp (ext, ".grb", 4) == 0) ; - - if (is_binary) - { - printf ("Reading binary file: %s\n", filename) ; - f = fopen (filename, "r") ; - if (f == NULL) - { - printf ("Binary file not found: [%s]\n", filename) ; - exit (1) ; - } - if (binread (&A, f) < 0) CATCH (-1001) ; // file I/O error - fclose (f) ; - f = NULL ; - } - else - { - printf ("Reading matrix market file: %s\n", filename) ; - f = fopen (filename, "r") ; - if (f == NULL) - { - printf ("Matrix market file not found: [%s]\n", filename) ; - exit (1) ; - } - int result = LAGraph_MMRead (&A, f, msg) ; - if (result != GrB_SUCCESS) - { - printf ("LAGraph_MMRead failed to read matrix: %s\n", - filename) ; - printf ("result: %d msg: %s\n", result, msg) ; - } - LAGRAPH_TRY (result) ; - fclose (f) ; - f = NULL ; - } - - // read in source nodes in Matrix Market format from the input file - if (argc > 2 && src_nodes != NULL) - { - // do not read in the file if the name starts with "-" - filename = argv [2] ; - if (filename [0] != '-') - { - printf ("sources: %s\n", filename) ; - f = fopen (filename, "r") ; - if (f == NULL) - { - printf ("Source node file not found: [%s]\n", filename) ; - exit (1) ; - } - int result = LAGraph_MMRead (src_nodes, f, msg) ; - if (result != GrB_SUCCESS) - { - printf ("LAGraph_MMRead failed to read source nodes" - " from: %s\n", filename) ; - printf ("result: %d msg: %s\n", result, msg) ; - } - LAGRAPH_TRY (result) ; - fclose (f) ; - f = NULL ; - } - } - } - else - { - - // Usage: ./test_whatever < matrixfile.mtx - printf ("matrix: from stdin\n") ; - - // read in the file in Matrix Market format from stdin - int result = LAGraph_MMRead (&A, stdin, msg) ; - if (result != GrB_SUCCESS) - { - printf ("LAGraph_MMRead failed to read: stdin\n") ; - printf ("result: %d msg: %s\n", result, msg) ; - } - LAGRAPH_TRY (result) ; - } - - //-------------------------------------------------------------------------- - // get the size of the problem. - //-------------------------------------------------------------------------- - - GrB_Index nrows, ncols ; - GRB_TRY (GrB_Matrix_nrows (&nrows, A)) ; - GRB_TRY (GrB_Matrix_ncols (&ncols, A)) ; - GrB_Index n = nrows ; - if (nrows != ncols) CATCH (GrB_DIMENSION_MISMATCH) ; // A must be square - - //-------------------------------------------------------------------------- - // typecast, if requested - //-------------------------------------------------------------------------- - - GRB_TRY (GxB_Matrix_type (&atype, A)) ; - - if (structural) - { - // convert to boolean, with all entries true - atype = GrB_BOOL ; - LAGRAPH_TRY (LAGraph_Matrix_Structure (&A2, A, msg)) ; - } - else if (pref != NULL && atype != pref) - { - // convert to the requested type - GRB_TRY (GrB_Matrix_new (&A2, pref, n, n)) ; - atype = pref ; - - GrB_UnaryOp op = NULL ; - if (pref == GrB_BOOL ) op = GrB_IDENTITY_BOOL ; - else if (pref == GrB_INT8 ) op = GrB_IDENTITY_INT8 ; - else if (pref == GrB_INT16 ) op = GrB_IDENTITY_INT16 ; - else if (pref == GrB_INT32 ) op = GrB_IDENTITY_INT32 ; - else if (pref == GrB_INT64 ) op = GrB_IDENTITY_INT64 ; - else if (pref == GrB_UINT8 ) op = GrB_IDENTITY_UINT8 ; - else if (pref == GrB_UINT16) op = GrB_IDENTITY_UINT16 ; - else if (pref == GrB_UINT32) op = GrB_IDENTITY_UINT32 ; - else if (pref == GrB_UINT64) op = GrB_IDENTITY_UINT64 ; - else if (pref == GrB_FP32 ) op = GrB_IDENTITY_FP32 ; - else if (pref == GrB_FP64 ) op = GrB_IDENTITY_FP64 ; - #if 0 - else if (pref == GxB_FC32 ) op = GxB_IDENTITY_FC32 ; - else if (pref == GxB_FC64 ) op = GxB_IDENTITY_FC64 ; - #endif - else CATCH (GrB_NOT_IMPLEMENTED) ; // unsupported type - - GRB_TRY (GrB_apply (A2, NULL, NULL, op, A, NULL)) ; - } - - if (A2 != NULL) - { - GrB_free (&A) ; - A = A2 ; - A2 = NULL ; - GRB_TRY (GrB_wait (A, GrB_MATERIALIZE)) ; - } - - //-------------------------------------------------------------------------- - // construct the initial graph - //-------------------------------------------------------------------------- - - bool A_is_symmetric = - (n == 134217726 || // HACK for kron - n == 134217728) ; // HACK for urand - - LAGraph_Kind G_kind = A_is_symmetric ? LAGraph_ADJACENCY_UNDIRECTED : - LAGraph_ADJACENCY_DIRECTED ; - LAGRAPH_TRY (LAGraph_New (G, &A, G_kind, msg)) ; - // LAGRAPH_TRY (LAGraph_Graph_Print (*G, 2, stdout, msg)) ; - - //-------------------------------------------------------------------------- - // remove self-edges, if requested - //-------------------------------------------------------------------------- - - if (remove_self_edges) - { - LAGRAPH_TRY (LAGraph_DeleteSelfEdges (*G, msg)) ; - } - // LAGRAPH_TRY (LAGraph_Graph_Print (*G, 2, stdout, msg)) ; - - //-------------------------------------------------------------------------- - // ensure all entries are > 0, if requested - //-------------------------------------------------------------------------- - - if (!structural && ensure_positive) - { - // drop explicit zeros (FUTURE: make this a utility function) - GrB_IndexUnaryOp idxop = NULL ; - if (atype == GrB_BOOL ) idxop = GrB_VALUENE_BOOL ; - else if (atype == GrB_INT8 ) idxop = GrB_VALUENE_INT8 ; - else if (atype == GrB_INT16 ) idxop = GrB_VALUENE_INT16 ; - else if (atype == GrB_INT32 ) idxop = GrB_VALUENE_INT32 ; - else if (atype == GrB_INT64 ) idxop = GrB_VALUENE_INT64 ; - else if (atype == GrB_UINT8 ) idxop = GrB_VALUENE_UINT8 ; - else if (atype == GrB_UINT16) idxop = GrB_VALUENE_UINT16 ; - else if (atype == GrB_UINT32) idxop = GrB_VALUENE_UINT32 ; - else if (atype == GrB_UINT64) idxop = GrB_VALUENE_UINT64 ; - else if (atype == GrB_FP32 ) idxop = GrB_VALUENE_FP32 ; - else if (atype == GrB_FP64 ) idxop = GrB_VALUENE_FP64 ; - #if 0 - else if (atype == GxB_FC32 ) idxop = GxB_VALUENE_FC32 ; - else if (atype == GxB_FC64 ) idxop = GxB_VALUENE_FC64 ; - #endif - if (idxop != NULL) - { - GRB_TRY (GrB_select ((*G)->A, NULL, NULL, idxop, (*G)->A, 0, NULL)); - } - - // A = abs (A) - GrB_UnaryOp op = NULL ; - if (atype == GrB_INT8 ) op = GrB_ABS_INT8 ; - else if (atype == GrB_INT16 ) op = GrB_ABS_INT16 ; - else if (atype == GrB_INT32 ) op = GrB_ABS_INT32 ; - else if (atype == GrB_INT64 ) op = GrB_ABS_INT64 ; - else if (atype == GrB_FP32 ) op = GrB_ABS_FP32 ; - else if (atype == GrB_FP64 ) op = GrB_ABS_FP64 ; - #if 0 - else if (atype == GxB_FC32 ) op = GxB_ABS_FC32 ; - else if (atype == GxB_FC64 ) op = GxB_ABS_FC64 ; - #endif - if (op != NULL) - { - GRB_TRY (GrB_apply ((*G)->A, NULL, NULL, op, (*G)->A, NULL)) ; - } - } - - //-------------------------------------------------------------------------- - // determine the graph properies - //-------------------------------------------------------------------------- - - // LAGRAPH_TRY (LAGraph_Graph_Print (*G, 2, stdout, msg)) ; - - if (!A_is_symmetric) - { - // compute G->AT and determine if A has a symmetric structure - LAGRAPH_TRY (LAGraph_Cached_IsSymmetricStructure (*G, msg)) ; - if (((*G)->is_symmetric_structure == LAGraph_TRUE) && structural) - { - // if G->A has a symmetric structure, declare the graph undirected - // and free G->AT since it isn't needed. - (*G)->kind = LAGraph_ADJACENCY_UNDIRECTED ; - GRB_TRY (GrB_Matrix_free (&((*G)->AT))) ; - } - else if (make_symmetric) - { - // make sure G->A is symmetric - bool sym ; - LAGRAPH_TRY (LAGraph_Matrix_IsEqual (&sym, (*G)->A, (*G)->AT, msg)); - if (!sym) - { - printf ("forcing G-> to be symmetric (via A = A+A')\n") ; - GrB_BinaryOp op = NULL ; - GrB_Type type ; - if (atype == GrB_BOOL ) op = GrB_LOR ; - else if (atype == GrB_INT8 ) op = GrB_PLUS_INT8 ; - else if (atype == GrB_INT16 ) op = GrB_PLUS_INT16 ; - else if (atype == GrB_INT32 ) op = GrB_PLUS_INT32 ; - else if (atype == GrB_INT64 ) op = GrB_PLUS_INT64 ; - else if (atype == GrB_UINT8 ) op = GrB_PLUS_UINT8 ; - else if (atype == GrB_UINT16) op = GrB_PLUS_UINT16 ; - else if (atype == GrB_UINT32) op = GrB_PLUS_UINT32 ; - else if (atype == GrB_UINT64) op = GrB_PLUS_UINT64 ; - else if (atype == GrB_FP32 ) op = GrB_PLUS_FP32 ; - else if (atype == GrB_FP64 ) op = GrB_PLUS_FP64 ; - #if 0 - else if (type == GxB_FC32 ) op = GxB_PLUS_FC32 ; - else if (type == GxB_FC64 ) op = GxB_PLUS_FC64 ; - #endif - else CATCH (GrB_NOT_IMPLEMENTED) ; // unknown type - GRB_TRY (GrB_eWiseAdd ((*G)->A, NULL, NULL, op, - (*G)->A, (*G)->AT, NULL)) ; - } - // G->AT is not required - GRB_TRY (GrB_Matrix_free (&((*G)->AT))) ; - (*G)->kind = LAGraph_ADJACENCY_UNDIRECTED ; - (*G)->is_symmetric_structure = LAGraph_TRUE ; - } - } - // LAGRAPH_TRY (LAGraph_Graph_Print (*G, 2, stdout, msg)) ; - - //-------------------------------------------------------------------------- - // generate 64 random source nodes, if requested but not provided on input - //-------------------------------------------------------------------------- - - #define NSOURCES 64 - - if (src_nodes != NULL && (*src_nodes == NULL)) - { - src_type = GrB_UINT64; - GRB_TRY (GrB_Matrix_new (src_nodes, src_type, NSOURCES, 1)) ; - srand (1) ; - for (int k = 0 ; k < NSOURCES ; k++) - { - uint64_t i = 1 + (rand ( ) % n) ; // in range 1 to n - // src_nodes [k] = i - GRB_TRY (GrB_Matrix_setElement (*src_nodes, i, k, 0)) ; - } - } - - if (src_nodes != NULL) - { - GRB_TRY (GrB_wait (*src_nodes, GrB_MATERIALIZE)) ; - } - - //-------------------------------------------------------------------------- - // free workspace, print a summary of the graph, and return result - //-------------------------------------------------------------------------- - - t_read = LAGraph_WallClockTime ( ) - t_read ; - printf ("read time: %g\n", t_read) ; - - LG_FREE_WORK ; - // LAGRAPH_TRY (LAGraph_Graph_Print (*G, LAGraph_SHORT, stdout, msg)) ; - return (GrB_SUCCESS) ; -} - -//------------------------------------------------------------------------------ -// demo_init: initialize LAGraph for a demo -//------------------------------------------------------------------------------ - -#undef LG_FREE_WORK -#undef LG_FREE_ALL -#define LG_FREE_ALL ; - -static inline int demo_init (bool burble) -{ - char msg [LAGRAPH_MSG_LEN] ; - msg [0] = '\0' ; - - #ifdef __linux__ - // Use mallopt to speedup malloc and free on Linux. Otherwise, it can take - // several seconds to free a large block of memory. For this to be - // effective, demo_init must be called before calling malloc/free, and - // before calling LAGraph_Init. - mallopt (M_MMAP_MAX, 0) ; // disable mmap; it's too slow - mallopt (M_TRIM_THRESHOLD, -1) ; // disable sbrk trimming - mallopt (M_TOP_PAD, 16*1024*1024) ; // increase padding to speedup malloc - #endif - -#if 0 - // just use the CPU - LAGRAPH_TRY (LAGraph_Init (NULL)) ; -#else - // use the GPU - // rmm_wrap_initialize (rmm_wrap_managed, INT32_MAX, INT64_MAX, 1) ; - rmm_wrap_initialize_all_same (rmm_wrap_managed, 256 * 1000000L, 256 * 100000000L, 1) ; - LAGRAPH_TRY (LAGr_Init (GxB_NONBLOCKING_GPU, rmm_wrap_malloc, - rmm_wrap_calloc, rmm_wrap_realloc, rmm_wrap_free, NULL)) ; - GxB_set (GxB_GPU_CONTROL, GxB_GPU_ALWAYS) ; -#endif - - #if LAGRAPH_SUITESPARSE - printf ("include: %s v%d.%d.%d [%s]\n", - GxB_IMPLEMENTATION_NAME, - GxB_IMPLEMENTATION_MAJOR, - GxB_IMPLEMENTATION_MINOR, - GxB_IMPLEMENTATION_SUB, - GxB_IMPLEMENTATION_DATE) ; - char *s ; - GxB_get (GxB_LIBRARY_NAME, &s) ; printf ("library: %s ", s) ; - int version [3] ; - GxB_get (GxB_LIBRARY_VERSION, version) ; - printf ("v%d.%d.%d ", version [0], version [1], version [2]) ; - GxB_get(GxB_LIBRARY_DATE, &s) ; printf ("[%s]\n", s) ; - GRB_TRY (GxB_set (GxB_BURBLE, burble)) ; - #else - printf ("\n") ; - printf ("###########################################################\n") ; - printf ("### Vanilla GraphBLAS ... do not publish these results! ###\n") ; - printf ("###########################################################\n") ; - #endif - return (GrB_SUCCESS) ; -} - -#undef LG_FREE_ALL -#endif diff --git a/src/benchmark/tc_gpu_demo.c b/src/benchmark/tc_gpu_demo.c deleted file mode 100644 index 5a5f530586..0000000000 --- a/src/benchmark/tc_gpu_demo.c +++ /dev/null @@ -1,287 +0,0 @@ -//------------------------------------------------------------------------------ -// LAGraph/src/benchmark/tc_demo.c: benchmark for LAGr_TriangleCount_GPU -//------------------------------------------------------------------------------ - -// 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 - -//------------------------------------------------------------------------------ - -// Usage: test_tc < matrixmarketfile.mtx -// test_tc matrixmarketfile.mtx -// test_tc matrixmarketfile.grb - -// Known triangle counts: -// kron: 106873365648 -// urand: 5378 -// twitter: 34824916864 -// web: 84907041475 -// road: 438804 - -#include "LAGraph_demo_GPU.h" - -#define NTHREAD_LIST 1 -// #define NTHREAD_LIST 2 -#define THREAD_LIST 0 - -// #define NTHREAD_LIST 6 -// #define THREAD_LIST 64, 32, 24, 12, 8, 4 - -#define LG_FREE_ALL \ -{ \ - LAGraph_Delete (&G, NULL) ; \ - GrB_free (&A) ; \ -} - -char t [256] ; - -char *method_name (int method, int sorting) -{ - char *s ; - switch (method) - { - case LAGr_TriangleCount_AutoMethod: s = "default (Sandia_LUT) " ; break ; - case LAGr_TriangleCount_Burkhardt: s = "Burkhardt: sum ((A^2) .* A) / 6" ; break ; - case LAGr_TriangleCount_Cohen: s = "Cohen: sum ((L*U) .* A) / 2" ; break ; - case LAGr_TriangleCount_Sandia_LL: s = "Sandia_LL: sum ((L*L) .* L) " ; break ; - case LAGr_TriangleCount_Sandia_UU: s = "Sandia_UU: sum ((U*U) .* U) " ; break ; - case LAGr_TriangleCount_Sandia_LUT: s = "Sandia_LUT: sum ((L*U') .* L) " ; break ; - case LAGr_TriangleCount_Sandia_ULT: s = "Sandia_ULT: sum ((U*L') .* U) " ; break ; - default: abort ( ) ; - } - - if (sorting == LAGr_TriangleCount_Descending) sprintf (t, "%s sort: descending degree", s) ; - else if (sorting == LAGr_TriangleCount_Ascending) sprintf (t, "%s ascending degree", s) ; - else if (sorting == LAGr_TriangleCount_AutoSort) sprintf (t, "%s auto-sort", s) ; - else sprintf (t, "%s sort: none", s) ; - return (t) ; -} - - -void print_method (FILE *f, int method, int sorting) -{ - fprintf (f, "%s\n", method_name (method, sorting)) ; -} - -int main (int argc, char **argv) -{ - - //-------------------------------------------------------------------------- - // initialize LAGraph and GraphBLAS - //-------------------------------------------------------------------------- - - char msg [LAGRAPH_MSG_LEN] ; - - GrB_Matrix A = NULL ; - LAGraph_Graph G = NULL ; - - // start GraphBLAS and LAGraph - bool burble = false ; - demo_init (burble) ; - - int ntrials = 3 ; - // ntrials = 1 ; // HACK - printf ("# of trials: %d\n", ntrials) ; - - int nt = NTHREAD_LIST ; - int Nthreads [20] = { 0, THREAD_LIST } ; - int nthreads_max, nthreads_outer, nthreads_inner ; - LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_outer, &nthreads_inner, msg)) ; - nthreads_max = nthreads_outer * nthreads_inner ; - if (Nthreads [1] == 0) - { - // create thread list automatically - Nthreads [1] = nthreads_max ; - for (int t = 2 ; t <= nt ; t++) - { - Nthreads [t] = Nthreads [t-1] / 2 ; - if (Nthreads [t] == 0) nt = t-1 ; - } - } - printf ("threads to test: ") ; - for (int t = 1 ; t <= nt ; t++) - { - int nthreads = Nthreads [t] ; - if (nthreads > nthreads_max) continue ; - printf (" %d", nthreads) ; - } - printf ("\n") ; - - //-------------------------------------------------------------------------- - // read in the graph - //-------------------------------------------------------------------------- - - char *matrix_name = (argc > 1) ? argv [1] : "stdin" ; - LAGRAPH_TRY (readproblem (&G, NULL, - true, true, true, NULL, false, argc, argv)) ; - LAGRAPH_TRY (LAGraph_Graph_Print (G, LAGraph_SHORT, stdout, msg)) ; - - // determine the cached out degree property - LAGRAPH_TRY (LAGraph_Cached_OutDegree (G, msg)) ; - - GrB_Index n, nvals ; - GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; - GRB_TRY (GrB_Matrix_nvals (&nvals, G->A)) ; - - //-------------------------------------------------------------------------- - // triangle counting - //-------------------------------------------------------------------------- - - GrB_Index ntriangles, ntsimple = 0 ; - -#if 0 - // check # of triangles - double tsimple = LAGraph_WallClockTime ( ) ; - LAGRAPH_TRY (LG_check_tri (&ntsimple, G, NULL)) ; - tsimple = LAGraph_WallClockTime ( ) - tsimple ; - printf ("# of triangles: %" PRId64 " slow time: %g sec\n", - ntsimple, tsimple) ; -#endif - - // warmup for more accurate timing, and also print # of triangles - double ttot = LAGraph_WallClockTime ( ) ; - printf ("\nwarmup method: ") ; -// int presort = LAGr_TriangleCount_AutoSort ; // = 0 (auto selection) - int presort = LAGr_TriangleCount_NoSort ; // HACK - print_method (stdout, 6, presort) ; - - // warmup method: - // LAGr_TriangleCount_Sandia_ULT: sum (sum ((U * L') .* U)) - GxB_set (GxB_GPU_CONTROL, GxB_GPU_NEVER) ; - LAGr_TriangleCount_Method method = LAGr_TriangleCount_Sandia_ULT ; - LAGRAPH_TRY (LAGr_TriangleCount_GPU (&ntriangles, G, &method, &presort, msg)) ; - printf ("# of triangles: %" PRIu64 "\n", ntriangles) ; - print_method (stdout, 6, presort) ; - ttot = LAGraph_WallClockTime ( ) - ttot ; - printf ("nthreads: %3d time: %12.6f rate: %6.2f (Sandia_ULT, one trial)\n", - nthreads_max, ttot, 1e-6 * nvals / ttot) ; - - // warmup method WITH GPU: - // LAGr_TriangleCount_Sandia_ULT: sum (sum ((U * L') .* U)) - GrB_Index ntriangles_gpu ; - GxB_set (GxB_GPU_CONTROL, GxB_GPU_ALWAYS) ; - LAGr_TriangleCount_Method method = LAGr_TriangleCount_Sandia_ULT ; - LAGRAPH_TRY (LAGr_TriangleCount_GPU (&ntriangles_gpu, G, &method, &presort, msg)) ; - printf ("# of triangles: %" PRIu64 " (GPU)\n", ntriangles_gpu) ; - print_method (stdout, 6, presort) ; - ttot = LAGraph_WallClockTime ( ) - ttot ; - printf ("nthreads: %3d time: %12.6f rate: %6.2f (Sandia_ULT, one trial)\n", - nthreads_max, ttot, 1e-6 * nvals / ttot) ; - - if (ntriangles_gpu != ntsimple) - { - printf ("wrong # triangles: %g %g\n", (double) ntriangles, - (double) ntsimple) ; - fflush (stdout) ; - fflush (stderr) ; - abort ( ) ; - } - - GxB_set (GxB_GPU_CONTROL, GxB_GPU_NEVER) ; - presort = LAGr_TriangleCount_AutoSort ; // = 0 (auto selection) - -#if 0 - if (ntriangles != ntsimple) - { - printf ("wrong # triangles: %g %g\n", (double) ntriangles, - (double) ntsimple) ; - abort ( ) ; - } -#endif - - double t_best = INFINITY ; - int method_best = -1 ; - int nthreads_best = -1 ; - int sorting_best = 0 ; - - // kron: input graph: nodes: 134217726 edges: 4223264644 - // fails on methods 3 and 4. - - // just try methods 5 and 6 - // for (int method = 5 ; method <= 6 ; method++) - - // try all methods 3 to 5 -// for (int method = 3 ; method <= 5 ; method++) - for (int method = 1 ; method <= 1 ; method++) // HACK - { - // for (int sorting = -1 ; sorting <= 2 ; sorting++) - -// int sorting = LAGr_TriangleCount_AutoSort ; // just use auto-sort - int sorting = LAGr_TriangleCount_NoSort ; // HACK - { - printf ("\nMethod: ") ; print_method (stdout, method, sorting) ; - if (n == 134217726 && method < 5) - { - printf ("kron fails on method %d; skipped\n", method) ; - continue ; - } - if (n != 134217728 && method < 5) - { - printf ("all but urand is slow with method %d: skipped\n", - method) ; - continue ; - } - - for (int t = 1 ; t <= nt ; t++) - { - int nthreads = Nthreads [t] ; - if (nthreads > nthreads_max) continue ; - LAGRAPH_TRY (LAGraph_SetNumThreads (1, nthreads, msg)) ; - GrB_Index nt2 ; - double ttot = 0, ttrial [100] ; - LAGr_TriangleCount_Presort p ; - LAGr_TriangleCount_Method m ; - for (int trial = 0 ; trial < ntrials ; trial++) - { - double tt = LAGraph_WallClockTime ( ) ; - m = method ; - p = sorting ; - LAGRAPH_TRY(LAGr_TriangleCount_GPU (&nt2, G, &m, &p, msg)); - ttrial [trial] = LAGraph_WallClockTime ( ) - tt ; - ttot += ttrial [trial] ; - printf ("trial %2d: %12.6f sec rate %6.2f # triangles: " - "%g\n", trial, ttrial [trial], - 1e-6 * nvals / ttrial [trial], (double) nt2) ; - } - ttot = ttot / ntrials ; - printf ("nthreads: %3d time: %12.6f rate: %6.2f", nthreads, - ttot, 1e-6 * nvals / ttot) ; - printf (" # of triangles: %" PRId64 " presort: %d\n", - ntriangles, (int) p) ; - if (nt2 != ntriangles) - { - printf ("Test failure!\n") ; - abort ( ) ; - } - fprintf (stderr, "\nMethod used: ") ; - print_method (stderr, m, p) ; - fprintf (stderr, "Avg: TC method%d.%d %3d: %10.3f sec: %s\n", - method, sorting, nthreads, ttot, matrix_name) ; - - if (ttot < t_best) - { - t_best = ttot ; - method_best = method ; - nthreads_best = nthreads ; - sorting_best = sorting ; - } - } - } - } - - printf ("\nBest method: ") ; - print_method (stdout, method_best, sorting_best) ; - printf ("nthreads: %3d time: %12.6f rate: %6.2f\n", - nthreads_best, t_best, 1e-6 * nvals / t_best) ; - LG_FREE_ALL ; - LAGRAPH_TRY (LAGraph_Finalize (msg)) ; - return (GrB_SUCCESS) ; -} diff --git a/src/benchmark/tc_gpu_old.c b/src/benchmark/tc_gpu_old.c deleted file mode 100644 index 1bbdcab877..0000000000 --- a/src/benchmark/tc_gpu_old.c +++ /dev/null @@ -1,341 +0,0 @@ -//------------------------------------------------------------------------------ -// LAGraph/src/benchmark/tc_demo.c: benchmark for LAGr_TriangleCount -//------------------------------------------------------------------------------ - -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. -// SPDX-License-Identifier: BSD-2-Clause -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. - -// Contributed by Timothy A. Davis, Texas A&M University - -//------------------------------------------------------------------------------ - -// Usage: test_tc < matrixmarketfile.mtx -// test_tc matrixmarketfile.mtx -// test_tc matrixmarketfile.grb - -// Known triangle counts: -// kron: 106873365648 -// urand: 5378 -// twitter: 34824916864 -// web: 84907041475 -// road: 438804 - -#include "LAGraph_demo_GPU.h" - -#define NTHREAD_LIST 2 -#define THREAD_LIST 40, 0 - -// #define NTHREAD_LIST 7 -// #define THREAD_LIST 64, 32, 24, 12, 8, 4, 0 - -#define LG_FREE_ALL \ -{ \ - LAGraph_Delete (&G, NULL) ; \ - GrB_free (&A) ; \ -} - -char t [256] ; - -char *method_name (int method, int sorting) -{ - char *s ; - switch (method) - { - case LAGraph_TriangleCount_Default: s = "default (SandiaDot) " ; break ; - case LAGraph_TriangleCount_Burkhardt: s = "Burkhardt: sum ((A^2) .* A) / 6" ; break ; - case LAGraph_TriangleCount_Cohen: s = "Cohen: sum ((L*U) .* A) / 2" ; break ; - case LAGraph_TriangleCount_Sandia: s = "Sandia: sum ((L*L) .* L) " ; break ; - case LAGraph_TriangleCount_Sandia2: s = "Sandia2: sum ((U*U) .* U) " ; break ; - case LAGraph_TriangleCount_SandiaDot: s = "SandiaDot: sum ((L*U') .* L) " ; break ; - case LAGraph_TriangleCount_SandiaDot2: s = "SandiaDot2: sum ((U*L') .* U) " ; break ; - default: abort ( ) ; - } - - if (sorting == LAGraph_TriangleCount_Descending) sprintf (t, "%s sort: descending degree", s) ; - else if (sorting == LAGraph_TriangleCount_Ascending) sprintf (t, "%s ascending degree", s) ; - else if (sorting == LAGraph_TriangleCount_AutoSort) sprintf (t, "%s auto-sort", s) ; - else sprintf (t, "%s sort: none", s) ; - return (t) ; -} - - -void print_method (FILE *f, int method, int sorting) -{ - fprintf (f, "%s\n", method_name (method, sorting)) ; -} - -int main (int argc, char **argv) -{ - - //-------------------------------------------------------------------------- - // initialize LAGraph and GraphBLAS - //-------------------------------------------------------------------------- - - char msg [LAGRAPH_MSG_LEN] ; - - GrB_Matrix A = NULL ; - LAGraph_Graph G = NULL ; - - // start GraphBLAS and LAGraph - bool burble = true ; - demo_init (burble) ; - - int ntrials = 5 ; - ntrials = 3 ; // HACK - printf ("# of trials: %d\n", ntrials) ; - - int nt = NTHREAD_LIST ; - int Nthreads [20] = { 0, THREAD_LIST } ; - int nthreads_max, nthreads_hi, nthreads_lo ; - LAGRAPH_TRY (LAGraph_GetNumThreads (&nthreads_hi, &nthreads_lo, msg)) ; - nthreads_max = nthreads_hi * nthreads_lo ; - if (Nthreads [1] == 0) - { - // create thread list automatically - Nthreads [1] = nthreads_max ; - for (int t = 2 ; t <= nt ; t++) - { - Nthreads [t] = Nthreads [t-1] / 2 ; - if (Nthreads [t] == 0) nt = t-1 ; - } - } - printf ("threads to test: ") ; - for (int t = 1 ; t <= nt ; t++) - { - int nthreads = Nthreads [t] ; - if (nthreads > nthreads_max) continue ; - printf (" %d", nthreads) ; - } - printf ("\n") ; - - //-------------------------------------------------------------------------- - // read in the graph - //-------------------------------------------------------------------------- - - char *matrix_name = (argc > 1) ? argv [1] : "stdin" ; - LAGRAPH_TRY (readproblem (&G, NULL, - true, true, true, NULL, false, argc, argv)) ; - LAGRAPH_TRY (LAGraph_DisplayGraph (G, LAGraph_SHORT, stdout, msg)) ; - - // determine the cached out degree property - LAGRAPH_TRY (LAGraph_Cached_OutDegree (G, msg)) ; - - GrB_Index n, nvals ; - GRB_TRY (GrB_Matrix_nrows (&n, G->A)) ; - GRB_TRY (GrB_Matrix_nvals (&nvals, G->A)) ; - -// printf ("Hack: force hypersparse\n") ; -// GxB_set (G->A, GxB_SPARSITY_CONTROL, GxB_HYPERSPARSE) ; - -#if 0 - // HACK: make sure G->A is non-iso - - // create an iterator - GxB_Iterator iterator ; - GxB_Iterator_new (&iterator) ; - // attach it to the matrix A - GrB_Info info = GxB_Matrix_Iterator_attach (iterator, G->A, NULL) ; - if (info < 0) { abort ( ) ; } - // seek to the first entry - info = GxB_Matrix_Iterator_seek (iterator, 1) ; - printf ("info %d\n", info) ; - while (info != GxB_EXHAUSTED) - { - // get the entry A(i,j) - GrB_Index i, j ; - GxB_Matrix_Iterator_getIndex (iterator, &i, &j) ; - // set it to 0 - printf ("setting A(%d,%d) = 0\n", (int) i, (int) j) ; - GRB_TRY (GrB_Matrix_setElement (G->A, 0, i, j)) ; - break ; - } - GrB_free (&iterator) ; - - GxB_print (G->A, 2) ; - GrB_wait (G->A, GrB_MATERIALIZE) ; - -#else - bool A_iso ; - GxB_Matrix_iso (&A_iso, A) ; - printf ("G->A iso: %d\n", A_iso) ; -#endif - - //-------------------------------------------------------------------------- - // triangle counting - //-------------------------------------------------------------------------- - - GrB_Index ntriangles, ntsimple = 0 ; - double tic [2], ttot ; - -#if 1 - // check # of triangles - LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; - LAGRAPH_TRY (LG_check_tri (&ntsimple, G, NULL)) ; - double tsimple ; - LAGRAPH_TRY (LAGraph_Toc (&tsimple, tic, NULL)) ; - printf ("# of triangles: %" PRId64 " slow time: %g sec\n", - ntsimple, tsimple) ; -#endif - - // warmup for more accurate timing, and also print # of triangles - printf ("\nwarmup method: ") ; -// int presort = LAGraph_TriangleCount_AutoSort ; // = 2 (auto selection) - int presort = LAGraph_TriangleCount_NoSort ; // HACK - print_method (stdout, 6, presort) ; - - // warmup method: without the GPU - // LAGraph_TriangleCount_SandiaDot2 = 6, // sum (sum ((U * L') .* U)) - GxB_set (GxB_GPU_CONTROL, GxB_GPU_NEVER) ; - LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; - LAGRAPH_TRY (LAGr_TriangleCount (&ntriangles, G, - LAGraph_TriangleCount_SandiaDot2, &presort, msg) ); - LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; - printf ("# of triangles: %" PRIu64 " (CPU)\n", ntriangles) ; - print_method (stdout, 6, presort) ; - printf ("nthreads: %3d time: %12.6f rate: %6.2f (SandiaDot2, one trial)\n", - nthreads_max, ttot, 1e-6 * nvals / ttot) ; - -#if 1 - if (ntriangles != ntsimple) - { - printf ("wrong # triangles: %g %g\n", (double) ntriangles, - (double) ntsimple) ; - fflush (stdout) ; - fflush (stderr) ; - // abort ( ) ; - } -#endif - - // warmup method: with the GPU - // LAGraph_TriangleCount_SandiaDot2 = 6, // sum (sum ((U * L') .* U)) - GrB_Index ntriangles_gpu ; - //presort = LAGraph_TriangleCount_NoSort ; //turn off sorting on GPU - GxB_set (GxB_GPU_CONTROL, GxB_GPU_ALWAYS) ; - LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; - LAGRAPH_TRY (LAGr_TriangleCount (&ntriangles_gpu, G, - LAGraph_TriangleCount_SandiaDot2, &presort, msg) ); - LAGRAPH_TRY (LAGraph_Toc (&ttot, tic, NULL)) ; - printf ("# of triangles: %" PRIu64 " (GPU)\n", ntriangles_gpu) ; - print_method (stdout, 6, presort) ; - printf ("nthreads: %3d time: %12.6f rate: %6.2f (SandiaDot2, warmup GPU)\n", - nthreads_max, ttot, 1e-6 * nvals / ttot) ; - - GxB_set (GxB_GPU_CONTROL, GxB_GPU_NEVER) ; - - presort = LAGraph_TriangleCount_AutoSort ; // = 2 (auto selection) -#if 1 - if (ntriangles_gpu != ntsimple) - { - printf ("wrong # triangles: %g %g\n", (double) ntriangles_gpu, - (double) ntsimple) ; - fflush (stdout) ; - fflush (stderr) ; - // abort ( ) ; - } -#endif - - double t_best = INFINITY ; - int method_best = -1 ; - int nthreads_best = -1 ; - int sorting_best = 0 ; - - // kron: input graph: nodes: 134217726 edges: 4223264644 - // fails on methods 3 and 4. - - // just try methods 5 and 6 - // for (int method = 5 ; method <= 6 ; method++) - - // try all methods 3 to 5 - for (int method = 1 ; method <= 1 ; method++) - { - // for (int sorting = -1 ; sorting <= 2 ; sorting++) - - int sorting = LAGraph_TriangleCount_AutoSort ; // just use auto-sort - sorting = LAGraph_TriangleCount_NoSort ; // HACK: no-sort - { - printf ("\nMethod: ") ; - int presort ; - print_method (stdout, method, sorting) ; - if (n == 134217726 && method < 5) - { - printf ("kron fails on method %d; skipped\n", method) ; - continue ; - } - - for (int t = 1 ; t <= nt ; t++) - { - int nthreads = Nthreads [t] ; - if (nthreads > nthreads_max) continue ; - if (nthreads != 0) // Don't Use GPU - { - GxB_Global_Option_set( GxB_GLOBAL_GPU_CONTROL, GxB_GPU_NEVER); - printf(" CPU ONLY using %d threads", nthreads); - presort = LAGraph_TriangleCount_AutoSort ; // = 2 (auto selection) - } - else - { - nthreads = 40; - GxB_Global_Option_set( GxB_GLOBAL_GPU_CONTROL, GxB_GPU_ALWAYS); - printf(" GPU ONLY using %d threads", nthreads); - presort = LAGraph_TriangleCount_NoSort ; //turn off sorting on GPU - } - - LAGRAPH_TRY (LAGraph_SetNumThreads (1, nthreads, msg)) ; - GrB_Index nt2 ; - double ttot = 0, ttrial [100] ; - for (int trial = 0 ; trial < ntrials ; trial++) - { - LAGRAPH_TRY (LAGraph_Tic (tic, NULL)) ; - //presort = sorting ; - - LAGRAPH_TRY( - LAGr_TriangleCount (&nt2, G, method, - &presort, msg) ); - - LAGRAPH_TRY (LAGraph_Toc (&ttrial [trial], tic, NULL)) ; - ttot += ttrial [trial] ; - printf ("trial %2d: %12.6f sec rate %6.2f # triangles: " - "%g\n", trial, ttrial [trial], - 1e-6 * nvals / ttrial [trial], (double) nt2) ; - } - ttot = ttot / ntrials ; - printf ("nthreads: %3d time: %12.6f rate: %6.2f", nthreads, - ttot, 1e-6 * nvals / ttot) ; - printf (" # of triangles: %" PRId64 " presort: %d\n", - nt2, presort) ; - #if 1 - if (nt2 != ntriangles) - { - printf ("Test failure!\n") ; - fflush (stdout) ; - fflush (stderr) ; - // abort ( ) ; - } - #endif - fprintf (stderr, "Avg: TC method%d.%d %3d: %10.3f sec: %s\n", - method, sorting, nthreads, ttot, matrix_name) ; - - if (ttot < t_best) - { - t_best = ttot ; - method_best = method ; - nthreads_best = nthreads ; - sorting_best = sorting ; - } - } - } - } - - printf ("\nBest method: ") ; - print_method (stdout, method_best, sorting_best) ; - printf ("nthreads: %3d time: %12.6f rate: %6.2f\n", - nthreads_best, t_best, 1e-6 * nvals / t_best) ; - LG_FREE_ALL ; - LAGRAPH_TRY (LAGraph_Finalize (msg)) ; - // FIXME: - rmm_wrap_finalize ( ) ; - return (GrB_SUCCESS) ; -} - From 90406e78b1bf552c8d070e857b2ae610f43c624b Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Sat, 10 Dec 2022 21:36:46 -0600 Subject: [PATCH 41/53] do not #include if OpenMP not available --- experimental/algorithm/LAGraph_FastGraphletTransform.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/experimental/algorithm/LAGraph_FastGraphletTransform.c b/experimental/algorithm/LAGraph_FastGraphletTransform.c index f7bba1a28f..d751ff6664 100644 --- a/experimental/algorithm/LAGraph_FastGraphletTransform.c +++ b/experimental/algorithm/LAGraph_FastGraphletTransform.c @@ -69,7 +69,9 @@ #include "LG_internal.h" #include "LAGraphX.h" +#ifdef _OPENMP #include +#endif void sub_one_mult (int64_t *z, const int64_t *x) { (*z) = (*x) * ((*x)-1) ; } From 5e3a13bdd0100da57b2dd8aab50172e899da4f18 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Wed, 14 Dec 2022 14:17:09 -0600 Subject: [PATCH 42/53] contrib --- ContributionInstructions.txt => CONTRIBUTING.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) rename ContributionInstructions.txt => CONTRIBUTING.md (98%) diff --git a/ContributionInstructions.txt b/CONTRIBUTING.md similarity index 98% rename from ContributionInstructions.txt rename to CONTRIBUTING.md index cf5f8709df..6729a06cd6 100644 --- a/ContributionInstructions.txt +++ b/CONTRIBUTING.md @@ -1,4 +1,3 @@ -File: ContributionInstructions.txt: Thank you for your interest in contributing to the LAGraph project (“We” or “Us”). By making any Contribution to this project, you agree to the terms @@ -95,7 +94,7 @@ necessary permissions to make this Contribution. (c) The grant of rights under Section 2 does not violate any grant of rights which You have made to third parties, including Your employer. If You are an employee, You warrant that Your employer has approved this Agreement. If You are -less than eighteen years old, Uour parent or guardian must sign a printed +less than eighteen years old, Your parent or guardian must sign a printed version of this Agreement and send it to permission@sei.cmu.edu. (d) You shall make each Contribution in full compliance with U.S. export control From c6a22a62267f33ab364c40c5e62871631eeb41cd Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Wed, 14 Dec 2022 15:57:44 -0600 Subject: [PATCH 43/53] code of conduct, changelog, and FindLAGraph --- CMakeLists.txt | 2 +- CODE_OF_CONDUCT.md | 134 ++++++++++++++++++++++++++++++++ ChangeLog | 10 ++- cmake_modules/FindLAGraph.cmake | 64 ++++++++++++--- 4 files changed, 198 insertions(+), 12 deletions(-) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f7c32be6a..b3e1b3ab41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,7 +49,7 @@ cmake_policy ( SET CMP0048 NEW ) set ( CMAKE_MACOSX_RPATH TRUE ) # version of LAGraph -set ( LAGraph_DATE "Oct 28, 2022" ) +set ( LAGraph_DATE "Dec 14, 2022" ) set ( LAGraph_VERSION_MAJOR 1 ) set ( LAGraph_VERSION_MINOR 0 ) set ( LAGraph_VERSION_SUB 1 ) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..d2db6f80c0 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,134 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +[https://graphblas.org][GraphBLAS.org] by contacting the GraphBLAS Steering Committee. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations + diff --git a/ChangeLog b/ChangeLog index 6a91e87e08..a926b89d5b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,15 @@ -Version 1.0.1: Oct 28, 2022 +Version 1.0.1: Dec 14, 2022 * bug fix: LAGraph_MMWrite incorrectly created a Matrix Market file with "array pattern" format, which is invalid. + * header updates: with copyright info + * CONTRIBUTING.md: renamed the file + * CODE_OF_CONDUCT.md: added, from https://www.contributor-covenant.org + * FindGraphBLAS.cmake and FindLAGraph.cmake: revised to find both dynamic + and static libraries, and to find the version number from the include + file if it's not present in the filename of the library. + * LAGraph_FastGraphletTransform: now able to compile it when OpenMP + is not available. Version 1.0.0: Sept 20, 2022 diff --git a/cmake_modules/FindLAGraph.cmake b/cmake_modules/FindLAGraph.cmake index 9627a00ab7..a95c27fd44 100644 --- a/cmake_modules/FindLAGraph.cmake +++ b/cmake_modules/FindLAGraph.cmake @@ -23,7 +23,8 @@ This module defines the following variables: :: LAGRAPH_INCLUDE_DIR - where to find LAGraph.h, etc. - LAGRAPH_LIBRARY - LAGraph library + LAGRAPH_LIBRARY - dynamic LAGraph library + LAGRAPH_STATIC - static LAGraph library LAGRAPH_LIBRARIES - List of libraries when using LAGraph. LAGRAPH_FOUND - True if LAGraph found. @@ -50,29 +51,70 @@ version. find_path( LAGRAPH_INCLUDE_DIR NAMES LAGraph.h + HINTS ${LAGRAPH_ROOT} + HINTS ENV LAGRAPH_ROOT HINTS ${CMAKE_SOURCE_DIR}/../LAGraph - PATHS LAGRAPH_ROOT ENV LAGRAPH_ROOT PATH_SUFFIXES include Include ) -# "build/lib" for LAGraph -message ( STATUS "Look in " ${CMAKE_SOURCE_DIR}/../LAGraph/build ) +# dynamic LAGraph library find_library( LAGRAPH_LIBRARY NAMES lagraph + HINTS ${LAGRAPH_ROOT} + HINTS ENV LAGRAPH_ROOT HINTS ${CMAKE_SOURCE_DIR}/../LAGraph - PATHS LAGRAPH_ROOT ENV LAGRAPH_ROOT PATH_SUFFIXES lib build ) -# get version of .so using REALPATH +if ( MSVC ) + set ( STATIC_SUFFIX .lib ) +else ( ) + set ( STATIC_SUFFIX .a ) +endif ( ) + +# static LAGraph library +set ( save ${CMAKE_FIND_LIBRARY_SUFFIXES} ) +set ( CMAKE_FIND_LIBRARY_SUFFIXES ${STATIC_SUFFIX} ${CMAKE_FIND_LIBRARY_SUFFIXES} ) +find_library ( LAGRAPH_STATIC + NAMES lagraph + HINTS ${LAGRAPH_ROOT} + HINTS ENV LAGRAPH_ROOT + HINTS ${CMAKE_SOURCE_DIR}/../LAGraph + PATH_SUFFIXES lib build + ) +set ( CMAKE_FIND_LIBRARY_SUFFIXES ${save} ) + +# get version of the library from the dynamic library name get_filename_component(LAGRAPH_LIBRARY ${LAGRAPH_LIBRARY} REALPATH) string( REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" LAGRAPH_VERSION ${LAGRAPH_LIBRARY} ) -set(LAGRAPH_LIBRARIES ${LAGRAPH_LIBRARY}) + +if ( NOT LAGRAPH_VERSION ) + # if the version does not appear in the filename, read the include file. + # The LAGraph.h file includes the following lines: + # #define LAGRAPH_VERSION_MAJOR 1 + # #define LAGRAPH_VERSION_MINOR 0 + # #define LAGRAPH_VERSION_UPDATE 1 + file ( STRINGS ${LAGRAPH_INCLUDE_DIR}/LAGraph.h LAGRAPH_VER_MAJOR_STRING + REGEX "define LAGRAPH_VERSION_MAJOR " ) + file ( STRINGS ${LAGRAPH_INCLUDE_DIR}/LAGraph.h LAGRAPH_VER_MINOR_STRING + REGEX "define LAGRAPH_VERSION_MINOR " ) + file ( STRINGS ${LAGRAPH_INCLUDE_DIR}/LAGraph.h LAGRAPH_VER_UPDATE_STRING + REGEX "define LAGRAPH_VERSION_UPDATE " ) + message ( STATUS "major from LAGraph.h: ${LAGRAPH_VER_MAJOR_STRING}" ) + message ( STATUS "minor from LAGraph.h: ${LAGRAPH_VER_MINOR_STRING}" ) + message ( STATUS "update from LAGraph.h: ${LAGRAPH_VER_UPDATE_STRING}" ) + string ( REGEX MATCH "[0-9]+" LAGRAPH_VER_MAJOR ${LAGRAPH_VER_MAJOR_STRING} ) + string ( REGEX MATCH "[0-9]+" LAGRAPH_VER_MINOR ${LAGRAPH_VER_MINOR_STRING} ) + string ( REGEX MATCH "[0-9]+" LAGRAPH_VER_UPDATE ${LAGRAPH_VER_UPDATE_STRING} ) + set ( LAGRAPH_VERSION "${LAGRAPH_VER_MAJOR}.${LAGRAPH_VER_MINOR}.${LAGRAPH_VER_UPDATE}") +endif ( ) + +set ( LAGRAPH_LIBRARIES ${LAGRAPH_LIBRARY} ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args( @@ -84,13 +126,15 @@ find_package_handle_standard_args( mark_as_advanced( LAGRAPH_INCLUDE_DIR LAGRAPH_LIBRARY + LAGRAPH_STATIC LAGRAPH_LIBRARIES ) if ( LAGRAPH_FOUND ) - message ( STATUS "LAGraph include dir: " ${LAGRAPH_INCLUDE_DIR} ) - message ( STATUS "LAGraph library: " ${LAGRAPH_LIBRARY} ) - message ( STATUS "LAGraph version: " ${LAGRAPH_VERSION} ) + message ( STATUS "LAGraph version: " ${LAGRAPH_VERSION} ) + message ( STATUS "LAGraph include: " ${LAGRAPH_INCLUDE_DIR} ) + message ( STATUS "LAGraph library: " ${LAGRAPH_LIBRARY} ) + message ( STATUS "LAGraph static:: " ${LAGRAPH_STATIC} ) else ( ) message ( STATUS "LAGraph not found" ) endif ( ) From 36f830192a58481b93a6d93f1ebd6f4804a3ed04 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Wed, 14 Dec 2022 16:16:09 -0600 Subject: [PATCH 44/53] readme with new code of conduct --- README.md | 5 ++++- include/LAGraph.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 26c50b6da9..c0e091ab5d 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,10 @@ LAGraph contains the following files and folders: config: LAGraph.h.in, for constructing include/LAGraph.h - ContributionInstructions.txt: how to contributed to LAGraph + CONTRIBUTING.md: how to contributed to LAGraph + + CODE_OF_CONDUCT.md: code of conduct from + https://www.contributor-covenant.org/version/2/1/code_of_conduct.html Contributors.txt: list of contributors diff --git a/include/LAGraph.h b/include/LAGraph.h index e94c39d32c..5a3435a441 100644 --- a/include/LAGraph.h +++ b/include/LAGraph.h @@ -37,7 +37,7 @@ // See also the LAGraph_Version utility method, which returns these values. // These definitions are derived from LAGraph/CMakeLists.txt. -#define LAGRAPH_DATE "Oct 28, 2022" +#define LAGRAPH_DATE "Dec 14, 2022" #define LAGRAPH_VERSION_MAJOR 1 #define LAGRAPH_VERSION_MINOR 0 #define LAGRAPH_VERSION_UPDATE 1 From 2544b3b08f7da45fcae27569b1cb6451ca05273a Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Mon, 26 Dec 2022 17:20:42 -0600 Subject: [PATCH 45/53] vanilla case --- CMakeLists.txt | 2 +- ChangeLog | 5 ++++- Makefile | 3 +++ experimental/algorithm/LAGraph_lcc.c | 7 ++++--- experimental/algorithm/LAGraph_msf.c | 8 +++++--- experimental/test/test_lcc.c | 10 ++++++++-- experimental/test/test_msf.c | 8 ++++++++ experimental/test/test_scc.c | 8 ++++++++ experimental/utility/LAGraph_SSaveSet.c | 3 ++- include/LAGraph.h | 2 +- src/algorithm/LG_BreadthFirstSearch_SSGrB.c | 8 ++++---- src/benchmark/LAGraph_demo.h | 2 +- src/benchmark/sssp_demo.c | 4 ++-- src/test/test_BreadthFirstSearch.c | 2 ++ src/test/test_DeleteCached.c | 2 ++ src/test/test_DisplayGraph.c | 2 ++ src/test/test_IsEqual.c | 2 ++ src/test/test_KindName.c | 2 ++ src/test/test_New.c | 2 ++ src/test/test_TriangleCount.c | 2 ++ src/test/test_export.c | 2 ++ src/test/test_vector.c | 2 ++ src/utility/LAGraph_TypeFromName.c | 2 +- src/utility/LAGraph_TypeName.c | 6 +++--- 24 files changed, 73 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b3e1b3ab41..50d0d4d21a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,7 +49,7 @@ cmake_policy ( SET CMP0048 NEW ) set ( CMAKE_MACOSX_RPATH TRUE ) # version of LAGraph -set ( LAGraph_DATE "Dec 14, 2022" ) +set ( LAGraph_DATE "Dec 26, 2022" ) set ( LAGraph_VERSION_MAJOR 1 ) set ( LAGraph_VERSION_MINOR 0 ) set ( LAGraph_VERSION_SUB 1 ) diff --git a/ChangeLog b/ChangeLog index a926b89d5b..2f8ea74c0b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -Version 1.0.1: Dec 14, 2022 +Version 1.0.1: Dec 26, 2022 * bug fix: LAGraph_MMWrite incorrectly created a Matrix Market file with "array pattern" format, which is invalid. @@ -10,6 +10,9 @@ Version 1.0.1: Dec 14, 2022 file if it's not present in the filename of the library. * LAGraph_FastGraphletTransform: now able to compile it when OpenMP is not available. + * bug fix: LAGRAPH_VANILLA option fixed. Added "make vanilla" to the + Makefile. GxB_*_TypeName methods are required, even for a "vanilla" + GraphBLAS. Version 1.0.0: Sept 20, 2022 diff --git a/Makefile b/Makefile index 6e20eb754b..7d22a3dcbc 100644 --- a/Makefile +++ b/Makefile @@ -53,6 +53,9 @@ default: library library: ( cd build && cmake $(CMAKE_OPTIONS) .. && $(MAKE) --jobs=${JOBS} ) +vanilla: + ( cd build && cmake $(CMAKE_OPTIONS) -DLAGRAPH_VANILLA=1 .. && $(MAKE) --jobs=${JOBS} ) + # compile with -g for debugging debug: ( cd build && cmake $(CMAKE_OPTIONS) -DCMAKE_BUILD_TYPE=Debug .. && $(MAKE) --jobs=${JOBS} ) diff --git a/experimental/algorithm/LAGraph_lcc.c b/experimental/algorithm/LAGraph_lcc.c index 07aa3d5a3d..3586ae49b9 100644 --- a/experimental/algorithm/LAGraph_lcc.c +++ b/experimental/algorithm/LAGraph_lcc.c @@ -121,9 +121,6 @@ int LAGraph_lcc // compute lcc for all nodes in A char *msg ) { -#if !LAGRAPH_SUITESPARSE - LG_ASSERT (false, GrB_NOT_IMPLEMENTED) ; -#else //-------------------------------------------------------------------------- // check inputs @@ -141,6 +138,10 @@ int LAGraph_lcc // compute lcc for all nodes in A GrB_UnaryOp LAGraph_COMB_UNDIR_FP64 = NULL ; GrB_Info info ; +#if !LAGRAPH_SUITESPARSE + LG_ASSERT (false, GrB_NOT_IMPLEMENTED) ; +#else + // n = size of A (# of nodes in the graph) GrB_Index n ; GRB_TRY (GrB_Matrix_nrows (&n, A)) ; diff --git a/experimental/algorithm/LAGraph_msf.c b/experimental/algorithm/LAGraph_msf.c index 8926a94798..518ecc124f 100644 --- a/experimental/algorithm/LAGraph_msf.c +++ b/experimental/algorithm/LAGraph_msf.c @@ -118,9 +118,7 @@ int LAGraph_msf { LG_CLEAR_MSG ; -#if !LAGRAPH_SUITESPARSE - LG_ASSERT (false, GrB_NOT_IMPLEMENTED) ; -#else + GrB_Info info; GrB_Index n; GrB_Matrix S = NULL, T = NULL; @@ -135,6 +133,10 @@ int LAGraph_msf GxB_SelectOp s1 = NULL, s2 = NULL; if (result == NULL || A == NULL) return (GrB_NULL_POINTER) ; +#if !LAGRAPH_SUITESPARSE + LG_ASSERT (false, GrB_NOT_IMPLEMENTED) ; +#else + GrB_Index ncols ; GRB_TRY (GrB_Matrix_nrows (&n, A)); GRB_TRY (GrB_Matrix_ncols (&ncols, A)); diff --git a/experimental/test/test_lcc.c b/experimental/test/test_lcc.c index d838eae9b1..d96ee9b52f 100644 --- a/experimental/test/test_lcc.c +++ b/experimental/test/test_lcc.c @@ -127,6 +127,7 @@ const matrix_info files [ ] = void test_lcc (void) { LAGraph_Init (msg) ; + #if LAGRAPH_SUITESPARSE for (int k = 0 ; ; k++) { @@ -190,6 +191,9 @@ void test_lcc (void) OK (LAGraph_Delete (&G, msg)) ; } + #else + printf ("test skipped\n") ; + #endif LAGraph_Finalize (msg) ; } @@ -200,6 +204,7 @@ void test_lcc (void) void test_errors (void) { LAGraph_Init (msg) ; + #if LAGRAPH_SUITESPARSE snprintf (filename, LEN, LG_DATA_DIR "%s", "karate.mtx") ; FILE *f = fopen (filename, "r") ; @@ -221,16 +226,17 @@ void test_errors (void) printf ("\nresult: %d\n", result) ; TEST_CHECK (result == GrB_NULL_POINTER) ; - #if LAGRAPH_SUITESPARSE // G->A is held by column OK (GxB_set (G->A, GxB_FORMAT, GxB_BY_COL)) ; result = LAGraph_lcc (&c, G->A, true, true, t, msg) ; printf ("\nresult: %d\n", result) ; TEST_CHECK (result == GrB_INVALID_VALUE) ; TEST_CHECK (c == NULL) ; - #endif OK (LAGraph_Delete (&G, msg)) ; + #else + printf ("test skipped\n") ; + #endif LAGraph_Finalize (msg) ; } diff --git a/experimental/test/test_msf.c b/experimental/test/test_msf.c index 459373c6cf..f914793dfc 100644 --- a/experimental/test/test_msf.c +++ b/experimental/test/test_msf.c @@ -58,6 +58,7 @@ const matrix_info files [ ] = void test_msf (void) { LAGraph_Init (msg) ; + #if LAGRAPH_SUITESPARSE for (int k = 0 ; ; k++) { @@ -119,6 +120,9 @@ void test_msf (void) OK (LAGraph_Delete (&G, msg)) ; } + #else + printf ("test skipped\n") ; + #endif LAGraph_Finalize (msg) ; } @@ -129,6 +133,7 @@ void test_msf (void) void test_errors (void) { LAGraph_Init (msg) ; + #if LAGRAPH_SUITESPARSE // C and A are NULL int result = LAGraph_msf (NULL, NULL, true, msg) ; @@ -140,6 +145,9 @@ void test_errors (void) TEST_CHECK (result == GrB_DIMENSION_MISMATCH) ; OK (GrB_free (&A)) ; + #else + printf ("test skipped\n") ; + #endif LAGraph_Finalize (msg) ; } diff --git a/experimental/test/test_scc.c b/experimental/test/test_scc.c index d16667c6fd..cea92e42ff 100644 --- a/experimental/test/test_scc.c +++ b/experimental/test/test_scc.c @@ -98,6 +98,7 @@ const matrix_info files [ ] = void test_scc (void) { LAGraph_Init (msg) ; + #if LAGRAPH_SUITESPARSE for (int k = 0 ; ; k++) { @@ -148,6 +149,9 @@ void test_scc (void) OK (LAGraph_Delete (&G, msg)) ; } + #else + printf ("test skipped\n") ; + #endif LAGraph_Finalize (msg) ; } @@ -158,6 +162,7 @@ void test_scc (void) void test_errors (void) { LAGraph_Init (msg) ; + #if LAGRAPH_SUITESPARSE GrB_Vector c = NULL ; GrB_Matrix A = NULL ; @@ -174,6 +179,9 @@ void test_errors (void) OK (GrB_free (&c)) ; OK (GrB_free (&A)) ; + #else + printf ("test skipped\n") ; + #endif LAGraph_Finalize (msg) ; } diff --git a/experimental/utility/LAGraph_SSaveSet.c b/experimental/utility/LAGraph_SSaveSet.c index d0d8454754..19d9fe8fd4 100644 --- a/experimental/utility/LAGraph_SSaveSet.c +++ b/experimental/utility/LAGraph_SSaveSet.c @@ -104,7 +104,8 @@ int LAGraph_SSaveSet // save a set of matrices from a *.lagraph file estimate, sizeof (uint8_t), msg)) ; GRB_TRY (GrB_Matrix_serialize (Contents [i].blob, (GrB_Index *) &(Contents [i].blob_size), Set [i])) ; - LG_TRY (LAGraph_Realloc (&(Contents [i].blob_size), + LG_TRY (LAGraph_Realloc ((void **) &(Contents [i].blob), + (size_t) Contents [i].blob_size, estimate, sizeof (uint8_t), msg)) ; } #endif diff --git a/include/LAGraph.h b/include/LAGraph.h index 5a3435a441..a46a569759 100644 --- a/include/LAGraph.h +++ b/include/LAGraph.h @@ -37,7 +37,7 @@ // See also the LAGraph_Version utility method, which returns these values. // These definitions are derived from LAGraph/CMakeLists.txt. -#define LAGRAPH_DATE "Dec 14, 2022" +#define LAGRAPH_DATE "Dec 26, 2022" #define LAGRAPH_VERSION_MAJOR 1 #define LAGRAPH_VERSION_MINOR 0 #define LAGRAPH_VERSION_UPDATE 1 diff --git a/src/algorithm/LG_BreadthFirstSearch_SSGrB.c b/src/algorithm/LG_BreadthFirstSearch_SSGrB.c index 9e2795c809..adc639aad0 100644 --- a/src/algorithm/LG_BreadthFirstSearch_SSGrB.c +++ b/src/algorithm/LG_BreadthFirstSearch_SSGrB.c @@ -62,16 +62,16 @@ int LG_BreadthFirstSearch_SSGrB // check inputs //-------------------------------------------------------------------------- -#if !LAGRAPH_SUITESPARSE - LG_ASSERT (false, GrB_NOT_IMPLEMENTED) ; -#else - LG_CLEAR_MSG ; GrB_Vector q = NULL ; // the current frontier GrB_Vector w = NULL ; // to compute work remaining GrB_Vector pi = NULL ; // parent vector GrB_Vector v = NULL ; // level vector +#if !LAGRAPH_SUITESPARSE + LG_ASSERT (false, GrB_NOT_IMPLEMENTED) ; +#else + bool compute_level = (level != NULL) ; bool compute_parent = (parent != NULL) ; if (compute_level ) (*level ) = NULL ; diff --git a/src/benchmark/LAGraph_demo.h b/src/benchmark/LAGraph_demo.h index e60c6f41b4..ed55a77d54 100644 --- a/src/benchmark/LAGraph_demo.h +++ b/src/benchmark/LAGraph_demo.h @@ -48,7 +48,7 @@ #define LEN LAGRAPH_BIN_HEADER #if !LAGRAPH_SUITESPARSE -#error "SuiteSparse:GraphBLAS v6.0.0 or later is required" +#warning "SuiteSparse:GraphBLAS v7.1.0 or later is required" #endif //------------------------------------------------------------------------------ diff --git a/src/benchmark/sssp_demo.c b/src/benchmark/sssp_demo.c index a39472e20a..961b1ab3b7 100644 --- a/src/benchmark/sssp_demo.c +++ b/src/benchmark/sssp_demo.c @@ -148,8 +148,8 @@ int main (int argc, char **argv) Delta, msg)) ; ttrial = LAGraph_WallClockTime ( ) - ttrial ; - printf ("sssp15: threads: %2d trial: %2d source %g " - "time: %10.4f sec\n", nthreads, trial, (double) src, ttrial) ; + printf ("sssp15: threads: %2d trial: %2d source %12" PRId64 + " time: %10.4f sec\n", nthreads, trial, src, ttrial) ; total_time += ttrial ; #if LG_CHECK_RESULT diff --git a/src/test/test_BreadthFirstSearch.c b/src/test/test_BreadthFirstSearch.c index 117ca441d7..b3703426a4 100644 --- a/src/test/test_BreadthFirstSearch.c +++ b/src/test/test_BreadthFirstSearch.c @@ -670,6 +670,8 @@ TEST_LIST = { {"BreadthFirstSearch_level", test_BreadthFirstSearch_level}, {"BreadthFirstSearch_both", test_BreadthFirstSearch_both}, {"BreadthFirstSearch_many", test_BreadthFirstSearch_many}, + #if LAGRAPH_SUITESPARSE {"BreadthFirstSearch_brutal", test_bfs_brutal }, + #endif {NULL, NULL} } ; diff --git a/src/test/test_DeleteCached.c b/src/test/test_DeleteCached.c index 82b872c7be..7aa11721f1 100644 --- a/src/test/test_DeleteCached.c +++ b/src/test/test_DeleteCached.c @@ -194,6 +194,8 @@ void test_del_brutal (void) TEST_LIST = { { "test_DeleteCached", test_DeleteCached }, + #if LAGRAPH_SUITESPARSE { "test_DeleteCached_brutal", test_del_brutal }, + #endif { NULL, NULL } } ; diff --git a/src/test/test_DisplayGraph.c b/src/test/test_DisplayGraph.c index 8cb707ddeb..297000c53d 100644 --- a/src/test/test_DisplayGraph.c +++ b/src/test/test_DisplayGraph.c @@ -294,7 +294,9 @@ void test_Graph_Print_brutal (void) TEST_LIST = { { "Graph_Print", test_Graph_Print }, + #if LAGRAPH_SUITESPARSE { "Graph_Print_brutal", test_Graph_Print_brutal }, + #endif { "Graph_Print_failures", test_Graph_Print_failures }, { NULL, NULL } } ; diff --git a/src/test/test_IsEqual.c b/src/test/test_IsEqual.c index d4ab4c844c..86cab86dc6 100644 --- a/src/test/test_IsEqual.c +++ b/src/test/test_IsEqual.c @@ -445,6 +445,8 @@ TEST_LIST = { "IsEqual", test_IsEqual }, { "Vector_IsEqual", test_Vector_IsEqual }, { "IsEqual_failures", test_IsEqual_failures }, + #if LAGRAPH_SUITESPARSE { "IsEqual_brutal", test_IsEqual_brutal }, + #endif { NULL, NULL } } ; diff --git a/src/test/test_KindName.c b/src/test/test_KindName.c index 7fdd9ae8ff..c244cb0ba5 100644 --- a/src/test/test_KindName.c +++ b/src/test/test_KindName.c @@ -91,6 +91,8 @@ void test_KindName_brutal (void) TEST_LIST = { { "KindName", test_KindName }, + #if LAGRAPH_SUITESPARSE { "KindName_brutal", test_KindName_brutal }, + #endif { NULL, NULL } } ; diff --git a/src/test/test_New.c b/src/test/test_New.c index 49b2fc358d..05def4143f 100644 --- a/src/test/test_New.c +++ b/src/test/test_New.c @@ -182,6 +182,8 @@ TEST_LIST = { { "New", test_New }, { "New_failures", test_New_failures }, + #if LAGRAPH_SUITESPARSE { "New_brutal", test_New_brutal }, + #endif { NULL, NULL } } ; diff --git a/src/test/test_TriangleCount.c b/src/test/test_TriangleCount.c index 8f5b6d1e03..e687f441b9 100644 --- a/src/test/test_TriangleCount.c +++ b/src/test/test_TriangleCount.c @@ -483,6 +483,8 @@ TEST_LIST = { {"TriangleCount" , test_TriangleCount}, {"TriangleCount_many" , test_TriangleCount_many}, {"TriangleCount_autosort", test_TriangleCount_autosort}, + #if LAGRAPH_SUITESPARSE {"TriangleCount_brutal" , test_TriangleCount_brutal}, + #endif {NULL, NULL} }; diff --git a/src/test/test_export.c b/src/test/test_export.c index 4190c1c7ff..59ce082734 100644 --- a/src/test/test_export.c +++ b/src/test/test_export.c @@ -212,6 +212,8 @@ void test_export_brutal (void) //**************************************************************************** TEST_LIST = { {"test_export", test_export }, + #if LAGRAPH_SUITESPARSE {"test_export_brutal", test_export_brutal }, + #endif {NULL, NULL} }; diff --git a/src/test/test_vector.c b/src/test/test_vector.c index 66493e08ac..6c9c4a29f7 100644 --- a/src/test/test_vector.c +++ b/src/test/test_vector.c @@ -104,6 +104,8 @@ void test_vector_brutal (void) TEST_LIST = { { "vector", test_vector }, + #if LAGRAPH_SUITESPARSE { "vector_brutal", test_vector_brutal }, + #endif { NULL, NULL } } ; diff --git a/src/utility/LAGraph_TypeFromName.c b/src/utility/LAGraph_TypeFromName.c index 5b238e2dfe..086d6b3efa 100644 --- a/src/utility/LAGraph_TypeFromName.c +++ b/src/utility/LAGraph_TypeFromName.c @@ -69,7 +69,7 @@ int LAGraph_TypeFromName else { (*type) = NULL ; - LG_ASSERT_MSG (false, GrB_NOT_IMPLEMENTED, + LG_ASSERT_MSGF (false, GrB_NOT_IMPLEMENTED, "type \"%s\" not supported", name) ; } return (GrB_SUCCESS) ; diff --git a/src/utility/LAGraph_TypeName.c b/src/utility/LAGraph_TypeName.c index 151b9cba6b..3a7b06fbe6 100644 --- a/src/utility/LAGraph_TypeName.c +++ b/src/utility/LAGraph_TypeName.c @@ -79,7 +79,7 @@ int LAGraph_Matrix_TypeName // determine the name of the type of the GrB_Matrix A //-------------------------------------------------------------------------- - #if LAGRAPH_SUITESPARSE + #if 1 // LAGRAPH_SUITESPARSE return (GxB_Matrix_type_name (name, A)) ; #else name [0] = '\0' ; @@ -113,7 +113,7 @@ int LAGraph_Vector_TypeName // determine the name of the type of the GrB_Vector v //-------------------------------------------------------------------------- - #if LAGRAPH_SUITESPARSE + #if 1 // LAGRAPH_SUITESPARSE return (GxB_Vector_type_name (name, v)) ; #else name [0] = '\0' ; @@ -147,7 +147,7 @@ int LAGraph_Scalar_TypeName // determine the name of the type of the GrB_Scalar s //-------------------------------------------------------------------------- - #if LAGRAPH_SUITESPARSE + #if 1 // LAGRAPH_SUITESPARSE return (GxB_Scalar_type_name (name, s)) ; #else name [0] = '\0' ; From 9e3bf6ce2361b29852357418e61ef01cd9ffadc7 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Mon, 26 Dec 2022 20:10:35 -0600 Subject: [PATCH 46/53] GAP test results for v7.4.1.beta1 --- src/benchmark/GAP_2022.txt | 40 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/benchmark/GAP_2022.txt b/src/benchmark/GAP_2022.txt index 9f9b6d4130..f17249c15d 100644 --- a/src/benchmark/GAP_2022.txt +++ b/src/benchmark/GAP_2022.txt @@ -2,6 +2,19 @@ hypersparse: 20-core Intel(R) Xeon(R) CPU E5-2698 v4 @ 2.20GHz, with 40 threads (all default settings), gcc 11.2.0 -O3 (Ubuntu 20.04), unless otherwise indicated. Single socket system (no NUMA effects). +Dec 26c: revised GB_AxB_saxpy3_slice_balanced (recover heuristic from v7.2.0). + LAGraph v1.0.1, gcc 9.4.0. See Doc/ChangeLog for SS:GrB v7.4.1. + Fixes the performance issues in SS:GrB v7.3.x through v7.4.0. + +Dec 26b: redo Aug 31 results (GrB 7.3.0, LAGraph 0.9.37), gcc 9.4.0 + Seems to match Aug 31 results. + +Dec 26a, 2022, SS:GrB 7.4.1 (draft), LAGraph 1.0.1. gcc 9.4.0. + hypersparse.engr.tamu.edu was having performance issues, unrelated to + GraphBLAS, which meant these performance regression tests were unstable in + Sept-Dec 2022. v7.3.x and v7.4.0 had poor performance in BC (and other + benchmarks) as a result. + Sept 5, 2022 with SS:GrB v7.3.0, LAGraph 0.9.37, gcc 11.2.0 Aug 31, 2022 with SS:GrB v7.3.0, LAGraph 0.9.37, gcc 9.4.0 Mar 14, 2022 with SS:GrB v6.2.5 and LAGraph 0.9.13 (Mar 11, 2022) @@ -14,6 +27,10 @@ Jan 2, 2022 with SS:GrB v6.1.3 BC GAP:2021 31.140 46.484 11.035 2.974 1.612 (Nov 27) ------------------------------------------------------------------ +BC ok 24.077 *ok 33.279 *ok 9.273 *ok 6.497 ok 33.380 (Dec 26c) +BC ok (Aug31) 24.049 * 33.498 * 9.215 * 6.528 33.308 (Dec 26b) +BC slow! 30.672 *? 34.003 *? 13.791 ??? 8.764 ? 33.703 (Dec 26a) + ------------------------------------------------------------------ BC SS 24.935 *? 33.333 * 9.238 * 6.419 33.208 (Sept 5) BC SS 23.897 * 33.140 * 9.152 * 6.413 33.105 (Aug 31) BC SS 24.060 * 33.113 * 9.177 * 6.824 33.288 (Mar 14) @@ -26,6 +43,10 @@ BC SS 23.984 * 33.425 * 9.185 * 6.511 33.533 (Jan 2) BFS GAP:2021 .309 .542 .209 .341 .316 (Nov 27) ------------------------------------------------------------------ +BFS .559 1.267 .359 .751 3.166 (Dec 26c) +BFS .559 1.236 .385 .763 3.160 (Dec 26b) +BFS .569 1.410 .403 .859 3.173 (Dec 26a) + ------------------------------------------------------------------ BFS SS .555 1.225 .362 .746 3.174 (Sept 5) BFS SS .551 1.221 .364 .754 3.146 (Aug 31) BFS SS .547 1.274 .396 .747 3.154 (Mar 14) @@ -38,6 +59,9 @@ BFS SS .543 1.308 .366 .757 3.177 (Jan 2) PR GAP:2021 20.256 25.438 15.024 5.148 1.043 (Nov 27) ------------------------------------------------------------------ +PR ok 21.906 27.589 17.029 9.190 1.190 (Dec 26c) +PR 21.853 27.615 16.883 9.262 1.259 (Dec 26a) + ------------------------------------------------------------------ PR SS 21.463 27.503 17.049 9.408 1.243 (Sept 5) PR SS 21.730 27.578 16.985 9.177 1.207 (Aug 31) PR SS 21.715 27.532 17.073 9.178 1.722 (Mar 14) @@ -50,6 +74,10 @@ PR SS 21.960 27.439 17.258 9.105 1.182 (Jan 2) CC GAP:2021 .531 1.653 .229 .237 .046 (Nov 27) ------------------------------------------------------------------ +CC ok 2.911 3.783 1.377 2.018 .746 (Dec 26c) +CC 2.979 3.811 1.383 2.105 . (Dec 26b) +CC 2.930 3.805 1.39 2.139 .828 (Dec 26a) + ------------------------------------------------------------------ CC SS 2.933 3.821 1.382 2.041 .770 (Sept 5) CC SS 3.416 ? 3.737 1.373 2.043 .768 (Aug 31) CC SS 2.933 3.763 1.425 2.091 .770 (Mar 14) @@ -62,6 +90,10 @@ CC SS 3.049 4.136 1.403 2.093 .769 (Jan 2) SSSP GAP:2021 4.977 7.283 1.962 .781 .265 (Nov 27) ------------------------------------------------------------------ +SSSP ok 16.052 25.574 7.546 8.117 30.771 (Dec 26c) +SSSP . . . . . (Dec 26b) +SSSP slow! 17.947 ? 28.719 ? 9.808 ? 11.677 ? 31.459 (Dec 26a) + ------------------------------------------------------------------ SSSP SS 16.108 25.813 7.633 8.309 33.389 (Sept 5) SSSP SS 15.998 25.478 7.488 8.098 30.689 (Aug 31) SSSP SS 15.973 25.357 7.504 8.181 30.796 (Mar 14) @@ -76,9 +108,13 @@ SSSP SS 16.043 24.428 7.487 7.971 44.180 (Jan 2) TC GAP:2021 361.216 21.831 77.734 21.834 .031 (Nov 27) ------------------------------------------------------------------ -TC SS:LL.L 870.215 28.370 . . . (Sept 5) +TC SS:dot ok 888.890 32.611 227.457 32.645 .247 (Dec 26c) +TC SS:dot . . . . . (Dec 26a) +TC SS:dot slow 893.486 ? 32.583 228.273 32.817 .253 (Dec 26a) + ------------------------------------------------------------------ +TC SS:LL.L . 28.370 . . . (Sept 5) TC SS:UU.U . 27.354 . . . (Sept 5) -TC SS:dot . 32.915 225.636 32.382 .192 (Sept 5) +TC SS:dot 870.215 32.915 225.636 32.382 .192 (Sept 5) TC SS:LL.L 881.901 ? 28.227 . . . (Aug 31) TC SS:UU.U . 27.030 . . . (Aug 31) From c30054905d48e6b64cc9e014b0f189c752580dad Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Tue, 27 Dec 2022 09:28:11 -0600 Subject: [PATCH 47/53] demo output --- src/benchmark/bfs_demo.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/benchmark/bfs_demo.c b/src/benchmark/bfs_demo.c index 0cb7cefdf2..5b198fcbcd 100644 --- a/src/benchmark/bfs_demo.c +++ b/src/benchmark/bfs_demo.c @@ -159,8 +159,8 @@ int main (int argc, char **argv) ttrial = LAGraph_WallClockTime ( ) - ttrial ; tp [nthreads] += ttrial ; printf ("parent only pushpull trial: %2d threads: %2d " - "src: %g %10.4f sec\n", - trial, nthreads, (double) src, ttrial) ; + "src: %12" PRId64 " %10.4f sec\n", + trial, nthreads, src, ttrial) ; fflush (stdout) ; int32_t maxlevel ; @@ -195,7 +195,7 @@ int main (int argc, char **argv) GRB_TRY (GrB_reduce (&maxlevel, NULL, GrB_MAX_MONOID_INT32, level, NULL)) ; printf ("level only pushpull trial: %2d threads: %2d " - "src: %g %10.4f sec maxlevel: %d\n", + "src: %12" PRId64 " %10.4f sec maxlevel: %d\n", trial, nthreads, (double) src, ttrial, maxlevel) ; fflush (stdout) ; @@ -230,7 +230,7 @@ int main (int argc, char **argv) GRB_TRY (GrB_reduce (&maxlevel, NULL, GrB_MAX_MONOID_INT32, level, NULL)) ; printf ("parent+level pushpull trial: %2d threads: %2d " - "src: %g %10.4f sec\n", + "src: %12" PRId64 " %10.4f sec\n", trial, nthreads, (double) src, ttrial) ; fflush (stdout) ; From daa6c412148e5e673dcaee76db0c92758c034ce1 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Wed, 28 Dec 2022 20:43:36 -0600 Subject: [PATCH 48/53] more vanilla --- experimental/algorithm/LAGraph_FastGraphletTransform.c | 5 +++++ experimental/algorithm/LAGraph_KCoreDecompose.c | 5 +++++ experimental/algorithm/LAGraph_msf.c | 8 ++++---- experimental/algorithm/LAGraph_scc.c | 4 ++++ experimental/algorithm/LG_CC_FastSV5.c | 8 ++++---- experimental/test/test_FastGraphletTransform.c | 3 +++ experimental/test/test_KCoreDecompose.c | 6 ++++++ 7 files changed, 31 insertions(+), 8 deletions(-) diff --git a/experimental/algorithm/LAGraph_FastGraphletTransform.c b/experimental/algorithm/LAGraph_FastGraphletTransform.c index d751ff6664..cbcc2acc1c 100644 --- a/experimental/algorithm/LAGraph_FastGraphletTransform.c +++ b/experimental/algorithm/LAGraph_FastGraphletTransform.c @@ -128,6 +128,10 @@ int LAGraph_FastGraphletTransform GrB_Index nvals ; int64_t ntri ; +#if !LAGRAPH_SUITESPARSE + LG_ASSERT (false, GrB_NOT_IMPLEMENTED) ; +#else + A = G->A ; GrB_Index n ; @@ -564,4 +568,5 @@ int LAGraph_FastGraphletTransform LG_FREE_WORK ; return (0) ; +#endif } diff --git a/experimental/algorithm/LAGraph_KCoreDecompose.c b/experimental/algorithm/LAGraph_KCoreDecompose.c index 3fb6d4618d..0b49638f1c 100644 --- a/experimental/algorithm/LAGraph_KCoreDecompose.c +++ b/experimental/algorithm/LAGraph_KCoreDecompose.c @@ -52,6 +52,10 @@ int LAGraph_KCore_Decompose LG_ASSERT (D != NULL, GrB_NULL_POINTER) ; (*D) = NULL ; +#if !LAGRAPH_SUITESPARSE + LG_ASSERT (false, GrB_NOT_IMPLEMENTED) ; +#else + LG_TRY (LAGraph_CheckGraph (G, msg)) ; if (G->kind == LAGraph_ADJACENCY_UNDIRECTED || @@ -108,4 +112,5 @@ int LAGraph_KCore_Decompose LG_FREE_WORK ; return (GrB_SUCCESS) ; +#endif } diff --git a/experimental/algorithm/LAGraph_msf.c b/experimental/algorithm/LAGraph_msf.c index 518ecc124f..1da39ee283 100644 --- a/experimental/algorithm/LAGraph_msf.c +++ b/experimental/algorithm/LAGraph_msf.c @@ -119,6 +119,10 @@ int LAGraph_msf LG_CLEAR_MSG ; +#if !LAGRAPH_SUITESPARSE + return (GrB_NOT_IMPLEMENTED) ; +#else + GrB_Info info; GrB_Index n; GrB_Matrix S = NULL, T = NULL; @@ -133,10 +137,6 @@ int LAGraph_msf GxB_SelectOp s1 = NULL, s2 = NULL; if (result == NULL || A == NULL) return (GrB_NULL_POINTER) ; -#if !LAGRAPH_SUITESPARSE - LG_ASSERT (false, GrB_NOT_IMPLEMENTED) ; -#else - GrB_Index ncols ; GRB_TRY (GrB_Matrix_nrows (&n, A)); GRB_TRY (GrB_Matrix_ncols (&ncols, A)); diff --git a/experimental/algorithm/LAGraph_scc.c b/experimental/algorithm/LAGraph_scc.c index dad90427ef..7b043e1b98 100644 --- a/experimental/algorithm/LAGraph_scc.c +++ b/experimental/algorithm/LAGraph_scc.c @@ -29,6 +29,8 @@ #include #include +#if LAGRAPH_SUITESPARSE + //**************************************************************************** // global C arrays used in SelectOp GrB_Index *I = NULL, *V = NULL, *F = NULL, *B = NULL, *M = NULL; @@ -100,6 +102,8 @@ static GrB_Info propagate (GrB_Vector label, GrB_Vector mask, return GrB_SUCCESS; } +#endif + //**************************************************************************** //**************************************************************************** int LAGraph_scc diff --git a/experimental/algorithm/LG_CC_FastSV5.c b/experimental/algorithm/LG_CC_FastSV5.c index 2c56061dcc..87aecfdcc6 100644 --- a/experimental/algorithm/LG_CC_FastSV5.c +++ b/experimental/algorithm/LG_CC_FastSV5.c @@ -330,16 +330,16 @@ int LG_CC_FastSV5 // SuiteSparse:GraphBLAS method, with GxB extensions ) { -#if !LAGRAPH_SUITESPARSE - LG_ASSERT_MSG (false, GrB_NOT_IMPLEMENTED, "SuiteSparse required") ; -#else - //-------------------------------------------------------------------------- // check inputs //-------------------------------------------------------------------------- LG_CLEAR_MSG ; +#if !LAGRAPH_SUITESPARSE + LG_ASSERT_MSG (false, GrB_NOT_IMPLEMENTED, "SuiteSparse required") ; +#else + uint32_t *V32 = NULL ; int32_t *ht_key = NULL, *ht_val = NULL ; GrB_Index n, nnz, *I = NULL ; diff --git a/experimental/test/test_FastGraphletTransform.c b/experimental/test/test_FastGraphletTransform.c index f7422a9361..f6d8eea25b 100644 --- a/experimental/test/test_FastGraphletTransform.c +++ b/experimental/test/test_FastGraphletTransform.c @@ -79,6 +79,8 @@ int64_t A_graphlet_counts [ ] = void test_FastGraphletTransform(void) { LAGraph_Init (msg) ; + #if LAGRAPH_SUITESPARSE + GrB_Matrix A = NULL, F_net = NULL ; GrB_Index n ; bool ok = 1 ; @@ -160,6 +162,7 @@ void test_FastGraphletTransform(void) //-------------------------------------------------------------------------- + #endif LAGraph_Finalize (msg) ; } diff --git a/experimental/test/test_KCoreDecompose.c b/experimental/test/test_KCoreDecompose.c index ae901bd46e..3b41453788 100644 --- a/experimental/test/test_KCoreDecompose.c +++ b/experimental/test/test_KCoreDecompose.c @@ -52,6 +52,7 @@ const matrix_info files [ ] = void test_KCoreDecompose (void) { LAGraph_Init (msg) ; + #if LAGRAPH_SUITESPARSE for (int k = 0 ; ; k++) { @@ -116,6 +117,7 @@ void test_KCoreDecompose (void) OK (LAGraph_Delete (&G, msg)) ; } + #endif LAGraph_Finalize (msg) ; } @@ -126,6 +128,7 @@ void test_KCoreDecompose (void) void test_errors (void) { LAGraph_Init (msg) ; + #if LAGRAPH_SUITESPARSE snprintf (filename, LEN, LG_DATA_DIR "%s", "karate.mtx") ; FILE *f = fopen (filename, "r") ; @@ -175,11 +178,14 @@ void test_errors (void) TEST_CHECK (c == NULL) ; OK (LAGraph_Delete (&G, msg)) ; + #endif LAGraph_Finalize (msg) ; } TEST_LIST = { + #if LAGRAPH_SUITESPARSE {"KCoreDecompose", test_KCoreDecompose}, {"KCoreDecompose_errors", test_errors}, + #endif {NULL, NULL} }; From 1e2500b18f7b29dde1154e3f7be290c92177ad79 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Wed, 28 Dec 2022 21:45:16 -0600 Subject: [PATCH 49/53] date --- CMakeLists.txt | 2 +- include/LAGraph.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 50d0d4d21a..ba16cf8f27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,7 +49,7 @@ cmake_policy ( SET CMP0048 NEW ) set ( CMAKE_MACOSX_RPATH TRUE ) # version of LAGraph -set ( LAGraph_DATE "Dec 26, 2022" ) +set ( LAGraph_DATE "Dec 28, 2022" ) set ( LAGraph_VERSION_MAJOR 1 ) set ( LAGraph_VERSION_MINOR 0 ) set ( LAGraph_VERSION_SUB 1 ) diff --git a/include/LAGraph.h b/include/LAGraph.h index a46a569759..b5246935e3 100644 --- a/include/LAGraph.h +++ b/include/LAGraph.h @@ -37,7 +37,7 @@ // See also the LAGraph_Version utility method, which returns these values. // These definitions are derived from LAGraph/CMakeLists.txt. -#define LAGRAPH_DATE "Dec 26, 2022" +#define LAGRAPH_DATE "Dec 28, 2022" #define LAGRAPH_VERSION_MAJOR 1 #define LAGRAPH_VERSION_MINOR 0 #define LAGRAPH_VERSION_UPDATE 1 From d742241fde0d5ceb701178054927fee4b438e3f5 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Sun, 1 Jan 2023 17:46:42 -0600 Subject: [PATCH 50/53] Find*.cmake updates --- cmake_modules/FindGraphBLAS.cmake | 28 +++++++++++++++++--------- cmake_modules/FindLAGraph.cmake | 33 ++++++++++++++++--------------- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/cmake_modules/FindGraphBLAS.cmake b/cmake_modules/FindGraphBLAS.cmake index d57493cc26..2d50e07692 100644 --- a/cmake_modules/FindGraphBLAS.cmake +++ b/cmake_modules/FindGraphBLAS.cmake @@ -112,16 +112,22 @@ string ( ${GRAPHBLAS_FILENAME} ) -if ( NOT GRAPHBLAS_VERSION ) +# set ( GRAPHBLAS_VERSION "" ) +if ( EXISTS "${GRAPHBLAS_INCLUDE_DIR}" AND NOT GRAPHBLAS_VERSION ) # if the version does not appear in the filename, read the include file - foreach ( _VERSION MAJOR MINOR SUB ) - file ( STRINGS ${GRAPHBLAS_INCLUDE_DIR}/GraphBLAS.h _VERSION_LINE REGEX "define[ ]+GxB_IMPLEMENTATION_${_VERSION}" ) - if ( _VERSION_LINE ) - string (REGEX REPLACE ".*define[ ]+GxB_IMPLEMENTATION_${_VERSION}[ ]+([0-9]*).*" "\\1" _GRAPHBLAS_${_VERSION} "${_VERSION_LINE}") - endif ( ) - unset ( _VERSION_LINE ) - endforeach ( ) - set (GRAPHBLAS_VERSION "${_GRAPHBLAS_MAJOR}.${_GRAPHBLAS_MINOR}.${_GRAPHBLAS_SUB}") + file ( STRINGS ${GRAPHBLAS_INCLUDE_DIR}/GraphBLAS.h GRAPHBLAS_MAJOR_STR + REGEX "define GxB_IMPLEMENTATION_MAJOR" ) + file ( STRINGS ${GRAPHBLAS_INCLUDE_DIR}/GraphBLAS.h GRAPHBLAS_MINOR_STR + REGEX "define GxB_IMPLEMENTATION_MINOR" ) + file ( STRINGS ${GRAPHBLAS_INCLUDE_DIR}/GraphBLAS.h GRAPHBLAS_PATCH_STR + REGEX "define GxB_IMPLEMENTATION_SUB" ) + message ( STATUS "major: ${GRAPHBLAS_MAJOR_STR}" ) + message ( STATUS "minor: ${GRAPHBLAS_MINOR_STR}" ) + message ( STATUS "patch: ${GRAPHBLAS_PATCH_STR}" ) + string ( REGEX MATCH "[0-9]+" GRAPHBLAS_MAJOR ${GRAPHBLAS_MAJOR_STR} ) + string ( REGEX MATCH "[0-9]+" GRAPHBLAS_MINOR ${GRAPHBLAS_MINOR_STR} ) + string ( REGEX MATCH "[0-9]+" GRAPHBLAS_PATCH ${GRAPHBLAS_PATCH_STR} ) + set (GRAPHBLAS_VERSION "${GRAPHBLAS_MAJOR}.${GRAPHBLAS_MINOR}.${GRAPHBLAS_PATCH}") endif ( ) set ( GRAPHBLAS_LIBRARIES ${GRAPHBLAS_LIBRARY} ) @@ -148,5 +154,9 @@ if ( GRAPHBLAS_FOUND ) message ( STATUS "GraphBLAS static: ${GRAPHBLAS_STATIC}" ) else ( ) message ( STATUS "GraphBLAS not found" ) + set ( GRAPHBLAS_INCLUDE_DIR "" ) + set ( GRAPHBLAS_LIBRARIES "" ) + set ( GRAPHBLAS_LIBRARY "" ) + set ( GRAPHBLAS_STATIC "" ) endif ( ) diff --git a/cmake_modules/FindLAGraph.cmake b/cmake_modules/FindLAGraph.cmake index a95c27fd44..deaf7455b1 100644 --- a/cmake_modules/FindLAGraph.cmake +++ b/cmake_modules/FindLAGraph.cmake @@ -93,25 +93,22 @@ string( ${LAGRAPH_LIBRARY} ) -if ( NOT LAGRAPH_VERSION ) - # if the version does not appear in the filename, read the include file. - # The LAGraph.h file includes the following lines: - # #define LAGRAPH_VERSION_MAJOR 1 - # #define LAGRAPH_VERSION_MINOR 0 - # #define LAGRAPH_VERSION_UPDATE 1 - file ( STRINGS ${LAGRAPH_INCLUDE_DIR}/LAGraph.h LAGRAPH_VER_MAJOR_STRING +set ( LAGRAPH_VERSION "" ) +if ( EXISTS "${LAGRAPH_INCLUDE_DIR}" AND NOT LAGRAPH_VERSION ) + # if the version does not appear in the filename, read the include file + file ( STRINGS ${LAGRAPH_INCLUDE_DIR}/LAGraph.h LAGRAPH_MAJOR_STR REGEX "define LAGRAPH_VERSION_MAJOR " ) - file ( STRINGS ${LAGRAPH_INCLUDE_DIR}/LAGraph.h LAGRAPH_VER_MINOR_STRING + file ( STRINGS ${LAGRAPH_INCLUDE_DIR}/LAGraph.h LAGRAPH_MINOR_STR REGEX "define LAGRAPH_VERSION_MINOR " ) - file ( STRINGS ${LAGRAPH_INCLUDE_DIR}/LAGraph.h LAGRAPH_VER_UPDATE_STRING + file ( STRINGS ${LAGRAPH_INCLUDE_DIR}/LAGraph.h LAGRAPH_PATCH_STR REGEX "define LAGRAPH_VERSION_UPDATE " ) - message ( STATUS "major from LAGraph.h: ${LAGRAPH_VER_MAJOR_STRING}" ) - message ( STATUS "minor from LAGraph.h: ${LAGRAPH_VER_MINOR_STRING}" ) - message ( STATUS "update from LAGraph.h: ${LAGRAPH_VER_UPDATE_STRING}" ) - string ( REGEX MATCH "[0-9]+" LAGRAPH_VER_MAJOR ${LAGRAPH_VER_MAJOR_STRING} ) - string ( REGEX MATCH "[0-9]+" LAGRAPH_VER_MINOR ${LAGRAPH_VER_MINOR_STRING} ) - string ( REGEX MATCH "[0-9]+" LAGRAPH_VER_UPDATE ${LAGRAPH_VER_UPDATE_STRING} ) - set ( LAGRAPH_VERSION "${LAGRAPH_VER_MAJOR}.${LAGRAPH_VER_MINOR}.${LAGRAPH_VER_UPDATE}") + message ( STATUS "major: ${LAGRAPH_MAJOR_STR}" ) + message ( STATUS "minor: ${LAGRAPH_MINOR_STR}" ) + message ( STATUS "patch: ${LAGRAPH_PATCH_STR}" ) + string ( REGEX MATCH "[0-9]+" LAGRAPH_MAJOR ${LAGRAPH_MAJOR_STR} ) + string ( REGEX MATCH "[0-9]+" LAGRAPH_MINOR ${LAGRAPH_MINOR_STR} ) + string ( REGEX MATCH "[0-9]+" LAGRAPH_PATCH ${LAGRAPH_PATCH_STR} ) + set (LAGRAPH_VERSION "${LAGRAPH_MAJOR}.${LAGRAPH_MINOR}.${LAGRAPH_PATCH}") endif ( ) set ( LAGRAPH_LIBRARIES ${LAGRAPH_LIBRARY} ) @@ -137,5 +134,9 @@ if ( LAGRAPH_FOUND ) message ( STATUS "LAGraph static:: " ${LAGRAPH_STATIC} ) else ( ) message ( STATUS "LAGraph not found" ) + set ( LAGRAPH_INCLUDE_DIR "" ) + set ( LAGRAPH_LIBRARIES "" ) + set ( LAGRAPH_LIBRARY "" ) + set ( LAGRAPH_STATIC "" ) endif ( ) From 02d6235ede36e97a560e3150dc27c2009db7632e Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Sun, 1 Jan 2023 17:49:11 -0600 Subject: [PATCH 51/53] Find*.cmake --- cmake_modules/FindLAGraph.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake_modules/FindLAGraph.cmake b/cmake_modules/FindLAGraph.cmake index deaf7455b1..b0ea8deada 100644 --- a/cmake_modules/FindLAGraph.cmake +++ b/cmake_modules/FindLAGraph.cmake @@ -93,7 +93,7 @@ string( ${LAGRAPH_LIBRARY} ) -set ( LAGRAPH_VERSION "" ) +# set ( LAGRAPH_VERSION "" ) if ( EXISTS "${LAGRAPH_INCLUDE_DIR}" AND NOT LAGRAPH_VERSION ) # if the version does not appear in the filename, read the include file file ( STRINGS ${LAGRAPH_INCLUDE_DIR}/LAGraph.h LAGRAPH_MAJOR_STR From 757e8a728e4f4d37efd609dd26a724cfd8176bdf Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Sun, 1 Jan 2023 18:05:51 -0600 Subject: [PATCH 52/53] MSVC: static library names --- experimental/CMakeLists.txt | 6 ++++++ experimental/test/CMakeLists.txt | 6 ++++++ src/CMakeLists.txt | 6 ++++++ src/test/CMakeLists.txt | 6 ++++++ 4 files changed, 24 insertions(+) diff --git a/experimental/CMakeLists.txt b/experimental/CMakeLists.txt index 404ca50bc8..a88386ffca 100644 --- a/experimental/CMakeLists.txt +++ b/experimental/CMakeLists.txt @@ -44,6 +44,12 @@ SET_TARGET_PROPERTIES ( lagraphx_static PROPERTIES POSITION_INDEPENDENT_CODE OFF SOVERSION ${LAGraph_VERSION_MAJOR} C_STANDARD_REQUIRED 11 ) + +if ( MSVC ) + set_target_properties ( lagraphx_static PROPERTIES + OUTPUT_NAME lagraphx_static ) +endif ( ) + set_property ( TARGET lagraphx_static PROPERTY C_STANDARD 11 ) target_link_libraries ( lagraphx_static PUBLIC lagraph_static ${GRAPHBLAS_LIBRARIES} ) target_link_directories ( lagraphx_static BEFORE PUBLIC ${CMAKE_SOURCE_DIR}/build ) diff --git a/experimental/test/CMakeLists.txt b/experimental/test/CMakeLists.txt index 796e1de10f..7b54598b4b 100644 --- a/experimental/test/CMakeLists.txt +++ b/experimental/test/CMakeLists.txt @@ -55,6 +55,12 @@ SET_TARGET_PROPERTIES ( lagraphxtest_static PROPERTIES POSITION_INDEPENDENT_CODE OFF SOVERSION ${LAGraph_VERSION_MAJOR} C_STANDARD_REQUIRED 11 ) + +if ( MSVC ) + set_target_properties ( lagraphxtest_static PROPERTIES + OUTPUT_NAME lagraphxtest_static ) +endif ( ) + set_property ( TARGET lagraphxtest_static PROPERTY C_STANDARD 11 ) target_link_libraries(lagraphxtest_static PUBLIC lagraph lagraphtest ${GRAPHBLAS_LIBRARIES}) target_link_directories( lagraphxtest_static BEFORE PUBLIC ${CMAKE_SOURCE_DIR}/build ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5fd6cdf1cf..daa435fbb4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -50,6 +50,12 @@ SET_TARGET_PROPERTIES ( lagraph_static PROPERTIES POSITION_INDEPENDENT_CODE OFF SOVERSION ${LAGraph_VERSION_MAJOR} C_STANDARD_REQUIRED 11 ) + +if ( MSVC ) + set_target_properties ( lagraph_static PROPERTIES + OUTPUT_NAME lagraph_static ) +endif ( ) + set_property ( TARGET lagraph_static PROPERTY C_STANDARD 11 ) target_link_libraries ( lagraph_static PUBLIC ${GRAPHBLAS_LIBRARIES} ${M_LIB} ) target_link_directories( lagraph_static BEFORE PUBLIC ${CMAKE_SOURCE_DIR}/build ) diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index dbeac48d75..ac675e0328 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -57,6 +57,12 @@ SET_TARGET_PROPERTIES ( lagraphtest_static PROPERTIES POSITION_INDEPENDENT_CODE OFF SOVERSION ${LAGraph_VERSION_MAJOR} C_STANDARD_REQUIRED 11 ) + +if ( MSVC ) + set_target_properties ( lagraphtest_static PROPERTIES + OUTPUT_NAME lagraphtest_static ) +endif ( ) + set_property ( TARGET lagraphtest_static PROPERTY C_STANDARD 11 ) target_link_libraries(lagraphtest_static PUBLIC lagraph ${GRAPHBLAS_LIBRARIES}) target_link_directories( lagraphtest_static BEFORE PUBLIC ${CMAKE_SOURCE_DIR}/build ) From d79e67e046934261b2553159fff89104646ed115 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Mon, 2 Jan 2023 13:41:25 -0600 Subject: [PATCH 53/53] FindGraphBLAS: windows port --- cmake_modules/FindGraphBLAS.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake_modules/FindGraphBLAS.cmake b/cmake_modules/FindGraphBLAS.cmake index 2d50e07692..b6e7d19894 100644 --- a/cmake_modules/FindGraphBLAS.cmake +++ b/cmake_modules/FindGraphBLAS.cmake @@ -85,15 +85,17 @@ find_library ( GRAPHBLAS_LIBRARY if ( MSVC ) set ( STATIC_SUFFIX .lib ) + set ( STATIC_NAME graphblas_static ) else ( ) set ( STATIC_SUFFIX .a ) + set ( STATIC_NAME graphblas ) endif ( ) # static SuiteSparse:GraphBLAS library set ( save ${CMAKE_FIND_LIBRARY_SUFFIXES} ) set ( CMAKE_FIND_LIBRARY_SUFFIXES ${STATIC_SUFFIX} ${CMAKE_FIND_LIBRARY_SUFFIXES} ) find_library ( GRAPHBLAS_STATIC - NAMES graphblas + NAMES ${STATIC_NAME} HINTS ${GRAPHBLAS_ROOT} HINTS ENV GRAPHBLAS_ROOT HINTS ${CMAKE_SOURCE_DIR}/..