LCOV - code coverage report
Current view: top level - experimental/utility - LAGraph_Random_Matrix.c (source / functions) Hit Total Coverage
Test: LAGraph code coverage report. Commit id: cc56ed4. Current time (UTC): 2024-08-30T17:14:30Z Lines: 84 84 100.0 %
Date: 2024-08-30 17:16:41 Functions: 2 2 100.0 %

          Line data    Source code
       1             : //------------------------------------------------------------------------------
       2             : // LAGraph_Random_Matrix: generate a random matrix
       3             : //------------------------------------------------------------------------------
       4             : 
       5             : // LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved.
       6             : // SPDX-License-Identifier: BSD-2-Clause
       7             : //
       8             : // For additional details (including references to third party source code and
       9             : // other files) see the LICENSE file or contact permission@sei.cmu.edu. See
      10             : // Contributors.txt for a full list of contributors. Created, in part, with
      11             : // funding and support from the U.S. Government (see Acknowledgments.txt file).
      12             : // DM22-0790
      13             : 
      14             : // Contributed by Timothy A. Davis, Texas A&M University
      15             : 
      16             : //------------------------------------------------------------------------------
      17             : 
      18             : // Constructs a sparse roughly uniformly distributed random matrix with roughly
      19             : // density*nrows*ncols entries.  If density == INFINITY then the matrix is
      20             : // generated with all entries present.
      21             : 
      22             : // If the type is GrB_FP32 or GrB_FP64, the values of A are returned in the
      23             : // range [0,1].  If any duplicate entries are generated, the largest one is
      24             : // take, so the distribution can be skewed towards 1 if the density is large.
      25             : // This could be fixed by using the GxB_IGNORE_DUP operator, but this would
      26             : // require SuiteSparse:GraphBLAS.
      27             : 
      28             : #define LG_FREE_WORK                            \
      29             : {                                               \
      30             :     LAGraph_Free ((void **) &I, NULL) ;         \
      31             :     LAGraph_Free ((void **) &J, NULL) ;         \
      32             :     LAGraph_Free ((void **) &ignore, NULL) ;    \
      33             :     LAGraph_Free (&X, NULL) ;                   \
      34             :     GrB_free (&Mod) ;                           \
      35             :     GrB_free (&Rows) ;                          \
      36             :     GrB_free (&Cols) ;                          \
      37             :     GrB_free (&Values) ;                        \
      38             :     GrB_free (&Seed) ;                          \
      39             :     GrB_free (&T) ;                             \
      40             : }
      41             : 
      42             : #define LG_FREE_ALL                             \
      43             : {                                               \
      44             :     LG_FREE_WORK ;                              \
      45             :     GrB_free (A) ;                              \
      46             : }
      47             : 
      48             : #include "LG_internal.h"
      49             : #include "LAGraphX.h"
      50             : 
      51             : // uncomment these to test vanilla case for just this file:
      52             : // #undef LAGRAPH_SUITESPARSE
      53             : // #define LAGRAPH_SUITESPARSE 0
      54             : 
      55             : //------------------------------------------------------------------------------
      56             : // mod function for uint64: z = x % y
      57             : //------------------------------------------------------------------------------
      58             : 
      59         660 : void mod_function (void *z, const void *x, const void *y)
      60             : {
      61         660 :     uint64_t a = (*((uint64_t *) x)) ;
      62         660 :     uint64_t b = (*((uint64_t *) y)) ;
      63         660 :     (*((uint64_t *) z)) = a % b ;
      64         660 : }
      65             : 
      66             : //------------------------------------------------------------------------------
      67             : // LAGraph_Random_Matrix
      68             : //------------------------------------------------------------------------------
      69             : 
      70          57 : GrB_Info LAGraph_Random_Matrix    // random matrix of any built-in type
      71             : (
      72             :     // output
      73             :     GrB_Matrix *A,      // A is constructed on output
      74             :     // input
      75             :     GrB_Type type,      // type of matrix to construct
      76             :     GrB_Index nrows,    // # of rows of A
      77             :     GrB_Index ncols,    // # of columns of A
      78             :     double density,     // density: build a sparse matrix with
      79             :                         // density*nrows*cols values if not INFINITY;
      80             :                         // build a dense matrix if INFINITY.
      81             :     uint64_t seed,      // random number seed
      82             :     char *msg
      83             : )
      84             : {
      85             : 
      86             :     //--------------------------------------------------------------------------
      87             :     // check inputs
      88             :     //--------------------------------------------------------------------------
      89             : 
      90          57 :     LG_CLEAR_MSG ;
      91          57 :     GrB_BinaryOp Mod = NULL ;
      92          57 :     GrB_Vector Rows = NULL, Cols = NULL, Values = NULL, Seed = NULL ;
      93          57 :     GrB_Matrix T = NULL ;
      94          57 :     GrB_Index *I = NULL, *J = NULL, *ignore = NULL ;
      95          57 :     GrB_Index I_size = 0, J_size = 0, X_size = 0 ;
      96          57 :     void *X = NULL ;
      97          57 :     LG_ASSERT (A != NULL && type != NULL, GrB_NULL_POINTER) ;
      98          57 :     LG_ASSERT_MSG (density >= 0, GrB_INVALID_VALUE, "invalid density") ;
      99             : 
     100          57 :     LG_ASSERT_MSG (type == GrB_BOOL
     101             :         || type == GrB_INT8   || type == GrB_INT16 || type == GrB_INT32
     102             :         || type == GrB_INT64  || type == GrB_UINT8 || type == GrB_UINT16
     103             :         || type == GrB_UINT32 || type == GrB_UINT64
     104             :         || type == GrB_FP32   || type == GrB_FP64,
     105             :         GrB_NOT_IMPLEMENTED, "unsupported type") ;
     106             : 
     107          56 :     GRB_TRY (GrB_Matrix_new (A, type, nrows, ncols)) ;
     108          56 :     if (nrows == 0 || ncols == 0)
     109             :     {
     110             :         // nothing to do: return A as the requested empty matrix
     111           1 :         return (GrB_SUCCESS) ;
     112             :     }
     113             : 
     114             :     //--------------------------------------------------------------------------
     115             :     // create the Mod operator
     116             :     //--------------------------------------------------------------------------
     117             : 
     118          55 :     GRB_TRY (GrB_BinaryOp_new (&Mod, mod_function,
     119             :         GrB_UINT64, GrB_UINT64, GrB_UINT64)) ;
     120             : 
     121             :     //--------------------------------------------------------------------------
     122             :     // determine the number of entries to generate
     123             :     //--------------------------------------------------------------------------
     124             : 
     125          55 :     bool A_is_full = isinf (density) ;
     126             :     GrB_Index nvals ;
     127          55 :     if (A_is_full)
     128             :     {
     129             :         // determine number of tuples for building a random dense matrix
     130          11 :         double nx = (double) nrows * (double) ncols ;
     131          11 :         LG_ASSERT_MSG (nx < (double) GrB_INDEX_MAX, GrB_OUT_OF_MEMORY,
     132             :             "Problem too large") ;
     133          11 :         nvals = nrows * ncols ;
     134             :     }
     135             :     else
     136             :     {
     137             :         // determine number of tuples for building a random sparse matrix
     138          44 :         double nx = density * (double) nrows * (double) ncols ;
     139          44 :         nx = round (nx) ;
     140          44 :         nx = fmax (nx, (double) 0) ;
     141          44 :         nx = fmin (nx, (double) GrB_INDEX_MAX) ;
     142          44 :         nvals = (GrB_Index) nx ;
     143             :     }
     144             : 
     145             :     //--------------------------------------------------------------------------
     146             :     // allocate workspace
     147             :     //--------------------------------------------------------------------------
     148             : 
     149             :     #if !LAGRAPH_SUITESPARSE
     150             :     {
     151             :         LG_TRY (LAGraph_Malloc ((void **) &ignore, nvals, sizeof (GrB_Index),
     152             :             msg)) ;
     153             :         LG_TRY (LAGraph_Malloc ((void **) &I, nvals, sizeof (GrB_Index), msg)) ;
     154             :         LG_TRY (LAGraph_Malloc ((void **) &J, nvals, sizeof (GrB_Index), msg)) ;
     155             :     }
     156             :     #endif
     157             : 
     158             :     //--------------------------------------------------------------------------
     159             :     // construct the random Seed vector
     160             :     //--------------------------------------------------------------------------
     161             : 
     162          55 :     GRB_TRY (GrB_Vector_new (&Seed, GrB_UINT64, nvals)) ;
     163          55 :     GRB_TRY (GrB_assign (Seed, NULL, NULL, 0, GrB_ALL, nvals, NULL)) ;
     164          55 :     LG_TRY (LAGraph_Random_Seed (Seed, seed, msg)) ;
     165             : 
     166             :     //--------------------------------------------------------------------------
     167             :     // construct the random indices if A is sparse, or all indices if full
     168             :     //--------------------------------------------------------------------------
     169             : 
     170          55 :     if (!A_is_full)
     171             :     {
     172             : 
     173             :         //----------------------------------------------------------------------
     174             :         // construct random indices for a sparse matrix
     175             :         //----------------------------------------------------------------------
     176             : 
     177             :         // Rows = mod (Seed, nrows) ;
     178          44 :         GRB_TRY (GrB_Vector_new (&Rows, GrB_UINT64, nvals)) ;
     179          44 :         GRB_TRY (GrB_apply (Rows, NULL, NULL, Mod, Seed, nrows, NULL)) ;
     180             : 
     181             :         // Seed = next (Seed)
     182          44 :         LG_TRY (LAGraph_Random_Next (Seed, msg)) ;
     183             : 
     184             :         // Cols = mod (Seed, ncols) ;
     185          44 :         GRB_TRY (GrB_Vector_new (&Cols, GrB_UINT64, nvals)) ;
     186          44 :         GRB_TRY (GrB_apply (Cols, NULL, NULL, Mod, Seed, ncols, NULL)) ;
     187             : 
     188             :         // Seed = next (Seed)
     189          44 :         LG_TRY (LAGraph_Random_Next (Seed, msg)) ;
     190             : 
     191             :         //----------------------------------------------------------------------
     192             :         // extract the indices
     193             :         //----------------------------------------------------------------------
     194             : 
     195             :         #if LAGRAPH_SUITESPARSE
     196             :         {
     197             :             // this takes O(1) time and space
     198          44 :             GRB_TRY (GxB_Vector_unpack_Full (Rows, (void **) &I, &I_size,
     199             :                 NULL, NULL)) ;
     200          44 :             GRB_TRY (GxB_Vector_unpack_Full (Cols, (void **) &J, &J_size,
     201             :                 NULL, NULL)) ;
     202             :         }
     203             :         #else
     204             :         {
     205             :             // this takes O(nvals) time and space
     206             :             GRB_TRY (GrB_Vector_extractTuples_UINT64 (ignore, I, &nvals,
     207             :                 Rows)) ;
     208             :             GRB_TRY (GrB_Vector_extractTuples_UINT64 (ignore, J, &nvals,
     209             :                 Cols)) ;
     210             :         }
     211             :         #endif
     212             : 
     213          44 :         GrB_free (&Rows) ;
     214          44 :         GrB_free (&Cols) ;
     215             : 
     216             :     }
     217             :     else
     218             :     {
     219             : 
     220             :         //----------------------------------------------------------------------
     221             :         // construct indices for a full matrix
     222             :         //----------------------------------------------------------------------
     223             : 
     224             :         #if !LAGRAPH_SUITESPARSE
     225             :         {
     226             :             // T = true (nrows, ncols) ;
     227             :             GRB_TRY (GrB_Matrix_new (&T, GrB_BOOL, nrows, ncols)) ;
     228             :             GRB_TRY (GrB_assign (T, NULL, NULL, true,
     229             :                 GrB_ALL, nrows, GrB_ALL, ncols, NULL)) ;
     230             :             // extract the row and column indices from T
     231             :             GRB_TRY (GrB_Matrix_extractTuples (I, J, (bool *) ignore, &nvals,
     232             :                 T)) ;
     233             :             GrB_free (&T) ;
     234             :         }
     235             :         #endif
     236             :     }
     237             : 
     238             :     //-------------------------------------------------------------------------
     239             :     // construct the random values
     240             :     //-------------------------------------------------------------------------
     241             : 
     242          55 :     if (type == GrB_BOOL)
     243             :     {
     244             :         // Values = (Seed < UINT64_MAX / 2)
     245           5 :         GRB_TRY (GrB_Vector_new (&Values, GrB_BOOL, nvals)) ;
     246           5 :         GRB_TRY (GrB_apply (Values, NULL, NULL,
     247             :             GrB_LT_UINT64, Seed, UINT64_MAX / 2, NULL)) ;
     248             :     }
     249          50 :     else if (type == GrB_UINT64)
     250             :     {
     251             :         // no need to allocate the Values vector; just use the Seed itself
     252           5 :         Values = Seed ;
     253           5 :         Seed = NULL ;
     254             :     }
     255             :     else
     256             :     {
     257             :         // Values = (type) Seed
     258          45 :         GRB_TRY (GrB_Vector_new (&Values, type, nvals)) ;
     259          45 :         GRB_TRY (GrB_assign (Values, NULL, NULL, Seed, GrB_ALL, nvals,
     260             :             NULL)) ;
     261             :     }
     262          55 :     GrB_free (&Seed) ;
     263             : 
     264             :     // scale the values to the range [0,1], if floating-point
     265          55 :     if (type == GrB_FP32)
     266             :     {
     267             :         // Values = Values / (float) UINT64_MAX
     268           5 :         GRB_TRY (GrB_apply (Values, NULL, NULL, GrB_DIV_FP32,
     269             :             Values, (float) UINT64_MAX, NULL)) ;
     270             :     }
     271          50 :     else if (type == GrB_FP64)
     272             :     {
     273             :         // Values = Values / (double) UINT64_MAX
     274           5 :         GRB_TRY (GrB_apply (Values, NULL, NULL, GrB_DIV_FP64,
     275             :             Values, (double) UINT64_MAX, NULL)) ;
     276             :     }
     277             : 
     278             :     //--------------------------------------------------------------------------
     279             :     // extract the values
     280             :     //--------------------------------------------------------------------------
     281             : 
     282             :     #if LAGRAPH_SUITESPARSE
     283             :     {
     284             :         // this takes O(1) time and space and works for any data type
     285          55 :         GRB_TRY (GxB_Vector_unpack_Full (Values, &X, &X_size, NULL, NULL)) ;
     286             :     }
     287             :     #else
     288             :     {
     289             :         // this takes O(nvals) time and space
     290             :         if (type == GrB_BOOL)
     291             :         {
     292             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (bool), msg)) ;
     293             :             GRB_TRY (GrB_Vector_extractTuples_BOOL (ignore, X, &nvals,
     294             :                 Values)) ;
     295             :         }
     296             :         else if (type == GrB_INT8)
     297             :         {
     298             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (int8_t),
     299             :                 msg)) ;
     300             :             GRB_TRY (GrB_Vector_extractTuples_INT8 (ignore, X, &nvals,
     301             :                 Values)) ;
     302             :         }
     303             :         else if (type == GrB_INT16)
     304             :         {
     305             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (int16_t),
     306             :                 msg)) ;
     307             :             GRB_TRY (GrB_Vector_extractTuples_INT16 (ignore, X, &nvals,
     308             :                 Values)) ;
     309             :         }
     310             :         else if (type == GrB_INT32)
     311             :         {
     312             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (int32_t),
     313             :                 msg)) ;
     314             :             GRB_TRY (GrB_Vector_extractTuples_INT32 (ignore, X, &nvals,
     315             :                 Values)) ;
     316             :         }
     317             :         else if (type == GrB_INT64)
     318             :         {
     319             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (int64_t),
     320             :                 msg)) ;
     321             :             GRB_TRY (GrB_Vector_extractTuples_INT64 (ignore, X, &nvals,
     322             :                 Values)) ;
     323             :         }
     324             :         else if (type == GrB_UINT8)
     325             :         {
     326             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (uint8_t),
     327             :                 msg)) ;
     328             :             GRB_TRY (GrB_Vector_extractTuples_UINT8 (ignore, X, &nvals,
     329             :                 Values)) ;
     330             :         }
     331             :         else if (type == GrB_UINT16)
     332             :         {
     333             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (uint16_t),
     334             :                 msg)) ;
     335             :             GRB_TRY (GrB_Vector_extractTuples_UINT16 (ignore, X, &nvals,
     336             :                 Values)) ;
     337             :         }
     338             :         else if (type == GrB_UINT32)
     339             :         {
     340             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (uint32_t),
     341             :                 msg)) ;
     342             :             GRB_TRY (GrB_Vector_extractTuples_UINT32 (ignore, X, &nvals,
     343             :                 Values)) ;
     344             :         }
     345             :         else if (type == GrB_UINT64)
     346             :         {
     347             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (uint64_t),
     348             :                 msg)) ;
     349             :             GRB_TRY (GrB_Vector_extractTuples_UINT64 (ignore, X, &nvals,
     350             :                 Values)) ;
     351             :         }
     352             :         else if (type == GrB_FP32)
     353             :         {
     354             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (float),
     355             :                 msg)) ;
     356             :             GRB_TRY (GrB_Vector_extractTuples_FP32 (ignore, X, &nvals,
     357             :                 Values)) ;
     358             :         }
     359             :         else // if (type == GrB_FP64)
     360             :         {
     361             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (double),
     362             :                 msg)) ;
     363             :             GRB_TRY (GrB_Vector_extractTuples_FP64 (ignore, X, &nvals,
     364             :                 Values)) ;
     365             :         }
     366             :         LAGraph_Free ((void **) &ignore, NULL) ;
     367             :     }
     368             :     #endif
     369             : 
     370          55 :     GrB_free (&Values) ;
     371             : 
     372             :     //--------------------------------------------------------------------------
     373             :     // build the matrix
     374             :     //--------------------------------------------------------------------------
     375             : 
     376             :     // Using GxB_IGNORE_DUP for the dup operator would be faster for
     377             :     // SuiteSparse, but it would result in a different matrix as compared to
     378             :     // the pure GrB case.
     379             : 
     380             :     #if LAGRAPH_SUITESPARSE
     381          55 :     if (A_is_full)
     382             :     {
     383             :         // this takes O(1) time and space
     384          11 :         GRB_TRY (GxB_Matrix_pack_FullR (*A, &X, X_size, false, NULL)) ;
     385             :     }
     386             :     else
     387             :     #endif
     388          44 :     if (type == GrB_BOOL)
     389             :     {
     390           4 :         GRB_TRY (GrB_Matrix_build_BOOL   (*A, I, J, X, nvals, GrB_LXOR)) ;
     391             :     }
     392          40 :     else if (type == GrB_INT8)
     393             :     {
     394           4 :         GRB_TRY (GrB_Matrix_build_INT8   (*A, I, J, X, nvals, GrB_PLUS_INT8)) ;
     395             :     }
     396          36 :     else if (type == GrB_INT16)
     397             :     {
     398           4 :         GRB_TRY (GrB_Matrix_build_INT16  (*A, I, J, X, nvals, GrB_PLUS_INT16)) ;
     399             :     }
     400          32 :     else if (type == GrB_INT32)
     401             :     {
     402           4 :         GRB_TRY (GrB_Matrix_build_INT32  (*A, I, J, X, nvals, GrB_PLUS_INT32)) ;
     403             :     }
     404          28 :     else if (type == GrB_INT64)
     405             :     {
     406           4 :         GRB_TRY (GrB_Matrix_build_INT64  (*A, I, J, X, nvals, GrB_PLUS_INT64)) ;
     407             :     }
     408          24 :     else if (type == GrB_UINT8)
     409             :     {
     410           4 :         GRB_TRY (GrB_Matrix_build_UINT8  (*A, I, J, X, nvals, GrB_PLUS_UINT8)) ;
     411             :     }
     412          20 :     else if (type == GrB_UINT16)
     413             :     {
     414           4 :         GRB_TRY (GrB_Matrix_build_UINT16 (*A, I, J, X, nvals, GrB_PLUS_UINT16));
     415             :     }
     416          16 :     else if (type == GrB_UINT32)
     417             :     {
     418           4 :         GRB_TRY (GrB_Matrix_build_UINT32 (*A, I, J, X, nvals, GrB_PLUS_UINT32));
     419             :     }
     420          12 :     else if (type == GrB_UINT64)
     421             :     {
     422           4 :         GRB_TRY (GrB_Matrix_build_UINT64 (*A, I, J, X, nvals, GrB_PLUS_UINT64));
     423             :     }
     424           8 :     else if (type == GrB_FP32)
     425             :     {
     426           4 :         GRB_TRY (GrB_Matrix_build_FP32   (*A, I, J, X, nvals, GrB_MAX_FP32)) ;
     427             :     }
     428             :     else // if (type == GrB_FP64)
     429             :     {
     430           4 :         GRB_TRY (GrB_Matrix_build_FP64   (*A, I, J, X, nvals, GrB_MAX_FP64)) ;
     431             :     }
     432             : 
     433             :     //--------------------------------------------------------------------------
     434             :     // free workspace and return result
     435             :     //--------------------------------------------------------------------------
     436             : 
     437          55 :     LG_FREE_WORK ;
     438          55 :     return (GrB_SUCCESS) ;
     439             : }

Generated by: LCOV version 1.14