Add LAGraph_Matrix_Sum and LAGraph_Matrix_Binary_Sum utilities - #407
Conversation
| // funding and support from the U.S. Government (see Acknowledgments.txt file). | ||
| // DM22-0790 | ||
|
|
||
| // Contributed by Michel Pelletier. |
There was a problem hiding this comment.
Original idea by Tim Davis.
|
Can you change this to be a PR to the 1.3.x branch? That's the current development branch. |
DrTimothyAldenDavis
left a comment
There was a problem hiding this comment.
Looks great!
Can you revise the PR to go to the v1.3.x branch instead of the stable branch? And can you put these in the experimental folder instead of src? Also put the header files in LAGraphX.h.
We have to talk in the LAGraph committee about what to add move from experimental to src, before anything can go into the src folder.
For the two utilities: would it be better to have a single method, LAGraph_Matrix_sum, which took in a parameter that told what method to use? That's something can can be discussed later, after these methods are merged into the experimental/utility folder.
LAGraph_Matrix_Sum combines an array of GrB_Matrix objects into a single matrix using a binary operator to resolve duplicate entries. It computes the total number of entries across all inputs, allocates one shared tuple buffer (I, J, X), extracts the tuples of each input matrix into the buffer, and calls GrB_Matrix_build with the dup operator to combine duplicate (i,j) coordinates. With dup = GrB_PLUS_FP64 (for example) this computes the element-wise sum of all the matrices. All input matrices must have identical dimensions and the same built-in type; user-defined types return GrB_NOT_IMPLEMENTED. Includes a test (src/test/test_Matrix_Sum.c) covering correctness, all built-in type branches, error handling, and a brutal malloc-failure variant.
The per-matrix extraction loop precomputes an offset (prefix-sum) array so each matrix's tuples occupy a disjoint region of the shared (I, J, X) buffer. That removes the loop-carried offset dependency and lets the extraction run across LG_nthreads_outer threads with OpenMP; each GrB_Matrix_extractTuples is still parallelized internally by GraphBLAS with LG_nthreads_inner threads (the two-level nested model). The public signature is unchanged: the thread count follows the usual LAGraph convention via LAGraph_SetNumThreads. Because GRB_TRY cannot return out of an OpenMP region, the first extraction error is captured under a critical section and checked after the loop. Adds test_Matrix_Sum_parallel, which sums many overlapping matrices with multiple outer threads and compares against an independently accumulated result.
Adds LAGraph_Matrix_Binary_Sum, which combines an array of matrices into a single matrix with the same interface and result as LAGraph_Matrix_Sum but a different technique: a pairwise binary reduction tree built from GrB_eWiseAdd (per the GraphChallenge "Anonymized Network Sensing" paper, "Binary Summation of Traffic Matrices"), rather than one large extract/build. At each level the matrices are summed in disjoint adjacent pairs using the dup operator; an unpaired (odd) trailing matrix is carried up to the next level unchanged, until a single matrix remains. The independent pair-sums within a level are parallelized across LG_nthreads_outer threads. Working on the smaller intermediate matrices of the tree keeps the active data in faster memory. All intermediate matrices are tracked in a single pre-NULLed Pool array with deterministic per-pair slots, so cleanup is a simple sweep that is correct on any failure path. Unlike LAGraph_Matrix_Sum, dup must be non-NULL since GrB_eWiseAdd requires a binary operator. Includes tests for correctness, odd counts (carry path), all built-in types, parallel reduction with multiple outer threads, error handling, and a brutal malloc-failure variant.
Replace the Pool design (which held all n-1 intermediate matrices simultaneously) with a double-buffered ownership model using per-slot bool flags (ownedW/ownedN). Each pair's two inputs are freed inside the parallel loop the moment their sum is built, so only the active merge frontier is ever resident. The Pool approach peaked at O(S * log n) of working memory; the eager-free model peaks at O(S), where S is the size of the current level. On synthetic data with 22% entry overlap the reduction is 0.43x and with 4.4% overlap it reaches 0.28x versus LAGraph_Matrix_Sum. Results are identical in all tested configurations.
Relocate LAGraph_Matrix_Sum and LAGraph_Matrix_Binary_Sum out of the stable src/ tree into the experimental tree, and move their prototypes from the stable public header (Config/LAGraph.h.in / include/LAGraph.h) to include/LAGraphX.h: - src/utility/LAGraph_Matrix_Sum.c -> experimental/utility/ - src/utility/LAGraph_Matrix_Binary_Sum.c -> experimental/utility/ - src/test/test_Matrix_Sum.c -> experimental/test/ - src/test/test_Matrix_Binary_Sum.c -> experimental/test/ Each source and test now includes LAGraphX.h, and the two prototypes use the LAGRAPHX_PUBLIC export macro. The tests register as ctests LAGraphX_Matrix_Sum and LAGraphX_Matrix_Binary_Sum. No CMake changes are needed: the experimental library and test globs pick up the moved files.
|
The branch is now rebased on v1.3.x. |
DrTimothyAldenDavis
left a comment
There was a problem hiding this comment.
Looks great to me. A future extension could add support for user-define types, assuming the dup operator is also user-defined. But that's not essential for now.
|
Shall I merge it in? |
Summary
Adds two
experimental/utility/functions that combine an array ofGrB_Matrixobjects into a single matrix, using a binary operator to resolve duplicate(i,j)entries. They compute the same result via two different techniques, so they can be compared:LAGraph_Matrix_Sum— concatenate-and-build: extract every matrix's tuples into one shared buffer, then a singleGrB_Matrix_build.LAGraph_Matrix_Binary_Sum— pairwise binary reduction tree ofGrB_eWiseAdd(per the GraphChallenge "Anonymized Network Sensing" paper, Fig. 3 "Binary Summation of Traffic Matrices").With
dup = GrB_PLUS_FP64(for example) either computes the element-wise sum of all the matrices; other operators generalize it (max, times, etc.). All input matrices must have identical dimensions and the same built-in type;Cis created with that type and dimensions. User-defined types returnGrB_NOT_IMPLEMENTED.LAGraph_Matrix_Sum(concatenate + build)nvalsacross all inputs and a per-matrix prefix-sum offset.I,J,X) large enough for every entry.LG_nthreads_outerthreads, since the regions never overlap.GrB_Matrix_buildwith the provideddupoperator to combine duplicate coordinates.LAGraph_Matrix_Binary_Sum(pairwise binary reduction)At each level the matrices are summed in disjoint adjacent pairs with
GrB_eWiseAddusingdup; an unpaired (odd) trailing matrix is carried up to the next level unchanged, until a single matrix remains. The independent pair-sums within a level run concurrently acrossLG_nthreads_outerthreads. Working on the smaller intermediate matrices of the tree keeps the active data in faster memory: adding two matrices each with N entries yields a matrix with fewer than 2N entries, so the relative work shrinks as the matrices grow.All intermediate matrices are tracked in a single pre-NULLed pool with deterministic per-pair slots, so cleanup is a simple sweep that is correct on any failure path. Unlike
LAGraph_Matrix_Sum,dupmust be non-NULL, sinceGrB_eWiseAddrequires a binary operator (NULLdupreturnsGrB_NULL_POINTER).Changes
experimental/utility/LAGraph_Matrix_Sum.c— concatenate/build implementation.experimental/utility/LAGraph_Matrix_Binary_Sum.c— binary-reduction implementation.include/LAGraphX.h— public declarations (experimentalLAGraphXAPI).experimental/test/test_Matrix_Sum.c,experimental/test/test_Matrix_Binary_Sum.c— tests.Testing
ctest -R LAGraphX_Matrix_Sumandctest -R LAGraphX_Matrix_Binary_Sumpass; clean builds with OpenMP on and off. The test binaries cover:GrB_eWiseAdd, single-matrix copy, empty-matrix inclusion)nmatrices == 0, NULL array entry, dimension/type mismatch, UDT, and NULLdupfor the binary variant)