GrB_Info read_matrix // read a double-precision or boolean matrix ( GrB_Matrix *A_output, // handle of matrix to create FILE *f, // file to read the tuples from bool make_symmetric, // if true, return A as symmetric bool no_self_edges, // if true, then remove self edges from A bool one_based, // if true, input matrix is 1-based bool boolean, // if true, input is GrB_BOOL, otherwise GrB_FP64 bool pr // if true, print status to stdout ) { int64_t len = 256 ; int64_t ntuples = 0 ; double x ; GrB_Index nvals ; //-------------------------------------------------------------------------- // set all pointers to NULL so that FREE_ALL can free everything safely //-------------------------------------------------------------------------- GrB_Matrix C = NULL, A = NULL, B = NULL ; GrB_Descriptor dt1 = NULL, dt2 = NULL ; GrB_UnaryOp scale2_op = NULL ; //-------------------------------------------------------------------------- // allocate initial space for tuples //-------------------------------------------------------------------------- size_t xsize = ((boolean) ? sizeof (bool) : sizeof (double)) ; GrB_Index *I = malloc (len * sizeof (int64_t)), *I2 = NULL ; GrB_Index *J = malloc (len * sizeof (int64_t)), *J2 = NULL ; void *X = malloc (len * xsize) ; bool *Xbool ; double *Xdouble ; void *X2 = NULL ; if (I == NULL || J == NULL || X == NULL) { // out of memory if (pr) printf ("out of memory for initial tuples\n") ; FREE_ALL ; return (GrB_OUT_OF_MEMORY) ; } Xbool = (bool *) X ; Xdouble = (double *) X ; //-------------------------------------------------------------------------- // read in the tuples from stdin, one per line //-------------------------------------------------------------------------- // format warnings vary with compilers, so read in as double double i2, j2 ; while (fscanf (f, "%lg %lg %lg\n", &i2, &j2, &x) != EOF) { int64_t i = (int64_t) i2 ; int64_t j = (int64_t) j2 ; if (ntuples >= len) { I2 = realloc (I, 2 * len * sizeof (int64_t)) ; J2 = realloc (J, 2 * len * sizeof (int64_t)) ; X2 = realloc (X, 2 * len * xsize) ; if (I2 == NULL || J2 == NULL || X2 == NULL) { if (pr) printf ("out of memory for tuples\n") ; FREE_ALL ; return (GrB_OUT_OF_MEMORY) ; } I = I2 ; I2 = NULL ; J = J2 ; J2 = NULL ; X = X2 ; X2 = NULL ; len = len * 2 ; Xbool = (bool *) X ; Xdouble = (double *) X ; } if (one_based) { i-- ; j-- ; } I [ntuples] = i ; J [ntuples] = j ; if (boolean) { Xbool [ntuples] = (x != 0) ; } else { Xdouble [ntuples] = x ; } ntuples++ ; } //-------------------------------------------------------------------------- // find the dimensions //-------------------------------------------------------------------------- if (pr) printf ("ntuples: %.16g\n", (double) ntuples) ; int64_t nrows = 0 ; int64_t ncols = 0 ; for (int64_t k = 0 ; k < ntuples ; k++) { nrows = MAX (nrows, I [k]) ; ncols = MAX (ncols, J [k]) ; } nrows++ ; ncols++ ; if (pr) printf ("nrows %.16g ncols %.16g\n", (double) nrows, (double) ncols) ; //-------------------------------------------------------------------------- // prune self edges //-------------------------------------------------------------------------- // but not if creating the augmented system aka a bipartite graph double tic [2], t1 ; simple_tic (tic) ; if (no_self_edges && ! (make_symmetric && nrows != ncols)) { int64_t ntuples2 = 0 ; for (int64_t k = 0 ; k < ntuples ; k++) { if (I [k] != J [k]) { // keep this off-diagonal edge I [ntuples2] = I [k] ; J [ntuples2] = J [k] ; if (boolean) { Xbool [ntuples2] = Xbool [k] ; } else { Xdouble [ntuples2] = Xdouble [k] ; } ntuples2++ ; } } ntuples = ntuples2 ; } t1 = simple_toc (tic) ; if (pr) printf ("time to prune self-edges: %12.6f\n", t1) ; //-------------------------------------------------------------------------- // build the matrix, summing up duplicates, and then free the tuples //-------------------------------------------------------------------------- GrB_Type xtype ; GrB_BinaryOp xop, xop2 ; if (boolean) { xtype = GrB_BOOL ; xop = GrB_LOR ; xop2 = GrB_FIRST_BOOL ; } else { xtype = GrB_FP64 ; xop = GrB_PLUS_FP64 ; xop2 = GrB_FIRST_FP64 ; } simple_tic (tic) ; GrB_Info info ; OK (GrB_Matrix_new (&C, xtype, nrows, ncols)) ; if (boolean) { OK (GrB_Matrix_build (C, I, J, Xbool, ntuples, xop)) ; } else { OK (GrB_Matrix_build (C, I, J, Xdouble, ntuples, xop)) ; } t1 = simple_toc (tic) ; if (pr) printf ("time to build the graph with GrB_Matrix_build: %12.6f\n", t1) ; #ifdef TEST_SETELEMENT { // This is just for testing performance of GrB_setElement and comparing // with GrB_build. It is not needed if this function is used in // production. // setElement will be just about as fast as build (perhaps 10% to 50% // more time) with non-blocking mode. If blocking mode is enabled, // setElement will be extremely and painfully slow since the matrix is // rebuilt every time a single entry is added. simple_tic (tic) ; OK (GrB_Matrix_new (&B, xtype, nrows, ncols)) ; for (int64_t k = 0 ; k < ntuples ; k++) { // B (I[k], J[k]) = X [k] GrB_Matrix_setElement (B, X [k], I [k], J [k]) ; } // force completion of B GrB_Matrix_nvals (&nvals, B) ; double t2 = simple_toc (tic) ; if (pr) printf ("time to build the graph with GrB_setElement:" " %12.6f\n", t2) ; GrB_free (&B) ; } #endif free (I) ; I = NULL ; free (J) ; J = NULL ; free (X) ; X = NULL ; //-------------------------------------------------------------------------- // construct the descriptors //-------------------------------------------------------------------------- // descriptor dt2: transpose the 2nd input OK (GrB_Descriptor_new (&dt2)) ; OK (GrB_Descriptor_set (dt2, GrB_INP1, GrB_TRAN)) ; // descriptor dt1: transpose the 1st input OK (GrB_Descriptor_new (&dt1)) ; OK (GrB_Descriptor_set (dt1, GrB_INP0, GrB_TRAN)) ; //-------------------------------------------------------------------------- // create the output matrix //-------------------------------------------------------------------------- if (make_symmetric) { //---------------------------------------------------------------------- // ensure the matrix is symmetric //---------------------------------------------------------------------- if (pr) printf ("make symmetric\n") ; if (nrows == ncols) { //------------------------------------------------------------------ // A = (C+C')/2 //------------------------------------------------------------------ if (pr) printf ("A = (C+C')/2\n") ; double tic [2], t ; simple_tic (tic) ; OK (GrB_Matrix_new (&A, xtype, nrows, nrows)) ; OK (GrB_eWiseAdd (A, NULL, NULL, xop, C, C, dt2)) ; OK (GrB_free (&C)) ; if (boolean) { *A_output = A ; A = NULL ; } else { OK (GrB_Matrix_new (&C, xtype, nrows, nrows)) ; OK (GrB_UnaryOp_new (&scale2_op, scale2, xtype, xtype)) ; OK (GrB_apply (C, NULL, NULL, scale2_op, A, NULL)) ; OK (GrB_free (&A)) ; OK (GrB_free (&scale2_op)) ; *A_output = C ; C = NULL ; } t = simple_toc (tic) ; if (pr) printf ("A = (C+C')/2 time %12.6f\n", t) ; } else { //------------------------------------------------------------------ // A = [0 C ; C' 0], a bipartite graph //------------------------------------------------------------------ // no self edges will exist if (pr) printf ("A = [0 C ; C' 0], a bipartite graph\n") ; double tic [2], t ; simple_tic (tic) ; int64_t n = nrows + ncols ; OK (GrB_Matrix_new (&A, xtype, n, n)) ; GrB_Index I_range [3], J_range [3] ; I_range [GxB_BEGIN] = 0 ; I_range [GxB_END ] = nrows-1 ; J_range [GxB_BEGIN] = nrows ; J_range [GxB_END ] = ncols+nrows-1 ; // A (nrows:n-1, 0:nrows-1) += C' OK (GrB_assign (A, NULL, xop2, // or NULL, C, J_range, GxB_RANGE, I_range, GxB_RANGE, dt1)) ; // A (0:nrows-1, nrows:n-1) += C OK (GrB_assign (A, NULL, xop2, // or NULL, C, I_range, GxB_RANGE, J_range, GxB_RANGE, NULL)) ; // force completion; if this statement does not appear, the // timing will not account for the final build, which would be // postponed until A is used by the caller in another GraphBLAS // operation. GrB_Matrix_nvals (&nvals, A) ; t = simple_toc (tic) ; if (pr) printf ("time to construct augmented system: %12.6f\n", t) ; *A_output = A ; // set A to NULL so the FREE_ALL macro does not free *A_output A = NULL ; } } else { //---------------------------------------------------------------------- // return the matrix as-is //---------------------------------------------------------------------- if (pr) printf ("leave A as-is\n") ; *A_output = C ; // set C to NULL so the FREE_ALL macro does not free *A_output C = NULL ; } //-------------------------------------------------------------------------- // success: free everything except the result, and return it to the caller //-------------------------------------------------------------------------- FREE_ALL ; if (pr) printf ("\nMatrix from file:\n") ; GxB_print (*A_output, pr ? GxB_SHORT : GxB_SILENT) ; return (GrB_SUCCESS) ; }
void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { bool malloc_debug = GB_mx_get_global (true) ; GrB_Matrix A = NULL ; void *Y = NULL ; void *Xtemp = NULL ; void *X = NULL ; GrB_Index nvals = 0 ; // check inputs GB_WHERE (USAGE) ; if (nargout > 3 || nargin < 1 || nargin > 2) { mexErrMsgTxt ("Usage: " USAGE) ; } #define GET_DEEP_COPY ; #define FREE_DEEP_COPY ; // get A (shallow copy) A = GB_mx_mxArray_to_Matrix (pargin [0], "A input", false, true) ; if (A == NULL) { FREE_ALL ; mexErrMsgTxt ("A failed") ; } mxClassID aclass = GB_mx_Type_to_classID (A->type) ; // get the number of entries in A GrB_Matrix_nvals (&nvals, A) ; mxClassID xclass ; GrB_Type xtype ; if (A->type == Complex) { // input argument xclass is ignored xtype = Complex ; xclass = mxDOUBLE_CLASS ; // create Xtemp if (nargout > 2) { GB_MALLOC_MEMORY (Xtemp, nvals, sizeof (double complex)) ; } } else { // get xclass, default is class (A), and the corresponding xtype xclass = GB_mx_string_to_classID (aclass, PARGIN (1)) ; xtype = GB_mx_classID_to_Type (xclass) ; if (xtype == NULL) { FREE_ALL ; mexErrMsgTxt ("X must be numeric") ; } // create X if (nargout > 2) { pargout [2] = mxCreateNumericMatrix (nvals, 1, xclass, mxREAL) ; X = (void *) mxGetData (pargout [2]) ; } } // create I pargout [0] = mxCreateNumericMatrix (nvals, 1, mxUINT64_CLASS, mxREAL) ; GrB_Index *I = (GrB_Index *) mxGetData (pargout [0]) ; // create J GrB_Index *J = NULL ; if (nargout > 1) { pargout [1] = mxCreateNumericMatrix (nvals, 1, mxUINT64_CLASS, mxREAL) ; J = (GrB_Index *) mxGetData (pargout [1]) ; } // [I,J,X] = find (A) if (GB_VECTOR_OK (A)) { // test extract vector methods GrB_Vector v = (GrB_Vector) A ; switch (xtype->code) { case GB_BOOL_code : METHOD (GrB_Vector_extractTuples (I, (bool *) X, &nvals, v)) ; break ; case GB_INT8_code : METHOD (GrB_Vector_extractTuples (I, (int8_t *) X, &nvals, v)) ; break ; case GB_UINT8_code : METHOD (GrB_Vector_extractTuples (I, (uint8_t *) X, &nvals, v)) ; break ; case GB_INT16_code : METHOD (GrB_Vector_extractTuples (I, (int16_t *) X, &nvals, v)) ; break ; case GB_UINT16_code : METHOD (GrB_Vector_extractTuples (I, (uint16_t *) X, &nvals, v)) ; break ; case GB_INT32_code : METHOD (GrB_Vector_extractTuples (I, (int32_t *) X, &nvals, v)) ; break ; case GB_UINT32_code : METHOD (GrB_Vector_extractTuples (I, (uint32_t *) X, &nvals, v)) ; break ; case GB_INT64_code : METHOD (GrB_Vector_extractTuples (I, (int64_t *) X, &nvals, v)) ; break ; case GB_UINT64_code : METHOD (GrB_Vector_extractTuples (I, (uint64_t *) X, &nvals, v)) ; break ; case GB_FP32_code : METHOD (GrB_Vector_extractTuples (I, (float *) X, &nvals, v)) ; break ; case GB_FP64_code : METHOD (GrB_Vector_extractTuples (I, (double *) X, &nvals, v)) ; break ; case GB_UCT_code : case GB_UDT_code : METHOD (GrB_Vector_extractTuples (I, Xtemp, &nvals, v)) ; break ; default : FREE_ALL ; mexErrMsgTxt ("unsupported class") ; } if (J != NULL) { for (int64_t p = 0 ; p < nvals ; p++) J [p] = 0 ; } } else { switch (xtype->code) { case GB_BOOL_code : METHOD (GrB_Matrix_extractTuples (I, J, (bool *) X, &nvals, A)) ; break ; case GB_INT8_code : METHOD (GrB_Matrix_extractTuples (I, J, (int8_t *) X, &nvals, A)) ; break ; case GB_UINT8_code : METHOD (GrB_Matrix_extractTuples (I, J, (uint8_t *) X, &nvals, A)) ; break ; case GB_INT16_code : METHOD (GrB_Matrix_extractTuples (I, J, (int16_t *) X, &nvals, A)) ; break ; case GB_UINT16_code : METHOD (GrB_Matrix_extractTuples (I, J, (uint16_t *) X, &nvals, A)) ; break ; case GB_INT32_code : METHOD (GrB_Matrix_extractTuples (I, J, (int32_t *) X, &nvals, A)) ; break ; case GB_UINT32_code : METHOD (GrB_Matrix_extractTuples (I, J, (uint32_t *) X, &nvals, A)) ; break ; case GB_INT64_code : METHOD (GrB_Matrix_extractTuples (I, J, (int64_t *) X, &nvals, A)) ; break ; case GB_UINT64_code : METHOD (GrB_Matrix_extractTuples (I, J, (uint64_t *) X, &nvals, A)) ; break ; case GB_FP32_code : METHOD (GrB_Matrix_extractTuples (I, J, (float *) X, &nvals, A)) ; break ; case GB_FP64_code : METHOD (GrB_Matrix_extractTuples (I, J, (double *) X, &nvals, A)) ; break; case GB_UCT_code : case GB_UDT_code : METHOD (GrB_Matrix_extractTuples (I, J, Xtemp, &nvals, A)) ; break; default : FREE_ALL ; mexErrMsgTxt ("unsupported class") ; } } if (A->type == Complex && nargout > 2) { // create the MATLAB complex X pargout [2] = mxCreateNumericMatrix (nvals, 1, mxDOUBLE_CLASS, mxCOMPLEX) ; GB_mx_complex_split (nvals, Xtemp, pargout [2]) ; } FREE_ALL ; }
GrB_Info ktruss_graphblas // compute the k-truss of a graph ( GrB_Matrix *p_C, // output k-truss subgraph, C GrB_Matrix A, // input adjacency matrix, A, not modified const int64_t k, // find the k-truss, where k >= 3 int64_t *p_nsteps // # of steps taken ) { //-------------------------------------------------------------------------- // check inputs //-------------------------------------------------------------------------- // ensure k is 3 or more if (k < 3) return (GrB_INVALID_VALUE) ; if (p_C == NULL || p_nsteps == NULL) return (GrB_NULL_POINTER) ; //-------------------------------------------------------------------------- // initializations //-------------------------------------------------------------------------- GrB_Info info ; GxB_SelectOp supportop = NULL ; GrB_Index n ; GrB_Matrix C = NULL ; OK (GrB_Matrix_nrows (&n, A)) ; OK (GrB_Matrix_new (&C, GrB_INT64, n, n)) ; // select operator int64_t support = (k-2) ; OK (GxB_SelectOp_new (&supportop, support_function, GrB_INT64)) ; // last_cnz = nnz (A) GrB_Index cnz, last_cnz ; OK (GrB_Matrix_nvals (&last_cnz, A)) ; //-------------------------------------------------------------------------- // find the k-truss of A //-------------------------------------------------------------------------- double tmult = 0 ; double tsel = 0 ; for (int64_t nsteps = 1 ; ; nsteps++) { //---------------------------------------------------------------------- // C<C> = C*C //---------------------------------------------------------------------- GrB_Matrix Cin = (nsteps == 1) ? A : C ; double t1 = omp_get_wtime ( ) ; OK (GrB_mxm (C, Cin, NULL, GxB_PLUS_LAND_INT64, Cin, Cin, NULL)) ; double t2 = omp_get_wtime ( ) ; printf ("C<C>=C*C time: %g\n", t2-t1) ; tmult += (t2-t1) ; //---------------------------------------------------------------------- // C = C .* (C >= support) //---------------------------------------------------------------------- OK (GxB_select (C, NULL, NULL, supportop, C, &support, NULL)) ; double t3 = omp_get_wtime ( ) ; printf ("select time: %g\n", t3-t2) ; tsel += (t3-t2) ; //---------------------------------------------------------------------- // check if the k-truss has been found //---------------------------------------------------------------------- OK (GrB_Matrix_nvals (&cnz, C)) ; if (cnz == last_cnz) { printf ("ktruss_grb done: tmult %g tsel %g\n", tmult, tsel) ; (*p_C) = C ; // return the output matrix C (*p_nsteps) = nsteps ; // return # of steps OK (GrB_free (&supportop)) ; // free the select operator return (GrB_SUCCESS) ; } last_cnz = cnz ; } }
int main (int argc, char **argv) { //-------------------------------------------------------------------------- // initializations //-------------------------------------------------------------------------- GrB_Info info ; GrB_Matrix A = NULL ; PageRank *Pd = NULL, *P2 = NULL ; iPageRank *Pi = NULL ; double tic [2], t ; OK (GrB_init (GrB_NONBLOCKING)) ; fprintf (stderr, "\npagerank_demo:\n") ; printf ( "\npagerank_demo:\n") ; //-------------------------------------------------------------------------- // read a matrix from stdin //-------------------------------------------------------------------------- bool one_based = false ; if (argc > 1) one_based = strtol (argv [1], NULL, 0) ; OK (read_matrix (&A, stdin, // read matrix from stdin false, // unsymmetric false, // self edges OK one_based, // 0-based or 1-based, depending on input arg true, // read input file as Boolean true)) ; // print status to stdout GrB_Index n, nvals ; OK (GrB_Matrix_nrows (&n, A)) ; OK (GrB_Matrix_nvals (&nvals, A)) ; //-------------------------------------------------------------------------- // compute the page rank via a real semiring //-------------------------------------------------------------------------- simple_tic (tic) ; OK (dpagerank (&Pd, A)) ; t = simple_toc (tic) ; fprintf (stderr, "n %g edges %g dpagerank time : %14.6f iters: 20\n", (double) n, (double) nvals, t) ; printf ( "n %g edges %g dpagerank time : %14.6f iters: 20\n", (double) n, (double) nvals, t) ; //-------------------------------------------------------------------------- // compute the page rank via an integer semiring //-------------------------------------------------------------------------- simple_tic (tic) ; OK (ipagerank (&Pi, A)) ; t = simple_toc (tic) ; fprintf (stderr, "n %g edges %g ipagerank time : %14.6f iters: 20\n", (double) n, (double) nvals, t) ; printf ( "n %g edges %g ipagerank time : %14.6f iters: 20\n", (double) n, (double) nvals, t) ; //-------------------------------------------------------------------------- // compute the page rank via an extreme semiring //-------------------------------------------------------------------------- int iters ; simple_tic (tic) ; OK (dpagerank2 (&P2, A, 100, 1e-5, &iters, GxB_DEFAULT)) ; t = simple_toc (tic) ; fprintf (stderr, "n %g edges %g dpagerank time : %14.6f iters: %d\n", (double) n, (double) nvals, t, iters) ; printf ( "n %g edges %g dpagerank time : %14.6f iters: %d\n", (double) n, (double) nvals, t, iters) ; //-------------------------------------------------------------------------- // print results //-------------------------------------------------------------------------- int64_t limit = MIN (n, 5000) ; printf ("Top %g nodes:\n", (double) limit) ; for (int64_t i = 0 ; i < limit ; i++) { printf ("%5g d:[%6g : %16.8e] i:[%6g : %16.8e] x:[%6g : %16.8e]", (double) i, (double) Pd [i].page, (double) Pd [i].pagerank, (double) Pi [i].page, (double) Pi [i].pagerank, (double) P2 [i].page, (double) P2 [i].pagerank) ; if (Pd [i].page != Pi [i].page || Pd [i].page != P2 [i].page) { printf ("mismatch") ; } printf ("\n") ; } //-------------------------------------------------------------------------- // free all workspace //-------------------------------------------------------------------------- FREE_ALL ; GrB_finalize ( ) ; }
void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { bool malloc_debug = GB_mx_get_global (true) ; GrB_Matrix C = NULL ; GrB_Descriptor desc = NULL ; GrB_Index *I = NULL, ni = 0, I_range [3] ; GrB_Index *J = NULL, nj = 0, J_range [3] ; bool ignore ; // check inputs GB_WHERE (USAGE) ; if (nargout > 1 || nargin < 2 || nargin > 5) { mexErrMsgTxt ("Usage: " USAGE) ; } // get C (make a deep copy) #define GET_DEEP_COPY \ C = GB_mx_mxArray_to_Matrix (pargin [0], "C input", true, true) ; #define FREE_DEEP_COPY GB_MATRIX_FREE (&C) ; GET_DEEP_COPY ; if (C == NULL) { FREE_ALL ; mexErrMsgTxt ("C failed") ; } mxClassID cclass = GB_mx_Type_to_classID (C->type) ; // get accum; default: NOP, default class is class(C) GrB_BinaryOp accum ; if (!GB_mx_mxArray_to_BinaryOp (&accum, pargin [1], "accum", GB_NOP_opcode, cclass, C->type == Complex, C->type == Complex)) { FREE_ALL ; mexErrMsgTxt ("accum failed") ; } // get I if (!GB_mx_mxArray_to_indices (&I, PARGIN (2), &ni, I_range, &ignore)) { FREE_ALL ; mexErrMsgTxt ("I failed") ; } // get J if (!GB_mx_mxArray_to_indices (&J, PARGIN (3), &nj, J_range, &ignore)) { FREE_ALL ; mexErrMsgTxt ("J failed") ; } // get desc if (!GB_mx_mxArray_to_Descriptor (&desc, PARGIN (4), "desc")) { FREE_ALL ; mexErrMsgTxt ("desc failed") ; } GrB_Index nrows, ncols ; GrB_Matrix_nvals (&nrows, C) ; GrB_Matrix_nvals (&ncols, C) ; // C(I,J) = accum (C(I,J),C) METHOD (GrB_assign (C, NULL, accum, C, I, ni, J, nj, desc)) ; GrB_wait ( ) ; TOC ; // return C to MATLAB as a struct and free the GraphBLAS C pargout [0] = GB_mx_Matrix_to_mxArray (&C, "C output", true) ; FREE_ALL ; }