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: 7b9d2ee. Current time (UTC): 2025-06-03T21:57:17Z Lines: 84 84 100.0 %
Date: 2025-06-03 22:02:40 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 (&State) ;                         \
      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         220 : void mod_function (void *z, const void *x, const void *y)
      60             : {
      61         220 :     uint64_t a = (*((uint64_t *) x)) ;
      62         220 :     uint64_t b = (*((uint64_t *) y)) ;
      63         220 :     (*((uint64_t *) z)) = a % b ;
      64         220 : }
      65             : 
      66             : #define MOD_FUNCTION_DEFN                                           \
      67             : "void mod_function (void *z, const void *x, const void *y)      \n" \
      68             : "{                                                              \n" \
      69             : "    uint64_t a = (*((uint64_t *) x)) ;                         \n" \
      70             : "    uint64_t b = (*((uint64_t *) y)) ;                         \n" \
      71             : "    (*((uint64_t *) z)) = a % b ;                              \n" \
      72             : "}"
      73             : 
      74             : //------------------------------------------------------------------------------
      75             : // LAGraph_Random_Matrix
      76             : //------------------------------------------------------------------------------
      77             : 
      78          80 : GrB_Info LAGraph_Random_Matrix    // random matrix of any built-in type
      79             : (
      80             :     // output
      81             :     GrB_Matrix *A,      // A is constructed on output
      82             :     // input
      83             :     GrB_Type type,      // type of matrix to construct
      84             :     GrB_Index nrows,    // # of rows of A
      85             :     GrB_Index ncols,    // # of columns of A
      86             :     double density,     // density: build a sparse matrix with
      87             :                         // density*nrows*cols values if not INFINITY;
      88             :                         // build a dense matrix if INFINITY.
      89             :     uint64_t seed,      // random number seed
      90             :     char *msg
      91             : )
      92             : {
      93             : 
      94             :     //--------------------------------------------------------------------------
      95             :     // check inputs
      96             :     //--------------------------------------------------------------------------
      97             : 
      98          80 :     LG_CLEAR_MSG ;
      99          80 :     GrB_BinaryOp Mod = NULL ;
     100          80 :     GrB_Vector Rows = NULL, Cols = NULL, Values = NULL, State = NULL ;
     101          80 :     GrB_Matrix T = NULL ;
     102          80 :     GrB_Index *I = NULL, *J = NULL, *ignore = NULL ;
     103          80 :     GrB_Index I_size = 0, J_size = 0, X_size = 0 ;
     104          80 :     void *X = NULL ;
     105          80 :     LG_ASSERT (A != NULL && type != NULL, GrB_NULL_POINTER) ;
     106          80 :     LG_ASSERT_MSG (density >= 0, GrB_INVALID_VALUE, "invalid density") ;
     107             : 
     108          80 :     LG_ASSERT_MSG (type == GrB_BOOL
     109             :         || type == GrB_INT8   || type == GrB_INT16 || type == GrB_INT32
     110             :         || type == GrB_INT64  || type == GrB_UINT8 || type == GrB_UINT16
     111             :         || type == GrB_UINT32 || type == GrB_UINT64
     112             :         || type == GrB_FP32   || type == GrB_FP64,
     113             :         GrB_NOT_IMPLEMENTED, "unsupported type") ;
     114             : 
     115          79 :     GRB_TRY (GrB_Matrix_new (A, type, nrows, ncols)) ;
     116          79 :     if (nrows == 0 || ncols == 0)
     117             :     {
     118             :         // nothing to do: return A as the requested empty matrix
     119           1 :         return (GrB_SUCCESS) ;
     120             :     }
     121             : 
     122             :     //--------------------------------------------------------------------------
     123             :     // create the Mod operator
     124             :     //--------------------------------------------------------------------------
     125             : 
     126             :     #if LAGRAPH_SUITESPARSE
     127          78 :     GRB_TRY (GxB_BinaryOp_new (&Mod, mod_function,
     128             :         GrB_UINT64, GrB_UINT64, GrB_UINT64,
     129             :         "mod_function", MOD_FUNCTION_DEFN)) ;
     130             :     #else
     131             :     GRB_TRY (GrB_BinaryOp_new (&Mod, mod_function,
     132             :         GrB_UINT64, GrB_UINT64, GrB_UINT64)) ;
     133             :     #endif
     134             : 
     135             :     //--------------------------------------------------------------------------
     136             :     // determine the number of entries to generate
     137             :     //--------------------------------------------------------------------------
     138             : 
     139          78 :     bool A_is_full = isinf (density) ;
     140             :     GrB_Index nvals ;
     141          78 :     if (A_is_full)
     142             :     {
     143             :         // determine number of tuples for building a random dense matrix
     144          17 :         double nx = (double) nrows * (double) ncols ;
     145          17 :         LG_ASSERT_MSG (nx < (double) GrB_INDEX_MAX, GrB_OUT_OF_MEMORY,
     146             :             "Problem too large") ;
     147          17 :         nvals = nrows * ncols ;
     148             :     }
     149             :     else
     150             :     {
     151             :         // determine number of tuples for building a random sparse matrix
     152          61 :         double nx = density * (double) nrows * (double) ncols ;
     153          61 :         nx = round (nx) ;
     154          61 :         nx = fmax (nx, (double) 0) ;
     155          61 :         nx = fmin (nx, (double) GrB_INDEX_MAX) ;
     156          61 :         nvals = (GrB_Index) nx ;
     157             :     }
     158             : 
     159             :     //--------------------------------------------------------------------------
     160             :     // allocate workspace
     161             :     //--------------------------------------------------------------------------
     162             : 
     163             :     #if !LAGRAPH_SUITESPARSE
     164             :     {
     165             :         LG_TRY (LAGraph_Malloc ((void **) &ignore, nvals, sizeof (GrB_Index),
     166             :             msg)) ;
     167             :         LG_TRY (LAGraph_Malloc ((void **) &I, nvals, sizeof (GrB_Index), msg)) ;
     168             :         LG_TRY (LAGraph_Malloc ((void **) &J, nvals, sizeof (GrB_Index), msg)) ;
     169             :     }
     170             :     #endif
     171             : 
     172             :     //--------------------------------------------------------------------------
     173             :     // construct the random dense State vector of size nvals
     174             :     //--------------------------------------------------------------------------
     175             : 
     176          78 :     GRB_TRY (GrB_Vector_new (&State, GrB_UINT64, nvals)) ;
     177          78 :     GRB_TRY (GrB_assign (State, NULL, NULL, 0, GrB_ALL, nvals, NULL)) ;
     178          78 :     LG_TRY (LAGraph_Random_Seed (State, seed, msg)) ;
     179             : 
     180             :     //--------------------------------------------------------------------------
     181             :     // construct the random indices if A is sparse, or all indices if full
     182             :     //--------------------------------------------------------------------------
     183             : 
     184          78 :     if (!A_is_full)
     185             :     {
     186             : 
     187             :         //----------------------------------------------------------------------
     188             :         // construct random indices for a sparse matrix
     189             :         //----------------------------------------------------------------------
     190             : 
     191             :         // Rows = mod (State, nrows) ;
     192          61 :         GRB_TRY (GrB_Vector_new (&Rows, GrB_UINT64, nvals)) ;
     193          61 :         GRB_TRY (GrB_apply (Rows, NULL, NULL, Mod, State, nrows, NULL)) ;
     194             : 
     195             :         // State = next (State)
     196          61 :         LG_TRY (LAGraph_Random_Next (State, msg)) ;
     197             : 
     198             :         // Cols = mod (State, ncols) ;
     199          61 :         GRB_TRY (GrB_Vector_new (&Cols, GrB_UINT64, nvals)) ;
     200          61 :         GRB_TRY (GrB_apply (Cols, NULL, NULL, Mod, State, ncols, NULL)) ;
     201             : 
     202             :         // State = next (State)
     203          61 :         LG_TRY (LAGraph_Random_Next (State, msg)) ;
     204             : 
     205             :         //----------------------------------------------------------------------
     206             :         // extract the indices
     207             :         //----------------------------------------------------------------------
     208             : 
     209             :         #if LAGRAPH_SUITESPARSE
     210             :         {
     211             :             // this takes O(1) time and space
     212          61 :             GRB_TRY (GxB_Vector_unpack_Full (Rows, (void **) &I, &I_size,
     213             :                 NULL, NULL)) ;
     214          61 :             GRB_TRY (GxB_Vector_unpack_Full (Cols, (void **) &J, &J_size,
     215             :                 NULL, NULL)) ;
     216             :         }
     217             :         #else
     218             :         {
     219             :             // this takes O(nvals) time and space
     220             :             GRB_TRY (GrB_Vector_extractTuples_UINT64 (ignore, I, &nvals,
     221             :                 Rows)) ;
     222             :             GRB_TRY (GrB_Vector_extractTuples_UINT64 (ignore, J, &nvals,
     223             :                 Cols)) ;
     224             :         }
     225             :         #endif
     226             : 
     227          61 :         GrB_free (&Rows) ;
     228          61 :         GrB_free (&Cols) ;
     229             : 
     230             :     }
     231             :     else
     232             :     {
     233             : 
     234             :         //----------------------------------------------------------------------
     235             :         // construct indices for a full matrix
     236             :         //----------------------------------------------------------------------
     237             : 
     238             :         #if !LAGRAPH_SUITESPARSE
     239             :         {
     240             :             // T = true (nrows, ncols) ;
     241             :             GRB_TRY (GrB_Matrix_new (&T, GrB_BOOL, nrows, ncols)) ;
     242             :             GRB_TRY (GrB_assign (T, NULL, NULL, true,
     243             :                 GrB_ALL, nrows, GrB_ALL, ncols, NULL)) ;
     244             :             // extract the row and column indices from T
     245             :             GRB_TRY (GrB_Matrix_extractTuples (I, J, (bool *) ignore, &nvals,
     246             :                 T)) ;
     247             :             GrB_free (&T) ;
     248             :         }
     249             :         #endif
     250             :     }
     251             : 
     252             :     //-------------------------------------------------------------------------
     253             :     // construct the random values
     254             :     //-------------------------------------------------------------------------
     255             : 
     256          78 :     if (type == GrB_BOOL)
     257             :     {
     258             :         // Values = (State < UINT64_MAX / 2)
     259           5 :         GRB_TRY (GrB_Vector_new (&Values, GrB_BOOL, nvals)) ;
     260           5 :         GRB_TRY (GrB_apply (Values, NULL, NULL,
     261             :             GrB_LT_UINT64, State, UINT64_MAX / 2, NULL)) ;
     262             :     }
     263          73 :     else if (type == GrB_UINT64)
     264             :     {
     265             :         // no need to allocate the Values vector; just use the State itself
     266           5 :         Values = State ;
     267           5 :         State = NULL ;
     268             :     }
     269             :     else
     270             :     {
     271             :         // Values = (type) State
     272          68 :         GRB_TRY (GrB_Vector_new (&Values, type, nvals)) ;
     273          68 :         GRB_TRY (GrB_assign (Values, NULL, NULL, State, GrB_ALL, nvals,
     274             :             NULL)) ;
     275             :     }
     276          78 :     GrB_free (&State) ;
     277             : 
     278             :     // scale the values to the range [0,1], if floating-point
     279          78 :     if (type == GrB_FP32)
     280             :     {
     281             :         // Values = Values / (float) UINT64_MAX
     282           8 :         GRB_TRY (GrB_apply (Values, NULL, NULL, GrB_DIV_FP32,
     283             :             Values, (float) UINT64_MAX, NULL)) ;
     284             :     }
     285          70 :     else if (type == GrB_FP64)
     286             :     {
     287             :         // Values = Values / (double) UINT64_MAX
     288          25 :         GRB_TRY (GrB_apply (Values, NULL, NULL, GrB_DIV_FP64,
     289             :             Values, (double) UINT64_MAX, NULL)) ;
     290             :     }
     291             : 
     292             :     //--------------------------------------------------------------------------
     293             :     // extract the values
     294             :     //--------------------------------------------------------------------------
     295             : 
     296             :     #if LAGRAPH_SUITESPARSE
     297             :     {
     298             :         // this takes O(1) time and space and works for any data type
     299          78 :         GRB_TRY (GxB_Vector_unpack_Full (Values, &X, &X_size, NULL, NULL)) ;
     300             :     }
     301             :     #else
     302             :     {
     303             :         // this takes O(nvals) time and space
     304             :         if (type == GrB_BOOL)
     305             :         {
     306             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (bool), msg)) ;
     307             :             GRB_TRY (GrB_Vector_extractTuples_BOOL (ignore, X, &nvals,
     308             :                 Values)) ;
     309             :         }
     310             :         else if (type == GrB_INT8)
     311             :         {
     312             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (int8_t),
     313             :                 msg)) ;
     314             :             GRB_TRY (GrB_Vector_extractTuples_INT8 (ignore, X, &nvals,
     315             :                 Values)) ;
     316             :         }
     317             :         else if (type == GrB_INT16)
     318             :         {
     319             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (int16_t),
     320             :                 msg)) ;
     321             :             GRB_TRY (GrB_Vector_extractTuples_INT16 (ignore, X, &nvals,
     322             :                 Values)) ;
     323             :         }
     324             :         else if (type == GrB_INT32)
     325             :         {
     326             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (int32_t),
     327             :                 msg)) ;
     328             :             GRB_TRY (GrB_Vector_extractTuples_INT32 (ignore, X, &nvals,
     329             :                 Values)) ;
     330             :         }
     331             :         else if (type == GrB_INT64)
     332             :         {
     333             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (int64_t),
     334             :                 msg)) ;
     335             :             GRB_TRY (GrB_Vector_extractTuples_INT64 (ignore, X, &nvals,
     336             :                 Values)) ;
     337             :         }
     338             :         else if (type == GrB_UINT8)
     339             :         {
     340             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (uint8_t),
     341             :                 msg)) ;
     342             :             GRB_TRY (GrB_Vector_extractTuples_UINT8 (ignore, X, &nvals,
     343             :                 Values)) ;
     344             :         }
     345             :         else if (type == GrB_UINT16)
     346             :         {
     347             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (uint16_t),
     348             :                 msg)) ;
     349             :             GRB_TRY (GrB_Vector_extractTuples_UINT16 (ignore, X, &nvals,
     350             :                 Values)) ;
     351             :         }
     352             :         else if (type == GrB_UINT32)
     353             :         {
     354             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (uint32_t),
     355             :                 msg)) ;
     356             :             GRB_TRY (GrB_Vector_extractTuples_UINT32 (ignore, X, &nvals,
     357             :                 Values)) ;
     358             :         }
     359             :         else if (type == GrB_UINT64)
     360             :         {
     361             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (uint64_t),
     362             :                 msg)) ;
     363             :             GRB_TRY (GrB_Vector_extractTuples_UINT64 (ignore, X, &nvals,
     364             :                 Values)) ;
     365             :         }
     366             :         else if (type == GrB_FP32)
     367             :         {
     368             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (float),
     369             :                 msg)) ;
     370             :             GRB_TRY (GrB_Vector_extractTuples_FP32 (ignore, X, &nvals,
     371             :                 Values)) ;
     372             :         }
     373             :         else // if (type == GrB_FP64)
     374             :         {
     375             :             LG_TRY (LAGraph_Malloc ((void **) &X, nvals, sizeof (double),
     376             :                 msg)) ;
     377             :             GRB_TRY (GrB_Vector_extractTuples_FP64 (ignore, X, &nvals,
     378             :                 Values)) ;
     379             :         }
     380             :         LAGraph_Free ((void **) &ignore, NULL) ;
     381             :     }
     382             :     #endif
     383             : 
     384          78 :     GrB_free (&Values) ;
     385             : 
     386             :     //--------------------------------------------------------------------------
     387             :     // build the matrix
     388             :     //--------------------------------------------------------------------------
     389             : 
     390             :     // Using GxB_IGNORE_DUP for the dup operator would be faster for
     391             :     // SuiteSparse, but it would result in a different matrix as compared to
     392             :     // the pure GrB case.
     393             : 
     394             :     #if LAGRAPH_SUITESPARSE
     395          78 :     if (A_is_full)
     396             :     {
     397             :         // this takes O(1) time and space
     398          17 :         GRB_TRY (GxB_Matrix_pack_FullR (*A, &X, X_size, false, NULL)) ;
     399             :     }
     400             :     else
     401             :     #endif
     402          61 :     if (type == GrB_BOOL)
     403             :     {
     404           4 :         GRB_TRY (GrB_Matrix_build_BOOL   (*A, I, J, X, nvals, GrB_LXOR)) ;
     405             :     }
     406          57 :     else if (type == GrB_INT8)
     407             :     {
     408           4 :         GRB_TRY (GrB_Matrix_build_INT8   (*A, I, J, X, nvals, GrB_PLUS_INT8)) ;
     409             :     }
     410          53 :     else if (type == GrB_INT16)
     411             :     {
     412           4 :         GRB_TRY (GrB_Matrix_build_INT16  (*A, I, J, X, nvals, GrB_PLUS_INT16)) ;
     413             :     }
     414          49 :     else if (type == GrB_INT32)
     415             :     {
     416           4 :         GRB_TRY (GrB_Matrix_build_INT32  (*A, I, J, X, nvals, GrB_PLUS_INT32)) ;
     417             :     }
     418          45 :     else if (type == GrB_INT64)
     419             :     {
     420           4 :         GRB_TRY (GrB_Matrix_build_INT64  (*A, I, J, X, nvals, GrB_PLUS_INT64)) ;
     421             :     }
     422          41 :     else if (type == GrB_UINT8)
     423             :     {
     424           4 :         GRB_TRY (GrB_Matrix_build_UINT8  (*A, I, J, X, nvals, GrB_PLUS_UINT8)) ;
     425             :     }
     426          37 :     else if (type == GrB_UINT16)
     427             :     {
     428           4 :         GRB_TRY (GrB_Matrix_build_UINT16 (*A, I, J, X, nvals, GrB_PLUS_UINT16));
     429             :     }
     430          33 :     else if (type == GrB_UINT32)
     431             :     {
     432           4 :         GRB_TRY (GrB_Matrix_build_UINT32 (*A, I, J, X, nvals, GrB_PLUS_UINT32));
     433             :     }
     434          29 :     else if (type == GrB_UINT64)
     435             :     {
     436           4 :         GRB_TRY (GrB_Matrix_build_UINT64 (*A, I, J, X, nvals, GrB_PLUS_UINT64));
     437             :     }
     438          25 :     else if (type == GrB_FP32)
     439             :     {
     440           4 :         GRB_TRY (GrB_Matrix_build_FP32   (*A, I, J, X, nvals, GrB_MAX_FP32)) ;
     441             :     }
     442             :     else // if (type == GrB_FP64)
     443             :     {
     444          21 :         GRB_TRY (GrB_Matrix_build_FP64   (*A, I, J, X, nvals, GrB_MAX_FP64)) ;
     445             :     }
     446             : 
     447             :     //--------------------------------------------------------------------------
     448             :     // free workspace and return result
     449             :     //--------------------------------------------------------------------------
     450             : 
     451          78 :     LG_FREE_WORK ;
     452          78 :     return (GrB_SUCCESS) ;
     453             : }

Generated by: LCOV version 1.14